Sie sind auf Seite 1von 1748

Guide de

référence du
programmeur

Zend Framework 1.10.x


Guide de référence du programmeur: Zend Framework 1.10.x
Date de publication 27/01/2010 by mikaelkael (SVN 20684)
Copyright © 2005-2010 Zend Technologies Inc. (http://www.zend.com)
Table des matières
I. Introduction au Zend Framework ................................................................................... 1
Présentation ............................................................................................................ 3
Installation ............................................................................................................... 4
II. Apprendre Zend Framework ......................................................................................... 5
Démarrez rapidement avec Zend Framework ............................................................ 8
1. Zend Framework & MVC Introduction ........................................................... 8
1.1. Zend Framework ............................................................................... 8
1.2. Model-View-Controller ....................................................................... 8
2. Create Your Project ................................................................................... 10
2.1. Install Zend Framework ................................................................... 10
2.2. Create Your Project ......................................................................... 10
2.3. The Bootstrap ................................................................................. 11
2.4. Configuration ................................................................................... 12
2.5. Action Controllers ............................................................................ 12
2.6. Views ............................................................................................. 13
2.7. Checkpoint ...................................................................................... 15
3. Create A Layout ........................................................................................ 15
4. Create a Model and Database Table ........................................................... 18
5. Create A Form ........................................................................................... 28
6. Congratulations! ......................................................................................... 31
Chargement automatique avec Zend Framework ..................................................... 33
1. Introduction ................................................................................................ 33
2. Architecture et buts .................................................................................... 33
2.1. Convention de noms des classes ..................................................... 33
2.2. Conventions et architecture d'Autoload ............................................. 33
3. Utilisation de base de l'autoloader ............................................................... 34
4. Auto-chargement de resources ................................................................... 36
5. Conclusion ................................................................................................. 37
Les plugins dans Zend Framework ......................................................................... 38
1. Introduction ................................................................................................ 38
2. Using Plugins ............................................................................................ 38
3. Conclusion ................................................................................................. 40
Bien démarrer avec Zend_Layout ........................................................................... 42
1. Introduction ................................................................................................ 42
2. Utiliser Zend_Layout .................................................................................. 42
2.1. Layout Configuration ....................................................................... 42
2.2. Créer un script de layout ................................................................. 43
2.3. Accéder à l'objet Layout .................................................................. 43
2.4. Autres opérations ............................................................................ 44
3. Zend_Layout: Conclusions .......................................................................... 45
Bien démarrer avec Zend_View .............................................................................. 46
1. Introduction ................................................................................................ 46
2. Basic Placeholder Usage ............................................................................ 46
3. Standard Placeholders ............................................................................... 49
3.1. Setting the DocType ........................................................................ 49
3.2. Specifying the Page Title ................................................................. 50
3.3. Specifying Stylesheets with HeadLink ............................................... 51
3.4. Aggregating Scripts Using HeadScript .............................................. 52
4. View Placeholders: Conclusion ................................................................... 54
Bien comprendre et utiliser les décorateurs Zend Form ............................................ 55
1. Introduction ................................................................................................ 55

iii
Guide de référence
du programmeur

2. Les bases des décorateurs ......................................................................... 55


2.1. Aperçu du pattern décorateur ........................................................... 55
2.2. Créer votre premier décorateur ........................................................ 57
3. Chainer les décorateurs ............................................................................. 58
4. Rendu individuel des décorateurs ............................................................... 62
5. Créer et rendre des éléments composites .................................................... 66
5.1. L'élément ........................................................................................ 66
5.2. Le décorateur ................................................................................. 68
5.3. Conclusion ...................................................................................... 71
6. Conclusion ................................................................................................. 71
Bien démarrer avec Zend_Session, Zend_Auth, et Zend_Acl .................................... 72
1. Fabrique une application Multi-Utilisateurs avec Zend Framework .................. 72
1.1. Zend Framework ............................................................................. 72
2. Gérer les sessions dans ZF ........................................................................ 72
2.1. Introduction aux sessions ................................................................ 72
2.2. Utilisation classique de Zend_Session .............................................. 73
2.3. Utilisation avancée de Zend_Session ............................................... 74
3. Authentification d'utilisateurs dans Zend Framework ..................................... 74
3.1. Introduction à l'authentification ......................................................... 74
3.2. Utilisation de base de Zend_Auth ..................................................... 74
4. Fabriquer un système de gestion d'autorisations avec Zend Framework ......... 76
4.1. Introduction à l'autorisation .............................................................. 76
4.2. Utilisation de base de Zend_Acl ....................................................... 76
Bien démarrer avec Zend_Search_Lucene .............................................................. 80
1. Introduction à Zend_Search_Lucene ........................................................... 80
2. Structure d'index Lucene ............................................................................ 81
3. Ouverture et création d'index ...................................................................... 82
4. Indexation .................................................................................................. 82
4.1. Politique d'indexation ....................................................................... 83
5. Recherche ................................................................................................. 83
6. Requêtes supportées ................................................................................. 84
7. Pagination de résultat de recherche ............................................................ 86
Bien démarrer avec Zend_Paginator ....................................................................... 88
1. Introduction ................................................................................................ 88
2. Simple Examples ....................................................................................... 88
3. Contrôles de la pagination et styles de défilement ........................................ 90
4. Putting it all Together ................................................................................. 91
III. Guide de référence Zend Framework ......................................................................... 93
Zend_Acl ............................................................................................................. 124
1. Introduction .............................................................................................. 124
1.1. A propos des ressources ............................................................... 124
1.2. A propos des rôles ........................................................................ 124
1.3. Créer la Liste de Contrôle d'Accès ................................................. 125
1.4. Registre des rôles ......................................................................... 126
1.5. Définir les Contrôles d'Accès .......................................................... 127
1.6. Interroger les ACL ......................................................................... 127
2. Affiner les Contrôles d'Accès .................................................................... 128
2.1. Mieux définir les Contrôles d'Accès ................................................ 128
2.2. Retirer les Contrôles d'Accès ......................................................... 130
3. Utilisation avancée ................................................................................... 130
3.1. Rendre les données ACL persistantes ............................................ 130
3.2. Écrire des règles ACL conditionnelles avec des assertions ............... 131
Zend_Amf ............................................................................................................ 132
1. Introduction .............................................................................................. 132

iv
Guide de référence
du programmeur

2. Zend_Amf_Server .................................................................................... 132


2.1. Connecting to the Server from Flex ................................................ 134
2.2. Error Handling ............................................................................... 136
2.3. AMF Responses ............................................................................ 136
2.4. Typed Objects ............................................................................... 136
2.5. Resources ..................................................................................... 138
2.6. Connecting to the Server from Flash ............................................... 138
2.7. Authentication ............................................................................... 140
Zend_Application .................................................................................................. 142
1. Introduction .............................................................................................. 142
2. Zend_Application démarrage rapide .......................................................... 142
2.1. Utiliser Zend_Tool ......................................................................... 142
2.2. Ajouter Zend_Application à votre existant ........................................ 144
2.3. Ajouter et créer des ressources ...................................................... 145
2.4. Aller plus loin avec Zend_Application .............................................. 147
3. Théorie générale ...................................................................................... 147
3.1. Bootstrapping ................................................................................ 148
3.2. Resource Plugins .......................................................................... 152
4. Exemples ................................................................................................. 153
5. Fonctionnalités principales ........................................................................ 156
5.1. Zend_Application ........................................................................... 156
5.2. Zend_Application_Bootstrap_Bootstrapper ...................................... 160
5.3. Zend_Application_Bootstrap_ResourceBootstrapper ........................ 161
5.4. Zend_Application_Bootstrap_BootstrapAbstract ............................... 162
5.5. Zend_Application_Bootstrap_Bootstrap ........................................... 165
5.6. Zend_Application_Resource_Resource ........................................... 166
5.7. Zend_Application_Resource_ResourceAbstract ............................... 166
6. Plugins de ressources disponibles ............................................................. 168
6.1. Zend_Application_Resource_Cachemanager ................................... 168
6.2. Zend_Application_Resource_Db ..................................................... 169
6.3. Zend_Application_Resource_Frontcontroller .................................... 170
6.4. Zend_Application_Resource_Layout ............................................... 171
6.5. Zend_Application_Resource_Locale ............................................... 171
6.6. Zend_Application_Resource_Log .................................................... 172
6.7. Zend_Application_Resource_Multidb ............................................... 173
6.8. Zend_Application_Resource_Mail ................................................... 174
6.9. Zend_Application_Resource_Modules ............................................. 174
6.10. Zend_Application_Resource_Navigation ........................................ 176
6.11. Zend_Application_Resource_Router ............................................. 176
6.12. Zend_Application_Resource_Session ............................................ 176
6.13. Zend_Application_Resource_View ................................................ 177
Zend_Auth ........................................................................................................... 178
1. Introduction .............................................................................................. 178
1.1. Adaptateurs ................................................................................... 178
1.2. Résultats ....................................................................................... 179
1.3. Persistance d'identité ..................................................................... 180
1.4. Utilisation de Zend_Auth ................................................................ 183
2. Authentification avec une table de base de données ................................... 184
2.1. Introduction ................................................................................... 184
2.2. Utilisation avancée : maintenir persistant l'objet de résultat DbTable
............................................................................................................. 186
2.3. Utilisation avancée par l'exemple .................................................... 186
3. Authentification "Digest" ............................................................................ 188
3.1. Introduction ................................................................................... 188

v
Guide de référence
du programmeur

3.2. Spécifications ................................................................................ 188


3.3. Identité .......................................................................................... 188
4. Adaptateur d'authentification HTTP ........................................................... 189
4.1. Introduction ................................................................................... 189
4.2. Fonctionnement ............................................................................. 189
4.3. Options de configuration ................................................................ 190
4.4. Résolveurs .................................................................................... 190
4.5. Usage général : ............................................................................. 191
5. LDAP Authentication ................................................................................ 192
5.1. Introduction ................................................................................... 192
5.2. Usage ........................................................................................... 192
5.3. The API ........................................................................................ 194
5.4. Server Options .............................................................................. 195
5.5. Collecting Debugging Messages ..................................................... 198
5.6. Common Options for Specific Servers ............................................. 199
6. Authentification OpenID ............................................................................ 201
6.1. Introduction ................................................................................... 201
6.2. Spécifications ................................................................................ 201
Zend_Barcode ..................................................................................................... 203
1. Introduction .............................................................................................. 203
2. Création de code-barres avec la classe Zend_Barcode ............................... 203
2.1. Utilisation de la fabrique Zend_Barcode::factory ............................... 203
2.2. Tracer un code-barres ................................................................... 204
2.3. Générer le rendu d'un code-barres ................................................. 204
3. Zend_Barcode Objects ............................................................................. 205
3.1. Common Options .......................................................................... 206
3.2. Common Additional Getters ........................................................... 208
3.3. Description of shipped barcodes ..................................................... 208
4. Zend_Barcode Renderers ......................................................................... 215
4.1. Common Options .......................................................................... 215
4.2. Zend_Barcode_Renderer_Image .................................................... 216
4.3. Zend_Barcode_Renderer_Pdf ........................................................ 217
Zend_Cache ........................................................................................................ 218
1. Introduction .............................................................................................. 218
2. Aspect théorique ...................................................................................... 220
2.1. La méthode de fabrique de Zend_Cache ........................................ 221
2.2. Baliser les enregistrements ............................................................ 222
2.3. Nettoyer le cache .......................................................................... 222
3. Les frontends Zend_Cache ....................................................................... 223
3.1. Zend_Cache_Core ......................................................................... 223
3.2. Zend_Cache_Frontend_Output ....................................................... 226
3.3. Zend_Cache_Frontend_Function .................................................... 227
3.4. Zend_Cache_Frontend_Class ........................................................ 228
3.5. Zend_Cache_Frontend_File ........................................................... 229
3.6. Zend_Cache_Frontend_Page ......................................................... 230
4. Les backends Zend_Cache ...................................................................... 235
4.1. Zend_Cache_Backend_File ............................................................ 235
4.2. Zend_Cache_Backend_Sqlite ......................................................... 237
4.3. Zend_Cache_Backend_Memcached ............................................... 237
4.4. Zend_Cache_Backend_Apc ........................................................... 238
4.5. Zend_Cache_Backend_Xcache ...................................................... 239
4.6. Zend_Cache_Backend_ZendPlatform ............................................. 239
4.7. Zend_Cache_Backend_TwoLevels ................................................. 239

vi
Guide de référence
du programmeur

4.8. Zend_Cache_Backend_ZendServer_Disk et
Zend_Cache_Backend_ZendServer_ShMem ........................................ 241
5. Le gestionnaire de Cache ......................................................................... 241
Zend_Captcha ..................................................................................................... 245
1. Introduction .............................................................................................. 245
2. Opération Captcha ................................................................................... 245
3. Adaptateurs CAPTCHA ............................................................................ 246
3.1. Zend_Captcha_Word ..................................................................... 246
3.2. Zend_Captcha_Dumb .................................................................... 247
3.3. Zend_Captcha_Figlet ..................................................................... 247
3.4. Zend_Captcha_Image .................................................................... 247
3.5. Zend_Captcha_ReCaptcha ............................................................ 248
Zend_CodeGenerator ........................................................................................... 249
1. Introduction .............................................................................................. 249
1.1. Théorie ......................................................................................... 249
2. Exemples Zend_CodeGenerator ............................................................... 251
3. Zend_CodeGenerator Réference ............................................................... 255
3.1. Classes abstraites et interfaces ...................................................... 255
3.2. Classes CodeGenerator concrêtes ................................................. 256
Zend_Config ........................................................................................................ 262
1. Introduction .............................................................................................. 262
2. Aspect théorique ...................................................................................... 263
3. Zend_Config_Ini ....................................................................................... 264
4. Zend_Config_Xml ..................................................................................... 266
Zend_Config_Writer .............................................................................................. 271
1. Zend_Config_Writer .................................................................................. 271
Zend_Console_Getopt .......................................................................................... 274
1. Introduction .............................................................................................. 274
2. Déclarer les règles Getopt ........................................................................ 275
2.1. Déclarer des options avec la syntaxe courte .................................... 275
2.2. Déclarer des options avec la syntaxe longue ................................... 275
3. Extraire les options et les arguments ......................................................... 276
3.1. Manipuler les exceptions Getopt ..................................................... 276
3.2. Extraire les options par nom .......................................................... 277
3.3. Extraire les options ........................................................................ 277
3.4. Extraction des arguments sans option ............................................. 278
4. Configurer Zend_Console_Getopt ............................................................. 278
4.1. Ajouter des règles d'options ........................................................... 278
4.2. Ajouter des messages d'aide ......................................................... 279
4.3. Ajouter des alias aux options ......................................................... 279
4.4. Ajouter des listes d'arguments ........................................................ 279
4.5. Ajouter une configuration ............................................................... 280
Zend_Controller ................................................................................................... 282
1. Zend_Controller - Démarrage rapide ......................................................... 282
1.1. Introduction ................................................................................... 282
1.2. Démarrage rapide ......................................................................... 282
2. Fondations de Zend_Controller ................................................................. 286
3. Le contrôleur frontal (Front Controller) ....................................................... 289
3.1. Présentation générale .................................................................... 289
3.2. Méthodes principales ..................................................................... 290
3.3. Méthodes d'accès à l'environnement ............................................... 292
3.4. Paramètres du contrôleur frontal .................................................... 293
3.5. Étendre le contrôleur frontal ........................................................... 294
4. L'objet Requête ........................................................................................ 294

vii
Guide de référence
du programmeur

4.1. Introduction ................................................................................... 294


4.2. Les requêtes HTTP ....................................................................... 295
4.3. Sous-classer l'objet Requête .......................................................... 298
5. Routeur Standard ..................................................................................... 299
5.1. Introduction ................................................................................... 299
5.2. Utilisation d'un routeur ................................................................... 301
5.3. Utilisation basique du routeur de réécriture ...................................... 301
5.4. Routes par défaut .......................................................................... 302
5.5. Base URL et sous dossiers ............................................................ 303
5.6. Paramètres globaux ....................................................................... 304
5.7. Types de route .............................................................................. 304
5.8. Utiliser Zend_Config avec le RewriteRouter ..................................... 315
5.9. Dérivation de l'objet Router ............................................................ 316
6. Le distributeur .......................................................................................... 316
6.1. Vue d'ensemble ............................................................................. 316
6.2. Sous-classer le distributeur ............................................................ 318
7. Contrôleurs d'action .................................................................................. 321
7.1. Introduction ................................................................................... 321
7.2. Initialisation d'objet ........................................................................ 322
7.3. Détournement Pre et Post-Dispatch (Hook) ..................................... 323
7.4. Accesseurs ................................................................................... 323
7.5. Intégration des Vues ...................................................................... 324
7.6. Méthodes utiles ............................................................................. 326
7.7. Sous-classer le contrôleur d'action .................................................. 326
8. Aides d'action (Helper) ............................................................................. 328
8.1. Introduction ................................................................................... 328
8.2. Initialisation des aides .................................................................... 328
8.3. Le gestionnaire d'aide (Broker) ....................................................... 329
8.4. Aides d'action intégrées ................................................................. 330
8.5. Écrire vos propres aides ................................................................ 358
9. Objet de réponse ..................................................................................... 359
9.1. Utilisation ...................................................................................... 359
9.2. Manipulation des en-têtes .............................................................. 361
9.3. Segments nommés ........................................................................ 361
9.4. Manipulation des exceptions dans l'objet de réponse ....................... 363
9.5. Dériver l'objet de réponse .............................................................. 363
10. Plugins .................................................................................................. 363
10.1. Introduction ................................................................................. 363
10.2. Écrire des plugins ........................................................................ 364
10.3. Utilisation des plugins .................................................................. 364
10.4. Récupération et manipulations des plugins .................................... 366
10.5. Plugins inclus dans Zend Framework ............................................ 366
11. Utilisation de conventions de dossiers modulaires .................................... 371
11.1. Introduction ................................................................................. 371
11.2. Spécification des dossiers de modules .......................................... 372
11.3. Routage des modules .................................................................. 373
11.4. Module ou contrôleur Default global .............................................. 373
12. Exceptions avec MVC ............................................................................ 373
12.1. Introduction ................................................................................. 373
12.2. Gestion des exceptions ................................................................ 373
12.3. Différents types d'exceptions que vous pouvez rencontrer ............... 375
Zend_Currency .................................................................................................... 378
1. Introduction à Zend_Currency ................................................................... 378
1.1. Pourquoi devriez-vous utiliser Zend_Currency ? .............................. 378

viii
Guide de référence
du programmeur

2. Utiliser Zend_Currency ............................................................................. 378


2.1. Utilisation de base ......................................................................... 378
2.2. Créer une monnaie basée sur une locale ........................................ 379
3. Options des monnaies .............................................................................. 379
4. Qu'est ce qui définit une monnaie? ........................................................... 380
5. Où est le symbole monnétaire? ................................................................ 382
6. A quoi ressemble une monnaie? ............................................................... 383
7. Travailler avec les valeurs des monnaies (les montants) ............................. 384
7.1. Travailler avec les valeurs des monnaies ........................................ 384
7.2. Utiliser la précision des monnaies .................................................. 385
8. Calculs avec les monnaies ....................................................................... 386
9. Echanger (convertir) des monnaies ........................................................... 387
10. Informations complémentaires pour Zend_Currency .................................. 388
10.1. Informations sur les monnaies ...................................................... 388
10.2. Optimisation des performances des monnaies ............................... 389
Zend_Date ........................................................................................................... 390
1. Introduction .............................................................................................. 390
1.1. Définissez toujours un fuseau horaire par défaut .............................. 390
1.2. Pourquoi utiliser Zend_Date ? ........................................................ 390
2. Aspect théorique ...................................................................................... 391
2.1. Fonctionnement interne ................................................................. 391
3. Méthodes de base ................................................................................... 392
3.1. La date courante ........................................................................... 392
3.2. Zend_Date : exemples ................................................................... 392
4. Zend_Date API Overview ......................................................................... 394
4.1. Zend_Date Options ....................................................................... 394
4.2. Working with Date Values .............................................................. 395
4.3. Basic Zend_Date Operations Common to Many Date Parts .............. 396
4.4. Comparing Dates .......................................................................... 399
4.5. Getting Dates and Date Parts ........................................................ 401
4.6. Working with Fractions of Seconds ................................................. 402
4.7. Sunrise / Sunset ............................................................................ 402
5. Créer des dates ....................................................................................... 403
5.1. Créer la date actuelle .................................................................... 403
5.2. Créer une date depuis une base de données .................................. 403
5.3. Créer des dates depuis un tableau ................................................. 404
6. Constants for General Date Functions ....................................................... 404
6.1. Using Constants ............................................................................ 404
6.2. List of All Constants ...................................................................... 405
6.3. Self-Defined OUTPUT Formats with ISO ......................................... 409
6.4. Self-Defined OUTPUT Formats Using PHP's date() Format
Specifiers ............................................................................................. 412
7. Exemples concrets ................................................................................... 415
7.1. Vérifier des dates .......................................................................... 415
7.2. Levé et couché du soleil ................................................................ 416
7.3. Fuseaux horaires (Timezones) ....................................................... 418
Zend_Db .............................................................................................................. 420
1. Zend_Db_Adapter .................................................................................... 420
1.1. Se connecter à un SGBD en utilisant un adaptateur ......................... 420
1.2. La base de données d'exemple ...................................................... 425
1.3. Lecture de résultats de requête ...................................................... 426
1.4. Effectuer des changements dans la base de données ...................... 429
1.5. Échapper des valeurs ou des identifiants ........................................ 433
1.6. Gérer les transactions dans une base de données ........................... 435

ix
Guide de référence
du programmeur

1.7. Lister et décrire les tables .............................................................. 436


1.8. Fermer une connexion ................................................................... 437
1.9. Exécuter des requêtes sur le driver directement .............................. 438
1.10. Récupérer la version du serveur SGBD ......................................... 439
1.11. Notes sur des adaptateur spécifiques ........................................... 439
2. Zend_Db_Statement ................................................................................. 443
2.1. Créer un statement ........................................................................ 443
2.2. Exécuter un statement ................................................................... 443
2.3. Récupérer des résultats depuis un statement SELECT ..................... 444
3. Zend_Db_Profiler ..................................................................................... 446
3.1. Introduction ................................................................................... 446
3.2. Utiliser le profileur ......................................................................... 447
3.3. Utilisation avancée du profileur ....................................................... 449
3.4. Profileurs spécialisés ..................................................................... 450
4. Zend_Db_Select ....................................................................................... 451
4.1. Introduction ................................................................................... 451
4.2. Créer un objet Select ..................................................................... 452
4.3. Construction de requêtes Select ..................................................... 452
4.4. Exécuter des requêtes Select ......................................................... 465
4.5. Autres méthodes ........................................................................... 466
5. Zend_Db_Table ....................................................................................... 468
5.1. Introduction ................................................................................... 468
5.2. Définir une classe de Table ........................................................... 468
5.3. Créer une instance de la classe de Table ....................................... 471
5.4. Insérer des enregistrement dans une table ...................................... 472
5.5. Mettre à jour des enregistrements dans une table ............................ 474
5.6. Supprimer des enregistrements d'une Table .................................... 475
5.7. Récupérer des enregistrements par clé primaire .............................. 475
5.8. Requêter pour plusieurs enregistrements ........................................ 477
5.9. Récupérer un seul enregistrement .................................................. 480
5.10. Récupérer les méta données d'une Table ..................................... 480
5.11. Cacher les méta données de la table ............................................ 481
5.12. Personnaliser et étendre une classe de Table ................................ 484
6. Zend_Db_Table_Row ............................................................................... 487
6.1. Introduction ................................................................................... 487
6.2. Récupérer un résultat (un "Row") ................................................... 487
6.3. Sauvegarde un Row en base de données ....................................... 489
6.4. Sérialisation et désérialisation d'un Row .......................................... 490
6.5. Étendre la classe Row ................................................................... 492
7. Zend_Db_Table_Rowset ........................................................................... 494
7.1. Introduction ................................................................................... 494
7.2. Récupérer un Rowset .................................................................... 494
7.3. Atteindre les Rows depuis un Rowset ............................................. 495
7.4. Récupérer un Rowset en tant que tableau (Array) ............................ 497
7.5. Sérialisation et Désérialisation d'un Rowset ..................................... 497
7.6. Étendre la classe Rowset .............................................................. 498
8. Relations Zend_Db_Table ......................................................................... 499
8.1. Introduction ................................................................................... 499
8.2. Définir ses relations ....................................................................... 500
8.3. Récupérer des enregistrements dépendants (enfants) ...................... 502
8.4. Récupérer l'enregistrement parent .................................................. 503
8.5. Récupérer des enregistrements dans une relation N-N (plusieurs-à-
plusieurs ou "many-to-many") .............................................................. 505
8.6. Opérations d'écritures en cascade .................................................. 507

x
Guide de référence
du programmeur

9. Zend_Db_Table_Definition ........................................................................ 509


9.1. Introduction ................................................................................... 509
9.2. Utilisation de base ......................................................................... 509
9.3. Utilisation avancée ........................................................................ 511
Zend_Debug ........................................................................................................ 513
1. Afficher des informations .......................................................................... 513
Zend_Dojo ........................................................................................................... 514
1. Introduction .............................................................................................. 514
2. Zend_Dojo_Data: dojo.data Envelopes ...................................................... 514
2.1. Zend_Dojo_Data Usage ................................................................. 514
2.2. Adding metadata to your containers ................................................ 516
2.3. Advanced Use Cases .................................................................... 516
3. Les aides de vues Dojo ............................................................................ 518
3.1. dojo() View Helper ......................................................................... 518
3.2. Dijit-Specific View Helpers ............................................................. 523
4. Les éléments de formulaire et les décorateurs Dojo .................................... 536
4.1. Dijit-Specific Form Decorators ........................................................ 537
4.2. Dijit-Specific Form Elements ........................................................... 539
4.3. Dojo Form Examples ..................................................................... 556
5. Zend_Dojo build layer support .................................................................. 557
5.1. Introduction ................................................................................... 557
5.2. Generating Custom Module Layers with Zend_Dojo_BuildLayer ........ 558
5.3. Generating Build Profiles with Zend_Dojo_BuildLayer ...................... 560
Zend_Dom ........................................................................................................... 563
1. Introduction .............................................................................................. 563
2. Zend_Dom_Query .................................................................................... 563
2.1. Aspect théorique ........................................................................... 563
2.2. Méthodes disponibles .................................................................... 564
Zend_Exception ................................................................................................... 566
1. Utiliser les exceptions ............................................................................... 566
2. Utilisation classique .................................................................................. 566
3. Exceptions précédentes ............................................................................ 567
Zend_Feed .......................................................................................................... 568
1. Introduction .............................................................................................. 568
2. Importer des flux ...................................................................................... 569
2.1. Flux personnalisés ......................................................................... 570
3. Obtenir des flux à partir de pages Web ..................................................... 574
4. Consommer un flux RSS .......................................................................... 574
5. Consommer un flux Atom ......................................................................... 576
6. Consommer une entrée Atom particulière .................................................. 577
7. Modifier la structure du flux ou des entrées ................................................ 577
8. Classes personnalisées pour les flux et entrées ......................................... 578
9. Zend_Feed_Reader .................................................................................. 580
9.1. Introduction ................................................................................... 580
9.2. Importing Feeds ............................................................................ 580
9.3. Retrieving Underlying Feed and Entry Sources ................................ 581
9.4. Cache Support and Intelligent Requests ......................................... 582
9.5. Locating Feed URIs from Websites ................................................. 583
9.6. Attribute Collections ....................................................................... 584
9.7. Retrieving Feed Information ........................................................... 585
9.8. Retrieving Entry/Item Information .................................................... 588
9.9. Extending Feed and Entry APIs ...................................................... 591
10. Zend_Feed_Writer .................................................................................. 595
10.1. Introduction ................................................................................. 595

xi
Guide de référence
du programmeur

10.2. Architecture ................................................................................. 595


10.3. Getting Started ............................................................................ 596
10.4. Setting Feed Data Points ............................................................. 597
10.5. Setting Entry Data Points ............................................................. 599
11. Zend_Feed_Pubsubhubbub .................................................................... 601
11.1. What is Pubsubhubbub? .............................................................. 601
11.2. Architecture ................................................................................. 602
11.3. Zend_Feed_Pubsubhubbub_Publisher .......................................... 602
11.4. Zend_Feed_Pubsubhubbub_Subscriber ........................................ 603
Zend_File ............................................................................................................ 611
1. Zend_File_Transfer .................................................................................. 611
1.1. Adaptateurs supportés par Zend_File_Transfer ................................ 612
1.2. Options de Zend_File_Transfer ...................................................... 612
1.3. Vérification des fichiers .................................................................. 613
1.4. Informations complémentaires sur les fichiers .................................. 613
1.5. Progress for file uploads ................................................................ 615
2. Validateurs pour Zend_File_Transfer ......................................................... 617
2.1. Utiliser les validateurs avec Zend_File_Transfer .............................. 618
2.2. Validateur Count ........................................................................... 620
2.3. Validateur Crc32 ........................................................................... 621
2.4. Validateur ExcludeExtension .......................................................... 621
2.5. Validateur ExcludeMimeType ......................................................... 622
2.6. Validateur Exists ........................................................................... 623
2.7. Validateur Extension ...................................................................... 623
2.8. Validateur FilesSize ....................................................................... 624
2.9. Validateur ImageSize ..................................................................... 625
2.10. Validateur IsCompressed ............................................................. 626
2.11. Validateur IsImage ....................................................................... 626
2.12. Validateur Hash ........................................................................... 626
2.13. Validateur Md5 ............................................................................ 627
2.14. Validateur MimeType ................................................................... 627
2.15. Validateur NotExists ..................................................................... 629
2.16. Validateur Sha1 ........................................................................... 629
2.17. Validateur Size ............................................................................ 629
2.18. Validateur WordCount .................................................................. 630
3. Filtres pour Zend_File_Transfer ................................................................ 631
3.1. Utiliser les filtres avec Zend_File_Transfer ...................................... 631
3.2. Filtre Decrypt ................................................................................ 632
3.3. Filtre Encrypt ................................................................................. 633
3.4. Filtre LowerCase ........................................................................... 633
3.5. Filtre Rename ............................................................................... 634
3.6. Filtre UpperCase ........................................................................... 635
Zend_Filter .......................................................................................................... 636
1. Introduction .............................................................................................. 636
1.1. Qu'est-ce qu'un filtre ? ................................................................... 636
1.2. Utilisation basique des filtres .......................................................... 636
1.3. Utilisation de la méthode statique staticFilter() ................................. 636
2. Classes de filtre standards ....................................................................... 637
2.1. Alnum ........................................................................................... 637
2.2. Alpha ............................................................................................ 637
2.3. BaseName .................................................................................... 637
2.4. Boolean ........................................................................................ 637
2.5. Callback ........................................................................................ 640
2.6. Compression et décompression ...................................................... 641

xii
Guide de référence
du programmeur

2.7. Decrypt ......................................................................................... 646


2.8. Digits ............................................................................................ 648
2.9. Dir ................................................................................................ 648
2.10. Encrypt ....................................................................................... 648
2.11. HtmlEntities ................................................................................. 651
2.12. Int ............................................................................................... 651
2.13. LocalizedToNormalized ................................................................ 651
2.14. NormalizedToLocalized ................................................................ 653
2.15. Null ............................................................................................. 654
2.16. PregReplace ............................................................................... 655
2.17. RealPath ..................................................................................... 656
2.18. StringToLower ............................................................................. 656
2.19. StringToUpper ............................................................................. 657
2.20. StringTrim ................................................................................... 657
2.21. Int ............................................................................................... 657
2.22. StripTags .................................................................................... 657
3. Chaînes de filtrage ................................................................................... 658
3.1. Changing filter chain order ............................................................. 658
4. Écriture de filtres ...................................................................................... 658
5. Zend_Filter_Input ..................................................................................... 659
5.1. Déclarer des règles de filtre et de validateur .................................... 660
5.2. Créer le processeur de filtres et validateurs ..................................... 661
5.3. Récupérer les champs validés/filtré, et les éventuels rapports ........... 661
5.4. Utiliser des méta commandes pour contrôler les règles des filtres et
validateurs ........................................................................................... 664
5.5. Ajouter des espaces de noms comme noms de classes ................... 669
6. Zend_Filter_Inflector ................................................................................. 670
6.1. Opération ...................................................................................... 671
6.2. Créer des chemins vers des filtres alternatifs ................................... 671
6.3. Paramétrer la cible de l'inflecteur .................................................... 671
6.4. Règles d'inflexion .......................................................................... 672
6.5. Autres méthodes utilitaires ............................................................. 674
6.6. Zend_Config avec Zend_Filter_Inflector .......................................... 675
Zend_Form .......................................................................................................... 676
1. Zend_Form .............................................................................................. 676
2. Zend_Form démarrage rapide ................................................................... 676
2.1. Créer un objet de formulaire .......................................................... 676
2.2. Ajouter des éléments au formulaire ................................................. 676
2.3. Rendre (visuellement) un formulaire ............................................... 678
2.4. Vérifier qu'un formulaire est valide .................................................. 680
2.5. Les statuts d'erreur ........................................................................ 680
2.6. Assembler le tout ensemble ........................................................... 681
2.7. Utiliser un objet Zend_Config ...................................................... 682
2.8. Conclusion .................................................................................... 683
3. Creating Form Elements Using Zend_Form_Element .................................. 683
3.1. Plugin Loaders .............................................................................. 683
3.2. Filters ........................................................................................... 686
3.3. Validators ...................................................................................... 687
3.4. Decorators .................................................................................... 692
3.5. Metadata and Attributes ................................................................. 694
3.6. Standard Elements ........................................................................ 695
3.7. Zend_Form_Element Methods ........................................................ 695
3.8. Configuration ................................................................................. 697
3.9. Custom Elements .......................................................................... 698

xiii
Guide de référence
du programmeur

4. Creating Forms Using Zend_Form ............................................................ 699


4.1. Plugin Loaders .............................................................................. 700
4.2. Elements ....................................................................................... 701
4.3. Display Groups ............................................................................. 705
4.4. Sub Forms .................................................................................... 709
4.5. Metadata and Attributes ................................................................. 710
4.6. Decorators .................................................................................... 711
4.7. Validation ...................................................................................... 713
4.8. Methods ........................................................................................ 715
4.9. Configuration ................................................................................. 718
4.10. Custom forms .............................................................................. 719
5. Créer un visuel personnalisé en utilisant Zend_Form_Decorator .................. 721
5.1. Configuration ................................................................................. 721
5.2. Décorateurs standards ................................................................... 722
5.3. Décorateurs personnalisés ............................................................. 722
5.4. Rendre des décorateurs individuellement ........................................ 725
6. Standard Form Elements Shipped With Zend Framework ............................ 725
6.1. Zend_Form_Element_Button .......................................................... 725
6.2. Zend_Form_Element_Captcha ....................................................... 726
6.3. Zend_Form_Element_Checkbox ..................................................... 727
6.4. Zend_Form_Element_File .............................................................. 727
6.5. Zend_Form_Element_Hidden ......................................................... 730
6.6. Zend_Form_Element_Hash ............................................................ 731
6.7. Zend_Form_Element_Image .......................................................... 731
6.8. Zend_Form_Element_MultiCheckbox .............................................. 731
6.9. Zend_Form_Element_Multiselect .................................................... 732
6.10. Zend_Form_Element_Password ................................................... 732
6.11. Zend_Form_Element_Radio ......................................................... 733
6.12. Zend_Form_Element_Reset ......................................................... 733
6.13. Zend_Form_Element_Select ......................................................... 733
6.14. Zend_Form_Element_Submit ........................................................ 734
6.15. Zend_Form_Element_Text ........................................................... 734
6.16. Zend_Form_Element_Textarea ..................................................... 734
7. Décorateurs standards fournis avec Zend Framework ................................. 734
7.1. Zend_Form_Decorator_Callback ............................................. 734
7.2. Zend_Form_Decorator_Captcha ............................................... 735
7.3. Zend_Form_Decorator_Description ....................................... 735
7.4. Zend_Form_Decorator_DtDdWrapper ....................................... 735
7.5. Zend_Form_Decorator_Errors ................................................. 736
7.6. Zend_Form_Decorator_Fieldset ............................................. 736
7.7. Zend_Form_Decorator_File ..................................................... 736
7.8. Zend_Form_Decorator_Form ..................................................... 736
7.9. Zend_Form_Decorator_FormElements ..................................... 736
7.10. Zend_Form_Decorator_FormErrors ....................................... 736
7.11. Zend_Form_Decorator_HtmlTag ............................................. 737
7.12. Zend_Form_Decorator_Image ................................................. 737
7.13. Zend_Form_Decorator_Label ................................................. 737
7.14. Zend_Form_Decorator_PrepareElements ............................. 738
7.15. Zend_Form_Decorator_ViewHelper ....................................... 738
7.16. Zend_Form_Decorator_ViewScript ....................................... 738
8. Internationaliser un formulaire Zend_Form ................................................. 740
8.1. Initialiser l'i18n dans les formulaires ................................................ 740
8.2. Cibles gérées par l'I18n ................................................................. 741
9. Advanced Zend_Form Usage .................................................................... 741

xiv
Guide de référence
du programmeur

9.1. Array Notation ............................................................................... 741


9.2. Multi-Page Forms .......................................................................... 744
Zend_Gdata ......................................................................................................... 746
1. Introduction .............................................................................................. 746
1.1. Structure of Zend_Gdata ................................................................ 746
1.2. Interacting with Google Services .................................................... 747
1.3. Obtaining instances of Zend_Gdata classes .................................... 747
1.4. Google Data Client Authentication .................................................. 748
1.5. Dependencies ............................................................................... 748
1.6. Creating a new Gdata client ........................................................... 748
1.7. Common Query Parameters ........................................................... 749
1.8. Fetching a Feed ............................................................................ 750
1.9. Working with Multi-page Feeds ...................................................... 750
1.10. Working with Data in Feeds and Entries ........................................ 751
1.11. Updating Entries .......................................................................... 751
1.12. Posting Entries to Google Servers ................................................ 751
1.13. Deleting Entries on Google Servers .............................................. 752
2. Authentification par procédé AuthSub ........................................................ 752
2.1. Création d'un client HTTP authentifié avec AuthSub ......................... 753
2.2. Destruction de l'authentification AuthSub ......................................... 754
3. Using the Book Search Data API .............................................................. 754
3.1. Authenticating to the Book Search service ...................................... 754
3.2. Searching for books ...................................................................... 755
3.3. Using community features .............................................................. 756
3.4. Book collections and My Library ..................................................... 758
4. Authentification avec ClientLogin ............................................................... 759
4.1. Création d'un client HTTP "ClientLogin" authentifié .......................... 760
4.2. Fermer un client HTTP authentifié par ClientLogin ........................... 760
5. Using Google Calendar ............................................................................ 760
5.1. Connecting To The Calendar Service ............................................. 761
5.2. Retrieving A Calendar List ............................................................. 763
5.3. Retrieving Events .......................................................................... 764
5.4. Creating Events ............................................................................. 766
5.5. Modifying Events ........................................................................... 769
5.6. Deleting Events ............................................................................. 769
5.7. Accessing Event Comments ........................................................... 770
6. Using Google Documents List Data API .................................................... 770
6.1. Get a List of Documents ................................................................ 770
6.2. Upload a Document ....................................................................... 771
6.3. Searching the documents feed ....................................................... 772
7. Using Google Health ................................................................................ 772
7.1. Connect To The Health Service ...................................................... 773
7.2. Profile Feed .................................................................................. 775
7.3. Profile List Feed ............................................................................ 777
7.4. Sending Notices to the Register Feed ............................................. 777
8. Using Google Spreadsheets ..................................................................... 778
8.1. Create a Spreadsheet .................................................................... 778
8.2. Get a List of Spreadsheets ............................................................ 778
8.3. Get a List of Worksheets ............................................................... 779
8.4. Interacting With List-based Feeds ................................................... 779
8.5. Interacting With Cell-based Feeds .................................................. 781
9. Using Google Apps Provisioning ............................................................... 782
9.1. Setting the current domain ............................................................. 783
9.2. Interacting with users ..................................................................... 783

xv
Guide de référence
du programmeur

9.3. Interacting with nicknames ............................................................. 786


9.4. Interacting with email lists .............................................................. 788
9.5. Interacting with email list recipients ................................................. 789
9.6. Handling errors ............................................................................. 790
10. Using Google Base ................................................................................ 791
10.1. Connect To The Base Service ...................................................... 791
10.2. Retrieve Items ............................................................................. 794
10.3. Insert, Update, and Delete Customer Items ................................... 795
11. Utilisation des albums Web Picasa .......................................................... 797
11.1. Se connecter au service .............................................................. 797
11.2. Comprendre et construire des requêtes ......................................... 800
11.3. Récupérer des flux et des éléments .............................................. 801
11.4. Créer des ressources .................................................................. 804
11.5. Supprimer des éléments .............................................................. 806
12. Using the YouTube Data API .................................................................. 807
12.1. Authentication .............................................................................. 808
12.2. Developer Keys and Client ID ...................................................... 808
12.3. Retrieving public video feeds ........................................................ 808
12.4. Retrieving video comments .......................................................... 810
12.5. Retrieving playlist feeds ............................................................... 810
12.6. Retrieving a list of a user's subscriptions ....................................... 811
12.7. Retrieving a user's profile ............................................................. 811
12.8. Uploading Videos to YouTube ...................................................... 812
12.9. Browser-based upload ................................................................. 813
12.10. Checking upload status .............................................................. 814
12.11. Other Functions ......................................................................... 815
13. Attraper les exceptions Gdata ................................................................. 815
Zend_Http ............................................................................................................ 817
1. Introduction .............................................................................................. 817
1.1. Utilisation de Zend_Http_Client ....................................................... 817
1.2. Les paramètres de configuration .................................................... 817
1.3. Utilisation basique ......................................................................... 818
1.4. Ajouts de paramètres GET et POST ............................................... 819
1.5. Accéder à la dernière requête, ou réponse ...................................... 820
2. Zend_Http_Client - Utilisation avancée ...................................................... 820
2.1. Redirections HTTP ........................................................................ 820
2.2. Ajout de cookies et gestion de leur persistance ............................... 820
2.3. Définir des en-têtes personnalisés .................................................. 821
2.4. Envoi de fichiers ............................................................................ 822
2.5. Envoyer des données brutes via POST ........................................... 823
2.6. Authentification HTTP .................................................................... 824
2.7. Envoyer plusieurs requêtes avec le même client .............................. 824
2.8. Data Streaming ............................................................................. 825
3. Zend_Http_Client - Adaptateurs de connexion ............................................ 826
3.1. Présentation globale ...................................................................... 826
3.2. Adaptateur Socket ......................................................................... 827
3.3. Adaptateur Proxy ........................................................................... 829
3.4. The cURL Adapter ........................................................................ 830
3.5. Adaptateur Test ............................................................................. 831
3.6. Créer vos propres adaptateurs de connexion ................................... 834
4. Zend_Http_Cookie and Zend_Http_CookieJar ............................................ 836
4.1. Introduction ................................................................................... 836
4.2. Instancier des objets Zend_Http_Cookie ......................................... 836
4.3. Zend_Http_Cookie méthodes getter ................................................ 837

xvi
Guide de référence
du programmeur

4.4. Zend_Http_Cookie: Correspondance de scénario ............................ 838


4.5. Classe Zend_Http_CookieJar : Instanciation .................................... 839
4.6. Ajouter des cookies à un objet Zend_Http_CookieJar ....................... 840
4.7. Récupérer les cookies présents dans un objet Zend_Http_CookieJar
............................................................................................................. 840
5. Zend_Http_Response ............................................................................... 841
5.1. Introduction ................................................................................... 841
5.2. Méthodes de tests booléennes ....................................................... 842
5.3. Méthodes accesseurs .................................................................... 842
5.4. Analyseurs statiques de réponse HTTP .......................................... 843
Zend_InfoCard ..................................................................................................... 845
1. Introduction .............................................................................................. 845
1.1. Basic Theory of Usage .................................................................. 845
1.2. Using as part of Zend_Auth ........................................................... 845
1.3. Using the Zend_InfoCard component standalone ............................. 847
1.4. Working with a Claims object ......................................................... 847
1.5. Attaching Information Cards to existing accounts ............................. 848
1.6. Creating Zend_InfoCard Adapters ................................................... 849
Zend_Json ........................................................................................................... 851
1. Introduction .............................................................................................. 851
2. Utilisation de base ................................................................................... 851
2.1. Pretty-printing JSON ...................................................................... 851
3. Utilisation avancée de Zend_Json ............................................................. 852
3.1. Objets JSON ................................................................................. 852
3.2. Encoding PHP objects ................................................................... 852
3.3. Internal Encoder/Decoder ............................................................... 852
3.4. JSON Expressions ........................................................................ 852
4. XML to JSON conversion ......................................................................... 853
5. Zend_Json_Server - JSON-RPC server ..................................................... 855
5.1. Advanced Details .......................................................................... 857
Zend_Layout ........................................................................................................ 863
1. Introduction .............................................................................................. 863
2. Zend_Layout - Démarrage rapide .............................................................. 863
2.1. Scripts de layout ........................................................................... 863
2.2. Utilisation de Zend_Layout avec le système MVC de Zend
Framework ........................................................................................... 864
2.3. Utilisation de Zend_Layout en composant indépendant .................... 865
2.4. Layout d'exemple .......................................................................... 866
3. Zend_Layout options de configuration ....................................................... 868
3.1. Exemples ...................................................................................... 868
4. Zend_Layout, utilisation avancée .............................................................. 870
4.1. Objets de vue personnalisés .......................................................... 870
4.2. Plugin de contrôleur frontal personnalisé ......................................... 871
4.3. Aide d'action personnalisée ............................................................ 871
4.4. Résolution de chemin de script personnalisé (inflecteur) ................... 871
Zend_Ldap .......................................................................................................... 873
1. Introduction .............................................................................................. 873
1.1. Theory of operation ....................................................................... 873
2. API overview ........................................................................................... 876
2.1. Configuration / options ................................................................... 876
2.2. API Reference ............................................................................... 878
3. Usage Scenarios ...................................................................................... 903
3.1. Authentication scenarios ................................................................ 903
3.2. Basic CRUD operations ................................................................. 904

xvii
Guide de référence
du programmeur

3.3. Extended operations ...................................................................... 905


4. Tools ....................................................................................................... 906
4.1. Creation and modification of DN strings .......................................... 906
4.2. Using the filter API to create search filters ....................................... 906
4.3. Modify LDAP entries using the Attribute API .................................... 906
5. Object oriented access to the LDAP tree using Zend_Ldap_Node ................ 906
5.1. Basic CRUD operations ................................................................. 906
5.2. Extended operations ...................................................................... 907
5.3. Tree traversal ................................................................................ 907
6. Getting information from the LDAP server .................................................. 907
6.1. RootDSE ....................................................................................... 907
6.2. Schema Browsing ......................................................................... 907
7. Serializing LDAP data to and from LDIF .................................................... 908
7.1. Serialize a LDAP entry to LDIF ...................................................... 908
7.2. Deserialize a LDIF string into a LDAP entry ..................................... 909
Zend_Loader ....................................................................................................... 911
1. Charger les fichiers et les classes dynamiquement ..................................... 911
1.1. Charger des fichiers ...................................................................... 911
1.2. Charger des classes ...................................................................... 911
1.3. Tester si un fichier est lisible .......................................................... 912
1.4. Utiliser l'autoloader ........................................................................ 913
2. L'autoloader ............................................................................................. 914
2.1. Utiliser le chargeur automatique (autoloader) ................................... 914
2.2. Selecting a Zend Framework version .............................................. 915
2.3. L'interface de l'autoloader .............................................................. 917
2.4. Référence de l'autoloader .............................................................. 917
3. Autoloaders de ressources ....................................................................... 920
3.1. Utilisation de l'autoloader de ressources ......................................... 920
3.2. L'autoloader de ressource Module .................................................. 922
3.3. Utiliser les autoloaders de ressources comme fabriques d'objets ....... 922
3.4. Référence de l'autoloader de ressources ......................................... 922
4. Chargeur de Plugins ................................................................................ 922
4.1. Utilisation basique ......................................................................... 923
4.2. Manipulation des chemins des Plugins ............................................ 924
4.3. Test des Plugins et récupération des noms de classe ...................... 924
4.4. Obtenir de meilleures performances avec les Plugins ....................... 924
Zend_Locale ........................................................................................................ 926
1. Introduction .............................................................................................. 926
1.1. What is Localization ...................................................................... 926
1.2. What is a Locale? ......................................................................... 927
1.3. How are Locales Represented? ...................................................... 927
1.4. Selecting the Right Locale ............................................................. 928
1.5. Usage of automatic Locales ........................................................... 928
1.6. Using a default Locale ................................................................... 929
1.7. ZF Locale-Aware Classes .............................................................. 930
1.8. Application wide locale .................................................................. 930
1.9. Zend_Locale_Format::setOptions(array $options) ............................ 931
1.10. Speed up Zend_Locale and its subclasses .................................... 931
2. Using Zend_Locale .................................................................................. 932
2.1. Copying, Cloning, and Serializing Locale Objects ............................. 932
2.2. Equality ......................................................................................... 932
2.3. Default locales .............................................................................. 933
2.4. Set a new locale ........................................................................... 933
2.5. Getting the language and region .................................................... 933

xviii
Guide de référence
du programmeur

2.6. Obtaining localized strings ............................................................. 934


2.7. Obtaining translations for "yes" and "no" ......................................... 948
2.8. Get a list of all known locales ........................................................ 949
2.9. Detecting locales ........................................................................... 949
3. Normalization and Localization .................................................................. 951
3.1. Number normalization: getNumber($input, Array $options) ................ 951
3.2. Number localization ....................................................................... 952
3.3. Number testing .............................................................................. 954
3.4. Float value normalization ............................................................... 954
3.5. Floating point value localization ...................................................... 954
3.6. Floating point value testing ............................................................ 954
3.7. Integer value normalization ............................................................ 955
3.8. Integer point value localization ....................................................... 955
3.9. Integer value testing ...................................................................... 955
3.10. Numeral System Conversion ........................................................ 955
4. Working with Dates and Times ................................................................. 957
4.1. Normalizing Dates and Times ........................................................ 957
4.2. Testing Dates ................................................................................ 960
4.3. Normalizing a Time ....................................................................... 961
4.4. Testing Times ............................................................................... 961
5. Supported locales .................................................................................... 961
Zend_Log ............................................................................................................ 973
1. Présentation ............................................................................................. 973
1.1. Créer un log .................................................................................. 973
1.2. Messages de logs ......................................................................... 973
1.3. Détruire un log .............................................................................. 974
1.4. Utiliser les priorités intégrées ......................................................... 974
1.5. Ajouter ses propres priorités .......................................................... 974
1.6. Comprendre les événements de logs .............................................. 975
2. Rédacteurs (Writers) ................................................................................ 975
2.1. Écrire vers un flux (stream) ............................................................ 975
2.2. Écrire dans des bases de données ................................................. 976
2.3. Écrire vers Firebug ........................................................................ 976
2.4. Écrire vers un émail ...................................................................... 979
2.5. Ecrire dans lee journal du système ................................................. 981
2.6. Ecrire vers le moniteur Zend Server ............................................... 982
2.7. Déraciner les rédacteurs ................................................................ 986
2.8. Tester avec un simulacre ............................................................... 986
2.9. Additionner les rédacteurs .............................................................. 986
3. Formateurs (mise en forme) ..................................................................... 987
3.1. Formatage simple .......................................................................... 987
3.2. Formater vers le XML .................................................................... 987
4. Filtres ...................................................................................................... 988
4.1. Filtrer pour tous les rédacteurs (Writers) ......................................... 988
4.2. Filtrer pour une seule instance de rédacteur .................................... 989
5. Utiliser la fabrique pour créer des logs ...................................................... 989
5.1. Options pour les objets d'écriture ................................................... 990
5.2. Options des filtres ......................................................................... 991
5.3. Créer des objets d'écriture et des filtres configurés .......................... 991
Zend_Mail ............................................................................................................ 994
1. Introduction .............................................................................................. 994
1.1. Pour commencer ........................................................................... 994
1.2. Configurer le transport sendmail par défaut ..................................... 994
2. Envoyer des émail en utilisant SMTP ........................................................ 995

xix
Guide de référence
du programmeur

3. Envoyer plusieurs émail par connexion SMTP ............................................ 996


4. Utiliser différents transports ...................................................................... 997
5. Émail HTML ............................................................................................. 997
6. Fichiers joints ........................................................................................... 998
7. Ajouter des destinataires .......................................................................... 999
8. Contrôler les limites MIME ........................................................................ 999
9. En-têtes additionnels ................................................................................ 999
10. Jeux de caractères ............................................................................... 1000
11. Encodage ............................................................................................. 1000
12. Authentification SMTP ........................................................................... 1001
13. Sécuriser les transports SMTP .............................................................. 1001
14. Lire des émail ...................................................................................... 1002
14.1. Exemple simple avec Pop3 ........................................................ 1002
14.2. Ouvrir un stockage local ............................................................. 1002
14.3. Ouvrir un stockage distant .......................................................... 1003
14.4. Extraire des messages et autres méthodes simples ...................... 1004
14.5. Travailler avec les messages ...................................................... 1004
14.6. Vérifier les drapeaux ("flags") ..................................................... 1006
14.7. Utiliser les dossiers .................................................................... 1007
14.8. Utilisation avancée ..................................................................... 1009
Zend_Markup ..................................................................................................... 1013
1. Introduction ............................................................................................ 1013
2. Guide de démarrage avec Zend_Markup ................................................. 1013
3. Analyseurs Zend_Markup (parsers) ......................................................... 1014
3.1. Theorie de l'analyse ..................................................................... 1014
3.2. L'analyseur BBCode .................................................................... 1015
3.3. L'analyseur Textile ....................................................................... 1015
4. Moteurs de rendu Zend_Markup ............................................................. 1016
4.1. Ajouter vos propres tags .............................................................. 1016
4.2. Liste de tags ............................................................................... 1017
Zend_Measure ................................................................................................... 1019
1. Introduction ............................................................................................ 1019
2. Création d'une mesure ........................................................................... 1019
2.1. Créer des mesures à partir de nombres entiers et décimaux ........... 1020
2.2. Créer des mesures à partir de chaînes de caractères ..................... 1020
2.3. Mesures à partir de chaînes localisées .......................................... 1020
3. Récupérer des mesures .......................................................................... 1021
3.1. Récupération automatique ............................................................ 1021
3.2. Récupération des valeurs ............................................................. 1022
3.3. Récupération de l'unité de mesure ................................................ 1022
3.4. Récupération en tant que chaîne régionale .................................... 1022
4. Manipuler des mesures .......................................................................... 1022
4.1. Convertir ..................................................................................... 1023
4.2. Ajouter et soustraire .................................................................... 1023
4.3. Vérifier l'égalité des mesures ........................................................ 1024
4.4. Comparer les mesures ................................................................. 1024
4.5. Changer manuellement des valeurs .............................................. 1025
4.6. Changer manuellement de type .................................................... 1025
5. Types de mesures ................................................................................. 1025
5.1. Conseils pour Zend_Measure_Binary ............................................ 1028
5.2. Conseils pour Zend_Measure_Number ......................................... 1028
5.3. Chiffres romains .......................................................................... 1029
Zend_Memory .................................................................................................... 1030
1. Présentation ........................................................................................... 1030

xx
Guide de référence
du programmeur

1.1. Introduction ................................................................................. 1030


1.2. Aspect théorique ......................................................................... 1030
2. Manager de mémoire ............................................................................. 1031
2.1. Créer un manager de mémoire ..................................................... 1031
2.2. Manager les objets mémoire ........................................................ 1032
2.3. Régler le manager de mémoire .................................................... 1033
3. Objet mémoire ....................................................................................... 1034
3.1. Mobile ......................................................................................... 1034
3.2. Verrouillé ..................................................................................... 1034
3.3. Propriété "value" du manager de mémoire ..................................... 1034
3.4. Interface du conteneur de mémoire ............................................... 1035
Zend_Mime ........................................................................................................ 1037
1. Zend_Mime ............................................................................................ 1037
1.1. Introduction ................................................................................. 1037
1.2. Méthodes statiques et constantes ................................................. 1037
1.3. Instancier Zend_Mime .................................................................. 1038
2. Zend_Mime_Message ............................................................................. 1038
2.1. Introduction ................................................................................. 1038
2.2. Instancier Zend_Mime_Message ................................................... 1038
2.3. Ajouter des parties MIME ............................................................. 1038
2.4. Gérer les frontières ...................................................................... 1038
2.5. Parser une chaîne de caractère pour créer un objet
Zend_Mime_Message (expérimental) .................................................. 1039
3. Zend_Mime_Part .................................................................................... 1039
3.1. Introduction ................................................................................. 1039
3.2. Instanciation ................................................................................ 1039
3.3. Méthodes pour retourner la partie du message en une chaîne de
caractères .......................................................................................... 1039
Zend_Navigation ................................................................................................ 1041
1. Introduction ............................................................................................ 1041
1.1. Pages et Conteneurs ................................................................... 1041
1.2. Séparation des données (modèle) et du rendu (vue) ...................... 1041
2. Pages .................................................................................................... 1041
2.1. Caractéristiques communes aux pages ......................................... 1042
2.2. Zend_Navigation_Page_Mvc ........................................................ 1044
2.3. Zend_Navigation_Page_Uri .......................................................... 1048
2.4. Créer des pages de type personnalisé .......................................... 1049
2.5. Créer des pages avec la fabrique ................................................. 1050
3. Containers ............................................................................................. 1052
3.1. Creating containers ...................................................................... 1052
3.2. Adding pages .............................................................................. 1055
3.3. Removing pages ......................................................................... 1055
3.4. Finding pages ............................................................................. 1056
3.5. Iterating containers ...................................................................... 1058
3.6. Other operations .......................................................................... 1058
Zend_Oauth ....................................................................................................... 1061
1. Introduction to OAuth ............................................................................. 1061
1.1. Protocol Workflow ........................................................................ 1061
1.2. Security Architecture .................................................................... 1062
1.3. Getting Started ............................................................................ 1063
Zend_OpenId ..................................................................................................... 1067
1. Introduction ............................................................................................ 1067
1.1. Qu'est ce qu'OpenID ? ................................................................. 1067
1.2. Comment cela fonctionne-t-il ? ..................................................... 1067

xxi
Guide de référence
du programmeur

1.3. Zend_OpenId Structure ................................................................ 1068


1.4. Standards OpenID supportés ....................................................... 1068
2. Zend_OpenId_Consumer Basics ............................................................. 1068
2.1. OpenID Authentication ................................................................. 1068
2.2. Combining all Steps in One Page ................................................. 1070
2.3. Consumer Realm ......................................................................... 1070
2.4. Immediate Check ......................................................................... 1071
2.5. Zend_OpenId_Consumer_Storage ................................................ 1071
2.6. Simple Registration Extension ...................................................... 1074
2.7. Integration with Zend_Auth ........................................................... 1075
2.8. Integration with Zend_Controller ................................................... 1077
3. Zend_OpenId_Provider ........................................................................... 1077
3.1. Quick Start .................................................................................. 1077
3.2. Combined Provide Scripts ............................................................ 1080
3.3. Simple Registration Extension ...................................................... 1081
3.4. Anything Else? ............................................................................ 1083
Zend_Paginator .................................................................................................. 1084
1. Introduction ............................................................................................ 1084
2. Utilisation ............................................................................................... 1084
2.1. Paginer des collections de données .............................................. 1084
2.2. The DbSelect and DbTableSelect adapter ..................................... 1085
2.3. Rendre des pages avec les scripts de vue .................................... 1086
3. Configuration .......................................................................................... 1090
4. Utilisation avancée ................................................................................. 1091
4.1. Adaptateurs de source de données personnalisée ......................... 1091
4.2. Styles de défilement personnalisés ............................................... 1091
4.3. Fonctionnalité de mise en cache .................................................. 1092
4.4. Zend_Paginator_AdapterAggregate Interface ................................. 1093
Zend_Pdf ........................................................................................................... 1094
1. Introduction ............................................................................................ 1094
2. Créer et charger des documents PDF ..................................................... 1094
3. Sauvegarder les changement dans un document PDF .............................. 1095
4. Les pages d'un document ....................................................................... 1095
4.1. Création de page ......................................................................... 1095
4.2. Clonage de page ......................................................................... 1096
5. Dessiner ................................................................................................ 1097
5.1. Géométrie ................................................................................... 1097
5.2. Couleurs ..................................................................................... 1097
5.3. Dessiner des formes .................................................................... 1098
5.4. Dessiner du texte ........................................................................ 1100
5.5. Utiliser des polices de caractères ................................................. 1101
5.6. Limitations des polices standard PDF ........................................... 1103
5.7. Extraction des polices .................................................................. 1104
5.8. Insertion d'images ........................................................................ 1106
5.9. Style de lignes ............................................................................ 1106
5.10. Style de remplissage .................................................................. 1107
5.11. Transformations linéaires ........................................................... 1108
5.12. Sauvegarder et restaurer l'état graphique .................................... 1109
5.13. Zone de dessin .......................................................................... 1109
5.14. Styles ........................................................................................ 1110
5.15. Transparence ............................................................................ 1113
6. Interactive Features ................................................................................ 1113
6.1. Destinations ................................................................................ 1113
6.2. Actions ........................................................................................ 1118

xxii
Guide de référence
du programmeur

6.3. Document Outline (bookmarks) ..................................................... 1120


6.4. Annotations ................................................................................. 1122
7. Informations du document et métadonnées .............................................. 1123
8. Exemple d'utilisation du module Zend_Pdf ............................................... 1125
Zend_ProgressBar .............................................................................................. 1127
1. Zend_ProgressBar .................................................................................. 1127
1.1. Introduction ................................................................................. 1127
1.2. Utilisation basique de Zend_Progressbar ....................................... 1127
1.3. Adaptateurs standard ................................................................... 1127
Zend_Queue ...................................................................................................... 1132
1. Introduction ............................................................................................ 1132
2. Example usage ...................................................................................... 1132
3. Framework ............................................................................................. 1133
3.1. Introduction ................................................................................. 1134
3.2. Commonality among adapters ...................................................... 1134
4. Adapters ................................................................................................ 1134
4.1. Specific Adapters - Configuration settings ...................................... 1135
4.2. Notes for Specific Adapters .......................................................... 1137
5. Customizing Zend_Queue ....................................................................... 1139
5.1. Creating your own adapter ........................................................... 1139
5.2. Creating your own message class ................................................ 1140
5.3. Creating your own message iterator class ..................................... 1141
5.4. Creating your own queue class ................................................... 1141
6. Stomp .................................................................................................... 1141
6.1. Stomp - Supporting classes .......................................................... 1141
Zend_Reflection ................................................................................................. 1142
1. Introduction ............................................................................................ 1142
2. Zend_Reflection Exemples ...................................................................... 1142
3. Réference de Zend_Reflection ................................................................ 1143
3.1. Zend_Reflection_Docblock ........................................................... 1144
3.2. Zend_Reflection_Docblock_Tag .................................................... 1144
3.3. Zend_Reflection_Docblock_Tag_Param ........................................ 1144
3.4. Zend_Reflection_Docblock_Tag_Return ........................................ 1145
3.5. Zend_Reflection_File ................................................................... 1145
3.6. Zend_Reflection_Class ................................................................ 1145
3.7. Zend_Reflection_Extension .......................................................... 1146
3.8. Zend_Reflection_Function ............................................................ 1146
3.9. Zend_Reflection_Method .............................................................. 1146
3.10. Zend_Reflection_Parameter ........................................................ 1146
3.11. Zend_Reflection_Property .......................................................... 1147
Zend_Registry .................................................................................................... 1148
1. Utiliser le registre ................................................................................... 1148
1.1. Mettre des valeurs dans le registre ............................................... 1148
1.2. Lire des valeurs du registre .......................................................... 1148
1.3. Construire un objet registre .......................................................... 1148
1.4. Accéder au registre comme à un tableau ...................................... 1149
1.5. Accéder au registre comme à un objet .......................................... 1149
1.6. Vérifier si un index existe ............................................................. 1150
1.7. Étendre le registre ....................................................................... 1150
1.8. Décharger le registre statique ....................................................... 1151
Zend_Rest ......................................................................................................... 1152
1. Introduction ............................................................................................ 1152
2. Zend_Rest_Client ................................................................................... 1152
2.1. Introduction ................................................................................. 1152

xxiii
Guide de référence
du programmeur

2.2. Réponses .................................................................................... 1153


2.3. Arguments de requêtes ................................................................ 1154
3. Zend_Rest_Server .................................................................................. 1155
3.1. Introduction ................................................................................. 1155
3.2. Utilisation d'un serveur REST ....................................................... 1155
3.3. Appelé un service Zend_Rest_Server ........................................... 1156
3.4. Envoyer un statut personnalisé ..................................................... 1156
3.5. Renvoyer une réponse XML personnalisée .................................... 1157
Zend_Search_Lucene ......................................................................................... 1158
1. Vue d'ensemble ..................................................................................... 1158
1.1. Introduction ................................................................................. 1158
1.2. Objet "Document" et "Field" .......................................................... 1158
1.3. Comprendre les types de champs ................................................. 1160
1.4. Documents HTML ........................................................................ 1160
1.5. Documents Word 2007 ................................................................ 1161
1.6. Document Powerpoint 2007 ......................................................... 1163
1.7. Documents Excel 2007 ................................................................ 1164
2. Créer des index ..................................................................................... 1165
2.1. Créer un nouvel index ................................................................. 1165
2.2. Mettre à jour un index .................................................................. 1165
2.3. Mise à jour de Documents ........................................................... 1165
2.4. Récupération de la taille de l'index ................................................ 1166
2.5. Optimisation d'index ..................................................................... 1166
2.6. Permissions ................................................................................. 1168
2.7. Limitations ................................................................................... 1168
3. Searching an Index ................................................................................ 1168
3.1. Building Queries .......................................................................... 1168
3.2. Search Results ............................................................................ 1170
3.3. Limiting the Result Set ................................................................. 1171
3.4. Results Scoring ........................................................................... 1171
3.5. Search Result Sorting .................................................................. 1172
3.6. Search Results Highlighting .......................................................... 1172
4. Langage de requêtes ............................................................................. 1174
4.1. Termes ....................................................................................... 1174
4.2. Champs ...................................................................................... 1175
4.3. Jokers (Wildcards) ....................................................................... 1175
4.4. Term Modifiers ............................................................................ 1176
4.5. Range Searches .......................................................................... 1176
4.6. Fuzzy Searches ........................................................................... 1177
4.7. Matched terms limitation .............................................................. 1177
4.8. Proximity Searches ...................................................................... 1177
4.9. Boosting a Term .......................................................................... 1177
4.10. Boolean Operators ..................................................................... 1178
4.11. Grouping ................................................................................... 1179
4.12. Field Grouping ........................................................................... 1179
4.13. Escaping Special Characters ...................................................... 1180
5. API de construction de requêtes ............................................................. 1180
5.1. Les Exceptions du parseur de requêtes ........................................ 1180
5.2. Requête sur un terme .................................................................. 1181
5.3. Requête multi-termes ................................................................... 1181
5.4. Requête booléene ....................................................................... 1182
5.5. Requête Joker (wildcard) ............................................................. 1184
5.6. Requête floue (fuzzy query) ......................................................... 1184
5.7. Requête de phrase ...................................................................... 1185

xxiv
Guide de référence
du programmeur

5.8. Requête d'intervalle ..................................................................... 1187


6. Jeu de caractères .................................................................................. 1188
6.1. Support UTF-8 et caractères sur un octet ...................................... 1188
6.2. Analyseur de texte par défaut ....................................................... 1188
6.3. Analyseurs de texte compatibles UTF-8 ........................................ 1188
7. Extensibilité ............................................................................................ 1190
7.1. Analyse de texte .......................................................................... 1190
7.2. Filtrage des segments .................................................................. 1192
7.3. Algorithme de score ..................................................................... 1193
7.4. Conteneur de stockage ................................................................ 1194
8. Agir avec Lucene Java ........................................................................... 1196
8.1. Formats de fichier ........................................................................ 1196
8.2. Répertoire Index .......................................................................... 1196
8.3. Code source Java ....................................................................... 1196
9. Avancé .................................................................................................. 1197
9.1. Depuis Zend Framework 1.6, gestion des transformations de format
d'index ............................................................................................... 1197
9.2. Utiliser les propriétés statiques de l'index ...................................... 1198
10. Bonnes pratiques ................................................................................. 1199
10.1. Nommage des champs .............................................................. 1199
10.2. Performance de l'indexation ........................................................ 1200
10.3. Indexation à l'arrêt du programme ............................................... 1202
10.4. Récupération de documents par leur id unique ............................. 1202
10.5. Utilisation de la mémoire ............................................................ 1203
10.6. Encodage .................................................................................. 1204
10.7. Maintenance de l'index ............................................................... 1205
Zend_Serializer .................................................................................................. 1206
1. Introduction ............................................................................................ 1206
1.1. Utiliser l'interface statique de Zend_Serializer ................................ 1206
2. Zend_Serializer_Adapter ......................................................................... 1207
2.1. Zend_Serializer_Adapter_PhpSerialize .......................................... 1207
2.2. Zend_Serializer_Adapter_Igbinary ................................................. 1207
2.3. Zend_Serializer_Adapter_Wddx .................................................... 1207
2.4. Zend_Serializer_Adapter_Json ..................................................... 1208
2.5. Zend_Serializer_Adapter_Amf 0 et 3 ............................................. 1208
2.6. Zend_Serializer_Adapter_PythonPickle ......................................... 1208
2.7. Zend_Serializer_Adapter_PhpCode ............................................... 1209
Zend_Server ...................................................................................................... 1210
1. Introduction ............................................................................................ 1210
2. Zend_Server_Reflection .......................................................................... 1210
2.1. Introduction ................................................................................. 1210
2.2. Utilisation .................................................................................... 1210
Zend_Service ..................................................................................................... 1212
1. Introduction ............................................................................................ 1212
2. Zend_Service_Akismet ........................................................................... 1212
2.1. Introduction ................................................................................. 1212
2.2. Verify an API key ........................................................................ 1213
2.3. Check for spam ........................................................................... 1213
2.4. Submitting known spam ............................................................... 1214
2.5. Submitting false positives (ham) ................................................... 1214
2.6. Zend-specific Methods ................................................................. 1215
3. Zend_Service_Amazon ........................................................................... 1215
3.1. Introduction ................................................................................. 1215
3.2. Codes de pays ............................................................................ 1216

xxv
Guide de référence
du programmeur

3.3. Rechercher un produit Amazon spécifique avec son ASIN .............. 1217
3.4. Lancer des recherches de produits sur Amazon ............................. 1217
3.5. Utiliser l'API alternative de requêtes .............................................. 1218
3.6. Classes Zend_Service_Amazon ................................................... 1218
4. Zend_Service_Amazon_Ec2 ................................................................... 1224
4.1. Introduction ................................................................................. 1224
4.2. What is Amazon Ec2? ................................................................. 1224
4.3. Static Methods ............................................................................ 1224
5. Zend_Service_Amazon_Ec2: Instances ................................................... 1224
5.1. Instance Types ............................................................................ 1224
5.2. Running Amazon EC2 Instances .................................................. 1226
5.3. Amazon Instance Utilities ............................................................. 1227
6. Zend_Service_Amazon_Ec2: Windows Instances ..................................... 1229
6.1. Windows Instances Usage ........................................................... 1230
7. Zend_Service_Amazon_Ec2: Reserved Instances .................................... 1231
7.1. How Reserved Instances are Applied ............................................ 1231
7.2. Reserved Instances Usage ........................................................... 1231
8. Zend_Service_Amazon_Ec2: CloudWatch Monitoring ............................... 1232
8.1. CloudWatch Usage ...................................................................... 1232
9. Zend_Service_Amazon_Ec2: Amazon Machine Images (AMI) ................... 1234
9.1. AMI Information Utilities ............................................................... 1234
9.2. AMI Attribute Utilities ................................................................... 1235
10. Zend_Service_Amazon_Ec2: Elastic Block Stroage (EBS) ....................... 1236
10.1. Create EBS Volumes and Snapshots .......................................... 1237
10.2. Describing EBS Volumes and Snapshots .................................... 1237
10.3. Attach and Detaching Volumes from Instances ............................ 1238
10.4. Deleting EBS Volumes and Snapshots ........................................ 1239
11. Zend_Service_Amazon_Ec2: Elastic IP Addresses ................................. 1239
12. Zend_Service_Amazon_Ec2: Keypairs ................................................... 1240
13. Zend_Service_Amazon_Ec2: Regions and Availability Zones ................... 1241
13.1. Amazon EC2 Regions ................................................................ 1241
13.2. Amazon EC2 Availability Zones .................................................. 1242
14. Zend_Service_Amazon_Ec2: Security Groups ........................................ 1242
14.1. Security Group Maintenance ....................................................... 1242
14.2. Authorizing Access .................................................................... 1243
14.3. Revoking Access ....................................................................... 1244
15. Zend_Service_Amazon_S3 ................................................................... 1245
15.1. Introduction ............................................................................... 1245
15.2. Registering with Amazon S3 ....................................................... 1245
15.3. API Documentation .................................................................... 1245
15.4. Features .................................................................................... 1245
15.5. Getting Started .......................................................................... 1245
15.6. Bucket operations ...................................................................... 1246
15.7. Object operations ....................................................................... 1247
15.8. Data Streaming ......................................................................... 1249
15.9. Stream wrapper ......................................................................... 1249
16. Zend_Service_Amazon_Sqs .................................................................. 1250
16.1. Introduction ............................................................................... 1250
16.2. Registering with Amazon SQS .................................................... 1250
16.3. API Documentation .................................................................... 1250
16.4. Features .................................................................................... 1250
16.5. Getting Started .......................................................................... 1250
16.6. Queue operations ...................................................................... 1251
16.7. Message operations ................................................................... 1252

xxvi
Guide de référence
du programmeur

17. Zend_Service_Audioscrobbler ............................................................... 1252


17.1. Introduction ............................................................................... 1252
17.2. Users ........................................................................................ 1253
17.3. Artists ........................................................................................ 1254
17.4. Tracks ....................................................................................... 1255
17.5. Tags ......................................................................................... 1255
17.6. Groups ...................................................................................... 1255
17.7. Forums ...................................................................................... 1256
18. Zend_Service_Delicious ........................................................................ 1256
18.1. Introduction ............................................................................... 1256
18.2. Récupérer vos entrées ............................................................... 1256
18.3. Zend_Service_Delicious_PostList ................................................ 1257
18.4. Édition des entrées .................................................................... 1258
18.5. Supprimer des entrées ............................................................... 1259
18.6. Ajout d'entrées .......................................................................... 1259
18.7. Les étiquettes ("tags") ................................................................ 1260
18.8. Les groupes d'étiquettes ............................................................ 1260
18.9. Données publiques .................................................................... 1260
18.10. Client HTTP ............................................................................. 1261
19. Zend_Service_DeveloperGarden ........................................................... 1262
19.1. Introduction to DeveloperGarden ................................................. 1262
19.2. BaseUserService ....................................................................... 1263
19.3. IP Location ................................................................................ 1264
19.4. Local Search ............................................................................. 1264
19.5. Send SMS ................................................................................. 1265
19.6. SMS Validation .......................................................................... 1265
19.7. Voice Call ................................................................................. 1266
19.8. ConferenceCall .......................................................................... 1267
19.9. Performance and Caching .......................................................... 1268
20. Zend_Service_Flickr ............................................................................. 1269
20.1. Introduction ............................................................................... 1269
20.2. Trouver les photos et les informations des utilisateurs Flickr .......... 1269
20.3. Trouver des photos dans le pool d'un groupe ............................... 1270
20.4. Récupérer les détails d'une image .............................................. 1270
20.5. Classes de résultats Zend_Service_Flickr .................................... 1270
21. Zend_Service_LiveDocx ........................................................................ 1272
21.1. Introduction to LiveDocx ............................................................. 1272
21.2. Zend_Service_LiveDocx_MailMerge ............................................ 1274
22. Zend_Service_Nirvanix ......................................................................... 1286
22.1. Introduction ............................................................................... 1286
22.2. Registering with Nirvanix ............................................................ 1286
22.3. API Documentation .................................................................... 1286
22.4. Features .................................................................................... 1287
22.5. Getting Started .......................................................................... 1287
22.6. Understanding the Proxy ............................................................ 1288
22.7. Examining Results ..................................................................... 1288
22.8. Handling Errors ......................................................................... 1289
23. Zend_Service_ReCaptcha ..................................................................... 1290
23.1. Introduction ............................................................................... 1290
23.2. Utilisation la plus simple ............................................................. 1290
23.3. Hiding email addresses .............................................................. 1291
24. Zend_Service_Simpy ............................................................................ 1292
24.1. Introduction ............................................................................... 1292
24.2. Liens ......................................................................................... 1292

xxvii
Guide de référence
du programmeur

24.3. Mots-clés ................................................................................... 1294


24.4. Notes ........................................................................................ 1295
24.5. Listes de surveillance ................................................................. 1296
25. Introduction .......................................................................................... 1297
25.1. Démarrage avec Zend_Service_SlideShare .......................... 1297
25.2. L'objet SlideShow ...................................................................... 1298
25.3. Récupérer un diaporama simplement .......................................... 1300
25.4. Récupérer des groupes de diaporamas ....................................... 1300
25.5. Politique de cache de Zend_Service_SlideShare ................... 1301
25.6. Changer le comportement du client HTTP ................................... 1302
26. Zend_Service_StrikeIron ....................................................................... 1302
26.1. Overview ................................................................................... 1302
26.2. Registering with StrikeIron .......................................................... 1303
26.3. Getting Started .......................................................................... 1303
26.4. Making Your First Query ............................................................ 1303
26.5. Examining Results ..................................................................... 1304
26.6. Handling Errors ......................................................................... 1305
26.7. Checking Your Subscription ........................................................ 1305
27. Zend_Service_StrikeIron: Bundled Services ........................................... 1306
27.1. ZIP Code Information ................................................................. 1306
27.2. U.S. Address Verification ............................................................ 1307
27.3. Sales & Use Tax Basic .............................................................. 1308
28. Zend_Service_StrikeIron: Advanced Uses .............................................. 1308
28.1. Using Services by WSDL ........................................................... 1308
28.2. Viewing SOAP Transactions ....................................................... 1309
29. Zend_Service_Technorati ...................................................................... 1309
29.1. Introduction ............................................................................... 1309
29.2. Getting Started .......................................................................... 1310
29.3. Making Your First Query ............................................................ 1310
29.4. Consuming Results .................................................................... 1311
29.5. Handling Errors ......................................................................... 1312
29.6. Checking Your API Key Daily Usage ........................................... 1312
29.7. Available Technorati Queries ...................................................... 1313
29.8. Zend_Service_Technorati Classes .............................................. 1316
30. Zend_Service_Twitter ........................................................................... 1319
30.1. Introduction ............................................................................... 1319
30.2. Authentication ............................................................................ 1320
30.3. Account Methods ....................................................................... 1320
30.4. Status Methods ......................................................................... 1321
30.5. User Methods ............................................................................ 1323
30.6. Direct Message Methods ............................................................ 1323
30.7. Friendship Methods ................................................................... 1324
30.8. Favorite Methods ....................................................................... 1325
30.9. Block Methods ........................................................................... 1325
30.10. Zend_Service_Twitter_Search ................................................... 1326
31. Zend_Service_WindowsAzure ............................................................... 1328
31.1. Introduction ............................................................................... 1328
31.2. Installing the Windows Azure SDK .............................................. 1328
31.3. API Documentation .................................................................... 1328
31.4. Features .................................................................................... 1328
31.5. Architecture ............................................................................... 1328
31.6. Zend_Service_WindowsAzure_Storage_Blob ............................... 1328
31.7. Zend_Service_WindowsAzure_Storage_Table ............................. 1333
31.8. Zend_Service_WindowsAzure_Storage_Queue ............................ 1340

xxviii
Guide de référence
du programmeur

32. Zend_Service_Yahoo ............................................................................ 1342


32.1. Introduction ............................................................................... 1342
32.2. Rechercher sur le Web avec Yahoo! ........................................... 1342
32.3. Trouver des images avec Yahoo! ................................................ 1343
32.4. Trouver des vidéos avec Yahoo! ................................................. 1343
32.5. Trouver des entreprises et des services locaux avec Yahoo! ......... 1343
32.6. Rechercher dans Yahoo! News ................................................... 1343
32.7. Rechercher avec Yahoo! Site Explorer Inbound Links ................... 1344
32.8. Rechercher avec Yahoo! Site Explorer's PageData ...................... 1344
32.9. Classes Zend_Service_Yahoo .................................................... 1344
Zend_Session .................................................................................................... 1351
1. Introduction ............................................................................................ 1351
2. Usage basique ....................................................................................... 1351
2.1. Tutoriel d'exemples ...................................................................... 1352
2.2. Énumérer les espaces de noms de session ................................... 1353
2.3. Accesseurs pour les espaces de noms de session ......................... 1353
3. Utilisation avancée ................................................................................. 1354
3.1. Démarrer une session .................................................................. 1354
3.2. Verrouiller les espaces de noms de session .................................. 1355
3.3. Expiration d'un espace de noms ................................................... 1355
3.4. Encapsulation de session et Contrôleurs ....................................... 1356
3.5. Limiter les instances multiples par espace de noms ....................... 1357
3.6. Travailler avec les tableaux .......................................................... 1357
3.7. Utiliser les sessions avec des objets ............................................. 1358
3.8. Utiliser les sessions avec les tests unitaires ................................... 1359
4. Gestion générale de la session ............................................................... 1360
4.1. Options de configuration .............................................................. 1361
4.2. L'erreur: "Headers Already Sent" .................................................. 1364
4.3. Identifiants de session ................................................................. 1364
4.4. rememberMe(integer $seconds) ........................................... 1365
4.5. forgetMe() ............................................................................... 1366
4.6. sessionExists() ..................................................................... 1366
4.7. destroy(bool $remove_cookie = true, bool $readonly
= true) ........................................................................................... 1366
4.8. stop() ....................................................................................... 1366
4.9. writeClose($readonly = true) .......................................... 1366
4.10. expireSessionCookie() ....................................................... 1367
4.11. setSaveHandler(Zend_Session_SaveHandler_Interface
$interface) .................................................................................... 1367
4.12. namespaceIsset($namespace) ............................................. 1367
4.13. namespaceUnset($namespace) ............................................. 1367
4.14. namespaceGet($namespace) ................................................. 1367
4.15. getIterator() ....................................................................... 1367
5. Zend_Session_SaveHandler_DbTable ..................................................... 1368
Zend_Soap ........................................................................................................ 1370
1. Zend_Soap_Server ................................................................................. 1370
1.1. Constructeur de Zend_Soap_Server .......................................... 1370
1.2. Méthodes de définitions de l'API du service ................................... 1371
1.3. Gestion des objets de requête et de réponse ................................. 1372
2. Zend_Soap_Client .................................................................................. 1374
2.1. Constructeur de Zend_Soap_Client .......................................... 1374
2.2. Effectuer des requêtes SOAP ....................................................... 1375
3. WSDL .................................................................................................... 1376
3.1. Constructeur Zend_Soap_Wsdl .................................................... 1376

xxix
Guide de référence
du programmeur

3.2. addMessage() ............................................................................. 1376


3.3. addPortType() ......................................................................... 1377
3.4. addPortOperation() ............................................................... 1377
3.5. addBinding() ........................................................................... 1378
3.6. addBindingOperation() ......................................................... 1378
3.7. addSoapBinding() ................................................................... 1378
3.8. addSoapOperation() ............................................................... 1378
3.9. addService() ........................................................................... 1379
3.10. Correspondance de type ............................................................ 1379
3.11. addDocumentation() ............................................................. 1381
3.12. Récupérer un document WSDL finalisé ....................................... 1381
4. Auto découverte ..................................................................................... 1381
4.1. Introduction à l'auto découverte .................................................... 1381
4.2. Auto découverte de classe ........................................................... 1383
4.3. Auto découverte des fonctions ...................................................... 1383
4.4. Types de donnée auto découverts ................................................ 1384
4.5. Styles de liaisons WSDL .............................................................. 1385
Zend_Tag .......................................................................................................... 1386
1. Introduction ............................................................................................ 1386
2. Zend_Tag_Cloud .................................................................................... 1386
2.1. Decorateurs ................................................................................. 1387
Zend_Test .......................................................................................................... 1389
1. Introduction ............................................................................................ 1389
2. Zend_Test_PHPUnit ............................................................................... 1389
2.1. Amorcer votre TestCase .............................................................. 1391
2.2. Tester vos contrôleurs et vos applications MVC ............................. 1392
2.3. Assertions ................................................................................... 1394
2.4. Exemples .................................................................................... 1396
3. Zend_Test_PHPUnit_Db ......................................................................... 1398
3.1. Quickstart .................................................................................... 1398
3.2. Utilisation, API et possibilités d'extension ...................................... 1402
3.3. Utiliser l'adaptateur de tests ......................................................... 1404
Zend_Text .......................................................................................................... 1406
1. Zend_Text_Figlet .................................................................................... 1406
2. Zend_Text_Table ................................................................................... 1407
Zend_TimeSync ................................................................................................. 1410
1. Introduction ............................................................................................ 1410
1.1. Pourquoi Zend_TimeSync ? ........................................................ 1410
1.2. Qu'est ce que NTP ? ................................................................... 1411
1.3. Qu'est ce que SNTP? .................................................................. 1411
1.4. Problèmes courants d'utilisation .................................................... 1411
1.5. Décider quel serveur de temps utiliser .......................................... 1411
2. Utiliser Zend_TimeSync .......................................................................... 1412
2.1. Requêter un serveur de temps public ............................................ 1412
2.2. Serveurs de temps multiples ........................................................ 1412
2.3. Les protocoles des serveurs de temps .......................................... 1413
2.4. Utiliser les ports pour les serveurs de temps .................................. 1413
2.5. Options pour les serveurs de temps .............................................. 1413
2.6. Utiliser des serveurs de temps différents ....................................... 1414
2.7. Informations sur les serveurs de temps ......................................... 1414
2.8. Gérer les exceptions .................................................................... 1414
Zend_Tool .......................................................................................................... 1416
1. Using Zend_Tool On The Command Line ................................................ 1416
1.1. Installation ................................................................................... 1416

xxx
Guide de référence
du programmeur

1.2. General Purpose Commands ....................................................... 1417


1.3. Project Specific Commands .......................................................... 1417
1.4. Environment Customization .......................................................... 1420
2. Extending Zend_Tool .............................................................................. 1421
2.1. Overview of Zend_Tool ................................................................ 1421
2.2. Zend_Tool_Framework Extensions ............................................... 1422
2.3. Zend_Tool_Project Extensions ..................................................... 1430
Zend_Tool_Framework ....................................................................................... 1432
1. Introduction ............................................................................................ 1432
2. Using the CLI Tool ................................................................................. 1432
2.1. Setting up the CLI tool ................................................................. 1433
2.2. Setting up the CLI tool on Unix-like Systems ................................. 1433
2.3. Setting up the CLI tool on Windows .............................................. 1435
2.4. Other Setup Considerations ......................................................... 1436
2.5. Where To Go Next? .................................................................... 1436
3. Architecture ............................................................................................ 1437
3.1. Registry ...................................................................................... 1437
3.2. Providers ..................................................................................... 1438
3.3. Loaders ....................................................................................... 1439
3.4. Manifests .................................................................................... 1440
3.5. Clients ........................................................................................ 1442
4. Creating Providers to use with Zend_Tool_Framework .............................. 1442
4.1. How Zend Tool finds your Providers ............................................. 1443
4.2. Basic Instructions for Creating Providers ....................................... 1443
4.3. The response object .................................................................... 1444
4.4. Advanced Development Information .............................................. 1444
5. Shipped System Providers ...................................................................... 1447
5.1. The Version Provider ................................................................... 1447
5.2. The Manifest Provider .................................................................. 1447
6. Extending and Configuring Zend_Tool_Framework ................................... 1447
6.1. Customizing Zend_Tool Console Client ......................................... 1447
Zend_Tool_Project ............................................................................................. 1450
1. Introduction ............................................................................................ 1450
2. Créer un projet ....................................................................................... 1450
3. Fournisseurs de Zend_Tool_Project ........................................................ 1451
4. Rouages internes de Zend_Tool_Project .................................................. 1451
4.1. Structure xml interne de Zend_Tool_Project .................................. 1451
4.2. Etendre les rouages de Zend_Tool_Project ................................... 1451
Zend_Translate .................................................................................................. 1452
1. Introduction ............................................................................................ 1452
1.1. Démarrer avec le multi-linguisme .................................................. 1452
2. Adaptateurs pour Zend_Translate ............................................................ 1453
2.1. Comment décider quel adaptateur de traduction utiliser ? ............... 1454
2.2. Intégrer ses propres adaptateurs .................................................. 1456
2.3. Améliorer les performances de tous les adaptateurs ....................... 1456
3. Utiliser les adaptateurs de traduction ....................................................... 1457
3.1. Structures des sources de traduction ............................................ 1458
3.2. Créer des fichiers sources de type tableau .................................... 1460
3.3. Créer des fichiers sources Gettext ................................................ 1461
3.4. Créer des fichiers source TMX ..................................................... 1462
3.5. Créer des fichiers source CSV ..................................................... 1462
3.6. Créer des fichiers sources INI ...................................................... 1463
3.7. Options pour les adaptateurs ........................................................ 1464
3.8. Gérer les langues ........................................................................ 1466

xxxi
Guide de référence
du programmeur

3.9. Détéction automatique de la source .............................................. 1468


3.10. Vérifier les traductions ................................................................ 1471
3.11. How to log not found translations ................................................ 1472
3.12. Access to the source data .......................................................... 1473
4. Creating source files ............................................................................... 1474
4.1. Creating Array source files ........................................................... 1474
4.2. Creating Gettext source files ........................................................ 1474
4.3. Creating TMX source files ............................................................ 1475
4.4. Creating CSV source files ............................................................ 1476
4.5. Creating INI source files ............................................................... 1476
5. Additional features for translation ............................................................ 1477
5.1. Options for adapters .................................................................... 1477
5.2. Handling languages ..................................................................... 1480
5.3. Automatic source detection .......................................................... 1482
5.4. Checking for translations .............................................................. 1484
5.5. How to log not found translations .................................................. 1485
5.6. Accessing source data ................................................................. 1486
6. Notation des pluriels pour Translation ...................................................... 1487
6.1. Méthode traditionnelle .................................................................. 1487
6.2. Méthode moderne de traduction du pluriel ..................................... 1487
6.3. Fichiers sources de pluriels .......................................................... 1488
6.4. Custom plural rules ...................................................................... 1489
Zend_Uri ............................................................................................................ 1491
1. Zend_Uri ................................................................................................ 1491
1.1. Aperçu ........................................................................................ 1491
1.2. Créer un nouvel URI .................................................................... 1491
1.3. Manipuler un URI existant ............................................................ 1491
1.4. Validation d'URI ........................................................................... 1492
1.5. Méthodes communes ................................................................... 1492
Zend_Validate .................................................................................................... 1494
1. Introduction ............................................................................................ 1494
1.1. Qu'est-ce qu'un validateur ? ......................................................... 1494
1.2. Utilisation basique des validateurs ................................................ 1494
1.3. Messages personnalisés .............................................................. 1495
1.4. Utilisation de la méthode statique is() ........................................ 1496
1.5. Translating messages .................................................................. 1497
2. Classes de validation standard ................................................................ 1498
2.1. Alnum ......................................................................................... 1498
2.2. Alpha .......................................................................................... 1498
2.3. Barcode ...................................................................................... 1498
2.4. Between ...................................................................................... 1498
2.5. Ccnum ........................................................................................ 1499
2.6. Date ............................................................................................ 1499
2.7. Db_RecordExists et Db_NoRecordExists ....................................... 1499
2.8. Digits .......................................................................................... 1501
2.9. EmailAddress .............................................................................. 1501
2.10. Float ......................................................................................... 1503
2.11. GreaterThan .............................................................................. 1503
2.12. Hex ........................................................................................... 1503
2.13. Hostname .................................................................................. 1503
2.14. Iban .......................................................................................... 1505
2.15. InArray ...................................................................................... 1506
2.16. Int ............................................................................................. 1506
2.17. Ip .............................................................................................. 1506

xxxii
Guide de référence
du programmeur

2.18. LessThan .................................................................................. 1506


2.19. NotEmpty .................................................................................. 1506
2.20. Regex ....................................................................................... 1506
2.21. Validateurs de Sitemap .............................................................. 1506
2.22. StringLength .............................................................................. 1507
3. Chaînes de validation ............................................................................. 1507
4. Écrire des validateurs ............................................................................. 1508
5. Messages de validation .......................................................................... 1512
5.1. Limiter la taille d'un message de validation .................................... 1517
Zend_Version ..................................................................................................... 1519
1. Lire la version de Zend Framework ......................................................... 1519
Zend_View ......................................................................................................... 1520
1. Introduction ............................................................................................ 1520
1.1. Script du Contrôleur ..................................................................... 1520
1.2. Script de vue ............................................................................... 1520
1.3. Options ....................................................................................... 1521
1.4. Balises courtes dans les scripts de vue ......................................... 1521
1.5. Accesseurs utiles ......................................................................... 1522
2. Scripts de contrôleur .............................................................................. 1523
2.1. Assigner des variables ................................................................. 1523
2.2. Effectuer le rendu d'un script de vue ............................................. 1524
2.3. Chemin des scripts de vue ........................................................... 1524
3. Scripts de vue ........................................................................................ 1525
3.1. Échapper la sortie ....................................................................... 1525
3.2. Utiliser des systèmes de gabarit (template) alternatifs ..................... 1526
4. Aides de vue ......................................................................................... 1532
4.1. Aides initiales .............................................................................. 1532
4.2. Chemin des aides ........................................................................ 1584
4.3. Écrire des aides personnalisées ................................................... 1585
4.4. Registering Concrete Helpers ....................................................... 1586
5. Zend_View_Abstract ............................................................................... 1587
Zend_Wildfire ..................................................................................................... 1588
1. Zend_Wildfire ......................................................................................... 1588
Zend_XmlRpc .................................................................................................... 1589
1. Introduction ............................................................................................ 1589
2. Zend_XmlRpc_Client .............................................................................. 1589
2.1. Introduction ................................................................................. 1589
2.2. Appels de méthodes .................................................................... 1589
2.3. Types et conversions ................................................................... 1590
2.4. Objet proxy du serveur ................................................................ 1592
2.5. Gestion des erreurs ..................................................................... 1592
2.6. Introspection du serveur ............................................................... 1593
2.7. De la requête à la réponse ........................................................... 1594
2.8. Client HTTP et tests .................................................................... 1594
3. Zend_XmlRpc_Server ............................................................................. 1594
3.1. Introduction ................................................................................. 1594
3.2. Usage de base ............................................................................ 1594
3.3. Structures du serveur .................................................................. 1595
3.4. Conventions ................................................................................ 1595
3.5. Utiliser des espaces de noms (Namespaces) ................................. 1596
3.6. Requêtes personnalisées ............................................................. 1596
3.7. Réponses personnalisées ............................................................ 1596
3.8. Gérer les exceptions grâce aux erreurs (Faults) ............................. 1597
3.9. Cacher la définition du serveur entre les requêtes .......................... 1597

xxxiii
Guide de référence
du programmeur

3.10. Exemples d'utilisation ................................................................. 1598


ZendX_Console_Process_Unix ........................................................................... 1602
1. ZendX_Console_Process_Unix ............................................................... 1602
1.1. Introduction ................................................................................. 1602
1.2. Basic usage of ZendX_Console_Process_Unix .............................. 1602
ZendX_JQuery ................................................................................................... 1604
1. Introduction ............................................................................................ 1604
2. ZendX_JQuery View Helpers .................................................................. 1604
2.1. jQuery() View Helper ................................................................... 1604
2.2. JQuery Helpers ........................................................................... 1610
3. ZendX_JQuery Form Elements and Decorators ........................................ 1616
3.1. General Elements and Decorator Usage ....................................... 1616
3.2. Form Elements ............................................................................ 1617
3.3. Form Decorators ......................................................................... 1617
A. Configuration système requise par Zend Framework ................................................ 1620
A.1. Introduction ................................................................................................. 1620
A.1.1. Version de PHP requise ................................................................... 1620
A.1.2. Extensions PHP ............................................................................... 1620
A.1.3. Les composants de Zend Framework ................................................ 1624
A.1.4. Dépendances internes de Zend Framework ....................................... 1628
B. Notes de migration de Zend Framework .................................................................. 1649
B.1. Zend Framework 1.10 ................................................................................. 1649
B.1.1. Zend_Feed_Reader .......................................................................... 1650
B.1.2. Zend_File_Transfer ........................................................................... 1650
B.1.3. Zend_Filter_HtmlEntities ................................................................... 1651
B.1.4. Zend_Filter_StripTags ....................................................................... 1651
B.1.5. Zend_Translate ................................................................................ 1651
B.1.6. Zend_Validate .................................................................................. 1652
B.2. Zend Framework 1.9 ................................................................................... 1653
B.2.1. Zend_File_Transfer ........................................................................... 1653
B.2.2. Zend_Filter ....................................................................................... 1653
B.2.3. Zend_Http_Client .............................................................................. 1653
B.2.4. Zend_Locale .................................................................................... 1654
B.2.5. Zend_View_Helper_Navigation .......................................................... 1655
B.2.6. Security fixes as with 1.9.7 ............................................................... 1656
B.3. Zend Framework 1.8 ................................................................................... 1657
B.3.1. Zend_Controller ................................................................................ 1657
B.3.2. Zend_Locale .................................................................................... 1657
B.4. Zend Framework 1.7 ................................................................................... 1657
B.4.1. Zend_Controller ................................................................................ 1657
B.4.2. Zend_File_Transfer ........................................................................... 1657
B.4.3. Zend_Locale .................................................................................... 1661
B.4.4. Zend_Translate ................................................................................ 1663
B.4.5. Zend_View ....................................................................................... 1664
B.5. Zend Framework 1.6 ................................................................................... 1664
B.5.1. Zend_Controller ................................................................................ 1665
B.5.2. Zend_File_Transfer ........................................................................... 1665
B.6. Zend Framework 1.5 ................................................................................... 1665
B.6.1. Zend_Controller ................................................................................ 1665
B.7. Zend Framework 1.0 ................................................................................... 1667
B.7.1. Zend_Controller ................................................................................ 1667
B.7.2. Zend_Currency ................................................................................. 1669
B.8. Zend Framework 0.9 ................................................................................... 1669
B.8.1. Zend_Controller ................................................................................ 1669

xxxiv
Guide de référence
du programmeur

B.9. Zend Framework 0.8 ................................................................................... 1670


B.9.1. Zend_Controller ................................................................................ 1670
B.10. Zend Framework 0.6 ................................................................................. 1671
B.10.1. Zend_Controller .............................................................................. 1671
C. Convention de codage PHP de Zend Framework .................................................... 1674
C.1. Vue d'ensemble .......................................................................................... 1674
C.1.1. Portée ............................................................................................. 1674
C.1.2. Buts ................................................................................................. 1675
C.2. Formatage des fichiers PHP ........................................................................ 1675
C.2.1. Général ........................................................................................... 1675
C.2.2. Indentation ....................................................................................... 1675
C.2.3. Longueur maximum d'une ligne ......................................................... 1675
C.2.4. Terminaison de lignes ...................................................................... 1675
C.3. Conventions de nommage ........................................................................... 1675
C.3.1. Classes ........................................................................................... 1675
C.3.2. Abstract Classes .............................................................................. 1676
C.3.3. Interfaces ......................................................................................... 1676
C.3.4. Noms de fichiers .............................................................................. 1676
C.3.5. Fonctions et méthodes ..................................................................... 1677
C.3.6. Variables ......................................................................................... 1677
C.3.7. Constantes ....................................................................................... 1678
C.4. Style de codage .......................................................................................... 1678
C.4.1. Démarcation du code PHP ............................................................... 1678
C.4.2. Chaînes de caractères ...................................................................... 1678
C.4.3. Tableaux .......................................................................................... 1679
C.4.4. Classes ........................................................................................... 1680
C.4.5. Fonctions et méthodes ..................................................................... 1681
C.4.6. Structure de contrôle ........................................................................ 1684
C.4.7. Documentation intégrée .................................................................... 1685
D. Zend Framework Documentation Standard .............................................................. 1687
D.1. Overview .................................................................................................... 1687
D.1.1. Scope .............................................................................................. 1687
D.2. Documentation File Formatting .................................................................... 1687
D.2.1. XML Tags ........................................................................................ 1687
D.2.2. Maximum Line Length ...................................................................... 1688
D.2.3. Indentation ....................................................................................... 1688
D.2.4. Line Termination .............................................................................. 1688
D.2.5. Empty tags ...................................................................................... 1688
D.2.6. Usage of whitespace within documents .............................................. 1689
D.2.7. Program Listings .............................................................................. 1691
D.2.8. Notes on specific inline tags ............................................................. 1692
D.2.9. Notes on specific block tags ............................................................. 1693
D.3. Recommendations ...................................................................................... 1694
D.3.1. Use editors without autoformatting ..................................................... 1694
D.3.2. Use Images ..................................................................................... 1694
D.3.3. Use Case Examples ......................................................................... 1694
D.3.4. Avoid Replicating phpdoc Contents ................................................... 1694
D.3.5. Use Links ........................................................................................ 1694
E. Recommended Project Structure for Zend Framework MVC Applications ................... 1696
E.1. Overview .................................................................................................... 1696
E.2. Recommended Project Directory Structure .................................................... 1696
E.3. Module Structure ......................................................................................... 1698
E.4. Rewrite Configuration Guide ........................................................................ 1699
E.4.1. Apache HTTP Server ........................................................................ 1699

xxxv
Guide de référence
du programmeur

E.4.2. Microsoft Internet Information Server ................................................. 1699


F. Guide de performance Zend Framework ................................................................. 1701
F.1. Introduction ................................................................................................. 1701
F.2. Chargement des classes ............................................................................. 1701
F.2.1. Comment optimiser mon include_path ? ............................................. 1701
F.2.2. Comment éliminer les déclarations require_once non nécessaires ? ..... 1703
F.2.3. Comment accélérer le chargement des plugins ? ................................ 1704
F.3. Performance de Zend_Db ............................................................................ 1705
F.3.1. Comment réduire la surcharge introduite par Zend_Db_Table lors de la
récupération des métadonnées de table ? .................................................. 1705
F.3.2. Le SQL généré avec Zend_Db_Select n'utilise pas mes index ;
comment améliorer ceci ? .......................................................................... 1706
F.4. Internationalisation (i18n) and Localisation (l10n) ........................................... 1706
F.4.1. Quel adaptateur de traduction dois-je utiliser ? .................................... 1706
F.4.2. Comment peut-on améliorer les performances de la traduction et de la
localisation ? ............................................................................................. 1707
F.5. View Rendering ........................................................................................... 1707
F.5.1. How can I speed up resolution of view helpers? .................................. 1707
F.5.2. How can I speed up view partials? .................................................... 1709
F.5.3. How can I speed up calls to the action() view helper? .......................... 1709
G. Informations de copyright ....................................................................................... 1712

xxxvi
Partie I. Introduction
au Zend Framework
Table des matières
Présentation .................................................................................................................... 3
Installation ....................................................................................................................... 4

2
Présentation
Zend Framework (ZF) est un framework open-source destiné aux développements d'applications
web et de services web avec PHP5. Le Zend Framework est construit en utilisant 100% de
code orienté-objet. La structure des composants du Zend Framework est quelque peu unique ;
chaque composant est conçu avec de faibles dépendances envers les autres composants.
Cette architecture faiblement couplée permet aux développeurs d'utiliser les composants
individuellement. On appelle souvent ce type de conception "use-at-will".

Bien qu'ils puissent être utilisés individuellement, les composants de la librairie standard de
Zend Framework forment un framework d'application web puissant et extensible quand ils sont
combinés. Le ZF offre une robuste et performante implémentation du motif MVC, une abstraction
de base de données simple d'utilisation, et un composant de formulaire qui implémente un rendu
HTML, la validation et le filtrage des données, ainsi les développeurs peuvent consolider toutes
ces opérations en utilisant une interface orienté-objet facile d'utilisation. D'autres composants,
comme Zend_Auth ou Zend_Acl, fournissent l'authentification d'utilisateurs et l'autorisation
envers les solutions de stockage de crédits habituels. D'autres encore, implémentent des
librairies clientes pour simplifier l'accès aux services web disponibles les plus populaires.
Quelque soit le besoin de votre application, vous avez toutes les chances de trouver un
composant de Zend Framework qui peut être utilisé pour réduire drastiquement votre temps de
développement avec une base de tests solide.

Le sponsor principal du projet Zend Framework est Zend Technologies, mais un certain nombre
d'entreprises a contribué à des composants ou à des fonctionnalités significatives du framework.
Des entreprises comme Google, Microsoft et StrikeIron ont travaillé en partenariat avec Zend
pour fournir des interfaces vers des services web et d'autres technologies qu'ils souhaitaient
rendre disponible aux développeurs utilisant Zend Framework.

Zend Framework ne pourrait pas fournir et supporter toutes ces fonctionnalités sans l'aide de
la vibrante communauté du Zend Framework. Les membres de la communauté, incluant les
contributeurs, se rendent disponibles sur les listes de diffusion, canaux IRC, et autres forums.
Quelque soit la question que vous avez sur le Zend Framework, la communauté est toujours
disponible pour y répondre.

3
Installation
Veuillez vous reporter à l'annexe concernant la configuration système requise pour plus
d'informations.

Installer Zend Framework est extrêmement simple. Une fois que vous avez téléchargé et
décompressé le framework, vous devez ajouter le dossier "/library" de la distribution en début
de votre chemin d'inclusion ("include_path"). Vous pouvez bien entendu aussi déplacer la
librairie à tout autre position (partagée ou non) dans votre arborescence de fichiers.

• Téléchargement de la dernière version stable : Cette version, disponible à la fois au format


.zip et au format .tar.gz, est un bon choix pour ceux qui débutent avec Zend Framework.

• Téléchargement du dernier cliché nocturne : Pour ceux qui veulent être à l'avant-garde, les
clichés nocturnes représentent le dernier progrès de développement de Zend Framework.
Ces clichés sont empaquetés avec la documentation en anglais seulement ou dans toutes
les langues disponibles. Si vous prévoyez de travailler avec les derniers développements de
Zend Framework, considérez plutôt l'emploi d'un client subversion (SVN).

• Utilisation d'un client Subversion (SVN) : Zend Framework est un logiciel open-source,
et le référentiel Subversion utilisé pour son développement est disponible publiquement.
Considérer l'utilisation de SVN pour récupérer Zend Framework si vous utilisez déjà SVN pour
vos propres développements, si vous voulez contribuer à l'évolution du framework, ou si vous
désirez mettre à jour votre version du framework plus souvent que les sorties stables.

L'exportation est utile si vous souhaitez obtenir une révision particulière du framework sans
les dossiers .svn créé dans une copie de travail.

L'extraction d'une copie de travail est intéressante si vous contribuez à Zend Framework, et
une copie de travail peut être mise à jour à n'importe quel moment avec svn update et les
changements peuvent être livrés au référentiel SVN avec la commande svn commit.

Une définition externe est très pratique pour les développeurs utilisant déjà SVN pour gérer
les copies de travail de leurs applications.

L'URL du tronc du référentiel SVN de Zend Framework est : http://framework.zend.com/svn/


framework/standard/trunk

Une fois votre copie de Zend Framework disponible, votre application nécessite d'avoir accès aux
classes du framework. Bien qu'il y ait plusieurs manières de réaliser ceci, votre include_path
de PHP doit contenir le chemin vers la bibliothèque de Zend Framework.

Zend fournit un tutoriel de démarrage rapide ("QuickStart") pour vous permettre de démarrer
rapidement. Ceci est une excellente manière pour commencer à apprendre le framework avec
une présentation de cas concrets que vous pourriez avoir à utiliser.

Puisque les composants de Zend Framework sont plutôt connectés de manière lâche, divers
composants peuvent être choisis pour un usage indépendant si nécessaire. Les chapitres
suivants documente l'utilisation de Zend Framework composant par composant.

4
Partie II. Apprendre Zend Framework
Table des matières
Démarrez rapidement avec Zend Framework .................................................................... 8
1. Zend Framework & MVC Introduction ................................................................... 8
1.1. Zend Framework ....................................................................................... 8
1.2. Model-View-Controller ............................................................................... 8
2. Create Your Project ........................................................................................... 10
2.1. Install Zend Framework ........................................................................... 10
2.2. Create Your Project ................................................................................. 10
2.3. The Bootstrap ......................................................................................... 11
2.4. Configuration ........................................................................................... 12
2.5. Action Controllers .................................................................................... 12
2.6. Views ..................................................................................................... 13
2.7. Checkpoint .............................................................................................. 15
3. Create A Layout ................................................................................................ 15
4. Create a Model and Database Table ................................................................... 18
5. Create A Form ................................................................................................... 28
6. Congratulations! ................................................................................................. 31
Chargement automatique avec Zend Framework ............................................................. 33
1. Introduction ........................................................................................................ 33
2. Architecture et buts ............................................................................................ 33
2.1. Convention de noms des classes ............................................................. 33
2.2. Conventions et architecture d'Autoload ..................................................... 33
3. Utilisation de base de l'autoloader ....................................................................... 34
4. Auto-chargement de resources ........................................................................... 36
5. Conclusion ......................................................................................................... 37
Les plugins dans Zend Framework ................................................................................. 38
1. Introduction ........................................................................................................ 38
2. Using Plugins .................................................................................................... 38
3. Conclusion ......................................................................................................... 40
Bien démarrer avec Zend_Layout ................................................................................... 42
1. Introduction ........................................................................................................ 42
2. Utiliser Zend_Layout .......................................................................................... 42
2.1. Layout Configuration ............................................................................... 42
2.2. Créer un script de layout ......................................................................... 43
2.3. Accéder à l'objet Layout .......................................................................... 43
2.4. Autres opérations .................................................................................... 44
3. Zend_Layout: Conclusions .................................................................................. 45
Bien démarrer avec Zend_View ...................................................................................... 46
1. Introduction ........................................................................................................ 46
2. Basic Placeholder Usage ................................................................................... 46
3. Standard Placeholders ....................................................................................... 49
3.1. Setting the DocType ................................................................................ 49
3.2. Specifying the Page Title ......................................................................... 50
3.3. Specifying Stylesheets with HeadLink ....................................................... 51
3.4. Aggregating Scripts Using HeadScript ...................................................... 52
4. View Placeholders: Conclusion ........................................................................... 54
Bien comprendre et utiliser les décorateurs Zend Form .................................................... 55
1. Introduction ........................................................................................................ 55
2. Les bases des décorateurs ................................................................................ 55
2.1. Aperçu du pattern décorateur ................................................................... 55
2.2. Créer votre premier décorateur ................................................................ 57
3. Chainer les décorateurs ..................................................................................... 58

6
Apprendre Zend Framework

4. Rendu individuel des décorateurs ....................................................................... 62


5. Créer et rendre des éléments composites ........................................................... 66
5.1. L'élément ................................................................................................ 66
5.2. Le décorateur ......................................................................................... 68
5.3. Conclusion .............................................................................................. 71
6. Conclusion ......................................................................................................... 71
Bien démarrer avec Zend_Session, Zend_Auth, et Zend_Acl ............................................ 72
1. Fabrique une application Multi-Utilisateurs avec Zend Framework ......................... 72
1.1. Zend Framework ..................................................................................... 72
2. Gérer les sessions dans ZF ............................................................................... 72
2.1. Introduction aux sessions ........................................................................ 72
2.2. Utilisation classique de Zend_Session ...................................................... 73
2.3. Utilisation avancée de Zend_Session ....................................................... 74
3. Authentification d'utilisateurs dans Zend Framework ............................................. 74
3.1. Introduction à l'authentification ................................................................. 74
3.2. Utilisation de base de Zend_Auth ............................................................. 74
4. Fabriquer un système de gestion d'autorisations avec Zend Framework ................. 76
4.1. Introduction à l'autorisation ...................................................................... 76
4.2. Utilisation de base de Zend_Acl ............................................................... 76
Bien démarrer avec Zend_Search_Lucene ...................................................................... 80
1. Introduction à Zend_Search_Lucene ................................................................... 80
2. Structure d'index Lucene .................................................................................... 81
3. Ouverture et création d'index .............................................................................. 82
4. Indexation .......................................................................................................... 82
4.1. Politique d'indexation ............................................................................... 83
5. Recherche ......................................................................................................... 83
6. Requêtes supportées ......................................................................................... 84
7. Pagination de résultat de recherche .................................................................... 86
Bien démarrer avec Zend_Paginator ............................................................................... 88
1. Introduction ........................................................................................................ 88
2. Simple Examples ............................................................................................... 88
3. Contrôles de la pagination et styles de défilement ................................................ 90
4. Putting it all Together ......................................................................................... 91

7
Démarrez rapidement avec Zend
Framework
1. Zend Framework & MVC Introduction
1.1. Zend Framework
Zend Framework is an open source, object oriented web application framework for PHP 5.
Zend Framework is often called a 'component library', because it has many loosely coupled
components that you can use more or less independently. But Zend Framework also provides
an advanced Model-View-Controller (MVC) implementation that can be used to establish
a basic structure for your Zend Framework applications. A full list of Zend Framework
components along with short descriptions may be found in the components overview. This
QuickStart will introduce you to some of Zend Framework's most commonly used components,
including Zend_Controller, Zend_Layout, Zend_Config, Zend_Db, Zend_Db_Table,
Zend_Registry, along with a few view helpers.

Using these components, we will build a simple database-driven guest book application within
minutes. The complete source code for this application is available in the following archives:

• zip

• tar.gz

1.2. Model-View-Controller
So what exactly is this MVC pattern everyone keeps talking about, and why should you care?
MVC is much more than just a three-letter acronym (TLA) that you can whip out anytime you want
to sound smart; it has become something of a standard in the design of modern web applications.
And for good reason. Most web application code falls under one of the following three categories:
presentation, business logic, and data access. The MVC pattern models this separation of
concerns well. The end result is that your presentation code can be consolidated in one part of
your application with your business logic in another and your data access code in yet another.
Many developers have found this well-defined separation indispensable for keeping their code
organized, especially when more than one developer is working on the same application.

More Information

Let's break down the pattern and take a look at the individual pieces:

8
Démarrez rapidement
avec Zend Framework

• Model - This is the part of your application that defines its basic functionality
behind a set of abstractions. Data access routines and some business logic
can be defined in the model.

• View - Views define exactly what is presented to the user. Usually controllers
pass data to each view to render in some format. Views will often collect data
from the user, as well. This is where you're likely to find HTML markup in your
MVC applications.

• Controller - Controllers bind the whole pattern together. They manipulate


models, decide which view to display based on the user's request and other
factors, pass along the data that each view will need, or hand off control to
another controller entirely. Most MVC experts recommend keeping controllers
as skinny as possible.

9
Démarrez rapidement
avec Zend Framework

Of course there is more to be said about this critical pattern, but this should
give you enough background to understand the guestbook application we'll be
building.

2. Create Your Project


In order to create your project, you must first download and extract Zend Framework.

2.1. Install Zend Framework


The easiest way to get Zend Framework along with a complete PHP stack is by installing Zend
Server. Zend Server has native installers for Mac OSX, Windows, Fedora Core, and Ubuntu, as
well as a universal installation package compatible with most Linux distributions.

After you have installed Zend Server, the Framework files may be found under /usr/local/
zend/share/ZendFramework on Mac OSX and Linux, and C:\Program Files\Zend
\ZendServer\share\ZendFramework on Windows. The include_path will already be
configured to include Zend Framework.

Alternately, you can Download the latest version of Zend Framework and extract the contents;
make a note of where you have done so.

Optionally, you can add the path to the library/ subdirectory of the archive to your php.ini's
include_path setting.

That's it! Zend Framework is now installed and ready to use.

2.2. Create Your Project


zf Command Line Tool
In your Zend Framework installation is a bin/ subdirectory, containing the scripts
zf.sh and zf.bat for Unix-based and Windows-based users, respectively.
Make a note of the absolute path to this script.

Wherever you see references to zf.sh or zf.bat, please substitute the


absolute path to the script. On Unix-like systems, you may want to use your shell's
alias functionality: alias zf.sh=path/to/ZendFramework/bin/zf.sh.

If you have problems setting up the zf command-line tool, please refer to the
manual.

Open a terminal (in Windows, Start -> Run, and then use cmd). Navigate to a directory where
you would like to start a project. Then, use the path to the appropriate script, and execute one
of the following:

# Unix:
% zf.sh create project quickstart

# DOS/Windows:
C:> zf.bat create project quickstart

Running this command will create your basic site structure, including your initial controllers and
views. The tree looks like the following:

10
Démarrez rapidement
avec Zend Framework

quickstart
|-- application
| |-- Bootstrap.php
| |-- configs
| | `-- application.ini
| |-- controllers
| | |-- ErrorController.php
| | `-- IndexController.php
| |-- models
| `-- views
| |-- helpers
| `-- scripts
| |-- error
| | `-- error.phtml
| `-- index
| `-- index.phtml
|-- library
|-- public
| `-- index.php
`-- tests
|-- application
| `-- bootstrap.php
|-- library
| `-- bootstrap.php
`-- phpunit.xml

At this point, if you haven't added Zend Framework to your include_path, we recommend
either copying or symlinking it into your library/ directory. In either case, you'll want to either
recursively copy or symlink the library/Zend/ directory of your Zend Framework installation
into the library/ directory of your project. On unix-like systems, that would look like one of
the following:

# Symlink:
% cd library; ln -s path/to/ZendFramework/library/Zend .

# Copy:
% cd library; cp -r path/to/ZendFramework/library/Zend .

On Windows systems, it may be easiest to do this from the Explorer.

Now that the project is created, the main artifacts to begin understanding are the bootstrap,
configuration, action controllers, and views.

2.3. The Bootstrap


Your Bootstrap class defines what resources and components to initialize. By default, Zend
Framework's Front Controller is initialized, and it uses the application/controllers/ as
the default directory in which to look for action controllers (more on that later). The class looks
like the following:

// application/Bootstrap.php

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
}

As you can see, not much is necessary to begin with.

11
Démarrez rapidement
avec Zend Framework

2.4. Configuration
While Zend Framework is itself configurationless, you often need to configure your application.
The default configuration is placed in application/configs/application.ini, and
contains some basic directives for setting your PHP environment (for instance, turning error
reporting on and off), indicating the path to your bootstrap class (as well as its class name), and
the path to your action controllers. It looks as follows:

; application/configs/application.ini

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
includePaths.library = APPLICATION_PATH "/../library"
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"

[staging : production]

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

Several things about this file should be noted. First, when using INI-style configuration, you
can reference constants directly and expand them; APPLICATION_PATH is actually a constant.
Additionally note that there are several sections defined: production, staging, testing, and
development. The latter three inherit settings from the "production" environment. This is a useful
way to organize configuration to ensure that appropriate settings are available in each stage of
application development.

2.5. Action Controllers


Your application's action controllers contain your application workflow, and do the work of
mapping your requests to the appropriate models and views.

An action controller should have one or more methods ending in "Action"; these methods
may then be requested via the web. By default, Zend Framework URLs follow the schema
/controller/action, where "controller" maps to the action controller name (minus the
"Controller" suffix) and "action" maps to an action method (minus the "Action" suffix).

Typically, you always need an IndexController, which is a fallback controller and which also
serves the home page of the site, and an ErrorController, which is used to indicate things
such as HTTP 404 errors (controller or action not found) and HTTP 500 errors (application errors).

The default IndexController is as follows:

// application/controllers/IndexController.php

class IndexController extends Zend_Controller_Action


{

public function init()

12
Démarrez rapidement
avec Zend Framework

{
/* Initialize action controller here */
}

public function indexAction()


{
// action body
}
}

And the default ErrorController is as follows:

// application/controllers/ErrorController.php

class ErrorController extends Zend_Controller_Action


{

public function errorAction()


{
$errors = $this->_getParam('error_handler');

switch ($errors->type) {
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:

// 404 error -- controller or action not found


$this->getResponse()->setHttpResponseCode(404);
$this->view->message = 'Page not found';
break;
default:
// application error
$this->getResponse()->setHttpResponseCode(500);
$this->view->message = 'Application error';
break;
}

$this->view->exception = $errors->exception;
$this->view->request = $errors->request;
}
}

You'll note that (1) the IndexController contains no real code, and (2) the
ErrorController makes reference to a "view" property. That leads nicely into our next subject.

2.6. Views
Views in Zend Framework are written in plain old PHP. View scripts are placed in application/
views/scripts/, where they are further categorized using the controller names. In our case,
we have an IndexController and an ErrorController, and thus we have corresponding
index/ and error/ subdirectories within our view scripts directory. Within these subdirectories,
you will then find and create view scripts that correspond to each controller action exposed; in the
default case, we thus have the view scripts index/index.phtml and error/error.phtml.

View scripts may contain any markup you want, and use the <?php opening tag and ?> closing
tag to insert PHP directives.

The following is what we install by default for the index/index.phtml view script:

13
Démarrez rapidement
avec Zend Framework

<!-- application/views/scripts/index/index.phtml -->


<style>

a:link,
a:visited
{
color: #0398CA;
}

span#zf-name
{
color: #91BE3F;
}

div#welcome
{
color: #FFFFFF;
background-image: url(http://framework.zend.com/images/bkg_header.jpg);
width: 600px;
height: 400px;
border: 2px solid #444444;
overflow: hidden;
text-align: center;
}

div#more-information
{
background-image: url(http://framework.zend.com/images/bkg_body-bottom.gif);
height: 100%;
}

</style>
<div id="welcome">
<h1>Welcome to the <span id="zf-name">Zend Framework!</span><h1 />
<h3>This is your project's main page<h3 />
<div id="more-information">
<p>
<img src="http://framework.zend.com/images/PoweredBy_ZF_4LightBG.png" />
</p>

<p>
Helpful Links: <br />
<a href="http://framework.zend.com/">Zend Framework Website</a> |
<a href="http://framework.zend.com/manual/en/">Zend Framework
Manual</a>
</p>
</div>
</div>

The error/error.phtml view script is slightly more interesting as it uses some PHP
conditionals:

<!-- application/views/scripts/error/error.phtml -->


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN";
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Zend Framework Default Application</title>

14
Démarrez rapidement
avec Zend Framework

</head>
<body>
<h1>An error occurred</h1>
<h2><?php echo $this->message ?></h2>

<?php if ('development' == $this->env): ?>


<h3>Exception information:</h3>
<p>
<b>Message:</b> <?php echo $this->exception->getMessage() ?>
</p>

<h3>Stack trace:</h3>
<pre><?php echo $this->exception->getTraceAsString() ?>
</pre>

<h3>Request Parameters:</h3>
<pre><?php echo var_export($this->request->getParams(), 1) ?>
</pre>
<?php endif ?>
</body>
</html>

2.7. Checkpoint
At this point, you should be able to fire up your initial Zend Framework application. Create a virtual
host in your web server, and point its document root to your application's public/ subdirectory.
Make sure your host's name is in your DNS or hosts file, and then point your browser to it. You
should be able to see a welcome page at this point.

3. Create A Layout
You may have noticed that the view scripts in the previous sections were HTML fragments- not
complete pages. This is by design; we want our actions to return content only related to the action
itself, not the application as a whole.

Now we must compose that generated content into a full HTML page. We'd also like to have a
consistent look and feel for the application. We will use a global site layout to accomplish both
of these tasks.

There are two design patterns that Zend Framework uses to implement layouts: Two Step View
and Composite View. Two Step View is usually associated with the Transform View pattern; the
basic idea is that your application view creates a representation that is then injected into the
master view for final transformation. The Composite View pattern deals with a view made of one
or more atomic, application views.

In Zend Framework, Zend_Layout combines the ideas behind these patterns. Instead of each
action view script needing to include site-wide artifacts, they can simply focus on their own
responsibilities.

Occasionally, however, you may need application-specific information in your site-wide view
script. Fortunately, Zend Framework provides a variety of view placeholders to allow you to
provide such information from your action view scripts.

To get started using Zend_Layout, first we need to inform our bootstrap to use the Layout
resource. This can be done by adding the following line to your application/configs/
application.ini file, within the production section:

15
Démarrez rapidement
avec Zend Framework

; application/configs/application.ini

; Add to [production] section:


resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"

The final INI file should look as follows:

; application/configs/application.ini

[production]
; PHP settings we want to initialize
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
includePaths.library = APPLICATION_PATH "/../library"
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"

[staging : production]

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

This directive tells your application to look for layout view scripts in application/layouts/
scripts. Create those directories now.

We also want to ensure we have an XHTML DocType declaration for our application. To enable
this, we need to add a resource to our bootstrap.

The simplest way to add a bootstrap resource is to simply create a protected method beginning
with the phrase _init. In this case, we want to initialize the doctype, so we'll create an
_initDoctype() method within our bootstrap class:

// application/Bootstrap.php

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
protected function _initDoctype()
{
}
}

Within that method, we need to hint to the view to use the appropriate doctype. But where will
the view object come from? The easy solution is to initialize the View resource; once we have,
we can pull the view object from the bootstrap and use it.

To initialize the view resource, add the following line to your application/configs/
application.ini file, in the section marked production:

; application/configs/application.ini

16
Démarrez rapidement
avec Zend Framework

; Add to [production] section:


resources.view[] =

This tells us to initialize the view with no options (the '[]' indicates that the "view" key is an array,
and we pass nothing to it).

Now that we have a view, let's flesh out our _initDoctype() method. In it, we will first ensure
the View resource has run, fetch the view object, and then configure it:

// application/Bootstrap.php

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
protected function _initDoctype()
{
$this->bootstrap('view');
$view = $this->getResource('view');
$view->doctype('XHTML1_STRICT');
}
}

Now that we've initialized Zend_Layout and set the Doctype, let's create our site-wide layout:

// application/layouts/scripts/layout.phtml

echo $this->doctype() ?>


<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Zend Framework Quickstart Application</title>
<?php echo $this->headLink()->appendStylesheet('/css/global.css') ?>
</head>
<body>
<div id="header" style="background-color: #EEEEEE; height: 30px;">
<div id="header-logo" style="float: left">
<b>ZF Quickstart Application</b>
</div>
<div id="header-navigation" style="float: right">
<a href="<?php echo $this->url(
array('controller'=>'guestbook'),
'default',
true) ?>">Guestbook</a>
</div>
</div>

<?php echo $this->layout()->content ?>


</body>
</html>

We grab our application content using the layout() view helper, and accessing the "content"
key. You may render to other response segments if you wish to, but in most cases, this is all
that's necessary.

Note also the use of the headLink() placeholder. This is an easy way to generate the HTML
for <link> elements, as well as to keep track of them throughout your application. If you need to
add additional CSS sheets to support a single action, you can do so, and be assured it will be
present in the final rendered page.

17
Démarrez rapidement
avec Zend Framework

Checkpoint
Now go to "http://localhost" and check out the source. You should see your
XHTML header, head, title, and body sections.

4. Create a Model and Database Table


Before we get started, let's consider something: where will these classes live, and how will
we find them? The default project we created instantiates an autoloader. We can attach other
autoloaders to it so that it knows where to find different classes. Typically, we want our various
MVC classes grouped under the same tree -- in this case, application/ -- and most often
using a common prefix.

Zend_Controller_Front has a notion of "modules", which are individual mini-applications.


Modules mimic the directory structure that the zf tool sets up under application/, and
all classes inside them are assumed to begin with a common prefix, the module name.
application/ is itself a module -- the "default" or "application" module. As such, we'll want to
setup autoloading for resources within this directory.

Zend_Application_Module_Autoloader provides the functionality needed to map the


various resources under a module to the appropriate directories, and provides a standard naming
mechanism as well. An instance of the class is created by default during initialization of the
bootstrap object; your application bootstrap will be default use the module prefix "Application".
As such, our models, forms, and table classes will all begin with the class prefix "Application_".

Now, let's consider what makes up a guestbook. Typically, they are simply a list of entries with
a comment, timestamp, and, often, email address. Assuming we store them in a database, we
may also want a unique identifier for each entry. We'll likely want to be able to save an entry,
fetch individual entries, and retrieve all entries. As such, a simple guestbook model API might
look something like this:

// application/models/Guestbook.php

class Application_Model_Guestbook
{
protected $_comment;
protected $_created;
protected $_email;
protected $_id;

public function __set($name, $value);


public function __get($name);

public function setComment($text);


public function getComment();

public function setEmail($email);


public function getEmail();

public function setCreated($ts);


public function getCreated();

public function setId($id);


public function getId();

public function save();


public function find($id);

18
Démarrez rapidement
avec Zend Framework

public function fetchAll();


}

__get() and __set() will provide a convenience mechanism for us to access the individual
entry properties, and proxy to the other getters and setters. They also will help ensure that only
properties we whitelist will be available in the object.

find() and fetchAll() provide the ability to fetch a single entry or all entries.

Now from here, we can start thinking about setting up our database.

First we need to initialize our Db resource. As with the Layout and View resource,
we can provide configuration for the Db resource. In your application/configs/
application.ini file, add the following lines in the appropriate sections.

; application/configs/application.ini

; Add these lines to the appropriate sections:


[production]
resources.db.adapter = "PDO_SQLITE"
resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"

[testing : production]
resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"

[development : production]
resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"

Your final configuration file should look like the following:

; application/configs/application.ini

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
resources.view[] =
resources.db.adapter = "PDO_SQLITE"
resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"

[staging : production]

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"

Note that the database(s) will be stored in data/db/. Create those directories, and make them
world-writeable. On unix-like systems, you can do that as follows:

% mkdir -p data/db; chmod -R a+rwX data

19
Démarrez rapidement
avec Zend Framework

On Windows, you will need to create the directories in Explorer and set the permissions to allow
anyone to write to the directory.

At this point we have a connection to a database; in our case, its a connection to a Sqlite database
located inside our application/data/ directory. So, let's design a simple table that will hold
our guestbook entries.

-- scripts/schema.sqlite.sql
--
-- You will need load your database schema with this SQL.

CREATE TABLE guestbook (


id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
email VARCHAR(32) NOT NULL DEFAULT 'noemail@test.com',
comment TEXT NULL,
created DATETIME NOT NULL
);

CREATE INDEX "id" ON "guestbook" ("id");

And, so that we can have some working data out of the box, lets create a few rows of information
to make our application interesting.

-- scripts/data.sqlite.sql
--
-- You can begin populating the database with the following SQL statements.

INSERT INTO guestbook (email, comment, created) VALUES


('ralph.schindler@zend.com',
'Hello! Hope you enjoy this sample zf application!',
DATETIME('NOW'));
INSERT INTO guestbook (email, comment, created) VALUES
('foo@bar.com',
'Baz baz baz, baz baz Baz baz baz - baz baz baz.',
DATETIME('NOW'));

Now that we have both the schema and some data defined. Lets get a script together that we can
now execute to build this database. Naturally, this is not needed in production, but this script will
help developers build out the database requirements locally so they can have the fully working
application. Create the script as scripts/load.sqlite.php with the following contents:

// scripts/load.sqlite.php

/**
* Script for creating and loading database
*/

// Initialize the application path and autoloading


defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
set_include_path(implode(PATH_SEPARATOR, array(
APPLICATION_PATH . '/../library',
get_include_path(),
)));
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();

// Define some CLI options

20
Démarrez rapidement
avec Zend Framework

$getopt = new Zend_Console_Getopt(array(


'withdata|w' => 'Load database with sample data',
'env|e-s' => 'Application environment for which to create database (defaults to devel
'help|h' => 'Help -- usage message',
));
try {
$getopt->parse();
} catch (Zend_Console_Getopt_Exception $e) {
// Bad options passed: report usage
echo $e->getUsageMessage();
return false;
}

// If help requested, report usage message


if ($getopt->getOption('h')) {
echo $getopt->getUsageMessage();
return true;
}

// Initialize values based on presence or absence of CLI options


$withData = $getopt->getOption('w');
$env = $getopt->getOption('e');
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (null === $env) ? 'development' : $env);

// Initialize Zend_Application
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);

// Initialize and retrieve DB resource


$bootstrap = $application->getBootstrap();
$bootstrap->bootstrap('db');
$dbAdapter = $bootstrap->getResource('db');

// let the user know whats going on (we are actually creating a
// database here)
if ('testing' != APPLICATION_ENV) {
echo 'Writing Database Guestbook in (control-c to cancel): ' . PHP_EOL;
for ($x = 5; $x > 0; $x--) {
echo $x . "\r"; sleep(1);
}
}

// Check to see if we have a database file already


$options = $bootstrap->getOption('resources');
$dbFile = $options['db']['params']['dbname'];
if (file_exists($dbFile)) {
unlink($dbFile);
}

// this block executes the actual statements that were loaded from
// the schema file.
try {
$schemaSql = file_get_contents(dirname(__FILE__) . '/schema.sqlite.sql');
// use the connection directly to load sql in batches
$dbAdapter->getConnection()->exec($schemaSql);
chmod($dbFile, 0666);

21
Démarrez rapidement
avec Zend Framework

if ('testing' != APPLICATION_ENV) {
echo PHP_EOL;
echo 'Database Created';
echo PHP_EOL;
}

if ($withData) {
$dataSql = file_get_contents(dirname(__FILE__) . '/data.sqlite.sql');
// use the connection directly to load sql in batches
$dbAdapter->getConnection()->exec($dataSql);
if ('testing' != APPLICATION_ENV) {
echo 'Data Loaded.';
echo PHP_EOL;
}
}

} catch (Exception $e) {


echo 'AN ERROR HAS OCCURED:' . PHP_EOL;
echo $e->getMessage() . PHP_EOL;
return false;
}

// generally speaking, this script will be run from the command line
return true;

Now, let's execute this script. From a terminal or the DOS command line, do the following:

% php scripts/load.sqlite.php --withdata

You should see output like the following:

path/to/ZendFrameworkQuickstart/scripts$ php load.sqlite.php --withdata


Writing Database Guestbook in (control-c to cancel):
1
Database Created
Data Loaded.

Now we have a fully working database and table for our guestbook application. Our next few
steps are to build out our application code. This includes building a data source (in our case, we
will use Zend_Db_Table), and a data mapper to connect that data source to our domain model.
Finally we'll also create the controller that will interact with this model to both display existing
entries and process new entries.

We'll use a Table Data Gateway to connect to our data source; Zend_Db_Table provides
this functionality. To get started, lets create a Zend_Db_Table-based table class. First, create
the directory application/models/DbTable/. Then create and edit a file Guestbook.php
within it, and add the following contents:

// application/models/DbTable/Guestbook.php

/**
* This is the DbTable class for the guestbook table.
*/
class Application_Model_DbTable_Guestbook extends Zend_Db_Table_Abstract
{
/** Table name */
protected $_name = 'guestbook';
}

22
Démarrez rapidement
avec Zend Framework

Note the class prefix: Application_Model_DbTable. The class prefix for our module,
"Application", is the first segment, and then we have the component, "Model_DbTable"; the latter
is mapped to the models/DbTable/ directory of the module.

All that is truly necessary when extending Zend_Db_Table is to provide a table name and
optionally the primary key (if it is not "id").

Now let's create a Data Mapper. A Data Mapper maps a domain object to the database.
In our case, it will map our model, Application_Model_Guestbook, to our data source,
Application_Model_DbTable_Guestbook. A typical API for a data mapper is as follows:

// application/models/GuestbookMapper.php

class Application_Model_GuestbookMapper
{
public function save($model);
public function find($id, $model);
public function fetchAll();
}

In addition to these methods, we'll add methods for setting and retrieving the Table Data
Gateway. The final class, located in application/models/GuestbookMapper.php, looks
like this:

// application/models/GuestbookMapper.php

class Application_Model_GuestbookMapper
{
protected $_dbTable;

public function setDbTable($dbTable)


{
if (is_string($dbTable)) {
$dbTable = new $dbTable();
}
if (!$dbTable instanceof Zend_Db_Table_Abstract) {
throw new Exception('Invalid table data gateway provided');
}
$this->_dbTable = $dbTable;
return $this;
}

public function getDbTable()


{
if (null === $this->_dbTable) {
$this->setDbTable('Application_Model_DbTable_Guestbook');
}
return $this->_dbTable;
}

public function save(Application_Model_Guestbook $guestbook)


{
$data = array(
'email' => $guestbook->getEmail(),
'comment' => $guestbook->getComment(),
'created' => date('Y-m-d H:i:s'),
);

23
Démarrez rapidement
avec Zend Framework

if (null === ($id = $guestbook->getId())) {


unset($data['id']);
$this->getDbTable()->insert($data);
} else {
$this->getDbTable()->update($data, array('id = ?' => $id));
}
}

public function find($id, Application_Model_Guestbook $guestbook)


{
$result = $this->getDbTable()->find($id);
if (0 == count($result)) {
return;
}
$row = $result->current();
$guestbook->setId($row->id)
->setEmail($row->email)
->setComment($row->comment)
->setCreated($row->created);
}

public function fetchAll()


{
$resultSet = $this->getDbTable()->fetchAll();
$entries = array();
foreach ($resultSet as $row) {
$entry = new Application_Model_Guestbook();
$entry->setId($row->id)
->setEmail($row->email)
->setComment($row->comment)
->setCreated($row->created)
->setMapper($this);
$entries[] = $entry;
}
return $entries;
}
}

Now it's time to update our model class slightly, to accomodate the data mapper. Just like the
data mapper contains a reference to the data source, the model contains a reference to the data
mapper. Additionally, we'll make it easy to populate the model by passing an array of data either
to the constructor or a setOptions() method. The final model class, located in application/
models/Guestbook.php, looks like this:

// application/models/Guestbook.php

class Application_Model_Guestbook
{
protected $_comment;
protected $_created;
protected $_email;
protected $_id;
protected $_mapper;

public function __construct(array $options = null)


{
if (is_array($options)) {
$this->setOptions($options);
}

24
Démarrez rapidement
avec Zend Framework

public function __set($name, $value)


{
$method = 'set' . $name;
if (('mapper' == $name) || !method_exists($this, $method)) {
throw new Exception('Invalid guestbook property');
}
$this->$method($value);
}

public function __get($name)


{
$method = 'get' . $name;
if (('mapper' == $name) || !method_exists($this, $method)) {
throw new Exception('Invalid guestbook property');
}
return $this->$method();
}

public function setOptions(array $options)


{
$methods = get_class_methods($this);
foreach ($options as $key => $value) {
$method = 'set' . ucfirst($key);
if (in_array($method, $methods)) {
$this->$method($value);
}
}
return $this;
}

public function setComment($text)


{
$this->_comment = (string) $text;
return $this;
}

public function getComment()


{
return $this->_comment;
}

public function setEmail($email)


{
$this->_email = (string) $email;
return $this;
}

public function getEmail()


{
return $this->_email;
}

public function setCreated($ts)


{
$this->_created = $ts;
return $this;
}

25
Démarrez rapidement
avec Zend Framework

public function getCreated()


{
return $this->_created;
}

public function setId($id)


{
$this->_id = (int) $id;
return $this;
}

public function getId()


{
return $this->_id;
}

public function setMapper($mapper)


{
$this->_mapper = $mapper;
return $this;
}

public function getMapper()


{
if (null === $this->_mapper) {
$this->setMapper(new Application_Model_GuestbookMapper());
}
return $this->_mapper;
}

public function save()


{
$this->getMapper()->save($this);
}

public function find($id)


{
$this->getMapper()->find($id, $this);
return $this;
}

public function fetchAll()


{
return $this->getMapper()->fetchAll();
}
}

Lastly, to connect these elements all together, lets create a guestbook controller that will both
list the entries that are currently inside the database.

To create a new controller, open a terminal or DOS console, navigate to your project directory,
and enter the following:

# Unix-like systems:
% zf.sh create controller guestbook

# DOS/Windows:
C:> zf.bat create controller guestbook

26
Démarrez rapidement
avec Zend Framework

This will create a new controller, GuestbookController, in application/controllers/


GuestbookController.php, with a single action method, indexAction(). It will also create
a view script directory for the controller, application/views/scripts/guestbook/, with
a view script for the index action.

We'll use the "index" action as a landing page to view all guestbook entries.

Now, let's flesh out the basic application logic. On a hit to indexAction(), we'll display all
guestbook entries. This would look like the following:

// application/controllers/GuestbookController.php

class GuestbookController extends Zend_Controller_Action


{
public function indexAction()
{
$guestbook = new Application_Model_Guestbook();
$this->view->entries = $guestbook->fetchAll();
}
}

And, of course, we need a view script to go along with that. Edit application/views/
scripts/guestbook/index.phtml to read as follows:

<!-- application/views/scripts/guestbook/index.phtml -->

<p><a href="<?php echo $this->url(


array(
'controller' => 'guestbook',
'action' => 'sign'
),
'default',
true) ?>">Sign Our Guestbook</a></p>

Guestbook Entries: <br />


<dl>
<?php foreach ($this->entries as $entry): ?>
<dt><?php echo $this->escape($entry->email) ?></dt>
<dd><?php echo $this->escape($entry->comment) ?></dd>
<?php endforeach ?>
</dl>

Checkpoint

Now browse to "http://localhost/guestbook". You should see the following in your


browser:

27
Démarrez rapidement
avec Zend Framework

Using the data loader script


The data loader script introduced in this section (scripts/load.sqlite.php)
can be used to create the database for each environment you have defined, as
well as to load it with sample data. Internally, it utilizes Zend_Console_Getopt,
which allows it to provide a number of command line switches. If you pass the "-
h" or "--help" switch, it will give you the available options:

Usage: load.sqlite.php [ options ]


--withdata|-w Load database with sample data
--env|-e [ ] Application environment for which to create database
(defaults to development)
--help|-h Help -- usage message)]]

The "-e" switch allows you to specify the value to use for the constant
APPLICATION_ENV -- which in turn allows you to create a SQLite database for
each environment you define. Be sure to run the script for the environment you
choose for your application when deploying.

5. Create A Form
For our guestbook to be useful, we need a form for submitting new entries.

Our first order of business is to create the actual form class. First, create the directory
application/forms/. This directory will contain form classes for the application. Next, we'll
create a form class in application/forms/Guestbook.php:

// application/forms/Guestbook.php

class Application_Form_Guestbook extends Zend_Form


{
public function init()
{

28
Démarrez rapidement
avec Zend Framework

// Set the method for the display form to POST


$this->setMethod('post');

// Add an email element


$this->addElement('text', 'email', array(
'label' => 'Your email address:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array(
'EmailAddress',
)
));

// Add the comment element


$this->addElement('textarea', 'comment', array(
'label' => 'Please Comment:',
'required' => true,
'validators' => array(
array('validator' => 'StringLength', 'options' => array(0, 20))
)
));

// Add a captcha
$this->addElement('captcha', 'captcha', array(
'label' => 'Please enter the 5 letters displayed below:',
'required' => true,
'captcha' => array(
'captcha' => 'Figlet',
'wordLen' => 5,
'timeout' => 300
)
));

// Add the submit button


$this->addElement('submit', 'submit', array(
'ignore' => true,
'label' => 'Sign Guestbook',
));

// And finally add some CSRF protection


$this->addElement('hash', 'csrf', array(
'ignore' => true,
));
}
}

The above form defines five elements: an email address field, a comment field, a CAPTCHA for
preventing spam submissions, a submit button, and a CSRF protection token.

Next, we will add a signAction() to our GuestbookController which will process the form
upon submission. To create the action and related view script, execute the following:

# Unix-like systems:
% zf.sh create action sign guestbook

# DOS/Windows:
C:> zf.bat create action sign guestbook

This will create a signAction() method in our controller, as well as the appropriate view script.

29
Démarrez rapidement
avec Zend Framework

Let's add some logic into our guestbook controller's sign action. We need to first check if we're
getting a POST or a GET request; in the latter case, we'll simply display the form. However, if we
get a POST request, we'll want to validate the posted data against our form, and, if valid, create
a new entry and save it. The logic might look like this:

// application/controllers/GuestbookController.php

class GuestbookController extends Zend_Controller_Action


{
// snipping indexAction()...

public function signAction()


{
$request = $this->getRequest();
$form = new Application_Form_Guestbook();

if ($this->getRequest()->isPost()) {
if ($form->isValid($request->getPost())) {
$model = new Application_Model_Guestbook($form->getValues());
$model->save();
return $this->_helper->redirector('index');
}
}

$this->view->form = $form;
}
}

Of course, we also need to edit the view script; edit application/views/scripts/


guestbook/sign.phtml to read:

<!-- application/views/scripts/guestbook/sign.phtml -->

Please use the form below to sign our guestbook!

<?php
$this->form->setAction($this->url());
echo $this->form;

Better Looking Forms

No one will be waxing poetic about the beauty of this form anytime soon. No
matter - form appearance is fully customizable! See the decorators section in the
reference guide for details.

Additionally, you may be interested in this series of posts on decorators.

Checkpoint

Now browse to "http://localhost/guestbook/sign". You should see the following in


your browser:

30
Démarrez rapidement
avec Zend Framework

6. Congratulations!
You have now built a very simple application using some of the most commonly used Zend
Framework components. Zend Framework makes many components available to you which
address most common requirements in web applications, including web services, search, PDF

31
Démarrez rapidement
avec Zend Framework

reading and writing, authentication, authorization, and much more. The Reference Guide is a
great place to find out more about the components you've used in this QuickStart as well as other
components. We hope you find Zend Framework useful and - more importantly - fun!

32
Chargement automatique avec Zend
Framework
1. Introduction
L'auto-chargement est un mécanisme qui élimine les inclusions de dépendances manuelles au
sein du code PHP. Le manuel sur l'autoload en PHPprécise qu'une fois qu'un autoloader a été
défini, "il est appelé automatiquement dans le cas où l'on tente d'utiliser une classe ou une
interface qui n'a pas encore été définie"

En utilisant l'auto-chargement, vous n'avez pas besoin de vous inquiéter du lieu où la classe
existe au sein du projet. Avec des autoloaders bien définis, la résolution du fichier contenant la
classe utilisée sera effectuée de manière transparente.

Aussi, l'autoloader chargeant la classe uniquement lorsque celle-ci est strictement nécessaire,
ceci peut avoir des effets très positifs sur les performances globales -- particulièrement si vous
prenez soin de supprimer tous les appels à require_once() avant votre déploiement.

Zend Framework encourage l'utilisation de l'auto-chargement et propose différents outils pour


charger le code des librairies comme celui de l'application. Ce tutoriel couvre ces outils et la
manière de les utiliser efficacement.

2. Architecture et buts
2.1. Convention de noms des classes
Pour comprendre l'autochargement dans le Zend Framework, vous devez d'abord comprendre
la relation entre nom de classe et nom de fichier.

Zend Framework a emprunté une idée de PEAR, dans lequel les noms des classes ont une
relation 1:1 avec le système de fichiers. Simplement, le caractère underscore ("_") est remplacé
par un séparateur de dossier pour résoudre le chemin vers le fichier, puis le suffixe ".php"
est ajouté. Par exemple, une classe "Foo_Bar_Baz" va correspondre à "Foo/Bar/Baz.php"
sur le système de fichiers. La supposition est alors que PHP résoudra les fichier relativement
à l'include_path ce qui permet d'utiliser include() et require() pour chercher le fichier
relativement à l'include_path.

Aussi, conformément à PEAR et au PHP project, nous utilisons et vous recommandons d'utiliser
un préfixe à votre code. Cela signifie que toutes les classes que vous écrivez doivent partager un
préfixe unique, par exemple, dans Zend Framework le préfixe est "Zend_". Cette convention de
noms évite toute collision dans les noms des classes. Dans Zend Framework, nous utilisons la
notion "d'espace de noms" ("namespace"); attention à éviter la confusion avec l'implémentation
native des espaces de noms de PHP.

Zend Framework suit ces règles simples en interne et nos standards de code vous encouragent
à faire de même avec le code de vos propres librairies.

2.2. Conventions et architecture d'Autoload


Le support de l'autochargement (autoload) de Zend Framework, implémenté grâce à
Zend_Loader_Autoloader, possède l'architecture et les buts suivants:

33
Chargement automatique
avec Zend Framework

• Correspondance d'espace de noms. Si l'espace de noms de la classe (son préfixe) n'est pas
dans une liste pré-enregistrée, retourner FALSE immédiatement. Ceci permet une optimisation
de la recherche ainsi que l'utilisation d'autres autoloaders ou d'un autoloader global par défaut.

• Permettre un auto-chargement "de secours". Dans le cas où l'on ne peut lister ou


prédéterminer les préfixes de manière claire et sûre, l'autoloader doit pouvoir être configuré
pour charger n'importe quel espace de noms de classes. Notez que ce cas n'est pas
recommandé car il fait intervenir des algorithmes complexes et non optimisés.

• Permettre la non-suppression des erreurs. Nous pensons -- et la plus grande partie de la


communauté PHP aussi -- que la suppression des erreurs est une mauvaise idée. C'est
couteux en ressources et cela masque les problèmes réels de l'application. Ainsi, par défaut,
la suppression des erreurs devrait être désactivée. Cependant, si un développeur insiste pour
l'activer, nous le permettons.

• Autoriser l'utilisation de fonctions d'autoload personnalisées. Certaines personnes ne veulent


pas utiliser Zend_Loader::loadClass() pour l'autoload, mais veulent tout de même
bénéficier des mécanismes du Zend Framework. Zend_Loader_Autoloader permet de
préciser ses propres fonctions d'auto-chargement.

• Permettre la manipulation de la chaine des autoloads de la SPL. Ceci autorise la spécification


d'autoloaders additionnels -- par exemple les chargeurs de ressources pour les classes n'ayant
pas une correspondance 1:1 avec le système de fichiers -- ces autoloaders pouvant être
chargés avant ou après l'autoloader principal de Zend Framework.

3. Utilisation de base de l'autoloader


Maintenant que vous savez les buts et le fonctionnement des autoloaders de Zend Framework,
voyons comment utiliser Zend_Loader_Autoloader.

Dans le cas le plus simple, vous incluez cette classe et l'instanciez. Comme
Zend_Loader_Autoloader est un singleton (car l'autoloader de la SPL est unique), nous
utilisons getInstance() pour en récupérer l'instance.

require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();

Par défaut, ceci va permettre de charger des classes dont le préfixe est "Zend_" ou "ZendX_",
si leurs fichiers sont dans votre include_path.

Que se passe-t-il si vous avez d'autres espaces de noms à charger? Le mieux et le plus simple
est alors d'utiliser la méthode registerNamespace() de l'instance. Vous pouvez lui passer
un préfixe simple, ou un tableau de préfixes:

require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
$loader->registerNamespace('Foo_');
$loader->registerNamespace(array('Foo_', 'Bar_'));

Aussi, vous pouvez indiquer à Zend_Loader_Autoloader d'agire comme autoloader par


défaut ("de secours"). Ceci signifie qu'il essayera de charger toute classe peu importe son
préfixe.

$loader->setFallbackAutoloader(true);

34
Chargement automatique
avec Zend Framework

N'utilisez pas l'autoloader de secours

Ce peut être tentant de se reposer abondamment sur


Zend_Loader_Autoloader comme chargeur de secours, nous ne
recommandons pas une telle pratique.

En interne, Zend_Loader_Autoloader utilise


Zend_Loader::loadClass() pour charger les classes. Cette méthode utilise
include() pour tenter de charger le fichier de la classe. include() retourne
FALSE s'il ne réussi pas -- mais renvoie aussi un warning PHP. Ce dernier point
peut mener à des problèmes:

• Si display_errors est activé, le warning sera inclus dans la sortie (l'affichage).

• Selon le niveau de error_reporting, le warning pourra aussi déclencher


l'écriture dans les journaux d'évènements.

Vous pouvez supprimer les messages d'erreur (la documentation de


Zend_Loader_Autoloader détaille cela), mais notez bien que la suppression
n'est utilisée que lorsque display_errors est activé; le journal des évènements
enregistrera toujours l'erreur. Pour ces raisons, nous vous recommandons de
bien configurer vos espaces de noms avec l'autoloader.

Préfixes d'espaces de nom et espaces de noms PHP

A l'heure de l'écriture de ces lignes, PHP 5.3 est sorti. Avec cette version, PHP
supporte maintenant officiellement les espaces de noms.

Cependant, Zend Framework date d'avant PHP 5.3, et donc les espaces de noms
PHP. Dans Zend Framework, lorsque nous parlons "d'espace de noms", nous
parlons d'une pratique consistant à préfixer le nom de la classe par un préfixe.
Par exemple, toutes les classes de Zend Framework commencent par "Zend_"
-- c'est notre espace de noms.

Zend Framework projette de supporter nativement les espaces de noms PHP


pour l'autoloader dans les versions futures. Il utilisera aussi ce support en interne,
à partir de la version 2.0.0.

Si vous possédez votre propre autoloader et que vous voulez l'utiliser avec Zend Framework
-- peut être un autoloader provenant d'une autre librairie que vous utilisez -- vous pouvez
l'enregistrer grâce aux méthodes de Zend_Loader_Autoloader pushAutoloader() et
unshiftAutoloader(). Ces méthodes ajoutent des autoloaders à la fin ou au début de
la chaine utilisée avant l'exécution des mecanismes internes d'auto-chargement de Zend
Framewor. Cette approche a les avantages suivants:

• Chaque méthode prend un deuxième paramètre : un espace de noms qui indique que
l'autoloader passé ne doit être utilisé que pour charger des classes dans cet espace de noms
là. Si la classe n'est pas dans cet espace de noms, l'autoloader sera alors ignoré, ce qui peut
amener à des optimisations de performance.

• Si vous devez manipuler le registre de spl_autoload(), prenez garde si vous préciser des
fonctions de rappels sous forme de méthodes de classes car spl_autoload_functions()
ne retourne pas exactement leurs définitions. Zend_Loader_Autoloader ne souffre pas de
ce problème.

35
Chargement automatique
avec Zend Framework

Voici une liste de définitions de fonctions de rappel pour auto-chargement valides en PHP.

// Ajoute à la suite de la pile la fonction 'my_autoloader',


// pour charger des classes commençant par 'My_':
$loader->pushAutoloader('my_autoloader', 'My_');

// Ajoute au début de la pile une méthode statique Foo_Loader::autoload(),


// pour charger des classes commençant par 'Foo_':
$loader->unshiftAutoloader(array('Foo_Loader', 'autoload'), 'Foo_');

4. Auto-chargement de resources
En développant des applications, il est souvent difficile de regrouper certaines classes dans
une relation 1:1 avec le système de fichiers que recommande le Zend framework, ou alors
ça ne semble pas intuitif de le faire. Cela signifie que les classes ne seront pas trouvées par
l'autoloader.

Si vous lisez les caractéristiques de l'architecture de l'autoloader, le dernier point de cette


section indique qu'une solution existe pour un tel problème. Zend Framework utilise alors
Zend_Loader_Autoloader_Resource .

Une ressource est juste un nom qui correspond à un espace de noms pour un composant (qui
est ajouté à l'espace de noms de l'autoloader) et un chemin (qui est relatif au chemin de base
de l'autoloader). Sous forme de code, vous feriez quelque chose comme:

$loader = new Zend_Application_Module_Autoloader(array(


'namespace' => 'Blog',
'basePath' => APPLICATION_PATH . '/modules/blog',
));

Une fois le chargeur en place, il faut l'informer des différents types de ressources qu'il va avoir
à gérer. Ces types sont simplement des paires d'arbres et de préfixes.

Considérons ce qui suit comme exemple:

path/to/some/resources/
|-- forms/
| `-- Guestbook.php // Foo_Form_Guestbook
|-- models/
| |-- DbTable/
| | `-- Guestbook.php // Foo_Model_DbTable_Guestbook
| |-- Guestbook.php // Foo_Model_Guestbook
| `-- GuestbookMapper.php // Foo_Model_GuestbookMapper

Le premier reflexe est de créer un chargeur de ressources:

$loader = new Zend_Loader_Autoloader_Resource(array(


'basePath' => 'path/to/some/resources/',
'namespace' => 'Foo',
));

Puis, nous définissons des types de ressources.


Zend_Loader_Autoloader_Resourse::addResourceType() prend trois arguments: le
"type" de resource (une chaine arbitraire), le chemin sous le chemin de base dans lequel le
type de ressource doit se trouver, et le préfixe particulier à utiliser pour ce type de ressource.
Dans l'arbre représenté ci-dessus, il y a trois types : form (dans le sous-dossier "forms", avec un

36
Chargement automatique
avec Zend Framework

préfixe "Form"), model (dans le sous-dossier "models", avec un préfixe "Model"), et dbtable (dans
le sous-dossier "models/DbTable", avec un préfixe "Model_DbTable"). Nous les définirons
comme ceci:

$loader->addResourceType('form', 'forms', 'Form')


->addResourceType('model', 'models', 'Model')
->addResourceType('dbtable', 'models/DbTable', 'Model_DbTable');

Il ne reste plus qu'à utiliser les classes:

$form = new Foo_Form_Guestbook();


$guestbook = new Foo_Model_Guestbook();

Autoload de ressource Module


La couche MVC de Zend Framework encourage l'utilisation de "modules", qui
sont des mini-applications de votre site. Les modules possèdent typiquement
des types de ressource par défaut, et Zend Framework recommande une
hiérarchie de répertoires standard pour les modules. Les autoloaders de
ressources sont particulièrement adaptés à cette situation -- tellement qu'ils sont
activés par défaut lorsque vous créez des classes de bootstrap qui étendent
Zend_Application_Module_Bootstrap. Pour plus d'informations, lisez la
documentation de Zend_Loader_Autoloader_Module.

5. Conclusion
Zend Framework encourage l'utilisation de l'auto-chargement, et l'initialise même par défaut dans
Zend_Application. Nous espérons que ce tutoriel vous a apporté toutes les informations
sur l'utilisation de Zend_Loader_Autoloader, ainsi que sur son extension pour ajouter des
autochargeurs personnalisés.

Pour plus d'informations sur son utilisation, lisez les sections du manuel sur
Zend_Loader_Autoloader et Zend_Loader_Autoloader_Resource.

37
Les plugins dans Zend Framework
1. Introduction
Zend Framework makes heavy use of plugin architectures. Plugins allow for easy extensibility
and customization of the framework while keeping your code separate from Zend Framework's
code.

Typically, plugins in Zend Framework work as follows:

• Plugins are classes. The actual class definition will vary based on the component -- you may
need to extend an abstract class or implement an interface, but the fact remains that the plugin
is itself a class.

• Related plugins will share a common class prefix. For instance, if you have created a number
of view helpers, they might all share the class prefix "Foo_View_Helper_".

• Everything after the common prefix will be considered the plugin name or short name
(versus the "long name", which is the full classname). For example, if the plugin prefix is
"Foo_View_Helper_", and the class name is "Foo_View_Helper_Bar", the plugin name
will be simply "Bar".

• Plugin names are typically case sensitive. The one caveat is that the initial letter can often be
either lower or uppercase; in our previous example, both "bar" and "Bar" would refer to the
same plugin.

Now let's turn to using plugins.

2. Using Plugins
Components that make use of plugins typically use Zend_Loader_PluginLoader to do their
work. This class has you register plugins by specifying one or more "prefix paths". The component
will then call the PluginLoader's load() method, passing the plugin's short name to it. The
PluginLoader will then query each prefix path to see if a class matching that short name exists.
Prefix paths are searched in LIFO (last in, first out) order, so it will match those prefix paths
registered last first -- allowing you to override existing plugins.

Some examples will make all of this more clear.

38
Les plugins dans Zend Framework

Exemple 1. Basic Plugin Example: Adding a single prefix path

In this example, we will assume some validators have been written and placed in the
directory foo/plugins/validators/, and that all these classes share the class prefix
"Foo_Validate_"; these two bits of information form our "prefix path". Furthermore, let's
assume we have two validators, one named "Even" (ensuring a number to be validated is
even), and another named "Dozens" (ensuring the number is a multiple of 12). The tree
might look like this:

foo/
|-- plugins/
| |-- validators/
| | |-- Even.php
| | |-- Dozens.php

Now, we'll inform a Zend_Form_Element instance of this prefix path.


Zend_Form_Element's addPrefixPath() method expects a third argument that
indicates the type of plugin for which the path is being registered; in this case, it's a "validate"
plugin.

$element->addPrefixPath('Foo_Validate', 'foo/plugins/validators/', 'validate');

Now we can simply tell the element the short name of the validators we want to use. In the
following example, we're using a mix of standard validators ("NotEmpty", "Int") and custom
validators ("Even", "Dozens"):

$element->addValidator('NotEmpty')
->addValidator('Int')
->addValidator('Even')
->addValidator('Dozens');

When the element needs to validate, it will then request the plugin class from the
PluginLoader. The first two validators will resolve to Zend_Validate_NotEmpty and
Zend_Validate_Int, respectively; the next two will resolve to Foo_Validate_Even and
Foo_Validate_Dozens, respectively.

What happens if a plugin is not found?

What happens if a plugin is requested, but the PluginLoader is unable to find a


class matching it? For instance, in the above example, if we registered the plugin
"Bar" with the element, what would happen?

The plugin loader will look through each prefix path, checking to see if a file
matching the plugin name is found on that path. If the file is not found, it then
moves on to the next prefix path.

Once the stack of prefix paths has been exhausted, if no matching file has been
found, it will throw a Zend_Loader_PluginLoader_Exception.

39
Les plugins dans Zend Framework

Exemple 2. Intermediate Plugin Usage: Overriding existing plugins

One strength of the PluginLoader is that its use of a LIFO stack allows you to override existing
plugins by creating your own versions locally with a different prefix path, and registering that
prefix path later in the stack.

For example, let's consider Zend_View_Helper_FormButton (view helpers are one form
of plugin). This view helper accepts three arguments, an element name (also used as the
element's DOM identifier), a value (used as the button label), and an optional array of
attributes. The helper then generates HTML markup for a form input element.

Let's say you want the helper to instead generate a true HTML button element; don't want
the helper to generate a DOM identifier, but instead use the value for a CSS class selector;
and that you have no interest in handling arbitrary attributes. You could accomplish this in a
couple of ways. In both cases, you'd create your own view helper class that implements the
behavior you want; the difference is in how you would name and invoke them.

Our first example will be to name the element with a unique name:
Foo_View_Helper_CssButton, which implies the plugin name "CssButton". While this
certainly is a viable approach, it poses several issues: if you've already used the Button
view helper in your code, you now have to refactor; alternately, if another developer starts
writing code for your application, they may inadvertently use the Button view helper instead
of your new view helper.

So, the better example is to use the plugin name "Button", giving us the class name
Foo_View_Helper_Button. We then register the prefix path with the view:

// Zend_View::addHelperPath() utilizes the PluginLoader; however, it inverts


// the arguments, as it provides a default value of "Zend_View_Helper" for the
// plugin prefix.
//
// The below assumes your class is in the directory 'foo/view/helpers/'.
$view->addHelperPath('foo/view/helpers', 'Foo_View_Helper');

Once done, anywhere you now use the "Button" helper will delegate to your custom
Foo_View_Helper_Button class!

3. Conclusion
Understanding the concept of prefix paths and overriding existing plugins will help you with your
understanding of many components within the framework. Plugins are used in a variety of places:

• Zend_Application: resources.

• Zend_Controller_Action: action helpers.

• Zend_Feed_Reader: plugins.

• Zend_Form: elements, filters, validators, and decorators.

• Zend_View: view helpers.

And several more places, besides. Learn the concepts early so you can leverage this important
extension point in Zend Framework.

40
Les plugins dans Zend Framework

Caveat
We'll note here that Zend_Controller_Front has a plugin system - but it does
not adhere to any of the guidelines offerred in this tutorial. The plugins registered
with the front controller must be instantiated directly and registered individually
with it. The reason for this is that this system predates any other plugin system
in the framework, and changes to it must be carefully weighed to ensure existing
plugins written by developers continue to work with it.

41
Bien démarrer avec Zend_Layout
1. Introduction
Dans une application utilisant les couches Zend Framework MVC, vos scripts de vue ne seront
que des blocs de HTML concernant l'action demandée. Par exemple, une action "/user/list"
mènerait vers un script de vue itérant sur les utilisateurs en présentant une liste:

<h2>Utilisateurs</h2>
<ul>
<?php if (!count($this->users)): ?>
<li>Pas d'utilisateurs</li>
<?php else: ?>
<?php foreach ($this->users as $user): ?>
<li>
<?php echo $this->escape($user->fullname) ?>
(<?php echo $this->escape($user->email) ?>)
</li>
<?php endforeach ?>
<?php endif ?>
</ul>

Comme c'est juste un bloc de code HTML, ce n'est pas une page valide, il manque le DOCTYPE
et la balise ouvrante HTML puis BODY. Quand seront-ils crées?

Dans les anciennes versions de Zend Framework, les développeurs créaient souvent des scripts
de vue "header" et "footer" qui servaient à cela. Ca fonctionnait certes, mais c'était difficile à
refactoriser, ou pour appeler du contenu provenant de plusieurs actions.

Le pattern Two-Step View solutionne beaucoup des problèmes indiqués. Avec, la vue
"application" est crée en premier, puis injectée dans une vue "page" ainsi présentée à l'utilisateur
client. la vue de page peut être imaginée comme un template global ou layout qui décrirait des
éléments communs utilisés au travers de multiples pages.

Dans Zend Framework, Zend_Layout implémente le pattern Two-Step View.

2. Utiliser Zend_Layout
L'utilisation classique de Zend_Layout est simple. En supposant que vous utilisez
Zend_Application, il suffit simplement de passer des options de configuration et créer un
script de layout.

2.1. Layout Configuration


L'endroit recommandé pour stocker les layouts est "layouts/scripts/" dans l'application:

application
|-- Bootstrap.php
|-- configs
| `-- application.ini
|-- controllers
|-- layouts
| `-- scripts
| |-- layout.phtml

42
Bien démarrer avec Zend_Layout

Pour initialiser Zend_Layout, ajouter ceci à votre fichier de configuration ("application/


configs/application.ini"):

resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"


resources.layout.layout = "layout"

La première ligne indique où chercher les scripts de layout; la seconde donne le nom du script
à utiliser (l'extension est supposée ".phtml" par défaut).

2.2. Créer un script de layout


Il convient maintenant de créer un script de layout. D'abord, vérifiez l'existance du dossier
"application/layouts/scripts"; puis ouvrez un éditeur et créez une mise en page
balisée. Les scripts de layout sont des scripts de vue, avec quelques différences tout de même.

<html>
<head>
<title>My Site</title>
</head>
<body>
<?php echo $this->layout()->content ?>
</body>
</html>

Dans l'exemple ci-dessus, un appel à l'aide de vue layout() y est effectué. Lorsque vous
activez l'instance de Zend_Layout, vous avez aussi accès à une aide d'acion et de vue qui
permettent d'accéder à l'instance de Zend_Layout; et vous pouvez ainsi appeler des méthodes
sur l'objet layout. Dans notre cas, nous récupérons une variable appelée $content, et nous
l'affichons. Par défaut, $content est peuplée du contenu de la vue rendue pour l'action en
cours. Sinon, tout ce que vous feriez dans un script de vue est valide dans un script de layout:
appel d'aides ou de méthodes sur la vue.

Maintenant, nous avons un script de layout fonctionnel et notre application sait où le trouver.

2.3. Accéder à l'objet Layout


Il est probable que vous ayez besoin d'accéder à l'objet instance layout. Cela est possible de
trois manières:

• Dans des scripts de vue: utilisez l'aide de vue layout(), qui retourne l'instance de
Zend_Layout enregistrée au moyen du plugin MVC.

<?php $layout = $this->layout(); ?>

Comme cela retourne l'objet de layout, vous pouvez appeler dessus toute méthode ou assigner
des variables.

• Dans vos contrôleurs: utilisez ici l'aide d'action layout(), qui agit comme l'aide de vue.

// Appel de l'aide comme méthode sur le gestionnaire d'aides:


$layout = $this->_helper->layout();

// Ou, de manière plus détaillée:


$helper = $this->_helper->getHelper('Layout');
$layout = $helper->getLayoutInstance();

43
Bien démarrer avec Zend_Layout

Comme avec l'aide de vue, vous pouvez appeler dès lors n'importe quelle méthode de layout
ou lui assigner des variables.

• Ailleurs: utilisez la méthode statique getMvcInstance(). Cette méthode retourne l'instance


de layout comme déja vu plus haut maintenant.

$layout = Zend_Layout::getMvcInstance();

• Via le bootstrap: utilisez la ressource layout qui crée, configure et retourne l'objet
Zend_Layout.

$layout = $bootstrap->getResource('Layout');

Partout où vous avez accès à l'objet bootstrap, il s'agit de la méthode recommandée par
rapport à getMvcInstance().

2.4. Autres opérations


Dans la plupart des cas, le script de configuration de layout ci-dessus (avec quelques
modifications) répondra à vos besoins. Cependant, dans certains cas il peut être intéressant
d'utiliser d'autres fonctionnalités. Dans les exemples qui suivent, vous allez utiliser une
desméthodes listées ci-dessus pour récupérer l'objet layout.

• Affecter les variables de layout. Zend_Layout garde en mémoire les variables de vue
spécifiques à la layout, la clé $content en est un exemple. Vous pouvez assigner et récupérer
ces variables grâce à la méthode assign() ou en y accédant comme des attributs classiques.

// Affecter du contenu:
$layout->somekey = "foo"

// Afficher ce même contenu:


echo $layout->somekey; // 'foo'

// Utiliser la méthode assign() :


$layout->assign('someotherkey', 'bar');

// Accéder à la variable reste identique:


echo $layout->someotherkey; // 'bar'

• disableLayout(). Occasionellement, vous pouriez vouloir d"sactiver totalement les


layouts, par exemple, pour répondre à une requête AJAX ou autravers d'une API RESTful.
Dans ces cas, appelez la méthode disableLayout() de l'objet layout.

$layout->disableLayout();

Le contraire de cette méthode, enableLayout(), permet de ré-activer le rendu des layouts


pour l'action en cours.

• Utiliser un autre script de layout: Si vous avez plusieurs scripts de layout pour votre application,
vous pouvez selectionner lequel rendre grâce à la méthode setLayout(). Précisez alors le
nom du script de layout, sans l'extension.

// Utiliser le script de layout "alternate.phtml":


$layout->setLayout('alternate');

44
Bien démarrer avec Zend_Layout

Le script de layout doit se trouver dans le $layoutPath précisé via la configuration (en
bootstrap générallement). Zend_Layout utilisera le nouveau script à rendre.

3. Zend_Layout: Conclusions
Zend_Layout est une simple surcouche à Zend_View en proposant un pattern Two-Step View,
offrant la fléxibilité de créer un design applicatif dans lequel le contenu est injecté.

Si vous regardez de près les exemple, vous sentirez peut-être que les fonctionnalités sont
limitées : comment modifier le titre de la page, injecter un tag script optionnel ou même créer
une sidebar? Ces questions concernent le concept de "Composite View" -- et trouveront réponse
dans le chapitre suivant couvrant des "placeholders."

45
Bien démarrer avec Zend_View
1. Introduction
In the previous chapter, we looked at primarily the Two Step View pattern, which allows you to
embed individual application views within a sitewide layout. At the end of that chapter, however,
we discussed some limitations:

• How do you alter the page title?

• How would you inject conditional scripts or stylesheets into the sitewide layout?

• How would you create and render an optional sidebar? What if there was some content that
was unconditional, and other content that was conditional for the sidebar?

These questions are addressed in the Composite View design pattern. One approach to that
pattern is to provide "hints" or content to the sitewide layout. In Zend Framework, this is achieved
through specialized view helpers called "placeholders." Placeholders allow you to aggregate
content, and then render that aggregate content elsewhere.

2. Basic Placeholder Usage


Zend Framework defines a generic placeholder() view helper that you may use for as many
custom placeholders you need. It also provides a variety of specific placeholder implementations
for often-needed functionality, such as specifying the DocType declaration, document title, and
more.

All placeholders operate in roughly the same way. They are containers, and thus allow you to
operate on them as collections. With them you can:

• Append or prepend items to the collection.

• Replace the entire collection with a single value.

• Specify a string with which to prepend output of the collection when rendering.

• Specify a string with which to append output of the collection when rendering.

• Specify a string with which to separate items of the collection when rendering.

• Capture content into the collection.

• Render the aggregated content.

Typically, you will call the helper with no arguments, which will return a container on which you
may operate. You will then either echo this container to render it, or call methods on it to configure
or populate it. If the container is empty, rendering it will simply return an empty string; otherwise,
the content will be aggregated according to the rules by which you configure it.

As an example, let's create a sidebar that consists of a number of "blocks" of content. You'll likely
know up-front the structure of each block; let's assume for this example that it might look like this:

<div class="sidebar">

46
Bien démarrer avec Zend_View

<div class="block">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
consectetur aliquet odio ac consectetur. Nulla quis eleifend
tortor. Pellentesque varius, odio quis bibendum consequat, diam
lectus porttitor quam, et aliquet mauris orci eu augue.
</p>
</div>
<div class="block">
<ul>
<li><a href="/some/target">Link</a></li>
<li><a href="/some/target">Link</a></li>
</ul>
</div>
</div>

The content will vary based on the controller and action, but the structure will be the same. Let's
first setup the sidebar in a resource method of our bootstrap:

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
// ...

protected function _initSidebar()


{
$this->bootstrap('View');
$view = $this->getResource('View');

$view->placeholder('sidebar')
// "prefix" -> markup to emit once before all items in collection
->setPrefix("<div class=\"sidebar\">\n <div class=\"block\">\n")
// "separator" -> markup to emit between items in a collection
->setSeparator("</div>\n <div class=\"block\">\n")
// "postfix" -> markup to emit once after all items in a collection
->setPostfix("</div>\n</div>");
}

// ...
}

The above defines a placeholder, "sidebar", that has no items. It configures the basic markup
structure of that placeholder, however, per our requirements.

Now, let's assume for the "user" controller that for all actions we'll want a block at the top
containing some information. We could accomplish this in two ways: (a) we could add the content
to the placeholder directly in the controller's preDispatch() method, or (b) we could render a
view script from within the preDispatch() method. We'll use (b), as it follows a more proper
separation of concerns (leaving view-related logic and functionality within a view script).

We'll name the view script "user/_sidebar.phtml", and populate it as follows:

<?php $this->placeholder('sidebar')->captureStart() ?>


<h4>User Administration</h4>
<ul>
<li><a href="<?php $this->url(array('action' => 'list')) ?>">
List</a></li>
<li><a href="<?php $this->url(array('action' => 'create')) ?>">
Create</a></a></li>

47
Bien démarrer avec Zend_View

</ul>
<?php $this->placeholder('sidebar')->captureEnd() ?>

The above example makes use of the content capturing feature of placeholders. By default,
content is appended as a new item in the container, allowing us to aggregate content. This
example makes use of view helpers and static HTML in order to generate markup, and the content
is then captured and appended into the placeholder itself.

To invoke the above view script, we would write the following in our preDispatch() method:

class UserController extends Zend_Controller_Action


{
// ...

public function preDispatch()


{
// ...

$this->view->render('user/_sidebar.phtml');

// ...
}

// ...
}

Note that we're not capturing the rendered value; there's no need, as the entierty of that view
is being captured into a placeholder.

Now, let's assume our "view" action in that same controller needs to present some information.
Within the "user/view.phtml" view script, we might have the following snippet of content:

$this->placeholder('sidebar')
->append('<p>User: ' . $this->escape($this->username) . '</p>');

This example makes use of the append() method, and passes it some simple markup to
aggregate.

Finally, let's modify our layout view script, and have it render the placeholder.

<html>
<head>
<title>My Site</title>
</head>
<body>
<div class="content">
<?php echo $this->layout()->content ?>
</div>
<?php echo $this->placeholder('sidebar') ?>
</body>
</html>

For controllers and actions that do not populate the "sidebar" placeholder, no content will be
rendered; for those that do, however, echoing the placeholder will render the content according to
the rules we created in our bootstrap, and the content we aggregated throughout the application.
In the case of the "/user/view" action, and assuming a username of "matthew", we would get
content for the sidebar as follows (formatted for readability):

48
Bien démarrer avec Zend_View

<div class="sidebar">
<div class="block">
<h4>User Administration</h4>
<ul>
<li><a href="/user/list">List</a></li>
<li><a href="/user/create">Create</a></a></li>
</ul>
</div>
<div class="block">
<p>User: matthew</p>
</div>
</div>

There are a large number of things you can do by combining placeholders and layout scripts;
experiment with them, and read the relevant manual sections for more information.

3. Standard Placeholders
In the previous section, we learned about the placeholder() view helper, and how it can be
used to aggregate custom content. In this section, we'll look at some of the concrete placeholders
shipped with Zend Framework, and how you can use them to your advantage when creating
complex composite layouts.

Most of the shipped placeholders are for generating content for the <head> section of your layout
content -- an area you typically cannot manipulate directly via your application view scripts, but
one you may want to influence. As examples: you may want your title to contain certain content
on every page, but specific content based on the controller and/or action; you may want to specify
CSS files to load based on what section of the application you're in; you may need specific
JavaScript scripts loaded at different times; or you may want to set the DocType declaration.

Zend Framework ships with placeholder implementations for each of these situations, and
several more.

3.1. Setting the DocType


DocType declarations are troublesome to memorize, and often essential to include in your
document to ensure the browser properly renders your content. The doctype() view helper
allows you to use simple string mnemonics to specify the desired DocType; additionally, other
helpers will query the doctype() helper to ensure the output generated conforms with the
requested DocType.

As an example, if you want to use the XHTML1 Strict DTD, you can simply specify:

$this->doctype('XHTML1_STRICT');

Among the other available mnemonics, you'll find these common types:

XHTML1_STRICT XHTML 1.0 Strict

XHTML1_TRANSITIONAL XHTML 1.0 Transitional

HTML4_STRICT HTML 4.01 Strict

HTML4_Loose HTML 4.01 Loose

HTML5 HTML 5

49
Bien démarrer avec Zend_View

You can assign the type and render the declaration in a single call:

echo $this->doctype('XHTML1_STRICT');

However, the better approach is to assign the type in your bootstrap, and then render it in your
layout. Try adding the following to your bootstrap class:

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
protected function _initDocType()
{
$this->bootstrap('View');
$view = $this->getResource('View');
$view->doctype('XHTML1_STRICT');
}
}

Then, in your layout script, simply echo the helper at the top of the file:

<?php echo $this->doctype() ?>


<html>
<!-- ... -->

This will ensure that your DocType-aware view helpers render the appropriate markup, ensure
that the type is set well before the layout is rendered, and provide a single location to change
the DocType.

3.2. Specifying the Page Title


Often, a site will include the site or business name as part of the page title, and then add additional
information based on the location within the site. As an example, the zend.com website includes
the string "Zend.com" on all pages, and the prepends information based on the page: "Zend
Server - Zend.com". Within Zend Framework, the headTitle() view helper can help simplify
this task.

At its simplest, the headTitle() helper allows you to aggregate content for the <title> tag;
when you echo it, it then assembles it based on the order in which segments are added. You
can control the order using prepend() and append(), and provide a separator to use between
segments using the setSeparator() method.

Typically, you should specify any segments common to all pages in your bootstrap, similar to how
we define the doctype. In this case, we'll define a _initPlaceholders() method for operating
on all the various placeholders, and specify an initial title as well as a separator.

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
// ...

protected function _initPlaceholders()


{
$this->bootstrap('View');
$view = $this->getResource('View');
$view->doctype('XHTML1_STRICT');

// Set the initial title and separator:


$view->headTitle('My Site')

50
Bien démarrer avec Zend_View

->setSeparator(' :: ');
}

// ...
}

Within a view script, we might want to add another segment:

<?php $this->headTitle()->append('Some Page'); // place after other segments ?>


<?php $this->headTitle()->prepend('Some Page'); // place before ?>

In our layout, we will simply echo the headTitle() helper:

<?php echo $this->doctype() ?>


<html>
<?php echo $this->headTitle() ?>
<!-- ... -->

This will generate the following output:

<!-- If append() was used: -->


<title>My Site :: Some Page</title>

<!-- If prepend() was used: -->


<title>Some Page :: My Site</title>

3.3. Specifying Stylesheets with HeadLink


Good CSS developers will often create a general stylesheet for sitewide styles, and individual
stylesheets for specific sections or pages of the website, and load these latter conditionally so
as to decrease the amount of data needing to be transferred on each request. The headLink()
placeholder makes such conditional aggregation of stylesheets trivial within your application.

To accomplish this, headLink() defines a number of "virtual" methods (via overloading) to


make the process trivial. The ones we will be concerned with are appendStylesheet() and
prependStylesheet(). Each takes up to four arguments, $href (the relative path to the
stylesheet), $media (the MIME type, which defaults to "text/css"), $conditionalStylesheet
(which can be used to specify a "condition" under which the stylesheet will be evaluated), and
$extras (an associative array of key and value pairs, commonly used to specify a key for
"media"). In most cases, you will only need to specify the first argument, the relative path to the
stylesheet.

In our example, we'll assume that all pages need to load the stylesheet located in "/styles/
site.css" (relative to the document root); we'll specify this in our _initPlaceholders()
bootstrap method.

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
// ...

protected function _initPlaceholders()


{
$this->bootstrap('View');
$view = $this->getResource('View');
$view->doctype('XHTML1_STRICT');

51
Bien démarrer avec Zend_View

// Set the initial title and separator:


$view->headTitle('My Site')
->setSeparator(' :: ');

// Set the initial stylesheet:


$view->headLink()->prependStylesheet('/styles/site.css');
}

// ...
}

Later, in a controller or action-specific view script, we can add more stylesheets:

<?php $this->headLink()->appendStylesheet('/styles/user-list.css') ?>

Within our layout view script, once again, we simply echo the placeholder:

<?php echo $this->doctype() ?>


<html>
<?php echo $this->headTitle() ?>
<?php echo $this->headLink() ?>
<!-- ... -->

This will generate the following output:

<link rel="stylesheet" type="text/css" href="/styles/site.css" />


<link rel="stylesheet" type="text/css" href="/styles/user-list.css" />

3.4. Aggregating Scripts Using HeadScript


Another common tactic to prevent long page load times is to only load JavaScript when
necessary. That said, you may need several layers of scripts: perhaps one for progressively
enhancing menus on the site, and another for page-specific content. In these situations, the
headScript() helper presents a solution.

Similar to the headLink() helper, headScript() provides the ability to append or prepend
scripts to the collection, and then echo the entire set. It provides the flexibility to specify
either script files themselves to load, or explicit JavaScript. You also have the option of
capturing JavaScript via captureStart()/captureEnd(), which allows you to simply inline
the JavaScript instead of requiring an additional call to your server.

Also like headLink(), headScript() provides "virtual" methods via overloading as a


convenience when specifying items to aggregate; common methods include prependFile(),
appendFile(), prependScript(), and appendScript(). The first two allow you to specify
files that will be referenced in a <script> tag's $src attribute; the latter two will take the content
provided and render it as literal JavaScript within a <script> tag.

In this example, we'll specify that a script, "/js/site.js" needs to be loaded on every page;
we'll update our _initPlaceholders() bootstrap method to do this.

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
// ...

protected function _initPlaceholders()


{

52
Bien démarrer avec Zend_View

$this->bootstrap('View');
$view = $this->getResource('View');
$view->doctype('XHTML1_STRICT');

// Set the initial title and separator:


$view->headTitle('My Site')
->setSeparator(' :: ');

// Set the initial stylesheet:


$view->headLink()->prependStylesheet('/styles/site.css');

// Set the initial JS to load:


$view->headScript()->prependFile('/js/site.js');
}

// ...
}

Within a view script, we might then add an extra script file to source, or capture some JavaScript
to include in our document.

<?php $this->headScript()->appendFile('/js/user-list.js') ?>


<?php $this->headScript()->captureStart() ?>
site = {
baseUrl: "<?php echo $this->baseUrl() ?>"
};
<?php $this->headScript()->captureEnd() ?>

Within our layout script, we then simply echo the placeholder, just as we have all the others:

<?php echo $this->doctype() ?>


<html>
<?php echo $this->headTitle() ?>
<?php echo $this->headLink() ?>
<?php echo $this->headScript() ?>
<!-- ... -->

This will generate the following output:

<script type="text/javascript" src="/js/site.js"></script>


<script type="text/javascript" src="/js/user-list.js"></script>
<script type="text/javascript">
site = {
baseUrl: "<?php echo $this->baseUrl() ?>"
};
</script>

InlineScript Variant
Many browsers will often block display of a page until all scripts and stylesheets
referenced in the <head> section have loaded. If you have a number of such
directives, this can impact how soon somebody can start actually viewing the
page.

One way around this is to emit your <script> tags just prior to closing the
<body> of your document. (This is a practice specifically recommend by the Y!
Slow project.)

53
Bien démarrer avec Zend_View

Zend Framework supports this in two different ways:

• You can render your headScript() tag whereever you like in your layout
script; just because the title references "head" does not mean it needs to be
rendered in that location.

• Alternately, you may use the inlineScript() helper, which is simply a


variant on headScript(), and retains the same behavior, but uses a separate
registry.

4. View Placeholders: Conclusion


View placeholders are a simple and powerful method for creating rich layouts for your application.
You can use a variety of standard placeholders, such as those discussed (doctype(),
headTitle(), headLink(), and headScript()), or use the generic placeholder()
helper to aggregate content and render it in custom ways. Experiment with their exposed
functionality, and visit the appropriate sections in the reference guide to find out about the
additional features they offer -- and how you may leverage those features to create rich content
for your readers.

54
Bien comprendre et utiliser les
décorateurs Zend Form
1. Introduction
Zend_Form utilise le pattern décorateur afin de générer le rendu des éléments. Contrairement au
pattern classique du décorateur, dans lequel se sont des objets qui sont passés, les décorateur
de Zend_Form implémentent un pattern strategy , et utilisent les méta-données contenues dans
l'élément ou le formulaire afin de créer une représentation de celles-ci.

Ne vous laissez pas surprendre par ces termes, les décorateurs de Zend_Form ne sont pas
terriblement difficiles et les mini-tutoriels qui suivent vont vous le prouver. Ils vont vous guider
pour les bases et les techniques avancées de décoration.

2. Les bases des décorateurs


2.1. Aperçu du pattern décorateur
Pour commencer, nous allons voir un epu de théorie sur le pattern décorateur . Une
technique consiste à définir une interface commune que les objets originaux et les décorateurs
implémentent; les décorateurs ayant comme dépendance les objets originaux, ils vont alors
pouvoir redéfinir ou proxier les appels à leurs méthodes. Voyons un peu de code afin de mieux
comprendre:

interface Window
{
public function isOpen();
public function open();
public function close();
}

class StandardWindow implements Window


{
protected $_open = false;

public function isOpen()


{
return $this->_open;
}

public function open()


{
if (!$this->_open) {
$this->_open = true;
}
}

public function close()


{
if ($this->_open) {
$this->_open = false;
}

55
Bien comprendre et utiliser
les décorateurs Zend Form

}
}

class LockedWindow implements Window


{
protected $_window;

public function __construct(Window $window)


{
$this->_window = $window;
$this->_window->close();
}

public function isOpen()


{
return false;
}

public function open()


{
throw new Exception('Cannot open locked windows');
}

public function close()


{
$this->_window->close();
}
}

Nous créons un objet de type StandardWindow, le passons au constructeur de


LockedWindow, et le comportement de notre fenêtre a maintenant changé. Le point fort ici est
que nous n'avons pas besoin d'implémenter une fonctionnalité de verrou ("lock") dans l'objet de
base (StandardWindow) -- le décorateur s'occupe de cela. En plus, vous pouvez utiliser votre
fenêtre décorée à la place de la fenêtre standard : elles implémentent la même interface.

Une utilisation particulièrement pratique du pattern décorateur est pour tout ce qui concerne
la représentation des objets. Par exemple un objet "Personne" qui en lui-même n'a aucune
représentation textuelle. Grâce au pattern décorateur, vous pouvez créer un objet qui va agir
comme une Personne mais qui pourra aussi représenter textuellement cette Personne.

Dans cet exemple particulier, nous allons utiliser leduck typing plutôt qu'une interface explicite.
Ceci permet à notre implémentation d'être un peu plus fléxible tout en gardant l'utilisation de la
décoration intacte.

class Person
{
public function setFirstName($name) {}
public function getFirstName() {}
public function setLastName($name) {}
public function getLastName() {}
public function setTitle($title) {}
public function getTitle() {}
}

class TextPerson
{
protected $_person;

56
Bien comprendre et utiliser
les décorateurs Zend Form

public function __construct(Person $person)


{
$this->_person = $person;
}

public function __call($method, $args)


{
if (!method_exists($this->_person, $method)) {
throw new Exception('Invalid method called on HtmlPerson: '
. $method);
}
return call_user_func_array(array($this->_person, $method), $args);
}

public function __toString()


{
return $this->_person->getTitle() . ' '
. $this->_person->getFirstName() . ' '
. $this->_person->getLastName();
}
}

Dans cet exemple, nous passons une instance Person au constructeur de TextPerson. Grâce
à la surcharge des méthodes, nous pouvons continuer d'appeler les méthodes de Person --
affecter un nom, un prénom, ... -- mais nous pouvons en plus récupérer une représentation sous
forme de chaine grâce à __toString().

Cet exemple est proche du fonctionnement interne des décorateurs de Zend_Form. La


différence est qu'au lieu que le décorateur n'encapsule l'objet initial, c'est l'objet élément qui
possède en lui un ou plusieurs decorateurs à qui il passe lui-même pour effectuer le rendu visuel.
Les décorateurs peuvent ainsi accéder à l'élément et en créer une représentation.

2.2. Créer votre premier décorateur


Les décorateurs de Zend_Form implémentent tous, Zend_Form_Decorator_Interface.
Cette interface permet de régler les options du décorateur, enregistrer en lui l'élément ainsi
qu'effectuer le rendu. YUne classe de base, Zend_Form_Decorator_Abstract, propose une
implémentation de cette logique de base dont vous aurez besoin, à l'exception du rendu que
vous devrez définir.

Imaginons une situation dans laquelle nous souhaitons simplement rendre un élément comme
un tag html text avec un libéllé(label). Juste la base, nous verrons plus tard la gestion des erreurs
et les éventuels autres tags html. Un tel décorateur pourrait ressembler à ça:

class My_Decorator_SimpleInput extends Zend_Form_Decorator_Abstract


{
protected $_format = '<label for="%s">%s</label>'
. '<input id="%s" name="%s" type="text" value="%s"/>';

public function render($content)


{
$element = $this->getElement();
$name = htmlentities($element->getFullyQualifiedName());
$label = htmlentities($element->getLabel());
$id = htmlentities($element->getId());
$value = htmlentities($element->getValue());

$markup = sprintf($this->_format, $name, $label, $id, $name, $value);

57
Bien comprendre et utiliser
les décorateurs Zend Form

return $markup;
}
}

Créons un élément qui utilise ce décorateur:

$decorator = new My_Decorator_SimpleInput();


$element = new Zend_Form_Element('foo', array(
'label' => 'Foo',
'belongsTo' => 'bar',
'value' => 'test',
'decorators' => array($decorator),
));

Le visuel de cet élément donne:

<label for="bar[foo]">Foo</label>
<input id="bar-foo" name="bar[foo]" type="text" value="test"/>

Nous pourrions aussi ranger cette classe dans un dossier de librairie, il faut alors informer
l'élément du chemin vers ce dossier, et ensuite faire référence au décorateur comme
"SimpleInput":

$element = new Zend_Form_Element('foo', array(


'label' => 'Foo',
'belongsTo' => 'bar',
'value' => 'test',
'prefixPath' => array('decorator' => array(
'My_Decorator' => 'path/to/decorators/',
)),
'decorators' => array('SimpleInput'),
));

Ceci permet de partager du code entre projets et ouvre aussi la possibilité d'étendre dans le
futur les classes rangées.

Dans le chapitre suivant, nous allons voir comment combiner les décorateurs afin de créer un
affichage par morceaux (composite).

3. Chainer les décorateurs


Si vous avez bien suivi la section précédente, vous avez pu remarquer que la méthode
render() prend un argument, $content. Il est de type chaine de caractères. render() va
utiliser cette chaine et décider de la remplacer, de rajouter ou de faire précéder du contenu à
celle-ci. Ceci permet de chaine les décorateurs -- ce qui ouvre des possibilités de créer ses
propres décorateurs qui vont rendre une petite partie des données d'un élément chacun -- c'est
la chaine complet de décorateurs qui déterminera le rendu final réel de l'élément.

Voyons voir en pratique comment ça fonctionne.

Pour la plupart des éléments, les décorateurs suiovants sont chargés par défaut:

• ViewHelper: utilise une aide de vue pour rendre l'élément balise de formulaire à proprement
parlé.

• Errors: utilise l'aide de vue FormErrors pour afficher les erreurs de validation éventuelles.

58
Bien comprendre et utiliser
les décorateurs Zend Form

• Description: utilise l'aide de vue FormNote afin de rendre la description éventuelle de


l'élément.

• HtmlTag: encapsule les trois objets ci-dessus dans un tag <dd>.

• Label: rend l'intitulé de l'élément en utilisant l'aide de vue FormLabel (et en encapsulant le
tout dans un tag <dt>).

Notez bien que chaque décorateur na qu'une petite tâche particulière et opère sur une partie
spécifique des données de l'élément auquel il est rattaché, le décorateur Errors récupère les
messages de validation de l'élément et les rend, le décorateur Label rend simplement le libéllé.
Ceci fait que chaque décorateur est très petit, réutilisable, et surtout testable.

Cet argument $content vient de là aussi : chaque décorateur travaille avec sa méthode
render() sur un contenu (générallement généré par le décorateur immédiatement précédent
dans la pile globale) et embellit ce contenu en lui rajoutant ou en lui faisant précéder des
informations. Il peut aussi remplacer totallement son contenu.

Ainsi, pensez au mécanisme des décorateurs comme la conception d'un oignon de l'intérieur
vers l'exterieur.

Voyons voir un exemple, le même que celuide la section précédente:

class My_Decorator_SimpleInput extends Zend_Form_Decorator_Abstract


{
protected $_format = '<label for="%s">%s</label>'
. '<input id="%s" name="%s" type="text" value="%s"/>';

public function render($content)


{
$element = $this->getElement();
$name = htmlentities($element->getFullyQualifiedName());
$label = htmlentities($element->getLabel());
$id = htmlentities($element->getId());
$value = htmlentities($element->getValue());

$markup = sprintf($this->_format, $id, $label, $id, $name, $value);


return $markup;
}
}

Supprimons la fonctionnalité libéllé (label) et créons un décorateur spécifique pour lui.

class My_Decorator_SimpleInput extends Zend_Form_Decorator_Abstract


{
protected $_format = '<input id="%s" name="%s" type="text" value="%s"/>';

public function render($content)


{
$element = $this->getElement();
$name = htmlentities($element->getFullyQualifiedName());
$id = htmlentities($element->getId());
$value = htmlentities($element->getValue());

$markup = sprintf($this->_format, $id, $name, $value);


return $markup;
}
}

59
Bien comprendre et utiliser
les décorateurs Zend Form

class My_Decorator_SimpleLabel extends Zend_Form_Decorator_Abstract


{
protected $_format = '<label for="%s">%s</label>';

public function render($content)


{
$element = $this->getElement();
$id = htmlentities($element->getId());
$label = htmlentities($element->getLabel());

$markup = sprint($this->_format, $id, $label);


return $markup;
}
}

Ok, ca semble bon mais il y a un problème : le dernier décorateur va l'emporter. Vous allez vous
retrouver avec comme seul rendu, celui du dernier décorateur.

Pour faire fonctionner le tout comme il se doit, concaténez simplement le contenu précédent
$content avec le contenu généré:

return $content . $markup;

Le problème avec cette approche est que vous ne pouvez pas choisir où se place
le contenu du décorateur en question. Heureusement, un mécanisme standard existe;
Zend_Form_Decorator_Abstract possède le concept de place et définit des constantes
pour le régler. Aussi, il permet de préciser un séparateur à placer entre les 2. Voyons celà:

class My_Decorator_SimpleInput extends Zend_Form_Decorator_Abstract


{
protected $_format = '<input id="%s" name="%s" type="text" value="%s"/>';

public function render($content)


{
$element = $this->getElement();
$name = htmlentities($element->getFullyQualifiedName());
$id = htmlentities($element->getId());
$value = htmlentities($element->getValue());

$markup = sprintf($this->_format, $id, $name, $value);

$placement = $this->getPlacement();
$separator = $this->getSeparator();
switch ($placement) {
case self::PREPEND:
return $markup . $separator . $content;
case self::APPEND:
default:
return $content . $separator . $markup;
}
}
}

class My_Decorator_SimpleLabel extends Zend_Form_Decorator_Abstract


{
protected $_format = '<label for="%s">%s</label>';

60
Bien comprendre et utiliser
les décorateurs Zend Form

public function render($content)


{
$element = $this->getElement();
$id = htmlentities($element->getId());
$label = htmlentities($element->getLabel());

$markup = sprintf($this->_format, $id, $label);

$placement = $this->getPlacement();
$separator = $this->getSeparator();
switch ($placement) {
case self::APPEND:
return $markup . $separator . $content;
case self::PREPEND:
default:
return $content . $separator . $markup;
}
}
}

Notez que dans l'exemple ci-dessus, nous intervertissons les comportements par défaut avec
append et prepend.

Créons dès lors un élément de formulaire qui va utiliser tout celà:

$element = new Zend_Form_Element('foo', array(


'label' => 'Foo',
'belongsTo' => 'bar',
'value' => 'test',
'prefixPath' => array('decorator' => array(
'My_Decorator' => 'path/to/decorators/',
)),
'decorators' => array(
'SimpleInput',
'SimpleLabel',
),
));

Comment ça fonctionne? et bien nous appelons render(), l'élément va alors commencer une
itération sur tous ses décorateurs, en appelant render() sur chacun. Il va passer une chaine
vide comme contenu pour le premier décorateur, et le rendu de chaque décorateur va servir de
contenu pour le suivant, ainsi de suite:

• Contenu initial : chaine vide: ''.

• chaine vide ('') est passée au décorateur SimpleInput, qui génère un tag de formulaire
de type input qu'il ajoute à la chaine vide: <input id="bar-foo" name="bar[foo]" type="text"
value="test"/>.

• Ce contenu généré est alors passé comme contenu original pour le décorateur SimpleLabel
qui génère un libéllé et le place avant le contenu original avec comme séparateur PHP_EOL, ce
qui donne: <label for="bar-foo">\n<input id="bar-foo" name="bar[foo]" type="text" value="test"/
>.

Mais attendez une minute! Et si nous voulions que le libéllé soit rendu après le tag de formulaire
pour une raison quelconque? Vous souvenez-vous de l'option "placement"? Vous pouvez la
préciser comme option de décorateur, et le plus simple est alors de la passer à la création de
l'élément:

61
Bien comprendre et utiliser
les décorateurs Zend Form

$element = new Zend_Form_Element('foo', array(


'label' => 'Foo',
'belongsTo' => 'bar',
'value' => 'test',
'prefixPath' => array('decorator' => array(
'My_Decorator' => 'path/to/decorators/',
)),
'decorators' => array(
'SimpleInput'
array('SimpleLabel', array('placement' => 'append')),
),
));

Notez que passer des options vous oblige à préciser le nom du décorateur dans un tableau en
tant que premier élément, le deuxième élément est un tableau d'options.

Le code ci-dessus propose un rendu : <input id="bar-foo" name="bar[foo]" type="text"


value="test"/>\n<label for="bar-foo">.

Grâce à cette technique, vous pouvez avoir plusieurs décorateurs dont chacun s'occupe de
rendre une petite partie d'un élément; et c'est en utilisant plusieurs décorateurs et en les chainant
correctement que vous obtiendrez un rendu complet : l'oignon final.

Avantages et inconvénients d'une telle technique, commençons par les inconvénients:

• C'est plus complexe qu'un rendu simple. Vous devez faire attention à chaque décorateur mais
en plus à l'ordre dans lequel ils agissent.

• Ca consomme plus de ressources. Plus de décorateurs, plus d'objets, multipliés par le nombre
d'éléments dans un formulaire et la consommation en ressources augmente. La mise en cache
peut aider.

Les avantages sont:

• Réutilisabilité. Vous pouvez créer des décorateurs complètement réutilisables car vous ne
vous souciez pas du rendu final, mais de chaque petit bout de rendu.

• Fléxibilité. Il est en théorie possible d'arriver au rendu final voulu très exactement, et ceci avec
une petite poignée de décorateurs.

Les exemples ci-dessus montrent l'utilisation de décorateurs au sein même d'un objet
Zend_Form et nous avons vu comment les décorateurs jouent les uns avec les autres pour
arriver au rendu final. Afin de pouvoir les utiliser de manière indépendante, la version 1.7 a
ajouté des méthodes fléxibles rendant les formulaires ressemblant au style Rail. Nous allons
nous pencher sur ce fait dans la section suivante.

4. Rendu individuel des décorateurs


Dans la section précédente, nous avons vu comment combiner les décorateurs afin de créer
un rendu complexe. Ceci est très fléxible mais rajoute tout de même un part de compléxité à
l'ensemble. Dans ce chapitre, nous allons inspecter le rendu individuel des décorateurs afin de
créer du contenu visuel pour des formulaires ou des éléments.

Une fois des décorateurs enregistrés, vous pouvez les récupérer via leur nom depuis l'élément.
Revoyons l'exemple précédent:

$element = new Zend_Form_Element('foo', array(

62
Bien comprendre et utiliser
les décorateurs Zend Form

'label' => 'Foo',


'belongsTo' => 'bar',
'value' => 'test',
'prefixPath' => array('decorator' => array(
'My_Decorator' => 'path/to/decorators/',
)),
'decorators' => array(
'SimpleInput'
array('SimpleLabel', array('placement' => 'append')),
),
));

Si nous voulons récupérer le décorateur SimpleInput, nous passons par la méthode


getDecorator():

$decorator = $element->getDecorator('SimpleInput');
echo $decorator->render('');

C'est simple et ça peut l'être encore plus; ré-écrivons le tout sur une seule ligne:

echo $element->getDecorator('SimpleInput')->render('');

Pas mauvais, mais toujours un peu compliqué. Pour simplifier, une notation raccourcie a été
introduite dans Zend_Form en 1.7: vous pouvez rendre n'importe quel décorateur enregistré en
appelant une méthode de la forme renderDecoratorName(). Ceci effectue le rendu et fait en
sorte que $content soit optionnel ce qui simplifie l'utilisation:

echo $element->renderSimpleInput();

C'est une simplification astucieuse, mais comment et pourquoi l'utiliser?

Beaucoup de développeurs ont des besoins très précis en affichage des formulaires. Ils préfèrent
avoir un contrôle complet sur tout l'affichage plutôt que d'utiliser une solution automatisée
qui peut s'écarter de leur but initial. Dans d'autres cas, les formulaires peuvent demander un
affichage extrêmement spécifique, en groupant des éléments alors que d'autres doivent pouvoir
être invisibles avant que l'on n'effectue telle action sur la page, etc.

Utilisons la possibilité de rendre un seul décorateur pour créer un affichage précis.

D'abord, définissons un formulaire. Celui-ci récupèrera des détails démographiques sur


l'utilisateur. Le rendu sera hautement personnalisé et dans certains cas il utilisera les aides de
vue directement plutôt que les éléments. Voici une définition simple du formulaire:

class My_Form_UserDemographics extends Zend_Form


{
public function init()
{
// Ajoute un chemin pour les décorateurs personnalisés
$this->addElementPrefixPaths(array(
'decorator' => array('My_Decorator' => 'My/Decorator'),
));

$this->addElement('text', 'firstName', array(


'label' => 'First name: ',
));
$this->addElement('text', 'lastName', array(
'label' => 'Last name: ',

63
Bien comprendre et utiliser
les décorateurs Zend Form

));
$this->addElement('text', 'title', array(
'label' => 'Title: ',
));
$this->addElement('text', 'dateOfBirth', array(
'label' => 'Date of Birth (DD/MM/YYYY): ',
));
$this->addElement('text', 'email', array(
'label' => 'Your email address: ',
));
$this->addElement('password', 'password', array(
'label' => 'Password: ',
));
$this->addElement('password', 'passwordConfirmation', array(
'label' => 'Confirm Password: ',
));
}
}

Nous n'utilisons pas de validateurs ou de filtres ici, car ils n'ont rien à voir avec
le rendu visuel qui nous interesse. En réalité, il y en aurait.

Maintenant réfléchissons au rendu visuel du formulaire. Une communalité concernant les nom
et prénom est qu'on les affiche l'un à coté de l'autre, à coté de leur titre, si présent. Les dates,
si elles n'utilisent pas Javascript, affichent souvent des champs séparés pour chaque segment
de la date.

Utilisons la possibilité de rendre des décorateurs un par un pour accomplir notre tâche. D'abord,
notez qu'aucun décorateur spécifique n'a été renseigné dans les éléments. Rappelons donc les
décorateurs par défaut de la plupart des éléments:

• ViewHelper: utilise une aide de vue pour rendre l'élément balise de formulaire à proprement
parlé.

• Errors: utilise l'aide de vue FormErrors pour afficher les erreurs de validation éventuelles.

• Description: utilise l'aide de vue FormNote afin de rendre la description éventuelle de


l'élément.

• HtmlTag: encapsule les trois objets ci-dessus dans un tag <dd>.

• Label: rend l'intitulé de l'élément en utilisant l'aide de vue FormLabel (et en encapsulant le
tout dans un tag <dt>).

Nous vous rappelons aussi que vous pouvez accéder à tout élément individuellement en tant
qu'attribut du formulaire représentant son nom.

Notre script de vue ressemblerait à cela:

<?php
$form = $this->form;
// Enlève le <dt> depuis l'intitulé
foreach ($form->getElements() as $element) {
$element->getDecorator('label')->setOption('tag', null);
}
?>

64
Bien comprendre et utiliser
les décorateurs Zend Form

<form method="<?php echo $form->getMethod() ?>" action="<?php echo


$form->getAction()?>">
<div class="element">
<?php echo $form->title->renderLabel()
. $form->title->renderViewHelper() ?>
<?php echo $form->firstName->renderLabel()
. $form->firstName->renderViewHelper() ?>
<?php echo $form->lastName->renderLabel()
. $form->lastName->renderViewHelper() ?>
</div>
<div class="element">
<?php echo $form->dateOfBirth->renderLabel() ?>
<?php echo $this->formText('dateOfBirth[day]', '', array(
'size' => 2, 'maxlength' => 2)) ?>
/
<?php echo $this->formText('dateOfBirth[month]', '', array(
'size' => 2, 'maxlength' => 2)) ?>
/
<?php echo $this->formText('dateOfBirth[year]', '', array(
'size' => 4, 'maxlength' => 4)) ?>
</div>
<div class="element">
<?php echo $form->password->renderLabel()
. $form->password->renderViewHelper() ?>
</div>
<div class="element">
<?php echo $form->passwordConfirmation->renderLabel()
. $form->passwordConfirmation->renderViewHelper() ?>
</div>
<?php echo $this->formSubmit('submit', 'Save') ?>
</form>

Si vous utilisez le script ci-dessus, vous verrez un code HTML ressemblant à ceci:

<form method="post" action="">


<div class="element">
<label for="title" tag="" class="optional">Title:</label>
<input type="text" name="title" id="title" value=""/>

<label for="firstName" tag="" class="optional">First name:</label>


<input type="text" name="firstName" id="firstName" value=""/>

<label for="lastName" tag="" class="optional">Last name:</label>


<input type="text" name="lastName" id="lastName" value=""/>
</div>

<div class="element">
<label for="dateOfBirth" tag="" class="optional">Date of Birth
(DD/MM/YYYY):</label>
<input type="text" name="dateOfBirth[day]" id="dateOfBirth-day"
value="" size="2" maxlength="2"/>
/
<input type="text" name="dateOfBirth[month]" id="dateOfBirth-month"
value="" size="2" maxlength="2"/>
/
<input type="text" name="dateOfBirth[year]" id="dateOfBirth-year"
value="" size="4" maxlength="4"/>
</div>

65
Bien comprendre et utiliser
les décorateurs Zend Form

<div class="element">
<label for="password" tag="" class="optional">Password:</label>
<input type="password" name="password" id="password" value=""/>
</div>

<div class="element">
<label for="passwordConfirmation" tag="" class="" id="submit"
value="Save"/>
</form>

Ca peut ne pas ressembler à quelque chose de terminé, mais avec un peu de CSS, cela
peut ressembler exactement à ce que vous cherchez. Le point important ici, c'est que le
formulaire a été généré en utilisant de la décoration manuelle personnalisée (ainsi que l'utilisation
d'échappement avec htmlentities).

Grâce à cette partie du tutoriel, vous devriez être à l'aise avec les possibilité de rendu de
Zend_Form. Dans la section suivante, nous verrons comment monter un élément de date grâce
à des éléments et des décorateur uniques assemblés main.

5. Créer et rendre des éléments composites


Dans la dernière section, nous avions un exemple traitant un élément "date de naissance":

<div class="element">
<?php echo $form->dateOfBirth->renderLabel() ?>
<?php echo $this->formText('dateOfBirth[day]', '', array(
'size' => 2, 'maxlength' => 2)) ?>
/
<?php echo $this->formText('dateOfBirth[month]', '', array(
'size' => 2, 'maxlength' => 2)) ?>
/
<?php echo $this->formText('dateOfBirth[year]', '', array(
'size' => 4, 'maxlength' => 4)) ?>
</div>

Comment représenteriez-vous cet élément en tant que Zend_Form_Element? Comment écrire


un décorateur qui s'assure de son rendu ?

5.1. L'élément
Les questions à se poser sur le fonctionnement de l'élément sont:

• Comment affecter et récupérer une valeur?

• Comment valider la valeur?

• Comment proposer l'affectation personnalisée d'une valeur composées de trois segments


(jour, mois, année)?

Les deux première questions se positionnent sur l'élément de formulaire lui-même, comment
vont fonctionner les méthodes setValue() et getValue()? L'autre question nous suggère
de nous questionner sur comment récupérer les segments représentant la date, ou comment
les affecter dans l'élément?

La solution est de surcharger la méthode setValue() dans l'élément pour proposer sa propre
logique. Dans le cas de notre exemple, notre élément devrait avoir trois comportements distincts:

66
Bien comprendre et utiliser
les décorateurs Zend Form

• Si un timestamp entier est utilisé, il doit aider à la détermination des entités jour, mois, année.

• Si une chaine est utilisée, elle devrait être transformée en timestamp, et cette valeur sera
utiliser pour déterminer les entités jour, mois, année.

• Si un tableau contenant les clés jour, mois, année est utilisé, alors les valeurs doivent être
stockées.

En interne, les jour, mois et année seront stockés distinctement. Lorsque la valeur de l'élément
sera demandée, nous récupèrerons une chaine formatée et normalisée. Nous surchargerons
getValue() pour assembler les segments élémentaires composant la date.

Voici à quoi ressemblerait la classe:

class My_Form_Element_Date extends Zend_Form_Element_Xhtml


{
protected $_dateFormat = '%year%-%month%-%day%';
protected $_day;
protected $_month;
protected $_year;

public function setDay($value)


{
$this->_day = (int) $value;
return $this;
}

public function getDay()


{
return $this->_day;
}

public function setMonth($value)


{
$this->_month = (int) $value;
return $this;
}

public function getMonth()


{
return $this->_month;
}

public function setYear($value)


{
$this->_year = (int) $value;
return $this;
}

public function getYear()


{
return $this->_year;
}

public function setValue($value)


{
if (is_int($value)) {
$this->setDay(date('d', $value))
->setMonth(date('m', $value))

67
Bien comprendre et utiliser
les décorateurs Zend Form

->setYear(date('Y', $value));
} elseif (is_string($value)) {
$date = strtotime($value);
$this->setDay(date('d', $date))
->setMonth(date('m', $date))
->setYear(date('Y', $date));
} elseif (is_array($value)
&& (isset($value['day'])
&& isset($value['month'])
&& isset($value['year'])
)
) {
$this->setDay($value['day'])
->setMonth($value['month'])
->setYear($value['year']);
} else {
throw new Exception('Valeur de date invalide');
}

return $this;
}

public function getValue()


{
return str_replace(
array('%year%', '%month%', '%day%'),
array($this->getYear(), $this->getMonth(), $this->getDay()),
$this->_dateFormat
);
}
}

Cette classe est fléxible : nous pouvons affecter les valeurs par défaut depuis une base de
données et être certains qu'elles seront stockées correctement. Aussi, la valeur peut être affectée
depuis un tableau provenant des entrées du formulaire. Enfin, nous avons tous les accesseurs
distincts pour chaque segment de la date, un décorateur pourra donc créer l'élément comme
il le voudra.

5.2. Le décorateur
Toujours en suivant notre exemple, imaginons que nous voulions que notre utilisateur saisissent
chaque segment jour, mois, année séparément. Heureusement, PHP permet d'utiliser la notation
tableau pour créer des éléments, ainsi nous pourrons capturer ces trois valeurs en une seule et
nous crérons un élément Zend_Form traitant avec des valeurs en tableau.

Le décorateur est relativement simple: Il va récupérer le jour, le mois et l'année de l'élément et


passer chaque valeur à une aide de vue qui rendra chaque champ individuellement. Nous les
rassemblerons ensuite dans le rendu final.

class My_Form_Decorator_Date extends Zend_Form_Decorator_Abstract


{
public function render($content)
{
$element = $this->getElement();
if (!$element instanceof My_Form_Element_Date) {
// Nous ne rendons que des éléments Date
return $content;
}

68
Bien comprendre et utiliser
les décorateurs Zend Form

$view = $element->getView();
if (!$view instanceof Zend_View_Interface) {
// Nous utilisons des aides de vue, si aucune vue n'existe
// nous ne rendons rien
return $content;
}

$day = $element->getDay();
$month = $element->getMonth();
$year = $element->getYear();
$name = $element->getFullyQualifiedName();

$params = array(
'size' => 2,
'maxlength' => 2,
);
$yearParams = array(
'size' => 4,
'maxlength' => 4,
);

$markup = $view->formText($name . '[day]', $day, $params)


. ' / ' . $view->formText($name . '[month]', $month, $params)
. ' / ' . $view->formText($name . '[year]', $year, $yearParams);

switch ($this->getPlacement()) {
case self::PREPEND:
return $markup . $this->getSeparator() . $content;
case self::APPEND:
default:
return $content . $this->getSeparator() . $markup;
}
}
}

Il faut maintenant préciser à notre élément d'utiliser notre décorateur par défaut. Pour ceci, il
faut informer l'élément du chemin vers notre décorateur. Nous pouvons effectuer ceci par le
constructeur:

class My_Form_Element_Date extends Zend_Form_Element_Xhtml


{
// ...

public function __construct($spec, $options = null)


{
$this->addPrefixPath(
'My_Form_Decorator',
'My/Form/Decorator',
'decorator'
);
parent::__construct($spec, $options);
}

// ...
}

Notez que l'on fait cela en constructeur et non dans la méthode init(). Ceci pour deux raisons.
D'abord, ceci permet d'étendre dans le futur notre élément afin d'y ajouter de la logique dans

69
Bien comprendre et utiliser
les décorateurs Zend Form

init sans se soucier de l'appel à parent::init(). Ensuite, celà permet aussi de redéfinir
le décorateur par défaut Date dans le futur si celà devient nécessaire, via le constructeur ou
la méthode init.

Ensuite, nous devons réécrire la méthode loadDefaultDecorators() pour lui indiquer


d'utiliser notre décorateur Date:

class My_Form_Element_Date extends Zend_Form_Element_Xhtml


{
// ...

public function loadDefaultDecorators()


{
if ($this->loadDefaultDecoratorsIsDisabled()) {
return;
}

$decorators = $this->getDecorators();
if (empty($decorators)) {
$this->addDecorator('Date')
->addDecorator('Errors')
->addDecorator('Description', array(
'tag' => 'p',
'class' => 'description'
))
->addDecorator('HtmlTag', array(
'tag' => 'dd',
'id' => $this->getName() . '-element'
))
->addDecorator('Label', array('tag' => 'dt'));
}
}

// ...
}

A qyuoi ressemble le rendu final ? Considérons l'élément suivant:

$d = new My_Form_Element_Date('dateOfBirth');
$d->setLabel('Date de naissance: ')
->setView(new Zend_View());

// Ces deux procédés sont équivalents:


$d->setValue('20 April 2009');
$d->setValue(array('year' => '2009', 'month' => '04', 'day' => '20'));

Si vous affichez cet élément, vous obtiendrez ce rendu (avec quelques modifications concernant
la mise en page du manuel et sa lisibilité):

<dt id="dateOfBirth-label"><label for="dateOfBirth" class="optional">


Date de naissance:
</label></dt>
<dd id="dateOfBirth-element">
<input type="text" name="dateOfBirth[day]" id="dateOfBirth-day"
value="20" size="2" maxlength="2"> /
<input type="text" name="dateOfBirth[month]" id="dateOfBirth-month"
value="4" size="2" maxlength="2"> /
<input type="text" name="dateOfBirth[year]" id="dateOfBirth-year"

70
Bien comprendre et utiliser
les décorateurs Zend Form

value="2009" size="4" maxlength="4">


</dd>

5.3. Conclusion
Nous avons maintenant un élément qui peut rendre de multiples champs de formulaire, et les
traiter comme une seule entité -- la valeur dateOfBirth sera passée comme un tableau à
l'élément et celui-ci créra les segments de date appropriés et retournera une valeur normalisée.

Aussi, nous pouvons toujours utiliser des décorateurs différents avec l'élément. Si nous avions
voulu utiliser un décorateur Dojo DateTextBox -- qui accepte et retourne des chaines -- we
aurions pu, sans modification sur l'élément lui-même.

Enfin, vous avez une API uniforme pour décrire un élement se composant se plusieurs segments
distincts.

6. Conclusion
Les décorateur de formulaire sont un système qui peut prendre du temps à maitriser. A première
vue, ils semblent complexes et rudes. Mais les différents sujets traités dans ce chapitre vous
aident à comprendre leur fonctionnement et vous montrent des manières de faire pour les utiliser
efficacement dans vos formulaires.

71
Bien démarrer avec Zend_Session,
Zend_Auth, et Zend_Acl
1. Fabrique une application Multi-Utilisateurs avec Zend
Framework
1.1. Zend Framework
Lorsque le web a été crée, il s'agissait d'un média permettant de consulter des documents
statiques. La demande de contenu a cru, le nombre d'internautes aussi et les sites webs sont
devenus des applications tournant sur de grosses plateformes.

HTTP est le protocole du web: sans état, des requêtes/réponses à courte durée de vie. Ce
protocole a été crée comme cela pour assurer le web tel qu'on l'entendait avant : servir du
contenu statique et c'est ce design qui a fait du web un immense succès. C'est aussi ce design
qui mène à des notions que les développeurs veulent utiliser dans leurs applications.

Ces informations nous mènent à trois questions:

• Comment distinguer les clients d'une application?

• Comment identifier ces clients?

• Comment contrôler les droits d'un client identifié?

Client contre Utilisateur

Nous utilisons le terme "client" et pas utilisateur. Les applications web deviennent
des fournisseurs de services. Ceci signifie que les "gens", les utilisateurs
humains avec des navigateurs web ne sont pas les seuls à consommer
l'application et ses services. Beaucoup d'autres applications web consomment
elles-mêmes des ressources sur une application via des technologies comme
REST, SOAP, ou XML-RPC. On voit bien qu'on ne peut parler d'utilisateur, nous
traitons donc les utilisateurs humains des utilisateurs machines sous le même
nom : des "clients" web.

Dans les chapitres qui suivent, nous nous attaquerons à ces problèmes que sont
l'authentification, l'identification et les détails. Nous allons découvrir trois composants:
Zend_Session, Zend_Auth, et Zend_Acl; nous montrerons des exemples concrets et des
possibilités d'extension.

2. Gérer les sessions dans ZF


2.1. Introduction aux sessions
Le succès du web est en grande partie dûe aux protocoles qui le supportent: HTTP. HTTP sur
TCP est par nature sans état ce qui signifie que le web n'a pas "de mémoire". Ce fait pose des
problèmes pour les développeurs voulant traiter leur application comme un service riche.

72
Bien démarrer avec Zend_Session,
Zend_Auth, et Zend_Acl

Interagir avec l'application web c'est en fait faire la somme de toutes les requêtes que celle-ci
reçoit. Et comme il y a beaucoup de clients, il y a beaucoup de requête, et le moyen d'associer
une requête à un client est appelé "session".

En PHP, le problème des sessions a été résolu au travers de l'extension session qui utilise un
système de persistance, typiquement basé sur des cookies et un stockage local des variables
dans $_SESSION. Dans Zend Framework, le composant Zend_Session ajoute de la valeur au
système de session de PHP notamment une manipulation objet.

2.2. Utilisation classique de Zend_Session


Le composant Zend_Session est un gestionnaire de session et une API pour stocker des
données dans la session de manière objet. L'API de la classe Zend_Session API permet de régler
des options et de démarrer/arrêter la session alors que Zend_Session_Namespace représente
un objet contenant des données à stocker en session.

C'est générallement une bonne pratique que de démarrer sa session en bootstrap, cependant
la première création d'un objet Zend_Session_Namespace démarrera la session par défaut.

Zend_Application peut permettre de configurer Zend_Session grâce aux parties


Zend_Application_Resource. Pour les utiliser, en supposant que votre projet utilise
Zend_Application, ajoutez le code suivant à application.ini:

resources.session.save_path = APPLICATION_PATH "/../data/session"


resources.session.use_only_cookies = true
resources.session.remember_me_seconds = 864000

Comme vous le remarquez, les options utilisées sont les mêmes que celles que reconnait ext/
session (l'extension session de PHP). Le chemin de stockage des session par exemple. Les
fichiers ini peuvent utiliser des constantes, nous réutilisons APPLICATION_PATH pour calculer
le chemin relatif vers un dossier arbitraire sensé stocker les sessions.

La plupart des composants de Zend Framework utilisant les sessions n'ont rien besoin de plus.
Dès lors, vous pouvez utiliser un composant faisant appel à la session, ou manipuler la session
vous-même au travers d'un ou plusieurs objets Zend_Session_Namespace.

Zend_Session_Namespace est une classe qui guide ses données vers $_SESSION. La
classe s'appelle Zend_Session_Namespace car elle crée des espaces de noms au sein de
$_SESSION, autorisant plusieurs composants ou objets à stocker des valeurs sans se marcher
dessus. Nous allons voir dans l'exemple qui suit comment créer un simple compteur de session
qui commence à 1000 et se remet à zéro après 1999.

$mysession = Zend_Session_Namespace('mysession');

if (!isset($mysession->counter)) {
$mysession->counter = 1000;
} else {
$mysession->counter++;
}

if ($mysession->counter > 1999) {


unset($mysession->counter);
}

Comme vous le remarquez, l'objet de session utilise les méthodes magiques __get, __set,
__isset, et __unset pour proposer une API intuitive. Les informations stockées dans notre
exemple le sont en réalité dans $_SESSION['mysession']['counter'].

73
Bien démarrer avec Zend_Session,
Zend_Auth, et Zend_Acl

2.3. Utilisation avancée de Zend_Session


Si vous voulez utiliser le gestionnaire de sauvegarde des sessions "DbTable", vous pouvez
simplement ajouter ces options à application.ini:

resources.session.saveHandler.class = "Zend_Session_SaveHandler_DbTable"
resources.session.saveHandler.options.name = "session"
resources.session.saveHandler.options.primary.session_id = "session_id"
resources.session.saveHandler.options.primary.save_path = "save_path"
resources.session.saveHandler.options.primary.name = "name"
resources.session.saveHandler.options.primaryAssignment.sessionId = "sessionId"
resources.session.saveHandler.options.primaryAssignment.sessionSavePath = "sessionSavePath"
resources.session.saveHandler.options.primaryAssignment.sessionName = "sessionName"
resources.session.saveHandler.options.modifiedColumn = "modified"
resources.session.saveHandler.options.dataColumn = "session_data"
resources.session.saveHandler.options.lifetimeColumn = "lifetime"

3. Authentification d'utilisateurs dans Zend Framework


3.1. Introduction à l'authentification
Une fois que l'application a récupéré les informations d'un utilisateur, elle doit vérifier leur
"authenticité", c'est l'authentification. Pour celà, deux informations sont nécessaires : l'identifiant
et un ensemble de règles régissant cet identifiant, aujourd'hui typiquement une chaine de
caractères servant de mot de passe est très classique, mais d'autres procédés existent
(reconnaissances digitales, occulaires...)

Un identifiant peut lui aussi être un "login" tout banal, mais pourquoi pas un numéro de membre,
une adresse email... le secret, lui, est donc souvent un mot de passe sous forme de chaine de
caractères.

3.2. Utilisation de base de Zend_Auth


Dans l'exemple suivant, nous utiliserons Zend_Auth afin d'effectuer une authentification des
plus classiques: champ login et password puis vérification en base de données. Cet exemple
suppose que vous utilisez Zend_Application afin de configurer une connexion à une base
de données.

Zend_Auth effectue deux tâches. D'abord elle doit récupérer un adaptateur d'authentification
afin de déclencher le processus d'authentification, puis si celui-ci est correct, elle doit faire
persister ces informations entre requêtes. Pour assurer cette persistance, Zend_Auth utilise un
Zend_Session_Namespace, mais en général vous n'aurez pas besoin d'agir sur cet objet.

Supposant une table de base de données suivante:

CREATE TABLE users (


id INTEGER NOT NULL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(32) NULL,
password_salt VARCHAR(32) NULL,
real_name VARCHAR(150) NULL
)

C'est une table qui inclue des champs nom, password et aussi grain de sel. Le grain de sel est
utilisé pour améliorer la sécurité contre les attaques par force brute qui cibleraient l'alogithme de
hashage du mot de passe. Plus d'informations sur le grain de sel.

74
Bien démarrer avec Zend_Session,
Zend_Auth, et Zend_Acl

Créons un formulaire de login simple. Nous utiliserons Zend_Form.

// localisé à application/forms/Auth/Login.php

class Default_Form_Auth_Login extends Zend_Form


{
public function init()
{
$this->setMethod('post');

$this->addElement(
'text', 'username', array(
'label' => 'Username:',
'required' => true,
'filters' => array('StringTrim'),
));

$this->addElement('password', 'password', array(


'label' => 'Password:',
'required' => true,
));

$this->addElement('submit', 'submit', array(


'ignore' => true,
'label' => 'Login',
));

}
}

Ce formulaire nous mène vers la création du contrôleur de traitement. Nous


l'appellerons "AuthController", et le logerons dans application/controllers/
AuthController.php. Il possèdera une seule méthode "loginAction()" vers laquelle le
formulaire enverra, la méthode va donc réagir à GET et à POST, elle encapsule toute la logique.

Le code suivant montre comment construire l'adaptateur d'authentification et l'intégration du


formulaire:

class AuthController extends Zend_Controller_Action


{

public function loginAction()


{
$db = $this->_getParam('db');

$loginForm = new Default_Form_Auth_Login($_POST);

if ($loginForm->isValid()) {

$adapter = new Zend_Auth_Adapter_DbTable(


$db,
'users',
'username',
'password',
'MD5(CONCAT(?, password_salt))'
);

$adapter->setIdentity($loginForm->getValue('username'));
$adapter->setCredential($loginForm->getValue('password'));

75
Bien démarrer avec Zend_Session,
Zend_Auth, et Zend_Acl

$result = $auth->authenticate($adapter);

if ($result->isValid()) {
$this->_helper->FlashMessenger('Successful Login');
$this->redirect('/');
return;
}

$this->view->loginForm = $loginForm;

Le script de vue est quant à lui enfantin, il sera logé dans application/views/scripts/
auth/login.phtml:

$this->form->setAction($this->url());
echo $this->form;

Et voila! Avec ce scénario de base, vous pouvez étendre les possibilités et répondre à vos
besoins précis. Tous les adaptateurs Zend_Auth se trouvent décrits dans le guide de réference.

4. Fabriquer un système de gestion d'autorisations avec


Zend Framework
4.1. Introduction à l'autorisation
Après qu'un utilisateur se soit authentifié, une application peut proposer différentes règles
d'accès à ses différentes ressources (parties). Le procédé qui consiste à savoir "qui a le droit
de faire quoi" est nommé "gestion des autorisations". Dans sa forme la plus simple l'autorisation
est la composition de trois facteurs:

• l'identitié de la personne souhaitant des droits - le rôle (qui?)

• la ressource demandée (sur quoi?)

• et optionnellement le privilège - le droit (quoi?)

Dans Zend Framework, le composant Zend_Acl vous propose de créer ces trois entités
remarquables, de les associer et de les interroger dans le futur.

4.2. Utilisation de base de Zend_Acl


En utilisant Zend_Acl, n'importe quel modèle peut servir de rôle ou de
ressource en implémentant l'interface adéquate. Pour créer des rôles, implémentez
Zend_Acl_Role_Interface, qui définit la méthode getRoleId(). Pour créer des
ressources, implémentez Zend_Acl_Resource_Interface qui définit la méthode
getResourceId().

Nous allons faire une démonstration avec un modèle simple. On peut le relier avec notre système
d'ACL en implémentant Zend_Acl_Role_Interface. La méthode getRoleId() retournera
"guest" lorsque l'ID est inconnu, ou l'ID du rôle lorsque celui-ci aura été affecté. Cette valeur

76
Bien démarrer avec Zend_Session,
Zend_Auth, et Zend_Acl

peut provenir de n'importe où, probablement qu'elle proviendra d'une définition faite en base de
données.

class Default_Model_User implements Zend_Acl_Role_Interface


{
protected $_aclRoleId = null;

public function getRoleId()


{
if ($this->_aclRoleId == null) {
return 'guest';
}

return $this->_aclRoleId;
}
}

Le concept des utilisateurs ayant des rôles est simple à comprendre, mais l'application peut
consommer plusieurs modèles et en retrouver des "ressources" qui seront consommables par
les rôles. Nous utiliserons simplement des billets de blog comme ressources dans nos exemples,
et comme les ressources sont des objets, nous ferons en sorte que l'ID d'un billet blog soir
'blogPost', naturellement cette valeur peut être calculée dynamiquement en fonction du besoin.

class Default_Model_BlogPost implements Zend_Acl_Resource_Interface


{
public function getResourceId()
{
return 'blogPost';
}
}

Maintenant que nous avons au minimum un rôle et une ressource, définissons règles qui les
lient. Ces règles seront lues lorsque le système recevra une requête d'acl demandant ce qu'il
est possible de faire avec tel rôle, telle ressource et éventuellement tel privilège.

Imaginons les règles suivantes:

$acl = new Zend_Acl();

// mise en place des rôles


$acl->addRole('guest');
// owner hérite du rôle guest
$acl->addRole('owner', 'guest');

// ajout de ressources
$acl->addResource('blogPost');

// ajout de privilèges liant des rôles et des ressources


$acl->allow('guest', 'blogPost', 'view');
$acl->allow('owner', 'blogPost', 'post');
$acl->allow('owner', 'blogPost', 'publish');

Les règles ci-dessus sont très simples: deux rôles "guest"(invité) et "owner" (propriétaire), et une
ressource "blogPost"(billet). Les invités sont autorisés à voir les billets, les propriétaires peuvent
poster et publier des billets. Pour requêter le système, procédez alors comme suit:

// Imaginons que le modèle User soit de type "guest"

77
Bien démarrer avec Zend_Session,
Zend_Auth, et Zend_Acl

$guestUser = new Default_Model_User();


$ownerUser = new Default_Model_Owner('OwnersUsername');

$post = new Default_Model_BlogPost();

$acl->isAllowed($guestUser, $post, 'view'); // true


$acl->isAllowed($ownerUser, $post, 'view'); // true
$acl->isAllowed($guestUser, $post, 'post'); // false
$acl->isAllowed($ownerUser, $post, 'post'); // true

Comme vous pouvez le voir le système répond comme il faut dans la mesure où les invités
peuvent lire les billets mais seuls les propriétaires peuvent en ajouter. Cependant ce système
peut sembler manquer de dynamisme. Comment vérifier qu'un utilisateur spécifique est bien
propriétaire d'un billet spécifique avant de l'autoriser à le publier ? Autrement dit, on veut s'assurer
que seuls les propriétaires des billets peuvent publier ceux-ci, et pas ceux des autres.

C'est là qu'entrent en jeu les assertions. Les assertions sont des vérifications supplémentaires à
effectuer en même temps que la vérification de la règle d'acl. Ce sont des objets. Utilisons notre
exemple avec une assertion:

class OwnerCanPublishBlogPostAssertion implements Zend_Acl_Assert_Interface


{
/**
* Cette assertion va recevoir le User et le BlogPost actuels.
*
* @param Zend_Acl $acl
* @param Zend_Acl_Role_Interface $user
* @param Zend_Acl_Resource_Interface $blogPost
* @param $privilege
* @return bool
*/
public function assert(Zend_Acl $acl,
Zend_Acl_Role_Interface $user = null,
Zend_Acl_Resource_Interface $blogPost = null,
$privilege = null)
{
if (!$user instanceof Default_Model_User) {
throw new Exception(__CLASS__
. '::'
. __METHOD__
. ' s'attend à un rôle'
. ' instance de User');
}

if (!$blogPost instanceof Default_Model_BlogPost) {


throw new Exception(__CLASS__
. '::'
. __METHOD__
. ' s'attend à un rôle'
. ' instance de BlogPost');
}

// Si le rôle est publisher, il peut toujours modifier son billet


if ($user->getRoleId() == 'publisher') {
return true;
}

// vérifions que qui que ce soit, il modifie uniquement ses propres billets
if ($user->id != null && $blogPost->ownerUserId == $user->id) {

78
Bien démarrer avec Zend_Session,
Zend_Auth, et Zend_Acl

return true;
} else {
return false;
}
}
}

Pour faire intervenir l'assertion dans les ACL, nous les utilisons comme ceci:

// remplacez ceci:
// $acl->allow('owner', 'blogPost', 'publish');
// par cela:
$acl->allow('owner',
'blogPost',
'publish',
new OwnerCanPublishBlogPostAssertion());

// ajoutons aussi le rôle "publisher" qui a accès à tout


$acl->allow('publisher', 'blogPost', 'publish');

Maintenant, dès que l'ACL est consultée pour savoir si un propriétaire peut publier un billet, cette
assertion sera vérifiée. Elle s'assure que sauf si le rôle est 'publisher' le propriétaire a bien écrit le
billet. Dans cet exemple, nous vérifions pour savoir si l'attribut ownerUserId du billet correspond
à l'identifiant de l'utilisateur en question.

79
Bien démarrer avec
Zend_Search_Lucene
1. Introduction à Zend_Search_Lucene
Le composant Zend_Search_Lucene est prévu pour fournir une solution de recherche full-text
1
prête à l'emploi. Il ne nécessite aucunes extensions PHP ni que des logiciels supplémentaires
soient installés, et peut être utilisé tout de suite après l'installation du Framework Zend.

Zend_Search_Lucene est un portage PHP du moteur de recherche full-text open source


populaire connu comme Apache Lucene. Voir http://lucene.apache.org/ pour plus de détails.

L'information doit être indexée pour être disponible à la recherche. Zend_Search_Lucene


et Java Lucene utilise un concept de document connu sous le nom d'"indexation atomique
d'élément."

Chaque document est un ensemble de champs : paires <nom, valeur> où le nom et la valeur sont
2
des chaînes UTF-8 . N'importe quel sous ensemble de champs de document peut être marqué
comme "indexé" pour inclure des données de champ durant le processus d'indexation de texte.

Les valeurs de champs peuvent être indexées segmentées durant l'indexation. Si un champ
n'est pas segmenté, alors la valeur du champ est stockée comme un seul terme ; autrement,
l'analyseur courant est utilisé pour la segmentation.

Plusieurs analyseurs sont fournis dans le paquet Zend_Search_Lucene. L'analyseur par


défaut fonctionne avec du texte ASCII (comme l'analyseur UTF-8 a besoin que l'extension
mbstring soit activée). Il n'est pas sensible à la case, et saute les nombres. Utilisez d'autres
analyseurs ou créez votre propre analyseur si vous avez besoin de changer ce comportement.

Utilisation des analyseurs durant l'indexation et la recherche

Note importante ! Les requêtes de recherches sont aussi segmentées en utilisant


"l'analyseur courant", ainsi le même analyseur doit être défini par défaut durant
le processus d'indexation et le processus de recherche. Ceci garantira que la
source et le texte recherché seront transformés en termes de la même manière.

Les valeurs de champs sont stockés optionnellement au sein de l'index. Ceci permet aux
données originale du champ d'être récupérée pendant la recherche. C'est le seul moyen
d'associer les résultats de recherche avec les données originales (l'ID interne du document peut
avoir changé après une optimisation d'index ou une auto-optimisation).

Ce qui doit être gardé en mémoire, c'est que l'index Lucene n'est pas une base de données. Il ne
fournit pas un mécanisme de sauvegarde de l'index à l'exception de la sauvegarde du répertoire
du système de fichier. Il ne fournit pas de mécanisme transactionnel bien que soient supportés
la mise à jour concurrente d'index ainsi que que la mise à jour et la lecture concurrente. Il n'est
pas comparable aux bases de données en terme de vitesse de récupération de données.

Donc c'est une bonne idée :


1
Bien que quelques fonctionnalités de traitement UTF-8 nécessitent que l'extension mbstring soit activée
2
Les chaînes Binaires sont aussi autorisées pour être utilisées comme des valeurs de champs

80
Bien démarrer avec
Zend_Search_Lucene

• De ne pas utiliser l'index Lucene comme du stockage car cela réduirait les performance de
récupération de résultat de recherche. Stocker uniquement les identifiants de documents
(chemin de documents, URLs, identifiant unique de base données) et associer les données
au sein de l'index. Ex. titre, annotation, categorie, information de langue, avatar. (Note : un
champs peut être inclu dans l'indexation, mais pas stocké, ou stocké, mais pas indexé).

• D'écrire des fonctionalités qui peuvent reconstruire intégralement l'index, si il a été corrompu
pour une raison ou pour une autre.

Les documents individuels dans l'index peuvent avoir des ensemble de champs totalement
différents. Le même champ dans différents documents n'a pas besoin d'avoir les mêmes
attributs. Ex. un champs peu être indexé pour l'un des documents mais sauté pour l'indexation
d'un autre. Le même principe s'applique au stockage, à la segmentation, ou traitement de valeur
de champ comme chaîne binaire.

2. Structure d'index Lucene


Afin d'utiliser l'intégralité des fonctionnalités de Zend_Search_Lucene avec un maximum de
performances, il est nécessaire que vous compreniez la structure interne d'un index.

Un index est stocké dans un ensemble de fichier au sein d'un seul répertoire.

Un index est un ensemble indépendant de segments dans lesquels sont stockées des
informations au sujet d'un sous-ensemble de documents indexés. Chaque segment a son propre
dictionnaire de terme, son propre index de dictionnaire de terme, et son propre stockage de
3
document (valeur de champ stocké) . Toutes les informations de segments sont stockées dans
un fichier _xxxxx.cfs, où xxxxx est le nom d'un segment.

Dès qu'un fichier de segment d'index est créé, il ne peut être mis à jour. De nouveaux documents
sont ajoutés à de nouveaux segments. Les documents supprimés sont seulement marqués
comme supprimés dans un fichier facultatif <segmentname>.del.

La mise à jour de document est effectuée en tant qu'opérations distincts de suppression et


4
d'ajout, même si elle est effectuée en utilisant un appel à l'API update() . Ceci simplifie l'ajout
de nouveaux documents, et permet de mettre à jour simultanément à l'aide des opérations de
recherche.

D'un autre coté, utiliser plusieurs segments (avoir un document par segment est un cas
exceptionnel) augmente le temps de recherche :

• La récupération d'un terme depuis le dictionnaire est effectué pour chaque segment ;

• Le dictionnaire de terme de l'index est préchargé pour chaque segment (ce processus occupe
la plupart du temps de recherche pour de simples requêtes et nécessite aussi de la mémoire
supplémentaire).

Si les termes du dictionnaires de recherche atteignent un point de saturation, la recherche à


travers un segment est N fois plus rapide que la recherche à travers N segments dans la plupart
des cas.

L'optimisation d'index fusionne deux segments ou plus en un segment unique. Un nouveau


segment est ajouté à la liste des segments de l'index, et les anciens segments sont exclus.
3
Depuis Lucene 2.3, les fichiers de stockage de document peuvent être partagés entre les segments; cependant,
Zend_Search_Lucene n'utilise pas cette possibilité
4
Cet appel est fourni uniquement par Java Lucene pour le moment, mais il est prévu d'étendre l'API Zend_Search_Lucene avec
une fonctionnalité similaire

81
Bien démarrer avec
Zend_Search_Lucene

La mise à jour de la liste de segments s'effectue de manière atomique. Ceci donne la capacité
d'ajouter de nouveaux documents simultanément, d'effectuer des optimisations d'index, et de
chercher à travers l'index.

L'auto-optimisation d'index s'effectue après chaque génération de segment. Elle fusionne


l'ensemble des plus petits segments en des segments plus grands, et les segments plus grands
en des segments encore plus grands, si nous avons suffisamment de segments à fusionner.

L'auto optimisation d'index est contrôlé par trois options :

• MaxBufferedDocs (Le nombre minimal de documents requis avant que les documents mis en
mémoire tampon soit écrits dans un nouveau segment) ;

• MaxMergeDocs (Le plus grand nombre de documents fusionnés par une opération
d'optimisation) ; et

• MergeFactor (qui détermine la fréquence à laquelle les indices de segments sont fusionnés
par les opérations d'auto-optimisation).

Si nous ajoutons un documents par exécution de script, MaxBufferedDocs n'est finalement pas
utilisé (seul un segment avec un seul document est créé à la fin de l'exécution du script, moment
auquel démarre le processus d'auto-optimisation).

3. Ouverture et création d'index


Toutes les opérations sur l'index (ex: créer un nouvel index, ajouter un document à l'index,
supprimer un document, chercher dans l'index) nécessite un objet index. Il peut être obtenu avec
l'une des méthodes suivantes.

Exemple 3. Création d'index Lucene

$index = Zend_Search_Lucene::create($indexPath);

Exemple 4. Ouverture d'index Lucene

$index = Zend_Search_Lucene::open($indexPath);

4. Indexation
L'indexation s'effectue en ajoutant un nouveau document à un index existant ou à un nouvel
index :

$index->addDocument($doc);

Il y a deux manières de créer un objet document. La première est de le faire manuellement.

Exemple 5. Construction manuel de document

$doc = new Zend_Search_Lucene_Document();


$doc->addField(Zend_Search_Lucene_Field::Text('url', $docUrl));
$doc->addField(Zend_Search_Lucene_Field::Text('title', $docTitle));
$doc->addField(Zend_Search_Lucene_Field::unStored('contents', $docBody));
$doc->addField(Zend_Search_Lucene_Field::binary('avatar', $avatarData));

La seconde méthode est de le charger depuis un fichier HTML ou Microsoft Office 2007 :

82
Bien démarrer avec
Zend_Search_Lucene

Exemple 6. Chargement de document

$doc = Zend_Search_Lucene_Document_Html::loadHTML($htmlString);
$doc = Zend_Search_Lucene_Document_Docx::loadDocxFile($path);
$doc = Zend_Search_Lucene_Document_Pptx::loadPptFile($path);
$doc = Zend_Search_Lucene_Document_Xlsx::loadXlsxFile($path);

Si un document est chargé depuis l'un des formats supportés, il peut quand même être étendu
manuellement avec des champs définis par l'utilisateur.

4.1. Politique d'indexation


Vous devrez définir votre politique d'indexation au sein de la conception de l'architecture de votre
application.

Vous pourriez avoir besoin d'une configuration d'indexation à la demande (quelque chose
comme le système OLTP). Sur de test systèmes, vous ajoutez généralement un document par
requête utilisateur. De cette manière, l'option MaxBufferedDocs n'affectera pas le système. D'un
autre coté, MaxMergeDocs est vraiment utile, car il vous permet de limiter le temps d'exécution
maximum du script. MergeFactor doit être définis par une valeur qui conserve un équilibre
entre le temps moyen d'indexation (il est aussi affecté par temps d'optimisation moyen) et les
performance de recherche (le niveau d'optimisation dépend du nombre de segments).

Si vous allez surtout effectuer des mises à jour d'index par lot, votre configuration devrait
utiliser une option MaxBufferedDocs définis à la valeur maximum supporté par la quantité de
mémoire disponible. MaxMergeDocs et MergeFactor doivent être définis à des valeurs réduisant
5
au maximum le recours à l'auto-optimisation . Les optimisations complètes d'index doivent être
appliquées après l'indexation.

Exemple 7. Optimisation d'index

$index->optimize();

Dans certaines configuration, il est plus efficace d'effectuer une série de mise à jour de l'index en
organisant une file de requête de mise à jour et de traiter plusieurs requête de mise à jour dans
une seule exécution de script. Ceci réduit la charge d'ouverture de l'index et permet d'utiliser le
tampon de document de l'index.

5. Recherche
La recherche s'effectue en utilisant la méthode find() :

Exemple 8. Recherche à travers l'index

$hits = $index->find($query);
foreach ($hits as $hit) {
printf("%d %f %s\n", $hit->id, $hit->score, $hit->title);
}

Cet exemple montre l'utilisation de deux propriétés particulières des résultats de recherche - id
et score.

id est un identifiant interne de document utilisé dans un index Lucene. Il peut être utilisé pour un
certains nombre d'opérations, tels que la suppression d'un document de l'index :
5
Une limite additionnelle est le nombre maximum de gestionnaire de fichiers supporter par le système d'exploitation pour les opérations
concurrente d'ouverture

83
Bien démarrer avec
Zend_Search_Lucene

Exemple 9. Suppression d'un document indexé

$index->delete($id);

Ou récupération d'un document à partir de l'index :

Exemple 10. Récupération d'un document indexé

$doc = $index->getDocument($id);

Identifiant interne de document

Note importante ! Les identifiants de documents internes peuvent changer suite


à une optimisation de l'index ou au processus d'auto-optimisation, mais il ne sera
jamais changé pendant l'exécution d'un script à moins que ne soient appellées
les méthodes addDocument() (ce qui peut impliquer une procédure d'auto-
optimisation) ou optimize().

Le champ score est un score de résultat. Les résultats de recherche sont triés par score
(meilleurs résultats en premier).

Il est aussi possible de trier l'ensemble de résultats en fonction d'une valeur de champ spécifique.
Voir la documentation Zend_Search_Lucene pour plus de détails sur cette possibilité.

Cette exemple montre aussi la possibilité d'accéder à des champs stockés (ex : $hit->title).
Les champs de documents stockés sont chargés lors du premier accès à l'une des propriété du
résultat autre que id ou score, et la valeur du champ correspondant est retournée.

Ceci cause une ambiguïté car les documents ont leurs propres champs id ou score par
conséquence, il n'est pas recommendé d'utiliser ces noms de champs dans les documents
stockés. Cependant, ils peuvent être accédé via la méthode : getDocument()

Exemple 11. Accéder aux champs "id" et "score" original du documents

$id = $hit->getDocument()->id;
$score = $hit->getDocument()->score;

6. Requêtes supportées
Zend_Search_Lucene et Lucene Java supportent un langage de requête puissant. Il permet
de rechercher des termes individuels, des phrases, des ensembles de termes ; en utilisant des
jokers ou des recherches floues ; en combinant des requêtes à l'aide d'opérateurs booléens et
ainsi de suite.

Une description détaillée du langage de requête peut être trouvé dans la documentation du
composant Zend_Search_Lucene.

Ci-dessous, des exemples de quelques requêtes types communes et de stratégies.

Exemple 12. Effectuer une requête pour un mot seul

hello

Recherche le mot "hello" à travers les champs de tous les documents.

84
Bien démarrer avec
Zend_Search_Lucene

Champ de recherche par défaut


Note importante ! Lucene Java recherche uniquement dans les champs de
"contenu" par défaut, mais Zend_Search_Lucene recherche à travers tous
les champs. Ce comportement peut être modifié en utilisant la méthode
Zend_Search_Lucene::setDefaultSearchField($fieldName).

Exemple 13. Effectuer une recherche de mots multiples

hello dolly

Recherche deux mots. Les deux mots sont facultatifs, au moins l'un des deux doit être
présent dans le résultat

Exemple 14. Mots requis dans une requête

+hello dolly

Recherche deux mots ; "hello" est requis, "dolly" est facultatif.

Exemple 15. Interdire des mots dans les documents recherchés

+hello -dolly

Recherche avec deux mots ; "hello" est requis, 'dolly' est interdit. En d'autres termes, si le
document contient "hello", mais contient aussi le mot "dolly", il ne sera pas retourné dans
l'ensemble de résultats.

Exemple 16. Rechercher des phrases

"hello dolly"

Recherche de la phrases "hello dolly" ; un document correspond uniquement si la chaine


exacte est présente.

Exemple 17. Effectuer des recherches dans des champs en particulier

title:"The Right Way" AND text:go

Recherche la phrase "The Right Way" au sein du champ title et le mot "go" dans la propriété
text.

Exemple 18. Effectuer des recherches dans des champs en particulier aussi bien
que dans le document complet

title:"The Right Way" AND go

Recherche la phrase "The Right Way" dans la propriété title et le mot "go" dans tous les
champs du document.

Exemple 19. Effectuer des recherches dans des champs en particulier aussi bien
que dans le document complet (Alternatif)

title:Do it right

Recherche le mot "Do" dans la propriété title et les mots "it" and "right" dans tous les champs ;
si l'un d'entre eux correspond, le document correspondra à un résultat de recherche.

85
Bien démarrer avec
Zend_Search_Lucene

Exemple 20. Faire des requêtes avec le joker "?"

te?t

Recherche les mots correspondants au motif "te?t", où "?" est n'importe quel caractère
unique.

Exemple 21. Faire des requêtes avec le joker "*"

test*

Recherche les mots correspondants au motif "test*", où "*" est n'importe quelle séquence
de 0 caractère ou plus.

Exemple 22. Rechercher une gamme inclusive de termes

mod_date:[20020101 TO 20030101]

Recherche la gamme de termes (inclusif).

Exemple 23. Rechercher une gamme exclusive de termes

title:{Aida to Carmen}

Recherche la gamme de termes (exculsif).

Exemple 24. Recherches floues

roam~

Recherche foue pour le mot "roam".

Exemple 25. Recherches booléennes

(framework OR library) AND php

Requête booléenne.

Toutes les requêtes supportées peuvent être construites via l'API de construction de requêtes
de Zend_Search_Lucene. De plus l'analyse et la construction de requêtes peuvent être
combinées :

Exemple 26. Combinaison d'analyse et de construction de requêtes

$userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);
$query = new Zend_Search_Lucene_Search_Query_Boolean();
$query->addSubquery($userQuery, true /* required */);
$query->addSubquery($constructedQuery, true /* required */);

7. Pagination de résultat de recherche


Comme mentionné plus haut, les objets de résultats de recherche utilisent le lazy loading pour
les champs de documents stockés. Lorsque l'on accède à l'un des champs stockés, le document
complet est chargé.

86
Bien démarrer avec
Zend_Search_Lucene

Ne récupérez pas tous les documents si vous avez seulement besoin de travailler sur une partie.
Parcourez les résultats de recherche et stockez l'ID du document (et éventuellement son score)
afin de récupérer les documents depuis l'index pendant la prochaine exécution du script.

Exemple 27. Exemple de pagination de résultat de recherche

$cacheId = md5($query);
if (!$resultSet = $cache->load($cacheId)) {
$hits = $index->find($query);
$resultSet = array();
foreach ($hits as $hit) {
$resultSetEntry = array();
$resultSetEntry['id'] = $hit->id;
$resultSetEntry['score'] = $hit->score;
$resultSet[] = $resultSetEntry;
}
$cache->save($resultSet, $cacheId);
}
$publishedResultSet = array();
for ($resultId = $startId; $resultId < $endId; $resultId++) {
$publishedResultSet[$resultId] = array(
'id' => $resultSet[$resultId]['id'],
'score' => $resultSet[$resultId]['score'],
'doc' => $index->getDocument($resultSet[$resultId]['id']),
);
}

87
Bien démarrer avec Zend_Paginator
1. Introduction
Let's say you're creating a blogging application that will be home to your vast collection of blog
posts. There is a good chance that you do not want all of your blog posts to appear on one
single page when someone visits your blog. An obvious solution would be to only display a
small number of blog posts on the screen at a time, and allow the user to browse through the
different pages, much like your favorite search engine shows you the result of your search query.
Zend_Paginator is designed to help you achieve the goal of dividing collections of data in
smaller, more manageable sets more easily, with more consistency, and with less duplicate code.

Zend_Paginator uses Adapters to support various data sources and ScrollingStyles to support
various methods of showing the user which pages are available. In later sections of this text we
will have a closer look at what these things are and how they can help you to make the most
out of Zend_Paginator.

Before going in-depth, we will have a look at some simple examples first. After these simple
examples, we will see how Zend_Paginator supports the most common use-case; paginating
database results.

This introduction has given you a quick overview of Zend_Paginator. To get started and to
have a look at some code snippets, let's have a look at some simple examples.

2. Simple Examples
In this first example we won't do anything spectacular, but hopefully it will give you a good idea
of what Zend_Paginator is designed to do. Let's say we have an array called $data with the
numbers 1 to 100 in it, which we want to divide over a number of pages. We can use the static
factory() method in the Zend_Paginator class to get a Zend_Paginator object with our
array in it.

// Create an array with numbers 1 to 100


$data = range(1, 100);

// Get a Paginator object using Zend_Paginator's built-in factory.


$paginator = Zend_Paginator::factory($data);

We're already almost done! The $paginator variable now contains a reference to the Paginator
object. By default it is setup to display 10 items per page. To display the items for the currently
active page, all you need to do is iterate over the Paginator object with a foreach loop. The
currently active page defaults to the first page if it's not explicitly specified. We will see how you
can select a specific page later on. The snippet below will display an unordered list containing
the numbers 1 to 10, which are the numbers on the first page.

// Create an array with numbers 1 to 100


$data = range(1, 100);

// Get a Paginator object using Zend_Paginator's built-in factory.


$paginator = Zend_Paginator::factory($data);

?><ul><?php

88
Bien démarrer avec Zend_Paginator

// Render each item for the current page in a list-item


foreach ($paginator as $item) {
echo '<li>' . $item . '</li>';
}

?></ul>

Now let's try and render the items on the second page. You can use the
setCurrentPageNumber() method to select which page you want to view.

// Create an array with numbers 1 to 100


$data = range(1, 100);

// Get a Paginator object using Zend_Paginator's built-in factory.


$paginator = Zend_Paginator::factory($data);

// Select the second page


$paginator->setCurrentPageNumber(2);

?><ul><?php

// Render each item for the current page in a list-item


foreach ($paginator as $item) {
echo '<li>' . $item . '</li>';
}

?></ul>

As expected, this little snippet will render an unordered list with the numbers 11 to 20 in it.

These simple examples demonstrate a small portion of what can be achieved with
Zend_Paginator. However, a real application rarely reads its data from a plain array, so the
next section is dedicated to showing you how you can use Paginator to paginate the results of a
database query. Before reading on, make sure you're familiar with the way Zend_Db_Select
works!

In the database examples we will look at a table with blog posts called 'posts'. The 'posts' table
has four columns: id, title, body, date_created. Let's dive right in and have a look at a simple
example.

// Create a select query. $db is a Zend_Db_Adapter object, which we assume


// already exists in your script.
$select = $db->select()->from('posts')->order('date_created DESC');

// Get a Paginator object using Zend_Paginator's built-in factory.


$paginator = Zend_Paginator::factory($select);

// Select the second page


$paginator->setCurrentPageNumber(2);

?><ul><?php

// Render each the title of each post for the current page in a list-item
foreach ($paginator as $item) {
echo '<li>' . $item->title . '</li>';
}

89
Bien démarrer avec Zend_Paginator

?></ul>

As you can see, this example is not that different from the previous one. The only difference is
that you pass a Zend_Db_Select object to the Paginator's factory() method, rather than
an array. For more details on how the database adapter makes sure that your query is being
executed efficiently, see the Zend_Paginator chapter in the reference manual on the DbSelect
and DbTableSelect adapters.

3. Contrôles de la pagination et styles de défilement


Rendre visuellement les éléments d'une page est un bon départ. Dans les sections précédentes,
nous avons aperçu la méthode setCurrentPageNumber() pour déterminer la page active. Le
point suivant est la navigation au travers de ces pages. Le paginateur vous fournit des outils pour
ça comme la possibilité de rendre un script de vue partiel et le support des styles de défilement
(ScrollingStyles).

La vue partiel est un bout de vue qui rend juste les contrôles de la pagination comme les boutons
suivant et précédent. Le design de la vue partielle est libre, il vous faudra simplement un objet
Zend_View. Commencez donc par créer un nouveau script de vue dans le dossier des scripts
de vue. Vous pouvez l'appeler comme vous voulez, nous l'appellerons "controls.phtml" de notre
coté. Le manuel comporte des exemples de tels scripts, en voici un.

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


<!-- First page link -->
<?php if (isset($this->previous)): ?>
<a href="<?php echo $this->url(array('page' => $this->first)); ?>">
First
</a> |
<?php else: ?>
<span class="disabled">First</span> |
<?php endif; ?>
<!-- Previous page link -->
<?php if (isset($this->previous)): ?>
<a href="<?php echo $this->url(array('page' => $this->previous)); ?>">
Previous
</a> |
<?php else: ?>
<span class="disabled"> Previous</span> |
<?php endif; ?>
<!-- Next page link -->
<?php if (isset($this->next)): ?>
<a href="<?php echo $this->url(array('page' => $this->next)); ?>">
Next
</a> |
<?php else: ?>
<span class="disabled">Next </span> |
<?php endif; ?>
<!-- Last page link -->
<?php if (isset($this->next)): ?>
<a href="<?php echo $this->url(array('page' => $this->last)); ?>">
Last
</a>
<?php else: ?>
<span class="disabled">Last</span>
<?php endif; ?>
</div>
<?php endif; ?>

90
Bien démarrer avec Zend_Paginator

Il faut maintenant indiquer à Zend_Paginator la vue partielle à utiliser. Ajoutez ceci à votre
bootstrap:

Zend_View_Helper_PaginationControl::setDefaultViewPartial('controls.phtml');

La dernière étape est la plus simple. Passez un objet Paginator à un script de vue (PAS
'controls.phtml'!). Ensuite, demandez simplement l'affichage de l'objet Paginator lui-même. Ceci
va faire intervenir l'aide de vue PaginationControl. Dans l'exemple qui suit, l'objet Paginator a
été affecté comme variable de vue 'paginator'. Ne vous inquiétez pas si vous ne comprenez pas
totalement le fonctionnement, les sections suivantes le détaillent.

<?php echo $this->paginator; ?>

Pour décider quels numéros de page afficher, le paginateur utilise des styles de défilement. Le
style par défaut est "Sliding", qui ressemble à la présentation des résultats de Yahoo! Un style
ressemblant à Google est "Elastic". Le style par défaut se règle au moyen de la méthode statique
setDefaultScrollingStyle(), ou lors du rendu du paginateur dans le script de vue mais
ceci nécessite un appel manuel à l'aide de vue.

// $this->paginator est un objet Paginator


<?php echo $this->paginationControl($this->paginator, 'Elastic', 'controls.phtml'); ?>

Pour une liste de tous les styles de défilement, consultez le manuel.

4. Putting it all Together


You have seen how to create a Paginator object, how to render the items on the current page,
and how to render a navigation element to browse through your pages. In this section you will
see how Paginator fits in with the rest of your MVC application.

In the following examples we will ignore the best practice implementation of using a Service
Layer to keep the example simple and easier to understand. Once you get familiar with using
Service Layers, it should be easy to see how Paginator can fit in with the best practice approach.

Lets start with the controller. The sample application is simple, and we'll just put everything in
the IndexController and the IndexAction. Again, this is for demonstration purposes only. A real
application should not use controllers in this manner.

class IndexController extends Zend_Controller_Action


{
public function indexAction()
{
// Setup pagination control view script. See the pagation control tutorial page
// for more information about this view script.
Zend_View_Helper_PaginationControl::setDefaultViewPartial('controls.phtml');

// Fetch an already instantiated database connection from the registry


$db = Zend_Registry::get('db');

// Create a select object which fetches blog posts, sorted decending by date of crea
$select = $db->select()->from('posts')->sort('date_created DESC');

// Create a Paginator for the blog posts query


$paginator = Zend_Paginator::factory($select);

// Read the current page number from the request. Default to 1 if no explicit page n

91
Bien démarrer avec Zend_Paginator

$paginator->setCurrentPageNumber($this->_getParam('page', 1));

// Assign the Paginator object to the view


$this->view->paginator = $paginator;
}
}

The following view script is the index.phtml view script for the IndexController's indexAction. The
view script can be kept simple. We're assuming the use of the default ScrollingStyle.

<ul>
<?php
// Render each the title of each post for the current page in a list-item
foreach ($this->paginator as $item) {
echo '<li>' . $item->title . '</li>';
}
?>
</ul>
<?php echo $this->paginator; ?>

Now navigate to your project's index and see Paginator in action. What we have discussed in
this tutorial is just the tip of the iceberg. The reference manual and API documentation can tell
you more about what you can do with Zend_Paginator.

92
Partie III. Guide de
référence Zend Framework
Table des matières
Zend_Acl ..................................................................................................................... 124
1. Introduction ...................................................................................................... 124
1.1. A propos des ressources ....................................................................... 124
1.2. A propos des rôles ................................................................................ 124
1.3. Créer la Liste de Contrôle d'Accès ......................................................... 125
1.4. Registre des rôles ................................................................................. 126
1.5. Définir les Contrôles d'Accès .................................................................. 127
1.6. Interroger les ACL ................................................................................. 127
2. Affiner les Contrôles d'Accès ............................................................................ 128
2.1. Mieux définir les Contrôles d'Accès ........................................................ 128
2.2. Retirer les Contrôles d'Accès ................................................................. 130
3. Utilisation avancée ........................................................................................... 130
3.1. Rendre les données ACL persistantes .................................................... 130
3.2. Écrire des règles ACL conditionnelles avec des assertions ....................... 131
Zend_Amf .................................................................................................................... 132
1. Introduction ...................................................................................................... 132
2. Zend_Amf_Server ............................................................................................ 132
2.1. Connecting to the Server from Flex ........................................................ 134
2.2. Error Handling ....................................................................................... 136
2.3. AMF Responses .................................................................................... 136
2.4. Typed Objects ....................................................................................... 136
2.5. Resources ............................................................................................. 138
2.6. Connecting to the Server from Flash ...................................................... 138
2.7. Authentication ....................................................................................... 140
Zend_Application .......................................................................................................... 142
1. Introduction ...................................................................................................... 142
2. Zend_Application démarrage rapide .................................................................. 142
2.1. Utiliser Zend_Tool ................................................................................. 142
2.2. Ajouter Zend_Application à votre existant ................................................ 144
2.3. Ajouter et créer des ressources .............................................................. 145
2.4. Aller plus loin avec Zend_Application ...................................................... 147
3. Théorie générale .............................................................................................. 147
3.1. Bootstrapping ........................................................................................ 148
3.2. Resource Plugins .................................................................................. 152
4. Exemples ......................................................................................................... 153
5. Fonctionnalités principales ................................................................................ 156
5.1. Zend_Application ................................................................................... 156
5.2. Zend_Application_Bootstrap_Bootstrapper .............................................. 160
5.3. Zend_Application_Bootstrap_ResourceBootstrapper ................................ 161
5.4. Zend_Application_Bootstrap_BootstrapAbstract ....................................... 162
5.5. Zend_Application_Bootstrap_Bootstrap ................................................... 165
5.6. Zend_Application_Resource_Resource ................................................... 166
5.7. Zend_Application_Resource_ResourceAbstract ....................................... 166
6. Plugins de ressources disponibles .................................................................... 168
6.1. Zend_Application_Resource_Cachemanager ........................................... 168
6.2. Zend_Application_Resource_Db ............................................................. 169
6.3. Zend_Application_Resource_Frontcontroller ............................................ 170
6.4. Zend_Application_Resource_Layout ....................................................... 171
6.5. Zend_Application_Resource_Locale ....................................................... 171
6.6. Zend_Application_Resource_Log ............................................................ 172
6.7. Zend_Application_Resource_Multidb ....................................................... 173

94
Guide de référence
Zend Framework

6.8. Zend_Application_Resource_Mail ........................................................... 174


6.9. Zend_Application_Resource_Modules ..................................................... 174
6.10. Zend_Application_Resource_Navigation ................................................ 176
6.11. Zend_Application_Resource_Router ..................................................... 176
6.12. Zend_Application_Resource_Session .................................................... 176
6.13. Zend_Application_Resource_View ........................................................ 177
Zend_Auth ................................................................................................................... 178
1. Introduction ...................................................................................................... 178
1.1. Adaptateurs ........................................................................................... 178
1.2. Résultats ............................................................................................... 179
1.3. Persistance d'identité ............................................................................. 180
1.4. Utilisation de Zend_Auth ........................................................................ 183
2. Authentification avec une table de base de données .......................................... 184
2.1. Introduction ........................................................................................... 184
2.2. Utilisation avancée : maintenir persistant l'objet de résultat DbTable .......... 186
2.3. Utilisation avancée par l'exemple ............................................................ 186
3. Authentification "Digest" .................................................................................... 188
3.1. Introduction ........................................................................................... 188
3.2. Spécifications ........................................................................................ 188
3.3. Identité .................................................................................................. 188
4. Adaptateur d'authentification HTTP ................................................................... 189
4.1. Introduction ........................................................................................... 189
4.2. Fonctionnement ..................................................................................... 189
4.3. Options de configuration ........................................................................ 190
4.4. Résolveurs ............................................................................................ 190
4.5. Usage général : ..................................................................................... 191
5. LDAP Authentication ........................................................................................ 192
5.1. Introduction ........................................................................................... 192
5.2. Usage ................................................................................................... 192
5.3. The API ................................................................................................ 194
5.4. Server Options ...................................................................................... 195
5.5. Collecting Debugging Messages ............................................................. 198
5.6. Common Options for Specific Servers .................................................... 199
6. Authentification OpenID .................................................................................... 201
6.1. Introduction ........................................................................................... 201
6.2. Spécifications ........................................................................................ 201
Zend_Barcode ............................................................................................................. 203
1. Introduction ...................................................................................................... 203
2. Création de code-barres avec la classe Zend_Barcode ....................................... 203
2.1. Utilisation de la fabrique Zend_Barcode::factory ...................................... 203
2.2. Tracer un code-barres ........................................................................... 204
2.3. Générer le rendu d'un code-barres ......................................................... 204
3. Zend_Barcode Objects ..................................................................................... 205
3.1. Common Options .................................................................................. 206
3.2. Common Additional Getters ................................................................... 208
3.3. Description of shipped barcodes ............................................................. 208
4. Zend_Barcode Renderers ................................................................................. 215
4.1. Common Options .................................................................................. 215
4.2. Zend_Barcode_Renderer_Image ............................................................ 216
4.3. Zend_Barcode_Renderer_Pdf ................................................................ 217
Zend_Cache ................................................................................................................ 218
1. Introduction ...................................................................................................... 218
2. Aspect théorique .............................................................................................. 220
2.1. La méthode de fabrique de Zend_Cache ................................................ 221

95
Guide de référence
Zend Framework

2.2. Baliser les enregistrements .................................................................... 222


2.3. Nettoyer le cache .................................................................................. 222
3. Les frontends Zend_Cache ............................................................................... 223
3.1. Zend_Cache_Core ................................................................................ 223
3.2. Zend_Cache_Frontend_Output ............................................................... 226
3.3. Zend_Cache_Frontend_Function ............................................................ 227
3.4. Zend_Cache_Frontend_Class ................................................................ 228
3.5. Zend_Cache_Frontend_File ................................................................... 229
3.6. Zend_Cache_Frontend_Page ................................................................. 230
4. Les backends Zend_Cache .............................................................................. 235
4.1. Zend_Cache_Backend_File .................................................................... 235
4.2. Zend_Cache_Backend_Sqlite ................................................................. 237
4.3. Zend_Cache_Backend_Memcached ....................................................... 237
4.4. Zend_Cache_Backend_Apc ................................................................... 238
4.5. Zend_Cache_Backend_Xcache .............................................................. 239
4.6. Zend_Cache_Backend_ZendPlatform ..................................................... 239
4.7. Zend_Cache_Backend_TwoLevels ......................................................... 239
4.8. Zend_Cache_Backend_ZendServer_Disk et
Zend_Cache_Backend_ZendServer_ShMem ................................................ 241
5. Le gestionnaire de Cache ................................................................................. 241
Zend_Captcha ............................................................................................................. 245
1. Introduction ...................................................................................................... 245
2. Opération Captcha ........................................................................................... 245
3. Adaptateurs CAPTCHA .................................................................................... 246
3.1. Zend_Captcha_Word ............................................................................. 246
3.2. Zend_Captcha_Dumb ............................................................................ 247
3.3. Zend_Captcha_Figlet ............................................................................. 247
3.4. Zend_Captcha_Image ............................................................................ 247
3.5. Zend_Captcha_ReCaptcha .................................................................... 248
Zend_CodeGenerator ................................................................................................... 249
1. Introduction ...................................................................................................... 249
1.1. Théorie ................................................................................................. 249
2. Exemples Zend_CodeGenerator ....................................................................... 251
3. Zend_CodeGenerator Réference ....................................................................... 255
3.1. Classes abstraites et interfaces .............................................................. 255
3.2. Classes CodeGenerator concrêtes ......................................................... 256
Zend_Config ................................................................................................................ 262
1. Introduction ...................................................................................................... 262
2. Aspect théorique .............................................................................................. 263
3. Zend_Config_Ini ............................................................................................... 264
4. Zend_Config_Xml ............................................................................................. 266
Zend_Config_Writer ...................................................................................................... 271
1. Zend_Config_Writer .......................................................................................... 271
Zend_Console_Getopt .................................................................................................. 274
1. Introduction ...................................................................................................... 274
2. Déclarer les règles Getopt ................................................................................ 275
2.1. Déclarer des options avec la syntaxe courte ........................................... 275
2.2. Déclarer des options avec la syntaxe longue ........................................... 275
3. Extraire les options et les arguments ................................................................. 276
3.1. Manipuler les exceptions Getopt ............................................................. 276
3.2. Extraire les options par nom .................................................................. 277
3.3. Extraire les options ................................................................................ 277
3.4. Extraction des arguments sans option .................................................... 278
4. Configurer Zend_Console_Getopt ..................................................................... 278

96
Guide de référence
Zend Framework

4.1. Ajouter des règles d'options ................................................................... 278


4.2. Ajouter des messages d'aide ................................................................. 279
4.3. Ajouter des alias aux options ................................................................. 279
4.4. Ajouter des listes d'arguments ................................................................ 279
4.5. Ajouter une configuration ....................................................................... 280
Zend_Controller ........................................................................................................... 282
1. Zend_Controller - Démarrage rapide ................................................................. 282
1.1. Introduction ........................................................................................... 282
1.2. Démarrage rapide ................................................................................. 282
2. Fondations de Zend_Controller ......................................................................... 286
3. Le contrôleur frontal (Front Controller) ............................................................... 289
3.1. Présentation générale ............................................................................ 289
3.2. Méthodes principales ............................................................................. 290
3.3. Méthodes d'accès à l'environnement ...................................................... 292
3.4. Paramètres du contrôleur frontal ............................................................ 293
3.5. Étendre le contrôleur frontal ................................................................... 294
4. L'objet Requête ................................................................................................ 294
4.1. Introduction ........................................................................................... 294
4.2. Les requêtes HTTP ............................................................................... 295
4.3. Sous-classer l'objet Requête .................................................................. 298
5. Routeur Standard ............................................................................................. 299
5.1. Introduction ........................................................................................... 299
5.2. Utilisation d'un routeur ........................................................................... 301
5.3. Utilisation basique du routeur de réécriture ............................................. 301
5.4. Routes par défaut ................................................................................. 302
5.5. Base URL et sous dossiers .................................................................... 303
5.6. Paramètres globaux ............................................................................... 304
5.7. Types de route ...................................................................................... 304
5.8. Utiliser Zend_Config avec le RewriteRouter ............................................. 315
5.9. Dérivation de l'objet Router .................................................................... 316
6. Le distributeur .................................................................................................. 316
6.1. Vue d'ensemble .................................................................................... 316
6.2. Sous-classer le distributeur .................................................................... 318
7. Contrôleurs d'action .......................................................................................... 321
7.1. Introduction ........................................................................................... 321
7.2. Initialisation d'objet ................................................................................ 322
7.3. Détournement Pre et Post-Dispatch (Hook) ............................................. 323
7.4. Accesseurs ........................................................................................... 323
7.5. Intégration des Vues ............................................................................. 324
7.6. Méthodes utiles ..................................................................................... 326
7.7. Sous-classer le contrôleur d'action ......................................................... 326
8. Aides d'action (Helper) ..................................................................................... 328
8.1. Introduction ........................................................................................... 328
8.2. Initialisation des aides ............................................................................ 328
8.3. Le gestionnaire d'aide (Broker) ............................................................... 329
8.4. Aides d'action intégrées ......................................................................... 330
8.5. Écrire vos propres aides ........................................................................ 358
9. Objet de réponse ............................................................................................. 359
9.1. Utilisation .............................................................................................. 359
9.2. Manipulation des en-têtes ...................................................................... 361
9.3. Segments nommés ................................................................................ 361
9.4. Manipulation des exceptions dans l'objet de réponse ............................... 363
9.5. Dériver l'objet de réponse ...................................................................... 363
10. Plugins .......................................................................................................... 363

97
Guide de référence
Zend Framework

10.1. Introduction ......................................................................................... 363


10.2. Écrire des plugins ................................................................................ 364
10.3. Utilisation des plugins .......................................................................... 364
10.4. Récupération et manipulations des plugins ............................................ 366
10.5. Plugins inclus dans Zend Framework .................................................... 366
11. Utilisation de conventions de dossiers modulaires ............................................ 371
11.1. Introduction ......................................................................................... 371
11.2. Spécification des dossiers de modules .................................................. 372
11.3. Routage des modules .......................................................................... 373
11.4. Module ou contrôleur Default global ...................................................... 373
12. Exceptions avec MVC .................................................................................... 373
12.1. Introduction ......................................................................................... 373
12.2. Gestion des exceptions ........................................................................ 373
12.3. Différents types d'exceptions que vous pouvez rencontrer ...................... 375
Zend_Currency ............................................................................................................ 378
1. Introduction à Zend_Currency ........................................................................... 378
1.1. Pourquoi devriez-vous utiliser Zend_Currency ? ...................................... 378
2. Utiliser Zend_Currency ..................................................................................... 378
2.1. Utilisation de base ................................................................................. 378
2.2. Créer une monnaie basée sur une locale ................................................ 379
3. Options des monnaies ...................................................................................... 379
4. Qu'est ce qui définit une monnaie? ................................................................... 380
5. Où est le symbole monnétaire? ........................................................................ 382
6. A quoi ressemble une monnaie? ....................................................................... 383
7. Travailler avec les valeurs des monnaies (les montants) ..................................... 384
7.1. Travailler avec les valeurs des monnaies ................................................ 384
7.2. Utiliser la précision des monnaies .......................................................... 385
8. Calculs avec les monnaies ............................................................................... 386
9. Echanger (convertir) des monnaies ................................................................... 387
10. Informations complémentaires pour Zend_Currency .......................................... 388
10.1. Informations sur les monnaies .............................................................. 388
10.2. Optimisation des performances des monnaies ....................................... 389
Zend_Date ................................................................................................................... 390
1. Introduction ...................................................................................................... 390
1.1. Définissez toujours un fuseau horaire par défaut ..................................... 390
1.2. Pourquoi utiliser Zend_Date ? ................................................................ 390
2. Aspect théorique .............................................................................................. 391
2.1. Fonctionnement interne ......................................................................... 391
3. Méthodes de base ........................................................................................... 392
3.1. La date courante ................................................................................... 392
3.2. Zend_Date : exemples ........................................................................... 392
4. Zend_Date API Overview ................................................................................. 394
4.1. Zend_Date Options ............................................................................... 394
4.2. Working with Date Values ...................................................................... 395
4.3. Basic Zend_Date Operations Common to Many Date Parts ...................... 396
4.4. Comparing Dates .................................................................................. 399
4.5. Getting Dates and Date Parts ................................................................ 401
4.6. Working with Fractions of Seconds ......................................................... 402
4.7. Sunrise / Sunset .................................................................................... 402
5. Créer des dates ............................................................................................... 403
5.1. Créer la date actuelle ............................................................................ 403
5.2. Créer une date depuis une base de données .......................................... 403
5.3. Créer des dates depuis un tableau ......................................................... 404
6. Constants for General Date Functions ............................................................... 404

98
Guide de référence
Zend Framework

6.1. Using Constants .................................................................................... 404


6.2. List of All Constants .............................................................................. 405
6.3. Self-Defined OUTPUT Formats with ISO ................................................. 409
6.4. Self-Defined OUTPUT Formats Using PHP's date() Format Specifiers ....... 412
7. Exemples concrets ........................................................................................... 415
7.1. Vérifier des dates .................................................................................. 415
7.2. Levé et couché du soleil ........................................................................ 416
7.3. Fuseaux horaires (Timezones) ............................................................... 418
Zend_Db ...................................................................................................................... 420
1. Zend_Db_Adapter ............................................................................................ 420
1.1. Se connecter à un SGBD en utilisant un adaptateur ................................ 420
1.2. La base de données d'exemple .............................................................. 425
1.3. Lecture de résultats de requête .............................................................. 426
1.4. Effectuer des changements dans la base de données .............................. 429
1.5. Échapper des valeurs ou des identifiants ................................................ 433
1.6. Gérer les transactions dans une base de données ................................... 435
1.7. Lister et décrire les tables ...................................................................... 436
1.8. Fermer une connexion ........................................................................... 437
1.9. Exécuter des requêtes sur le driver directement ...................................... 438
1.10. Récupérer la version du serveur SGBD ................................................ 439
1.11. Notes sur des adaptateur spécifiques ................................................... 439
2. Zend_Db_Statement ......................................................................................... 443
2.1. Créer un statement ............................................................................... 443
2.2. Exécuter un statement ........................................................................... 443
2.3. Récupérer des résultats depuis un statement SELECT ............................ 444
3. Zend_Db_Profiler ............................................................................................. 446
3.1. Introduction ........................................................................................... 446
3.2. Utiliser le profileur ................................................................................. 447
3.3. Utilisation avancée du profileur ............................................................... 449
3.4. Profileurs spécialisés ............................................................................. 450
4. Zend_Db_Select .............................................................................................. 451
4.1. Introduction ........................................................................................... 451
4.2. Créer un objet Select ............................................................................ 452
4.3. Construction de requêtes Select ............................................................. 452
4.4. Exécuter des requêtes Select ................................................................. 465
4.5. Autres méthodes ................................................................................... 466
5. Zend_Db_Table ............................................................................................... 468
5.1. Introduction ........................................................................................... 468
5.2. Définir une classe de Table ................................................................... 468
5.3. Créer une instance de la classe de Table ............................................... 471
5.4. Insérer des enregistrement dans une table .............................................. 472
5.5. Mettre à jour des enregistrements dans une table .................................... 474
5.6. Supprimer des enregistrements d'une Table ............................................ 475
5.7. Récupérer des enregistrements par clé primaire ...................................... 475
5.8. Requêter pour plusieurs enregistrements ................................................ 477
5.9. Récupérer un seul enregistrement .......................................................... 480
5.10. Récupérer les méta données d'une Table ............................................. 480
5.11. Cacher les méta données de la table .................................................... 481
5.12. Personnaliser et étendre une classe de Table ....................................... 484
6. Zend_Db_Table_Row ....................................................................................... 487
6.1. Introduction ........................................................................................... 487
6.2. Récupérer un résultat (un "Row") ........................................................... 487
6.3. Sauvegarde un Row en base de données ............................................... 489
6.4. Sérialisation et désérialisation d'un Row ................................................. 490

99
Guide de référence
Zend Framework

6.5. Étendre la classe Row ........................................................................... 492


7. Zend_Db_Table_Rowset ................................................................................... 494
7.1. Introduction ........................................................................................... 494
7.2. Récupérer un Rowset ............................................................................ 494
7.3. Atteindre les Rows depuis un Rowset ..................................................... 495
7.4. Récupérer un Rowset en tant que tableau (Array) ................................... 497
7.5. Sérialisation et Désérialisation d'un Rowset ............................................. 497
7.6. Étendre la classe Rowset ...................................................................... 498
8. Relations Zend_Db_Table ................................................................................ 499
8.1. Introduction ........................................................................................... 499
8.2. Définir ses relations ............................................................................... 500
8.3. Récupérer des enregistrements dépendants (enfants) .............................. 502
8.4. Récupérer l'enregistrement parent .......................................................... 503
8.5. Récupérer des enregistrements dans une relation N-N (plusieurs-à-
plusieurs ou "many-to-many") ...................................................................... 505
8.6. Opérations d'écritures en cascade .......................................................... 507
9. Zend_Db_Table_Definition ................................................................................ 509
9.1. Introduction ........................................................................................... 509
9.2. Utilisation de base ................................................................................. 509
9.3. Utilisation avancée ................................................................................ 511
Zend_Debug ................................................................................................................ 513
1. Afficher des informations .................................................................................. 513
Zend_Dojo ................................................................................................................... 514
1. Introduction ...................................................................................................... 514
2. Zend_Dojo_Data: dojo.data Envelopes .............................................................. 514
2.1. Zend_Dojo_Data Usage ......................................................................... 514
2.2. Adding metadata to your containers ....................................................... 516
2.3. Advanced Use Cases ............................................................................ 516
3. Les aides de vues Dojo .................................................................................... 518
3.1. dojo() View Helper ................................................................................. 518
3.2. Dijit-Specific View Helpers ..................................................................... 523
4. Les éléments de formulaire et les décorateurs Dojo ........................................... 536
4.1. Dijit-Specific Form Decorators ................................................................ 537
4.2. Dijit-Specific Form Elements .................................................................. 539
4.3. Dojo Form Examples ............................................................................. 556
5. Zend_Dojo build layer support .......................................................................... 557
5.1. Introduction ........................................................................................... 557
5.2. Generating Custom Module Layers with Zend_Dojo_BuildLayer ................ 558
5.3. Generating Build Profiles with Zend_Dojo_BuildLayer .............................. 560
Zend_Dom ................................................................................................................... 563
1. Introduction ...................................................................................................... 563
2. Zend_Dom_Query ............................................................................................ 563
2.1. Aspect théorique ................................................................................... 563
2.2. Méthodes disponibles ............................................................................ 564
Zend_Exception ........................................................................................................... 566
1. Utiliser les exceptions ....................................................................................... 566
2. Utilisation classique .......................................................................................... 566
3. Exceptions précédentes .................................................................................... 567
Zend_Feed .................................................................................................................. 568
1. Introduction ...................................................................................................... 568
2. Importer des flux .............................................................................................. 569
2.1. Flux personnalisés ................................................................................. 570
3. Obtenir des flux à partir de pages Web ............................................................. 574
4. Consommer un flux RSS .................................................................................. 574

100
Guide de référence
Zend Framework

5.
Consommer un flux Atom ................................................................................. 576
6.
Consommer une entrée Atom particulière .......................................................... 577
7.
Modifier la structure du flux ou des entrées ....................................................... 577
8.
Classes personnalisées pour les flux et entrées ................................................. 578
9.
Zend_Feed_Reader .......................................................................................... 580
9.1. Introduction ........................................................................................... 580
9.2. Importing Feeds .................................................................................... 580
9.3. Retrieving Underlying Feed and Entry Sources ........................................ 581
9.4. Cache Support and Intelligent Requests ................................................. 582
9.5. Locating Feed URIs from Websites ........................................................ 583
9.6. Attribute Collections ............................................................................... 584
9.7. Retrieving Feed Information ................................................................... 585
9.8. Retrieving Entry/Item Information ............................................................ 588
9.9. Extending Feed and Entry APIs ............................................................. 591
10. Zend_Feed_Writer .......................................................................................... 595
10.1. Introduction ......................................................................................... 595
10.2. Architecture ......................................................................................... 595
10.3. Getting Started .................................................................................... 596
10.4. Setting Feed Data Points ..................................................................... 597
10.5. Setting Entry Data Points ..................................................................... 599
11. Zend_Feed_Pubsubhubbub ............................................................................ 601
11.1. What is Pubsubhubbub? ...................................................................... 601
11.2. Architecture ......................................................................................... 602
11.3. Zend_Feed_Pubsubhubbub_Publisher .................................................. 602
11.4. Zend_Feed_Pubsubhubbub_Subscriber ................................................ 603
Zend_File .................................................................................................................... 611
1. Zend_File_Transfer .......................................................................................... 611
1.1. Adaptateurs supportés par Zend_File_Transfer ....................................... 612
1.2. Options de Zend_File_Transfer .............................................................. 612
1.3. Vérification des fichiers .......................................................................... 613
1.4. Informations complémentaires sur les fichiers .......................................... 613
1.5. Progress for file uploads ........................................................................ 615
2. Validateurs pour Zend_File_Transfer ................................................................. 617
2.1. Utiliser les validateurs avec Zend_File_Transfer ...................................... 618
2.2. Validateur Count ................................................................................... 620
2.3. Validateur Crc32 ................................................................................... 621
2.4. Validateur ExcludeExtension .................................................................. 621
2.5. Validateur ExcludeMimeType ................................................................. 622
2.6. Validateur Exists ................................................................................... 623
2.7. Validateur Extension .............................................................................. 623
2.8. Validateur FilesSize ............................................................................... 624
2.9. Validateur ImageSize ............................................................................. 625
2.10. Validateur IsCompressed ..................................................................... 626
2.11. Validateur IsImage ............................................................................... 626
2.12. Validateur Hash ................................................................................... 626
2.13. Validateur Md5 .................................................................................... 627
2.14. Validateur MimeType ........................................................................... 627
2.15. Validateur NotExists ............................................................................. 629
2.16. Validateur Sha1 ................................................................................... 629
2.17. Validateur Size .................................................................................... 629
2.18. Validateur WordCount .......................................................................... 630
3. Filtres pour Zend_File_Transfer ........................................................................ 631
3.1. Utiliser les filtres avec Zend_File_Transfer .............................................. 631
3.2. Filtre Decrypt ........................................................................................ 632

101
Guide de référence
Zend Framework

3.3. Filtre Encrypt ......................................................................................... 633


3.4. Filtre LowerCase ................................................................................... 633
3.5. Filtre Rename ....................................................................................... 634
3.6. Filtre UpperCase ................................................................................... 635
Zend_Filter .................................................................................................................. 636
1. Introduction ...................................................................................................... 636
1.1. Qu'est-ce qu'un filtre ? ........................................................................... 636
1.2. Utilisation basique des filtres .................................................................. 636
1.3. Utilisation de la méthode statique staticFilter() ......................................... 636
2. Classes de filtre standards ............................................................................... 637
2.1. Alnum ................................................................................................... 637
2.2. Alpha .................................................................................................... 637
2.3. BaseName ............................................................................................ 637
2.4. Boolean ................................................................................................ 637
2.5. Callback ................................................................................................ 640
2.6. Compression et décompression .............................................................. 641
2.7. Decrypt ................................................................................................. 646
2.8. Digits .................................................................................................... 648
2.9. Dir ........................................................................................................ 648
2.10. Encrypt ............................................................................................... 648
2.11. HtmlEntities ......................................................................................... 651
2.12. Int ....................................................................................................... 651
2.13. LocalizedToNormalized ........................................................................ 651
2.14. NormalizedToLocalized ........................................................................ 653
2.15. Null ..................................................................................................... 654
2.16. PregReplace ....................................................................................... 655
2.17. RealPath ............................................................................................. 656
2.18. StringToLower ..................................................................................... 656
2.19. StringToUpper ..................................................................................... 657
2.20. StringTrim ........................................................................................... 657
2.21. Int ....................................................................................................... 657
2.22. StripTags ............................................................................................ 657
3. Chaînes de filtrage ........................................................................................... 658
3.1. Changing filter chain order ..................................................................... 658
4. Écriture de filtres .............................................................................................. 658
5. Zend_Filter_Input ............................................................................................. 659
5.1. Déclarer des règles de filtre et de validateur ........................................... 660
5.2. Créer le processeur de filtres et validateurs ............................................. 661
5.3. Récupérer les champs validés/filtré, et les éventuels rapports ................... 661
5.4. Utiliser des méta commandes pour contrôler les règles des filtres et
validateurs ................................................................................................... 664
5.5. Ajouter des espaces de noms comme noms de classes ........................... 669
6. Zend_Filter_Inflector ......................................................................................... 670
6.1. Opération .............................................................................................. 671
6.2. Créer des chemins vers des filtres alternatifs .......................................... 671
6.3. Paramétrer la cible de l'inflecteur ............................................................ 671
6.4. Règles d'inflexion .................................................................................. 672
6.5. Autres méthodes utilitaires ..................................................................... 674
6.6. Zend_Config avec Zend_Filter_Inflector .................................................. 675
Zend_Form .................................................................................................................. 676
1. Zend_Form ...................................................................................................... 676
2. Zend_Form démarrage rapide ........................................................................... 676
2.1. Créer un objet de formulaire .................................................................. 676
2.2. Ajouter des éléments au formulaire ........................................................ 676

102
Guide de référence
Zend Framework

2.3. Rendre (visuellement) un formulaire ....................................................... 678


2.4. Vérifier qu'un formulaire est valide .......................................................... 680
2.5. Les statuts d'erreur ................................................................................ 680
2.6. Assembler le tout ensemble ................................................................... 681
2.7. Utiliser un objet Zend_Config .............................................................. 682
2.8. Conclusion ............................................................................................ 683
3. Creating Form Elements Using Zend_Form_Element .......................................... 683
3.1. Plugin Loaders ...................................................................................... 683
3.2. Filters ................................................................................................... 686
3.3. Validators .............................................................................................. 687
3.4. Decorators ............................................................................................ 692
3.5. Metadata and Attributes ......................................................................... 694
3.6. Standard Elements ................................................................................ 695
3.7. Zend_Form_Element Methods ................................................................ 695
3.8. Configuration ......................................................................................... 697
3.9. Custom Elements .................................................................................. 698
4. Creating Forms Using Zend_Form .................................................................... 699
4.1. Plugin Loaders ...................................................................................... 700
4.2. Elements ............................................................................................... 701
4.3. Display Groups ..................................................................................... 705
4.4. Sub Forms ............................................................................................ 709
4.5. Metadata and Attributes ......................................................................... 710
4.6. Decorators ............................................................................................ 711
4.7. Validation .............................................................................................. 713
4.8. Methods ................................................................................................ 715
4.9. Configuration ......................................................................................... 718
4.10. Custom forms ...................................................................................... 719
5. Créer un visuel personnalisé en utilisant Zend_Form_Decorator .......................... 721
5.1. Configuration ......................................................................................... 721
5.2. Décorateurs standards ........................................................................... 722
5.3. Décorateurs personnalisés ..................................................................... 722
5.4. Rendre des décorateurs individuellement ................................................ 725
6. Standard Form Elements Shipped With Zend Framework ................................... 725
6.1. Zend_Form_Element_Button .................................................................. 725
6.2. Zend_Form_Element_Captcha ............................................................... 726
6.3. Zend_Form_Element_Checkbox ............................................................. 727
6.4. Zend_Form_Element_File ...................................................................... 727
6.5. Zend_Form_Element_Hidden ................................................................. 730
6.6. Zend_Form_Element_Hash .................................................................... 731
6.7. Zend_Form_Element_Image .................................................................. 731
6.8. Zend_Form_Element_MultiCheckbox ...................................................... 731
6.9. Zend_Form_Element_Multiselect ............................................................ 732
6.10. Zend_Form_Element_Password ........................................................... 732
6.11. Zend_Form_Element_Radio ................................................................. 733
6.12. Zend_Form_Element_Reset ................................................................. 733
6.13. Zend_Form_Element_Select ................................................................. 733
6.14. Zend_Form_Element_Submit ............................................................... 734
6.15. Zend_Form_Element_Text ................................................................... 734
6.16. Zend_Form_Element_Textarea ............................................................. 734
7. Décorateurs standards fournis avec Zend Framework ......................................... 734
7.1. Zend_Form_Decorator_Callback ..................................................... 734
7.2. Zend_Form_Decorator_Captcha ....................................................... 735
7.3. Zend_Form_Decorator_Description ............................................... 735
7.4. Zend_Form_Decorator_DtDdWrapper ............................................... 735

103
Guide de référence
Zend Framework

7.5. Zend_Form_Decorator_Errors ......................................................... 736


7.6. Zend_Form_Decorator_Fieldset ..................................................... 736
7.7. Zend_Form_Decorator_File ............................................................. 736
7.8. Zend_Form_Decorator_Form ............................................................. 736
7.9. Zend_Form_Decorator_FormElements ............................................. 736
7.10. Zend_Form_Decorator_FormErrors ............................................... 736
7.11. Zend_Form_Decorator_HtmlTag ..................................................... 737
7.12. Zend_Form_Decorator_Image ......................................................... 737
7.13. Zend_Form_Decorator_Label ......................................................... 737
7.14. Zend_Form_Decorator_PrepareElements ..................................... 738
7.15. Zend_Form_Decorator_ViewHelper ............................................... 738
7.16. Zend_Form_Decorator_ViewScript ............................................... 738
8. Internationaliser un formulaire Zend_Form ......................................................... 740
8.1. Initialiser l'i18n dans les formulaires ........................................................ 740
8.2. Cibles gérées par l'I18n ......................................................................... 741
9. Advanced Zend_Form Usage ........................................................................... 741
9.1. Array Notation ....................................................................................... 741
9.2. Multi-Page Forms .................................................................................. 744
Zend_Gdata ................................................................................................................. 746
1. Introduction ...................................................................................................... 746
1.1. Structure of Zend_Gdata ........................................................................ 746
1.2. Interacting with Google Services ............................................................ 747
1.3. Obtaining instances of Zend_Gdata classes ............................................ 747
1.4. Google Data Client Authentication .......................................................... 748
1.5. Dependencies ....................................................................................... 748
1.6. Creating a new Gdata client ................................................................... 748
1.7. Common Query Parameters ................................................................... 749
1.8. Fetching a Feed .................................................................................... 750
1.9. Working with Multi-page Feeds .............................................................. 750
1.10. Working with Data in Feeds and Entries ................................................ 751
1.11. Updating Entries .................................................................................. 751
1.12. Posting Entries to Google Servers ........................................................ 751
1.13. Deleting Entries on Google Servers ...................................................... 752
2. Authentification par procédé AuthSub ................................................................ 752
2.1. Création d'un client HTTP authentifié avec AuthSub ................................ 753
2.2. Destruction de l'authentification AuthSub ................................................. 754
3. Using the Book Search Data API ...................................................................... 754
3.1. Authenticating to the Book Search service .............................................. 754
3.2. Searching for books .............................................................................. 755
3.3. Using community features ...................................................................... 756
3.4. Book collections and My Library ............................................................. 758
4. Authentification avec ClientLogin ....................................................................... 759
4.1. Création d'un client HTTP "ClientLogin" authentifié .................................. 760
4.2. Fermer un client HTTP authentifié par ClientLogin ................................... 760
5. Using Google Calendar .................................................................................... 760
5.1. Connecting To The Calendar Service ..................................................... 761
5.2. Retrieving A Calendar List ..................................................................... 763
5.3. Retrieving Events .................................................................................. 764
5.4. Creating Events ..................................................................................... 766
5.5. Modifying Events ................................................................................... 769
5.6. Deleting Events ..................................................................................... 769
5.7. Accessing Event Comments ................................................................... 770
6. Using Google Documents List Data API ............................................................ 770
6.1. Get a List of Documents ........................................................................ 770

104
Guide de référence
Zend Framework

6.2. Upload a Document ............................................................................... 771


6.3. Searching the documents feed ............................................................... 772
7. Using Google Health ........................................................................................ 772
7.1. Connect To The Health Service ............................................................. 773
7.2. Profile Feed .......................................................................................... 775
7.3. Profile List Feed .................................................................................... 777
7.4. Sending Notices to the Register Feed ..................................................... 777
8. Using Google Spreadsheets ............................................................................. 778
8.1. Create a Spreadsheet ............................................................................ 778
8.2. Get a List of Spreadsheets .................................................................... 778
8.3. Get a List of Worksheets ....................................................................... 779
8.4. Interacting With List-based Feeds ........................................................... 779
8.5. Interacting With Cell-based Feeds .......................................................... 781
9. Using Google Apps Provisioning ....................................................................... 782
9.1. Setting the current domain ..................................................................... 783
9.2. Interacting with users ............................................................................. 783
9.3. Interacting with nicknames ..................................................................... 786
9.4. Interacting with email lists ...................................................................... 788
9.5. Interacting with email list recipients ......................................................... 789
9.6. Handling errors ..................................................................................... 790
10. Using Google Base ........................................................................................ 791
10.1. Connect To The Base Service .............................................................. 791
10.2. Retrieve Items ..................................................................................... 794
10.3. Insert, Update, and Delete Customer Items ........................................... 795
11. Utilisation des albums Web Picasa .................................................................. 797
11.1. Se connecter au service ...................................................................... 797
11.2. Comprendre et construire des requêtes ................................................ 800
11.3. Récupérer des flux et des éléments ...................................................... 801
11.4. Créer des ressources .......................................................................... 804
11.5. Supprimer des éléments ...................................................................... 806
12. Using the YouTube Data API .......................................................................... 807
12.1. Authentication ...................................................................................... 808
12.2. Developer Keys and Client ID .............................................................. 808
12.3. Retrieving public video feeds ................................................................ 808
12.4. Retrieving video comments .................................................................. 810
12.5. Retrieving playlist feeds ....................................................................... 810
12.6. Retrieving a list of a user's subscriptions ............................................... 811
12.7. Retrieving a user's profile ..................................................................... 811
12.8. Uploading Videos to YouTube .............................................................. 812
12.9. Browser-based upload ......................................................................... 813
12.10. Checking upload status ...................................................................... 814
12.11. Other Functions ................................................................................. 815
13. Attraper les exceptions Gdata ......................................................................... 815
Zend_Http .................................................................................................................... 817
1. Introduction ...................................................................................................... 817
1.1. Utilisation de Zend_Http_Client .............................................................. 817
1.2. Les paramètres de configuration ............................................................ 817
1.3. Utilisation basique ................................................................................. 818
1.4. Ajouts de paramètres GET et POST ....................................................... 819
1.5. Accéder à la dernière requête, ou réponse .............................................. 820
2. Zend_Http_Client - Utilisation avancée .............................................................. 820
2.1. Redirections HTTP ................................................................................ 820
2.2. Ajout de cookies et gestion de leur persistance ....................................... 820
2.3. Définir des en-têtes personnalisés .......................................................... 821

105
Guide de référence
Zend Framework

2.4. Envoi de fichiers ................................................................................... 822


2.5. Envoyer des données brutes via POST .................................................. 823
2.6. Authentification HTTP ............................................................................ 824
2.7. Envoyer plusieurs requêtes avec le même client ...................................... 824
2.8. Data Streaming ..................................................................................... 825
3. Zend_Http_Client - Adaptateurs de connexion ................................................... 826
3.1. Présentation globale .............................................................................. 826
3.2. Adaptateur Socket ................................................................................. 827
3.3. Adaptateur Proxy ................................................................................... 829
3.4. The cURL Adapter ................................................................................ 830
3.5. Adaptateur Test ..................................................................................... 831
3.6. Créer vos propres adaptateurs de connexion .......................................... 834
4. Zend_Http_Cookie and Zend_Http_CookieJar .................................................... 836
4.1. Introduction ........................................................................................... 836
4.2. Instancier des objets Zend_Http_Cookie ................................................. 836
4.3. Zend_Http_Cookie méthodes getter ........................................................ 837
4.4. Zend_Http_Cookie: Correspondance de scénario .................................... 838
4.5. Classe Zend_Http_CookieJar : Instanciation ............................................ 839
4.6. Ajouter des cookies à un objet Zend_Http_CookieJar ............................... 840
4.7. Récupérer les cookies présents dans un objet Zend_Http_CookieJar ........ 840
5. Zend_Http_Response ....................................................................................... 841
5.1. Introduction ........................................................................................... 841
5.2. Méthodes de tests booléennes ............................................................... 842
5.3. Méthodes accesseurs ............................................................................ 842
5.4. Analyseurs statiques de réponse HTTP .................................................. 843
Zend_InfoCard ............................................................................................................. 845
1. Introduction ...................................................................................................... 845
1.1. Basic Theory of Usage .......................................................................... 845
1.2. Using as part of Zend_Auth ................................................................... 845
1.3. Using the Zend_InfoCard component standalone ..................................... 847
1.4. Working with a Claims object ................................................................. 847
1.5. Attaching Information Cards to existing accounts ..................................... 848
1.6. Creating Zend_InfoCard Adapters .......................................................... 849
Zend_Json ................................................................................................................... 851
1. Introduction ...................................................................................................... 851
2. Utilisation de base ........................................................................................... 851
2.1. Pretty-printing JSON .............................................................................. 851
3. Utilisation avancée de Zend_Json ..................................................................... 852
3.1. Objets JSON ......................................................................................... 852
3.2. Encoding PHP objects ........................................................................... 852
3.3. Internal Encoder/Decoder ....................................................................... 852
3.4. JSON Expressions ................................................................................ 852
4. XML to JSON conversion ................................................................................. 853
5. Zend_Json_Server - JSON-RPC server ............................................................. 855
5.1. Advanced Details .................................................................................. 857
Zend_Layout ................................................................................................................ 863
1. Introduction ...................................................................................................... 863
2. Zend_Layout - Démarrage rapide ...................................................................... 863
2.1. Scripts de layout ................................................................................... 863
2.2. Utilisation de Zend_Layout avec le système MVC de Zend Framework ...... 864
2.3. Utilisation de Zend_Layout en composant indépendant ............................ 865
2.4. Layout d'exemple .................................................................................. 866
3. Zend_Layout options de configuration ............................................................... 868
3.1. Exemples .............................................................................................. 868

106
Guide de référence
Zend Framework

4. Zend_Layout, utilisation avancée ...................................................................... 870


4.1. Objets de vue personnalisés .................................................................. 870
4.2. Plugin de contrôleur frontal personnalisé ................................................. 871
4.3. Aide d'action personnalisée .................................................................... 871
4.4. Résolution de chemin de script personnalisé (inflecteur) ........................... 871
Zend_Ldap .................................................................................................................. 873
1. Introduction ...................................................................................................... 873
1.1. Theory of operation ............................................................................... 873
2. API overview ................................................................................................... 876
2.1. Configuration / options ........................................................................... 876
2.2. API Reference ....................................................................................... 878
3. Usage Scenarios .............................................................................................. 903
3.1. Authentication scenarios ........................................................................ 903
3.2. Basic CRUD operations ......................................................................... 904
3.3. Extended operations .............................................................................. 905
4. Tools ............................................................................................................... 906
4.1. Creation and modification of DN strings .................................................. 906
4.2. Using the filter API to create search filters ............................................... 906
4.3. Modify LDAP entries using the Attribute API ............................................ 906
5. Object oriented access to the LDAP tree using Zend_Ldap_Node ........................ 906
5.1. Basic CRUD operations ......................................................................... 906
5.2. Extended operations .............................................................................. 907
5.3. Tree traversal ........................................................................................ 907
6. Getting information from the LDAP server .......................................................... 907
6.1. RootDSE ............................................................................................... 907
6.2. Schema Browsing ................................................................................. 907
7. Serializing LDAP data to and from LDIF ............................................................ 908
7.1. Serialize a LDAP entry to LDIF .............................................................. 908
7.2. Deserialize a LDIF string into a LDAP entry ............................................ 909
Zend_Loader ............................................................................................................... 911
1. Charger les fichiers et les classes dynamiquement ............................................. 911
1.1. Charger des fichiers .............................................................................. 911
1.2. Charger des classes .............................................................................. 911
1.3. Tester si un fichier est lisible .................................................................. 912
1.4. Utiliser l'autoloader ................................................................................ 913
2. L'autoloader ..................................................................................................... 914
2.1. Utiliser le chargeur automatique (autoloader) ........................................... 914
2.2. Selecting a Zend Framework version ...................................................... 915
2.3. L'interface de l'autoloader ...................................................................... 917
2.4. Référence de l'autoloader ...................................................................... 917
3. Autoloaders de ressources ............................................................................... 920
3.1. Utilisation de l'autoloader de ressources ................................................. 920
3.2. L'autoloader de ressource Module .......................................................... 922
3.3. Utiliser les autoloaders de ressources comme fabriques d'objets ............... 922
3.4. Référence de l'autoloader de ressources ................................................ 922
4. Chargeur de Plugins ........................................................................................ 922
4.1. Utilisation basique ................................................................................. 923
4.2. Manipulation des chemins des Plugins .................................................... 924
4.3. Test des Plugins et récupération des noms de classe .............................. 924
4.4. Obtenir de meilleures performances avec les Plugins ............................... 924
Zend_Locale ................................................................................................................ 926
1. Introduction ...................................................................................................... 926
1.1. What is Localization .............................................................................. 926
1.2. What is a Locale? ................................................................................. 927

107
Guide de référence
Zend Framework

1.3. How are Locales Represented? ............................................................. 927


1.4. Selecting the Right Locale ..................................................................... 928
1.5. Usage of automatic Locales ................................................................... 928
1.6. Using a default Locale ........................................................................... 929
1.7. ZF Locale-Aware Classes ...................................................................... 930
1.8. Application wide locale .......................................................................... 930
1.9. Zend_Locale_Format::setOptions(array $options) .................................... 931
1.10. Speed up Zend_Locale and its subclasses ............................................ 931
2. Using Zend_Locale .......................................................................................... 932
2.1. Copying, Cloning, and Serializing Locale Objects .................................... 932
2.2. Equality ................................................................................................. 932
2.3. Default locales ...................................................................................... 933
2.4. Set a new locale ................................................................................... 933
2.5. Getting the language and region ............................................................ 933
2.6. Obtaining localized strings ..................................................................... 934
2.7. Obtaining translations for "yes" and "no" ................................................. 948
2.8. Get a list of all known locales ................................................................ 949
2.9. Detecting locales ................................................................................... 949
3. Normalization and Localization .......................................................................... 951
3.1. Number normalization: getNumber($input, Array $options) ....................... 951
3.2. Number localization ............................................................................... 952
3.3. Number testing ...................................................................................... 954
3.4. Float value normalization ....................................................................... 954
3.5. Floating point value localization .............................................................. 954
3.6. Floating point value testing .................................................................... 954
3.7. Integer value normalization .................................................................... 955
3.8. Integer point value localization ............................................................... 955
3.9. Integer value testing .............................................................................. 955
3.10. Numeral System Conversion ................................................................ 955
4. Working with Dates and Times ......................................................................... 957
4.1. Normalizing Dates and Times ................................................................ 957
4.2. Testing Dates ........................................................................................ 960
4.3. Normalizing a Time ............................................................................... 961
4.4. Testing Times ....................................................................................... 961
5. Supported locales ............................................................................................ 961
Zend_Log .................................................................................................................... 973
1. Présentation ..................................................................................................... 973
1.1. Créer un log ......................................................................................... 973
1.2. Messages de logs ................................................................................. 973
1.3. Détruire un log ...................................................................................... 974
1.4. Utiliser les priorités intégrées ................................................................. 974
1.5. Ajouter ses propres priorités .................................................................. 974
1.6. Comprendre les événements de logs ...................................................... 975
2. Rédacteurs (Writers) ........................................................................................ 975
2.1. Écrire vers un flux (stream) .................................................................... 975
2.2. Écrire dans des bases de données ......................................................... 976
2.3. Écrire vers Firebug ................................................................................ 976
2.4. Écrire vers un émail .............................................................................. 979
2.5. Ecrire dans lee journal du système ......................................................... 981
2.6. Ecrire vers le moniteur Zend Server ....................................................... 982
2.7. Déraciner les rédacteurs ........................................................................ 986
2.8. Tester avec un simulacre ....................................................................... 986
2.9. Additionner les rédacteurs ...................................................................... 986
3. Formateurs (mise en forme) ............................................................................. 987

108
Guide de référence
Zend Framework

3.1. Formatage simple .................................................................................. 987


3.2. Formater vers le XML ............................................................................ 987
4. Filtres .............................................................................................................. 988
4.1. Filtrer pour tous les rédacteurs (Writers) ................................................. 988
4.2. Filtrer pour une seule instance de rédacteur ............................................ 989
5. Utiliser la fabrique pour créer des logs .............................................................. 989
5.1. Options pour les objets d'écriture ........................................................... 990
5.2. Options des filtres ................................................................................. 991
5.3. Créer des objets d'écriture et des filtres configurés .................................. 991
Zend_Mail .................................................................................................................... 994
1. Introduction ...................................................................................................... 994
1.1. Pour commencer ................................................................................... 994
1.2. Configurer le transport sendmail par défaut ............................................. 994
2. Envoyer des émail en utilisant SMTP ................................................................ 995
3. Envoyer plusieurs émail par connexion SMTP ................................................... 996
4. Utiliser différents transports .............................................................................. 997
5. Émail HTML ..................................................................................................... 997
6. Fichiers joints ................................................................................................... 998
7. Ajouter des destinataires .................................................................................. 999
8. Contrôler les limites MIME ................................................................................ 999
9. En-têtes additionnels ........................................................................................ 999
10. Jeux de caractères ....................................................................................... 1000
11. Encodage ..................................................................................................... 1000
12. Authentification SMTP .................................................................................. 1001
13. Sécuriser les transports SMTP ...................................................................... 1001
14. Lire des émail .............................................................................................. 1002
14.1. Exemple simple avec Pop3 ................................................................ 1002
14.2. Ouvrir un stockage local ..................................................................... 1002
14.3. Ouvrir un stockage distant .................................................................. 1003
14.4. Extraire des messages et autres méthodes simples ............................. 1004
14.5. Travailler avec les messages ............................................................. 1004
14.6. Vérifier les drapeaux ("flags") ............................................................. 1006
14.7. Utiliser les dossiers ............................................................................ 1007
14.8. Utilisation avancée ............................................................................. 1009
Zend_Markup ............................................................................................................. 1013
1. Introduction .................................................................................................... 1013
2. Guide de démarrage avec Zend_Markup ......................................................... 1013
3. Analyseurs Zend_Markup (parsers) ................................................................. 1014
3.1. Theorie de l'analyse ............................................................................. 1014
3.2. L'analyseur BBCode ............................................................................ 1015
3.3. L'analyseur Textile ............................................................................... 1015
4. Moteurs de rendu Zend_Markup ..................................................................... 1016
4.1. Ajouter vos propres tags ...................................................................... 1016
4.2. Liste de tags ....................................................................................... 1017
Zend_Measure ........................................................................................................... 1019
1. Introduction .................................................................................................... 1019
2. Création d'une mesure ................................................................................... 1019
2.1. Créer des mesures à partir de nombres entiers et décimaux ................... 1020
2.2. Créer des mesures à partir de chaînes de caractères ............................. 1020
2.3. Mesures à partir de chaînes localisées ................................................. 1020
3. Récupérer des mesures ................................................................................. 1021
3.1. Récupération automatique .................................................................... 1021
3.2. Récupération des valeurs ..................................................................... 1022
3.3. Récupération de l'unité de mesure ........................................................ 1022

109
Guide de référence
Zend Framework

3.4. Récupération en tant que chaîne régionale ........................................... 1022


4. Manipuler des mesures .................................................................................. 1022
4.1. Convertir ............................................................................................. 1023
4.2. Ajouter et soustraire ............................................................................ 1023
4.3. Vérifier l'égalité des mesures ................................................................ 1024
4.4. Comparer les mesures ......................................................................... 1024
4.5. Changer manuellement des valeurs ...................................................... 1025
4.6. Changer manuellement de type ............................................................ 1025
5. Types de mesures ......................................................................................... 1025
5.1. Conseils pour Zend_Measure_Binary .................................................... 1028
5.2. Conseils pour Zend_Measure_Number ................................................. 1028
5.3. Chiffres romains .................................................................................. 1029
Zend_Memory ............................................................................................................ 1030
1. Présentation ................................................................................................... 1030
1.1. Introduction ......................................................................................... 1030
1.2. Aspect théorique ................................................................................. 1030
2. Manager de mémoire ..................................................................................... 1031
2.1. Créer un manager de mémoire ............................................................. 1031
2.2. Manager les objets mémoire ................................................................ 1032
2.3. Régler le manager de mémoire ............................................................ 1033
3. Objet mémoire ............................................................................................... 1034
3.1. Mobile ................................................................................................. 1034
3.2. Verrouillé ............................................................................................. 1034
3.3. Propriété "value" du manager de mémoire ............................................ 1034
3.4. Interface du conteneur de mémoire ...................................................... 1035
Zend_Mime ................................................................................................................ 1037
1. Zend_Mime .................................................................................................... 1037
1.1. Introduction ......................................................................................... 1037
1.2. Méthodes statiques et constantes ......................................................... 1037
1.3. Instancier Zend_Mime .......................................................................... 1038
2. Zend_Mime_Message ..................................................................................... 1038
2.1. Introduction ......................................................................................... 1038
2.2. Instancier Zend_Mime_Message .......................................................... 1038
2.3. Ajouter des parties MIME ..................................................................... 1038
2.4. Gérer les frontières .............................................................................. 1038
2.5. Parser une chaîne de caractère pour créer un objet Zend_Mime_Message
(expérimental) ............................................................................................ 1039
3. Zend_Mime_Part ............................................................................................ 1039
3.1. Introduction ......................................................................................... 1039
3.2. Instanciation ........................................................................................ 1039
3.3. Méthodes pour retourner la partie du message en une chaîne de
caractères .................................................................................................. 1039
Zend_Navigation ........................................................................................................ 1041
1. Introduction .................................................................................................... 1041
1.1. Pages et Conteneurs ........................................................................... 1041
1.2. Séparation des données (modèle) et du rendu (vue) .............................. 1041
2. Pages ............................................................................................................ 1041
2.1. Caractéristiques communes aux pages ................................................. 1042
2.2. Zend_Navigation_Page_Mvc ................................................................ 1044
2.3. Zend_Navigation_Page_Uri .................................................................. 1048
2.4. Créer des pages de type personnalisé .................................................. 1049
2.5. Créer des pages avec la fabrique ......................................................... 1050
3. Containers ..................................................................................................... 1052
3.1. Creating containers .............................................................................. 1052

110
Guide de référence
Zend Framework

3.2. Adding pages ...................................................................................... 1055


3.3. Removing pages ................................................................................. 1055
3.4. Finding pages ..................................................................................... 1056
3.5. Iterating containers .............................................................................. 1058
3.6. Other operations .................................................................................. 1058
Zend_Oauth ............................................................................................................... 1061
1. Introduction to OAuth ..................................................................................... 1061
1.1. Protocol Workflow ................................................................................ 1061
1.2. Security Architecture ............................................................................ 1062
1.3. Getting Started .................................................................................... 1063
Zend_OpenId ............................................................................................................. 1067
1. Introduction .................................................................................................... 1067
1.1. Qu'est ce qu'OpenID ? ......................................................................... 1067
1.2. Comment cela fonctionne-t-il ? ............................................................. 1067
1.3. Zend_OpenId Structure ........................................................................ 1068
1.4. Standards OpenID supportés ............................................................... 1068
2. Zend_OpenId_Consumer Basics ..................................................................... 1068
2.1. OpenID Authentication ......................................................................... 1068
2.2. Combining all Steps in One Page ......................................................... 1070
2.3. Consumer Realm ................................................................................. 1070
2.4. Immediate Check ................................................................................. 1071
2.5. Zend_OpenId_Consumer_Storage ........................................................ 1071
2.6. Simple Registration Extension .............................................................. 1074
2.7. Integration with Zend_Auth ................................................................... 1075
2.8. Integration with Zend_Controller ........................................................... 1077
3. Zend_OpenId_Provider ................................................................................... 1077
3.1. Quick Start .......................................................................................... 1077
3.2. Combined Provide Scripts .................................................................... 1080
3.3. Simple Registration Extension .............................................................. 1081
3.4. Anything Else? .................................................................................... 1083
Zend_Paginator .......................................................................................................... 1084
1. Introduction .................................................................................................... 1084
2. Utilisation ....................................................................................................... 1084
2.1. Paginer des collections de données ...................................................... 1084
2.2. The DbSelect and DbTableSelect adapter ............................................. 1085
2.3. Rendre des pages avec les scripts de vue ............................................ 1086
3. Configuration .................................................................................................. 1090
4. Utilisation avancée ......................................................................................... 1091
4.1. Adaptateurs de source de données personnalisée ................................. 1091
4.2. Styles de défilement personnalisés ....................................................... 1091
4.3. Fonctionnalité de mise en cache .......................................................... 1092
4.4. Zend_Paginator_AdapterAggregate Interface ......................................... 1093
Zend_Pdf ................................................................................................................... 1094
1. Introduction .................................................................................................... 1094
2. Créer et charger des documents PDF ............................................................. 1094
3. Sauvegarder les changement dans un document PDF ...................................... 1095
4. Les pages d'un document ............................................................................... 1095
4.1. Création de page ................................................................................. 1095
4.2. Clonage de page ................................................................................. 1096
5. Dessiner ........................................................................................................ 1097
5.1. Géométrie ........................................................................................... 1097
5.2. Couleurs ............................................................................................. 1097
5.3. Dessiner des formes ............................................................................ 1098
5.4. Dessiner du texte ................................................................................ 1100

111
Guide de référence
Zend Framework

5.5. Utiliser des polices de caractères ......................................................... 1101


5.6. Limitations des polices standard PDF ................................................... 1103
5.7. Extraction des polices .......................................................................... 1104
5.8. Insertion d'images ................................................................................ 1106
5.9. Style de lignes .................................................................................... 1106
5.10. Style de remplissage .......................................................................... 1107
5.11. Transformations linéaires ................................................................... 1108
5.12. Sauvegarder et restaurer l'état graphique ............................................ 1109
5.13. Zone de dessin ................................................................................. 1109
5.14. Styles ................................................................................................ 1110
5.15. Transparence .................................................................................... 1113
6. Interactive Features ........................................................................................ 1113
6.1. Destinations ........................................................................................ 1113
6.2. Actions ................................................................................................ 1118
6.3. Document Outline (bookmarks) ............................................................ 1120
6.4. Annotations ......................................................................................... 1122
7. Informations du document et métadonnées ...................................................... 1123
8. Exemple d'utilisation du module Zend_Pdf ....................................................... 1125
Zend_ProgressBar ...................................................................................................... 1127
1. Zend_ProgressBar .......................................................................................... 1127
1.1. Introduction ......................................................................................... 1127
1.2. Utilisation basique de Zend_Progressbar .............................................. 1127
1.3. Adaptateurs standard ........................................................................... 1127
Zend_Queue .............................................................................................................. 1132
1. Introduction .................................................................................................... 1132
2. Example usage .............................................................................................. 1132
3. Framework ..................................................................................................... 1133
3.1. Introduction ......................................................................................... 1134
3.2. Commonality among adapters .............................................................. 1134
4. Adapters ........................................................................................................ 1134
4.1. Specific Adapters - Configuration settings ............................................. 1135
4.2. Notes for Specific Adapters .................................................................. 1137
5. Customizing Zend_Queue ............................................................................... 1139
5.1. Creating your own adapter ................................................................... 1139
5.2. Creating your own message class ........................................................ 1140
5.3. Creating your own message iterator class ............................................. 1141
5.4. Creating your own queue class ........................................................... 1141
6. Stomp ............................................................................................................ 1141
6.1. Stomp - Supporting classes ................................................................. 1141
Zend_Reflection ......................................................................................................... 1142
1. Introduction .................................................................................................... 1142
2. Zend_Reflection Exemples .............................................................................. 1142
3. Réference de Zend_Reflection ........................................................................ 1143
3.1. Zend_Reflection_Docblock ................................................................... 1144
3.2. Zend_Reflection_Docblock_Tag ............................................................ 1144
3.3. Zend_Reflection_Docblock_Tag_Param ................................................ 1144
3.4. Zend_Reflection_Docblock_Tag_Return ................................................ 1145
3.5. Zend_Reflection_File ........................................................................... 1145
3.6. Zend_Reflection_Class ........................................................................ 1145
3.7. Zend_Reflection_Extension .................................................................. 1146
3.8. Zend_Reflection_Function .................................................................... 1146
3.9. Zend_Reflection_Method ...................................................................... 1146
3.10. Zend_Reflection_Parameter ............................................................... 1146
3.11. Zend_Reflection_Property .................................................................. 1147

112
Guide de référence
Zend Framework

Zend_Registry ............................................................................................................ 1148


1. Utiliser le registre ........................................................................................... 1148
1.1. Mettre des valeurs dans le registre ....................................................... 1148
1.2. Lire des valeurs du registre .................................................................. 1148
1.3. Construire un objet registre .................................................................. 1148
1.4. Accéder au registre comme à un tableau .............................................. 1149
1.5. Accéder au registre comme à un objet .................................................. 1149
1.6. Vérifier si un index existe ..................................................................... 1150
1.7. Étendre le registre ............................................................................... 1150
1.8. Décharger le registre statique ............................................................... 1151
Zend_Rest ................................................................................................................. 1152
1. Introduction .................................................................................................... 1152
2. Zend_Rest_Client ........................................................................................... 1152
2.1. Introduction ......................................................................................... 1152
2.2. Réponses ............................................................................................ 1153
2.3. Arguments de requêtes ........................................................................ 1154
3. Zend_Rest_Server .......................................................................................... 1155
3.1. Introduction ......................................................................................... 1155
3.2. Utilisation d'un serveur REST ............................................................... 1155
3.3. Appelé un service Zend_Rest_Server ................................................... 1156
3.4. Envoyer un statut personnalisé ............................................................. 1156
3.5. Renvoyer une réponse XML personnalisée ........................................... 1157
Zend_Search_Lucene ................................................................................................. 1158
1. Vue d'ensemble ............................................................................................. 1158
1.1. Introduction ......................................................................................... 1158
1.2. Objet "Document" et "Field" .................................................................. 1158
1.3. Comprendre les types de champs ........................................................ 1160
1.4. Documents HTML ................................................................................ 1160
1.5. Documents Word 2007 ........................................................................ 1161
1.6. Document Powerpoint 2007 ................................................................. 1163
1.7. Documents Excel 2007 ........................................................................ 1164
2. Créer des index ............................................................................................. 1165
2.1. Créer un nouvel index ......................................................................... 1165
2.2. Mettre à jour un index ......................................................................... 1165
2.3. Mise à jour de Documents ................................................................... 1165
2.4. Récupération de la taille de l'index ....................................................... 1166
2.5. Optimisation d'index ............................................................................. 1166
2.6. Permissions ......................................................................................... 1168
2.7. Limitations ........................................................................................... 1168
3. Searching an Index ........................................................................................ 1168
3.1. Building Queries .................................................................................. 1168
3.2. Search Results .................................................................................... 1170
3.3. Limiting the Result Set ......................................................................... 1171
3.4. Results Scoring ................................................................................... 1171
3.5. Search Result Sorting .......................................................................... 1172
3.6. Search Results Highlighting .................................................................. 1172
4. Langage de requêtes ..................................................................................... 1174
4.1. Termes ............................................................................................... 1174
4.2. Champs .............................................................................................. 1175
4.3. Jokers (Wildcards) ............................................................................... 1175
4.4. Term Modifiers .................................................................................... 1176
4.5. Range Searches .................................................................................. 1176
4.6. Fuzzy Searches ................................................................................... 1177
4.7. Matched terms limitation ...................................................................... 1177

113
Guide de référence
Zend Framework

4.8. Proximity Searches .............................................................................. 1177


4.9. Boosting a Term .................................................................................. 1177
4.10. Boolean Operators ............................................................................. 1178
4.11. Grouping ........................................................................................... 1179
4.12. Field Grouping ................................................................................... 1179
4.13. Escaping Special Characters .............................................................. 1180
5. API de construction de requêtes ..................................................................... 1180
5.1. Les Exceptions du parseur de requêtes ................................................ 1180
5.2. Requête sur un terme .......................................................................... 1181
5.3. Requête multi-termes ........................................................................... 1181
5.4. Requête booléene ............................................................................... 1182
5.5. Requête Joker (wildcard) ..................................................................... 1184
5.6. Requête floue (fuzzy query) ................................................................. 1184
5.7. Requête de phrase .............................................................................. 1185
5.8. Requête d'intervalle ............................................................................. 1187
6. Jeu de caractères .......................................................................................... 1188
6.1. Support UTF-8 et caractères sur un octet .............................................. 1188
6.2. Analyseur de texte par défaut .............................................................. 1188
6.3. Analyseurs de texte compatibles UTF-8 ................................................ 1188
7. Extensibilité .................................................................................................... 1190
7.1. Analyse de texte ................................................................................. 1190
7.2. Filtrage des segments .......................................................................... 1192
7.3. Algorithme de score ............................................................................. 1193
7.4. Conteneur de stockage ........................................................................ 1194
8. Agir avec Lucene Java ................................................................................... 1196
8.1. Formats de fichier ................................................................................ 1196
8.2. Répertoire Index .................................................................................. 1196
8.3. Code source Java ............................................................................... 1196
9. Avancé .......................................................................................................... 1197
9.1. Depuis Zend Framework 1.6, gestion des transformations de format
d'index ....................................................................................................... 1197
9.2. Utiliser les propriétés statiques de l'index .............................................. 1198
10. Bonnes pratiques ......................................................................................... 1199
10.1. Nommage des champs ...................................................................... 1199
10.2. Performance de l'indexation ............................................................... 1200
10.3. Indexation à l'arrêt du programme ...................................................... 1202
10.4. Récupération de documents par leur id unique .................................... 1202
10.5. Utilisation de la mémoire .................................................................... 1203
10.6. Encodage .......................................................................................... 1204
10.7. Maintenance de l'index ....................................................................... 1205
Zend_Serializer .......................................................................................................... 1206
1. Introduction .................................................................................................... 1206
1.1. Utiliser l'interface statique de Zend_Serializer ........................................ 1206
2. Zend_Serializer_Adapter ................................................................................. 1207
2.1. Zend_Serializer_Adapter_PhpSerialize .................................................. 1207
2.2. Zend_Serializer_Adapter_Igbinary ......................................................... 1207
2.3. Zend_Serializer_Adapter_Wddx ............................................................ 1207
2.4. Zend_Serializer_Adapter_Json ............................................................. 1208
2.5. Zend_Serializer_Adapter_Amf 0 et 3 ..................................................... 1208
2.6. Zend_Serializer_Adapter_PythonPickle ................................................. 1208
2.7. Zend_Serializer_Adapter_PhpCode ...................................................... 1209
Zend_Server .............................................................................................................. 1210
1. Introduction .................................................................................................... 1210
2. Zend_Server_Reflection .................................................................................. 1210

114
Guide de référence
Zend Framework

2.1. Introduction ......................................................................................... 1210


2.2. Utilisation ............................................................................................ 1210
Zend_Service ............................................................................................................. 1212
1. Introduction .................................................................................................... 1212
2. Zend_Service_Akismet ................................................................................... 1212
2.1. Introduction ......................................................................................... 1212
2.2. Verify an API key ................................................................................ 1213
2.3. Check for spam ................................................................................... 1213
2.4. Submitting known spam ....................................................................... 1214
2.5. Submitting false positives (ham) ........................................................... 1214
2.6. Zend-specific Methods ......................................................................... 1215
3. Zend_Service_Amazon ................................................................................... 1215
3.1. Introduction ......................................................................................... 1215
3.2. Codes de pays .................................................................................... 1216
3.3. Rechercher un produit Amazon spécifique avec son ASIN ...................... 1217
3.4. Lancer des recherches de produits sur Amazon .................................... 1217
3.5. Utiliser l'API alternative de requêtes ...................................................... 1218
3.6. Classes Zend_Service_Amazon ........................................................... 1218
4. Zend_Service_Amazon_Ec2 ........................................................................... 1224
4.1. Introduction ......................................................................................... 1224
4.2. What is Amazon Ec2? ......................................................................... 1224
4.3. Static Methods .................................................................................... 1224
5. Zend_Service_Amazon_Ec2: Instances ........................................................... 1224
5.1. Instance Types .................................................................................... 1224
5.2. Running Amazon EC2 Instances .......................................................... 1226
5.3. Amazon Instance Utilities ..................................................................... 1227
6. Zend_Service_Amazon_Ec2: Windows Instances ............................................. 1229
6.1. Windows Instances Usage ................................................................... 1230
7. Zend_Service_Amazon_Ec2: Reserved Instances ............................................ 1231
7.1. How Reserved Instances are Applied .................................................... 1231
7.2. Reserved Instances Usage .................................................................. 1231
8. Zend_Service_Amazon_Ec2: CloudWatch Monitoring ....................................... 1232
8.1. CloudWatch Usage .............................................................................. 1232
9. Zend_Service_Amazon_Ec2: Amazon Machine Images (AMI) ........................... 1234
9.1. AMI Information Utilities ....................................................................... 1234
9.2. AMI Attribute Utilities ........................................................................... 1235
10. Zend_Service_Amazon_Ec2: Elastic Block Stroage (EBS) ............................... 1236
10.1. Create EBS Volumes and Snapshots .................................................. 1237
10.2. Describing EBS Volumes and Snapshots ............................................ 1237
10.3. Attach and Detaching Volumes from Instances .................................... 1238
10.4. Deleting EBS Volumes and Snapshots ................................................ 1239
11. Zend_Service_Amazon_Ec2: Elastic IP Addresses ......................................... 1239
12. Zend_Service_Amazon_Ec2: Keypairs ........................................................... 1240
13. Zend_Service_Amazon_Ec2: Regions and Availability Zones .......................... 1241
13.1. Amazon EC2 Regions ........................................................................ 1241
13.2. Amazon EC2 Availability Zones .......................................................... 1242
14. Zend_Service_Amazon_Ec2: Security Groups ................................................ 1242
14.1. Security Group Maintenance .............................................................. 1242
14.2. Authorizing Access ............................................................................ 1243
14.3. Revoking Access ............................................................................... 1244
15. Zend_Service_Amazon_S3 ........................................................................... 1245
15.1. Introduction ....................................................................................... 1245
15.2. Registering with Amazon S3 ............................................................... 1245
15.3. API Documentation ............................................................................ 1245

115
Guide de référence
Zend Framework

15.4. Features ............................................................................................ 1245


15.5. Getting Started .................................................................................. 1245
15.6. Bucket operations .............................................................................. 1246
15.7. Object operations ............................................................................... 1247
15.8. Data Streaming ................................................................................. 1249
15.9. Stream wrapper ................................................................................. 1249
16. Zend_Service_Amazon_Sqs .......................................................................... 1250
16.1. Introduction ....................................................................................... 1250
16.2. Registering with Amazon SQS ............................................................ 1250
16.3. API Documentation ............................................................................ 1250
16.4. Features ............................................................................................ 1250
16.5. Getting Started .................................................................................. 1250
16.6. Queue operations .............................................................................. 1251
16.7. Message operations ........................................................................... 1252
17. Zend_Service_Audioscrobbler ....................................................................... 1252
17.1. Introduction ....................................................................................... 1252
17.2. Users ................................................................................................ 1253
17.3. Artists ............................................................................................... 1254
17.4. Tracks ............................................................................................... 1255
17.5. Tags ................................................................................................. 1255
17.6. Groups .............................................................................................. 1255
17.7. Forums ............................................................................................. 1256
18. Zend_Service_Delicious ................................................................................ 1256
18.1. Introduction ....................................................................................... 1256
18.2. Récupérer vos entrées ....................................................................... 1256
18.3. Zend_Service_Delicious_PostList ........................................................ 1257
18.4. Édition des entrées ............................................................................ 1258
18.5. Supprimer des entrées ....................................................................... 1259
18.6. Ajout d'entrées .................................................................................. 1259
18.7. Les étiquettes ("tags") ........................................................................ 1260
18.8. Les groupes d'étiquettes .................................................................... 1260
18.9. Données publiques ............................................................................ 1260
18.10. Client HTTP ..................................................................................... 1261
19. Zend_Service_DeveloperGarden ................................................................... 1262
19.1. Introduction to DeveloperGarden ........................................................ 1262
19.2. BaseUserService ............................................................................... 1263
19.3. IP Location ........................................................................................ 1264
19.4. Local Search ..................................................................................... 1264
19.5. Send SMS ......................................................................................... 1265
19.6. SMS Validation .................................................................................. 1265
19.7. Voice Call ......................................................................................... 1266
19.8. ConferenceCall .................................................................................. 1267
19.9. Performance and Caching .................................................................. 1268
20. Zend_Service_Flickr ..................................................................................... 1269
20.1. Introduction ....................................................................................... 1269
20.2. Trouver les photos et les informations des utilisateurs Flickr .................. 1269
20.3. Trouver des photos dans le pool d'un groupe ...................................... 1270
20.4. Récupérer les détails d'une image ...................................................... 1270
20.5. Classes de résultats Zend_Service_Flickr ............................................ 1270
21. Zend_Service_LiveDocx ................................................................................ 1272
21.1. Introduction to LiveDocx ..................................................................... 1272
21.2. Zend_Service_LiveDocx_MailMerge .................................................... 1274
22. Zend_Service_Nirvanix ................................................................................. 1286
22.1. Introduction ....................................................................................... 1286

116
Guide de référence
Zend Framework

22.2. Registering with Nirvanix .................................................................... 1286


22.3. API Documentation ............................................................................ 1286
22.4. Features ............................................................................................ 1287
22.5. Getting Started .................................................................................. 1287
22.6. Understanding the Proxy .................................................................... 1288
22.7. Examining Results ............................................................................. 1288
22.8. Handling Errors ................................................................................. 1289
23. Zend_Service_ReCaptcha ............................................................................. 1290
23.1. Introduction ....................................................................................... 1290
23.2. Utilisation la plus simple ..................................................................... 1290
23.3. Hiding email addresses ...................................................................... 1291
24. Zend_Service_Simpy .................................................................................... 1292
24.1. Introduction ....................................................................................... 1292
24.2. Liens ................................................................................................. 1292
24.3. Mots-clés ........................................................................................... 1294
24.4. Notes ................................................................................................ 1295
24.5. Listes de surveillance ......................................................................... 1296
25. Introduction .................................................................................................. 1297
25.1. Démarrage avec Zend_Service_SlideShare .................................. 1297
25.2. L'objet SlideShow .............................................................................. 1298
25.3. Récupérer un diaporama simplement .................................................. 1300
25.4. Récupérer des groupes de diaporamas ............................................... 1300
25.5. Politique de cache de Zend_Service_SlideShare .......................... 1301
25.6. Changer le comportement du client HTTP ........................................... 1302
26. Zend_Service_StrikeIron ............................................................................... 1302
26.1. Overview ........................................................................................... 1302
26.2. Registering with StrikeIron .................................................................. 1303
26.3. Getting Started .................................................................................. 1303
26.4. Making Your First Query .................................................................... 1303
26.5. Examining Results ............................................................................. 1304
26.6. Handling Errors ................................................................................. 1305
26.7. Checking Your Subscription ................................................................ 1305
27. Zend_Service_StrikeIron: Bundled Services ................................................... 1306
27.1. ZIP Code Information ......................................................................... 1306
27.2. U.S. Address Verification .................................................................... 1307
27.3. Sales & Use Tax Basic ...................................................................... 1308
28. Zend_Service_StrikeIron: Advanced Uses ...................................................... 1308
28.1. Using Services by WSDL ................................................................... 1308
28.2. Viewing SOAP Transactions ............................................................... 1309
29. Zend_Service_Technorati .............................................................................. 1309
29.1. Introduction ....................................................................................... 1309
29.2. Getting Started .................................................................................. 1310
29.3. Making Your First Query .................................................................... 1310
29.4. Consuming Results ............................................................................ 1311
29.5. Handling Errors ................................................................................. 1312
29.6. Checking Your API Key Daily Usage ................................................... 1312
29.7. Available Technorati Queries .............................................................. 1313
29.8. Zend_Service_Technorati Classes ...................................................... 1316
30. Zend_Service_Twitter ................................................................................... 1319
30.1. Introduction ....................................................................................... 1319
30.2. Authentication .................................................................................... 1320
30.3. Account Methods ............................................................................... 1320
30.4. Status Methods ................................................................................. 1321
30.5. User Methods .................................................................................... 1323

117
Guide de référence
Zend Framework

30.6. Direct Message Methods .................................................................... 1323


30.7. Friendship Methods ........................................................................... 1324
30.8. Favorite Methods ............................................................................... 1325
30.9. Block Methods ................................................................................... 1325
30.10. Zend_Service_Twitter_Search ........................................................... 1326
31. Zend_Service_WindowsAzure ....................................................................... 1328
31.1. Introduction ....................................................................................... 1328
31.2. Installing the Windows Azure SDK ...................................................... 1328
31.3. API Documentation ............................................................................ 1328
31.4. Features ............................................................................................ 1328
31.5. Architecture ....................................................................................... 1328
31.6. Zend_Service_WindowsAzure_Storage_Blob ....................................... 1328
31.7. Zend_Service_WindowsAzure_Storage_Table ..................................... 1333
31.8. Zend_Service_WindowsAzure_Storage_Queue ................................... 1340
32. Zend_Service_Yahoo .................................................................................... 1342
32.1. Introduction ....................................................................................... 1342
32.2. Rechercher sur le Web avec Yahoo! ................................................... 1342
32.3. Trouver des images avec Yahoo! ....................................................... 1343
32.4. Trouver des vidéos avec Yahoo! ......................................................... 1343
32.5. Trouver des entreprises et des services locaux avec Yahoo! ................. 1343
32.6. Rechercher dans Yahoo! News .......................................................... 1343
32.7. Rechercher avec Yahoo! Site Explorer Inbound Links ........................... 1344
32.8. Rechercher avec Yahoo! Site Explorer's PageData .............................. 1344
32.9. Classes Zend_Service_Yahoo ............................................................ 1344
Zend_Session ............................................................................................................ 1351
1. Introduction .................................................................................................... 1351
2. Usage basique ............................................................................................... 1351
2.1. Tutoriel d'exemples .............................................................................. 1352
2.2. Énumérer les espaces de noms de session ........................................... 1353
2.3. Accesseurs pour les espaces de noms de session ................................. 1353
3. Utilisation avancée ......................................................................................... 1354
3.1. Démarrer une session .......................................................................... 1354
3.2. Verrouiller les espaces de noms de session .......................................... 1355
3.3. Expiration d'un espace de noms ........................................................... 1355
3.4. Encapsulation de session et Contrôleurs ............................................... 1356
3.5. Limiter les instances multiples par espace de noms ............................... 1357
3.6. Travailler avec les tableaux .................................................................. 1357
3.7. Utiliser les sessions avec des objets ..................................................... 1358
3.8. Utiliser les sessions avec les tests unitaires .......................................... 1359
4. Gestion générale de la session ....................................................................... 1360
4.1. Options de configuration ...................................................................... 1361
4.2. L'erreur: "Headers Already Sent" .......................................................... 1364
4.3. Identifiants de session ......................................................................... 1364
4.4. rememberMe(integer $seconds) ................................................... 1365
4.5. forgetMe() ....................................................................................... 1366
4.6. sessionExists() ............................................................................. 1366
4.7. destroy(bool $remove_cookie = true, bool $readonly =
true) ....................................................................................................... 1366
4.8. stop() ............................................................................................... 1366
4.9. writeClose($readonly = true) .................................................. 1366
4.10. expireSessionCookie() ............................................................... 1367
4.11. setSaveHandler(Zend_Session_SaveHandler_Interface
$interface) ............................................................................................ 1367
4.12. namespaceIsset($namespace) ..................................................... 1367

118
Guide de référence
Zend Framework

4.13. namespaceUnset($namespace) ..................................................... 1367


4.14. namespaceGet($namespace) ......................................................... 1367
4.15. getIterator() ............................................................................... 1367
5. Zend_Session_SaveHandler_DbTable ............................................................. 1368
Zend_Soap ................................................................................................................ 1370
1. Zend_Soap_Server ......................................................................................... 1370
1.1. Constructeur de Zend_Soap_Server .................................................. 1370
1.2. Méthodes de définitions de l'API du service ........................................... 1371
1.3. Gestion des objets de requête et de réponse ........................................ 1372
2. Zend_Soap_Client .......................................................................................... 1374
2.1. Constructeur de Zend_Soap_Client .................................................. 1374
2.2. Effectuer des requêtes SOAP ............................................................... 1375
3. WSDL ............................................................................................................ 1376
3.1. Constructeur Zend_Soap_Wsdl ............................................................ 1376
3.2. addMessage() ..................................................................................... 1376
3.3. addPortType() ................................................................................. 1377
3.4. addPortOperation() ....................................................................... 1377
3.5. addBinding() ................................................................................... 1378
3.6. addBindingOperation() ................................................................. 1378
3.7. addSoapBinding() ........................................................................... 1378
3.8. addSoapOperation() ....................................................................... 1378
3.9. addService() ................................................................................... 1379
3.10. Correspondance de type .................................................................... 1379
3.11. addDocumentation() ..................................................................... 1381
3.12. Récupérer un document WSDL finalisé ............................................... 1381
4. Auto découverte ............................................................................................. 1381
4.1. Introduction à l'auto découverte ............................................................ 1381
4.2. Auto découverte de classe ................................................................... 1383
4.3. Auto découverte des fonctions ............................................................. 1383
4.4. Types de donnée auto découverts ........................................................ 1384
4.5. Styles de liaisons WSDL ...................................................................... 1385
Zend_Tag .................................................................................................................. 1386
1. Introduction .................................................................................................... 1386
2. Zend_Tag_Cloud ............................................................................................ 1386
2.1. Decorateurs ......................................................................................... 1387
Zend_Test .................................................................................................................. 1389
1. Introduction .................................................................................................... 1389
2. Zend_Test_PHPUnit ....................................................................................... 1389
2.1. Amorcer votre TestCase ...................................................................... 1391
2.2. Tester vos contrôleurs et vos applications MVC ..................................... 1392
2.3. Assertions ........................................................................................... 1394
2.4. Exemples ............................................................................................ 1396
3. Zend_Test_PHPUnit_Db ................................................................................. 1398
3.1. Quickstart ............................................................................................ 1398
3.2. Utilisation, API et possibilités d'extension .............................................. 1402
3.3. Utiliser l'adaptateur de tests ................................................................. 1404
Zend_Text .................................................................................................................. 1406
1. Zend_Text_Figlet ............................................................................................ 1406
2. Zend_Text_Table ........................................................................................... 1407
Zend_TimeSync ......................................................................................................... 1410
1. Introduction .................................................................................................... 1410
1.1. Pourquoi Zend_TimeSync ? ............................................................... 1410
1.2. Qu'est ce que NTP ? ........................................................................... 1411
1.3. Qu'est ce que SNTP? .......................................................................... 1411

119
Guide de référence
Zend Framework

1.4. Problèmes courants d'utilisation ............................................................ 1411


1.5. Décider quel serveur de temps utiliser .................................................. 1411
2. Utiliser Zend_TimeSync .................................................................................. 1412
2.1. Requêter un serveur de temps public .................................................... 1412
2.2. Serveurs de temps multiples ................................................................ 1412
2.3. Les protocoles des serveurs de temps .................................................. 1413
2.4. Utiliser les ports pour les serveurs de temps ......................................... 1413
2.5. Options pour les serveurs de temps ..................................................... 1413
2.6. Utiliser des serveurs de temps différents ............................................... 1414
2.7. Informations sur les serveurs de temps ................................................. 1414
2.8. Gérer les exceptions ............................................................................ 1414
Zend_Tool .................................................................................................................. 1416
1. Using Zend_Tool On The Command Line ........................................................ 1416
1.1. Installation ........................................................................................... 1416
1.2. General Purpose Commands ............................................................... 1417
1.3. Project Specific Commands .................................................................. 1417
1.4. Environment Customization .................................................................. 1420
2. Extending Zend_Tool ...................................................................................... 1421
2.1. Overview of Zend_Tool ........................................................................ 1421
2.2. Zend_Tool_Framework Extensions ....................................................... 1422
2.3. Zend_Tool_Project Extensions ............................................................. 1430
Zend_Tool_Framework ............................................................................................... 1432
1. Introduction .................................................................................................... 1432
2. Using the CLI Tool ......................................................................................... 1432
2.1. Setting up the CLI tool ......................................................................... 1433
2.2. Setting up the CLI tool on Unix-like Systems ......................................... 1433
2.3. Setting up the CLI tool on Windows ...................................................... 1435
2.4. Other Setup Considerations ................................................................. 1436
2.5. Where To Go Next? ............................................................................ 1436
3. Architecture .................................................................................................... 1437
3.1. Registry .............................................................................................. 1437
3.2. Providers ............................................................................................. 1438
3.3. Loaders ............................................................................................... 1439
3.4. Manifests ............................................................................................ 1440
3.5. Clients ................................................................................................ 1442
4. Creating Providers to use with Zend_Tool_Framework ...................................... 1442
4.1. How Zend Tool finds your Providers ..................................................... 1443
4.2. Basic Instructions for Creating Providers ............................................... 1443
4.3. The response object ............................................................................ 1444
4.4. Advanced Development Information ...................................................... 1444
5. Shipped System Providers .............................................................................. 1447
5.1. The Version Provider ........................................................................... 1447
5.2. The Manifest Provider .......................................................................... 1447
6. Extending and Configuring Zend_Tool_Framework ........................................... 1447
6.1. Customizing Zend_Tool Console Client ................................................. 1447
Zend_Tool_Project ..................................................................................................... 1450
1. Introduction .................................................................................................... 1450
2. Créer un projet ............................................................................................... 1450
3. Fournisseurs de Zend_Tool_Project ................................................................ 1451
4. Rouages internes de Zend_Tool_Project ......................................................... 1451
4.1. Structure xml interne de Zend_Tool_Project .......................................... 1451
4.2. Etendre les rouages de Zend_Tool_Project ........................................... 1451
Zend_Translate .......................................................................................................... 1452
1. Introduction .................................................................................................... 1452

120
Guide de référence
Zend Framework

1.1. Démarrer avec le multi-linguisme .......................................................... 1452


2. Adaptateurs pour Zend_Translate ................................................................... 1453
2.1. Comment décider quel adaptateur de traduction utiliser ? ....................... 1454
2.2. Intégrer ses propres adaptateurs .......................................................... 1456
2.3. Améliorer les performances de tous les adaptateurs .............................. 1456
3. Utiliser les adaptateurs de traduction ............................................................... 1457
3.1. Structures des sources de traduction .................................................... 1458
3.2. Créer des fichiers sources de type tableau ............................................ 1460
3.3. Créer des fichiers sources Gettext ........................................................ 1461
3.4. Créer des fichiers source TMX ............................................................. 1462
3.5. Créer des fichiers source CSV ............................................................. 1462
3.6. Créer des fichiers sources INI .............................................................. 1463
3.7. Options pour les adaptateurs ............................................................... 1464
3.8. Gérer les langues ................................................................................ 1466
3.9. Détéction automatique de la source ...................................................... 1468
3.10. Vérifier les traductions ........................................................................ 1471
3.11. How to log not found translations ........................................................ 1472
3.12. Access to the source data .................................................................. 1473
4. Creating source files ....................................................................................... 1474
4.1. Creating Array source files ................................................................... 1474
4.2. Creating Gettext source files ................................................................ 1474
4.3. Creating TMX source files .................................................................... 1475
4.4. Creating CSV source files .................................................................... 1476
4.5. Creating INI source files ....................................................................... 1476
5. Additional features for translation .................................................................... 1477
5.1. Options for adapters ............................................................................ 1477
5.2. Handling languages ............................................................................. 1480
5.3. Automatic source detection .................................................................. 1482
5.4. Checking for translations ...................................................................... 1484
5.5. How to log not found translations ......................................................... 1485
5.6. Accessing source data ......................................................................... 1486
6. Notation des pluriels pour Translation .............................................................. 1487
6.1. Méthode traditionnelle .......................................................................... 1487
6.2. Méthode moderne de traduction du pluriel ............................................. 1487
6.3. Fichiers sources de pluriels .................................................................. 1488
6.4. Custom plural rules .............................................................................. 1489
Zend_Uri .................................................................................................................... 1491
1. Zend_Uri ........................................................................................................ 1491
1.1. Aperçu ................................................................................................ 1491
1.2. Créer un nouvel URI ............................................................................ 1491
1.3. Manipuler un URI existant .................................................................... 1491
1.4. Validation d'URI ................................................................................... 1492
1.5. Méthodes communes ........................................................................... 1492
Zend_Validate ............................................................................................................ 1494
1. Introduction .................................................................................................... 1494
1.1. Qu'est-ce qu'un validateur ? ................................................................. 1494
1.2. Utilisation basique des validateurs ........................................................ 1494
1.3. Messages personnalisés ...................................................................... 1495
1.4. Utilisation de la méthode statique is() ................................................ 1496
1.5. Translating messages .......................................................................... 1497
2. Classes de validation standard ........................................................................ 1498
2.1. Alnum ................................................................................................. 1498
2.2. Alpha .................................................................................................. 1498
2.3. Barcode .............................................................................................. 1498

121
Guide de référence
Zend Framework

2.4. Between .............................................................................................. 1498


2.5. Ccnum ................................................................................................ 1499
2.6. Date .................................................................................................... 1499
2.7. Db_RecordExists et Db_NoRecordExists .............................................. 1499
2.8. Digits .................................................................................................. 1501
2.9. EmailAddress ...................................................................................... 1501
2.10. Float ................................................................................................. 1503
2.11. GreaterThan ...................................................................................... 1503
2.12. Hex ................................................................................................... 1503
2.13. Hostname .......................................................................................... 1503
2.14. Iban .................................................................................................. 1505
2.15. InArray .............................................................................................. 1506
2.16. Int ..................................................................................................... 1506
2.17. Ip ...................................................................................................... 1506
2.18. LessThan .......................................................................................... 1506
2.19. NotEmpty .......................................................................................... 1506
2.20. Regex ............................................................................................... 1506
2.21. Validateurs de Sitemap ...................................................................... 1506
2.22. StringLength ...................................................................................... 1507
3. Chaînes de validation ..................................................................................... 1507
4. Écrire des validateurs ..................................................................................... 1508
5. Messages de validation .................................................................................. 1512
5.1. Limiter la taille d'un message de validation ............................................ 1517
Zend_Version ............................................................................................................. 1519
1. Lire la version de Zend Framework ................................................................. 1519
Zend_View ................................................................................................................. 1520
1. Introduction .................................................................................................... 1520
1.1. Script du Contrôleur ............................................................................. 1520
1.2. Script de vue ....................................................................................... 1520
1.3. Options ............................................................................................... 1521
1.4. Balises courtes dans les scripts de vue ................................................. 1521
1.5. Accesseurs utiles ................................................................................. 1522
2. Scripts de contrôleur ...................................................................................... 1523
2.1. Assigner des variables ......................................................................... 1523
2.2. Effectuer le rendu d'un script de vue ..................................................... 1524
2.3. Chemin des scripts de vue ................................................................... 1524
3. Scripts de vue ................................................................................................ 1525
3.1. Échapper la sortie ............................................................................... 1525
3.2. Utiliser des systèmes de gabarit (template) alternatifs ............................ 1526
4. Aides de vue ................................................................................................. 1532
4.1. Aides initiales ...................................................................................... 1532
4.2. Chemin des aides ............................................................................... 1584
4.3. Écrire des aides personnalisées ........................................................... 1585
4.4. Registering Concrete Helpers ............................................................... 1586
5. Zend_View_Abstract ....................................................................................... 1587
Zend_Wildfire ............................................................................................................. 1588
1. Zend_Wildfire ................................................................................................. 1588
Zend_XmlRpc ............................................................................................................ 1589
1. Introduction .................................................................................................... 1589
2. Zend_XmlRpc_Client ...................................................................................... 1589
2.1. Introduction ......................................................................................... 1589
2.2. Appels de méthodes ............................................................................ 1589
2.3. Types et conversions ........................................................................... 1590
2.4. Objet proxy du serveur ........................................................................ 1592

122
Guide de référence
Zend Framework

2.5. Gestion des erreurs ............................................................................. 1592


2.6. Introspection du serveur ....................................................................... 1593
2.7. De la requête à la réponse .................................................................. 1594
2.8. Client HTTP et tests ............................................................................ 1594
3. Zend_XmlRpc_Server ..................................................................................... 1594
3.1. Introduction ......................................................................................... 1594
3.2. Usage de base .................................................................................... 1594
3.3. Structures du serveur .......................................................................... 1595
3.4. Conventions ........................................................................................ 1595
3.5. Utiliser des espaces de noms (Namespaces) ........................................ 1596
3.6. Requêtes personnalisées ..................................................................... 1596
3.7. Réponses personnalisées .................................................................... 1596
3.8. Gérer les exceptions grâce aux erreurs (Faults) ..................................... 1597
3.9. Cacher la définition du serveur entre les requêtes .................................. 1597
3.10. Exemples d'utilisation ......................................................................... 1598
ZendX_Console_Process_Unix ................................................................................... 1602
1. ZendX_Console_Process_Unix ....................................................................... 1602
1.1. Introduction ......................................................................................... 1602
1.2. Basic usage of ZendX_Console_Process_Unix ...................................... 1602
ZendX_JQuery ........................................................................................................... 1604
1. Introduction .................................................................................................... 1604
2. ZendX_JQuery View Helpers .......................................................................... 1604
2.1. jQuery() View Helper ........................................................................... 1604
2.2. JQuery Helpers ................................................................................... 1610
3. ZendX_JQuery Form Elements and Decorators ................................................ 1616
3.1. General Elements and Decorator Usage ............................................... 1616
3.2. Form Elements .................................................................................... 1617
3.3. Form Decorators ................................................................................. 1617

123
Zend_Acl
1. Introduction
Zend_Acl fournit une implémentation légère et flexible de listes de contrôle d'accès (ACL) pour
la gestion de privilèges. En général, une application peut utiliser ces ACL pour contrôler l'accès
à certains objets par d'autres objets demandeurs.

Dans le cadre de cette documentation :

• une ressource est un objet dont l'accès est contrôlé,

• un rôle est un objet qui peut demander l'accès à une ressource.

Dit simplement, les rôles demandent l'accès à des ressources. Par exemple, si une personne
demande l'accès à une voiture, alors la personne est le rôle demandeur et la voiture est la
ressource, puisque l'accès à la voiture est soumis à un contrôle.

Grâce à la définition et à la mise en oeuvre d'une ACL, une application peut contrôler comment
les objets demandeurs (rôles) reçoivent l'accès (ou non) à des objets protégés (ressources).

1.1. A propos des ressources


Avec Zend_Acl, créer une ressource est très simple. Zend_Acl fournit
Zend_Acl_Resource_Interface pour faciliter la tâche aux développeurs. Une classe
a simplement besoin d'implémenter cette interface, qui consiste en une seule méthode,
getResourceId(), pour que Zend_Acl reconnaît l'objet comme étant une ressource. Par
ailleurs, Zend_Acl_Resource est fourni par Zend_Acl comme une implémentation basique
de ressource que les développeurs peuvent étendre si besoin.

Zend_Acl fournit une structure en arbre à laquelle plusieurs ressources (ou "zone sous contrôle
d'accès") peuvent être ajoutées. Puisque les ressources sont sauvées dans cet arbre, elles
peuvent être organisées du général (via la racine de l'arbre) jusqu'au particulier (via les feuilles
de l'arbre). Les requêtes envers une ressource spécifique vont automatiquement entraîner la
recherche de règles sur ses parents au sein de la structure hiérarchique des ressources, ce qui
permet un héritage simple des règles. Par exemple, si une règle par défaut doit être appliquée
à tous les bâtiments d'une ville, on pourra simplement assigner la règle à la ville elle-même, au
lieu de la répéter à tous les bâtiments. Mais certains bâtiments peuvent nécessiter des règles
spécifiques, et ceci peut se faire aisément avec Zend_Acl en assignant les règles nécessaires
à chaque bâtiment de la ville qui nécessite une exception. Une ressource peut hériter d'un seul
parent ressource, qui hérite lui même de son propre parent, et ainsi de suite.

Zend_Acl supporte aussi des privilèges pour chaque ressource (par exemple : "créer", "lire",
"modifier", "supprimer"), et le développeur peut assigner des règles qui affectent tous les
privilèges ou seuls certains privilèges d'une ressource.

1.2. A propos des rôles


Comme pour les ressources, créer un rôle est très simple. Tout rôle doit implémenter
Zend_Acl_Role_Interface qui consiste en une seule méthode getRoleId(). De plus,
Zend_Acl_Role est inclus dans Zend_Acl comme une implémentation basique de rôle que
les développeurs peuvent étendre si besoin.

Dans Zend_Acl, un rôle peut hériter de un ou plusieurs rôles. Ceci permet de supporter
l'héritage de règles à travers plusieurs rôles. Par exemple, un rôle utilisateur, comme "Éric", peut

124
Zend_Acl

appartenir à un ou plusieurs rôles d'action, tels que "éditeur" ou "administrateur". Le développeur


peut créer des règles pour "éditeur" et "administrateur" séparément, et "Éric" va hériter des règles
des deux sans avoir à définir des règles directement pour "Éric".

Bien que la possibilité d'hériter de plusieurs rôles soit très utile, l'héritage multiple introduit aussi
un certain degré de complexité. L'exemple ci-dessous illustre l'ambiguïté et la manière dont
Zend_Acl la résout.

Exemple 28. Héritages multiples entre rôles

Le code ci-dessous définit trois rôles de base - "guest", "member", et "admin" - desquels
d'autres rôles peuvent hériter. Ensuite, un rôle identifié par "someUser" est créé et hérite des
trois autres rôles. L'ordre selon lequel ces rôles apparaissent dans le tableau $parents est
important. Lorsque cela est nécessaire Zend_Acl recherche les règles d'accès définies non
seulement pour le rôle demandé (ici "someUser"), mais aussi pour les autres rôles desquels
le rôle recherché hérite (ici "guest", "member", et "admin") :

$acl = new Zend_Acl();

$acl->addRole(new Zend_Acl_Role('guest'))
->addRole(new Zend_Acl_Role('member'))
->addRole(new Zend_Acl_Role('admin'));

$parents = array('guest', 'member', 'admin');


$acl->addRole(new Zend_Acl_Role('someUser'), $parents);

$acl->add(new Zend_Acl_Resource('someResource'));

$acl->deny('invite', 'someResource');
$acl->allow('membre', 'someResource');

echo $acl->isAllowed('someUser', 'someResource') ? 'autorisé' : 'refusé';

Puisqu'il n'y a pas de règle spécifiquement définie pour le rôle "someUser" et


"someResource", Zend_Acl doit rechercher des règles qui pourraient être définies pour
des rôles dont "someUser" hérite. Premièrement, le rôle "admin" est contrôlé, et il n'y a pas
de règle d'accès définie pour lui. Ensuite, le rôle "member" est visité, et Zend_Acl trouve
qu'il y a une règle qui spécifie que "member" a un accès autorisé à "someResource".

Si Zend_Acl continuait à examiner toutes les règles de tous les rôles parents, il trouverait
que "someResource" est interdit d'accès à "someResource". Ceci introduit une ambiguïté
puisque maintenant "someUser" est à la fois autorisé et interdit d'accès à "someResource",
puisqu'il hérite de règles opposées de ses différents parents.

Zend_Acl résout cette ambiguïté en arrêtant la recherche de règles d'accès dès qu'une
première règle est découverte. Dans notre exemple, puisque le rôle "member" est examiné
avant le rôle "guest", le résultat devrait afficher "autorisé".

Lorsque vous spécifiez plusieurs parents pour un rôle, conservez à l'esprit


que le dernier parent listé est le premier dans lequel une règle utilisable sera
recherchée.

1.3. Créer la Liste de Contrôle d'Accès


Une ACL peut représenter n'importe quel ensemble d'objets physiques ou virtuels que vous
souhaitez. Pour les besoins de la démonstration, nous allons créer un système basique d'ACL

125
Zend_Acl

pour une Gestion de Contenus (CMS) qui comporte plusieurs niveaux de groupes au sein d'une
grande variété de zones. Pour créer un nouvel objet ACL, nous créons une nouvelle instance
d'ACL sans paramètres :

$acl = new Zend_Acl();

Jusqu'à ce que le développeur spécifie une règle "allow", Zend_Acl refuse


l'accès pour tous les privilèges sur chaque ressource pour chaque rôle.

1.4. Registre des rôles


Les systèmes de gestion de contenu (ou CMS) vont pratiquement toujours nécessiter une
hiérarchie de permissions afin de déterminer les droits de rédaction de ses utilisateurs. Il pourrait
y avoir un groupe "Invités" qui donne accès aux démonstrations, un groupe "Staff" pour la
majorité des utilisateurs du CMS qui réalisent la plupart du travail quotidien, un groupe "Éditeur"
pour ceux qui sont responsables de la publication, l'archivage, la relecture et la suppression, et
enfin un groupe "Administrateur" dont les tâches incluent toutes les tâches des autres groupes
plus des tâches de maintenance, de gestion des utilisateurs, configuration et backup ou export.
Cet ensemble de permissions peut être représenté dans un registre de rôles, permettant à
chaque groupe d'hériter des privilèges des groupes "parents". Les permissions peuvent être
rendues de la manière suivante :

Tableau 1. Contrôles d'Accès pour un exemple de CMS

Nom Permissions Permissions héritées de


Invité Voir N/A
Staff Modifier, Soumettre, Relire Invité
Éditeur Publier, Archiver, Supprimer Staff
Administrateur (Reçoit tous les accès) N/A

Pour cet exemple, Zend_Acl_Role est utilisé, mais n'importe quel objet qui implémente
Zend_Acl_Role_Interface est acceptable. Ces groupes peuvent être ajoutés au registre
des rôles comme suit :

$acl = new Zend_Acl();

// Ajoute des groupes au registre des rôles en utilisant Zend_Acl_Role

// Invité n'hérite d'aucun accès


$roleinvite = new Zend_Acl_Role('invite');
$acl->addRole($roleinvite);

// Staff hérite de Invité


$acl->addRole(new Zend_Acl_Role('staff'), $roleinvite);

// Ce que précède pourrait aussi être écrit:


// $acl->addRole(new Zend_Acl_Role('staff'), 'invite');

// Editeur hérite de staff


$acl->addRole(new Zend_Acl_Role('editeur'), 'staff');

// Administrateur n'hérite pas d'accès

126
Zend_Acl

$acl->addRole(new Zend_Acl_Role('administrateur'));

1.5. Définir les Contrôles d'Accès


Maintenant que l'ACL contient les rôles nécessaires, on peut établir des règles qui définissent
comment les ressources accèdent aux rôles. Vous avez sans doute noté que nous n'avons défini
aucune ressource particulière pour cet exemple, ce qui est plus simple pour illustrer comment les
règles s'appliquent à toutes les ressources. Zend_Acl fournit une implémentation dans laquelle
les règles doivent simplement être assignées du général au particulier, ce qui réduit le nombre
de règles spécifiques à ajouter. Ceci grâce à l'héritage.

Généralement Zend_Acl se conforme à une règle donnée si et seulement si


une règle plus spécifique ne s'applique pas.

En conséquence, on peut définir un nombre assez complexe de règles avec un nombre minimal
de code. Pour définir les permissions comme définies ci-dessus :

$acl = new Zend_Acl();

$roleinvite = new Zend_Acl_Role('invité');


$acl->addRole($roleinvite);
$acl->addRole(new Zend_Acl_Role('staff'), $roleinvite);
$acl->addRole(new Zend_Acl_Role('editeur'), 'staff');
$acl->addRole(new Zend_Acl_Role('administrateur'));

// Invité peut uniquement voir le contenu


$acl->allow($roleinvite, null, 'voir');

/*
ce qui précède peut aussi être écrit :
$acl->allow('invité', null, 'voir');
*/

// Staff hérite des privilèges de Invité, mais a aussi ses propres


// privilèges
$acl->allow('staff', null, array('edit', 'submit', 'relire'));

// Editeur hérite les privilèges voir, modifier, soumettre,


// et relire de Staff, mais a aussi besoin de certains privilèges
$acl->allow('editeur', null, array('publier', 'archiver', 'supprimer'));

// Administrateur hérite de rien, mais reçoit tous les privilèges


$acl->allow('administrateur');

Les valeurs NULL dans les appels allow() ci-dessus sont utilisées pour indiquer que les règles
s'appliquent à toutes les ressources.

1.6. Interroger les ACL


Nous avons maintenant une ACL flexible, qui peut être utilisée pour déterminer si l'objet appelant
a les permissions pour réaliser les fonctions au sein de l'application web. Interroger cette liste
est assez simple en utilisant la méthode isAllowed() :

echo $acl->isAllowed('invité', null, 'voir') ?


"autorisé" : "refusé";
// autorisé

127
Zend_Acl

echo $acl->isAllowed('staff', null, 'publier') ?


"autorisé" : "refusé";
// refusé

echo $acl->isAllowed('staff', null, 'relire') ?


"autorisé" : "refusé";
// autorisé

echo $acl->isAllowed('editeur', null, 'voir') ?


"autorisé" : "refusé";
// autorisé parce que hérité de Invité

echo $acl->isAllowed('editeur', null, 'modifier') ?


"autorisé" : "refusé";
// refusé parce qu'il n'y a pas de règle pour 'modifier'

echo $acl->isAllowed('administrateur', null, 'voir') ?


"autorisé" : "refusé";
// autorisé car administrateur est autorisé pour tout

echo $acl->isAllowed('administrateur') ?
"autorisé" : "refusé";
// autorisé car administrateur est autorisé pour tout

echo $acl->isAllowed('administrateur', null, 'modifier') ?


"autorisé" : "refusé";
// autorisé car administrateur est autorisé pour tout

2. Affiner les Contrôles d'Accès


2.1. Mieux définir les Contrôles d'Accès
L'ACL basique définie dans le chapitre précédentmontre comment plusieurs privilèges peuvent
être alloués pour l'ensemble de l'ACL (toutes les ressources). En pratique, toutefois, les contrôles
d'accès ont souvent des exceptions et des degrés de complexité variables. Zend_Acl permet
d'atteindre ce degré de finesse d'une manière directe et flexible.

Pour l'exemple du CMS, nous avons déterminé que bien que le groupe "Staff" couvre les besoins
de la plupart des utilisateurs, un groupe "Marketing" est nécessaire. Ce groupe doit avoir accès à
la newsletter et aux dernières news dans le CMS. Le groupe va recevoir la possibilité de publier
et d'archiver à la fois des newsletters et des news.

De plus, il a été demandé que le groupe "Staff" puisse voir les nouveaux textes, mais
pas les nouvelles news. Enfin, il devrait être impossible pour tout le monde (y compris les
administrateurs) d'archiver un contenu qui n'aurait une durée de vie que de 1 ou 2 jours.

En premier lieu, nous modifions le registre des rôles pour refléter ces changements. Nous avons
dit que le groupe "Marketing" a les même permissions de base que "Staff". Donc nous créons
"marketing" pour qu'il hérite des permissions de "staff".

// Le nouveau groupe Marketing hérite des permissions de Staff


$acl->addRole(new Zend_Acl_Role('marketing'), 'staff');

Ensuite, notez que les contrôles d'accès plus haut font référence à des ressources (ex.
"newsletters", "dernières news", "annonces"). Maintenant, nous ajoutons ces Ressources :

128
Zend_Acl

// Créer les Ressources pour les règles

// newsletter
$acl->addResource(new Zend_Acl_Resource('newsletter'));

// news
$acl->addResource(new Zend_Acl_Resource('news'));

// dernières news
$acl->addResource(new Zend_Acl_Resource('latest'), 'news');

// annonces
$acl->addResource(new Zend_Acl_Resource('announcement'), 'news');

Ensuite c'est simplement une manière de définir ces règles spécifiques sur les parties cibles de
l'ACL :

// Le Marketing doit être capable de publier


// et d'archiver les newsletters et les dernières news
$acl->allow('marketing',
array('newsletter', 'latest'),
array('publish', 'archive'));

// Staff (et marketing, par héritage),


// n'ont pas la permission de relire les dernières news
$acl->deny('staff', 'latest', 'relire');

// Personne (y compris les administrateurs)


// n'a la permission d'archiver des annonces
$acl->deny(null, 'annonce', 'archive');

On peut maintenant interroger les ACL sur base des dernières modifications :

echo $acl->isAllowed('staff', 'newsletter', 'publish') ?


"autorisé" : "refusé"; // refusé

echo $acl->isAllowed('marketing', 'newsletter', 'publish') ?


"autorisé" : "refusé"; // autorisé

echo $acl->isAllowed('staff', 'latest', 'publish') ?


"autorisé" : "refusé"; // refusé

echo $acl->isAllowed('marketing', 'latest', 'publish') ?


"autorisé" : "refusé"; // autorisé

echo $acl->isAllowed('marketing', 'latest', 'archive') ?


"autorisé" : "refusé"; // autorisé

echo $acl->isAllowed('marketing', 'latest', 'revise') ?


"autorisé" : "refusé"; // refusé

echo $acl->isAllowed('editor', 'announcement', 'archive') ?


"autorisé" : "refusé"; // refusé

echo $acl->isAllowed('administrator', 'announcement', 'archive') ?


"autorisé" : "refusé"; // refusé

129
Zend_Acl

2.2. Retirer les Contrôles d'Accès


Pour retirer une ou plusieurs règles des ACL, utilisez simplement la méthode removeAllow()
ou removeDeny(). Comme pour allow() et deny(), vous pouvez utiliser une valeur NULL
pour indiquer que la méthode s'applique à tous les rôles, ressources et / ou privilèges.

// Retire l'interdiction de relire les dernières news au Staff


// (et au marketing, par héritage)
$acl->removeDeny('staff', 'latest', 'relire');

echo $acl->isAllowed('marketing', 'latest', 'relire') ?


"autorisé" : "refusé"; // autorisé

// Retire l'autorisation de publier


// et archiver les newsletters au Marketing
$acl->removeAllow('marketing',
'newsletter',
array('publish', 'archive'));

echo $acl->isAllowed('marketing', 'newsletter', 'publish') ?


"autorisé" : "refusé"; // refusé

echo $acl->isAllowed('marketing', 'newsletter', 'archive') ?


"autorisé" : "refusé"; // refusé

Les privilèges peuvent être modifiés de manière incrémentielle comme indiqué au dessus, mais
une valeur NULL pour les privilèges écrase ces modifications incrémentielles.

// donne au groupe Marketing toutes les permissions


// sur les dernières nouvelles
$acl->allow('marketing', 'latest');

echo $acl->isAllowed('marketing', 'latest', 'publish') ?


"autorisé" : "refusé"; // autorisé

echo $acl->isAllowed('marketing', 'latest', 'archive') ?


"autorisé" : "refusé"; // autorisé

echo $acl->isAllowed('marketing', 'latest', 'anything') ?


"autorisé" : "refusé"; // autorisé

3. Utilisation avancée
3.1. Rendre les données ACL persistantes
Zend_Acl a été conçu pour ne pas nécessiter de technologie spécifique comme une base
de données ou un serveur de cache pour conserver les données ACL. Son implémentation
PHP permet de créer des outils d'administration basés sur Zend_Acl assez facilement. De
nombreuses situations nécessitent une certaine forme de maintenance ou de gestion des ACL,
et Zend_Acl fournit les méthodes pour définir et interroger les règles d'accès d'une application.

Le stockage des données ACL est dès lors laissé aux bons soins du développeur, dans la mesure
où les cas d'utilisation peuvent grandement varier d'un cas à l'autre. Puisque Zend_Acl est
sérialisable, les objets ACL peuvent être sérialisés avec la fonction serialize() de PHP, et le
résultat peut être stocké n'importe où le développeur le désire : fichier, base de donnée, cache.

130
Zend_Acl

3.2. Écrire des règles ACL conditionnelles avec des assertions


Parfois, une règle pour autoriser ou interdire l'accès d'un rôle à une ressource n'est pas absolu,
mais dépend de plusieurs critères. Par exemple, supposons qu'un certain accès peut être
autorisé, mais uniquement entre 8h du matin et 5h du soir. Un autre exemple consisterait à
interdire l'accès parce que la requête provient d'une adresse IP qui est notée comme source
d'abus. Zend_Acl dispose d'un support intégré pour implémenter des règles sur quoique ce soit
dont le développeur ait besoin.

Zend_Acl fourni le support pour les règles conditionnelles via


Zend_Acl_Assert_Interface. Pour mettre en oeuvre cette interface, il suffit d'implémenter
la méthode assert() :

class CleanIPAssertion implements Zend_Acl_Assert_Interface


{
public function assert(Zend_Acl $acl,
Zend_Acl_Role_Interface $role = null,
Zend_Acl_Resource_Interface $resource = null,
$privilege = null)
{
return $this->_isCleanIP($_SERVER['REMOTE_ADDR']);
}

protected function _isCleanIP($ip)


{
//...
}
}

Lorsqu'une classe d'assertion est disponible, le développeur doit fournir une instance de cette
classe lorsqu'il assigne une règle conditionnelle. Une règle qui est créée avec une assertion
s'applique uniquement dans les cas où l'assertion retourne une valeur TRUE.

$acl = new Zend_Acl();


$acl->allow(null, null, null, new CleanIPAssertion());

Le code ci-dessus crée une règle conditionnelle qui autorise l'accès à tous les privilèges, sur
tout et pour tout le monde, sauf lorsque l'adresse IP de la requête fait partie de la liste noire.
Si une requête provient d'une adresse IP qui n'est pas considérée comme "propre", alors la
règle d'autorisation ne s'applique pas. Puisque la règle s'applique à tous les rôles, toutes les
Ressources, et tous les privilèges, une IP "sale" aboutira à un refus d'accès. Ceci constitue un
cas spécial, et il faut bien noter que tous les autres cas (donc, si un rôle, une ressource ou un
privilège est défini pour la règle), une assertion qui échoue aboutit à une règle qui ne s'applique
pas et ce sont alors les autres règles qui servent à déterminer si l'accès est autorisé ou non.

La méthode assert() d'un objet d'assertion reçoit l'ACL, le rôle, la ressource et le privilège
auquel une requête d'autorisation (c.-à-d., isAllowed()) s'applique, afin de fournir un contexte
à la classe d'assertion pour déterminer ses conditions lorsque cela est nécessaire.

131
Zend_Amf
1. Introduction
Zend_Amf fournit le support pour l' Action Message Format(AMF) d'Adobe, permettant la
communication entre le Flash Playerd'Adobe et PHP. De manière spécifique, il fournit une
implémentation serveur pour gérer les requêtes envoyées par le Flash Player au serveur et fait
correspondre ces requêtes à des objets, à des méthodes de classe et à des callbacks arbitraires.

La spécification AMF3est librement disponible, et sert de référence pour les types de messages
qui peuvent être envoyés entre le Flash Player et le serveur.

2. Zend_Amf_Server
Zend_Amf_Server provides an RPC-style server for handling requests made from the Adobe
Flash Player using the AMF protocol. Like all Zend Framework server classes, it follows the
SoapServer API, providing an easy to remember interface for creating servers.

132
Zend_Amf

Exemple 29. Basic AMF Server

Let's assume that you have created a class Foo with a variety of public methods. You may
create an AMF server using the following code:

$server = new Zend_Amf_Server();


$server->setClass('Foo');
$response = $server->handle();
echo $response;

Alternately, you may choose to attach a simple function as a callback instead:

$server = new Zend_Amf_Server();


$server->addFunction('myUberCoolFunction');
$response = $server->handle();
echo $response;

You could also mix and match multiple classes and functions. When doing so, we suggest
namespacing each to ensure that no method name collisions occur; this can be done by
simply passing a second string argument to either addFunction() or setClass():

$server = new Zend_Amf_Server();


$server->addFunction('myUberCoolFunction', 'my')
->setClass('Foo', 'foo')
->setClass('Bar', 'bar');
$response = $server->handle();
echo $response;

The Zend_Amf_Server also allows services to be dynamically loaded based on a supplied


directory path. You may add as many directories as you wish to the server. The order
that you add the directories to the server will be the order that the LIFO search will be
performed on the directories to match the class. Adding directories is completed with the
addDirectory() method.

$server->addDirectory(dirname(__FILE__) .'/../services/');
$server->addDirectory(dirname(__FILE__) .'/../package/');

When calling remote services your source name can have underscore ("_") and dot (".")
directory delimiters. When an underscore is used PEAR and Zend Framework class naming
conventions will be respected. This means that if you call the service com_Foo_Bar the
server will look for the file Bar.php in the each of the included paths at com/Foo/Bar.php.
If the dot notation is used for your remote service such as com.Foo.Bar each included
path will have com/Foo/Bar.php append to the end to autoload Bar.php

All AMF requests sent to the script will then be handled by the server, and an AMF response
will be returned.

All Attached Methods and Functions Need Docblocks


Like all other server components in Zend Framework, you must document your
class methods using PHP docblocks. At the minimum, you need to provide
annotations for each required argument as well as the return value. As examples:

// Function to attach:

/**

133
Zend_Amf

* @param string $name


* @param string $greeting
* @return string
*/
function helloWorld($name, $greeting = 'Hello')
{
return $greeting . ', ' . $name;
}

// Attached class

class World
{
/**
* @param string $name
* @param string $greeting
* @return string
*/
public function hello($name, $greeting = 'Hello')
{
return $greeting . ', ' . $name;
}
}

Other annotations may be used, but will be ignored.

2.1. Connecting to the Server from Flex


Connecting to your Zend_Amf_Server from your Flex project is quite simple; you simply need
to point your endpoint URI to your Zend_Amf_Server script.

Say, for instance, you have created your server and placed it in the server.php file in your
application root, and thus the URI is http://example.com/server.php. In this case, you
would modify your services-config.xml file to set the channel endpoint uri attribute to this
value.

If you have never created a service-config.xml file you can do so by opening your project
in your Navigator window. Right click on the project name and select 'properties'. In the Project
properties dialog go into 'Flex Build Path' menu, 'Library path' tab and be sure the 'rpc.swc' file
is added to your projects path and Press Ok to close the window.

You will also need to tell the compiler to use the service-config.xml to find the
RemoteObject endpoint. To do this open your project properties panel again by right clicking
on the project folder from your Navigator and selecting properties. From the properties popup
select 'Flex Compiler' and add the string: -services "services-config.xml". Press Apply then
OK to return to update the option. What you have just done is told the Flex compiler to look to the
services-config.xml file for runtime variables that will be used by the RemotingObject class.

We now need to tell Flex which services configuration file to use for connecting to our remote
methods. For this reason create a new 'services-config.xml' file into your Flex project src
folder. To do this right click on the project folder and select 'new' 'File' which will popup a new
window. Select the project folder and then name the file 'services-config.xml' and press
finish.

Flex has created the new services-config.xml and has it open. Use the following example
text for your services-config.xml file. Make sure that you update your endpoint to match
that of your testing server. Make sure you save the file.

134
Zend_Amf

<?xml version="1.0" encoding="UTF-8"?>


<services-config>
<services>
<service id="zend-service"
class="flex.messaging.services.RemotingService"
messageTypes="flex.messaging.messages.RemotingMessage">
<destination id="zend">
<channels>
<channel ref="zend-endpoint"/>
</channels>
<properties>
<source>*</source>
</properties>
</destination>
</service>
</services>
<channels>
<channel-definition id="zend-endpoint"
class="mx.messaging.channels.AMFChannel">
<endpoint uri="http://example.com/server.php"
class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
</channels>
</services-config>

There are two key points in the example. First, but last in the listing, we create an AMF channel,
and specify the endpoint as the URL to our Zend_Amf_Server:

<channel-definition id="zend-endpoint"
<endpoint uri="http://example.com/server.php"
class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>

Notice that we've given this channel an identifier, "zend-endpoint". The example create a service
destination that refers to this channel, assigning it an ID as well -- in this case "zend".

Within our Flex MXML files, we need to bind a RemoteObject to the service. In MXML, this might
be done as follows:

<mx:RemoteObject id="myservice"
fault="faultHandler(event)"
showBusyCursor="true"
destination="zend">

Here, we've defined a new remote object identified by "myservice" bound to the service
destination "zend" we defined in the services-config.xml file. We then call methods on it
in our ActionScript by simply calling "myservice.<method>". As an example:

myservice.hello("Wade");

When namespacing, you would use "myservice.<namespace>.<method>":

myservice.world.hello("Wade");

For more information on Flex RemoteObject invocation, visit the Adobe Flex 3 Help site.

135
Zend_Amf

2.2. Error Handling


By default, all exceptions thrown in your attached classes or functions will be caught and returned
as AMF ErrorMessages. However, the content of these ErrorMessage objects will vary based on
whether or not the server is in "production" mode (the default state).

When in production mode, only the exception code will be returned. If you disable production
mode -- something that should be done for testing only -- most exception details will be returned:
the exception message, line, and backtrace will all be attached.

To disable production mode, do the following:

$server->setProduction(false);

To re-enable it, pass a TRUE boolean value instead:

$server->setProduction(true);

Disable production mode sparingly!


We recommend disabling production mode only when in development. Exception
messages and backtraces can contain sensitive system information that you may
not wish for outside parties to access. Even though AMF is a binary format,
the specification is now open, meaning anybody can potentially deserialize the
payload.

One area to be especially careful with is PHP errors themselves. When the display_errors INI
directive is enabled, any PHP errors for the current error reporting level are rendered directly
in the output -- potentially disrupting the AMF response payload. We suggest turning off the
display_errors directive in production to prevent such problems

2.3. AMF Responses


Occasionally you may desire to manipulate the response object slightly, typically to return extra
message headers. The handle() method of the server returns the response object, allowing
you to do so.

Exemple 30. Adding Message Headers to the AMF Response

In this example, we add a 'foo' MessageHeader with the value 'bar' to the response prior
to returning it.

$response = $server->handle();
$response->addAmfHeader(new Zend_Amf_Value_MessageHeader('foo', true, 'bar'))
echo $response;

2.4. Typed Objects


Similar to SOAP, AMF allows passing objects between the client and server. This allows a great
amount of flexibility and coherence between the two environments.

Zend_Amf provides three methods for mapping ActionScript and PHP objects.

• First, you may create explicit bindings at the server level, using the setClassMap() method.
The first argument is the ActionScript class name, the second the PHP class name it maps to:

136
Zend_Amf

// Map the ActionScript class 'ContactVO' to the PHP class 'Contact':


$server->setClassMap('ContactVO', 'Contact');

• Second, you can set the public property $_explicitType in your PHP class, with the value
representing the ActionScript class to map to:

class Contact
{
public $_explicitType = 'ContactVO';
}

• Third, in a similar vein, you may define the public method getASClassName() in your PHP
class; this method should return the appropriate ActionScript class:

class Contact
{
public function getASClassName()
{
return 'ContactVO';
}
}

Although we have created the ContactVO on the server we now need to make its corresponding
class in AS3 for the server object to be mapped to.

Right click on the src folder of the Flex project and select New -> ActionScript File. Name the
file ContactVO and press finish to see the new file. Copy the following code into the file to finish
creating the class.

package
{
[Bindable]
[RemoteClass(alias="ContactVO")]
public class ContactVO
{
public var id:int;
public var firstname:String;
public var lastname:String;
public var email:String;
public var mobile:String;
public function ProductVO():void {
}
}
}

The class is syntactically equivalent to the PHP of the same name. The variable names are
exactly the same and need to be in the same case to work properly. There are two unique AS3
meta tags in this class. The first is bindable which makes fire a change event when it is updated.
The second tag is the RemoteClass tag which defines that this class can have a remote object
mapped with the alias name in this case ContactVO. It is mandatory that this tag the value that
was set is the PHP class are strictly equivalent.

[Bindable]
private var myContact:ContactVO;

private function getContactHandler(event:ResultEvent):void {

137
Zend_Amf

myContact = ContactVO(event.result);
}

The following result event from the service call is cast instantly onto the Flex ContactVO. Anything
that is bound to myContact will be updated with the returned ContactVO data.

2.5. Resources
Zend_Amf provides tools for mapping resource types returned by service classes into data
consumable by ActionScript.

In order to handle specific resource type, the user needs to create a plugin class named after the
resource name, with words capitalized and spaces removed (so, resource type "mysql result"
becomes MysqlResult), with some prefix, e.g. My_MysqlResult. This class should implement
one method, parse(), receiving one argument - the resource - and returning the value that
should be sent to ActionScript. The class should be located in the file named after the last
component of the name, e.g. MysqlResult.php.

The directory containing the resource handling plugins should be registered with Zend_Amf type
loader:

Zend_Amf_Parse_TypeLoader::addResourceDirectory(
"My",
"application/library/resources/My"
);

For detailed discussion of loading plugins, please see the plugin loader section.

Default directory for Zend_Amf resources is registered automatically and currently contains
handlers for "mysql result" and "stream" resources.

// Example class implementing handling resources of type mysql result


class Zend_Amf_Parse_Resource_MysqlResult
{
/**
* Parse resource into array
*
* @param resource $resource
* @return array
*/
public function parse($resource) {
$result = array();
while($row = mysql_fetch_assoc($resource)) {
$result[] = $row;
}
return $result;
}
}

Trying to return unknown resource type (i.e., one for which no handler plugin exists) will result
in an exception.

2.6. Connecting to the Server from Flash


Connecting to your Zend_Amf_Server from your Flash project is slightly different than from
Flex. However once the connection Flash functions with Zend_Amf_Server the same way is

138
Zend_Amf

flex. The following example can also be used from a Flex AS3 file. We will reuse the same
Zend_Amf_Server configuration along with the World class for our connection.

Open Flash CS and create and new Flash File (ActionScript 3). Name the document
ZendExample.fla and save the document into a folder that you will use for this example.
Create a new AS3 file in the same directory and call the file Main.as. Have both files open in your
editor. We are now going to connect the two files via the document class. Select ZendExample
and click on the stage. From the stage properties panel change the Document class to Main. This
links the Main.as ActionScript file with the user interface in ZendExample.fla. When you run
the Flash file ZendExample the Main.as class will now be run. Next we will add ActionScript
to make the AMF call.

We now are going to make a Main class so that we can send the data to the server and display
the result. Copy the following code into your Main.as file and then we will walk through the code
to describe what each element's role is.

package {
import flash.display.MovieClip;
import flash.events.*;
import flash.net.NetConnection;
import flash.net.Responder;

public class Main extends MovieClip {


private var gateway:String = "http://example.com/server.php";
private var connection:NetConnection;
private var responder:Responder;

public function Main() {


responder = new Responder(onResult, onFault);
connection = new NetConnection;
connection.connect(gateway);
}

public function onComplete( e:Event ):void{


var params = "Sent to Server";
connection.call("World.hello", responder, params);
}

private function onResult(result:Object):void {


// Display the returned data
trace(String(result));
}
private function onFault(fault:Object):void {
trace(String(fault.description));
}
}
}

We first need to import two ActionScript libraries that perform the bulk of the work. The first
is NetConnection which acts like a by directional pipe between the client and the server. The
second is a Responder object which handles the return values from the server related to the
success or failure of the call.

import flash.net.NetConnection;
import flash.net.Responder;

In the class we need three variables to represent the NetConnection, Responder, and the
gateway URL to our Zend_Amf_Server installation.

139
Zend_Amf

private var gateway:String = "http://example.com/server.php";


private var connection:NetConnection;
private var responder:Responder;

In the Main constructor we create a responder and a new connection to the Zend_Amf_Server
endpoint. The responder defines two different methods for handling the response from the server.
For simplicity I have called these onResult and onFault.

responder = new Responder(onResult, onFault);


connection = new NetConnection;
connection.connect(gateway);

In the onComplete function which is run as soon as the construct has completed we send the
data to the server. We need to add one more line that makes a call to the Zend_Amf_Server
World->hello function.

connection.call("World.hello", responder, params);

When we created the responder variable we defined an onResult and onFault function to handle
the response from the server. We added this function for the successful result from the server.
A successful event handler is run every time the connection is handled properly to the server.

private function onResult(result:Object):void {


// Display the returned data
trace(String(result));
}

The onFault function, is called if there was an invalid response from the server. This happens
when there is an error on the server, the URL to the server is invalid, the remote service or
method does not exist, and any other connection related issues.

private function onFault(fault:Object):void {


trace(String(fault.description));
}

Adding in the ActionScript to make the remoting connection is now complete. Running the
ZendExample file now makes a connection to Zend Amf. In review you have added the required
variables to open a connection to the remote server, defined what methods should be used when
your application receives a response from the server, and finally displayed the returned data to
output via trace().

2.7. Authentication
Zend_Amf_Server allows you to specify authentication and authorization hooks to control
access to the services. It is using the infrastructure provided by Zend_Auth and Zend_Acl
components.

In order to define authentication, the user provides authentication adapter extening


Zend_Amf_Auth_Abstract abstract class. The adapter should implement the
authenticate() method just like regular authentication adapter.

The adapter should use properties _username and _password from the parent
Zend_Amf_Auth_Abstract class in order to authenticate. These values are set by the server
using setCredentials() method before call to authenticate() if the credentials are
received in the AMF request headers.

140
Zend_Amf

The identity returned by the adapter should be an object containing property role for the ACL
access control to work.

If the authentication result is not successful, the request is not proceseed further and failure
message is returned with the reasons for failure taken from the result.

The adapter is connected to the server using setAuth() method:

$server->setAuth(new My_Amf_Auth());

Access control is performed by using Zend_Acl object set by setAcl() method:

$acl = new Zend_Acl();


createPermissions($acl); // create permission structure
$server->setAcl($acl);

If the ACL object is set, and the class being called defines initAcl() method, this method will
be called with the ACL object as an argument. The class then can create additional ACL rules
and return TRUE, or return FALSE if no access control is required for this class.

After ACL have been set up, the server will check if access is allowed with role set by the
authentication, resource being the class name (or NULL for function calls) and privilege being
the function name. If no authentication was provided, then if the anonymous role was defined,
it will be used, otherwise the access will be denied.

if($this->_acl->isAllowed($role, $class, $function)) {


return true;
} else {
require_once 'Zend/Amf/Server/Exception.php';
throw new Zend_Amf_Server_Exception("Access not allowed");
}

141
Zend_Application
1. Introduction
Zend_Application propose une interface de lancement (bootstrap) pour vos applications,
permettant la réutilisabilité des ressources utilisées, la vérification de dépendances et des
classes de bootstrap basées sur des modules. Ce composant s'occupe aussi de configurer
l'environnement PHP et propose l'autoload par défaut.

2. Zend_Application démarrage rapide


Il existe deux manières d'aborder Zend_Application, elles dépendent de la manière dont
vous commencez votre projet. Dans tous les cas, vous devrez créer une classe Bootstrap et
un fichier de configuration.

Si vous souhaitez utiliser Zend_Tool pour créer votre projet, continuez votre lecture. Si vous
ajoutez Zend_Application à un projet existant, vous devriez passer à la suite.

2.1. Utiliser Zend_Tool


La manière la plus rapide d'utiliser Zend_Application est d'appeler Zend_Tool pour créer
votre projet. Ceci va aussi créer la classe de Bootstrap.

Pour créer un projet, éxecutez la commande zf (sur les systèmes *nix) :

% zf create project newproject

Pour Windows, zf.bat:

C:> zf.bat create project newproject

Ceci va créer une structure de projet ressemblant à:

newproject
|-- application
| |-- Bootstrap.php
| |-- configs
| | `-- application.ini
| |-- controllers
| | |-- ErrorController.php
| | `-- IndexController.php
| |-- models
| `-- views
| |-- helpers
| `-- scripts
| |-- error
| | `-- error.phtml
| `-- index
| `-- index.phtml
|-- library
|-- public
| `-- index.php
`-- tests
|-- application
| `-- bootstrap.php

142
Zend_Application

|-- library
| `-- bootstrap.php
`-- phpunit.xml

Dans une telle structure, le bootstrap est newproject/application/Bootstrap.php, et


ressemble en premier lieux à ceci:

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
}

Notez aussi la présence d'un fichier de configuration newproject/application/configs/


application.ini, il contient :

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
includePaths.library = APPLICATION_PATH "/../library"
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"

[staging : production]

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

Tous ces paramètres s'utilisent avec Zend_Application et avec le bootstrap.

Un autre fichier intéressant est newproject/public/index.php, qui invoque


Zend_Application et le démarre.

// Define path to application directory


defined('APPLICATION_PATH')
|| define('APPLICATION_PATH',
realpath(dirname(__FILE__) . '/../application'));

// Define application environment


defined('APPLICATION_ENV')
|| define('APPLICATION_ENV',
(getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
: 'production'));

/** Zend_Application */
require_once 'Zend/Application.php';

// Create application, bootstrap, and run


$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
$application->bootstrap()
->run();

143
Zend_Application

Pour continuer le guide de démarrage rapide,voyez la section sur les Ressources.

2.2. Ajouter Zend_Application à votre existant


Les bases de Zend_Application sont très simples :

• Créez un fichier application/Bootstrap.php contenant une classe Bootstrap.

• Créez un fichier application/configs/application.ini contenant la configuration de


base pour Zend_Application.

• Modifiez public/index.php afin d'utiliser Zend_Application.

D'abord, créez la classe Bootstrap class. Dans le fichier application/Bootstrap.php,


voici le contenu :

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
}

Créez maintenant votre configuration. Pour ce tutoriel, nous utilisons une syntaxe INI, bien sûr
une syntaxe XML ou PHP est utilisable aussi. Créez donc le fichier application/configs/
application.ini, et ajoutez lui ce contenu :

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
includePaths.library = APPLICATION_PATH "/../library"
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"

[staging : production]

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

Maintenant, modifions le script de démarrage public/index.php. Si le fichier n'existe pas,


créez le, et placez ce contenu dedans :

// Define path to application directory


defined('APPLICATION_PATH')
|| define('APPLICATION_PATH',
realpath(dirname(__FILE__) . '/../application'));

// Define application environment


defined('APPLICATION_ENV')
|| define('APPLICATION_ENV',
(getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
: 'production'));

// Typically, you will also want to add your library/ directory


// to the include_path, particularly if it contains your ZF installed
set_include_path(implode(PATH_SEPARATOR, array(

144
Zend_Application

dirname(dirname(__FILE__)) . '/library',
get_include_path(),
)));

/** Zend_Application */
require_once 'Zend/Application.php';

// Create application, bootstrap, and run


$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
$application->bootstrap()
->run();

Notez que l'environnement applicatif est défini dans une constante "APPLICATION_ENV". Nous
recommandons la spécification d'un tel paramètre dans la configuration générale du serveur web.
Pour Apache, vous pouvez utiliser .htaccess si votre serveur le permet. Nous recommandons
un fichier public/.htaccess avec le contenu suivant :

SetEnv APPLICATION_ENV development

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

Apprenez mod_rewrite
Les règles de réécriture ci-dessus autorisent l'accès à tout fichier existant dans
l'hôte virtuel. S'il existe des fichiers que vous ne voulez pas exposer, utilisez des
règles plus restrictives. Le site web d'Apache vous permettra d'en apprendre plus
au sujet de mod_rewrite.

Voila, à partir de maintenant nous sommes prêts à tirer partie de la puissance de


Zend_Application.

2.3. Ajouter et créer des ressources


Si vous avez suivi les instructions jusqu'à maintenant, alors votre classe de bootstrap utilisera
le contrôleur frontal et lorsque lancée, lancera le dispatch du contrôleur frontal. En vérité, il va
être rapidement nécessaire de rajouter de la configuration, concernant d'autres objets divers
(appelés "ressources").

Nous allons voir ici comment créer et configurer des ressources. D'abord un layout, puis nous
personnaliserons un objet de vue.

Une ressource assez standard proposée par Zend_Application est "layout". Cette ressource
attend une configuration qu'elle fera suivre immédiatement à Zend_Layout.

Pour l'utiliser, vous devrez modifier votre fichier de configuration comme suit:

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0

145
Zend_Application

bootstrap.path = APPLICATION_PATH "/Bootstrap.php"


bootstrap.class = "Bootstrap"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"

; AJOUTEZ CES LIGNES


resources.layout.layout = "layout"
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"

[staging : production]

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

Si ce n'est pas déja fait, créez le dossier application/layouts/scripts/, et le fichier


layout.phtml dans ce même dossier. Voici un exemple de script de layout tout à fait classique:

<?php echo $this->doctype() ?>


<html>
<head>
<?php echo $this->headTitle() ?>
<?php echo $this->headLink() ?>
<?php echo $this->headStyle() ?>
<?php echo $this->headScript() ?>
</head>
<body>
<?php echo $this->layout()->content ?>
</body>
</html>

Voila, vous avez un layout fonctionnel.

Maintenant passons à la vue. Nous voulons un DocType HTML et une valeur de titre par défaut
à utiliser dans la partie "head" du HTML. Nous pouvons ordonner ceci en éditant la classe
Bootstrap et en ajoutant une méthode.

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
protected function _initView()
{
// Initialisons la vue
$view = new Zend_View();
$view->doctype('XHTML1_STRICT');
$view->headTitle('My First Zend Framework Application');

// Ajoutons là au ViewRenderer
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(
'ViewRenderer'
);
$viewRenderer->setView($view);

// Retourner la vue pour qu'elle puisse être stockée par le bootstrap


return $view;
}
}

146
Zend_Application

Cette méthode va être lancée automatiquement lors du bootstrap et configurera une vue.

2.4. Aller plus loin avec Zend_Application


Nous vennons de voir comment configurer de manière basique Zend_Application ainsi que
les principes du bootstrap. Pour un maximum de réutilisation de code, vous devriez songer à
utiliser des plugins de ressources. Continuez à lire la suite !

3. Théorie générale
Monter une application MVC configurée et prête à être lancée requière de plus en plus de code
au fur et à mesure de l'ajout de fonctionnalités : monter une base de données, configurer la vue
et ses aides, les layouts, enregistrer des plugins, des aides d'action et bien plus encore...

Aussi, vous réutiliserez souvent le même code dans vos tests, dans une tâche cron ou encore
un service. Il est certes possible d'inclure le script de bootstrap dans de tels cas, mais souvent
des variables seront dépendantes de l'environnement. Par exemple, vous n'aurez pas besoin
de MVC dans une tâche cron, ou alors vous aurez juste besoin de l'accès à la base de données
dans un script de service.

Zend_Application a pour but de simplifier ces processus et de promouvoir la réutilisabilité


de code en encapsulant les étages de définition du bootstrap en concepts orientés objet (OO).

Zend_Application se décompose en 3 parties :

• Zend_Application charge l'environnement PHP, à savoir les include_paths et les


autoloads, et instancie la classe de bootstrap demandée.

• Zend_Application_Bootstrap regroupe les interfaces pour les classes de bootstrap.


Zend_Application_Bootstrap_Bootstrap propose des fonctionnalités de base
concernant l'amorçage (le bootstrap), à savoir des algorithmes de vérification des
dépendances et la possibilité de charger des ressources à la demande.

• Zend_Application_Resource est une interface pour les ressources de bootstrap qui


peuvent être chargées à la demande depuis les instances de bootstrap.

Les développeurs créent une classe de bootstrap pour leur application en


étendant Zend_Application_Bootstrap_Bootstrap ou en implémentant (au minimum)
Zend_Application_Bootstrap_Bootstrapper. Le point d'entrée (public/index.php)
chargera Zend_Application en l'instanciant et en lui passant :

• L'environnement courant

• Des options de bootstrapping

Les options de bootstrap incluent le chemin vers le fichier contenant la classe de bootstrap, et
optionnellement :

• Des include_paths supplémentaires

• Des espaces de nom d'autoload à enregistrer

• Des paramètres php.ini à initialiser

• Le nom de la classe pour le bootstrap (sinon "Bootstrap" sera utilisée)

• Des paires préfixe / chemin pour les ressources à utiliser

• N'importe quelle ressource à utiliser (nom de classe ou nom court)

147
Zend_Application

• Des chemins additionnels vers un fichier de configuration à charger

• Des options de configuration supplémentaires

Les options peuvent être un tableau, un objet Zend_Config, ou le chemin vers un fichier de
configuration.

3.1. Bootstrapping
Zend_Application's second area of responsibility is executing the application bootstrap.
Bootstraps minimally need to implement Zend_Application_Bootstrap_Bootstrapper,
which defines the following API:

interface Zend_Application_Bootstrap_Bootstrapper
{
public function __construct($application);
public function setOptions(array $options);
public function getApplication();
public function getEnvironment();
public function getClassResources();
public function getClassResourceNames();
public function bootstrap($resource = null);
public function run();
}

This API allows the bootstrap to accept the environment and configuration from the application
object, report the resources its responsible for bootstrapping, and then bootstrap and run the
application.

You can implement this interface on your own, extend


Zend_Application_Bootstrap_BootstrapAbstract, or use
Zend_Application_Bootstrap_Bootstrap.

Besides this functionality, there are a number of other areas of concern you should familiarize
yourself with.

3.1.1. Resource Methods


The Zend_Application_Bootstrap_BootstrapAbstract implementation provides a
simple convention for defining class resource methods. Any protected method beginning with a
name prefixed with _init will be considered a resource method.

To bootstrap a single resource method, use the bootstrap() method, and pass it the name of
the resource. The name will be the method name minus the _init prefix.

To bootstrap several resource methods, pass an array of names. Too bootstrap all resource
methods, pass nothing.

Take the following bootstrap class:

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
protected function _initFoo()
{
// ...
}

protected function _initBar()


{

148
Zend_Application

// ...
}

protected function _initBaz()


{
// ...
}
}

To bootstrap just the _initFoo() method, do the following:

$bootstrap->bootstrap('foo');

To bootstrap the _initFoo() and _initBar() methods, do the following:

$bootstrap->bootstrap(array('foo', 'bar'));

To bootstrap all resource methods, call bootstrap() with no arguments:

$bootstrap->bootstrap();

3.1.2. Bootstraps that use resource plugins


To make your bootstraps more re-usable, we have provided the ability to push your resources into
resource plugin classes. This allows you to mix and match resources simply via configuration. We
will cover how to create resources later; in this section we will show you how to utilize them only.

If your bootstrap should be capable of using resource plugins, you will need to implement
an additional interface, Zend_Application_Bootstrap_ResourceBootstrapper. This
interface defines an API for locating, registering, and loading resource plugins:

interface Zend_Application_Bootstrap_ResourceBootstrapper
{
public function registerPluginResource($resource, $options = null);
public function unregisterPluginResource($resource);
public function hasPluginResource($resource);
public function getPluginResource($resource);
public function getPluginResources();
public function getPluginResourceNames();
public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader);
public function getPluginLoader();
}

Resource plugins basically provide the ability to create resource intializers that can be re-used
between applications. This allows you to keep your actual bootstrap relatively clean, and to
introduce new resources without needing to touch your bootstrap itself.

Zend_Application_Bootstrap_BootstrapAbstract (and
Zend_Application_Bootstrap_Bootstrap by extension) implement this interface as well,
allowing you to utilize resource plugins.

To utilize resource plugins, you must specify them in the options passed to the application object
and/or bootstrap. These options may come from a configuration file, or be passed in manually.
Options will be of key to options pairs, with the key representing the resource name. The resource
name will be the segment following the class prefix. For example, the resources shipped with
Zend Framework have the class prefix "Zend_Application_Resource_"; anything following
this would be the name of the resource. As an example,

149
Zend_Application

$application = new Zend_Application(APPLICATION_ENV, array(


'resources' => array(
'FrontController' => array(
'controllerDirectory' => APPLICATION_PATH . '/controllers',
),
),
));

This indicates that the "FrontController" resource should be used, with the options specified.

If you begin writing your own resource plugins, or utilize third-party resource plugins, you
will need to tell your bootstrap where to look for them. Internally, the bootstrap utilizes
Zend_Loader_PluginLoader, so you will only need to indicate the common class prefix an
path pairs.

As an example, let's assume you have custom resource plugins in APPLICATION_PATH/


resources/ and that they share the common class prefix of My_Resource. You would then
pass that information to the application object as follows:

$application = new Zend_Application(APPLICATION_ENV, array(


'pluginPaths' => array(
'My_Resource' => APPLICATION_PATH . '/resources/',
),
'resources' => array(
'FrontController' => array(
'controllerDirectory' => APPLICATION_PATH . '/controllers',
),
),
));

You would now be able to use resources from that directory.

Just like resource methods, you use the bootstrap() method to execute resource plugins.
Just like with resource methods, you can specify either a single resource plugin, multiple plugins
(via an array), or all plugins. Additionally, you can mix and match to execute resource methods
as well.

// Execute one:
$bootstrap->bootstrap('FrontController');

// Execute several:
$bootstrap->bootstrap(array('FrontController', 'Foo'));

// Execute all resource methods and plugins:


$bootstrap->bootstrap();

3.1.3. Resource Registry


Many, if not all, of your resource methods or plugins will initialize objects, and in many cases,
these objects will be needed elsewhere in your application. How can you access them?

Zend_Application_Bootstrap_BootstrapAbstract provides a local registry for these


objects. To store your objects in them, you simply return them from your resources.

For maximum flexibility, this registry is referred to as a "container" internally; its only requirements
are that it is an object. Resources are then registered as properties named after the resource
name. By default, an instance of Zend_Registry is used, but you may also specify any
other object you wish. The methods setContainer() and getContainer() may be used

150
Zend_Application

to manipulate the container itself. getResource($resource) can be used to fetch a given


resource from the container, and hasResource($resource) to check if the resource has
actually been registered.

As an example, consider a basic view resource:

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
protected function _initView()
{
$view = new Zend_View();
// more initialization...

return $view;
}
}

You can then check for it and/or fetch it as follows:

// Using the has/getResource() pair:


if ($bootstrap->hasResource('view')) {
$view = $bootstrap->getResource('view');
}

// Via the container:


$container = $bootstrap->getContainer();
if (isset($container->view)) {
$view = $container->view;
}

Please note that the registry and also the container is not global. This
means that you need access to the bootstrap in order to fetch resources.
Zend_Application_Bootstrap_Bootstrap provides some convenience for this: during its
run() execution, it registers itself as the front controller parameter "bootstrap", which allows you
to fetch it from the router, dispatcher, plugins, and action controllers.

As an example, if you wanted access to the view resource from above within your action
controller, you could do the following:

class FooController extends Zend_Controller_Action


{
public function init()
{
$bootstrap = $this->getInvokeArg('bootstrap');
$view = $bootstrap->getResource('view');
// ...
}
}

3.1.4. Dependency Tracking


In addition to executing resource methods and plugins, it's necessary to ensure that these
are executed once and once only; these are meant to bootstrap an application, and executing
multiple times can lead to resource overhead.

At the same time, some resources may depend on other resources being executed. To
solve these two issues, Zend_Application_Bootstrap_BootstrapAbstract provides a
simple, effective mechanism for dependency tracking.

151
Zend_Application

As noted previously, all resources -- whether methods or plugins -- are bootstrapped by calling
bootstrap($resource), where $resource is the name of a resource, an array of resources,
or, left empty, indicates all resources should be run.

If a resource depends on another resource, it should call bootstrap() within its code to ensure
that resource has been executed. Subsequent calls to it will then be ignored.

In a resource method, such a call would look like this:

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
protected function _initRequest()
{
// Ensure the front controller is initialized
$this->bootstrap('FrontController');

// Retrieve the front controller from the bootstrap registry


$front = $this->getResource('FrontController');

$request = new Zend_Controller_Request_Http();


$request->setBaseUrl('/foo');
$front->setRequest($request);

// Ensure the request is stored in the bootstrap registry


return $request;
}
}

3.2. Resource Plugins


As noted previously, a good way to create re-usable bootstrap resources and to offload much of
your coding to discrete classes is to utilize resource plugins. While Zend Framework ships with
a number of standard resource plugins, the intention is that developers should write their own
to encapsulate their own initialization needs.

Resources plugins need only implement Zend_Application_Resource_Resource, or,


more simply still, extend Zend_Application_Resource_ResourceAbstract. The basic
interface is simply this:

interface Zend_Application_Resource_Resource
{
public function __construct($options = null);
public function setBootstrap(
Zend_Application_Bootstrap_Bootstrapper $bootstrap
);
public function getBootstrap();
public function setOptions(array $options);
public function getOptions();
public function init();
}

The interface defines simply that a resource plugin should accept options to the constructor,
have mechanisms for setting and retrieving options, have mechanisms for setting and retrieving
the bootstrap object, and an initialization method.

As an example, let's assume you have a common view intialization you use in your applications.
You have a common doctype, CSS and JavaScript, and you want to be able to pass in a base
document title via configuration. Such a resource plugin might look like this:

152
Zend_Application

class My_Resource_View extends Zend_Application_Resource_ResourceAbstract


{
protected $_view;

public function init()


{
// Return view so bootstrap will store it in the registry
return $this->getView();
}

public function getView()


{
if (null === $this->_view) {
$options = $this->getOptions();
$title = '';
if (array_key_exists('title', $options)) {
$title = $options['title'];
unset($options['title']);
}

$view = new Zend_View($options);


$view->doctype('XHTML1_STRICT');
$view->headTitle($title);
$view->headLink()->appendStylesheet('/css/site.css');
$view->headScript()->appendfile('/js/analytics.js');

$viewRenderer =
Zend_Controller_Action_HelperBroker::getStaticHelper(
'ViewRenderer'
);
$viewRenderer->setView($view);

$this->_view = $view;
}
return $this->_view;
}
}

As long as you register the prefix path for this resource plugin, you can then use it in your
application. Even better, because it uses the plugin loader, you are effectively overriding the
shipped "View" resource plugin, ensuring that your own is used instead.

4. Exemples
La classe de bootstrap elle-même sera typiquement minimaliste ; souvent, elle s'agira
simplement d'une extension vide de la classe de bootstrap de base :

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
}

Avec un fichier de configuration tel que :

; APPLICATION_PATH/configs/application.ini
[production]
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"

153
Zend_Application

[testing : production]
[development : production]

Cependant, si de l'initialisation personnalisée est nécessaire, alors vous avez 2 choix. D'abord
vous pouvez écrire des méthodes préfixées par _init pour ajouter du code au bootstrap. De telles
méthodes seront appelées par bootstrap(), et peuvent être appelées comme si elles étaient
publiques, par : bootstrap<resource>(). Elles peuvent accepter un tableau d'options.

Si votre méthode de ressource retourne une valeur, elle sera stockée dans un conteneur du
bootstrap. Ceci peut être utile quand différentes ressources ont besoin d'interagir (comme une
ressource s'injectant elle-même dans une autre). La méthode getResource() peut être utilisée
pour récupérer ces valeurs.

L'exemple ci-dessous montre une méthode de ressource pour l'initialisation d'un objet requête.
Il utilise le traqueur de dépendances (il dépend de la ressource de contrôleur frontal), récupère
une ressource à partir du bootstrap, et retourne une valeur à stocker dans le bootstrap.

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{
protected function _initRequest()
{
// Vérifie que le contrôleur frontal est bien présent, et le récupère
$this->bootstrap('FrontController');
$front = $this->getResource('FrontController');

// Initialise l'objet requête


$request = new Zend_Controller_Request_Http();
$request->setBaseUrl('/foo');

// On l'ajoute au contrôleur frontal


$front->setRequest($request);

// Le bootstrap va stocker cette valeur dans la clé 'request'


// de son conteneur
return $request;
}
}

Notez l'appel à bootstrap() ; Ceci permet de s'assurer que le contrôleur frontal a bien été
initialisé avant d'appeler cette méthode.

Une autre option consiste à utiliser des ressources de bootstrap. Les plugins de ressources sont
des objets qui s'occupent d'initialisations spéciales, elles peuvent être spécifiées :

• à l'instanciation d'un objet Zend_Application ;

• pendant l'initialisation de l'objet bootstrap ;

• en les activant spécifiquement via des appels de méthodes sur l'objet de bootstrap.

Les plugins de ressources implémentent


Zend_Application_Resource_ResourceAbstract, qui définit simplement qu'elles
peuvent être injectées dans l'objet les appelant, et qu'elles ont une méthode init(). Voici un
exemple d'un bootstrap de vue :

class My_Bootstrap_Resource_View

154
Zend_Application

extends Zend_Application_ResourceAbstract
{
public function init()
{
$view = new Zend_View($this->getOptions());
Zend_Dojo::enableView($view);

$view->doctype('XHTML1_STRICT');
$view->headTitle()->setSeparator(' - ')->append('My Site');
$view->headMeta()->appendHttpEquiv('Content-Type',
'text/html; charset=utf-8');

$view->dojo()->setDjConfigOption('parseOnLoad', true)
->setLocalPath('/js/dojo/dojo.js')
->registerModulePath('../spindle', 'spindle')
->addStylesheetModule('spindle.themes.spindle')
->requireModule('spindle.main')
->disable();

$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(
'ViewRenderer'
);
$viewRenderer->setView($view);

return $view;
}
}

Pour dire au bootstrap d'utiliser cette classe, vous devrez fournir le nom de la classe pour ce
plugin de ressource, ou une combinaison préfixe / chemin de chargeur de plugin (plugin loader)
et le nom court du plugin de ressource ("view") :

$application = new Zend_Application(


APPLICATION_ENV,
array(
'resources' => array(
'My_Bootstrap_Resource_View' => array(), // nom de la classe OU
'view' => array(), // nom court

'FrontController' => array(


'controllerDirectory' => APPLICATION_PATH . '/controllers',
),
),

// Pour les noms courts, définissez les chemins :


'resourcePaths = array(
'My_Bootstrap_Resource' => 'My/Bootstrap/Resource',
)
)
);

Les plugins de ressource peuvent en appeler d'autres via le bootstrap parent :

class My_Bootstrap_Resource_Layout
extends Zend_Application_ResourceAbstract
{
public function init()
{
// Assurons nous que la vue est initialisée...

155
Zend_Application

$this->getBootstrap()->bootstrap('view');

// Récupère l'objet de vue :


$view = $this->getBootstrap()->getResource('view');

// ...
}
}

En usage normal, vous instancierez votre application, lancerez le bootstrap, puis l'application :

$application = new Zend_Application(...);


$application->bootstrap()
->run();

Pour un script personnalisé, vous auriez peut être besoin de ne lancer que des ressources
spécifiques :

$application = new Zend_Application(...);


$application->getBootstrap()->bootstrap('db');

$service = new Zend_XmlRpc_Server();


$service->setClass('Foo'); // uses database...
echo $service->handle();

Plutôt que d'utiliser la méthode bootstrap() pour appeler les méthodes internes, vous pouvez
surcharger :

$application = new Zend_Application(...);


$application->getBootstrap()->bootstrapDb();

5. Fonctionnalités principales
Ici vous trouverez une documentation type API concernant les composants coeurs de
Zend_Application.

5.1. Zend_Application
Zend_Application est la classe de base du composant et le point d'entrée de votre
application Zend Framework. Ses buts sont multiples : configurer l'environnement PHP (incluant
l'autoloading) et exécuter le bootstrap de votre application.

Typiquement, vous allez passer toute la configuration au constructeur de Zend_Application,


mais vous pouvez aussi configurer l'objet via ses méthodes. Ce chapitre illustrera les deux
aspects.

Tableau 2. Zend_Application options


Option Description
phpSettings Tableau de paramètres php.ini à utiliser.
Les clés doivent être des clés reconnues dans
php.ini.
includePaths Chemins additionnels à ajouter à include_path.
Ces chemins sont ajoutés avant l'include_path.
L'option doit être un tableau de chemins.

156
Zend_Application

Option Description
autoloaderNamespaces Tableau d'espaces de noms à enregistrer dans
Zend_Loader_Autoloader.
bootstrap Soit une chaîne vers le fichier contenant la
classe de bootstrap, soit un tableau avec les
clés 'path' et 'class' menant vers le bootstrap.

Noms des options

Notez que les noms des options ne sont pas sensibles à la casse.

Tableau 3. Méthodes dans Zend_Application

Méthode Valeur de retour Paramètres Description


Void
__construct($environment, • $environment : Une instance de
$options = null) requis, Chaîne Zend_Loader_Autoloader
représentant est enregistrée lors
l'environnement de l'instanciation. Les
actuel dans lequel options passées au
tourne l'application. constructeur sont
Par exemple passées à
"development", setOptions().
"testing", "qa", ou
"production". Les
significations de ces
chaînes sont à
définir par la suite.

• $options :
optionnel.

• String : chemin
vers un fichier
Zend_Config à
charger pour la
configuration de
votre application.
$environment
sera utilisé pour
déterminer la
section de
configuration à
charger depuis le
fichier.

• Array : tableau
associatif de
données de
configuration pour
votre application.

• Zend_Config :
un instance

157
Zend_Application

Méthode Valeur de retour Paramètres Description


d'objet de
configuration.
getEnvironment() String N/A Récupère
l'environnement passé
au constructeur.
getAutoloader() N/A
Zend_Loader_Autoloader Récupère l'objet
Zend_Loader_Autoloader
enregistré lors de
l'instanciation.
setOptions(array Zend_Application • $options : requis. Toutes les options
$options) Un tableau d'options sont stockées en
pour l'application. interne, et appeler
plusieurs fois la même
méthode fusionnera
les options qu'elle
définit. Les options
qui correspondent aux
diverses méthodes
setter seront passées
à ces méthodes.
Par exemple, l'option
"phpSettings" sera
passée à
setPhpSettings().
getOptions() Array N/A Récupère toutes
les options utilisées
pour initialiser l'objet.
Pourrait être utilisé
pour mettre en
cache les options
Zend_Config entre
chaque requête, par
exemple.
hasOption($key) Boolean • $key : La clé de Indique si une option
l'option à chercher correspondant à une
clé précise a été
utilisée ou pas. Les
clés sont insensibles à
la casse.
getOption($key) Mixed • $key : La clé de Récupère l'option
l'option à récupérer correspondant à la clé
passée, NULL si celle-
ci n'existe pas.
Zend_Application • $settings : requis.
setPhpSettings(array Affecte à la
$settings, Tableau associatif volée des paramètres
$prefix = '') de paramètres PHP de php.ini. Les
INI paramètres séparés
par des points peuvent
• $prefix : être imbriqués
optionnel. Préfixe

158
Zend_Application

Méthode Valeur de retour Paramètres Description


pour construire la hiérarchiquement
chaîne des clés (comme dans le cas
d'options. Utilisée des paramètres INI de
en interne pour Zend_Config).
faire correspondre
les clés php.ini
séparés par des
points (".") avec
des tableaux à
plusieurs niveaux.
En temps normal,
cet argument ne
devrait jamais être
utilisé par
l'utilisateur.
Zend_Application • $namespaces
setAutoloaderNamespaces(array : Enregistre des
$namespaces) requis. Tableau de espaces de noms
chaînes dans
représentant les Zend_Loader_Autoloader.
espaces de noms
à enregistrer dans
Zend_Loader_Autoloader.
Zend_Application • $path : requis. Peut
setBootstrap($path,
$class = null) être soit un objet de
Zend_Application_Bootstrap_Bootstrapper,
soit une chaîne
représentant le
chemin vers la
classe de bootstrap,
soit un tableau
associatif nom de
classe => chemin
de fichier, ou encore
un tableau associatif
avec les clés "class"
et "path".

• $class : optionnel.
Si $path est
une chaîne, $class
doit être indiqué
et doit être une
chaîne représentant
le nom d'une classe
contenue dans le
fichier représenté
par le chemin.
getBootstrap() NULL | N/A Récupère l'instance du
bootstrap enregistrée.
Zend_Application_Bootstrap_Bootstrapper
bootstrap() Void N/A Appelle la méthode
bootstrap() du

159
Zend_Application

Méthode Valeur de retour Paramètres Description


bootstrap pour lancer
l'application.
run() Void N/A Appelle la méthode
run() du bootstrap
pour lancer le dispatch
de l'application.

5.2. Zend_Application_Bootstrap_Bootstrapper
Zend_Application_Bootstrap_Bootstrapper est l'interface de base que toutes les
classes de bootstrap doivent implémenter. Les fonctionnalités apportées sont la configuration,
l'identification des ressources, le bootstrap (d'une ressource ou de l'application entière), et le
lancement (dispatching) de l'application.

Voici les méthodes définies par l'interface.

Tableau 4. Méthodes de Zend_Application_Bootstrap_Bootstrapper


Méthode Valeur de retour Paramètres Description
Void
__construct($application) • $application : Constructeur. Accepte
requis. Accepte un un argument qui peut
argument instance être une instance de
de Zend_Application
Zend_Applicationou un autre objet
ou de bootstrap.
Zend_Application_Bootstrap_Bootstrapper
• $options : requis. Une
setOptions(array Zend_Application_Bootstrap_Bootstrapper option qui
$options) Tableaux d'options à correspond à un setter
configurer. lui sera passé, sinon
l'option est stockée
pour pouvoir être
utilisée plus tard.
getApplication() Zend_Application | N/A Récupère l'objet
d'application passé au
Zend_Application_Bootstrap_Bootstrapper
constructeur.
getEnvironment() String N/A Récupère la chaîne
d'environnement
enregistrée dans
l'objet d'application.
Array
getClassResources() N/A Retourne la liste
des classes utilisées
comme classes de
ressources.
Mixed
bootstrap($resource • $resource : Si $resource est
= null) optionnel. vide, exécute toutes
les ressources. Si une
chaîne est passée,
exécute uniquement la
ressource considérée.
Enfin, si un tableau
de chaînes est passé,

160
Zend_Application

Méthode Valeur de retour Paramètres Description


toutes les ressources
représentées par
ses chaînes sont
exécutées.
run() Void N/A Définit la logique à
lancer après avoir
lancé le bootstrap.

5.3. Zend_Application_Bootstrap_ResourceBootstrapper
Zend_Application_Bootstrap_ResourceBootstrapper est une interface utilisée
lorsqu'une classe de bootstrap chargera une ressource externe, ce qui signifie que les
ressources peuvent ne pas être définies comme de simples méthodes, mais via des classes
"plugins". Cette interface devrait être utilisée avec Zend_Application_Bootstrap_Bootstrapper ;
Zend_Application_Bootstrap_BootstrapAbstract implémente cette fonctionnalité.

Voici les méthodes définies par l'interface.

Tableau 5. Méthodes de Zend_Application_Bootstrap_ResourceBootstrapper


Méthode Valeur de retour Paramètres Description
registerPluginResource($resource, • $resource : requis. Enregistre
Zend_Application_Bootstrap_ResourceBootstrapper une
$options = null) Un nom de ressource avec la
ressource ou un classe, ajoutant une
objet configuration
optionnelle à fournir à
Zend_Application_Resource_Resource
la ressource.
• $options :
optionnel. Un
tableau d'objets
Zend_Config à
passer au
constructeur de la
ressource.
unregisterPluginResource($resource) • $resource : requis. Supprime un plugin de
Zend_Application_Bootstrap_ResourceBootstrapper
Nom de la ressource ressource de la classe.
à effacer de la
liste des ressources
chargées.
Boolean
hasPluginResource($resource) • $resource : requis. Détermine si une
Nom de la ressource donnée a
ressource. été enregistrée.
getPluginResource($resource) • $resource : requis. Récupère
Zend_Application_Resource_Resource une
Nom de la ressource instance de plugin
à récupérer (string). de ressource par son
nom.
Array
getPluginResourceNames() N/A Récupère une liste de
noms de tous les
plugins enregistrés.
• $loader : requis. Enregistre
setPluginLoader(Zend_Loader_PluginLoader_Interface
Zend_Application_Bootstrap_ResourceBootstrapper un
$loader) Instance de PluginLoader

161
Zend_Application

Méthode Valeur de retour Paramètres Description


PluginLoader (chargeur de classes)
(chargeur de à utiliser pour résoudre
classes) à utiliser les noms de plugins en
pour résoudre les classes.
noms de plugins en
classes.
N/A
getPluginLoader() Zend_Loader_PluginLoader_Interface Récupère l'objet
pluginLoader chargé.

5.4. Zend_Application_Bootstrap_BootstrapAbstract
Zend_Application_Bootstrap_BootstrapAbstract est une classe abstraite
qui propose les fonctionnalités de base d'un bootstrap classique.
Elle implémente à la fois Zend_Application_Bootstrap_Bootstrapper et
Zend_Application_Bootstrap_ResourceBootstrapper.

Tableau 6. Méthodes de Zend_Application_Bootstrap_BootstrapAbstract

Méthode Valeur de retour Paramètres Description


Void
__construct($application) • $application : Constructeur. Accepte
requis. Accepte un un seul argument de
objet type
Zend_ApplicationZend_Application,
ou ou un autre objet
bootstrap.
Zend_Application_Bootstrap_Bootstrapper
• $options : requis. Toute
setOptions(array Zend_Application_Bootstrap_Bootstrapper option
$options) Tableau d'options à possédant un setter
configurer. l'invoquera, sinon
l'option sera stockée
pour une utilisation
ultérieure. Par
exemple, si votre
classe fille définit une
méthode setFoo(),
l'option 'foo' passera
sa valeur à cette
méthode.

Deux options
supplémentaires
spéciales peuvent
aussi être utilisée.
pluginPaths spécifie
des préfixes de chemin
vers les plugins ; on
attend ici un tableau
de paires préfixes,
chemins. resources
permet de spécifier un
plugin à utiliser.

162
Zend_Application

Méthode Valeur de retour Paramètres Description


getOptions() Array N/A Retourne toutes les
options enregistrées
via setOptions().
hasOption($key) Boolean • $key : requis. Détermine si une
Option dont on veut option est présente.
tester la présence.
getOption($key) Mixed • $key: requis. Option Récupère la valeur
à récupérer. de l'option associée à
la clé passée comme
paramètre retourne
NULL si aucune option
n'est enregistrée avec
cette clé.
setApplication(Zend_Application • $application : Enregistre
Zend_Application_Bootstrap_BootstrapAbstract l'objet
| requis. application parent, ou
Zend_Application_Bootstrap_Bootstrapper un objet de bootstrap.
$application)
getApplication() Zend_Application | N/A Récupère l'objet
application
Zend_Application_Bootstrap_Bootstrapper ou
bootstrap passé par le
constructeur.
getEnvironment() String N/A Récupère
l'environnement
(chaîne) enregistré
dans l'objet parent,
application ou
bootstrap.
Array
getClassResources() N/A Récupère la liste des
noms des chargeurs
de ressources définis
dans la classe.
Spécifique à
l'implémentation.
getContainer() Object N/A Récupère le conteneur
stockant les
ressources. Si aucun
conteneur n'est
spécifié, un objet
Zend_Registry sera
crée pour cet usage,
puis retourné.
setContainer($container) • $container, Définit un conteneur
Zend_Application_Bootstrap_BootstrapAbstract
requis. Un objet mémorisant les
dans lequel stocker ressources.
les ressources. Lorsqu'une ressource
est demandée, elle est
chargée puis stocker
dans ce conteneur
pour être retournée

163
Zend_Application

Méthode Valeur de retour Paramètres Description


lors des prochains
appels.
hasResource($name)Boolean • $name, requis. Nom Lorsqu'une ressource
de la ressource dont est demandée
on veut vérifier la (retournée par une
présence. méthode ou un
plugin), elle est
stockée dans un
objet conteneur (voyez
getContainer() et
setContainer().)
Cette méthode
interroge le conteneur
pour savoir si une
ressource y est
présente.
getResource($name)Mixed • $name, requis. Nom Lorsqu'une ressource
de la ressource à est demandée
récupérer (retournée par une
méthode ou un
plugin), elle est
stockée dans un
objet conteneur (voyez
getContainer() et
setContainer().)
Cette méthode
récupère une
ressource depuis le
conteneur.
Mixed
bootstrap($resource • $resource: Si $resource est
= null) optionnel. vide, charge toutes les
ressources
(bootstrap). Si une
chaîne est passée,
charge uniquement la
ressource demandée.
Enfin si un tableau
est passé, charge les
ressources nommées
dans ce tableau.

Cette méthode peut


être utilisée pour
déclencher le
chargement d'une
ressource, définit sous
forme de méthode
ou de plugin (c'est
égal). Attention si vous
spécifiez à la fois
une méthode et un

164
Zend_Application

Méthode Valeur de retour Paramètres Description


plugin pour une même
ressource, alors la
méthode sera préférée
comme bootstrap, le
plugin sera ignoré.
run() Void N/A Définit la logique
applicative à lancer
après le bootstrap (la
configuration)
__call($method, Mixed • $method : requis. Propose une interface
$args) Nom de la méthode agréable pour
appelée configurer (bootstrap)
des ressources
• $args : requis. individuelles en
Tableau appelant
d'arguments 'bootstrap<NomDeLaRessource>()'
d'invocation pour la à la place de
méthode. bootstrap().

5.5. Zend_Application_Bootstrap_Bootstrap
Zend_Application_Bootstrap_Bootstrap est une implémentation concrète de
Zend_Application_Bootstrap_BootstrapAbstract. Ces caractéristiques principales sont
l'enregistrement de la ressource Front Controller, et la méthode run() qui vérifie d'abord la
présence d'un module par défaut dans le contrôleur frontal, avant de lancer le dispatching.

Dans la plupart des cas, vous étendrez cette classe dans vos bootstraps, ou encore vous
utiliserez cette classe en lui fournissant une liste de plugins à utiliser.

5.5.1. Activer l'autoload de l'application


De plus, cette implémentation de bootstrap fournit la possibilité de spécifier l'espace de noms
ou le préfixe de classe pour les ressources situées dans son arborescence, ce qui va activer
le chargement automatique des différentes resources de l'application ; essentiellement, ceci
instancie un objet Zend_Application_Module_Autoloader, en fournissant l'espace de noms
requêté et le dossier de bootstrap en tant qu'arguments. Vous pouvez activer cette fonctionnalité
en fournissant l'espace de noms à l'option de configuration "appnamespace". Par exemple avec
un fichier INI :

appnamespace = "Application"

Ou en XML :

<appnamespace>Application</appnamespace>

Par défaut, Zend_Tool va activer cette option avec la valeur "Application".

Alternativement, vous pouvez simplement définir la propriété $_appNamespace de votre classe


de bootstrap avec la valeur appropriée :

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap


{

165
Zend_Application

protected $_appNamespace = 'Application';


}

5.6. Zend_Application_Resource_Resource
Zend_Application_Resource_Resource est une interface implémentée par les plugins
de ressources lorsqu'ils sont utilisés par des classes de bootstrap implémentant
Zend_Application_Bootstrap_ResourceBootstrapper. Les classes de plugins de
ressources doivent accepter de la configuration, doivent pouvoir être lancées ("bootstrapées")
et doivent utiliser un pattern strategy pour initialiser la ressource.

Tableau 7. Méthodes de Zend_Application_Resource_Resource

Méthode Valeur de retour Paramètres Description


Void
__construct($options • $options: Le constructeur doit
= null) optionnel. Options posséder un
d'initialisation. paramètre permettant
de configurer l'état de
la ressource.
• $bootstrap:
setBootstrap(Zend_Application_Bootstrap_Bootstrapper
Zend_Application_Resource_Resource Doit autoriser
$bootstrap) requis. Bootstrap l'enregistrement du
parent initialisant bootstrap parent.
cette ressource.
getBootstrap() N/A Récupère
Zend_Application_Bootstrap_Bootstrapper l'objet
bootstrap enregistré.
• $options: requis. Définit
setOptions(array Zend_Application_Resource_Resource l'état
$options) Options de d'initialisation de la
configuration de la ressource.
ressource
getOptions() Array N/A Récupère les options
enregistrées.
init() Mixed N/A Pattern strategy:
exécute l'initialisation
de la ressource.

5.7. Zend_Application_Resource_ResourceAbstract
Zend_Application_Resource_ResourceAbstract est une classe abstaite implementant
Zend_Application_Resource_Resource, c'est un bon point de départ pour créer vos propres
plugins de ressources.

Note: Cette classe abstraite n'implémente pas la méthode init(); elle doit donc être
implémentée par les extensions concrêtes de cette classe.

Tableau 8. Méthodes de Zend_Application_Resource_ResourceAbstract

Méthode Valeur de retour Paramètres Description


Void
__construct($options • $options: Le constructeur doit
= null) optionnel. Options accepter un
de configuration de paramètres permettant
la ressource.

166
Zend_Application

Méthode Valeur de retour Paramètres Description


de définir l'état de la
ressource.
• $bootstrap
setBootstrap(Zend_Application_Bootstrap_Bootstrapper : Doit
Zend_Application_Resource_ResourceAbstract accepter
$bootstrap) requis. Bootstrap l'enregistrement du
parent initialisant bootstrap parent.
cette resource.
getBootstrap() N/A Récupère
Zend_Application_Bootstrap_Bootstrapper l'objet
bootstrap enregistré.
• $options : Définit l'état
setOptions(array Zend_Application_Resource_ResourceAbstract de la
$options) required. Options de ressource.
la ressource.
getOptions() Array N/A Retourne les options
enregistrées.

5.7.1. Noms des resources


Lorque vous enregistrez des plugins de ressources, il existe alors 3 manières d'y faire référence
dans la classe du bootstrap parent, en fonction de la manière dont vous avez configuré le
bootstrap.

D'abord, si vos classes de plugins existent dans un chemin précis, vous pouvez alors y faire
référence simplement par leur nom court -- la portion du nom de la classe située après le
préfixe de classe. Par exemple, la classe "Zend_Application_Resource_View" peut être
référencée simplement via "View" car le préfixe "Zend_Application_Resource" est déja
enregistré. Vous pouvez aussi utiliser le nom long de classe complet :

$app = new Zend_Application(APPLICATION_ENV, array(


'pluginPaths' => array(
'My_Resource' => 'My/Resource/',
),
'resources' => array(
// Si la classe suivante existe:
'My_Resource_View' => array(),

// alors ceci est équivalent:


'View' => array(),
),
));

Quoiqu'il en soit, vous pouvez lancer (bootstrap) la ressource ou la récupérer via son nom court:

$bootstrap->bootstrap('view');
$view = $bootstrap->getResource('view');

Ensuite, si aucun chemin précis n'est enregistré, il reste possible de passer ses plugins de
ressources via leur nom de classe complet :

$app = new Zend_Application(APPLICATION_ENV, array(


'resources' => array(
// Ceci va charger le plugin de ressource standard 'View':
'View' => array(),

167
Zend_Application

// Alors que ceci charge une classe spécifiquement via son nom:
'My_Resource_View' => array(),
),
));

La récupération de ces objets se fait alors de manière plus clarifiée :

$bootstrap->bootstrap('My_Resource_View');
$view = $bootstrap->getResource('My_Resource_View');

La troisième méthode découle des deux précédentes. Il est possible de donner un nom court
à n'importe quelle classe. Ajoutez une variable publique $_explicitType dans la classe du
plugin, sa valeur sera alors utilisée comme nom court pour référencer le plugin dans le bootstrap.
Définissons par exemple notre propre vue :

class My_Resource_View extends Zend_Application_Resource_ResourceAbstract


{
public $_explicitType = 'My_View';

public function init()


{
// du code ici...
}
}

Nous pouvons dès lors lancer cette ressource (bootstrap) ou la récupérer via le nom "My_View":

$bootstrap->bootstrap('My_View');
$view = $bootstrap->getResource('My_View');

Grâce à ses différentes manières de faire, vous pouvez redéfinir des plugins existants, en ajouter
ou encore les mixer pour accomplir des tâches d'initialisation complexes.

6. Plugins de ressources disponibles


Vous trouverez ci-après la documentation de type API concernant tous les plugins disponibles
par défaut dans Zend_Application.

6.1. Zend_Application_Resource_Cachemanager
Zend_Application_Resource_Cachemanager peut être utilisé pour configurer un jeu
d'ensemble d'options Zend_Cache permettant de paramétrer des caches à chargement tardifs
("lazy loading") avec Zend_Cache_Manager

Comme le gestionnaire de cache est un mécanisme à chargement tardif, les options sont
traduites en modèle d'options utilisé pour instancier un objet de cache à la demande.

168
Zend_Application

Exemple 31. Exemple de configuration d'une ressource de gestionnaire de cache

Ci-dessous vous trouverez un extrait de fichier INI montrant comment


Zend_Cache_Manager peut être configuré. Le format est le préfixe de la ressource
Cachemanager (resources.cachemanager) suivi par le nom d'un modèle (par exemple
resources.cachemanager.database) et finalement suivi par une option habituelle de
Zend_Cache.

resources.cachemanager.database.frontend.name = Core
resources.cachemanager.database.frontend.options.lifetime = 7200
resources.cachemanager.database.frontend.options.automatic_serialization = true
resources.cachemanager.database.backend.name = File
resources.cachemanager.database.backend.options.cache_dir = "/path/to/cache"

Ensuite reécupérer ce cache à partir du gestionnaire est aussi simple que d'accéder à
l'instance du gestionnaire et d'appeler $cacheManager->getCache('database');.

6.2. Zend_Application_Resource_Db
Zend_Application_Resource_Db initialisera un adaptateur Zend_Db basé sur les options
qui lui seront fournis. Par défaut, il spécifiera aussi cet adaptateur comme adaptateur par défaut
à utiliser avec Zend_Db_Table. Si vous souhaitez utiliser simultanément de multiples bases de
données, vous pouvez utiliser la plugin de ressource Multidb.

Les clés de configuration suivantes sont reconnues :

• adapter : le type de l'adaptateur Zend_Db.

• params : un tableau associatif des paramètres de configuration à utiliser pour la récupération


de l'instance de l'adaptateur.

• isDefaultTableAdapter : spécifie si l'adaptateur est celui par défaut des tables.

Exemple 32. Exemple de configuration d'une ressource d'adaptateur de base


données

Voici un exmple de configuration INI qui peut-être utilisé pour initialiser une ressource de
base de données.

[production]
resources.db.adapter = "pdo_mysql"
resources.db.params.host = "localhost"
resources.db.params.username = "webuser"
resources.db.params.password = "XXXXXXX"
resources.db.params.dbname = "test"
resources.db.isDefaultTableAdapter = true

Récupération de l'instance de l'adaptateur


Si vous choisissez de ne pas utiliser l'adaptateur instancié avec cette ressource
comme adaptateur par défaut pour les tables, comment pourrez-vous récupérer
l'instance ?

Comme tout plugin de ressource, vous pouvez extraire votre plugin de ressource
de votre fichier d'initialisation :

$resource = $bootstrap->getPluginResource('db');

169
Zend_Application

Une fois que vous avez l'objet ressource, vous pouvez récupérer l'adaptateur de
base de données en utilisant la méthode getDbAdapter() :

$db = $resource->getDbAdapter();

6.3. Zend_Application_Resource_Frontcontroller
Probablement la ressource que vous allez le plus communément charger avec
Zend_Application sera la ressource de contrôleur frontal qui fournit la possibilité de
configurer Zend_Controller_Front. Cette ressource permet de spécifier n'importe quel
paramètre du contrôleur frontal, de spécifier les plugins à initialiser, et bien plus...

Une fois initialisée, la ressource assigne la propriété $frontController du fichier


d'initialisation à l'instance Zend_Controller_Front.

Les clés de configuration disponibles incluent les suivantes et sont sensibles à la casse :

• controllerDirectory : une chaîne de caractères spécifiant un seul dossier de contrôleurs, ou un


tableau associant un nom de module et un dossier de contrôleurs.

• moduleControllerDirectoryName : une chaîne de caractères indiquant un sous-dossier dans


ce module qui contient les contrôleurs.

• moduleDirectory : un dossier dans lequel tous les modules peuvent être trouvés.

• defaultControllerName : nom du contrôleur par défaut (normalement "index").

• defaultAction : nom de l'action par défaut (normalement "index").

• defaultModule : nom du module par défaut (normalement "default").

• baseUrl : URL de base explicite vers l'application (normalement auto-détecté).

• plugins : tableau de nom de classe de plugins de contrôleurs. La ressource instanciera chaque


classe (sans arguments de contructeur) et les enregistrera dans le contrôleur frontal.

• params : tableau de paires clés / valeurs à enregistrer dans le contrôleur frontal.

Si une clé non-connue est fournie, elle sera enregistrée comme paramètre du contrôleur frontal
en la fournissant à setParam().

Exemple 33. Exemple de configuration d'une ressource de contrôleur frontal

Voici un extrait de configuration INI montrant comment configurer la ressource de contrôleur


frontal.

[production]
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
resources.frontController.moduleControllerDirectoryName = "actions"
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
resources.frontController.defaultControllerName = "site"
resources.frontController.defaultAction = "home"
resources.frontController.defaultModule = "static"
resources.frontController.baseUrl = "/subdir"
resources.frontController.plugins.foo = "My_Plugin_Foo"
resources.frontController.plugins.bar = "My_Plugin_Bar"
resources.frontController.env = APPLICATION_ENV

170
Zend_Application

Exemple 34. Récupération de votre contrôleur frontal à partir de votre initialiseur

Une fois la ressource de contrôleur frontal initialisée, vous pouvez récupérer l'instance via
la propriété $frontController de votre initialiseur.

$bootstrap->bootstrap('frontController');
$front = $bootstrap->frontController;

6.4. Zend_Application_Resource_Layout
Zend_Application_Resource_Layout peut être utilisé pour configurer Zend_Layout. Les
options de configurations sont les mêmes que celles de Zend_Layout.

Exemple 35. Exemple de configuration de layout

Ci-dessous un exemple de code INI montrant comment configurer la ressource navigation.

resources.layout.layout = "NomDuLayoutParDefaut"
resources.layout.layoutPath = "/chemin/vers/layouts"

6.5. Zend_Application_Resource_Locale
Zend_Application_Resource_Locale can be used to set an application-wide locale which
is then used in all classes and components which work with localization or internationalization.

There are basically three usecases for the Locale Resource Plugin. Each of them should be used
depending on the applications need.

6.5.1. Autodetect the locale to use


Without specifying any options for Zend_Application_Resource_Locale, Zend_Locale
will detect the locale, which your application will use, automatically.

This detection works because your client sends the wished language within his HTTP request.
Normally the clients browser sends the languages he wants to see, and Zend_Locale uses
this information for detection.

But there are 2 problems with this approach:

• The browser could be setup to send no language

• The user could have manually set a locale which does not exist

In both cases Zend_Locale will fallback to other mechanism to detect the locale:

• When a locale has been set which does not exist, Zend_Locale tries to downgrade this string.

When, for example, en_ZZ is set it will automatically be degraded to en. In this case en will
be used as locale for your application.

• When the locale could also not be detected by downgrading, the locale of your environment
(web server) will be used. Most available environments from Web Hosters use en as locale.

• When the systems locale could not be detected Zend_Locale will use it's default locale, which
is set to en per default.

171
Zend_Application

For more informations about locale detection take a look into this chapter on Zend_Locale's
automatic detection.

6.5.2. Autodetect the locale and adding a own fallback


The above autodetection could lead to problems when the locale could not be
detected and you want to have another default locale than en. To prevent this,
Zend_Application_Resource_Locale allows you to set a own locale which will be used in
the case that the locale could not be detected.

Exemple 36. Autodetect locale and setting a fallback

The following snippet shows how to set a own default locale which will be used when the
client does not send a locale himself.

; Try to determine automatically first,


; if unsuccessful, use nl_NL as fallback.
resources.locale.default = "nl_NL"

6.5.3. Forcing a specific locale to use


Sometimes it is useful to define a single locale which has to be used. This can be done by using
the force option.

In this case this single locale will be used and the automatic detection is turned off.

Exemple 37. Defining a single locale to use

The following snippet shows how to set a single locale for your entire application.

; No matter what, the nl_NL locale will be used.


resources.locale.default = "nl_NL"
resources.locale.force = true

6.6. Zend_Application_Resource_Log
Zend_Application_Resource_Log permet d'instancier une instance Zend_Log avec
une nombre quelconque de rédacteurs. La configuration sera fournie à la méthode
Zend_Log::factory() vous permettant de spécifier les combinaisons de rédacteurs et
de filtres. L'instance de journalisation peut ensuite être récupérée à partir du bootstrap afin
d'enregistrer les événements.

Exemple 38. Exemple de configuration d'une ressource de journalisation

Ci-dessous, vous avez un extrait de fichier INI montrant comment configurer la ressource
de journalisation.

resources.log.stream.writerName = "Stream"
resources.log.stream.writerParams.stream = APPLICATION_PATH "/../data/logs/application.l
resources.log.stream.writerParams.mode = "a"
resources.log.stream.filterName = "Priority"
resources.log.stream.filterParams.priority = 4

Pour plus d'informations concernant les options disponibles, vous pouvez consulter la
documentation de Zend_Log::factory().

172
Zend_Application

6.7. Zend_Application_Resource_Multidb
Zend_Application_Resource_Multidb est utilisé pour initialiser de multiples connexions
vers des bases de données. Vous pouvez utiliser les mêmes options qu'avec le plugin de
ressource Db. Cependant, pour spécifier une connexion par défaut, vous pouvez aussi utiliser
la directive 'default'.

Exemple 39. Paramétrer de multiples connexions vers des bases de données

Ci-dessous vous avez un exemple de configuration INI montrant l'initialisation de deux


connexions.

[production]
resources.multidb.db1.adapter = "pdo_mysql"
resources.multidb.db1.host = "localhost"
resources.multidb.db1.username = "webuser"
resources.multidb.db1.password = "XXXX"
resources.multidb.db1.dbname = "db1"

resources.multidb.db2.adapter = "pdo_pgsql"
resources.multidb.db2.host = "example.com"
resources.multidb.db2.username = "dba"
resources.multidb.db2.password = "notthatpublic"
resources.multidb.db2.dbname = "db2"
resources.multidb.db2.default = true

Exemple 40. Récupérer un adaptateur de bases de données spécifique

Lorsque vous utilisez ce plugin de ressource, vous aurez sans doute besoin de récupérer un
adaptateur spécifique. Ceci peut être réalisé en utilisant la méthode getDb(). La méthode
getDb() retourne l'instance d'une classe qui étend Zend_Db_Adapter_Abstract. Si
vous n'avez pas activé un adaptateur par défaut, une exception sera levée lorsque vous
appelerez cette méthode sans lui fournir de paramètre.

$resource = $bootstrap->getPluginResource('multidb');
$db1 = $resource->getDb('db1');
$db2 = $resource->getDb('db2');
$defaultDb = $resource->getDb();

Exemple 41. Récupérer l'adaptateur de base de données par défaut

De plus, vous pouvez récupérer l'adaptateur par défaut en utilisant la méthode


getDefaultDb(). Si vous n'avez pas activé d'adaptateur par défaut, le premier configuré
sera retourné. Si vous spécifiez FALSE en tant que premier paramètre, alors vous récupérez
NULL si adaptateur par défaut n'est configuré.

Ci-dessous vous avez un exemple qui suppose que le plugin de ressource Multidb a été
configuré avec l'exemple INI ci-dessus :

$resource = $bootstrap->getPluginResource('multidb');
$db2 = $resource->getDefaultDb();

// Même config, mais maintenant sans adaptateur par défaut :


$db1 = $resource->getDefaultDb();
$null = $resource->getDefaultDb(false); // null

173
Zend_Application

6.8. Zend_Application_Resource_Mail
Zend_Application_Resource_Mail peut être utilisé pour instancier un transport pour
Zend_Mail ou pour paramétrer le nom par défaut et l'adresse, ainsi que le nom et l'adresse
de réponse par défaut.

Lors de l'instanciation d'un transport, il est automatiquement enregistré avec Zend_Mail.


Cependant en paramétrant la directive transport.register à FALSE, ce comportement n'apparait
pas.

Exemple 42. Exemple de configuration de la ressource Mail

Ci-dessous, vous avez un extrait d'un fichier INI montrant comment configurer le plugin de
ressource Mail.

resources.mail.transport.type = smtp
resources.mail.transport.host = "smtp.example.com"
resources.mail.transport.auth = login
resources.mail.transport.username = myUsername
resources.mail.transport.password = myPassword
resources.mail.transport.register = true ; True by default
resources.mail.defaultFrom.email = john@example.com
resources.mail.defaultFrom.name = "John Doe"
resources.mail.defaultReplyTo.email = Jane@example.com
resources.mail.defaultReplyTo.name = "Jane Doe"

6.9. Zend_Application_Resource_Modules
Zend_Application_Resource_Modules est utilisé pour initialiser les modules de votre
application. Si votre module possède un fichier Bootstrap.php à sa racine, et que celui-ci
contient une classe nommée Module_Bootstrap (où "Module" est le nom du module), alors
celle-ci sera utiliser pour lancer votre module.

Par défaut, une instance de Zend_Application_Module_Autoloader sera créée pour le


module en question, utilisant le nom du module et son dossier pour s'initialiser.

Puisque la ressource Modules ne prend pas d'argument par défaut, pour l'activer via la
configuration, vous devez créer un tableau vide. Since the Modules resource does not take any
arguments by default, in order to enable it via configuration, you need to create it as an empty
array. En configuration de type INI cela ressemblerait à ceci :

resources.modules[] =

En configuration de type XML cela ressemblerait à ceci :

<resources>
<modules>
<!-- Emplacement pour s'assurer qu'un tableau est créé -->
<placeholder />
</modules>
</resources>

En utilisant un tableau PHP, il suffit de le créer comme un tableau vide :

$options = array(
'resources' => array(

174
Zend_Application

'modules' => array()


)
);

Dépendance envers le contrôleur frontal


La ressource Modules possède une dépendance envers la ressource Front
Controller. Vous pouvez bien sûr proposer votre propre implémentation de
la ressource du contrôleur frontal, si tant est que sa classe se termine par
"Frontcontroller", ou, si vous choisissez d'utiliser une méthode d'initialisation,
celle-ci doit être "_initFrontController".

Exemple 43. Configurer les modules

Vous pouvez spécifier la configuration en utilisant le nom du module comme préfixe de


section dans le fichier de configuration.

Par exemple, supposons que vous possédiez un module appelé "news". Voici des exemples
INI et XML de fichiers de configuration pour ce module.

[production]
news.resources.db.adapter = "pdo_mysql"
news.resources.db.params.host = "localhost"
news.resources.db.params.username = "webuser"
news.resources.db.params.password = "XXXXXXX"
news.resources.db.params.dbname = "news"

<?xml version="1.0"?>
<config>
<production>
<news>
<resources>
<db>
<adapter>pdo_mysql</adapter>
<params>
<host>localhost</host>
<username>webuser</username>
<password>XXXXXXX</password>
<dbname>news</dbname>
</params>
<isDefaultAdapter>true</isDefaultAdapter>
</db>
</resources>
</news>
</production>
</config>

Exemple 44. Récupérer un bootstrap de module

Il peut être utile de pouvoir récupérer l'objet bootstrap de votre module, pour en exécuter par
exemple des méthodes spécifiques, ou encore pour en récupérer l'autoloader. La méthode
getExecutedBootstraps() peut être utilisée dans ce cas là, elle s'applique sur un objet
ressource de modules.

$resource = $bootstrap->getPluginResource('modules');
$moduleBootstraps = $resource->getExecutedBootstraps();
$newsBootstrap = $moduleBootstraps['news'];

175
Zend_Application

6.10. Zend_Application_Resource_Navigation
Zend_Application_Resource_Navigation peut être utilisé pour configurer une instance
de Zend_Navigation. Les options de configurations sont les mêmes que celles de
Zend_Navigation.

Une fois configuré, l'objet de navigation est ajouté à Zend_View_Helper_Navigation par


défaut.

Exemple 45. Exemple de configuration de la ressource Navigation

Voici un exemple de syntaxe INI concernant la configuration de la ressource navigation.

resources.navigation.pages.page1.label = "Nom de la première page"


resources.navigation.pages.page1.route = "Route concernant la première page"

; Page 2 est une sous-page de page 1


resources.navigation.pages.page1.pages.page2.type = "Zend_Navigation_Page_Uri"
resources.navigation.pages.page1.pages.page2.label = "Nom de la seconde page"
resources.navigation.pages.page1.pages.page2.uri = "/url/to/page/2"

6.11. Zend_Application_Resource_Router
Zend_Application_Resource_Router est utilisé pour configurer le routeur enregistré
grâce aux options du contrôleur frontal. Les options sont identiques à celles de
Zend_Controller_Router_Route.

Exemple 46. Exemple de configuration du routeur

Voici l'exemple d'un fichier INI qui configure une ressource de type routeur.

resources.router.routes.route_id.route = "/login"
resources.router.routes.route_id.defaults.module = "user"
resources.router.routes.route_id.defaults.controller = "login"
resources.router.routes.route_id.defaults.action = "index"

; Optionellement, un séparateur de chaines peut être précisé:


resources.router.chainNameSeparator = "_"

Pour plus d'informations sur le séparateur de chaines, voyez sa section.

6.12. Zend_Application_Resource_Session
Zend_Application_Resource_Session est utilisé pour configurer Zend_Session et
éventuellement un support de sauvegarde sessions (SaveHandler).

Pour créer un support de sauvegarde session, passez la clé saveHandler (case insensitive) à la
ressource. La valeur d'une telle option peut être :

• String : cette chaîne indique le nom d'une classe implémentant


Zend_Session_SaveHandler_Interface.

• Array : avec les clés "class" et optionnellement "options", indiquant une classe à instancier
(implémentant Zend_Session_SaveHandler_Interface) et un tableau d'options à
passer à son constructeur.

176
Zend_Application

• Zend_Session_SaveHandler_Interface : un objet implémentant cette interface.

Toute autre option non reconnue sera alors passée à Zend_Session::setOptions() pour
configurer Zend_Session.

Exemple 47. Exemple de ressource session

Voici un fichier INI permettant de configurer une session via la ressource.


Il affecte des options à Zend_Session et configure une instance de
Zend_Session_SaveHandler_DbTable.

resources.session.save_path = APPLICATION_PATH "/../data/session"


resources.session.use_only_cookies = true
resources.session.remember_me_seconds = 864000
resources.session.saveHandler.class = "Zend_Session_SaveHandler_DbTable"
resources.session.saveHandler.options.name = "session"
resources.session.saveHandler.options.primary.session_id = "session_id"
resources.session.saveHandler.options.primary.save_path = "save_path"
resources.session.saveHandler.options.primary.name = "name"
resources.session.saveHandler.options.primaryAssignment.sessionId = "sessionId"
resources.session.saveHandler.options.primaryAssignment.sessionSavePath = "sessionSavePa
resources.session.saveHandler.options.primaryAssignment.sessionName = "sessionName"
resources.session.saveHandler.options.modifiedColumn = "modified"
resources.session.saveHandler.options.dataColumn = "session_data"
resources.session.saveHandler.options.lifetimeColumn = "lifetime"

Configurez votre base de données avant !


Si vous configurez le gestionnaire Zend_Session_SaveHandler_DbTable,
vous devez configurer votre base de données avant. Pour cela, servez vous de
la ressource Db et assurez vous que la clé "resources.db" apparaît bien avant
la clé "resources.session". Vous pouvez aussi utiliser votre propre ressource qui
initialise la base de données et affecte l'adaptateur Zend_Db_Table par défaut.

6.13. Zend_Application_Resource_View
Zend_Application_Resource_View peut être utilisée pour configurer une instance
Zend_View instance. Les clés de configurations sont celles de Zend_View.

Dès que l'instance est configurée, ceci crée une instace de


Zend_Controller_Action_Helper_ViewRenderer et enregistre le ViewRenderer avec
Zend_Controller_Action_HelperBroker - à partir duquel vous pourrez le récupérer plus
tard.

Exemple 48. Exemple de configuration d'une ressource de vue

Voici un extrait de configuration INI montrant comment configurer une ressource de vue.

resources.view.encoding = "UTF-8"
resources.view.basePath = APPLICATION_PATH "/views/scripts"

177
Zend_Auth
1. Introduction
Zend_Auth fournit une API pour l'authentification et inclut des adaptateurs concrets
d'authentification pour les cas les plus courants.

Zend_Auth est uniquement concerné par le processus d'authentification et non pas par
le processus d'autorisation. L'authentification est définie de manière lâche (souple) afin de
déterminer si une entité donnée est bien celle qu'elle prétend être (c.-à-d. identification), sur la
base d'identifiants fournis. L'autorisation, l'action de décider si une entité donnée peut accéder
à d'autres entités et / ou exécuter des opérations sur celles-ci ne fait pas partie des prérogatives
de Zend_Auth. Pour plus d'informations sur les autorisations et le contrôle d'accès via Zend
Framework, voyez Zend_Acl.

La classe Zend_Auth inclut un singleton - uniquement une instance de la


classe est disponible - à travers la méthode statique getInstance(). Celle ci
utilise un opérateur new et le mot-clé clone ne fonctionnera pas avec la classe
Zend_Auth, utilisez plutôt getInstance().

1.1. Adaptateurs
Un adaptateur Zend_Auth est utilisé pour authentifier via un service particulier d'authentification,
comme LDAP, RDBMS ou un stockage basé sur des fichiers. Les différents adaptateurs peuvent
posséder des options et des comportements très divers. Cependant, quelques méthodes de
base leur sont communes. Par exemple, accepter des éléments d'authentification (incluant
une identité prétendue), authentifier et retourner un résultat sont des éléments communs aux
adaptateurs Zend_Auth.

Chaque classe d'adaptateur Zend_Auth implémente Zend_Auth_Adapter_Interface.


Cette interface définit une méthode, authenticate(), celle-ci est implémentée par une classe
adaptateur à fin de réaliser l'authentification. Chaque classe adaptateur doit être préparée avant
tout appel de authenticate(). Cela implique que chaque adaptateur fournisse la possibilité
de définir des éléments d'authentification (par exemple identifiant et mot de passe) et de définir
des valeurs pour les options spécifiques de l'adaptateur, tels que les paramètres de connexion
à une base de données pour un adaptateur qui en fait usage.

L'exemple suivant est un adaptateur d'authentification qui requiert un identifiant et un mot de


passe. D'autres détails, tel que la manière d'interroger le service d'authentification, ont été omis
par souci de clarté :

class MonAdaptateurAuth implements Zend_Auth_Adapter_Interface


{
/**
* Définition de l'identifiant et du mot de passe
* pour authentification
*
* @return void
*/
public function __construct($identifiant, $motdepasse)
{

178
Zend_Auth

// ...
}

/**
* Réalise une tentative d'authentification
*
* @throws Zend_Auth_Adapter_Exception Si l'authentification
* ne peut pas être réalisée
* @return Zend_Auth_Result
*/
public function authenticate()
{
// ...
}
}

Comme indiqué dans la documentation "docblock", authenticate() doit retourner une


instance de Zend_Auth_Result (ou d'une classe dérivée de Zend_Auth_Result). Si
pour quelque raison que ce soit, la requête d'authentification ne peut pas être réalisée,
authenticate() retournera une exception dérivée de Zend_Auth_Adapter_Exception.

1.2. Résultats
Les adaptateurs Zend_Auth retournent une instance de Zend_Auth_Result via
authenticate() de manière à présenter les résultats d'une tentative d'authentification. Les
adaptateurs alimentent l'objet Zend_Auth_Result lors de sa construction, de manière à ce que
les quatre méthodes suivantes fournissent de base un lot d'opérations communes aux résultats
des adaptateurs Zend_Auth :

• isValid() : retourne TRUE si et seulement si le résultat représente une tentative réussie


d'authentification.

• getCode() : retourne une constante Zend_Auth_Result qui détermine le type de retour


accepté ou refusé (N.D.T. : voir tableau ci dessous). Cela peut être utilisé pour les
développeurs voulant distinguer en amont les différents types de résultat. Il est possible
d'avoir des statistiques détaillées, par exemple. Une autre utilisation est la personnalisation du
message de retour au client. Attention cependant à ne pas trop donner de détails aux clients
pour des raisons de sécurité. Pour plus de détails, consultez les notes ci-dessous.

• getIdentity() : retourne l'identité de la tentative d'authentification.

• getMessages() : retourne un tableau de messages relatifs à une tentative infructueuse


d'authentification.

Un développeur peut connecter le résultat de l'authentification avec des opérations spécifiques.


Certaines opérations développées peuvent bloquer le compte après plusieurs refus du mot de
passe, bannir une adresse IP après plusieurs essais sur des comptes inexistants ou fournir un
message spécifique à l'utilisateur final. Les codes suivants sont disponibles :

Zend_Auth_Result::SUCCESS
Zend_Auth_Result::FAILURE
Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND
Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS
Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID
Zend_Auth_Result::FAILURE_UNCATEGORIZED

179
Zend_Auth

L'exemple suivant illustre comment utiliser le retour :

// A l'intérieur de la méthode AuthController / loginAction


$resultat = $this->_auth->authenticate($adapter);

switch ($resultat->getCode()) {

case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND:
/** l'identifiant n'existe pas **/
break;

case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
/** mauvaise authentification **/
break;

case Zend_Auth_Result::SUCCESS:
/** authentification acceptée **/
break;

default:
/** autres cas **/
break;
}

1.3. Persistance d'identité


Authentifier une requête qui contient des paramètres d'authentification est utile en soi, mais il est
également important de permettre le maintien de l'identité authentifiée sans avoir à représenter
ces paramètres d'authentification à chaque requête.

HTTP est un protocole sans état, cependant, des techniques telles que les cookies ou les
sessions ont été développées de manière à faciliter le maintien d'un contexte lors de multiples
requêtes dans les applications Web.

1.3.1. Persistance par défaut dans une session PHP

Par défaut, Zend_Auth fournit un stockage persistant de l'identité, après une


authentification réussie, via les sessions PHP. Après une authentification réussie,
Zend_Auth::authenticate() conserve l'identité résultant de l'authentification dans un
stockage persistant. A moins d'une configuration particulière, Zend_Auth utilise une
classe de stockage nommée Zend_Auth_Storage_Session, qui utilise Zend_Session.
Une classe personnalisée peut être utilisée pour fournir un objet implémentant
Zend_Auth_Storage_Interface à Zend_Auth::setStorage().

Si la persistance automatique de l'identité n'est pas souhaitable dans un cas


particulier, alors le développeur peut renoncer à utiliser la classe Zend_Auth et
préférer utiliser directement une classe adaptateur.

180
Zend_Auth

Exemple 49. Changer l'espace de nommage de la session

Zend_Auth_Storage_Session utilise un espace de nommage de Zend_Auth.


Cet espace peut être écrit en passant les valeurs au constructeur de
Zend_Auth_Storage_Session, et ces valeurs sont passées en interne au constructeur
de Zend_Session_Namespace. Cela doit être fait avant l'authentification, et avant que
Zend_Auth::authenticate() ait accompli le stockage automatique de l'identité.

// Sauver une référence du singleton, instance de Zend_Auth


$auth = Zend_Auth::getInstance();

// Utiliser 'unEspaceDeNommage' instance de 'Zend_Auth'


$auth->setStorage(new Zend_Auth_Storage_Session('unEspaceDeNommage'));

/**
* @todo Paramètrage de l'adaptateur d'authentification :
* $authAdaptateur
*/

// authentification, sauvegarde du résultat


// et stockage du résultat en cas de succès
$resultat = $auth->authenticate($authAdaptateur);

1.3.2. Installer un stockage personnalisé

Parfois les développeurs ont besoin d'utiliser un comportement de persistance d'identité


différent de celui fourni par Zend_Auth_Storage_Session. Dans ces cas, les développeurs
implémentent simplement Zend_Auth_Storage_Interface et fournissent t une instance de
la classe à Zend_Auth::setStorage().

181
class MonStockage implements Zend_Auth_Storage_Interface
{
Pour utiliser une classe de stockage d'identité persistante autre que
/** Zend_Auth
Zend_Auth_Storage_Session, le développeur commence par implémenter
* Retourne true si et seulement si le stockage est vide
Zend_Auth_Storage_Interface
* :
* @throws Zend_Auth_Storage_Exception S'il est impossible de déterminer
Exemple
* 50. Utiliser une classe de stockage personnalisée
si le stockage est vide
* @return boolean
*/
public function isEmpty()
{
/**
* @todo implémentation
*/
}

/**
* Retourne le contenu du stockage
*
* Comportement à définir si le stockage est vide.
*
* @throws Zend_Auth_Storage_Exception Si la lecture du stockage
* est impossible
* @return mixed
*/
public function read()
{
/**
* @todo implémentation
*/
}

/**
* Ecrit $contents dans le stockage
*
* @param mixed $contents
* @throws Zend_Auth_Storage_Exception Si l'écriture de $contents
* est impossible
* @return void
*/
public function write($contents)
{
/**
* @todo implementation
*/
}

/**
* RAZ du stockage
*
* @throws Zend_Auth_Storage_Exception Si la remise à zéro (RAZ)
* est impossible
* @return void
*/
// Définit function
public la classeclear()
personnalisée à utiliser
{
Zend_Auth::getInstance()->setStorage(new MonStockage());
/**
Ensuite la *classe
@todopersonnalisée est invoquée, avant la requête d'authentification, avec
implementation
/**
Zend_Auth::setStorage()
*/ :
* @todo Paramètrage de l'adaptateur d'authentification :
* } $authAdaptateur
*/
}
// Authentification, sauvegarde et
// persistance du résultat en cas de succès.
$result = Zend_Auth::getInstance()->authenticate($authAdaptateur);

182
Zend_Auth

1.4. Utilisation de Zend_Auth


Deux manières d'utiliser les adaptateurs Zend_Auth sont proposées :

1. indirectement, via Zend_Auth::authenticate() ;

2. directement, via la méthode authenticate() de l'adaptateur.

L'exemple suivant illustre la manière d'utiliser un adaptateur Zend_Auth de manière indirecte


via l'utilisation de la classe Zend_Auth :

// Obtention d'une référence de l'instance du Singleton de Zend_Auth


$auth = Zend_Auth::getInstance();

// Définition de l'adaptateur d'authentification


$authAdaptateur = new MonAdaptateurAuth($identifiant, $motdepasse);

// Tentative d'authentification et stockage du résultat


$resultat = $auth->authenticate($authAdaptateur);

if (!$resultat->isValid()) {
// Echec de l'authentification ; afficher pourquoi
foreach ($resultat->getMessages() as $message) {
echo "$message\n";
}
} else {
// Authentification réussie ; l'identité ($identifiant) est
// stockée dans la session
// $resultat->getIdentity() === $auth->getIdentity()
// $resultat->getIdentity() === $identifiant
}

Une fois la tentative d'authentification réalisée, tel que montré ci-dessus, il est très simple de
vérifier si une identité correctement authentifiée existe :

$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
// l'identité existe ; on la récupère
$identite = $auth->getIdentity();
}

Pour retirer une identité du stockage persistant, utilisez simplement la méthode


clearIdentity(). A utiliser typiquement pour implémenter une opération de déconnexion
d'une application :

Zend_Auth::getInstance()->clearIdentity();

Quand l'utilisation automatique du stockage persistant n'est pas appropriée, le développeur peut
simplement contourner l'utilisation de la classe Zend_Auth en utilisant directement une classe
adaptateur. L'usage direct d'une classe adaptateur implique de configurer et préparer l'objet
adaptateur et d'appeler ensuite sa méthode authenticate(). Les détails spécifiques à un
adaptateur sont décrits dans la documentation de chacun d'entre-eux. L'exemple suivant utilise
directement MonAdaptateurAuth :

// Définition de l'adaptateur d'authentification

183
Zend_Auth

$authAdaptateur = new MonAdaptateurAuth($identifiant, $motdepasse);

// Tentative d'authentification, stockage du résultat


$resultat = $authAdaptateur->authenticate();

if (!$resultat->isValid()) {
// échec de l'authentification ; afficher pourquoi
foreach ($resultat->getMessages() as $message) {
echo "$message\n";
}
} else {
// Authentification réussie
// $resultat->getIdentity() === $identifiant
}

2. Authentification avec une table de base de données


2.1. Introduction
Zend_Auth_Adapter_DbTable fournit la possibilité d'authentifier sur la base de crédits
stockés dans une table de base de données. Comme Zend_Auth_Adapter_DbTable requiert
qu'une instance de Zend_Db_Adapter_Abstract soit fournie à son constructeur, chaque
instance est liée à une connexion de base de données particulière. Les autres options de
configuration peuvent être réglées grâce au constructeur ou au travers de différentes méthodes,
une pour chaque option.

Les options de configuration disponibles incluent :

• tableName : il s'agit du nom de la table dans la base de données qui contient les crédits
d'authentification, et envers laquelle la requête d'authentification sera réalisée.

• identityColumn : il s'agit du nom de la colonne dans la table utilisée pour représenter l'identité.
La colonne d'identité doit contenir une valeur unique, comme un "username" ou une adresse
émail.

• credentialColumn : il s'agit du nom de la colonne dans la table utilisée pour représenter le


crédit. Dans le cas d'une simple authentification par identité / mot de passe, la valeur de crédit
correspond au mot de passe. Voir aussi l'option credentialTreatment.

• credentialTreatment : dans la plupart des cas, les mots de passe et autres données sensibles
sont cryptés, hachés, encodés, masqués, ou sinon traités à travers une fonction ou un
algorithme. En spécifiant un traitement paramétrable de chaîne avec cette méthode, comme
MD5(?) ou PASSWORD(?), un développeur peut appliquer un code SQL arbitraire sur les
données de crédit fournies. Comme ces fonctions sont spécifiques à chaque gestionnaire de
base de données (SGBD), vérifiez le manuel de la base de données pour vérifier la disponibilité
de ces fonctions dans votre système.

184
Zend_Auth

Comme expliqué dans l'introduction, le constructeur de Zend_Auth_Adapter_DbTable


requiert une instance
Exemple de Zend_Db_Adapter_Abstract
51. Utilisation basique qui est utilisée comme connexion
Le
à la code suivant
base de créeà laquelle
données un adaptateur pour
l'instance une base d'authentification
d'adaptateur de données en est mémoire, créetout,
liée. Avant un
schéma avecàune
la connexion tablede
la base unique,
donnée et devrait
insère une
être ligne
crée. sur laquelle nous pouvons réaliser une
requête
// Créed'authentification
une connexion plus tard. Cet
de base de exemple
données requiert
SQLite que l'extension PDO SQLite soit
en mémoire
disponible :
$dbAdapter = new Zend_Db_Adapter_Pdo_Sqlite(array('dbname' =>
':memory:'));

// Construit une requête de création de table


$sqlCreate = 'CREATE TABLE [users] ( '
. '[id] INTEGER NOT NULL PRIMARY KEY, '
. '[username] VARCHAR(50) UNIQUE NOT NULL, '
. '[password] VARCHAR(32) NULL, '
. '[real_name] VARCHAR(150) NULL)';

// Crée la table de crédits d'authentification


$dbAdapter->query($sqlCreate);

// Construit la requête pour insérer une ligne pour laquelle


// l'authentification pourra réussir
$sqlInsert = "INSERT INTO users (username, password, real_name) "
. "VALUES ('my_username', 'my_password', 'My Real Name')";

Avec
// une connexion
Insertion de base de données et des données disponibles dans la table,
des données
$dbAdapter->query($sqlInsert);
une instance de Zend_Auth_Adapter_DbTable peut être créée. Les valeurs d'options
de
// configuration
Configure une peuvent être fournies
instance avec desauparamètres
constructeurdeouconstructeur
en tant que paramètres
... aux
méthodes de réglage après l'instanciation :
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter,
'users',
'username',
'password');

// ... ou configure l'instance avec des méthodes de réglage


$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
$authAdapter->setTableName('users')
A cet instant, l'instance de l'adaptateur d'authentification est prête à recevoir des requêtes
->setIdentityColumn('username')
->setCredentialColumn('password');
d'authentification.
// Règle les valeurs led'entrées
Dans but de réaliser une requête d'authentification, les valeurs des
des crédits
crédits requêtés sont fournies à l'adaptateur
// (en général, à partir d'un formulaire avant d'appeler la méthode authenticate() :
d'enregistrement)
$authAdapter->setIdentity('my_username')
->setCredential('my_password');

En plus
// de la disponibilité
Réalise la requêtede la méthode getIdentity()
d'authentification, pour récupérer
et sauvegarde l'objet du résultat
le résultat
$result = $authAdapter->authenticate();
d'authentification, Zend_Auth_Adapter_DbTable supporte aussi la récupération de la
// Affiche l'identité
ligne
echo de la table qui a réussi l'authentification
$result->getIdentity() . "\n\n"; :

// Affiche la ligne de résultat


print_r($authAdapter->getResultRowObject());

/* Affiche:
my_username

Array
(
[id] => 1
[username] => my_username
[password] => my_password
[real_name] => My Real Name
Puisque la ligne de la table contient la valeur de crédit, il est important de garantir ces valeurs
)
*/
contre l'accès fortuit.

185
Zend_Auth

2.2. Utilisation avancée : maintenir persistant l'objet de résultat


DbTable
Par défaut, Zend_Auth_Adapter_DbTable retourne l'identité fournie à l'objet Auth
en cas d'authentification couronnée de succès. Un autre scénario d'utilisation, où les
développeurs veulent stocker dans le mécanisme de stockage persistant du Zend_Auth
un objet d'identité contenant d'autres informations utiles, est résolu en utilisant la méthode
getResultRowObject() retournant un objet stdClass. Le petit bout de code suivant illustre
cette utilisation :

// authentifie avec Zend_Auth_Adapter_DbTable


$result = $this->_auth->authenticate($adapter);

if ($result->isValid()) {

// stocke l'identité comme objet dans lequel seulement username et


// real_name sont retournés
$storage = $this->_auth->getStorage();
$storage->write($adapter->getResultRowObject(array('username',
'real_name')));

// stocke l'identité comme objet dans lequel la colonne password


// a été omis
$storage->write($adapter->getResultRowObject(null, 'password'));

/* ... */

} else {

/* ... */

2.3. Utilisation avancée par l'exemple


Bien que le but initial de Zend_Auth (et par extension celui de
Zend_Auth_Adapter_DbTable) est principalement l'authentification et non l'autorisation (ou
contrôle d'accès), il existe quelques exemples et problèmes qui franchissent la limite des
domaines auxquels ils appartiennent. Selon la façon dont vous avez décidé d'expliquer votre
problème, il semble parfois raisonnable de résoudre ce qui pourrait ressembler à un problème
d'autorisation dans l'adaptateur d'authentification.

Ceci étant dit, Zend_Auth_Adapter_DbTable possède des mécanismes qui sont construits
de telle sorte qu'ils peuvent être démultipliés pour ajouter des contrôles supplémentaires au
moment de l'authentification pour résoudre quelques problèmes communs d'utilisateur.

// La valeur du champs "etat" d'un compte


// ne doit pas être égal à "compromis"
$adapter = new Zend_Auth_Adapter_DbTable($db,
'utilisateurs',
'login',
'password',
'MD5(?) AND etat != "compromis"');

// La valeur du champs "actif" d'un compte


// doit être égal à "TRUE"
$adapter = new Zend_Auth_Adapter_DbTable($db,

186
Zend_Auth

'utilisateurs',
'login',
'password',
'MD5(?) AND actif = "TRUE"');

Un autre scénario possible est l'implantation d'un mécanisme de "salting". "Salting" est un terme
se référant une technique qui peut fortement améliorer la sécurité de votre application. C'est
basé sur l'idée que concaténer une chaîne aléatoire à tout mot de passe rend impossible la
réussite d'une attaque de type "brute force" sur la base de données en utilisant des valeurs
préalablement hashées issues d'un dictionnaire.

Par conséquent nous devons modifier notre table pour stocker notre chaîne de "salt" aléatoire :

$sqlAlter = "ALTER TABLE [users] "


. "ADD COLUMN [password_salt] "
. "AFTER [password]";

$dbAdapter->query($sqlAlter);

Voici une méthode simple pour générer une chaîne aléatoire pour chaque utilisateur à leur
enregistrement :

for ($i = 0; $i < 50; $i++)


{
$dynamicSalt .= chr(rand(33, 126));
}

Et maintenant, construisons l'adaptateur :

$adapter = new Zend_Auth_Adapter_DbTable(


$db,
'users',
'username',
'password',
"MD5(CONCAT('"
. Zend_Registry::get('staticSalt')
. "', ?, password_salt))"
);

Vous pouvez encore améliorer la sécurité en utilisant une chaîne de "salt"


statique codée en dur dans votre application. Dans le cas ou la base de données
est compromise (par exemple par une attaque de type injection SQL) mais que
votre serveur Web est intact, les données sont inutilisables par l'attaquant.

Une autre alternative est d'utiliser la méthode getDbSelect() de la classe


Zend_Auth_Adapter_DbTable après la construction de l'adaptateur. Cette méthode
retournera une instance d'objet Zend_Db_Select utilisée pour réaliser la routine
authenticate(). Il est important de noter que cette méthode retournera toujours le même
objet, que la méthode authenticate() a été appelée ou non. Cet objet ne comportera aucune
information d'identité ou de crédit puisque celles-ci sont placées dans l'objet select au moment
de authenticate().

Un exemple de situation nécessitant l'utilisation de la méthode getDbSelect() serait de vérifier


le statut d'un utilisateur, en d'autres termes pour voir si le compte d'un utilisateur est activé.

// En continuant avec l'exemple ci-dessus

187
Zend_Auth

$adapter = new Zend_Auth_Adapter_DbTable(


$db,
'users',
'username',
'password',
'MD5(?)'
);

// Récupérer l'objet select (par référence)


$select = $adapter->getDbSelect();
$select->where('active = "TRUE"');

// Authentification, ceci s'assure que users.active = TRUE


$adapter->authenticate();

3. Authentification "Digest"
3.1. Introduction
L'authentification "Digest" est une méthode d'authentification HTTP qui améliore
l'authentification basique en fournissant un moyen d'authentifier sans avoir à transmettre le mot
de passe en clair sur le réseau.

Cet adaptateur permet l'authentification en utilisant un fichier texte contenant des lignes
comportant les éléments de base d'une authentification Digest :

• identifiant, tel que "utilisateur.jean"

• domaine, tel que "Zone administrative"

• hachage MD55 d'un identifiant, domaine et mot de passe, séparés par des caractères deux-
points.

Les éléments ci-dessus sont séparés par des caractères deux-points, comme dans l'exemple
suivant (dans lequel le mot de passe est "unMotdepasse") :

unUtilisateur:Un domaine:3b17d7f3a9374666e892cbce58aa724f

3.2. Spécifications
L'adaptateur d'authentification Digest, Zend_Auth_Adapter_Digest requiert plusieurs
paramètres d'entrée :

• filename : fichier utilisé pour réaliser l'authentification

• realm : domaine d'authentification Digest ("realm" en anglais)

• username : identifiant d'authentification Digest

• password : mot de passe pour l'identifiant dans le domaine

Ces paramètres doivent être définis avant l'appel de authenticate().

3.3. Identité
L'adaptateur d'authentification Digest retourne un objet Zend_Auth_Result, lequel a été
alimenté avec l'identité sous la forme d'un tableau ayant pour clés realm (domaine) et username

188
Zend_Auth

(identifiant). Les valeurs respectives associées à ces clés correspondent aux valeurs définies
avant l'appel à authenticate().

$adaptateur = new Zend_Auth_Adapter_Digest($nomFichier,


$domaine,
$identifiant,
$motdepasse);

$resultat = $adaptateur->authenticate();

$identite = $resultat->getIdentity();

print_r($identite);

/*
Array
(
[realm] => Un domaine
[username] => unUtilisateur
)
*/

4. Adaptateur d'authentification HTTP


4.1. Introduction
Zend_Auth_Adapter_Http fournit une implémentation des authentifications HTTP Basicet
Digest, au regard de la norme RFC-2617. Digest est une méthode d'authentification HTTP
basée sur Basic, mais qui augmente la sécurité en fournissant un moyen d'authentification sans
transmettre le mot de passe en clair, sur le réseau.

Caractéristiques principales :

• Support des méthodes Basic et Digest ;

• Propose tous les des schémas de challenge, le client peut répondre avec le schéma qu'il
supporte ;

• Support de l'authentification Proxy ;

• Inclus le support d'authentification de type fichier, et fournit une interface pour créer son propre
support, comme une base de données.

Il y a quelques caractéristiques de la RFC-2617 qui ne sont pas encore supportées :

• Le "Nonce tracking", mécanisme qui évite les attaques par répétitions ;

• Authentification avec vérification d'intégrité ("auth-int") ;

• En-tête HTTP "Authentication-Info".

4.2. Fonctionnement
Cette adaptateur utilise 2 sous-composants, la classe d'authentification HTTP elle-même et
des "Résolveurs." La classe d'authentification HTTP encapsule la logique de commande des
authentifications Basic et Digest. Elle utilise aussi un résolveur pour chercher les identifiants sur
un disque (fichier texte par défaut), et les analyser. Ils sont alors comparés aux valeurs envoyées
par le client pour déterminer une éventuelle correspondance.

189
Zend_Auth

4.3. Options de configuration


La classe Zend_Auth_Adapter_Http requière un tableau de configuration lors de sa
construction. Il y a plusieurs options de configuration disponibles, dont certaines requises :

Tableau 9. Liste des options de configuration

Nom Requise (?) Description


accept_schemes Oui Détermine les schémas
d'authentification que
l'adaptateur va accepter du
client. Ce doit être une liste
séparée par des espaces,
contenant 'basic' et / ou
'digest'.
realm Oui Fournit le nom de
l'authentification ("realm") ;
chaque nom d'utilisateur
doit être unique, par nom
d'authentification.
digest_domains Oui lorsque accept_schemes Liste d'URI, séparées
contient "digest" d'espace, pour lesquelles
la même information
d'authentification est valide.
Les URI peuvent pointer vers
différents serveurs.
nonce_timeout Oui lorsque accept_schemes Nombre de seconde pour
contient "digest" la validité du jeton
d'authentification. Voyez les
notes ci-dessous.
proxy_auth Non Désactivé par défaut. Activez
le pour effectuer une
authentification via un Proxy.

L'implémentation actuelle du nonce_timeout a des effets intéressants. Ce


paramètre doit déterminer le temps de validité d'un jeton, autrement dit : le temps
d'acceptation d'un client. Par exemple, une valeur de 3600 aura pour effet de
commander à l'adaptateur le rappel des informations d'identification du client,
toutes les heures. Ce comportement sera changé lorsque le paramètre "nonce
tracking" sera supporté.

4.4. Résolveurs
Le travail du résolveur consiste à récupérer un nom d'utilisateur ("username") et un nom
d'authentification ("realm") et retourner des identifiants. L'authentification Basic s'attend à
recevoir une version encodée Base64 du mot de passe ("password"). L'authentification Digest,
elle, attend un hash du "username", du "realm", et du "password" (séparés par des deux-points).
Actuellement le seul algorithme de hash supporté est MD5.

Zend_Auth_Adapter_Http se fie a des objets implémentant


Zend_Auth_Adapter_Http_Resolver_Interface. Une classe de résolution de fichier

190
Zend_Auth

texte est inclue avec cet adaptateur, mais n'importe quelle classe peut être écrite, grâce à
l'interface.

4.4.1. Résolveur fichiers


Cette classe est très simple. Son constructeur ne prend qu'un paramètre qui définit le nom du
fichier cible. Un accesseur existe aussi. Sa méthode resolve() traverse le fichier texte à la
recherche de la ligne qui correspond au "username" et au "realm". La syntaxe est similaire aux
fichiers htpasswd d'Apache :

<username>:<realm>:<credentials>\n

Chaque ligne se décompose en 3 champs - "username", "realm", et "credentials" - séparés par


des deux-points. Le résolveur ne fait que retourner la valeur de "credentials". Ainsi, avec Basic
cette valeur devra être le mot de passe en clair de l'utilisateur identifié par "username". En mode
Digest, la valeur MD5 de toute la chaîne "username:realm:password" (avec les deux-points).

Pour créer des résolveurs de fichiers séparés, utilisez :

$path = 'files/passwd.txt';
$resolver = new Zend_Auth_Adapter_Http_Resolver_File($path);

ou

$path = 'files/passwd.txt';
$resolver = new Zend_Auth_Adapter_Http_Resolver_File();
$resolver->setFile($path);

Si le chemin donné n'est pas lisible, une exception est envoyée.

4.5. Usage général :


Tout d'abord, créez un tableau de configuration avec les options requises :

$config = array(
'accept_schemes' => 'basic digest',
'realm' => 'My Web Site',
'digest_domains' => '/members_only /my_account',
'nonce_timeout' => 3600,
);

Ce tableau va permettre d'accepter les modes Basic ou Digest et demandera une authentification
pour les zones du site situées sous /members_only et /my_account. La valeur du "real" est
en général affichée par le navigateur dans la boite de dialogue. Le paramètre nonce_timeout,
fonctionne comme expliqué plus haut.

Ensuite, créez un objet de Zend_Auth_Adapter_Http :

$adapter = new Zend_Auth_Adapter_Http($config);

Comme nous supportons les 2 modes Basic et Digest, nous avons besoin de deux résolveurs
différents :

$basicResolver = new Zend_Auth_Adapter_Http_Resolver_File();


$basicResolver->setFile('files/basicPasswd.txt');

$digestResolver = new Zend_Auth_Adapter_Http_Resolver_File();


$digestResolver->setFile('files/digestPasswd.txt');

191
Zend_Auth

$adapter->setBasicResolver($basicResolver);
$adapter->setDigestResolver($digestResolver);

Enfin, nous procédons à la demande d'authentification. L'adaptateur a besoin de deux objets


"Request" et "Response" :

assert($request instanceof Zend_Controller_Request_Http);


assert($response instanceof Zend_Controller_Response_Http);

$adapter->setRequest($request);
$adapter->setResponse($response);

$result = $adapter->authenticate();
if (!$result->isValid()) {
// Mauvais username/password, ou action annulée
}

5. LDAP Authentication
5.1. Introduction
Zend_Auth_Adapter_Ldap supports web application authentication with LDAP services. Its
features include username and domain name canonicalization, multi-domain authentication, and
failover capabilities. It has been tested to work with Microsoft Active Directory and OpenLDAP,
but it should also work with other LDAP service providers.

This documentation includes a guide on using Zend_Auth_Adapter_Ldap, an exploration of


its API, an outline of the various available options, diagnostic information for troubleshooting
authentication problems, and example options for both Active Directory and OpenLDAP servers.

5.2. Usage
To incorporate Zend_Auth_Adapter_Ldap authentication into your application quickly, even
if you're not using Zend_Controller, the meat of your code should look something like the
following:

$username = $this->_request->getParam('username');
$password = $this->_request->getParam('password');

$auth = Zend_Auth::getInstance();

$config = new Zend_Config_Ini('../application/config/config.ini',


'production');
$log_path = $config->ldap->log_path;
$options = $config->ldap->toArray();
unset($options['log_path']);

$adapter = new Zend_Auth_Adapter_Ldap($options, $username,


$password);

$result = $auth->authenticate($adapter);

if ($log_path) {
$messages = $result->getMessages();

$logger = new Zend_Log();

192
Zend_Auth

$logger->addWriter(new Zend_Log_Writer_Stream($log_path));
$filter = new Zend_Log_Filter_Priority(Zend_Log::DEBUG);
$logger->addFilter($filter);

foreach ($messages as $i => $message) {


if ($i-- > 1) { // $messages[2] and up are log messages
$message = str_replace("\n", "\n ", $message);
$logger->log("Ldap: $i: $message", Zend_Log::DEBUG);
}
}
}

Of course, the logging code is optional, but it is highly recommended that you use a logger.
Zend_Auth_Adapter_Ldap will record just about every bit of information anyone could want
in $messages (more below), which is a nice feature in itself for something that has a history of
being notoriously difficult to debug.

The Zend_Config_Ini code is used above to load the adapter options. It is also optional. A
regular array would work equally well. The following is an example application/config/
config.ini file that has options for two separate servers. With multiple sets of server options
the adapter will try each, in order, until the credentials are successfully authenticated. The names
of the servers (e.g., 'server1' and 'server2') are largely arbitrary. For details regarding the options
array, see the Server Options section below. Note that Zend_Config_Ini requires that any
values with "equals" characters (=) will need to be quoted (like the DNs shown below).

[production]

ldap.log_path = /tmp/ldap.log

; Typical options for OpenLDAP


ldap.server1.host = s0.foo.net
ldap.server1.accountDomainName = foo.net
ldap.server1.accountDomainNameShort = FOO
ldap.server1.accountCanonicalForm = 3
ldap.server1.username = "CN=user1,DC=foo,DC=net"
ldap.server1.password = pass1
ldap.server1.baseDn = "OU=Sales,DC=foo,DC=net"
ldap.server1.bindRequiresDn = true

; Typical options for Active Directory


ldap.server2.host = dc1.w.net
ldap.server2.useStartTls = true
ldap.server2.accountDomainName = w.net
ldap.server2.accountDomainNameShort = W
ldap.server2.accountCanonicalForm = 3
ldap.server2.baseDn = "CN=Users,DC=w,DC=net"

The above configuration will instruct Zend_Auth_Adapter_Ldap to attempt to authenticate


users with the OpenLDAP server s0.foo.net first. If the authentication fails for any reason,
the AD server dc1.w.net will be tried.

With servers in different domains, this configuration illustrates multi-domain authentication. You
can also have multiple servers in the same domain to provide redundancy.

Note that in this case, even though OpenLDAP has no need for the short NetBIOS style domain
name used by Windows, we provide it here for name canonicalization purposes (described in
the Username Canonicalization section below).

193
Zend_Auth

5.3. The API


The Zend_Auth_Adapter_Ldap constructor accepts three parameters.

The $options parameter is required and must be an array containing one or more sets of
options. Note that it is an array of arrays of Zend_Ldap options. Even if you will be using only
one LDAP server, the options must still be within another array.

Below is print_r() output of an example options parameter containing two sets of server
options for LDAP servers s0.foo.net and dc1.w.net (the same options as the above INI
representation):

Array
(
[server2] => Array
(
[host] => dc1.w.net
[useStartTls] => 1
[accountDomainName] => w.net
[accountDomainNameShort] => W
[accountCanonicalForm] => 3
[baseDn] => CN=Users,DC=w,DC=net
)

[server1] => Array


(
[host] => s0.foo.net
[accountDomainName] => foo.net
[accountDomainNameShort] => FOO
[accountCanonicalForm] => 3
[username] => CN=user1,DC=foo,DC=net
[password] => pass1
[baseDn] => OU=Sales,DC=foo,DC=net
[bindRequiresDn] => 1
)

The information provided in each set of options above is different mainly because AD does not
require a username be in DN form when binding (see the bindRequiresDn option in the Server
Options section below), which means we can omit a number of options associated with retrieving
the DN for a username being authenticated.

What is a Distinguished Name?


A DN or "distinguished name" is a string that represents the path to an object
within the LDAP directory. Each comma-separated component is an attribute
and value representing a node. The components are evaluated in reverse. For
example, the user account CN=Bob Carter,CN=Users,DC=w,DC=net is located
directly within the CN=Users,DC=w,DC=net container. This structure is best
explored with an LDAP browser like the ADSI Edit MMC snap-in for Active
Directory or phpLDAPadmin.

The names of servers (e.g. 'server1' and 'server2' shown above) are largely arbitrary, but for the
sake of using Zend_Config, the identifiers should be present (as opposed to being numeric
indexes) and should not contain any special characters used by the associated file formats (e.g.
the '.' INI property separator, '&' for XML entity references, etc).

194
Zend_Auth

With multiple sets of server options, the adapter can authenticate users in multiple domains and
provide failover so that if one server is not available, another will be queried.

The Gory Details: What Happens in the Authenticate Method?

When the authenticate() method is called, the adapter iterates over each
set of server options, sets them on the internal Zend_Ldap instance, and
calls the Zend_Ldap::bind() method with the username and password being
authenticated. The Zend_Ldap class checks to see if the username is qualified
with a domain (e.g., has a domain component like alice@foo.net or FOO
\alice). If a domain is present, but does not match either of the server's
domain names (foo.net or FOO), a special exception is thrown and caught
by Zend_Auth_Adapter_Ldap that causes that server to be ignored and the
next set of server options is selected. If a domain does match, or if the user
did not supply a qualified username, Zend_Ldap proceeds to try to bind with
the supplied credentials. if the bind is not successful, Zend_Ldap throws a
Zend_Ldap_Exception which is caught by Zend_Auth_Adapter_Ldap and
the next set of server options is tried. If the bind is successful, the iteration
stops, and the adapter's authenticate() method returns a successful result.
If all server options have been tried without success, the authentication fails,
and authenticate() returns a failure result with error messages from the last
iteration.

The username and password parameters of the Zend_Auth_Adapter_Ldap constructor


represent the credentials being authenticated (i.e., the credentials supplied by the user through
your HTML login form). Alternatively, they may also be set with the setUsername() and
setPassword() methods.

5.4. Server Options


Each set of server options in the context of Zend_Auth_Adapter_Ldap consists of the
following options, which are passed, largely unmodified, to Zend_Ldap::setOptions():

Tableau 10. Server Options

Name Description
host The hostname of LDAP server that these
options represent. This option is required.
port The port on which the LDAP server is listening.
If useSsl is TRUE, the default port value is 636.
If useSsl is FALSE, the default port value is 389.
useStartTls Whether or not the LDAP client should
use TLS (aka SSLv2) encrypted transport.
A value of TRUE is strongly favored in
production environments to prevent passwords
from be transmitted in clear text. The default
value is FALSE, as servers frequently require
that a certificate be installed separately
after installation. The useSsl and useStartTls
options are mutually exclusive. The useStartTls
option should be favored over useSsl but not all
servers support this newer mechanism.

195
Zend_Auth

Name Description
useSsl Whether or not the LDAP client should use
SSL encrypted transport. The useSsl and
useStartTls options are mutually exclusive, but
useStartTls should be favored if the server
and LDAP client library support it. This value
also changes the default port value (see port
description above).
username The DN of the account used to perform
account DN lookups. LDAP servers that
require the username to be in DN form
when performing the "bind" require this option.
Meaning, if bindRequiresDn is TRUE, this
option is required. This account does not need
to be a privileged account; an account with
read-only access to objects under the baseDn
is all that is necessary (and preferred based on
the Principle of Least Privilege).
password The password of the account used to perform
account DN lookups. If this option is not
supplied, the LDAP client will attempt an
"anonymous bind" when performing account
DN lookups.
bindRequiresDn Some LDAP servers require that the username
used to bind be in DN form like CN=Alice
Baker,OU=Sales,DC=foo,DC=net (basically all
servers except AD). If this option is TRUE, this
instructs Zend_Ldap to automatically retrieve
the DN corresponding to the username being
authenticated, if it is not already in DN form,
and then re-bind with the proper DN. The
default value is FALSE. Currently only Microsoft
Active Directory Server (ADS) is known not
to require usernames to be in DN form when
binding, and therefore this option may be
FALSE with AD (and it should be, as retrieving
the DN requires an extra round trip to the
server). Otherwise, this option must be set
to TRUE (e.g. for OpenLDAP). This option
also controls the default acountFilterFormat
used when searching for accounts. See the
accountFilterFormat option.
baseDn The DN under which all accounts being
authenticated are located. This option is
required. if you are uncertain about the
correct baseDn value, it should be sufficient
to derive it from the user's DNS domain
using DC= components. For example, if the
user's principal name is alice@foo.net,
a baseDn of DC=foo,DC=net should
work. A more precise location (e.g.,

196
Zend_Auth

Name Description
OU=Sales,DC=foo,DC=net) will be more
efficient, however.
accountCanonicalForm A value of 2, 3 or 4 indicating the form to
which account names should be canonicalized
after successful authentication. Values are
as follows: 2 for traditional username style
names (e.g., alice), 3 for backslash-style
names (e.g., FOO\alice) or 4 for principal
style usernames (e.g., alice@foo.net). The
default value is 4 (e.g., alice@foo.net). For
example, with a value of 3, the identity returned
by Zend_Auth_Result::getIdentity()
(and Zend_Auth::getIdentity(), if
Zend_Auth was used) will always be FOO
\alice, regardless of what form Alice
supplied, whether it be alice, alice@foo.net,
FOO\alice, FoO\aLicE, foo.net\alice,
etc. See the Account Name Canonicalization
section in the Zend_Ldap documentation for
details. Note that when using multiple sets
of server options it is recommended, but not
required, that the same accountCanonicalForm
be used with all server options so that the
resulting usernames are always canonicalized
to the same form (e.g., if you canonicalize
to EXAMPLE\username with an AD server
but to username@example.com with an
OpenLDAP server, that may be awkward for
the application's high-level logic).
accountDomainName The FQDN domain name for which the
target LDAP server is an authority (e.g.,
example.com). This option is used to
canonicalize names so that the username
supplied by the user can be converted
as necessary for binding. It is also
used to determine if the server is an
authority for the supplied username (e.g., if
accountDomainName is foo.net and the user
supplies bob@bar.net, the server will not be
queried, and a failure will result). This option is
not required, but if it is not supplied, usernames
in principal name form (e.g., alice@foo.net)
are not supported. It is strongly recommended
that you supply this option, as there are many
use-cases that require generating the principal
name form.
accountDomainNameShort The 'short' domain for which the target
LDAP server is an authority (e.g., FOO).
Note that there is a 1:1 mapping
between the accountDomainName and
accountDomainNameShort. This option should

197
Zend_Auth

Name Description
be used to specify the NetBIOS domain
name for Windows networks, but may also be
used by non-AD servers (e.g., for consistency
when multiple sets of server options with
the backslash style accountCanonicalForm).
This option is not required but if it is not
supplied, usernames in backslash form (e.g.,
FOO\alice) are not supported.
accountFilterFormat The LDAP search filter used to search for
accounts. This string is a printf()-style
expression that must contain one '%s' to
accomodate the username. The default value
is '(&(objectClass=user)(sAMAccountName=
%s))', unless bindRequiresDn is set to
TRUE, in which case the default is
'(&(objectClass=posixAccount)(uid=%s))'. For
example, if for some reason you wanted
to use bindRequiresDn = true with AD
you would need to set accountFilterFormat
= '(&(objectClass=user)(sAMAccountName=
%s))'.
optReferrals If set to TRUE, this option indicates to the LDAP
client that referrals should be followed. The
default value is FALSE.

If you enable useStartTls = TRUE or useSsl = TRUE you may find that the LDAP
client generates an error claiming that it cannot validate the server's certificate.
Assuming the PHP LDAP extension is ultimately linked to the OpenLDAP
client libraries, to resolve this issue you can set "TLS_REQCERT never" in
the OpenLDAP client ldap.conf (and restart the web server) to indicate to
the OpenLDAP client library that you trust the server. Alternatively, if you are
concerned that the server could be spoofed, you can export the LDAP server's
root certificate and put it on the web server so that the OpenLDAP client can
validate the server's identity.

5.5. Collecting Debugging Messages


Zend_Auth_Adapter_Ldap collects debugging information within its authenticate()
method. This information is stored in the Zend_Auth_Result object as messages. The array
returned by Zend_Auth_Result::getMessages() is described as follows

Tableau 11. Debugging Messages


Messages Array Index Description
Index 0 A generic, user-friendly message that is
suitable for displaying to users (e.g.,
"Invalid credentials"). If the authentication is
successful, this string is empty.
Index 1 A more detailed error message that is not
suitable to be displayed to users but should
be logged for the benefit of server operators.

198
Zend_Auth

Messages Array Index Description


If the authentication is successful, this string is
empty.
Indexes 2 and higher All log messages in order starting at index 2.

In practice, index 0 should be displayed to the user (e.g., using the FlashMessenger helper),
index 1 should be logged and, if debugging information is being collected, indexes 2 and higher
could be logged as well (although the final message always includes the string from index 1).

5.6. Common Options for Specific Servers


5.6.1. Options for Active Directory
For ADS, the following options are noteworthy:

Tableau 12. Options for Active Directory


Name Additional Notes
host As with all servers, this option is required.
useStartTls For the sake of security, this should be TRUE
if the server has the necessary certificate
installed.
useSsl Possibly used as an alternative to useStartTls
(see above).
baseDn As with all servers, this option is
required. By default AD places all user
accounts under the Users container (e.g.,
CN=Users,DC=foo,DC=net), but the default is
not common in larger organizations. Ask your
AD administrator what the best DN for accounts
for your application would be.
accountCanonicalForm You almost certainly want this to be 3 for
backslash style names (e.g., FOO\alice),
which are most familiar to Windows users.
You should not use the unqualified form 2
(e.g., alice), as this may grant access to your
application to users with the same username
in other trusted domains (e.g., BAR\alice and
FOO\alice will be treated as the same user).
(See also note below.)
accountDomainName This is required with AD unless
accountCanonicalForm 2 is used, which, again,
is discouraged.
accountDomainNameShort The NetBIOS name of the domain that users
are in and for which the AD server is an
authority. This is required if the backslash style
accountCanonicalForm is used.

Technically there should be no danger of accidental cross-domain authentication


with the current Zend_Auth_Adapter_Ldap implementation, since server

199
Zend_Auth

domains are explicitly checked, but this may not be true of a future
implementation that discovers the domain at runtime, or if an alternative adapter
is used (e.g., Kerberos). In general, account name ambiguity is known to be the
source of security issues, so always try to use qualified account names.

5.6.2. Options for OpenLDAP

For OpenLDAP or a generic LDAP server using a typical posixAccount style schema, the
following options are noteworthy:

Tableau 13. Options for OpenLDAP

Name Additional Notes


host As with all servers, this option is required.
useStartTls For the sake of security, this should be TRUE
if the server has the necessary certificate
installed.
useSsl Possibly used as an alternative to useStartTls
(see above).
username Required and must be a DN, as OpenLDAP
requires that usernames be in DN form when
performing a bind. Try to use an unprivileged
account.
password The password corresponding to the username
above, but this may be omitted if the LDAP
server permits an anonymous binding to query
user accounts.
bindRequiresDn Required and must be TRUE, as OpenLDAP
requires that usernames be in DN form when
performing a bind.
baseDn As with all servers, this option is required and
indicates the DN under which all accounts
being authenticated are located.
accountCanonicalForm Optional, but the default value is 4 (principal
style names like alice@foo.net), which may
not be ideal if your users are used to backslash
style names (e.g., FOO\alice). For backslash
style names use value 3.
accountDomainName Required unless you're using
accountCanonicalForm 2, which is not
recommended.
accountDomainNameShort If AD is not also being used, this value is not
required. Otherwise, if accountCanonicalForm
3 is used, this option is required and should
be a short name that corresponds adequately
to the accountDomainName (e.g., if your
accountDomainName is foo.net, a good
accountDomainNameShort value might be
FOO).

200
Zend_Auth

6. Authentification OpenID
6.1. Introduction
Zend_Auth_Adapter_OpenId permet l'authentification à travers un serveur distant OpenID.
Une telle authentification attend que l'utilisateur fournisse à l'application Web son identifiant
OpenID. L'utilisateur est alors redirigé vers un fournisseur de services OpenID, afin de s'identifier
en rapport avec l'application Web utilisée. Un mot de passe ou un autre procédé est utilisé, et
celui-ci n'est jamais connu de l'application Web originale.

L'identité OpenID est juste une URI qui pointe vers une page avec des informations décrivant
le serveur à utiliser et des informations sur l'utilisateur. Pour plus d'informations, consultez le
site officiel OpenID.

La classe Zend_Auth_Adapter_OpenId utilise Zend_OpenId_Consumer qui sert à gérer le


protocole OpenID.

Zend_OpenId utilise l'extension GMP, si disponible. L'utilisation de


l'extension GMP est recommandée pour améliorer les performances de
Zend_Auth_Adapter_OpenId.

6.2. Spécifications
Comme toute autre classe adaptateur de Zend_Auth, Zend_Auth_Adapter_OpenId
implémente Zend_Auth_Adapter_Interface, qui définit une seule méthode :
authenticate(). Elle est utilisée pour l'authentification elle-même, une fois que l'objet est
prêt. La préparation d'un objet OpenID nécessite quelques options à passer à Zend_OpenId.

A la différence des autres adaptateurs Zend_Auth, l'adaptateur


Zend_Auth_Adapter_OpenId utilise une authentification sur un serveur
externe à l'application, et nécessitera donc deux requêtes HTTP. Ainsi
Zend_Auth_Adapter_OpenId::authenticate() devra être appelée deux fois : d'abord
pour rediriger l'utilisateur vers le serveur OpenID (rien ne sera donc retourné par la méthode),
qui lui-même redirigera l'utilisateur vers l'application, où un deuxième appel de méthode
Zend_Auth_Adapter_OpenId::authenticate() vérifiera la signature et complétera le
processus. Un objet Zend_Auth_Result sera alors cette fois-ci retourné.

L'exemple suivant montre l'utilisation de Zend_Auth_Adapter_OpenId.


Zend_Auth_Adapter_OpenId::authenticate() est appelée deux fois. La première fois
juste après avoir envoyé le formulaire HTML, lorsque $_POST['openid_action'] vaut
"login", et la deuxième fois après la redirection HTTP du serveur OpenID vers l'application,
lorsque $_GET['openid_mode'] ou $_POST['openid_mode'] existe.

<?php
$status = "";
$auth = Zend_Auth::getInstance();
if ((isset($_POST['openid_action']) &&
$_POST['openid_action'] == "login" &&
!empty($_POST['openid_identifier'])) ||
isset($_GET['openid_mode']) ||
isset($_POST['openid_mode'])) {
$result = $auth->authenticate(
new Zend_Auth_Adapter_OpenId(@$_POST['openid_identifier']));
if ($result->isValid()) {

201
Zend_Auth

$status = "You are logged-in as "


. $auth->getIdentity()
. "<br>\n";
} else {
$auth->clearIdentity();
foreach ($result->getMessages() as $message) {
$status .= "$message<br>\n";
}
}
} else if ($auth->hasIdentity()) {
if (isset($_POST['openid_action']) &&
$_POST['openid_action'] == "logout") {
$auth->clearIdentity();
} else {
$status = "You are logged-in as "
. $auth->getIdentity()
. "<br>\n";
}
}
?>
<html><body>
<?php echo htmlspecialchars($status);?>
<form method="post"><fieldset>
<legend>OpenID Login</legend>

<input type="text" name="openid_identifier" value="">


<input type="submit" name="openid_action" value="login">
<input type="submit" name="openid_action" value="logout">
</fieldset></form></body></html>

Il est possible de personnaliser le processus, pour par exemple demander une redirection
du serveur OpenID vers l'application, sur une page différente de la première. Ceci
peut être fait avec des objets personnalisés Zend_OpenId_Consumer_Storage ou
Zend_Controller_Response. Vous pouvez aussi utiliser le procédé "Simple Registration"
pour récupérer les informations au sujet de l'utilisateur, en provenance du serveur
OpenID. Toutes ces possibilités sont écrites et détaillées dans le chapitre concernant
Zend_OpenId_Consumer.

202
Zend_Barcode
1. Introduction
Zend_Barcode fournit une manière générique de générer des code-barres. Le composant
Zend_Barcode est divisé en deux sous-composants : les objets code-barres et les générateurs
de rendu. Les objets permettent de créer les code-barres indépendamment du support de rendu.
Les générateurs de rendu vous permettent de tracer les code-barres en fonction sur le support.

2. Création de code-barres avec la classe Zend_Barcode


2.1. Utilisation de la fabrique Zend_Barcode::factory
Zend_Barcode possède une méthode de fabrique pour créer une instance d'un générateur
de rendu qui étend Zend_Barcode_Renderer_RendererAbstract. Ce méthode accepte 5
arguments.

1. Le nom du format de code-barres (ex. "code39") (obligatoire)

2. Le nom du générateur de rendu (ex. "image") (obligatoire)

3. Les options de l'objet code-barres (un tableau ou un objet Zend_Config) (optionnel)

4. Les options du générateur de rendu (un tableau ou un objet Zend_Config) (optionnel)

5. Booléen indiquant si le générateur automatique d'erreur est activé. Si une exception intervient,
l'objet code-barres fourni sera remplacé par un objet représentant l'erreur (optionnel par défaut
vaut TRUE)

Exemple 52. Récupérer un générateur de rendu avec Zend_Barcode::factory()

Zend_Barcode::factory() instancie un objet code-barres et un générateur de rendu


et les lie ensemble. Dans le premier exemple, nous allons utiliser le type de code-barres
Code39 avec le générateur de rendu Image.

// Seul le texte à écrire est obligatoire


$barcodeOptions = array('text' => 'ZEND-FRAMEWORK');
// Pas d'options requises
$rendererOptions = array();
$renderer = Zend_Barcode::factory(
'code39', 'image', $barcodeOptions, $rendererOptions
);

203
Zend_Barcode

Exemple 53. Utiliser Zend_Barcode::factory() avec des objets Zend_Config

Vous pouvez fournir un objet Zend_Config à la fabrique afin de créer les objets souhaités.
L'exemple suivant est fonctionnellement équivalent au précédent.

// En utilisant seulement un objet Zend_Config


$config = new Zend_Config(array(
'barcode' => 'code39',
'barcodeParams' => array('text' => 'ZEND-FRAMEWORK'),
'renderer' => 'image',
'rendererParams' => array('imageType' => 'gif'),
));
$renderer = Zend_Barcode::factory($config);

2.2. Tracer un code-barres


Quand vous dessiner un code-barres, vous récupérez la ressource dans laquelle le code-barres
est tracée. Pour ensuite tracer le code-barres, vous pouvez appeler la méthode draw() du
générateur de rendu ou simplement utiliser la méthode proxy fournie par Zend_Barcode.

Exemple 54. Tracer un code-barres avec l'objet générateur de rendu

// Seul le texte à écrire est obligatoire


$barcodeOptions = array('text' => 'ZEND-FRAMEWORK');
// Pas d'options requises
$rendererOptions = array();
// Tracé du code-barres dans une nouvelle image
$imageResource = Zend_Barcode::factory(
'code39', 'image', $barcodeOptions, $rendererOptions
)->draw();

Exemple 55. Trace un code-barres avec Zend_Barcode::draw()

// Seul le texte à écrire est obligatoire


$barcodeOptions = array('text' => 'ZEND-FRAMEWORK');
// Pas d'options requises
$rendererOptions = array();
// Tracé du code-barres dans une nouvelle image
$imageResource = Zend_Barcode::draw(
'code39', 'image', $barcodeOptions, $rendererOptions
);

2.3. Générer le rendu d'un code-barres


Quand vous générez un code-barres, vous dessinez le code-barres, vous envoyez les entêtes
et vous envoyez la ressource (par exemple vers un navigateur). Pour rendre un code-barres,
vous pouvez appeler la méthode render() du générateur de rendu ou simplement utiliser la
méthode proxy fournie par Zend_Barcode.

204
Zend_Barcode

Exemple 56. Effectuer le rendu d'un code-barres avec l'objet générateur de rendu

// Seul le texte à écrire est obligatoire


$barcodeOptions = array('text' => 'ZEND-FRAMEWORK');
// Pas d'options requises
$rendererOptions = array();
// Tracé du code-barres dans une nouvelle image,
// envoi des entêtes et de l'image
Zend_Barcode::factory(
'code39', 'image', $barcodeOptions, $rendererOptions
)->render();

Ceci générera ce code-barres :

Exemple 57. Effectuer le rendu d'un code-barres avec Zend_Barcode::render()

// Seul le texte à écrire est obligatoire


$barcodeOptions = array('text' => 'ZEND-FRAMEWORK');
// Pas d'options requises
$rendererOptions = array();
// Tracé du code-barres dans une nouvelle image,
// envoi des entêtes et de l'image
Zend_Barcode::render(
'code39', 'image', $barcodeOptions, $rendererOptions
);

Ceci générera le même code-barres que l'exemple précédent.

3. Zend_Barcode Objects
Barcode objects allow you to generate barcodes independently of the rendering support. After
generation, you can retrieve the barcode as an array of drawing instructions that you can provide
to a renderer.

Objects have a large number of options. Most of them are common to all objects. These options
can be set in four ways:

• As an array or a Zend_Config object passed to the constructor.

• As an array passed to the setOptions() method.

• As a Zend_Config object passed to the setConfig() method.

• Via individual setters for each configuration type.

205
Zend_Barcode

Exemple 58. Different ways to parameterize a barcode object

$options = array('text' => 'ZEND-FRAMEWORK', 'barHeight' => 40);

// Case 1: constructor
$barcode = new Zend_Barcode_Object_Code39($options);

// Case 2: setOptions()
$barcode = new Zend_Barcode_Object_Code39();
$barcode->setOptions($options);

// Case 3: setConfig()
$config = new Zend_Config($options);
$barcode = new Zend_Barcode_Object_Code39();
$barcode->setConfig($config);

// Case 4: individual setters


$barcode = new Zend_Barcode_Object_Code39();
$barcode->setText('ZEND-FRAMEWORK')
->setBarHeight(40);

3.1. Common Options


In the following list, the values have no units; we will use the term "unit." For example, the
default value of the "thin bar" is "1 unit". The real units depend on the rendering support (see
the renderers documentation for more information). Setters are each named by uppercasing
the initial letter of the option and prefixing the name with "set" (e.g. "barHeight" becomes
"setBarHeight"). All options have a corresponding getter prefixed with "get" (e.g. "getBarHeight").
Available options are:

Tableau 14. Common Options

Option Data Type Default Value Description


barcodeNamespace String Namespace of the
Zend_Barcode_Object
barcode; for example,
if you need to extend
the embedding objects
barHeight Integer 50 Height of the bars
barThickWidth Integer 3 Width of the thick bar
barThinWidth Integer 1 Width of the thin
factor Integer 1 Factor by which to
multiply bar widths and
font sizes
foreColor Integer 0 (black) Color of the bar and the
text. Could be provided
as an integer or as
a HTML value (e.g.
"#333333")
backgroundColor Integer or String 16777125 (white) Color of the
background. Could be
provided as an integer
or as a HTML value
(e.g. "#333333")

206
Zend_Barcode

Option Data Type Default Value Description


reverseColor Boolean FALSE Allow switching the
color of the bar and the
background
orientation Integer 0 Orientation of the
barcode
font String or Integer NULL Font path to a TTF font
or a number between
1 and 5 if using image
generation with GD
(internal fonts)
fontSize Integer 10 Size of the font
(not applicable with
numeric fonts)
withBorder Boolean FALSE Draw a border around
the barcode and the
quiet zones
drawText Boolean TRUE Set if the text is
displayed below the
barcode
stretchText Boolean FALSE Specify if the text is
stretched all along the
barcode
withChecksum Boolean FALSE Indicate whether or
not the checksum is
automatically added to
the barcode
withChecksumInText Boolean FALSE Indicate whether or
not the checksum is
displayed in the textual
representation
text String NULL The text to represent
as a barcode

3.1.1. Particular case of static setBarcodeFont()


You can set a commont font for all your objects by using the static method
Zend_Barcode_Object::setBarcodeFont(). This value can be always be overridden for
individual objects by using the setFont() method.

// In your bootstrap:
Zend_Barcode_Object::setBarcodeFont('my_font.ttf');

// Later in your code:


Zend_Barcode::render(
'code39',
'pdf',
array('text' => 'ZEND-FRAMEWORK')
); // will use 'my_font.ttf'

// or:

207
Zend_Barcode

Zend_Barcode::render(
'code39',
'image',
array(
'text' => 'ZEND-FRAMEWORK',
'font' => 3
)
); // will use the 3rd GD internal font

3.2. Common Additional Getters

Tableau 15. Common Getters

Getter Data Type Description


getType() String Return the name of
the barcode class without
the namespace (e.g.
Zend_Barcode_Object_Code39
returns simply "code39")
getRawText() String Return the original text
provided to the object
getTextToDisplay() String Return the text to display,
including, if activated, the
checksum value
getQuietZone() Integer Return the size of the space
needed before and after the
barcode without any drawing
getInstructions() Array Return drawing instructions as
an array.
getHeight($recalculate Integer Return the height of the
= false) barcode calculated after
possible rotation
getWidth($recalculate Integer Return the width of the barcode
= false) calculated after possible
rotation
Integer
getOffsetTop($recalculate Return the position of the top
= false) of the barcode calculated after
possible rotation
Integer
getOffsetLeft($recalculate Return the position of the left
= false) of the barcode calculated after
possible rotation

3.3. Description of shipped barcodes


You will find below detailed information about all barcode types shipped by default with Zend
Framework.

208
Zend_Barcode

3.3.1. Zend_Barcode_Object_Error

This barcode is a special case. It is internally used to automatically render an exception caught
by the Zend_Barcode component.

3.3.2. Zend_Barcode_Object_Code25

• Name: Code 25 (or Code 2 of 5 or Code 25 Industrial)

• Allowed characters: '0123456789'

• Checksum: optional (modulo 10)

• Length: variable

There are no particular options for this barcode.

3.3.3. Zend_Barcode_Object_Code25interleaved

This barcode extends Zend_Barcode_Object_Code25 (Code 2 of 5), and has the same
particulars and options, and adds the following:

• Name: Code 2 of 5 Interleaved

• Allowed characters: '0123456789'

• Checksum: optional (modulo 10)

• Length: variable (always even number of characters)

Available options include:

Tableau 16. Zend_Barcode_Object_Code25interleaved Options

Option Data Type Default Value Description


withBearerBars Boolean FALSE Draw a thick bar at the
top and the bottom of
the barcode.

209
Zend_Barcode

If the number of characters is not even,


Zend_Barcode_Object_Code25interleaved will automatically prepend
the missing zero to the barcode text.

3.3.4. Zend_Barcode_Object_Ean2

This barcode extends Zend_Barcode_Object_Ean5 (EAN 5), and has the same particulars
and options, and adds the following:

• Name: EAN-2

• Allowed characters: '0123456789'

• Checksum: only use internally but not displayed

• Length: 2 characters

There are no particular options for this barcode.

If the number of characters is lower than 2, Zend_Barcode_Object_Ean2 will


automatically prepend the missing zero to the barcode text.

3.3.5. Zend_Barcode_Object_Ean5

This barcode extends Zend_Barcode_Object_Ean13 (EAN 13), and has the same particulars
and options, and adds the following:

• Name: EAN-5

• Allowed characters: '0123456789'

• Checksum: only use internally but not displayed

• Length: 5 characters

There are no particular options for this barcode.

If the number of characters is lower than 5, Zend_Barcode_Object_Ean5 will


automatically prepend the missing zero to the barcode text.

210
Zend_Barcode

3.3.6. Zend_Barcode_Object_Ean8

This barcode extends Zend_Barcode_Object_Ean13 (EAN 13), and has the same particulars
and options, and adds the following:

• Name: EAN-8

• Allowed characters: '0123456789'

• Checksum: mandatory (modulo 10)

• Length: 8 characters (including checksum)

There are no particular options for this barcode.

If the number of characters is lower than 8, Zend_Barcode_Object_Ean8 will


automatically prepend the missing zero to the barcode text.

3.3.7. Zend_Barcode_Object_Ean13

• Name: EAN-13

• Allowed characters: '0123456789'

• Checksum: mandatory (modulo 10)

• Length: 13 characters (including checksum)

There are no particular options for this barcode.

If the number of characters is lower than 13, Zend_Barcode_Object_Ean13


will automatically prepend the missing zero to the barcode text.

3.3.8. Zend_Barcode_Object_Code39

• Name: Code 39

211
Zend_Barcode

• Allowed characters: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ -.$/+%'

• Checksum: optional (modulo 43)

• Length: variable

Zend_Barcode_Object_Code39 will automatically add the start and stop


characters ('*') for you.

There are no particular options for this barcode.

3.3.9. Zend_Barcode_Object_Identcode

This barcode extends Zend_Barcode_Object_Code25interleaved (Code 2 of 5


Interleaved), and inherits some of its capabilities; it also has a few particulars of its own.

• Name: Identcode (Deutsche Post Identcode)

• Allowed characters: '0123456789'

• Checksum: mandatory (modulo 10 different from Code25)

• Length: 12 characters (including checksum)

There are no particular options for this barcode.

If the number of characters is lower than 12,


Zend_Barcode_Object_Identcode will automatically prepend missing zeros
to the barcode text.

3.3.10. Zend_Barcode_Object_Itf14

This barcode extends Zend_Barcode_Object_Code25interleaved (Code 2 of 5


Interleaved), and inherits some of its capabilities; it also has a few particulars of its own.

• Name: ITF-14

• Allowed characters: '0123456789'

• Checksum: mandatory (modulo 10)

• Length: 14 characters (including checksum)

There are no particular options for this barcode.

212
Zend_Barcode

If the number of characters is lower than 14, Zend_Barcode_Object_Itf14


will automatically prepend missing zeros to the barcode text.

3.3.11. Zend_Barcode_Object_Leitcode

This barcode extends Zend_Barcode_Object_Identcode (Deutsche Post Identcode), and


inherits some of its capabilities; it also has a few particulars of its own.

• Name: Leitcode (Deutsche Post Leitcode)

• Allowed characters: '0123456789'

• Checksum: mandatory (modulo 10 different from Code25)

• Length: 14 characters (including checksum)

There are no particular options for this barcode.

If the number of characters is lower than 14,


Zend_Barcode_Object_Leitcode will automatically prepend missing zeros
to the barcode text.

3.3.12. Zend_Barcode_Object_Planet

• Name: Planet (PostaL Alpha Numeric Encoding Technique)

• Allowed characters: '0123456789'

• Checksum: mandatory (modulo 10)

• Length: 12 or 14 characters (including checksum)

There are no particular options for this barcode.

3.3.13. Zend_Barcode_Object_Postnet

• Name: Postnet (POSTal Numeric Encoding Technique)

• Allowed characters: '0123456789'

• Checksum: mandatory (modulo 10)

• Length: 6, 7, 10 or 12 characters (including checksum)

There are no particular options for this barcode.

213
Zend_Barcode

3.3.14. Zend_Barcode_Object_Royalmail

• Name: Royal Mail or RM4SCC (Royal Mail 4-State Customer Code)

• Allowed characters: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'

• Checksum: mandatory

• Length: variable

There are no particular options for this barcode.

3.3.15. Zend_Barcode_Object_Upca

This barcode extends Zend_Barcode_Object_Ean13 (EAN-13), and inherits some of its


capabilities; it also has a few particulars of its own.

• Name: UPC-A (Universal Product Code)

• Allowed characters: '0123456789'

• Checksum: mandatory (modulo 10)

• Length: 12 characters (including checksum)

There are no particular options for this barcode.

If the number of characters is lower than 12, Zend_Barcode_Object_Upca will


automatically prepend missing zeros to the barcode text.

3.3.16. Zend_Barcode_Object_Upce

This barcode extends Zend_Barcode_Object_Upca (UPC-A), and inherits some of its


capabilities; it also has a few particulars of its own. The first character of the text to encode is
the system (0 or 1).

• Name: UPC-E (Universal Product Code)

• Allowed characters: '0123456789'

• Checksum: mandatory (modulo 10)

214
Zend_Barcode

• Length: 8 characters (including checksum)

There are no particular options for this barcode.

If the number of characters is lower than 8, Zend_Barcode_Object_Upce will


automatically prepend missing zeros to the barcode text.

If the first character of the text to encode is not 0 or 1,


Zend_Barcode_Object_Upce will automatically replace it by 0.

4. Zend_Barcode Renderers
Renderers have some common options. These options can be set in four ways:

• As an array or a Zend_Config object passed to the constructor.

• As an array passed to the setOptions() method.

• As a Zend_Config object passed to the setConfig() method.

• As discrete values passed to individual setters.

Exemple 59. Different ways to parameterize a renderer object

$options = array('topOffset' => 10);

// Case 1
$renderer = new Zend_Barcode_Renderer_Pdf($options);

// Case 2
$renderer = new Zend_Barcode_Renderer_Pdf();
$renderer->setOptions($options);

// Case 3
$config = new Zend_Config($options);
$renderer = new Zend_Barcode_Renderer_Pdf();
$renderer->setConfig($config);

// Case 4
$renderer = new Zend_Barcode_Renderer_Pdf();
$renderer->setTopOffset(10);

4.1. Common Options


In the following list, the values have no unit; we will use the term "unit." For example, the default
value of the "thin bar" is "1 unit." The real units depend on the rendering support. The individual
setters are obtained by uppercasing the initial letter of the option and prefixing the name with
"set" (e.g. "barHeight" => "setBarHeight"). All options have a correspondant getter prefixed with
"get" (e.g. "getBarHeight"). Available options are:

Tableau 17. Common Options


Option Data Type Default Value Description
rendererNamespace String Namespace of the
Zend_Barcode_Renderer
renderer; for example,

215
Zend_Barcode

Option Data Type Default Value Description


if you need to extend
the renderers
horizontalPosition String "left" Can be "left", "center"
or "right". Can be
useful with PDF or
if the setWidth()
method is used with an
image renderer.
verticalPosition String "top" Can be "top", "middle"
or "bottom". Can be
useful with PDF or
if the setHeight()
method is used with an
image renderer.
leftOffset Integer 0 Top position of the
barcode inside the
renderer. If used, this
value will override the
"horizontalPosition"
option.
topOffset Integer 0 Top position of the
barcode inside the
renderer. If used, this
value will override
the "verticalPosition"
option.
automaticRenderError Boolean TRUE Whether or not to
automatically render
errors. If an exception
occurs, the provided
barcode object will be
replaced with an Error
representation. Note
that some errors (or
exceptions) can not be
rendered.
moduleSize Float 1 Size of a rendering
module in the support.
barcode Zend_Barcode_Object
NULL The barcode object to
render.

An additional getter exists: getType(). It returns the name of the renderer class without the
namespace (e.g. Zend_Barcode_Renderer_Image returns "image").

4.2. Zend_Barcode_Renderer_Image
The Image renderer will draw the instruction list of the barcode object in an image resource. The
component requires the GD extension. The default width of a module is 1 pixel.

Available option are:

216
Zend_Barcode

Tableau 18. Zend_Barcode_Renderer_Image Options

Option Data Type Default Value Description


height Integer 0 Allow you to specify
the height of the result
image. If "0", the height
will be calculated by
the barcode object.
width Integer 0 Allow you to specify
the width of the result
image. If "0", the width
will be calculated by
the barcode object.
imageType String "png" Specify the image
format. Can be "png",
"jpeg", "jpg" or "gif".

4.3. Zend_Barcode_Renderer_Pdf
The PDF renderer will draw the instruction list of the barcode object in a PDF document. The
default width of a module is 0.5 point.

There are no particular options for this renderer.

217
Zend_Cache
1. Introduction
Zend_Cache fournit un moyen générique de mettre en cache des données.

Le cache dans Zend Framework est réalisé via les frontends alors que les caches
d'enregistrements sont stockés grâce à des adaptateurs de backend (File, Sqlite, Memcache...)
grâce à un système souple d'ID et de balises. En les utilisant, il est simple de supprimer des types
spécifiques d'enregistrements par la suite (par exemple: "supprime tous les enregistrements de
cache marqués avec une balise donnée").

Le coeur du module (Zend_Cache_Core) est générique, souple et configurable. Pour le


moment, pour vos besoins spécifiques, il y a des frontends qui étendent Zend_Cache_Core
simplement : Output, File, Function et Class.

Exemple 60. Créer un frontend avec Zend_Cache::factory()

Zend_Cache::factory() instancie les objets corrects et les lie ensemble. Dans le


premier exemple, nous allons utiliser le frontend Core avec le backend File.

$frontendOptions = array(
'lifetime' => 7200, // temps de vie du cache de 2 heures
'automatic_serialization' => true
);

$backendOptions = array(
// Répertoire où stocker les fichiers de cache
'cache_dir' => './tmp/'
);

// créer un objet Zend_Cache_Core


$cache = Zend_Cache::factory('Core',
'File',
$frontendOptions,
$backendOptions);

Frontends et Backends constitués de plusieurs mots

Certains frontends et backends sont nommés en utilisant plusieurs mots, comme


"ZendPlatform". En les spécifiant à la fabrique, séparez les en utilisant un
séparateur de mot, comme l'espace (" "), le tiret ("-") ou le point (".").

218
Zend_Cache

Exemple 61. Mettre en cache un résultat de requête sur une base de données

Maintenant que nous avons un frontend, nous pouvons mettre en cache tout type de
données (nous avons activé la sérialisation). Par exemple nous pouvons mettre en cache le
résultat d'une requête de base de données coûteuse. Après qu'il soit mis en cache, il n'y a
plus besoin de se connecter à la base de données. Les enregistrements récupérés depuis
le cache sont désérialisés.

// $cache initialisé dans l'exemple précédent

// on regarde si un cache existe déjà


if(!$result = $cache->load('myresult')) {

// le cache est manquant, connexion à la base de données


$db = Zend_Db::factory( [...] );

$result = $db->fetchAll('SELECT * FROM grosse_table');

$cache->save($result, 'myresult');

} else {

// il y a un cache
echo "Ceci est issu du cache !\n\n";

print_r($result);

219
Zend_Cache

Exemple 62. Cache de sortie avec le frontend de sortie Zend_Cache

Nous marquons les sections dans lesquelles nous voulons un cache de sortie en ajoutant de
la logique conditionnelle, en encapsulant la section entre les méthodes start() et end()
(cela ressemble au premier exemple et est le coeur de la stratégie de mise en cache).

A l'intérieur, affichez vos données comme d'habitude toutes les sorties seront misent en
cache quand la méthode end() est appelée. A la prochaine exécution, la section complète
sera évitée, au profit de la récupération de son cache (si le cache est encore valide).

$frontendOptions = array(
// temps de vue du cache de 30 secondes
'lifetime' => 30,
// par défaut
'automatic_serialization' => false
);

$backendOptions = array('cache_dir' => './tmp/');

$cache = Zend_Cache::factory('Output',
'File',
$frontendOptions,
$backendOptions);

// nous passons un identifiant unique de la méthode start()


if(!$cache->start('mypage')) {
// affichage

echo 'Hello world! ';


echo 'Ceci est issu du cache('.time().') ';

// la sortie est sauvegardée est envoyé au navigateur


$cache->end();
}

echo "Ceci n' jamais mis en cache (" . time() . ").";

Notez que nous affichons le résultat de time() deux fois ; c'est dans un but de
démonstration. Essayez de lancer la page et de la rafraîchir plusieurs fois ; vous allez
constater que le premier nombre ne change pas alors que le second change à chaque
actualisation. C'est parce que le premier nombre a été mis en cache et sauvegardé. Après
30 secondes ("lifeTime" a été mis à 30 secondes), le premier nombre devrait de nouveau
correspondre au second nombre parce que le cache a expiré -- seulement pour être mis
en cache de nouveau. Vous devriez essayer ce code dans votre navigateur ou dans une
console.

Lorsque vous utilisez Zend_Cache, faîtes attention à l'identifiant du cache


(passé à save() et start()). Il doit être unique pour chaque ressource que
vous mettez en cache, sinon il est possible que des caches en efface d'autres,
ou encore pire, s'affiche en lieu et place d'autres.

2. Aspect théorique
Il y a trois concepts clés dans Zend_Cache. Le premier est l'identifiant unique (une chaîne)
qui est utilisé pour identifier les enregistrements de cache. Le second est la directive "lifeTime"

220
Zend_Cache

vue dans les exemples ; elle définit combien de temps la ressource de cache est considérée
comme à jour. Le troisième est l'exécution conditionnelle, ainsi chaque partie de votre code
peut être évitée entièrement, pour améliorer methodname performances. La fonction principale
du frontend (Zend_Cache_Core::get()) est toujours faite pour retourner FALSE en cas de
cache manquant, si cela donne du sens à la nature d'un frontend. Cela permet aux utilisateurs
d'entourer des parties de code qu'ils veulent mettre en cache (et éviter) dans une instruction
if(){ ... } où la condition est une méthode Zend_Cache. A la fin de ces blocs, vous devez
sauvegarder ce que vous avez généré (par exemple Zend_Cache_Core::save()).

Le design de l'exécution conditionnelle de votre code généré n'est pas forcément


dans des frontends (Function, par exemple) quand toute la logique est
implémentée à l'intérieur du frontend.

Le "Cache hit" est un terme pour une condition quand l'enregistrement de cache
est trouvé, valide, et à jour (en d'autres mots, qu'il n'a pas encore expiré). Le
"Cache miss" est tout le reste. Lorsque un "Cache miss" survient, vous devez
générer vos données (comme vous le feriez normalement) et les mettre en cache.
Lorsque vous avez un "Cache hit", le backend récupère pour vous et de façon
transparente, les enregistrements.

2.1. La méthode de fabrique de Zend_Cache


Une bonne manière de construire une instance utilisable d'un frontend Zend_Cache est donnée
dans l'exemple suivant :

// Nous choisissons un backend (par exemple 'File' ou 'Sqlite')


$backendName = '[...]';

// Nous choisissons un frontend (par exemple: 'Core', 'Output',


// 'Page'...)
$frontendName = '[...]';

// Nous définissons un tableau d'options pour le frontend choisit


$frontendOptions = array([...]);

// Nous définissons un tableau d'options pour le banckend choisit


$backendOptions = array([...]);

// Nous créons la bonne instance


// Bien sur, les deux derniers arguments sont optionnels
$cache = Zend_Cache::factory($frontendName,
$backendName,
$frontendOptions,
$backendOptions);

Dans les exemples suivants, nous nous assurerons que la variable $cache utilise une instance
de frontend valide, et que vous comprenez comment passer des paramètres à vos backends.

Utilisez toujours Zend_Cache::factory() pour obtenir des instances de


frontend. Instancier des frontends et des backends par vous-même ne
fonctionnera pas comme prévu.

221
Zend_Cache

2.2. Baliser les enregistrements


Les balises sont un moyen de catégoriser les enregistrements de cache. Quand vous
sauvegardez un cache avec la méthode save() vous pouvez définir un tableau de balises
qui s'appliqueront à cet enregistrement. Ensuite vous serez en mesure de nettoyer tous les
enregistrements de cache identifiés par une balise (ou plusieurs) donnée :

$cache->save($grande_donnees,
'monIDUnique',
array('tagA', 'tagB', 'tagC'));

Notez que la méthode save() accepte un quatrième paramètre optionnel :


$specificLifetime (si différent de FALSE, il affecte un "lifeTime" spécifique
pour cet enregistrement de cache particulier).

2.3. Nettoyer le cache


Pour supprimer / invalider un identifiant de cache particulier, vous pouvez utiliser la méthode
remove() :

$cache->remove('idAEffacer');

Pour effacer / invalider plusieurs identifiants de caches en une seule opération, vous pouvez
utiliser la méthode clean(). Par exemple, pour supprimer tous les caches :

// nettoie tous les enregistrements


$cache->clean(Zend_Cache::CLEANING_MODE_ALL);

// nettoie uniquement les caches obsolètes


$cache->clean(Zend_Cache::CLEANING_MODE_OLD);

Si vous voulez effacer les caches correspondant aux balises "tagA" et "tagC" :

$cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG,
array('tagA', 'tagC'));

Si vous voulez effacer les caches ne correspondant pas aux balises "tagA" et "tagC" :

$cache->clean(Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG,
array('tagA', 'tagC'));

Si vous voulez effacer les caches correspondant aux balises "tagA" ou "tagC" :

$cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG,
array('tagA', 'tagC'));

Les modes disponibles de nettoyage sont CLEANING_MODE_ALL, CLEANING_MODE_OLD,


CLEANING_MODE_MATCHING_TAG, CLEANING_MODE_NOT_MATCHING_TAG et
CLEANING_MODE_MATCHING_ANY_TAG. Les derniers, comme leur nom l'indique, sont à
combiner avec un tableau de balises pour réaliser les opérations de nettoyage.

222
Zend_Cache

3. Les frontends Zend_Cache


3.1. Zend_Cache_Core
3.1.1. Introduction
Zend_Cache_Core est un frontend spécial parce qu'il est le coeur du module. C'est le frontend
de cache générique qui est étendu par les autres classes.

Tous les frontends héritent de Zend_Cache_Core ainsi ses méthodes et


options (décrites ci-dessous) seront aussi disponibles dans les autres frontends,
cependant ils ne sont pas documentés ici.

3.1.2. Options disponibles


Ces options sont passées à la méthode de fabrique comme montrées dans les exemples
précédents.

Tableau 19. Options du frontend Core


Option Type de données Valeur par défaut Description
caching Boolean TRUE Active / désactive le
cache (peut-être très
utile pour le débogage
de scripts en cache)
cache_id_prefix String NULL Un préfixe pour tous
les ID de cache, si
réglé à NULL, aucun
préfixe d'ID de cache
ne sera utilisé. Le
préfixe d'ID de cache
sert essentiellement à
créer des espaces
de noms dans le
cache, permettant à
plusieurs applications
ou sites Web d'utiliser
un cache partagé.
Chaque application ou
site web peut utilisé un
préfixe d'ID de cache
différent et un préfixe
peut aussi être utilisé
plusieurs fois.
lifetime Integer 3600 Temps de vie (en
secondes) du cache, si
défini à NULL, le cache
est valide indéfiniment
logging Boolean FALSE Si défini à TRUE, le
logging par Zend_Log
est activé (mais le
système sera plus lent)

223
Zend_Cache

Option Type de données Valeur par défaut Description


write_control Boolean TRUE Active / désactive
le contrôle d'écriture
(le cache est lu
juste après l'écriture
pour détecter des
entrées corrompues),
activer "writeControl"
va ralentir un petit
peu l'écriture du cache,
mais pas la lecture
(il peut détecter des
fichiers de cache
corrompus, mais ceci
n'est pas un contrôle
parfait).
automatic_serialization Boolean FALSE Active / désactive la
sérialisation
automatique, il peut
être utilisé pour
enregistrer
directement des
données qui ne sont
pas des chaînes de
caractères (mais c'est
plus lent).
automatic_cleaning_factor
Integer 0 Active / désactive le
nettoyage
automatique ("garbage
collector"): 0 signifie
aucun nettoyage
automatique de cache,
1 signifie un nettoyage
systématique du cache
et x > 1 signifie
le nettoyage aléatoire
1 fois toute les x
écritures.
ignore_user_abort Boolean FALSE Si réglé à TRUE,
le cache active
le drapeau PHP
"ignore_user_abort"
dans la méthode
save() pour prévenir
de la corruption du
cache dans certains
cas.

3.1.3. Exemples

Un exemple est donné dans le manuel, tout au début.

224
Zend_Cache

Si vous stocker uniquement des chaînes de caractères dans le cache (parce qu'avec l'option
"automatic_serialization", il est possible de stocker des booléens), vous pouvez utiliser une
construction plus compact comme :

// nous avons déjà $cache

$id = 'myBigLoop'; // id de cache de "ce que l'on veut cacher"

if (!($data = $cache->load($id))) {
// cache absent

$data = '';
for ($i = 0; $i < 10000; $i++) {
$data = $data . $i;
}

$cache->save($data);

// [...] fait quelque chose avec $data


// (affichage, passage ailleurs, etc, etc)

Si vous voulez cacher des blocs multiples ou des instances de données, l'idée reste la même :

// on s'assure que l'on utilise des identifiant uniques


$id1 = 'foo';
$id2 = 'bar';

// block 1
if (!($data = $cache->load($id1))) {
// cache absent

$data = '';
for ($i=0;$i<10000;$i++) {
$data = $data . $i;
}

$cache->save($data);

}
echo($data);

// ceci n'est pas affecté par la mise en cache


echo('NEVER CACHED! ');

// block 2
if (!($data = $cache->load($id2))) {
// cache missed

$data = '';
for ($i=0;$i<10000;$i++) {
$data = $data . '!';
}

$cache->save($data);

}
echo($data);

225
Zend_Cache

Si vous voulez cacher des valeurs "spéciales" (des booléens avec l'option
"automatic_serialization") ou des chaînes vides, vous ne pouvez pas utiliser la construction
compacte montrée ci-dessus. Vous devez tester de manière formelle l'état du cache.

// La construction compacte (ne pas utiliser si vous cachez


// des chaînes et/ou des booléens)
if (!($data = $cache->load($id))) {

// cache absent

// [...] on crée $data

$cache->save($data);

// on fait qqch avec $data

// [...]

// La construction complète (fonctionne dans tous les cas)


if (!($cache->test($id))) {

// cache absent

// [...] on crée $data

$cache->save($data);

} else {

// lecture du cache

$data = $cache->load($id);

// on fait qqch avec $data

3.2. Zend_Cache_Frontend_Output
3.2.1. Introduction
Zend_Cache_Frontend_Output est un frontend capturant la sortie. Il utilise la bufferisation
de sortie de PHP pour capturer tout ce qui passe entre les méthodes start() et end().

3.2.2. Options disponibles


Ce frontend n'a pas d'options spécifiques autres que celles de Zend_Cache_Core.

3.2.3. Exemples
Un exemple est donnée dans le manuel, tout au début. Le voici avec des changements mineurs :

// s'il y a un cache manquant, la bufferisation de sortie est lancée


if (!$cache->start('mypage')) {

226
Zend_Cache

// affiche tout comme d'habitude


echo 'Hello world! ';
echo 'This is cached ('.time().') ';

$cache->end(); // affiche ce qu'il y a dans le buffer


}

echo 'This is never cached ('.time().').';

Utiliser cette forme est assez simple pour définir une mise de cache de sortie dans vos projets
déjà en production, avec peu de refactorisation de code.

3.3. Zend_Cache_Frontend_Function
3.3.1. Introduction
Zend_Cache_Frontend_Function met en cache les résultats des appels de fonction. Elle a
une seule méthode principale appelée call() qui prend un nom de fonction et des paramètres
pour l'appel dans un tableau.

3.3.2. Options disponibles


Tableau 20. Options du frontend Function

Option Type de données Valeur par défaut Description


cache_by_default Boolean TRUE si TRUE, les appels de
fonction seront mis en
cache par défaut
cached_functions Array '' les noms de fonctions
seront toujours mis en
cache
non_cached_functions Array '' les noms de fonctions
ne doivent jamais être
mis en cache

3.3.3. Exemples
Utiliser la fonction call() est la même chose qu'utiliser call_user_func_array() en PHP :

$cache->call('veryExpensiveFunc', $params);

// $params est dans un tableau par exemple, pour appeler


// (avec mise en cache) : veryExpensiveFunc(1, 'foo', 'bar')
// vous devriez utiliser
$cache->call('veryExpensiveFunc', array(1, 'foo', 'bar'));

Zend_Cache_Frontend_Function est assez intelligente pour mettre en cache la valeur de


retour de la fonction, ainsi que sa sortie interne.

Vous pouvez passer n'importe quelle fonction utilisateur à l'exception de


array(), echo(), empty(), eval(), exit(), isset(), list(), print()
et unset().

227
Zend_Cache

3.4. Zend_Cache_Frontend_Class
3.4.1. Introduction
Zend_Cache_Frontend_Class est différent de Zend_Cache_Frontend_Function parce
qu'elle permet de mettre en cache les objets et les méthodes statiques.

3.4.2. Options disponibles


Tableau 21. Options du frontend Class
Option Type de données Valeur par défaut Description
cached_entity (requis) Mixed si défini avec un
nom de classe, nous
allons mettre en cache
une classe abstraite et
utiliser uniquement les
appels statiques ; si
défini avec un objet,
nous allons mettre en
cache les méthodes de
cet objet.
cache_by_default Boolean TRUE si TRUE, les appels
vont être cachés par
défaut
cached_methods Array les noms des
méthodes qui seront
toujours mis en cache
non_cached_methods Array les noms des
méthodes qui ne
doivent jamais être
mises en cache

3.4.3. Exemples
Par exemple, pour mettre en cache des appels statiques :

class test {

// Méthode statique
public static function foobar($param1, $param2) {
echo "foobar_output($param1, $param2)";
return "foobar_return($param1, $param2)";
}

// [...]
$frontendOptions = array(
'cached_entity' => 'test' // Le nom de la classe
);
// [...]

// l'appel caché
$res = $cache->foobar('1', '2');

228
Zend_Cache

Pour mettre en cache des appels classiques aux méthodes :

class test {

private $_string = 'hello !';

public function foobar2($param1, $param2) {


echo($this->_string);
echo "foobar2_output($param1, $param2)";
return "foobar2_return($param1, $param2)";
}

// [...]
$frontendOptions = array(
'cached_entity' => new test() // Une instance de la classe
);
// [...]

// L'appel mis en cache


$res = $cache->foobar2('1', '2');

3.5. Zend_Cache_Frontend_File
3.5.1. Introduction
Zend_Cache_Frontend_File est un frontend piloté par la modification d'un "fichier maître".
C'est vraiment intéressant, par exemple, dans les problématiques de configuration ou de
templates. Il est également possible d'utiliser plusieurs fichiers maîtres.

Par exemple, vous avez un fichier de configuration XML qui est analysé par une
fonction, celle-ci retourne un "objet de configuration" (comme avec Zend_Config). Avec
Zend_Cache_Frontend_File, vous pouvez stocker l'objet de configuration dans le cache
(pour éviter d'analyser le fichier de configuration XML chaque fois) mais avec une sorte de forte
dépendance au fichier maître. Ainsi si le fichier XML de configuration est modifié, le cache est
immédiatement invalide.

3.5.2. Options disponibles


Tableau 22. Options du frontend File

Option Type de données Valeur par défaut Description


master_file (déprécié) String '' le chemin complet et le
nom du fichier maître
master_files Array array() un tableau de chemin
complet de fichiers
maîtres
master_files_mode String Zend_Cache_Frontend_File::MODE_OR
Zend_Cache_Frontend_File::MODE
oU
Zend_Cache_Frontend_File::MODE
; si MODE_AND, alors
tous les fichiers
maîtres doivent être
modifiés pour rendre

229
Zend_Cache

Option Type de données Valeur par défaut Description


invalide le cache, si
MODE_OR, alors un
seul fichier maître
modifié est nécessaire
pour invalider le cache
ignore_missing_master_files
Boolean FALSE si TRUE, l'absence de
fichiers maîtres est
ignoré
silencieusement
(sinon une exception
est levée)

3.5.3. Exemples
L'utilisation de ce frontend est la même que celle de Zend_Cache_Core. Il n'y a pas besoin
d'exemple spécifique - la seule chose à faire est de définir le master_file lors de l'utilisation de
la fabrique.

3.6. Zend_Cache_Frontend_Page
3.6.1. Introduction
Zend_Cache_Frontend_Page est comme Zend_Cache_Frontend_Output mais créé pour
une page complète. Il est impossible d'utiliser Zend_Cache_Frontend_Page pour mettre en
cache un bloc unique.

D'un autre côté, le "cache ID", est calculé automatiquement avec $_SERVER['REQUEST_URI']
et (en fonction des options) $_GET, $_POST, $_SESSION, $_COOKIE, $_FILES. De plus, vous
avez seulement une méthode pour appeler (start()) parce que l'appel à end() est totalement
automatique lorsque la page est terminé.

Pour le moment, ceci n'est pas implémenté mais nous prévoyons d'ajouter un système de
condition HTTP pour économiser de la bande passante (le système émettra un en-tête "HTTP
304 Not Modified" si le cache est trouvé, et si le navigateur a déjà la bonne version).

3.6.2. Options disponibles


Tableau 23. Options du frontend Page
Option Type de données Valeur par défaut Description
http_conditional Boolean FALSE utilisez le système
"httpConditionnal" ou
pas (pas encore
implémenté)
debug_header Boolean FALSE si TRUE, un texte de
débogage est ajouté
avant chaque page de
cache
default_options Array array(...see un tableau associatif
below...) d'options par défaut :

• (boolean, TRUE par


défaut) cache : le

230
Zend_Cache

Option Type de données Valeur par défaut Description


cache est activé si
TRUE

• (boolean, FALSE
par défaut)
cache_with_get_variables
:
si TRUE, le cache
est toujours activé
même s'il y a des
variables dans le
tableau $_GET

• (boolean, FALSE
par défaut)
cache_with_post_variables
:
si TRUE, le cache
est toujours activé
même s'il y a des
variables dans le
tableau $_POST

• (boolean, FALSE
par défaut)
cache_with_session_variables
:
si TRUE, le cache
est toujours activé
s'il y a des variables
dans le tableau
$_SESSION

• (boolean, FALSE
par défaut)
cache_with_files_variables
:
si TRUE, le cache est
toujours activé s'il y
a des variables dans
le tableau $_FILES

• (boolean, FALSE
par défaut)
cache_with_cookie_variables
:
si TRUE, le cache
est toujours activé
s'il y a des variables
dans le tableau
$_COOKIE

• (boolean, TRUE par


défaut)
make_id_with_get_variables
:
si TRUE, l'identifiant
du cache sera
dépendant du

231
Zend_Cache

Option Type de données Valeur par défaut Description


contenu du tableau
$_GET

• (boolean, TRUE par


défaut)
make_id_with_post_variables
:
si TRUE, l'identifiant
du cache sera
dépendant du
contenu du tableau
$_POST

• (boolean, TRUE par


défaut)
make_id_with_session_variables
:
si TRUE, l'identifiant
du cache sera
dépendant du
contenu du tableau
$_SESSION

• (boolean, TRUE par


défaut)
make_id_with_files_variables
:
si TRUE, l'identifiant
du cache sera
dépendant du
contenu du tableau
$_FILES

• (boolean, TRUE par


défaut)
make_id_with_cookie_variables
:
si TRUE, l'identifiant
du cache sera
dépendant du
contenu du tableau
$_COOKIE

• (int, FALSE par


défaut)
specific_lifetime :
si TRUE, la
durée de vie
fournie sera utilisée
pour l'expression
régulière choisie

• (array, array() par


défaut) tags :
balises pour
l'enregistrement en
cache

232
Zend_Cache

Option Type de données Valeur par défaut Description


• (int, NULL par
défaut) priority :
priorité (si le
backend le
supporte)
regexps Array array() un tableau associatif
pour définir les
options, uniquement
pour certaines
REQUEST_URI, les
clés sont des
expressions régulières
PCRE, les valeurs
sont des tableaux
associatifs avec des
options spécifiques
pour définir si les
expressions régulières
correspondent dans
$_SERVER['REQUEST_URI']
(voir les options
par défaut pour la
liste des options
disponibles) ; si
plusieurs expressions
régulières
correspondent à un
$_SERVER['REQUEST_URI'],
seule la dernière sera
utilisée.
memorize_headers Array array() un tableau de chaînes
correspondant aux
noms d'en-têtes
HTTP. Les en-têtes
listés seront stockées
avec les données de
cache et renvoyées
lorsque le cache sera
rappelé.

3.6.3. Exemples

L'utilisation de Zend_Cache_Frontend_Page est vraiment trivial :

// [...] // require, configuration et factory

$cache->start();
// si le cache est trouvé, le résultat est envoyé au navigateur
// et le script s'arrête là

// reste de la page ...

233
Zend_Cache

Un exemple plus complexe qui montre un moyen pour obtenir une gestion centralisée du cache
dans un fichier d'amorçage (pour utiliser avec Zend_Controller par exemple)

// vous devriez éviter de mettre trop de lignes avant la section


// de cache par exemple, pour des performances optimales,
// "require_once" ou "Zend_Loader::loadClass" devrait être
// après la section de cache

$frontendOptions = array(
'lifetime' => 7200,
'debug_header' => true, // pour le déboguage
'regexps' => array(
// met en cache la totalité d'IndexController
'^/$' => array('cache' => true),

// met en cache la totalité d'IndexController


'^/index/' => array('cache' => true),

// nous ne mettons pas en cache l'ArticleController...


'^/article/' => array('cache' => false),

// ...mais nous mettons en cache l'action "view"


'^/article/view/' => array(
// de cet ArticleController
'cache' => true,

// et nous mettons en cache même lorsqu'il y a


// des variables dans $_POST
'cache_with_post_variables' => true,

// (mais le cache sera dépendent du tableau $_POST)


'make_id_with_post_variables' => true,
)
)
);
$backendOptions = array(
'cache_dir' => '/tmp/'
);

// obtenir un objet Zend_Cache_Frontend_Page


$cache = Zend_Cache::factory('Page',
'File',
$frontendOptions,
$backendOptions);

$cache->start();
// si nous trouvons un cache, le résultat est envoyé au navigateur,
// et le script s'arrête là

// [...] la fin du fichier de démarrage


// (ces lignes ne seront pas exécutées si on trouve un cache)

3.6.4. La méthode spécifique cancel()


A cause de problèmes de design, dans certains cas (par exemple quand on utilise des codes
de retour HTTP autres que 200), vous pouvez avoir besoin de stopper le processus de mise en
cache courant. Il a donc été introduit pour ce frontend en particulier, la méthode cancel().

// [...] require, configuration et fabrique

234
Zend_Cache

$cache->start();

// [...]

if ($unTest) {
$cache->cancel();
// [...]
}

// [...]

4. Les backends Zend_Cache


Il existe deux types de backends : les standards et les étendus. Bien sûr, les backends étendus
offrent des fonctionnalités supplémentaires.

4.1. Zend_Cache_Backend_File
Ces backends (étendus) stockent les enregistrements de cache dans des fichiers (dans un
dossier choisi).

Les options disponibles sont :

Tableau 24. Options du backend File


Option Type de données Valeur par défaut Description
cache_dir String /tmp/ Répertoire où stocker
les fichiers de cache
file_locking Boolean TRUE Active / désactive le
verrou de fichier :
peut éviter la
corruption du cache
dans de mauvaises
circonstances, mais il
n'aide en rien sur des
serveur multithreadés
ou sur des systèmes
de fichier NFS...
read_control Boolean TRUE Active / désactive le
contrôle de lecture :
si activé, une clé
de contrôle est
embarquée dans le
fichier de cache et
cette clé est comparée
avec celle calculée
après la lecture.
read_control_type String 'crc32' Type de contrôle de
lecture (seulement si
le contrôle de lecture
est activé). Les valeurs
disponibles sont :
"md5" (meilleur mais

235
Zend_Cache

Option Type de données Valeur par défaut Description


plus lent), "crc32" (un
peu moins sécurisé,
mais plus rapide, c'est
un meilleur choix),
"adler32" (nouveau
choix, plus rapide que
crc32),"strlen" pour un
test de longueur
uniquement (le plus
rapide).
hashed_directory_level Integer 0 Niveau de structure du
hash du répertoire :
0 signifie "pas
de hashage de
la structure du
répertoire", 1 signifie
"un niveau de
répertoire", 2 signifie
"deux niveaux"... Cette
option peut accélérer
le cache seulement
lorsque vous avez
plusieurs centaines
de fichiers de
cache. Seuls des
tests de performance
spécifiques peuvent
vous aider à choisir la
meilleure valeur pour
vous. 1 ou 2, peut-être
un bon départ.
hashed_directory_umask
Integer 0700 Umask pour
l'arborescence
file_name_prefix String 'zend_cache' Préfixe pour les
fichiers mis en cache ;
faîtes très attention
avec cette option,
en cas de valeur
trop générique dans
le dossier de cache
(comme /tmp), ceci
peut causer des
désastres lors du
nettoyage du cache.
cache_file_umask Integer 0700 umask des fichiers de
cache.
metatadatas_array_max_size
Integer 100 Taille maximale
interne pour les
tableaux de
métadonnées (ne

236
Zend_Cache

Option Type de données Valeur par défaut Description


changez pas cette
valeur à moins de bien
savoir ce que vous
faîtes).

4.2. Zend_Cache_Backend_Sqlite
Ce backend (étendu) stocke les enregistrements de cache dans une base de donnée SQLite.

Les options disponibles sont :

Tableau 25. Options du backend Sqlite

Option Type de données Valeur par défaut Description


cache_db_complete_path
String NULL Le chemin complet
(obligatoire) (nom du fichier inclus)
de la base de donnée
SQLite
automatic_vacuum_factor
Integer 10 Désactive / Active le
processus de vidange
automatique. Celui-ci
défragmente le fichier
de base de données
(et diminue sa
taille) quand clean()
ou delete() est
appelé : 0 pour une
vidange automatique ;
1 pour une
vidange systématique
(quand clean()
ou delete() est
appelé) ; x (entier)
> 1 pour une
vidange automatique
aléatoirement 1 fois
sur x clean() ou
delete().

4.3. Zend_Cache_Backend_Memcached
Ce backend (étendu) stocke les enregistrements de cache dans un serveur memcached.
Memcached est un système de cache en mémoire distribuée, de haute performance. Pour utiliser
ce backend, vous devez avoir un démon memcached et l'extension PECL memcache.

Attention : avec ce backend, les balises ("tags") ne sont pas supportées pour le moment comme
l'argument "doNotTestCacheValidity=true".

Les options disponibles sont :

237
Zend_Cache

Tableau 26. Options du backend Memcached

Option Type de données Valeur par défaut Description


servers Array array(array('host' => Un tableau de
'localhost', 'port' => serveurs memcached ;
11211, 'persistent' => chaque serveur
true, 'weight' => memcached est décrit
1, 'timeout' => 5, par un tableau
'retry_interval' => 15, associatif : 'host' =>
'status' => true, (string) : le nom du
'failure_callback' => serveur memcached,
'' )) 'port' => (int) : le port du
serveur memcached,
'persistent' => (bool) :
utilisation ou pas des
connexions
persistantes pour ce
serveur memcached,
'weight' => (int) :
le poids du serveur
memcached, 'timeout'
=> (int) : le time out du
serveur memcached,
'retry_interval' =>
(int) : l'intervalle avant
réexécution du serveur
memcached, 'status'
=> (bool) : le statut du
serveur memcached,
'failure_callback' =>
(callback) : le
failure_callback
d'échec du serveur
memcached.
compression Boolean FALSE TRUE, si vous voulez
utiliser la compression
à la volée
compatibility Boolean FALSE TRUE, si vous
voulez utiliser le
mode de compatibilité
avec les anciens
serveurs / extensions
memcache

4.4. Zend_Cache_Backend_Apc
Ce backend (étendu) stocke les enregistrements de cache en mémoire partagée grâce à
l'extension APC (Alternative PHP Cache) qui est requise pour utiliser ce backend.

Attention: avec ce backend, les balises ("tags") ne sont pas supportées pour le moment comme
l'argument "doNotTestCacheValidity=true".

Il n'y a pas d'options pour ce backend.

238
Zend_Cache

4.5. Zend_Cache_Backend_Xcache
Ce backend stocke ces enregistrements de cache dans la mémoire partagée à travers l'extension
XCache(qui est bien sûr nécessaire pour utiliser ce backend).

Attention : avec ce backend, les balises ("tags") ne sont pas supportées pour le moment comme
l'argument "doNotTestCacheValidity=true".

Les options disponibles sont :

Tableau 27. Options du backend Xcache


Option Type de données Valeur par défaut Description
user String NULL xcache.admin.user,
nécessaire pour la
méthode clean().
password String NULL xcache.admin.pass
(en texte clair non
MD5), nécessaire pour
la méthode clean().

4.6. Zend_Cache_Backend_ZendPlatform
Ce backend utilise l'API de cache de contenu de la Zend Platform. Naturellement, pour utiliser
ce backend, vous devez avoir installé une Zend Platorm.

Ce backend supporte les balises ("tags") mais ne supporte pas le mode de nettoyage
CLEANING_MODE_NOT_MATCHING_TAG.

Spécifiez ce backend en utilisant un séparateur de mot - "-", ".", " " ou "_" - entre les mots "Zend"
et "Platform" quand vous utilisez la méthode Zend_Cache::factory() :

$cache = Zend_Cache::factory('Core', 'Zend Platform');

Il n'y a pas d'options pour ce backend.

4.7. Zend_Cache_Backend_TwoLevels
Ce backend (étendu) est un hybride. Il stocke les enregistrements de cache dans deux autres
backends : un rapide (mais limité) comme Apc, Memcache... et un plus "lent" comme File, Sqlite...

Ce backend utilise le paramètre priorité (fourni au niveau du frontend au moment d'un


enregistrement) et l'espace restant dans le backend rapide pour optimiser l'utilisation de ces
deux backends.

Spécifiez ce backend avec un séparateur de mots - "-", ".", " ", ou "_" - entre les mots "Two" et
"Levels" quand vous utilisez la méthode Zend_Cache::factory() :

$cache = Zend_Cache::factory('Core', 'Two Levels');

Les options disponibles sont :

Tableau 28. Options du backend TwoLevels


Option Type de données Valeur par défaut Description
slow_backend String File le nom du backend
"lent"

239
Zend_Cache

Option Type de données Valeur par défaut Description


fast_backend String Apc le nom du backend
"rapide"
slow_backend_options Array array() les options du backend
"lent"
fast_backend_options Array array() les options du backend
"rapide"
slow_backend_custom_naming
Boolean FALSE si TRUE, l'argument
"slow_backend" est
utilisé en tant que
nom complet de
classe ; si FALSE,
l'argument frontend est
utilisé concaténé à
"Zend_Cache_Backend_<...>"
fast_backend_custom_naming
Boolean FALSE si TRUE, l'argument
"fast_backend" est
utilisé en tant que
nom complet de
classe ; si FALSE,
l'argument frontend est
utilisé concaténé à
"Zend_Cache_Backend_<...>"
slow_backend_autoloadBoolean FALSE si TRUE, il n'y
aura pas de
require_once pour le
"slow_backend" (utile
seulement pour les
backends
personnalisés)
fast_backend_autoload Boolean FALSE si TRUE, il n'y aura pas
de require_once pour
le "fast_backend" (utile
seulement pour les
backends
personnalisés)
auto_refresh_fast_cache
Boolean TRUE si TRUE,
rafraîchissement
automatique du cache
rapide quand un
enregistrement est
appelé
stats_update_factor Integer 10 désactive/personnalise
le calcul du
pourcentage de
remplissage du
backend rapide (lors
d'une sauvegarde d'un
enregistrement dans
le cache, le calcul

240
Zend_Cache

Option Type de données Valeur par défaut Description


du remplissage est
effectué aléatoirement
1 fois sur x écritures de
cache)

4.8. Zend_Cache_Backend_ZendServer_Disk et
Zend_Cache_Backend_ZendServer_ShMem
Ces backends utilisent les fonctionnalités de mise en cache de Zend Serverpour stocker les
données.

Attention : avec ces backends ne supportent pas les balises ("tags") pour le moment de même
que l'argument "doNotTestCacheValidity=true".

Ces backends fonctionnent seulement dans l'environnement de Zend Server pour les pages
requêtées à travers HTTP ou HTTPS et ne fonctionnent pas pour les scripts exécutés en ligne
de commande.

Spécifiez ce backend en utilisant le paramètre customBackendNaming à TRUE quand vous


utilisez la méthode Zend_Cache::factory() :

$cache = Zend_Cache::factory('Core', 'Zend_Cache_Backend_ZendServer_Disk',


$frontendOptions, $backendOptions, false, true);

Il n'y a pas d'options pour ce backend.

5. Le gestionnaire de Cache
Une application comporte par nature plusieurs caches de types différents fonctions du contrôleur
ou du modèle accédé. Afin de faciliter la création et la manipulation des options de Zend_Cache
au plus tôt (par exemple en bootstrap), Zend_Cache_Manager a été créée. Cette classe est
accompagnée de Zend_Application_Resource_Cachemanager pour tout ce qui concerne
le bootstrap et Zend_Controller_Action_Helper_Cache afin d'accéder aux caches depuis
les contrôleurs et autres aides d'action.

Le gestionnaire de cache utilise des templates, ce sont en fait des ensembles


de configurations valides pour un cache. Ces templates s'enregistrent grâce à
Zend_Cache_Manager::setCacheTemplate() et ne donnent naissance à un objet de
cache que lorsque Zend_Cache_Manager::getCache() sera appelée.

$manager = new Zend_Cache_Manager;

$dbCache = array(
'frontend' => array(
'name' => 'Core',
'options' => array(
'lifetime' => 7200,
'automatic_serialization' => true
)
),
'backend' => array(
'name' => 'Core',
'options' => array(

241
Zend_Cache

'cache_dir' => '/path/to/cache'


)
)
);

$manager->setCacheTemplate('database', $dbCache);

/**
* Partout ailleurs où le gestionnaire de cache est accessible...
*/
$databaseCache = $manager->getCache('database');

Le gestionnaire autorise aussi l'enregistrement d'objets de cache préalablement créés, ceci


grâce à la méthode Zend_Cache_Manager::setCache().

$frontendOptions = array(
'lifetime' => 7200,
'automatic_serialization' => true
);

$backendOptions = array(
'cache_dir' => '/path/to/cache'
);

$dbCache = Zend_Cache::factory('Core',
'File',
$frontendOptions,
$backendOptions);

$manager = new Zend_Cache_Manager;


$manager->setCache('database', $dbCache);

/**
* Partout ailleurs où le gestionnaire de cache est accessible...
*/
$databaseCache = $manager->getCache('database');

Si vous n'êtes pas sûr si le gestionnaire possède en lui un template de configuration ou un objet
de cache déja enregistré, vérifiez celà grâce à Zend_Cache_Manager::hasCache().

$manager = new Zend_Cache_Manager;

$dbCache = array(
'frontend' => array(
'name' => 'Core',
'options' => array(
'lifetime' => 7200,
'automatic_serialization' => true
)
),
'backend' => array(
'name' => 'Core',
'options' => array(
'cache_dir' => '/path/to/cache'
)
)
);

$manager->setCacheTemplate('database', $dbCache);

242
Zend_Cache

/**
* Partout ailleurs où le gestionnaire de cache est accessible...
*/
if ($manager->hasCache('database')) {
$databaseCache = $manager->getCache('database');
} else {
// Créer un cache à la main puisque non trouvé dans le gestionnaire
}

Dans certains cas, vous pouvez avoir défini un certain de cas d'utilisation avec
Zend_Cache_Manager, mais vous avez besoin de préciser un option dans un cas particulier.
Il est alors possible de modifier la configuration d'un template de cache après l'avoir saisie, ceci
au moyen de Zend_Cache_Manager::setTemplateOptions().

$manager = new Zend_Cache_Manager;

$dbCache = array(
'frontend' => array(
'name' => 'Core',
'options' => array(
'lifetime' => 7200,
'automatic_serialization' => true
)
),
'backend' => array(
'name' => 'Core',
'options' => array(
'cache_dir' => '/path/to/cache'
)
)
);

$manager->setCacheTemplate('database', $dbCache);

/**
* Partout ailleurs où le gestionnaire de cache est accessible...
* Ici nous changeons le support de stockage vers Memcache plutôt que ce
* qu'il était avant : File.
*/
$fineTuning = array(
'backend' => array(
'name' => 'Memcached',
'options' => array(
'servers' => array(
array(
'host' => 'localhost',
'port' => 11211,
'persistent' => true,
'weight' => 1,
'timeout' => 5,
'retry_interval' => 15,
'status' => true,
'failure_callback' => ''
)
)
)
)
);

243
Zend_Cache

$manager->setTemplateOptions('database', $fineTuning);
$databaseCache = $manager->getCache('database');

Pour rendre le gestionnaire de cache plus utile, il


est accompagné de Zend_Application_Resource_Cachemanager et
Zend_Controller_Action_Helper_Cache. Toutes deux sont décrites dans leurs pages
respectives de la documentation.

Aussi, Zend_Cache_Manager inclut déja quatre templates prédéfinis "skeleton", "default",


"page" et "tagcache". Le cache "default" utilise des fichiers comme stockage et un
Core comme frontend, il s'attend à posséder un dossier cache_dir appelé "cache" au
même niveau que le dossier normalisé "public" dans une application Zend Framework.
Le cache "skeleton" est un cache NULL, il ne comporte pas d'options. Les 2 autres
caches sont utilisés avec des pages statiques dans lesquelles du HTML, XML ou
encore JSON peut être stocké dans des fichiers statiques dans /public. Le contrôle
sur les pages statiques est assuré par Zend_Controller_Action_Helper_Cache,
même si vous pouvez changer les options "page", "tagcache" (par
exemple) en utilisant Zend_Cache_Manager::setTemplateOptions() ou même
Zend_Cache_Manager::setCacheTemplate().

244
Zend_Captcha
1. Introduction
CAPTCHA est l'acronyme anglais de "Completely Automated Public Turing test to tell Computers
and Humans Apart" [N.D.T. : test de Turing automatisé permettant de différencier un utilisateur
humain d'un ordinateur], il est utilisé comme contre-réponse pour s'assurer que l'émetteur de
l'information est un humain et pas un processus automatisé. Typiquement, un captcha est utilisé
lors de la soumission d'un formulaire quand des utilisateurs authentifiés ne sont pas nécessaires
mais si vous désirez empêcher la soumission de spam.

Les captchas peuvent prendre un variété de formes, incluant poser des questions de logique,
présenter des polices de travers, et présenter des images en demandant ce qu'elle représente.
Zend_Captcha a pour but de fournir une variété de backends qui peuvent être utilisés de
manière autonome ou en conjonction avec Zend_Form.

2. Opération Captcha
Tous les adaptateurs CAPTCHA implémentent Zend_Captcha_Adapter, qui ressemble à
ceci :

interface Zend_Captcha_Adapter extends Zend_Validate_Interface


{
public function generate();

public function render(Zend_View $view, $element = null);

public function setName($name);

public function getName();

public function getDecorator();

// De plus, pour satisfaire Zend_Validate_Interface :


public function isValid($value);

public function getMessages();

public function getErrors();


}

Le mutateur et l'accesseur "name" sont utilisés pour spécifier et récupérer l'identifiant du


CAPTCHA. getDecorator() peut être utilisé pour spécifier un décorateur Zend_Form soit
par son nom ou en retournant un objet décorateur. Les vraies clés sont utilisées sauf pour
generate() et render(). generate() est utilisé pour créer l'élément CAPTCHA. Ce
processus typiquement stockera l'élément en session ainsi il pourra être utilisé pour comparaison
dans les requêtes suivantes. render() est utilisé pour effectuer le rendu de l'information que
représente le CAPTCHA - en image, en texte Figlet, en problème logique, ou tout autre type
de CAPTCHA.

Un cas d'utilisation typique pourrait ressembler à ceci :

// Créer une instance de Zend_View

245
Zend_Captcha

$view = new Zend_View();

// Requête original :
$captcha = new Zend_Captcha_Figlet(array(
'name' => 'foo',
'wordLen' => 6,
'timeout' => 300,
));
$id = $captcha->generate();
echo $captcha->render($view);

// Lors de la requête suivante :


// suppose que $captcha a été paramètré avant,
// et que $value est la valeur soumise :
if ($captcha->isValid($_POST['foo'], $_POST)) {
// Validated!
}

3. Adaptateurs CAPTCHA
Les adaptateurs suivants sont fournis dans Zend Framework par défaut.

3.1. Zend_Captcha_Word
Zend_Captcha_Word est un adaptateur abstrait qui sert de classe de base pour la plupart
des autres adaptateurs CAPTCHA. Il fournit des mutateurs permettant de spécifier la taille
du mot le TTL de session, l'objet d'espace de noms de session à utiliser, et la classe
d'espace de noms de session à utiliser pour la persistance si vous ne souhaitez pas utiliser
Zend_Session_Namespace pour la persistance. Zend_Captcha_Word encapsule toute la
logique de validation.

Par défaut la taille du mot est de 8 caractères, le timeout de session est de 5 minutes et l'objet
d'espace de nom de session utilisé est Zend_Session_Namespace (avec l'espace de nom
("Zend_Form_Captcha_<captcha ID>").

En plus des méthodes standards fournies par Zend_Captcha_Adapter,


Zend_Captcha_Word propose les méthodes suivantes :

• setWordLen($length) et getWordLen() vous permettent de piloter la taille du "mot"


généré, en caractères.

• setTimeout($ttl) et getTimeout() vous donnent la main sur le temps-de-vie du jeton


de session. $ttl est exprimé en secondes.

• setSessionClass($class) et getSessionClass() vous permettent de piloter la classe


de session, si vous désirez utiliser une alternative à Zend_Session_Namespace, ceci dans
le but de faire persister le jeton CAPTCHA en session.

• getId() retourne l'identifiant du jeton actuel.

• getWord() retourne le mot généré utilisé avec le CAPTCHA. Il sera généré pour vous si
aucun n'existe déjà.

• setSession(Zend_Session_Namespace $session) permet d'injecter un objet de


session qui sera utilisé pour faire persister le jeton de CAPTCHA. getSession() retourne
l'objet de session actuellement utilisé.

246
Zend_Captcha

Tous les CAPTCHA Word vous autorisent à passer un tableau d'options au constructeur, ou à
setOptions() (un objet Zend_Config peut être utilisé avec setConfig()). Par défaut, les
clés timeout wordLen et sessionClass seront utilisées.

Zend_Captcha_Word est une classe abstraite et ne peut être utilisée


directement.

3.2. Zend_Captcha_Dumb
L'adaptateur Zend_Captch_Dumb propose une chaine aléatoire qui doit être ressaisie,
mais inversée. Ce n'est pas une solution CAPTCHA idéale (un robot peut la détourner), il
devrait être utilisé comme solution de remplacement extrême, ou pour les tests. Il étend
Zend_Captcha_Word.

3.3. Zend_Captcha_Figlet
L'adaptateur Zend_Captcha_Figlet utilise Zend_Text_Figlet pour présenter un captcha.
Seuls les caractères alphabétiques sont utilisables.

Les options passées au constructeur le seront pour l'objet Zend_Text_Figlet que l'adaptateur
va utiliser. Voyez la documentation de Zend_Text_Figletpour plus d'informations.

3.4. Zend_Captcha_Image
L'adaptateur Zend_Captcha_Image prend le mot généré et le transforme en image
difficile à analyser pour un programme informatique (robot). Pour cela, il nécessite
l'extension GD, compilée avec le support TrueType et Freetype. Actuellement, l'adaptateur
Zend_Captcha_Image ne génère que des images PNG.

Zend_Captcha_Image étend Zend_Captcha_Word, et propose les méthodes additionnelles


suivantes :

• setExpiration($expiration) et getExpiration() vous autorisent à manipuler le


temps maximum que l'image CAPTCHA doit rester sur le disque. En général, il s'agit d'un
temps supérieur à celui de la session. Un ramasse-miettes passe régulièrement à chaque
instanciation de l'objet CAPTCHA Image : il détruit les images arrivées à expiration. La période
d'expiration doit être exprimée en secondes.

• setGcFreq($gcFreq) et getGcFreg() vous permettent de manipuler la fréquence de


collecte du ramasse-miettes des images. Le ramasse-miettes passera à une fréquence de 1/
$gcFreq. Par défaut 1 / 100, soit toutes les 100 requêtes.

• setFont($font) et getFont() vous donnent le moyen de manipuler la police que vous


souhaitez utiliser. $font doit indiquer le chemin complet vers la police à utiliser pour générer
le CAPTCHA. Une exception sera levée si vous ne spécifiez pas ce paramètre.

• setFontSize($fsize) et getFontSize() servent pour spécifier et récupérer la taille de


la police à utiliser (en pixels) pour générer l CAPTCHA. Par défaut : 24px.

• setHeight($height) et getHeight() servent pour spécifier et récupérer la hauteur de


la police à utiliser (en pixels) pour générer le CAPTCHA. Par défaut : 50px.

• setWidth($width) et getWidth() servent pour spécifier et récupérer la largeur de la


police à utiliser (en pixels) pour générer le CAPTCHA. Par défaut : 200px.

247
Zend_Captcha

• setImgDir($imgDir) et getImgDir() vous permettent de manipuler le dossier dans


lequel les images CAPTCHA générées seront stockées. Par défaut, il s'agit de "./images/
captcha/", qui devrait être pris relativement au fichier de bootstrap du site.

• setImgUrl($imgUrl) et getImgUrl() vous donnent le moyen de manipuler le chemin


relatif à utiliser pour la balise HTML servant à afficher l'image du CAPTCHA. Par défaut, il
s'agit de "/images/captcha/".

• setSuffix($suffix) et getSuffix() vous donnent la main sur le suffixe à utiliser pour


le nom du fichier de l'image générée par le CAPTCHA. Il s'agit par défaut de ".png". Note :
changer ceci ne changera pas le type de l'image générée.

Toutes les options ci-dessus peuvent aussi être passées en constructeur. Supprimer la partie
"set" de leur méthodes, et passez leur première lettre en minuscule pour avoir les clés du tableau
d'options que le constructeur utilise. ("suffix", "height", "imgUrl", etc...).

3.5. Zend_Captcha_ReCaptcha
L'adaptateur Zend_Captcha_ReCaptcha utilise Zend_Service_ReCaptcha pour générer des
CAPTCHA. Les méthodes suivantes lui sont propres :

• setPrivKey($key) et getPrivKey() vous permettent de gérer la clé privée utilisée avec


le service ReCaptcha. Cette clé doit être spécifiée en constructeur, mais peut être ensuite
modifiée.

• setPubKey($key) et getPubKey() vous permettent de gérer la clé publique utilisée avec


le service ReCaptcha. Cette clé doit être spécifiée en constructeur, mais peut être ensuite
modifiée.

• setService(Zend_Service_ReCaptcha $service) et getService() vous


permettent d'interagir directement avec l'objet service ReCaptcha utilisé par l'adaptateur.

248
Zend_CodeGenerator
1. Introduction
Zend_CodeGenerator est un outils permettant de générer du code PHP en utilisant une
interface orientée objet. Il peut générer ou mettre à jour du code. Il est aussi possible d'étendre
ces classes afin de changer le langage de référence pour générer du Javascript, des hôtes
virtuels Apache ..., par exemple.

1.1. Théorie
Dans la plupart des cas, vous créerez une instance du générateur de code, et vous le configurez.
Pour afficher le code généré, un simple echo suffira, ou l'appel à sa méthode generate().

// Passage de configuration au constructor:


$file = new Zend_CodeGenerator_Php_File(array(
'classes' => array(
new Zend_CodeGenerator_Php_Class(array(
'name' => 'World',
'methods' => array(
new Zend_CodeGenerator_Php_Method(array(
'name' => 'hello',
'body' => 'echo \'Hello world!\';',
)),
),
)),
)
));

// Configuration après instanciation


$method = new Zend_CodeGenerator_Php_Method();
$method->setName('hello')
->setBody('echo \'Hello world!\';');

$class = new Zend_CodeGenerator_Php_Class();


$class->setName('World')
->setMethod($method);

$file = new Zend_CodeGenerator_Php_File();


$file->setClass($class);

// Rendu du fichier généré:


echo $file;

// 2criture du fichier généré:


file_put_contents('World.php', $file->generate());

Les 2 exemples ci-dessus vont rendre le même résultat :

<?php

class World
{

249
Zend_CodeGenerator

public function hello()


{
echo 'Hello world!';
}

Il est aussi possible de mettre à jour un code existant, par exemple, ajouter une méthode
à une classe. Dans ce cas, vous devez inspecter le code existant en utilisant la réflexion,
puis ajouter une nouvelle méthode. Zend_CodeGenerator rend ceci très simple en utilisant
Zend_Reflection.

Par exemple, imaginons que nous avons sauvegardé le code de l'exemple ci-dessus dans un
fichier "World.php" que nous avons alors inclus. Nous pourrions dès lors agir comme suit :

$class = Zend_CodeGenerator_Php_Class::fromReflection(
new Zend_Reflection_Class('World')
);

$method = new Zend_CodeGenerator_Php_Method();


$method->setName('mrMcFeeley')
->setBody('echo \'Hello, Mr. McFeeley!\';');
$class->setMethod($method);

$file = new Zend_CodeGenerator_Php_File();


$file->setClass($class);

// Rendu du code généré


echo $file;

// Ou encore sauvegarde par dessus l'ancien fichier


file_put_contents('World.php', $file->generate());

La nouvelle classe ressemblera à ça :

<?php

class World
{

public function hello()


{
echo 'Hello world!';
}

public function mrMcFeeley()


{
echo 'Hellow Mr. McFeeley!';
}

250
Zend_CodeGenerator

2. Exemples Zend_CodeGenerator
Exemple 63. Génération de classes PHP

L'exemple suivant génère le code d'une classe avec son bloc de commentaires PHPDoc.

$foo = new Zend_CodeGenerator_Php_Class();


$docblock = new Zend_CodeGenerator_Php_Docblock(array(
'shortDescription' => 'Sample generated class',
'longDescription' => 'This is a class generated with Zend_CodeGenerator.',
'tags' => array(
array(
'name' => 'version',
'description' => '$Rev:$',
),
array(
'name' => 'license',
'description' => 'New BSD',
),
),
));
$foo->setName('Foo')
->setDocblock($docblock);
echo $foo->generate();

Le résultat est :

/**
* Sample generated class
*
* This is a class generated with Zend_CodeGenerator.
*
* @version $Rev:$
* @license New BSD
*
*/
class Foo
{

251
Zend_CodeGenerator

Exemple 64. Générer des classes PHP avec des attributs de classe
Suivant l'exemple précédant, nous ajoutons maintenant des attributs à la classe.
$foo = new Zend_CodeGenerator_Php_Class();
$docblock = new Zend_CodeGenerator_Php_Docblock(array(
'shortDescription' => 'Sample generated class',
'longDescription' => 'This is a class generated with Zend_CodeGenerator.',
'tags' => array(
array(
'name' => 'version',
'description' => '$Rev:$',
),
array(
'name' => 'license',
'description' => 'New BSD',
),
),
));
$foo->setName('Foo')
->setDocblock($docblock)
->setProperties(array(
array(
'name' => '_bar',
'visibility' => 'protected',
'defaultValue' => 'baz',
),
array(
'name' => 'baz',
'visibility' => 'public',
'defaultValue' => 'bat',
),
array(
'name' => 'bat',
'const' => true,
'defaultValue' => 'foobarbazbat',
),
));
echo $foo->generate();

Le résultat sera :
/**
* Sample generated class
*
* This is a class generated with Zend_CodeGenerator.
*
* @version $Rev:$
* @license New BSD
*
*/
class Foo
{

protected $_bar = 'baz';

public $baz = 'bat';

const bat = 'foobarbazbat';

252
->setProperties(array(
array(
'name' => '_bar',
'visibility' => 'protected',
Zend_CodeGenerator
'defaultValue' => 'baz',
),
array(
'name'
Exemple 65. => 'baz',
Générer des classes PHP avec des méthodes
'visibility' => 'public',
'defaultValue' => 'bat',
),
array(
'name' => 'bat',
'const' => true,
'defaultValue' => 'foobarbazbat',
),
))
->setMethods(array(
// Method passed as array
array(
'name' => 'setBar',
'parameters' => array(
array('name' => 'bar'),
),
'body' => '$this->_bar = $bar;' . "\n" . 'return $this;',
'docblock' => new Zend_CodeGenerator_Php_Docblock(array(
'shortDescription' => 'Set the bar property',
/** 'tags' => array(
* Sample generated class
new Zend_CodeGenerator_Php_Docblock_Tag_Param(array(
* 'paramName' => 'bar',
* This is a class generated with Zend_CodeGenerator.
'datatype' => 'string'
* )),
* @version $Rev:$ new Zend_CodeGenerator_Php_Docblock_Tag_Return(array(
* @license New BSD 'datatype' => 'string',
*/ )),
class Foo ),
{ )),
),
protected
// Method$_bar = 'baz';
passed as concrete instance
new Zend_CodeGenerator_Php_Method(array(
Le résultat sera :
public $baz
'name'= 'bat';
=> 'getBar',
'body' => 'return $this->_bar;',
const bat = 'foobarbazbat';
'docblock' => new Zend_CodeGenerator_Php_Docblock(array(
'shortDescription' => 'Retrieve the bar property',
/** 'tags' => array(
* Set the bar property
new Zend_CodeGenerator_Php_Docblock_Tag_Return(array(
* 'datatype' => 'string|null',
* @param string)), bar
* @return string
),
*/ )),
public
)),function setBar($bar)
{
));
$this->_bar = $bar;
return $this;
echo $foo->generate();
}

/**
* Retrieve the bar property
*
* @return string|null
*/
public function getBar()
{
return $this->_bar;
}

253
Zend_CodeGenerator

Zend_CodeGenerator_Php_File sert à générer le contenu de fichiers PHP. Il est


possible d'insérer
Exemple du codedes
66. Générer de fichiers
classes,PHP
ou n'importe quel code. Si vous attachez des
Dans
$file l'exemple
classes,= vous suivant, nous supposons
sousque
new Zend_CodeGenerator_Php_File(array(
pouvez les passer vous de
forme avez défini $foo
tableaux ou comme étant d'objets
directement le code
d'une des classes
'classes' des
=> exemples précédents.
array($foo);
Zend_CodeGenerator_Php_Class.
'docblock' => new Zend_CodeGenerator_Php_Docblock(array(
'shortDescription' => 'Foo class file',
'tags' => array(
array(
'name' => 'license',
'description' => 'New BSD',
),
),
<?php )),
L'appel
Le
/**
$code =à generate()
résultat
'body' va générer le code, mais pas l'écrire
sera : => 'define(\'APPLICATION_ENV\',
$file->generate(); dans un fichier. Pour ce faire,
\'testing\');',
ilfile_put_contents('Foo.php',
));*faudra d'abordfile
Foo class capturer le contenu:
$code);
*
* @license New BSD
*/

/**
* Sample generated class
*
* This is a class generated with Zend_CodeGenerator.
*
* @version $Rev:$
* @license New BSD
*/
class Foo
{

protected $_bar = 'baz';

public $baz = 'bat';

const bat = 'foobarbazbat';

/**
* Set the bar property
*
* @param string bar
* @return string
*/
public function setBar($bar)
{
$this->_bar = $bar;
return $this;
}

/**
* Retrieve the bar property
*
* @return string|null
*/
public function getBar()
{
return $this->_bar;
}

define('APPLICATION_ENV', 'testing');

254
Zend_CodeGenerator

Exemple 67. Ajouter du code à un fichier PHP existant en utilisant la réflexion

Vous pouvez ajouter du code PHP à n'importe quel fichier PHP existant à condition d'utiliser
la réflexion sur celui-ci afin de l'analyser. La méthode fromReflectedFileName() va
vous y aider.

$generator = Zend_CodeGenerator_Php_File::fromReflectedFileName($path);
$body = $generator->getBody();
$body .= "\n\$foo->bar();";
file_put_contents($path, $generator->generate());

Exemple 68. Ajouter du code à une classe PHP existante en utilisant la réflexion

Vous pouvez aussi ajouter du code à une classe existante. Utilisez fromReflection()
pour transformer la classe en objet Reflection. Ajoutez ensuite des méthodes, des attributs,
puis régénérez le code de la classe modifiée :

$generator = Zend_CodeGenerator_Php_Class::fromReflection(
new Zend_Reflection_Class($class)
);
$generator->setMethod(array(
'name' => 'setBaz',
'parameters' => array(
array('name' => 'baz'),
),
'body' => '$this->_baz = $baz;' . "\n" . 'return $this;',
'docblock' => new Zend_CodeGenerator_Php_Docblock(array(
'shortDescription' => 'Set the baz property',
'tags' => array(
new Zend_CodeGenerator_Php_Docblock_Tag_Param(array(
'paramName' => 'baz',
'datatype' => 'string'
)),
new Zend_CodeGenerator_Php_Docblock_Tag_Return(array(
'datatype' => 'string',
)),
),
)),
));
$code = $generator->generate();

3. Zend_CodeGenerator Réference
3.1. Classes abstraites et interfaces
3.1.1. Zend_CodeGenerator_Abstract
La classe de base de CodeGenerator dont toutes les classes héritent. Elle propose l'API
suivante :

abstract class Zend_CodeGenerator_Abstract


{
final public function __construct(Array $options = array())
public function setOptions(Array $options)
public function setSourceContent($sourceContent)
public function getSourceContent()
protected function _init()
protected function _prepare()

255
Zend_CodeGenerator

abstract public function generate();


final public function __toString()
}

Le constructeur appelle _init() (restée vide, à écrire dans les classes concrètes), puis passe
le paramètre $options à setOptions(), et enfin appelle _prepare() (encore une fois, vide,
à écrire dans les classes concrètes).

Comme partout dans Zend Framework, setOptions() compare les clés du tableau passé
comme paramètre à des setters de la classe, et passe donc la valeur à la bonne méthode si
trouvée.

__toString() est marquée final, et proxie vers generate().

setSourceContent() et getSourceContent() permettent soit de définir le contenu par


défaut soit de remplacer ce contenu par la tâche de génération.

3.1.2. Zend_CodeGenerator_Php_Abstract
Zend_CodeGenerator_Php_Abstract étend Zend_CodeGenerator_Abstract et ajoute
des méthodes permettant de savoir si le contenu a changé et aussi le nombre d'indentation à
utiliser avant chaque ligne de code à générer. L'API est la suivante :

abstract class Zend_CodeGenerator_Php_Abstract


extends Zend_CodeGenerator_Abstract
{
public function setSourceDirty($isSourceDirty = true)
public function isSourceDirty()
public function setIndentation($indentation)
public function getIndentation()
}

3.1.3. Zend_CodeGenerator_Php_Member_Abstract
Zend_CodeGenerator_Php_Member_Abstract est une classe de base pour générer des
propriétés ou des méthodes de classe, et propose des accesseurs et des mutateurs pour créer
la visibilité, l'abstraction, la staticité ou la finalité. L'API est la suivante :

abstract class Zend_CodeGenerator_Php_Member_Abstract


extends Zend_CodeGenerator_Php_Abstract
{
public function setAbstract($isAbstract)
public function isAbstract()
public function setStatic($isStatic)
public function isStatic()
public function setVisibility($visibility)
public function getVisibility()
public function setName($name)
public function getName()
}

3.2. Classes CodeGenerator concrêtes


3.2.1. Zend_CodeGenerator_Php_Body
Zend_CodeGenerator_Php_Body est utilisée pour générer du code procédural à inclure dans
un fichier. Vous passez donc simplement du contenu à cet objet, qui vous le ressortira une fois
son generate() appelé.

256
Zend_CodeGenerator

L'API de cette classe est comme suit :

class Zend_CodeGenerator_Php_Body extends Zend_CodeGenerator_Php_Abstract


{
public function setContent($content)
public function getContent()
public function generate()
}

3.2.2. Zend_CodeGenerator_Php_Class

Zend_CodeGenerator_Php_Class est utilisée pour générer du code de classes PHP. Les


fonctions de bases génèrent la classe PHP elle-même, ainsi que ses commentaires PHP
DocBlock. Vous pouvez bien sûr spécifier la classe comme abstraite, finale, ou encore lui rajouter
des constantes / attributs / méthodes sous forme d'autres objets décrits eux aussi dans ce
chapitre.

Voici l'API :

class Zend_CodeGenerator_Php_Class extends Zend_CodeGenerator_Php_Abstract


{
public static function fromReflection(
Zend_Reflection_Class $reflectionClass
)
public function setDocblock(Zend_CodeGenerator_Php_Docblock $docblock)
public function getDocblock()
public function setName($name)
public function getName()
public function setAbstract($isAbstract)
public function isAbstract()
public function setExtendedClass($extendedClass)
public function getExtendedClass()
public function setImplementedInterfaces(Array $implementedInterfaces)
public function getImplementedInterfaces()
public function setProperties(Array $properties)
public function setProperty($property)
public function getProperties()
public function getProperty($propertyName)
public function setMethods(Array $methods)
public function setMethod($method)
public function getMethods()
public function getMethod($methodName)
public function hasMethod($methodName)
public function isSourceDirty()
public function generate()
}

La méthode setProperty() accepte soit un tableau qui peut être utilisé pour générer
une instance de Zend_CodeGenerator_Php_Property, soit directement une instance de
Zend_CodeGenerator_Php_Property. setMethod() se manipule de la même manière, et
utilise une instance de Zend_CodeGenerator_Php_Method.

A noter que setDocBlock() attend une instance de


Zend_CodeGenerator_Php_DocBlock.

257
Zend_CodeGenerator

3.2.3. Zend_CodeGenerator_Php_Docblock
Zend_CodeGenerator_Php_Docblock est utilisée pour générer des éléments PHP arbitraire,
y compris les commentaires de description longs ou courts.

Les tags annotation doivent être spécifiés via setTag() ou setTags() qui prennent en
paramètre un objet Zend_CodeGenerator_Php_Docblock_Tag ou un tableau qui permettra
sa construction.

Voici l'API :

class Zend_CodeGenerator_Php_Docblock extends Zend_CodeGenerator_Php_Abstract


{
public static function fromReflection(
Zend_Reflection_Docblock $reflectionDocblock
)
public function setShortDescription($shortDescription)
public function getShortDescription()
public function setLongDescription($longDescription)
public function getLongDescription()
public function setTags(Array $tags)
public function setTag($tag)
public function getTags()
public function generate()
}

3.2.4. Zend_CodeGenerator_Php_Docblock_Tag
Zend_CodeGenerator_Php_Docblock_Tag est utilisée pour créer des tags d'annotation
PHP DocBlck. Les tags doivent posséder un nom (la partie qui suit immédiatement le '@') et une
description (ce qui suit le tag).

Voici l'API :

class Zend_CodeGenerator_Php_Docblock_Tag
extends Zend_CodeGenerator_Php_Abstract
{
public static function fromReflection(
Zend_Reflection_Docblock_Tag $reflectionTag
)
public function setName($name)
public function getName()
public function setDescription($description)
public function getDescription()
public function generate()
}

3.2.5. Zend_CodeGenerator_Php_DocBlock_Tag_Param
Zend_CodeGenerator_Php_DocBlock_Tag_Param est une version spéciale de
Zend_CodeGenerator_Php_DocBlock_Tag, et permet de représenter un paramètre d'une
méthode. Le nom du tag est donc connu, mais des informations additionnelles sont requises :
le nom du paramètre et le type de données qu'il représente.

L'API de cette classe est la suivante :

class Zend_CodeGenerator_Php_Docblock_Tag_Param

258
Zend_CodeGenerator

extends Zend_CodeGenerator_Php_Docblock_Tag
{
public static function fromReflection(
Zend_Reflection_Docblock_Tag $reflectionTagParam
)
public function setDatatype($datatype)
public function getDatatype()
public function setParamName($paramName)
public function getParamName()
public function generate()
}

3.2.6. Zend_CodeGenerator_Php_DocBlock_Tag_Return
Zend_CodeGenerator_Php_Docblock_Tab_Return est une variante qui permet de
modéliser la valeur de retour d'une méthode. Dans ce cas, le nom du tag est connu ('return')
mais pas le type de retour.

Voici l'API :

class Zend_CodeGenerator_Php_Docblock_Tag_Param
extends Zend_CodeGenerator_Php_Docblock_Tag
{
public static function fromReflection(
Zend_Reflection_Docblock_Tag $reflectionTagReturn
)
public function setDatatype($datatype)
public function getDatatype()
public function generate()
}

3.2.7. Zend_CodeGenerator_Php_File
Zend_CodeGenerator_Php_File est utilisée pour générer le contenu complet d'un fichier
PHP. Le fichier peut contenir des classes, du code PHP ou encore des commentaires PHPDoc.

Pour ajouter des classes, vous devrez soit passer un tableau d'informations à
passer au constructeur de Zend_CodeGenerator_Php_Class, soit un objet de cette
dernière classe directement. Idem concernant les commentaires PHPDoc et la classe
Zend_CodeGenerator_Php_Docblock

Voici l'API de la classe :

class Zend_CodeGenerator_Php_File extends Zend_CodeGenerator_Php_Abstract


{
public static function fromReflectedFilePath(
$filePath,
$usePreviousCodeGeneratorIfItExists = true,
$includeIfNotAlreadyIncluded = true)
public static function fromReflection(Zend_Reflection_File $reflectionFile)
public function setDocblock(Zend_CodeGenerator_Php_Docblock $docblock)
public function getDocblock()
public function setRequiredFiles($requiredFiles)
public function getRequiredFiles()
public function setClasses(Array $classes)
public function getClass($name = null)
public function setClass($class)
public function setFilename($filename)

259
Zend_CodeGenerator

public function getFilename()


public function getClasses()
public function setBody($body)
public function getBody()
public function isSourceDirty()
public function generate()
}

3.2.8. Zend_CodeGenerator_Php_Member_Container
Zend_CodeGenerator_Php_Member_Container est utilisée en interne par
Zend_CodeGenerator_Php_Class pour garder une trace des attributs et des méthodes de
classe. Ceux-ci sont indéxés par nom.

Voici l'API de cette classe :

class Zend_CodeGenerator_Php_Member_Container extends ArrayObject


{
public function __construct($type = self::TYPE_PROPERTY)
}

3.2.9. Zend_CodeGenerator_Php_Method
Zend_CodeGenerator_Php_Method est utilisée pour décrire une méthode d'une classe,
et va générer son code, et ses éventuels commentaires PHPDoc. La visibilité et
le statut (abstraite, finale, statique) peuvent être spécifiées par la classe parente
Zend_CodeGenerator_Php_Member_Abstract. Enfin, il est aussi possible de spécifier les
paramètres de la méthodes, et sa valeur de retour.

Les paramètres peuvent être indiqués via setParameter() ou setParameters()


qui acceptent soit des tableaux décrivant les paramètres à passer au constructeur
deZend_CodeGenerator_Php_Parameter, soit des objets de cette dernière classe.

L'API de cette classe est la suivante :

class Zend_CodeGenerator_Php_Method
extends Zend_CodeGenerator_Php_Member_Abstract
{
public static function fromReflection(
Zend_Reflection_Method $reflectionMethod
)
public function setDocblock(Zend_CodeGenerator_Php_Docblock $docblock)
public function getDocblock()
public function setFinal($isFinal)
public function setParameters(Array $parameters)
public function setParameter($parameter)
public function getParameters()
public function setBody($body)
public function getBody()
public function generate()
}

3.2.10. Zend_CodeGenerator_Php_Parameter
Zend_CodeGenerator_Php_Parameter est utilisée pour décrire un paramètre de méthode.
Chacun doit avoir une position (sinon l'ordre de leur enregistrement sera utilisé par défaut), une
valeur par défaut, un type et enfin un nom.

260
Zend_CodeGenerator

Voici l'API :

class Zend_CodeGenerator_Php_Parameter extends Zend_CodeGenerator_Php_Abstract


{
public static function fromReflection(
Zend_Reflection_Parameter $reflectionParameter
)
public function setType($type)
public function getType()
public function setName($name)
public function getName()
public function setDefaultValue($defaultValue)
public function getDefaultValue()
public function setPosition($position)
public function getPosition()
public function getPassedByReference()
public function setPassedByReference($passedByReference)
public function generate()
}

Plusieurs problèmes peuvent apparaitre lorsque l'on veut paramétrer un null, un


booléen ou un tableau en tant que valeur par défaut. Pour ceci le conteneur
Zend_CodeGenerator_Php_ParameterDefaultValue peut être utilisé, par exemple :

$parameter = new Zend_CodeGenerator_Php_Parameter();


$parameter->setDefaultValue(
new Zend_CodeGenerator_Php_Parameter_DefaultValue("null")
);
$parameter->setDefaultValue(
new Zend_CodeGenerator_Php_Parameter_DefaultValue("array('foo', 'bar')")
);

En interne setDefaultValue() convertit aussi les valeurs qui peuvent être exprimées en PHP
dans le conteneur.

3.2.11. Zend_CodeGenerator_Php_Property
Zend_CodeGenerator_Php_Property est utilisée pour décrire une propriété, nous
entendons par là une variable ou une constante. Une valeur par défaut peut alors
être spécifiée. La visibilité de la propriété peut être définie par la classe parente,
Zend_CodeGenerator_Php_Member_Abstract.

Voici l'API :

class Zend_CodeGenerator_Php_Property
extends Zend_CodeGenerator_Php_Member_Abstract
{
public static function fromReflection(
Zend_Reflection_Property $reflectionProperty
)
public function setConst($const)
public function isConst()
public function setDefaultValue($defaultValue)
public function getDefaultValue()
public function generate()
}

261
Zend_Config
1. Introduction
Zend_Config est conçu pour simplifier l'accès et l'utilisation des données de configuration dans
les applications. Il fournit une interface utilisateur basée sur des propriétés d'objets imbriquées.
Les données de configuration peuvent venir de sources variées supportant une organisation
hiérarchique des données. Actuellement Zend_Config fournit des adaptateurs pour les
données de configuration qui sont stockées dans des fichier textes avec Zend_Config_Ini
et Zend_Config_Xml.

Exemple 69. Utilisation native de Zend_Config

Normalement on s'attend à ce que les utilisateurs emploient une des classes


d'adaptateur telles que Zend_Config_Ini ou Zend_Config_Xml, mais si les données
de configuration sont disponibles dans un tableau PHP, on peut simplement passer les
données au constructeur de Zend_Config afin d'utiliser une interface orientée objet
simple :

// Fourni un tableau de configuration


$configArray = array(
'webhost' => 'www.example.com',
'database' => array(
'adapter' => 'pdo_mysql',
'params' => array(
'host' => 'db.example.com',
'username' => 'dbuser',
'password' => 'secret',
'dbname' => 'mydatabase'
)
)
);

// Crée un objet à partir des données de configuration


$config = new Zend_Config($configArray);

// Affiche une donnée de configuration en particulier


// (résultat : 'www.example.com')
echo $config->webhost;

// Utilise les données de configuration pour se connecter


// à une base de données
$db = Zend_Db::factory($config->database->adapter,
$config->database->params->toArray());

// Autre possibilité : fournir simplement l'objet Zend_Config.


// Zend_Db factory sait comment l'interpréter.
$db = Zend_Db::factory($config->database);

Comme illustré dans l'exemple ci-dessus, Zend_Config fournit une syntaxe de propriétés
d'objets imbriquées pour accéder aux données de configuration passées à son constructeur.

Avec l'accès de type orienté-objet aux données, Zend_Config a aussi la méthode get() qui
retournera la valeur par défaut si l'élément n'existe pas. Par exemple :

262
Zend_Config

$host = $config->database->get('host', 'localhost');

Exemple 70. Utilisez Zend_Config avec un fichier de configuration en PHP

Il est souvent souhaitable d'utiliser une fichier de configuration en pur PHP. Le code suivant
illustre comment ceci peut être facilement réalisé :

// config.php
return array(
'webhost' => 'www.example.com',
'database' => array(
'adapter' => 'pdo_mysql',
'params' => array(
'host' => 'db.example.com',
'username' => 'dbuser',
'password' => 'secret',
'dbname' => 'mydatabase'
)
)
);

// Lecture de la configuration
$config = new Zend_Config(require 'config.php');

// Affiche une donnée de configuration ('www.example.com')


echo $config->webhost;

2. Aspect théorique
Les données de configuration sont transmis au constructeur de Zend_Config sous la forme
d'un tableau associatif, qui peut être multidimensionnel, afin de supporter une organisation
des données du général vers le spécifique. Les classes d'adaptateur concrètes permettent de
construire le tableau associatif pour le constructeur de Zend_Config à partir du système de
stockage des données de configuration. Dans certaines utilisations spécifiques, les scripts de
l'utilisateur peuvent fournir de tels tableaux directement au constructeur de Zend_Config, sans
employer une classe d'adaptateur.

Chaque valeur du tableau de données de configuration devient une propriété de l'objet


Zend_Config. La clé est utilisée comme nom de propriété. Si une valeur est un tableau, alors
la propriété d'objet résultante est créée comme un nouveau objet Zend_Config, chargé avec
les données du tableau. Cela se déroule récursivement, tel qu'une hiérarchie de données de
configuration peut être créée avec n'importe quel nombre de niveaux.

Zend_Config implémente les interfaces Countable et Iterator afin de faciliter l'accès simple aux
données de configuration. Ainsi, on peut employer la fonction count() et des constructions de
PHP telles que foreach sur des objets Zend_Config.

Par défaut, les données de configuration fournies par Zend_Config ne sont pas modifiables
(lecture seule), et une affectation (par exemple, $config->database->host = 'example.com';)
lèvera une exception. Ce comportement par défaut peut cependant être surchargé par le
constructeur pour permettre la modification des valeurs de données. De plus, quand les
modifications sont autorisées, Zend_Config supporte l'effacement de valeurs (c'est-à-dire
unset($config->database->host)). La méthode readOnly() peut être utilisée pour
déterminer si les modifications sont autorisés pour un objet Zend_Config donné et la méthode
setReadOnly() peut être utilisée pour empêcher toute nouvelle modification d'un objet
Zend_Config qui aurait été créé en autorisant le modifications.

263
Zend_Config

Il est important de ne pas confondre des modifications en cours de script avec


l'enregistrement des données de configuration dans le support de stockage
spécifique. Les outils pour créer et modifier des données de configuration pour
différents supports de stockage ne concernent pas Zend_Config. Des solutions
tiers open-source sont facilement disponibles afin de créer et / ou de modifier les
données de configuration pour différents supports de stockage.

Les classes d'adaptateur héritent de la classe de Zend_Config ce qui permet d'utiliser ses
fonctionnalités.

La famille des classes Zend_Config permet d'organiser les données de configuration en


sections. Les classes d'adaptateur Zend_Config peuvent être chargées en spécifiant une
section unique, des sections multiples, ou toutes les sections (si aucune n'est indiquée).

Les classes d'adaptateurs Zend_Config supporte un modèle d'héritage simple qui permet à
des données de configuration d'être héritées d'une section de données de configuration dans
d'autres. Ceci afin de réduire ou d'éliminer le besoin de reproduire des données de configuration
pour différents cas. Une section héritante peut également surchargée les valeurs dont elle hérite
de sa section parente. Comme l'héritage des classes PHP, une section peut hériter d'une section
parent, qui peut hériter d'une section grand-parent, et ainsi de suite, mais l'héritage multiple (c.-
à-d., la section C héritant directement des sections parents A et B) n'est pas supporté.

Si vous avez deux objets Zend_Config, vous pouvez les fusionner en un objet unique en
utilisant la fonction merge(). Par exemple, prenons $config et $localConfig, vous pouvez
fusionner $localConfig dans $config en utilisant $config->merge($localConfig);. Les
éléments de $localConfig surchargeront les éléments nommés de la même manière dans
$config.

L'objet Zend_Config qui réalise la fusion doit avoir été construit en autorisant
les modifications, en fournissant TRUE en tant que second paramètre du
constructeur. La méthode setReadOnly() peut être utilisée pour empêcher
toute nouvelle modification après la fin de la fusion.

3. Zend_Config_Ini
Zend_Config_Ini permet aux développeurs de stocker des données de configuration dans
le format familier d'un fichier INI et de les lire dans l'application en employant une syntaxe
de propriétés d'objet imbriquées. Le format INI est spécialisé pour fournir à la fois la capacité
d'avoir une hiérarchie des données de configuration et permettre l'héritage entre les sections de
données de configuration. La hiérarchie des données de configuration est supportée grâce au
fractionnement des clés à l'aide de points (.). Une section peut être étendue ou héritée d'une
autre section en suivant le nom de section avec le caractère de deux points (:) et le nom de la
section de laquelle des données doivent être héritées.

Analyse d'un fichier INI

Zend_Config_Ini utilise la fonction parse_ini_file() de PHP.


Veuillez prendre connaissance de la documentation pour appréhender ses
comportements spécifiques, qui se propagent à Zend_Config_Ini, tel que
la façon dont les valeurs spéciales : TRUE, FALSE, "yes", "no" et NULL sont
manipulées.

264
Zend_Config

Séparateur de clé
Par défaut, le séparateur de clé est le caractère point (.), cependant cela peut
être changé en changeant la clé nestSeparator de $options en construisant
l'objet Zend_Config_Ini. Par exemple :

$options['nestSeparator'] = ':';
$options = new Zend_Config_Ini('/chemin/vers/config.ini',
'test',
$options);

Exemple 71. Utiliser Zend_Config_Ini

Cet exemple illustre une utilisation de base de Zend_Config_Ini pour le chargement des
données de configuration à partir d'un fichier INI. Dans cet exemple il y a des données
de configuration pour un environnement de production et pour un environnement de test.
Puisque les données de configuration de l'environnement de test sont très semblables à
celles de la production, la section de test hérite de la section de production. Dans ce cas,
la décision est arbitraire et pourrait avoir été écrite réciproquement, avec la section de
production héritant de la section de test, bien que ceci ne doit pas être le cas pour des
situations plus complexes. Supposons, que les données suivantes de configuration sont
contenues dans /chemin/vers/config.ini :

; Données de configuration du site de production


[production]
webhost = www.example.com
database.adapter = pdo_mysql
database.params.host = db.example.com
database.params.username = dbuser
database.params.password = secret
database.params.dbname = dbname

; Données de configuration du site de test héritant du site


; de production et surchargeant les clés nécessaires
[test : production]
database.params.host = dev.example.com
database.params.username = devuser
database.params.password = devsecret

Ensuite, supposons que le développeur ait besoin des données de configuration de test
issues du fichier INI. Il est facile de charger ces données en indiquant le fichier INI et la
section de test :

$config = new Zend_Config_Ini('/chemin/vers/config.ini', 'test');

echo $config->database->params->host; // affiche "dev.example.com"


echo $config->database->params->dbname; // affiche "dbname"

Tableau 29. Paramètres du constructeur de Zend_Config_Ini


Paramètres Notes
$filename Le fichier INI à charger.
$section La [section] dans le fichier ini qui
doit être chargé. L'affectation de NULL

265
Zend_Config

Paramètres Notes
à ce paramètre chargera toutes les
sections. Alternativement, un tableau
de noms de section peut être fourni
pour charger des sections multiples.
$options (par défault FALSE) Tableau d'options. Les clés suivantes
sont supportées :

• allowModifications : Mettre à TRUE


pour permettre la modification
en mémoire des données de
configuration chargées. Par défaut à
FALSE.

• nestSeparator : Caractère à utiliser


en tant que séparateur d'imbrication.
Par défaut ".".

4. Zend_Config_Xml
Zend_Config_Xml permet aux développeurs de stocker des données de configuration dans
un format simple XML et de les lire grâce à une syntaxe de propriétés d'objets imbriquées. Le
nom de l'élément racine du fichier XML n'a pas d'importance et peut être nommé arbitrairement.
Le premier niveau des éléments XML correspond aux sections des données de configuration.
Le format XML supporte l'organisation hiérarchique par l'emboîtement des éléments XML à
l'intérieur des éléments de niveau section. Le contenu d'un élément XML de niveau le plus bas
correspond aux données de configuration. L'héritage des sections est supportée par un attribut
spécial de XML nommé extends, et la valeur de cet attribut correspond à la section de laquelle
des données doivent être héritées.

Type retourné

Les données de configuration lues grâce à Zend_Config_Xml sont toujours


des chaînes de caractères. La conversion des données à partir des chaînes
de caractères vers d'autres types de données est laissée aux développeurs en
fonction de leurs besoins.

266
Zend_Config

Exemple 72. Utiliser Zend_Config_Xml

Cet exemple illustre une utilisation de base de Zend_Config_Xml pour le chargement des
données de configuration à partir d'un fichier XML. Dans cet exemple il y a des données
de configuration pour un environnement de production et pour un environnement de test.
Puisque les données de configuration de l'environnement de test sont très semblables à
celles de la production, la section de test hérite de la section de production. Dans ce cas,
la décision est arbitraire et pourrait avoir été écrite réciproquement, avec la section de
production héritant de la section de test, bien que ceci ne doit pas être le cas pour des
situations plus complexes. Supposons, que les données suivantes de configuration sont
contenues dans /chemin/vers/config.xml :

<?xml version="1.0"?>
<configdata>
<production>
<webhost>www.example.com</webhost>
<database>
<adapter>pdo_mysql</adapter>
<params>
<host>db.example.com</host>
<username>dbuser</username>
<password>secret</password>
<dbname>dbname</dbname>
</params>
</database>
</production>
<test extends="production">
<database>
<params>
<host>dev.example.com</host>
<username>devuser</username>
<password>devsecret</password>
</params>
</database>
</test>
</configdata>

Ensuite, supposons que le développeur a besoin des données de configuration de test


issues du fichier XML. Il est facile de charger ces données en indiquant le fichier XML et
la section de test :

$config = new Zend_Config_Xml('/chemin/vers/config.xml', 'test');

echo $config->database->params->host; // affiche "dev.example.com"


echo $config->database->params->dbname; // affiche "dbname"

267
Zend_Config

Exemple 73. Utilisation des attributs de balise avec Zend_Config_Xml

Zend_Config_Xml supporte aussi 2 autres manières de définir des noeuds dans la


configuration. Celles-ci utilisent les attributs de balises. Puisque les attributs extends et value
sont des mots réservés (ce dernier par la seconde manière d'utiliser les attributs), ils ne
doivent pas être utilisés. La première manière d'utiliser les attributs est de les ajouter au
noeud parent, ils seront ainsi interprétés en tant qu'enfant de ce noeud :

<?xml version="1.0"?>
<configdata>
<production webhost="www.example.com">
<database adapter="pdo_mysql">
<params host="db.example.com"
username="dbuser"
password="secret"
dbname="dbname"/>
</database>
</production>
<staging extends="production">
<database>
<params host="dev.example.com"
username="devuser"
password="devsecret"/>
</database>
</staging>
</configdata>

La seconde manière ne permet pas vraiment de raccourcir la configuration, mais la rend


plus facile à maintenir puisque vous n'avez pas à écrire les noms de balises deux fois. Vous
créez simplement une balise vide ayant sa valeur dans value :

<?xml version="1.0"?>
<configdata>
<production>
<webhost>www.example.com</webhost>
<database>
<adapter value="pdo_mysql"/>
<params>
<host value="db.example.com"/>
<username value="dbuser"/>
<password value="secret"/>
<dbname value="dbname"/>
</params>
</database>
</production>
<staging extends="production">
<database>
<params>
<host value="dev.example.com"/>
<username value="devuser"/>
<password value="devsecret"/>
</params>
</database>
</staging>
</configdata>

268
Zend_Config

Chaînes de caractères XML

Zend_Config_Xml est capable de charger une chaîne de caractères XML


directement, par exemple si elle est issue d'une base de données. La chaîne est
fournie en tant que premier paramètre du constructeur et doit commencer par
les caractères '<?xml' :

$string = <<<EOT
<?xml version="1.0"?>
<config>
<production>
<db>
<adapter value="pdo_mysql"/>
<params>
<host value="db.example.com"/>
</params>
</db>
</production>
<staging extends="production">
<db>
<params>
<host value="dev.example.com"/>
</params>
</db>
</staging>
</config>
EOT;

$config = new Zend_Config_Xml($string, 'staging');

Espace de noms XML de Zend_Config

Zend_Config possède son propre espace de noms XML, qui ajoute des
fonctionnalités additionnelles lors du processus d'analyse. Pour tirer avantage
de celui-ci, vous devez définir l'espace de noms avec l'URI http://
framework.zend.com/xml/zesnd-config-xml/1.0/ dans votre noeud
racine de configuration.

Avec l'espace de noms activé, vous pouvez maintenant utiliser les constantes
PHP à l'intérieur de vos fichiers de configuration. De plus l'attribut extends a été
déplacé dans ce nouvel espace de noms et déprécié de l'espace de noms NULL.
Il en sera complétement effacé dans Zend Framework 2.0.

$string = <<<EOT
<?xml version="1.0"?>
<config xmlns:zf="http://framework.zend.com/xml/zend-config-xml/1.0/">
<production>
<includePath>
<zf:const zf:name="APPLICATION_PATH"/>/library</includePath>
<db>
<adapter value="pdo_mysql"/>
<params>
<host value="db.example.com"/>
</params>
</db>
</production>

269
Zend_Config

<staging zf:extends="production">
<db>
<params>
<host value="dev.example.com"/>
</params>
</db>
</staging>
</config>
EOT;

define('APPLICATION_PATH', dirname(__FILE__));
$config = new Zend_Config_Xml($string, 'staging');

echo $config->includePath; // Affiche "/var/www/something/library"

270
Zend_Config_Writer
1. Zend_Config_Writer
Zend_Config_Writer vous donne la possibilité d'écrire des fichiers de configuration à partir
d'objets Zend_Config. Il fonctionne avec des adaptateurs détachés du système et est donc
très simple à utiliser. Par défaut Zend_Config_Writer embarque trois adaptateurs, qui
fonctionnent tous sur la base de fichiers. Vous instanciez un rédacteur ("writer") avec des
options spécifiques, qui peuvent être filename et config. Ensuite vous pouvez appeler la
méthode write() du rédacteur et le fichier de configuration est créé. Vous pouvez aussi fournir
$filename et $config directement à la méthode write(). Actuellement les rédacteurs
suivants sont embarqués avec Zend_Config_Writer :

• Zend_Config_Writer_Array

• Zend_Config_Writer_Ini

• Zend_Config_Writer_Xml

Le rédacteur INI possède deux modes de rendu en fonction des sections. Par défaut la
configuration de premier niveau est toujours écrite dans des noms de section. En appelant
$writer->setRenderWithoutSections();, toutes les options sont écrites dans l'espace de noms
global du fichier INI et aucune section n'est appliquée.

De plus, Zend_Config_Writer_Ini a un paramètre optionnel additionnel nestSeparator,


définissant le caractère séparant les profondeurs d'imbrication. Par défaut il s'agit du point,
comme Zend_Config_Ini l'accepte par défaut.

Lors de la modification ou la création d'objet Zend_Config, il y a quelques informations à


garder en mémoire. Pour créer ou modifier une valeur, vous appelez simplement le réglage
d'un paramètre d'un objet Zend_Config grâce à l'accesseur de paramètre ("->"). Pour créer
une section à la racine ou pour créer une branche, vous avez juste à créer un nouveau tableau
($config->branch = array();). Pour définir quelle section en étend une autre, vous devez appeler
la méthode setExtend() sur l'objet Zend_Config racine.

271
Zend_Config_Writer

Exemple 74. Utilisation de Zend_Config_Writer

Cet exemple illustre une utilisation basique Zend_Config_Writer_Xml pour créer un


nouveau fichier de configuration :

// Créer l'objet de configuration


$config = new Zend_Config(array(), true);
$config->production = array();
$config->staging = array();

$config->setExtend('staging', 'production');

$config->production->db = array();
$config->production->db->hostname = 'localhost';
$config->production->db->username = 'production';

$config->staging->db = array();
$config->staging->db->username = 'staging';

// Ecrire le fichier de l'une des manières suivantes :


// a)
$writer = new Zend_Config_Writer_Xml(array('config' => $config,
'filename' => 'config.xml'));
$writer->write();

// b)
$writer = new Zend_Config_Writer_Xml();
$writer->setConfig($config)
->setFilename('config.xml')
->write();

// c)
$writer = new Zend_Config_Writer_Xml();
$writer->write('config.xml', $config);

Ceci créera un fichier de configuration XML avec les sections "production" et "staging", où
"staging" étend "production".

Exemple 75. Modifier une configuration existante

Cet exemple montre comment modifier un fichier de configuration existant :

// Charger toutes les sections d'un fichier de configuration existant,


// tout en évitant les sections étendues.
$config = new Zend_Config_Ini('config.ini',
null,
array('skipExtends' => true,
'allowModifications' => true));

// Modifier une valeur


$config->production->hostname = 'foobar';

// Ecrire le fichier
$writer = new Zend_Config_Writer_Ini(array('config' => $config,
'filename' => 'config.ini'));
$writer->write();

272
Zend_Config_Writer

Chargement d'un fichier de configuration


Lors du chargement d'un fichier de configuration existant afin de le modifier, il est
très important de charger toutes les sections et d'éviter les sections étendues,
évitant ainsi toute fusion de valeurs. Ceci est réalisé en fournissant l'option
skipExtends au constructeur.

Pour tous les rédacteurs à base de fichiers (INI, XML et tableau PHP), en interne la méthode
render() est utilisée pour construire la chaîne de configuration. Cette méthode peut être
utilisée en dehors de la classe si vous souhaitez accéder à une représentation textuelle de vos
données de configuration.

273
Zend_Console_Getopt
1. Introduction
La classe Zend_Console_Getopt aide les applications lancées en ligne de commande à
analyser les options et arguments.

Les utilisateurs peuvent spécifier des arguments en ligne de commande quand ils exécutent votre
application. Ces arguments ont du sens dans l'application : changer son comportement, choisir
des ressources, ou spécifier des paramètres. Beaucoup d'options ont une signification usuelle,
par exemple "--verbose" permet la production d'informations supplémentaires dans beaucoup
d'applications. D'autres options peuvent avoir un sens qui est différent pour chaque application.
Par exemple, "-c" prend des sens différents lorsqu'il est utilisé dans grep, ls, et tar.

Nous avons ci-dessous quelques définitions de termes. L'usage commun des termes varie, mais
cette documentation utilisera les définitions ci-dessous.

• "argument" : une chaîne de caractères qui apparaît dans la ligne de commande après le nom
de la commande. Les arguments peuvent être des options ou bien peut apparaître sans option,
appeler des ressources sur lesquelles la commande agit.

• "option" : un argument qui signifie que la commande va changer son comportement par défaut
d'une manière quelconque.

• "flag" (drapeau) : la première partie d'une option, identifie le but de l'option. Un drapeau est
précédé conventionnellement par un ou deux tirets ("-" or "--"). Un drapeau court comporte
un caractère unique. Un drapeau long est une chaîne de plusieurs caractères. Un tiret simple
précède un drapeau court ou un groupe de drapeaux courts. Un tiret double précède un
drapeau long. Les drapeaux longs ne peuvent pas être groupés.

• "parameter" (paramètre) : la seconde partie d'une option ; une donnée qui peut accompagner
un drapeau, si c'est applicable à l'option donnée. Par exemple, beaucoup de commandes
acceptent "--verbose", mais typiquement cette option n'a aucun paramètre. Cependant, une
option comme "--user a presque toujours besoin d'un paramètre à sa suite.

Un paramètre peut être donné comme un argument séparé après un argument de drapeau,
ou comme faisant partie de la même chaîne de caractères, séparé du drapeau par le
symbole égal ("="). La dernière forme est autorisée seulement avec des drapeaux longs. Par
exemple, -u username, --user username, et --user=username sont des formats supportés
par Zend_Console_Getopt.

• "cluster" (groupe) : les drapeaux courts peuvent être combinés dans une chaîne de caractère
unique précédée par un tiret simple. Par exemple, " ls -1str" emploie un groupe de quatre
drapeaux courts. Cette commande est équivalente à " ls -1 -s -t -r". Seuls les drapeaux courts
peuvent être groupés. Vous ne pouvez pas faire un groupe de drapeaux longs.

Par exemple, dans "mysql --user=root mabase", "mysql" est la commande, "--user=root" est
une option, "--user" est un drapeau, "root" est un paramètre de l'option, et "mabase" est un
argument mais pas une option dans notre définition.

Zend_Console_Getopt fournit une interface pour déclarer quels drapeaux sont valides pour
votre application, produit une erreur et un message s'ils emploient un drapeau invalide, et
transmet à votre application les drapeaux spécifiés par l'utilisateur.

274
Zend_Console_Getopt

Getopt n'est pas une application framework

Zend_Console_Getopt n'interprète pas le sens des drapeaux ou des


paramètres, cette classe n'exécute pas non plus de processus d'application
ou n'invoque pas le code d'application. Vous devez implémenter ces
actions dans votre propre code d'application. Vous pouvez utiliser la classe
Zend_Console_Getopt pour analyser la ligne d'instruction et fournir des
méthodes orientées objet pour savoir quelles options ont été données par un
utilisateur, mais le code pour utiliser ces données pour appeler les parties de
votre application devra être dans une autre classe PHP.

Les sections suivantes décrivent l'utilisation de Zend_Console_Getopt.

2. Déclarer les règles Getopt


Le constructeur de la classe Zend_Console_Getopt prend un à trois arguments. Le premier
argument déclare quelles options sont supportées par votre application. Cette classe supporte
des formes de syntaxe alternatives pour déclarer les options. Voir les sections ci-dessous pour
le format et l'utilisation de ces formes de syntaxe.

Le constructeur prend deux arguments supplémentaires, qui sont facultatifs. Le deuxième


argument peut contenir les arguments de la ligne de commande. La valeur par défaut est
$_SERVER['argv'].

Le troisième argument du constructeur peut contenir des options de configuration pour adapter
le comportement de Zend_Console_Getopt. Voir la section Ajouter une configuration pour la
référence des options disponibles.

2.1. Déclarer des options avec la syntaxe courte


Zend_Console_Getopt supporte une syntaxe compacte semblable à cela employée par GNU
Getopt (voir http://www.gnu.org/software/libc/manual/html_node/Getopt.html). Cette syntaxe
supporte seulement des drapeaux courts (1 seul caractère). Dans une chaîne de caractère
unique, vous entrez chacune des lettres qui correspondent aux drapeaux supportés par votre
application. Une lettre suivie d'un caractère deux points (":") indique un drapeau qui exige un
paramètre.

Exemple 76. Utiliser la syntaxe courte

$opts = new Zend_Console_Getopt('abp:');

L'exemple ci-dessus montre l'utilisation de Zend_Console_Getopt pour déclarer que des


options peuvent être données en tant que "-a", "-b" ou "-p". Le dernier drapeau exige un
paramètre.

La syntaxe courte est limitée aux drapeaux courts (1 seul caractère). Les alias, les types des
paramètres, et les messages d'aide ne sont pas supportés dans la syntaxe courte.

2.2. Déclarer des options avec la syntaxe longue


Une syntaxe différente avec plus de possibilités est également disponible. Cette syntaxe permet
d'indiquer des alias pour les drapeaux, les types de paramètres d'option, et aussi des messages
d'aide pour décrire l'utilisation à l'utilisateur. Au lieu d'utiliser une chaîne de caractère unique

275
Zend_Console_Getopt

comme pour la syntaxe courte, la syntaxe longue emploie un tableau associatif comme premier
argument du constructeur pour déclarer les options.

La clé de chaque élément du tableau associatif est une chaîne avec un format qui nomme le
drapeau, avec tous ses alias, séparés par le symbole "|". Après la série des alias, si l'option exige
un paramètre, il y a un symbole égal ("=") avec une lettre qui représente le type du paramètre :

• "=s" pour un paramètre de type chaîne de caractère.

• "=w" pour un paramètre de type mot (une chaîne de caractère qui ne contient pas d'espace).

• "=i" pour un paramètre de type entier (integer).

Si le paramètre est optionnel, on utilise le tiret ("-") au lieu du symbole égal.

La valeur de chaque élément dans le tableau associatif est un message d'aide pour décrire à
l'utilisateur comment employer votre programme.

Exemple 77. Utiliser la syntaxe longue

$opts = new Zend_Console_Getopt(


array(
'abricot|a' => 'option abricot, sans parametres',
'banane|b=i' => 'option banane, avec un parametre entier obligatoire',
'pear|p-s' => 'option pear, avec un parametre chaîne optionel'
)
);

Dans l'exemple ci-dessus, il y a trois options. "--abricot" et "-a" sont des alias l'un pour l'autre et
l'option ne prend pas de paramètres. "--banane" et "-b" sont des alias l'un pour l'autre et l'option
prend un paramètre obligatoire de type entier. Enfin, "--pear" et "-p" sont des alias l'un pour
l'autre et l'option prend un paramètre optionnel de type chaîne de caractère.

3. Extraire les options et les arguments


Après avoir déclaré les options que l'objet Zend_Console_Getopt doit identifier, et fourni les
arguments de la ligne de commande ou un tableau, vous pouvez interroger l'objet pour connaître
les options indiquées par un utilisateur lors d'un appel à votre programme en ligne de commande.
La classe implémente les méthodes magiques ainsi vous pouvez interroger directement par les
noms d'options.

L'analyse des données est reportée jusqu'à ce que vous invoquiez pour la première fois l'objet
Zend_Console_Getopt pour découvrir si une option était renseignée, l'objet exécute alors
son analyse. Ceci permet plusieurs appels de méthode pour configurer les options, arguments,
messages d'aide, et les options de configuration, avant que l'analyse ne soit lancée.

3.1. Manipuler les exceptions Getopt


Si l'utilisateur a donné des options invalides sur la ligne de commande, la fonction d'analyse
syntaxique lève une Zend_Console_Getopt_Exception. Vous devrez récupérer cette
exception dans votre code d'application. Vous pouvez utiliser la méthode parse() pour forcer
l'objet à analyser les arguments. C'est utile parce que vous pouvez invoquer parse() dans un
bloc try. S'il passe, vous pouvez être sûrs que l'analyse syntaxique ne lèvera pas d'exception
de nouveau. L'exception est lancée via une méthode personnalisée getUsageMessage(), qui
retourne comme une chaîne de caractère l'ensemble formaté des messages d'utilisation pour
toutes les options déclarées.

276
Zend_Console_Getopt

Exemple 78. Récupérer une exception Getopt

try {
$opts = new Zend_Console_Getopt('abp:');
$opts->parse();
} catch (Zend_Console_Getopt_Exception $e) {
echo $e->getUsageMessage();
exit;
}

Les cas, où l'analyse syntaxique lève une exception, incluent :

• L'option passée n'est pas reconnue.

• L'option nécessite un paramètre mais aucun n'est fourni.

• Le paramètre d'option n'a pas le bon type. Par exemple, une chaîne de caractères non-
numérique quand un nombre entier a été exigé.

3.2. Extraire les options par nom


Vous pouvez employer la méthode getOption() pour connaître la valeur d'une option. Si
l'option avait un paramètre, cette méthode retourne la valeur du paramètre. Si l'option n'avait
aucun paramètre mais que l'utilisateur en indiquait sur dans la ligne de commande, la méthode
retournerait TRUE. Sinon la méthode retournerait NULL.

Exemple 79. Utiliser getOption()

$opts = new Zend_Console_Getopt('abp:');


$b = $opts->getOption('b');
$p_parameter = $opts->getOption('p');

De manière alternative, vous pouvez employer la fonction magique __get() pour rechercher
la valeur d'une option comme si c'était une variable de membre de classe. La méthode magique
__isset() est également implémentée.

Exemple 80. Utiliser les méthodes magiques __get() et __isset()

$opts = new Zend_Console_Getopt('abp:');


if (isset($opts->b)) {
echo "J'ai recu l'option b.\n";
}
$p_parameter = $opts->p; // null si non fourni

Si vos options sont déclarées avec des alias, vous pouvez employer n'importe quel alias de
l'option dans les méthodes ci-dessus.

3.3. Extraire les options


Il y a plusieurs méthodes pour extraire l'ensemble complet des options fournies par l'utilisateur
dans la ligne de commande courante.

• Comme pour une chaîne de caractères : employez la méthode toString(). Les options
sont retournées sous la forme d'une chaîne de caractère où les paires drapeau=valeur sont
séparées par des espaces. La valeur d'une option qui n'a pas de paramètre est la chaîne
"TRUE".

277
Zend_Console_Getopt

• Comme un tableau : employez la méthode toArray(). Les options sont retournées dans
un tableau de chaînes de caractères indexé par des nombres, les chaînes de drapeau sont
suivies par les chaînes de paramètres éventuels.

• Comme une chaîne au format JSON : employez la méthode toJson().

• Comme une chaîne au format XML : employez la méthode toXml().

Dans toutes les méthodes de déchargement ci-dessus, la chaîne du drapeau est la première
chaîne dans la liste des alias correspondants. Par exemple, si les noms d'alias d'option étaient
déclarés comme "verbose|v", alors la première chaîne, "verbose", est employé comme nom de
l'option. Le nom du drapeau d'option n'inclut pas le tiret précédent.

3.4. Extraction des arguments sans option


Après que les arguments d'option et ainsi que les paramètres de la ligne de commande ont
été analysés, il peut exister des arguments additionnels restants. Vous pouvez interroger ces
arguments en utilisant la méthode getRemainingArgs(). Cette méthode renvoie un tableau
de chaîne qui ne fait partie d'aucune option.

Exemple 81. Utiliser getRemainingArgs()

$opts = new Zend_Console_Getopt('abp:');


$opts->setArguments(array('-p', 'p_parameter', 'nomdefichier'));
$args = $opts->getRemainingArgs(); // retourne array('nomdefichier')

Zend_Console_Getopt supporte la convention GNU selon laquelle un argument se


composant d'un double-tiret signifie la fin des options. Tous les arguments suivant celui-ci doivent
être traités en tant qu'arguments sans options. C'est utile si vous avez un argument sans options
qui commence par un tiret. Par exemple : "rm -- -nomdefichier-avec-tiret".

4. Configurer Zend_Console_Getopt
4.1. Ajouter des règles d'options
Vous pouvez ajouter de nouvelles règles d'option en complément de celles indiquées dans le
constructeur de Zend_Console_Getopt, en utilisant la méthode addRules(). L'argument
d'addRules() est identique au premier argument du constructeur de classe. C'est soit une
chaîne dans le format d'options de syntaxe courte, soit un tableau associatif dans le format
d'options de syntaxe longue. Voir "Déclarer les règles Getopt" pour les détails sur la syntaxe de
déclaration des options.

Exemple 82. Utilisation d'addRules()

$opts = new Zend_Console_Getopt('abp:');


$opts->addRules(
array(
'verbose|v' => 'Print verbose output'
)
);

L'exemple au-dessus montre comment ajouter l'option "--verbose" avec l'alias "-v" à
un ensemble d'options définies dans l'appel au constructeur. Notez que vous pouvez
mélanger des options de syntaxe courte et de syntaxe longue dans la même instance de
Zend_Console_Getopt.

278
Zend_Console_Getopt

4.2. Ajouter des messages d'aide


En plus d'indiquer les messages d'aide en déclarant les règles d'option dans le long format, vous
pouvez associer des messages d'aide aux règles d'option en utilisant la méthode setHelp().
L'argument de la méthode setHelp() est un tableau associatif, dans laquelle la clé est un
drapeau, et la valeur est le message d'aide correspondant.

Exemple 83. Utiliser setHelp()

$opts = new Zend_Console_Getopt('abp:');


$opts->setHelp(
array(
'a' => 'option abricot, sans paramètres',
'b' => 'option banane, avec un paramètre entier obligatoire',
'p' => 'option pear, avec un paramètre chaîne de caractères optionel'
)
);

Si vous déclarez des options avec des alias, vous pouvez employer n'importe quel alias comme
clé du tableau associatif.

La méthode setHelp() est la seule manière de définir des messages d'aide si vous déclarez
les options en utilisant la syntaxe courte.

4.3. Ajouter des alias aux options


Vous pouvez déclarer des alias pour des options en utilisant la méthode setAliases().
L'argument est un tableau associatif, dont la clé est une chaîne de drapeau déclaré auparavant,
et dont la valeur est un nouvel alias pour ce drapeau. Ces alias sont fusionnés avec tous les
alias existants. En d'autres termes, les alias que vous avez déclarés plus tôt sont toujours actifs.

Un alias ne peut être déclaré qu'une seule fois. Si vous essayez de redéfinir un alias, une
Zend_Console_Getopt_Exception est levée.

Exemple 84. Utiliser setAliases()

$opts = new Zend_Console_Getopt('abp:');


$opts->setAliases(
array(
'a' => 'apple',
'a' => 'apfel',
'p' => 'pear'
)
);

Dans l'exemple ci-dessus, après leurs déclarations, "-a", "--apple" et "--apfel" sont des alias les
un pour les autres. En outre "-p" et "--pear" sont des alias l'un pour l'autre.

La méthode setAliases() est la seule manière de définir des alias si vous déclarez les options
en utilisant la syntaxe courte.

4.4. Ajouter des listes d'arguments


Par défaut, Zend_Console_Getopt utilise $_SERVER['argv'] comme tableau des
arguments de ligne de commande à analyser. De manière alternative, vous pouvez indiquer
le tableau d'arguments comme deuxième argument de constructeur. En conclusion, vous

279
Zend_Console_Getopt

pouvez ajouter de nouveaux d'arguments à ceux déjà utilisés en utilisant la méthode


addArguments(), ou vous pouvez remplacer le choix courant d'arguments en utilisant la
méthode setArguments(). Dans les deux cas, le paramètre de ces méthodes est un simple
tableau de chaîne. L'ancienne méthode ajoutait le tableau aux arguments courants, et la nouvelle
méthode substitue le tableau aux arguments courants.

Exemple 85. Utilisation de addArguments() et setArguments()

// Par défaut, le constructeur utilise $_SERVER['argv']


$opts = new Zend_Console_Getopt('abp:');

// Ajoute un tableau aux arguments existants


$opts->addArguments(array('-a', '-p', 'p_parameter', 'non_option_arg'));

// Remplace les arguments existants par un nouveau tableau


$opts->setArguments(array('-a', '-p', 'p_parameter', 'non_option_arg'));

4.5. Ajouter une configuration


Le troisième paramètre du constructeur de Zend_Console_Getopt est un tableau d'options
de configuration qui affectent le comportement de l'instance d'objet retournée. Vous pouvez
également indiquer des options de configuration en utilisant la méthode setOptions(), ou
vous pouvez placer une option individuelle en utilisant la méthode setOption().

Clarifier le terme "option"


Le terme "option" est employé pour la configuration de la classe
Zend_Console_Getopt afin de correspondre à la terminologie utilisée dans le
reste de Zend Framework. Ce n'est pas la même chose que les options de la
ligne de commande qui sont analysées par la classe Zend_Console_Getopt.

Les options actuellement supportées ont des définitions de constantes dans la classe. Les
options, leurs constantes (avec des valeurs littérales entre parenthèses) sont énumérées ci-
dessous :

• Zend_Console_Getopt::CONFIG_DASHDASH ("dashDash"), si TRUE, utilise le drapeau


spécial "--" pour signifier la fin des drapeaux. Les arguments de la ligne de commande suivant
le double-tiret ne sont pas interprétées comme options, même si les arguments commencent
par un tiret. Cette option de configuration vaut TRUE par défaut.

• Zend_Console_Getopt::CONFIG_IGNORECASE ("ignoreCase"), si TRUE, fait


correspondre des alias même s'ils différent en terme de casse. C'est-à-dire, "-a" et "-A" seront
considérés comme des synonymes. Cette option de configuration vaut FALSE par défaut.

• Zend_Console_Getopt::CONFIG_RULEMODE ("ruleMode") peut avoir les valeurs


Zend_Console_Getopt::MODE_ZEND ("zend") ou Zend_Console_Getopt::MODE_GNU
("gnu"). Il ne devrait pas être nécessaire d'employer cette option à moins que vous n'étendiez
la classe avec les formes additionnelles de syntaxe. Les deux modes supportés dans la classe
Zend_Console_Getopt de base sont sans équivoque. Si le spécificateur est une chaîne
de caractère, la classe passe en MODE_GNU, autrement elle est en MODE_ZEND. Mais si vous
étendez la classe et ajoutez de nouvelles formes de syntaxe, vous pouvez avoir à indiquer le
mode en utilisant cette option.

Plus d'options de configuration pourront être ajoutées en tant que futurs perfectionnements de
cette classe.

280
Zend_Console_Getopt

Les deux arguments de la méthode setOption() sont un nom d'option de configuration et une
valeur d'option.

Exemple 86. Utilisation de setOption()

$opts = new Zend_Console_Getopt('abp:');


$opts->setOption('ignoreCase', true);

L'argument de la méthode setOptions() est un tableau associatif. Les clés de ce tableau


sont les noms d'option de configuration, et les valeurs sont des valeurs de configuration. C'est
également le format de tableau utilisé par le constructeur de classe. Les valeurs de configuration
que vous indiquez sont fusionnées avec la configuration courante ; vous n'avez pas à énumérer
toutes les options.

Exemple 87. Utilisation de setOptions()

$opts = new Zend_Console_Getopt('abp:');


$opts->setOptions(
array(
'ignoreCase' => true,
'dashDash' => false
)
);

281
Zend_Controller
1. Zend_Controller - Démarrage rapide
1.1. Introduction
Zend_Controller est le coeur du système MVC de Zend Framework. MVC équivaut à
Modèle-Vue-Contrôleuret est un motif de conception ("design pattern") visant à séparer la
logique d'application de la logique d'affichage. Zend_Controller_Front implémente un
modèle de contrôleur frontal ("Front Controller"), dans lequel toutes les demandes sont arrêtées
par le contrôleur frontal et distribuées vers différents contrôleurs d'action ("Action Controller")
basés sur l'URL demandé.

Le système Zend_Controller a été construit dans un souci d'extensibilité, soit par sous-
classement des classes existantes, en écrivant les nouvelles classes qui implémentent les
diverses interfaces et les classes abstraites qui forment la base de la famille de contrôleur
des classes, soit par écriture de plugins ou d'aides d'action afin d'utiliser ou d'augmenter les
fonctionnalités du système.

1.2. Démarrage rapide


Si vous avez besoin d'informations plus détaillées, lisez les sections suivantes. Si vous voulez
juste démarrer rapidement, lisez ce qui suit.

1.2.1. Créer votre disposition de système de fichiers

La première étape est de créer votre disposition de système de fichiers. La disposition typique
est la suivante :

application/
controllers/
IndexController.php
models/
views/
scripts/
index/
index.phtml
helpers/
filters/
html/
.htaccess
index.php

1.2.2. Régler votre document root

Dans votre serveur Web, faîtes pointer votre "document root" vers le dossier html du système
de fichiers ci-dessus.

1.2.3. Créer vos règles de réécriture

Éditez le fichier html/.htaccess afin de lire ceci :

282
Zend_Controller

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

Connaître mod_rewrite

Les règles de réécriture ci-dessus autorisent l'accès à tous fichiers sous la racine
de votre hôte virtuel. Si vous avez des fichiers que vous ne souhaitez pas
exposer, vous pouvez souhaiter restreindre ces règles. Allez sur le site d'Apache
pour en apprendre davantage concernant mod_rewrite.

Si vous avez IIS 7.0, utilisez ceci pour votre configuration de réécriture :

<?xml version="1.0" encoding="UTF-8"?>


<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Imported Rule 1" stopProcessing="true">
<match url="^.*$" />
<conditions logicalGrouping="MatchAny">
<add input="{REQUEST_FILENAME}"
matchType="IsFile" pattern=""
ignoreCase="false" />
<add input="{REQUEST_FILENAME}"
matchType="IsDirectory"
pattern="" ignoreCase="false" />
</conditions>
<action type="None" />
</rule>
<rule name="Imported Rule 2" stopProcessing="true">
<match url="^.*$" />
<action type="Rewrite" url="index.php" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

Les règles ci-dessus vont redirigées toute requête vers des ressources existantes (liens
symboliques, fichiers non vides, ou répertoires non-vides), tout autre requête sera renvoyée vers
le contrôleur frontal.

Les règles de réécriture ci-dessus sont pour Apache ; pour des exemples
de règles de réécriture pour d'autres serveurs Web, reportez-vous à la
documentation du routeur.

1.2.4. Créer votre fichier d'amorçage (bootstrap)


Le fichier d'amorçage est la page vers laquelle toutes les demandes sont dirigées -- html/
index.php dans ce cas-ci. Ouvrez html/index.php dans l'éditeur de votre choix et ajouter
ce qui suit :

283
Zend_Controller

Zend_Controller_Front::run('/chemin/vers/application/controllers');

Ceci va instancier et distribuer le contrôleur frontal, qui conduira les demandes vers les
contrôleurs d'action.

1.2.5. Créer votre contrôleur d'action par défaut


Avant de discuter des contrôleurs d'action, vous devez d'abord comprendre comment les
requêtes sont dirigées dans Zend Framework. Par défaut, le premier segment d'un chemin
d'URL correspond à un contrôleur, et le second à une action. Par exemple, l'URL est http://
framework.zend.com/roadmap/components, le chemin est /roadmap/components, qui
correspondra au contrôleur roadmap et à l'action components. Si aucune action n'est fournie,
l'action index est présumé, et si aucun contrôleur n'est fourni, le contrôleur index est présumé
(suivant la convention Apache qui fait correspondre un DirectoryIndex automatiquement).

Le distributeur du Zend_Controller prend alors la valeur du contrôleur et le fait correspondre


à une classe. Par défaut, il s'agit du nom du contrôleur suivi du mot Controller. Ainsi, dans
notre exemple ci-dessus, le contrôleur roadmap correspond à la classe RoadmapController.

De la même manière, la valeur de l'action correspond à une méthode de la classe contrôleur. Par
défaut, la valeur est écrit en minuscule, et le mot Action est ajouté. Ainsi, dans notre exemple
ci-dessus, l'action components devient componentsAction, et la méthode finale appelée est
RoadmapController::componentsAction().

Créons maintenant un contrôleur d'action par défaut et une méthode d'action. Comme noté
auparavant, le contrôleur et l'action par défaut sont tous les deux nommées index. Ouvrez le
fichier application/controllers/IndexController.php, et entrez ce qui suit :

/** Zend_Controller_Action */

class IndexController extends Zend_Controller_Action


{
public function indexAction()
{
$this->render();
}
}

Par défaut, l'aide d'action ViewRendererest activé. Ceci signifie qu'en définissant simplement
une méthode d'action et un script de vue correspondant, vous obtiendrez automatiquement le
rendu du contenu. Par défaut, Zend_View est utilisé en tant que couche Vue dans le MVC. Le
ViewRenderer utilise le nom du contrôleur (par exemple, index) et le nom de l'action courante
(par exemple, index) pour déterminer le modèle à afficher. Par défaut, le fichier modèle se
termine par l'extension .phtml, cela signifie que dans l'exemple ci-dessus, le modèle index/
index.phtml sera rendu. De plus, le ViewRenderer suppose automatiquement que le dossier
views situé au même niveau que le dossier des contrôleurs est le dossier de base des vues,
et que les scripts de vues sont dans le sous-dossier views/scripts/. Ainsi le modèle rendu
sera trouvé dans application/views/scripts/index/index.phtml.

1.2.6. Créer votre script de vue


Comme mentionné dans la section précédente, les scripts de vue sont dans application/
views/scripts/ ; le script de vue pour le contrôleur et l'action par défaut est donc
application/views/scripts/index/index.phtml. Créer ce fichier, et saisissez ce
HTML :

284
Zend_Controller

<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>My first Zend Framework App</title>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>

1.2.7. Créer votre contrôleur d'erreur


Par défaut, le plugin de gestion des erreursest enregistré. Ce plugin nécessite qu'un contrôleur
existe pour gérer les erreurs. Par défaut, il s'agit d'un ErrorController dans le module par
défaut avec une méthode errorAction :

/** Zend_Controller_Action */

class ErrorController extends Zend_Controller_Action


{
public function errorAction()
{
}
}

En considérant l'architecture des dossiers vu ci-dessus, le fichier sera dans application/


controllers/ErrorController.php. Vous devez aussi créer une script de vue dans
application/views/scripts/error/error.phtml ; exemple de contenu possible :

<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Erreur</title>
</head>
<body>
<h1>Erreur apparue</h1>
<p>Une erreur est apparue ; veuillez rééssayer plus tard.</p>
</body>
</html>

1.2.8. Voir le site !


Avec votre premier contrôleur et votre première vue, vous pouvez maintenant démarrer votre
navigateur et aller sur votre site. En supposant que exemple.fr est votre domaine, chacun des
URLs suivants vous dirigera vers la page que nous avons tout juste créée :

• http://exemple.fr/

• http://exemple.fr/index

• http://exemple.fr/index/index

285
Zend_Controller

Vous êtes maintenant prêt à créer de nouveaux contrôleurs et de nouvelles méthodes d'action.
Félicitations !

2. Fondations de Zend_Controller
Le système Zend_Controller est conçu pour être léger, modulaire, et extensible. Il est de
conception minimaliste pour permettre la flexibilité et la liberté aux utilisateurs tout en fournissant
assez de structure de sorte que les systèmes établis autour de Zend_Controller partagent
certaines conventions communes et dispositions semblables de code.

Le diagramme suivant décrit le déroulement des opérations, et ce qui suit décrit en détail les
interactions :

286
Zend_Controller

Le déroulement des opérations de Zend_Controller est implémenté par plusieurs


composants. Même s'il n'est pas nécessaire de comprendre complètement les détails de tous
ces composants pour employer le système, avoir une bonne connaissance du fonctionnement
du processus est utile.

287
Zend_Controller

• Zend_Controller_Front orchestre le déroulement entier des opérations du système


Zend_Controller. C'est une interprétation du modèle contrôleur frontal ("FrontController").
Zend_Controller_Front traite toutes les demandes reçues par le serveur et
est finalement responsable de déléguer les demandes aux contrôleurs d'action
("ActionControllers" [Zend_Controller_Action]).

• Zend_Controller_Request_Abstract (souvent référencé comme Request Object)


représente l'environnement de la requête et fournit les méthodes pour régler et rechercher le
contrôleur, l'action et les paramètres fournis. De plus il contient l'information si l'action qu'elle
contient a été distribuée ou non par Zend_Controller_Dispatcher. Des extensions de
l'objet abstrait de requête peuvent être employées pour encapsuler l'environnement entier de
requête, permettant à des routeurs de récupérer les informations issues de l'environnement
de requête afin de régler les noms de contrôleur et d'action.

Par défaut, Zend_Controller_Request_Http est employé, ce qui permet d'accéder à


l'environnement complet de requête HTTP.

• Zend_Controller_Router_Interface est employé pour définir les routeurs. Le


routage est le processus d'examen de l'environnement de requête pour déterminer quel
contrôleur, et action de ce contrôleur, devraient recevoir la requête. Ces contrôleur,
action, et paramètres facultatifs sont alors placés dans l'objet de requête à traiter par
Zend_Controller_Dispatcher_Standard. Le routage se produit seulement une fois :
quand la demande est initialement reçue et avant que le premier contrôleur ne soit distribué.

Le routeur par défaut, Zend_Controller_Router_Rewrite, récupère un URI comme


indiqué dans Zend_Controller_Request_Http et le décompose en contrôleur, action,
et paramètres basés sur l'information de chemin de l'URL. Par exemple, l'URL http://
localhost/foo/bar/key/value serait décodée pour employer le contrôleur foo, l'action
bar, et pour indiquer un paramètre key avec une valeur value.

Zend_Controller_Router_Rewrite peut également être utilisé pour faire correspondre


des chemins arbitraires ; voir la documentation du routeurpour plus d'information.

• Zend_Controller_Dispatcher_Interface est utilisé pour définir les distributeurs. La


distribution est le processus chargé de récupérer le contrôleur et l'action issus de l'objet
de requête et de les faire correspondre à un fichier/classe de contrôleur et à une méthode
d'action dans la classe du contrôleur. Si le contrôleur ou l'action n'existent pas, il se charge de
déterminer des contrôleurs et des actions par défaut à distribuer.

Le processus de distribution réel se compose de l'instanciation de la classe de contrôleur et


de l'appel de la méthode d'action dans cette classe. A la différence du routage, qui se produit
seulement une fois, la distribution se produit dans une boucle. Si le statut distribué de l'objet
de requête est remis à zéro à un moment quelconque, la boucle sera répétée, en appelant
l'action actuellement placée dans l'objet de requête. La première fois que la boucle se termine
avec une propriété de statut d'objet de requête distribué à vrai (booléen TRUE), le processus
s'arrête.

Le distributeur par défaut est Zend_Controller_Dispatcher_Standard. Il définit les


contrôleurs comme des classes pouvant se nommer avec une série de caractère majuscules
et/ou minuscules et se terminant par le mot Controller, et des méthodes d'action suivant
la notationCamel se terminant avec le mot Action : FooController::barAction(). Dans
ce cas-ci, le contrôleur est désigné comme foo et l'action comme bar.

288
Zend_Controller

Conventions de nommage (casse)

Puisque les humains sont notoirement incompatibles avec le respect des


majuscules et des minuscules quand ils tapent des liens, Zend Framework
normalise les chemins en lettres minuscules. Ceci, naturellement, affectera
votre manière d'appeler vos contrôleurs et actions... ou vous vous référez à
eux dans les liens.

Si vous souhaitez que votre classe ou action de contrôleur ait de multiples


motsEnCassesMélangées ou motsEnNotationCamel, vous devrez séparer ces
mots dans l'URL avec soit un tiret ("-"), soit un point (".") (bien que vous puissiez
configurer le caractère utilisé).

Par exemple, si vous souhaitez l'action


FooBarController::bazBatAction(), vous vous referez à elle avec
l'URL /foo-bar/baz-bat ou /foo.bar/baz.bat.

• Zend_Controller_Action est le composant contrôleur d'action de base. Chaque


contrôleur est une classe simple qui étend la classe de Zend_Controller_Action et devrait
contenir une ou plusieurs méthodes d'action.

• Zend_Controller_Response_Abstract définit une classe de réponse de base employée


pour rassembler et retourner les réponses des contrôleurs d'action. Il rassemble les en-têtes
et le contenu du corps.

La classe de réponse par défaut est Zend_Controller_Response_Http, qui convient pour


l'usage dans un environnement HTTP.

Le déroulement des opérations de Zend_Controller est relativement simple.


Une demande est reçue par Zend_Controller_Front, qui appelle alternativement
Zend_Controller_Router_Rewrite pour déterminer le contrôleur (et l'action dans ce
contrôleur) à distribuer. Zend_Controller_Router_Rewrite décompose l'URI afin de régler
les noms de contrôleur et d'action dans la requête. Zend_Controller_Front entre alors
dans une boucle de distribution. Il appelle Zend_Controller_Dispatcher_Standard,
en lui passant la requête, pour distribuer le contrôleur et l'action indiqués dans la requête
(ou utiliser les valeurs par défaut). Après que le contrôleur ait fini, la commande revient
à Zend_Controller_Front. Si le contrôleur a indiqué qu'un autre contrôleur devait être
distribué en remettant à zéro le statut distribué de la requête, la boucle continue et une autre
distribution est effectuée. Sinon, le processus se termine.

3. Le contrôleur frontal (Front Controller)


3.1. Présentation générale
Zend_Controller_Front implémente un motif de contrôleur frontalutilisé dans les
applications Modèle-Vue-Contrôleur (MVC). Son but est d'initialiser l'environnement de requête,
d'acheminer la requête entrante et de distribuer ensuite n'importe quelles actions découvertes ;
il agrège n'importe quelles réponses et les retourne quand le processus est complet.

Zend_Controller_Front implémente aussi le motif Singleton, signifiant que seule une


instance du contrôleur frontal peut être disponible à n'importe quel moment. Cela lui permet
aussi d'agir comme un enregistrement dans lequel les autres objets du processus de distribution
peuvent écrire.

289
Zend_Controller

Zend_Controller_Front enregistre un plugin brokeravec lui, permettant à des événements


divers qu'il déclenche d'être observés par plugins. Dans la plupart des cas, cela donne au
développeur l'occasion de construire le processus de distribution du site sans avoir besoin
d'étendre le contrôleur frontal pour ajouter une fonctionnalité.

Le contrôleur frontal a besoin au minimum d'un ou plusieurs répertoires contenants les


contrôleurs d'actionpour faire son travail. Une variété de méthodes peut aussi être invoquée pour
plus tard construire l'environnement de contrôleur frontal et celui de ses classes d'aide.

Comportement par défaut


Par défaut, le contrôleur frontal charge le plugin ErrorHandler, ainsi que le plugin
d'aide d'action ViewRenderer. Ceci est fait respectivement pour simplifier la
gestion d'erreur et le rendu des vues dans vos contrôleurs.

Pour désactiver ErrorHandler, exécutez l'action suivante à n'importe quel


point précédant l'appel à dispatch() :

// Désactivez le plugin ErrorHandler :


$front->setParam('noErrorHandler', true);

Pour désactiver ViewRenderer, exécutez l'action suivante à n'importe quel


point précédant l'appel à dispatch() :

// Désactivez l'aide ViewRenderer :


$front->setParam('noViewRenderer', true);

3.2. Méthodes principales


Le contrôleur frontal a plusieurs accesseurs pour construire son environnement. Cependant, il y
a trois méthodes principales clés dans la fonctionnalité de contrôleur frontal :

3.2.1. getInstance()
getInstance() est utilisé pour récupérer une instance du contrôleur frontal. Comme le
contrôleur frontal implémente un motif de Singleton, c'est aussi le seul moyen possible pour
instancier un objet unique de contrôleur frontal.

$front = Zend_Controller_Front::getInstance();

3.2.2. setControllerDirectory() et addControllerDirectory


setControllerDirectory() est utilisé pour informer le distributeuroù chercher les fichiers
de classes de contrôleurs d'action. Ces méthodes acceptent un chemin unique ou un tableau
associatif de paires modules/chemins.

Quelques exemples :

// Régler le dossier des contrôleurs par défaut :


$front->setControllerDirectory('../application/controllers');

// Régler plusieurs répertoires de modules d'un seul coup :


$front->setControllerDirectory(array(
'default' => '../application/controllers',
'blog' => '../modules/blog/controllers',

290
Zend_Controller

'news' => '../modules/news/controllers',


));

// Ajouter le répertoire de module 'foo' :


$front->addControllerDirectory('../modules/foo/controllers', 'foo');

Si vous utilisez addControllerDirectory() sans nom de module, cela


réglera le répertoire pour le module default - en surchargeant une valeur déjà
existante.

Vous pouvez récupérer les réglages courants des répertoires du contrôleur en utilisant
getControllerDirectory() ; ceci retournera un tableau des paires modules/chemins.

3.2.3. addModuleDirectory() et getModuleDirectory()


Un des aspects du contrôleur frontal est que vous puissiez définir une structure de dossiers
modulairepour créer des composants autonomes ; ceux-ci sont nommés "modules".

Chaque module doit être dans son propre dossier, ce dossier étant un miroir du dossier
du module "default" en terme de structure - c'est-à-dire, qu'il doit contenir un sous-dossier
"controllers" au minimum, et typiquement un sous-dossier "views" puis d'autres sous-dossiers.

addModuleDirectory() vous permet de fournir le nom du dossier contenant un ou plusieurs


dossier de modules. Il scanne alors le dossier et les ajoute au contrôleur frontal.

Ensuite, si vous souhaitez déterminer le chemin vers un module en particulier ou vers le module
courant, vous pouvez appeler getModuleDirectory(), en fournissant optionnellement le
nom du module spécifique que vous recherchez.

3.2.4. dispatch()
dispatch(Zend_Controller_Request_Abstract $request = null,
Zend_Controller_Response_Abstract $response = null) fait le gros travail du
contrôleur frontal. Il peut facultativement prendre un objet de requêteet/ou un objet de réponse,
permettant ainsi au développeur de fournir des objets personnalisés.

Si aucun objet de requête ou de réponse ne lui sont fournis, dispatch() vérifiera s'il existe des
objets précédemment enregistrés et utilisera ceux-là ou des objets par défaut pour les utiliser
dans son processus (dans les deux cas, le mode HTTP sera utilisé par défaut).

De la même manière, dispatch() vérifie s'il existe des objets routeuret distributeurinscrits, et
instancie des versions par défaut si aucun n'est trouvé.

Le processus de distribution possède trois évènements

• le routage

• la distribution

• la réponse

Le routage a lieu exactement une fois, utilisant les valeurs de l'objet de requête quand
dispatch() est appelé. La distribution a lieu dans une boucle ; une demande peut soit indiquer
des actions multiples à distribuer, soit le contrôleur ou un plugin peuvent remettre à zéro l'objet
de requête et ainsi forcer la distribution d'actions supplémentaires. Quand tout est réalisé, le
contrôleur frontal retourne la réponse.

291
Zend_Controller

3.2.5. run()
Zend_Controller_Front::run($path) est une méthode "raccourci", statique, prenant
simplement un chemin vers un répertoire contenant des contrôleurs. Elle récupère l'instance
de contrôleur frontal (via getInstance()), enregistre le chemin fourni par l'intermédiaire de
setControllerDirectory(), et finalement réalise la distribution.

Fondamentalement, run() est une méthode de convenance qui peut être employée pour les
installations de sites qui n'exigent pas la personnalisation de l'environnement du contrôleur
frontal.

// Instancie le contrôleur frontal, règle les dossiers de contrôleurs,


// et distribue en une seule étape :
Zend_Controller_Front::run('../application/controllers');

3.3. Méthodes d'accès à l'environnement


En plus des méthodes énumérées ci-dessus, il y a un certain nombre de méthodes d'accès
qui peuvent être employées pour affecter l'environnement de contrôleur frontal - et ainsi
l'environnement des classes auxquelles le contrôleur frontal délégue.

• resetInstance() peut être utilisé pour effacer tous les réglages courants. Son but principal
est pour les tests, mais elle peut également être employée pour des instances où vous
souhaitez enchaîner ensemble les contrôleurs frontaux multiples.

• (set|get)DefaultControllerName() vous permet d'indiquer un nom différent pour


l'utilisation du contrôleur par défaut ("index" est employé sinon) et de rechercher la valeur
courante. Ils mandatent le distributeur.

• (set|get)DefaultAction() vous permet d'indiquer un nom différent pour l'utilisation


de l'action par défaut ("index" est employé sinon) et de rechercher la valeur courante. Ils
mandatent le distributeur.

• (set|get)Request() vous permet d'indiquer la classe ou l'objet de requête à utiliser durant


le processus de distribution et de rechercher la valeur courante. En réglant l'objet de requête,
vous pouvez fournir le nom d'une classe de requête, dans ce cas la méthode chargera le
fichier de classe et l'instanciera.

• (set|get)Router() vous permet d'indiquer la classe ou l'objet de routage à utiliser durant


le processus de distribution et de rechercher la valeur courante. En réglant l'objet de routage,
vous pouvez fournir le nom d'une classe de routage, dans ce cas la méthode chargera le
fichier de classe et l'instanciera.

Lors de la recherche d'un objet routeur, cela vérifie d'abord si un objet est présent, et sinon,
instancie le routeur par défaut ("rewrite router").

• (set|get)BaseUrl() vous permet d'indiquer l'URL de base à écarter lors du routage des
requêtes et de rechercher la valeur courante. La valeur est fournie à l'objet de requête juste
avant le routage.

• (set|get)Dispatcher() vous permet d'indiquer la classe ou l'objet distributeur à utiliser


durant le processus de distribution et de rechercher la valeur courante. En réglant l'objet de
distribution, vous pouvez fournir le nom d'une classe de distribution, dans ce cas la méthode
chargera le fichier de classe et l'instanciera.

Lors de la recherche d'un objet distributeur, cela vérifie d'abord si un objet est présent, et
sinon, instancie le distributeur par défaut.

292
Zend_Controller

• (set|get)Response() vous permet d'indiquer la classe ou l'objet de réponse à utiliser


durant le processus de distribution et de rechercher la valeur courante. En réglant l'objet
de réponse, vous pouvez fournir le nom d'une classe de réponse, dans ce cas la méthode
chargera le fichier de classe et l'instanciera.

• registerPlugin(Zend_Controller_Plugin_Abstract $plugin, $stackIndex =


null) vous permet d'inscrire un objet plugin. En réglant le paramètre facultatif $stackIndex,
vous pouvez contrôler l'ordre dans lequel les plugins seront exécutés.

• unregisterPlugin($plugin) vous permet de désinscrire un objet plugin. $plugin peut


être soit un objet plugin ou une chaîne représentant la classe du plugin à désinscrire.

• throwExceptions($flag) est utilisée pour activer/désactiver la possibilité de lever des


exceptions durant le processus de distribution. Par défaut, les exceptions sont récupérées et
placées dans l'objet réponse ; activer throwExceptions() surchargera ce comportement
et indiquera au contrôleur frontal de ne pas enregistrer le plugin de gestion des erreurs :
ErrorHandler.

Pour plus d'informations, voir Section 12, « Exceptions avec MVC ».

• returnResponse($flag) est utilisée pour informer le contrôleur frontal soit de


récupérer la réponse (TRUE) issue de dispatch(), ou si la réponse peut être
automatiquement émise (FALSE). Par défaut la réponse est automatiquement émise
(en appelant Zend_Controller_Response_Abstract::sendResponse()) ; activer
returnResponse() surchargera ce comportement.

Les raisons de la récupération de la réponse incluent le désir de vérifier l'existence


d'exceptions avant d'émettre la réponse, la nécessité d'enregistrer certains aspects de la
réponse (comme les en-têtes), etc.

3.4. Paramètres du contrôleur frontal


Dans l'introduction, nous avons indiqué que le contrôleur frontal agit également en tant
qu'enregistreur pour les divers composants du contrôleur. Il réalise ceci grâce à une famille
de méthodes "param". Ces méthodes vous permettent d'enregistrer des données arbitraires -
objets et variables - que le contrôleur frontal peut rechercher à tout moment dans la chaîne de
distribution. Ces valeurs sont transmises au routeur, au distributeur, et aux contrôleurs d'action.
Les méthodes incluent :

• setParam($name, $value) vous permet de régler un paramètre unique nommé $name


avec la valeur $value.

• setParams(array $params) vous permet de régler des paramètres multiples en une seule
fois en utilisant un tableau associatif.

• getParam($name) vous permet de récupérer un unique paramètre, en utilisant $name


comme identificateur.

• getParams() vous permet de récupérer la liste entière des paramètres.

• clearParams() vous permet d'effacer un paramètre unique (en fournissant l'identificateur


sous forme de chaîne), des paramètres multiples (en fournissant un tableau d'identificateurs
sous forme de chaîne), ou tous les paramètres (en ne fournissant rien).

Il y a plusieurs paramètres prédéfinis qui peuvent être réglés et qui ont des utilisations spécifiques
dans la chaîne d'expédition :

293
Zend_Controller

• useDefaultControllerAlways() est utilisée pour informer le distributeur d'utiliser le


contrôleur par défaut dans le module par défaut pour toute requête qui ne serait pas
distribuable (par exemple si le module/contrôleur/action n'existe pas). Par défaut, cette
fonctionnalité est désactivée.

Voir Section 12.3, « Différents types d'exceptions que vous pouvez rencontrer » pour plus
d'informations concernant l'utilisation de ce réglage.

• disableOutputBuffering() est utilisée pour informer le distributeur qu'il ne doit pas


utiliser l'"output buffering" pour capturer le rendu généré par les contrôleurs d'action. Par
défaut, le distributeur capture tout rendu et l'ajoute au contenu de l'objet réponse.

• noViewRenderer est utilisée pour désactiver le ViewRenderer. Réglez ce paramètre à TRUE


pour le désactiver.

• noErrorHandler est utilisée pour désactiver le plugin ErrorHandler. Réglez ce paramètre


à TRUE pour le désactiver.

3.5. Étendre le contrôleur frontal


Pour étendre le contrôleur frontal, vous devez au minimum surcharger la méthode
getInstance() :

class Mon_Controleur_Frontal extends Zend_Controller_Front


{
public static function getInstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}

return self::$_instance;
}
}

Surcharger la méthode getInstance() assure que des appels suivants à


Zend_Controller_Front::getInstance() retourneront une instance de votre nouvelle
sous-classe au lieu d'une instance de Zend_Controller_Front - c'est particulièrement utile
pour certains des routeurs alternatifs et certaines aides de vue.

Typiquement, vous n'aurez pas besoin de sous-classer le contrôleur frontal à moins que vous ne
deviez ajouter une nouvelle fonctionnalité (par exemple, un plugin d'autoloader, ou une manière
d'indiquer des chemins d'aide d'action). Quelques exemples où vous pouvez vouloir changer le
comportement peuvent inclure modifier comment des répertoires de contrôleur sont stockés, ou
quel routeur ou distributeur par défaut sont employés.

4. L'objet Requête
4.1. Introduction
L'objet requête est un objet simple de valeur qui est passé entre Zend_Controller_Front
et le routeur, le distributeur, et les classes de contrôleur. Il empaquette les noms du module
demandé, du contrôleur, de l'action, et des paramètres facultatifs, aussi bien que le reste de
l'environnement de requête, que ce soit le HTTP, du CLI, ou de PHP-GTK.

294
Zend_Controller

• Le nom de module est accessible par getModuleName() et setModuleName().

• Le nom de contrôleur est accessible par getControllerName() et


setControllerName().

• Le nom de l'action à appeler dans le contrôleur est accessible par getActionName() et


setActionName().

• Les paramètres accessibles par l'action sont dans un tableau associatif de paires clés
et valeurs qui sont récupérables par getParams() et modifiables par setParams(), ou
individuellement par getParam() et setParam().

En fonction du type de requête, il peut y avoir plus de méthodes disponibles. La requête


par défaut utilisée, Zend_Controller_Request_Http, par exemple, a des méthodes pour
rechercher l'URI de la requête, l'information sur le chemin, les paramètres $_GET et $_POST, etc.

L'objet requête est passé au contrôleur frontal, ou si aucun n'est fourni, il est instancié au début
du processus de distribution, avant que le routage ne se produise. Il est passé à travers chaque
objet dans la chaîne de distribution.

De plus, l'objet requête est particulièrement utile pour les tests. Le développeur peut simuler
l'environnement de requête, y compris le module, le contrôleur, l'action, les paramètres, l'URI,
etc., et passe l'objet requête au contrôleur frontal pour tester une application. Une fois appairés
avec l'objet réponse, les tests unitaires élaboré et précis d'application MVC deviennent possible.

4.2. Les requêtes HTTP


4.2.1. Accéder aux données de la requête
Zend_Controller_Request_Http encapsule l'accès aux valeurs appropriées telles que le
nom de la clé et la valeur pour les variables contrôleur d'action et routeur , et tous les paramètres
additionnels analysés à partir de l'URI. Il permet en plus l'accès aux valeurs contenues dans les
superglobales en tant que membres publics, et contrôle l'URL de base et l'URI courants de la
requête. Des valeurs superglobales ne peuvent pas être placées dans un objet requête, au lieu
de cela utilisez les méthodes setParam() et getParam() pour régler ou pour récupérer des
paramètres d'utilisateur.

Données superglobales
En accédant à des données superglobales par
Zend_Controller_Request_Http en tant que propriétés publiques de
membre, il est nécessaire de maintenir dans l'esprit que le nom de propriété
(clé du tableau des superglobales) est assorti à une superglobale dans un ordre
spécifique de priorité : 1. GET, 2. POST, 3. COOKIE, 4. SERVER, 5. ENV.

Des superglobales spécifiques peuvent être accédées en utilisant une méthode publique comme
alternative. Par exemple, la valeur directe $_POST['user'] peut être accédée en appelant
getPost('user') sur l'objet de requête. Ceci inclue getQuery() pour rechercher des
éléments $$_GET, et getHeader() pour récupérer les en-têtes de la requête.

Données GET et POST


Soyez prudent en accédant à des données de l'objet de requête car il n'est pas
du tout filtré. Le routeur et le distributeur valident et filtrent les données pour leur
usage, mais laissent les données intactes dans l'objet de requête.

295
Zend_Controller

Récupérer les données POST brutes


A partir de la version 1.5.0, vous pouvez aussi les données POST brutes avec
la méthode getRawBody(). La méthode retourne FALSE si aucune donnée n'a
été envoyé, et le corps complet du POST sinon.

Ceci est principalement utile pour accepter le contenu lors du développement


des applications MVC de type REST.

Vous pouvez également placer des paramètres d'utilisateur dans l'objet de requête en utilisant
setParam() et récupérer ces derniers en utilisant plus tard getParam(). Le routeur se sert de
cette fonctionnalité pour faire correspondre des paramètres de l'URI de la requête dans l'objet
requête.

getParam() retrouve plus que les paramètres d'utilisateur


Afin d'effectuer une partie de son travail, getParam() recherche réellement
dans plusieurs sources. Dans l'ordre de priorité, ceux-ci incluent : l'ensemble
de paramètres d'utilisateur réglés par l'intermédiaire de setParam(), les
paramètres GET, et finalement les paramètres POST. Faites attention à ceci
lorsque vous récupérez des données par l'intermédiaire de cette méthode.

Si vous souhaitez rechercher seulement dans les valeurs que vous avez
paramétrées avec setParam(), utilisez getUserParam().

De plus, à partir de la version 1.5.0, vous pouvez verrouiller les sources de


paramètres à utiliser. setParamSources() vous permet de spécifier un tableau
vide ou un tableau contenant une ou plusieurs des valeurs "_GET" ou "_POST"
indiquant quelle source de paramètres est autorisée (par défaut les deux sont
autorisées) ; si vous souhaitez restreindre l'accès seulement à "_GET", spécifiez
setParamSources(array('_GET')).

Caprices d'Apache
Si vous utilisez le gestionnaire 404 d'Apache pour passer les requêtes
entrantes au contrôleur frontal, ou si vous utilisez le drapeau PT avec les
règles de ré-écriture, $_SERVER['REDIRECT_URL'] contient l'URI dont vous
avez besoin, pas $_SERVER['REQUEST_URI']. Si vous employez une telle
installation et obtenez un routage invalide, vous devriez employer la classe
Zend_Controller_Request_Apache404 au lieu de la classe HTTP par
défaut pour votre objet de requête :

$request = new Zend_Controller_Request_Apache404();


$front->setRequest($request);

Cette classe étend la classe Zend_Controller_Request_Http et modifie


simplement la recherche automatique de l'URI de la requête. Elle peut être
employée comme un remplacement "drop-in".

4.2.2. Base de l'URL et sous-dossiers


Zend_Controller_Request_Http permet à Zend_Controller_Router_Rewrite d'être
employé dans des sous-répertoires. Zend_Controller_Request_Http essayera de détecter
automatiquement votre base d'URL et de la régler en conséquence.

296
Zend_Controller

Par exemple, si vous maintenez votre index.php dans un sous-répertoire du serveur Web
appelé /projects/myapp/index.php, la base d'URL (rewrite base) devrait être réglé à /
projects/myapp. Cette chaîne sera alors dépouillée du début du chemin avant de calculer tous
les routes correspondantes. Ceci libère de la nécessité de l'ajouter au début de n'importe laquelle
de vos routes. Une route 'user/:username' correspondra à des URI comme http://
localhost/projects/myapp/user/martel et http://example.com/user/martel.

La détection d'URL est sensible à la casse


La détection automatique d'URL de base est sensible à la casse, ainsi assurez
vous que votre URL correspond à un nom de sous-répertoire dans le système
de fichiers (même sur les machines Windows). S'il n'y en a pas, une exception
sera levée.

Si la base de l'URL est détectée de manière inexacte vous pouvez la surcharger avec
votre propre chemin de base grâce à la méthode setBaseUrl() soit de la classe de
Zend_Controller_Request_Http, soit de la classe de Zend_Controller_Front. La
méthode la plus facile est de la régler dans Zend_Controller_Front, qui le transmets dans
l'objet de requête. Exemple d'utilisation pour régler une base d'URL personnalisée :

/**
* Distribue la requête avec une base d'URL réglé
* avec Zend_Controller_Front.
*/
$router = new Zend_Controller_Router_Rewrite();
$controller = Zend_Controller_Front::getInstance();
$controller->setControllerDirectory('./application/controllers')
->setRouter($router)
->setBaseUrl('/projects/myapp'); // affecte la base d'url
$response = $controller->dispatch();

4.2.3. Déterminer le type de la requête


getMethod() vous permet de déterminer le type de requête HTTP utiliser pour appeler la
ressource courante. De plus, différentes méthodes existent pour récupérer sous la forme de
booléen le type de requête réalisée :

• isGet()

• isPost()

• isPut()

• isDelete()

• isHead()

• isOptions()

La principale utilisation est lors de la création des architectures MVC de type REST.

4.2.4. Détecter les requêtes AJAX


Zend_Controller_Request_Http possède une méthode rudimentaire pour détecter les
requêtes AJAX : isXmlHttpRequest(). Cette méthode parcourt les en-têtes de la requête
HTTP à la recherche de X-Requested-With ayant la valeur "XMLHttpRequest" ; si celui-ci est
trouvé, la méthode retourne TRUE.

297
Zend_Controller

Actuellement, on sait que cet en-tête est fourni par défaut par les bibliothèques JS suivantes :

• Prototype et Scriptaculous (et les librairies dérivées de Prototype)

• Yahoo! UI Library

• jQuery

• MochiKit

La plupart des librairies AJAX vous permettent d'envoyer vos propres en-têtes de requête HTTP ;
si votre librairie n'envoie pas cet en-tête, ajoutez le simplement afin d'être sûr que la méthode
isXmlHttpRequest() fonctionne dans votre cas.

4.3. Sous-classer l'objet Requête


La classe de requête de base utilisée pour tous les objets de requête est la classe abstraite
Zend_Controller_Request_Abstract. Au minimum, elle définit les méthodes suivantes :

abstract class Zend_Controller_Request_Abstract


{
/**
* @return string
*/
public function getControllerName();

/**
* @param string $value
* @return self
*/
public function setControllerName($value);

/**
* @return string
*/
public function getActionName();

/**
* @param string $value
* @return self
*/
public function setActionName($value);

/**
* @return string
*/
public function getControllerKey();

/**
* @param string $key
* @return self
*/
public function setControllerKey($key);

/**
* @return string
*/
public function getActionKey();

298
Zend_Controller

/**
* @param string $key
* @return self
*/
public function setActionKey($key);

/**
* @param string $key
* @return mixed
*/
public function getParam($key);

/**
* @param string $key
* @param mixed $value
* @return self
*/
public function setParam($key, $value);

/**
* @return array
*/
public function getParams();

/**
* @param array $array
* @return self
*/
public function setParams(array $array);

/**
* @param boolean $flag
* @return self
*/
public function setDispatched($flag = true);

/**
* @return boolean
*/
public function isDispatched();
}

L'objet de requête est un conteneur pour l'environnement de la requête. La chaîne de contrôleur


doit seulement savoir régler et récupérer le contrôleur, l'action, les paramètres facultatifs, et le
statut distribué. Par défaut, la demande recherchera ses propres paramètres en utilisant les clés
de contrôleur ou d'action afin de déterminer le contrôleur et l'action.

Étendez cette classe, ou une de ses dérivés, quand vous avez besoin de la classe de requête
pour interagir avec un environnement spécifique afin de récupérer des données pour les utiliser
dans les tâches ci-dessus. Les exemples incluent l'environnement HTTP, un environnement CLI,
ou un environnement PHP-GTK.

5. Routeur Standard
5.1. Introduction
Zend_Controller_Router_Rewrite est le routeur par défaut du framework. Le routage
consiste à analyser l'URI définie (la partie après l'URL de base) et la décomposer en valeurs

299
Zend_Controller

déterminant quels module, contrôleur et action doivent recevoir la requête. Ces valeurs sont
encapsulées dans un objet de requête Zend_Controller_Request_Http qui est alors injecté
dans Zend_Controller_Dispatcher_Standard pour y être traité Le routage n'est effectué
qu'une seule fois par requête : juste avant que le premier contrôleur ne soit traité (distribué)

Zend_Controller_Router_Rewrite intervient pour fournir un environnement de requête


similaire à "mod_rewrite", tout en utilisant uniquement du PHP. Il est désigné sur les principes
de Ruby on Rails et ne requière pas de connaissances particulières en réécriture d'URL. Il est
destiné à fonctionner avec une seule règle de réécriture Apache, dont voici des exemples :

RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css|html)$ index.php

ou (recommandé) :

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

Le routeur de réécriture peut aussi être utilisé avec un serveur Web IIS (versions <= 7.0) si
Isapi_Rewrite a été installée comme une extension Isap avec la règle suivante :

RewriteRule ^[\w/\%]*(?:\.(?!(?:js|ico|gif|jpg|png|css|html)$)[\w\%]*$)? /index.php [I]

IIS Isapi_Rewrite
Lorsque IIS est utilisé, $_SERVER['REQUEST_URI'] n'existera pas ou vaudra
une chaîne vide. Dans ce cas, Zend_Controller_Request_Http essaiera
d'utiliser la valeur de $_SERVER['HTTP_X_REWRITE_URL'], initialisée par
l'extension Isapi_Rewrite.

IIS 7.0 introduit un moodule de réécriture d'URL natif, et il peut être configuré comme ceci :

<?xml version="1.0" encoding="UTF-8"?>


<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Imported Rule 1" stopProcessing="true">
<match url="^.*$" />
<conditions logicalGrouping="MatchAny">
<add input="{REQUEST_FILENAME}"
matchType="IsFile" pattern=""
ignoreCase="false" />
<add input="{REQUEST_FILENAME}"
matchType="IsDirectory"
pattern="" ignoreCase="false" />
</conditions>
<action type="None" />
</rule>
<rule name="Imported Rule 2" stopProcessing="true">
<match url="^.*$" />
<action type="Rewrite" url="index.php" />
</rule>

300
Zend_Controller

</rules>
</rewrite>
</system.webServer>
</configuration>

Si vous utilisez Lighttpd, la règle de réécriture suivante est valide :

url.rewrite-once = (
".*\?(.*)$" => "/index.php?$1",
".*\.(js|ico|gif|jpg|png|css|html)$" => "$0",
"" => "/index.php"
)

5.2. Utilisation d'un routeur


Pour utiliser un routeur et le configurer, vous devez le récupérer et ajouter des routes :

/* Créer un routeur */
$router = $frontctrl->getRouter();
// retourne un routeur de réécriture par défaut
$router->addRoute(
'user',
new Zend_Controller_Router_Route('user/:username',
array('controller' => 'user',
'action' => 'info'))
);

5.3. Utilisation basique du routeur de réécriture


Le coeur de ce routeur repose sur le concept de routes personnalisées. Les routes sont
ajoutées en appelant la méthode addRoute() et en lui passant une instance implémentant
Zend_Controller_Router_Route_Interface. Exemple :

$router->addRoute('user',
new Zend_Controller_Router_Route('user/:username'));

Le routeur de réécriture est fourni avec six types de route, dont une spéciale :

• Zend_Controller_Router_Route

• Zend_Controller_Router_Route_Static

• Zend_Controller_Router_Route_Regex

• Zend_Controller_Router_Route_Hostname

• Zend_Controller_Router_Route_Chain

• Zend_Controller_Router_Rewrite *

Chaque route peut être utilisée plusieurs fois pour créer un chaîne de routes représentant un
schéma de routage personnalisé. La route du module, en revanche, ne devrait être utilisée
qu'une seule fois, elle est en générale la route la plus générique (par défaut). Chaque route sera
définie un peu plus tard.

Le premier paramètre de addRoute est le nom de la route. Il sera utilisé plus tard pour la
sélectionner (par exemple pour générer un URL. Le deuxième paramètre étant l'objet route lui-
même.

301
Zend_Controller

L'utilisation la plus plausible du nom de la route est illustrée dans l'aide vue "url" :

<a href="<?php echo $this->url(array('username' => 'martel'), 'user') ?>">


Martel
</a>

Ce qui donnera un "href" : user/martel.

Le routage consiste simplement à itérer toutes les routes reçues et à les faire correspondre
à l'URI de la requête courante. Dès qu'une correspondance est établie, les variables sont
injectées dans l'objet Zend_Controller_Request utilisé après dans le distributeur et dans les
contrôleurs. Si aucune correspondance n'est trouvée, la route suivante dans la pile est analysée.

Si vous devez déterminer quelle route a été trouvée, vous pouvez utilisez la méthode
getCurrentRouteName(), qui vous retournera l'identifiant utilisé pour enregistrer la route
dans le routeur. Si vous souhaitez récupérer l'objet de la route actuelle, vous pouvez utiliser
getCurrentRoute().

Pile LIFO
Les routes sont analysées dans l'ordre LIFO : dernière fournie, première
analysée. Veillez à définir les routes les génériques en premier donc.

Paramètres de la requête
Les paramètres de la requête proviennent de l'utilisateur,
ou des routes définies. Ils seront plus tard accessibles
via Zend_Controller_Request::getParam() ou la méthode
Zend_Controller_Action::_getParam().

Il y a trois valeurs spéciales qui peuvent être utilisées dans la définition de vos routes : - "module",
"controller" et "action" -. Ces valeurs sont utilisées par Zend_Controller_Dispatcher pour
trouver les contrôleurs et action à distribuer.

Valeurs spéciales
Le nom de ces valeurs peut être changé dans
Zend_Controller_Request_Http avec les méthodes setControllerKey
et setActionKey.

5.4. Routes par défaut


Zend_Controller_Router_Rewrite possède des routes par défaut qui vont correspondre pour
des URI du type controller/action. De plus, un nom de module peut être spécifié comme
premier élément du chemin, autorisant ainsi des URI du type module/controller/action.
Enfin, chaque paramètres de la requête sera trouvé à la fin de la requête, comme controller/
action/var1/value1/var2/value2.

Exemples avec ces routes :

// Considérons :
$ctrl->setControllerDirectory(
array(
'default' => '/path/to/default/controllers',

302
Zend_Controller

'news' => '/path/to/news/controllers',


'blog' => '/path/to/blog/controllers'
)
);

Module seulement:
http://example/news
module == news

Un module invalide dirige vers le contrôleur:


http://example/foo
controller == foo

Module + controller:
http://example/blog/archive
module == blog
controller == archive

Module + controller + action:


http://example/blog/archive/list
module == blog
controller == archive
action == list

Module + controller + action + params:


http://example/blog/archive/list/sort/alpha/date/desc
module == blog
controller == archive
action == list
sort == alpha
date == desc

La route par défaut est simplement un objet Zend_Controller_Router_Route_Module,


stocké sous le nom "default" dans le routeur de réécriture(RewriteRouter). Il est conçu comme
ceci :

$compat = new Zend_Controller_Router_Route_Module(array(),


$dispatcher,
$request);
$this->addRoute('default', $compat);

Si vous ne souhaitez pas cette route par défaut, créez en une et stocker la avec le nom
"default" (écrasement), ou supprimez la route avec removeDefaultRoutes() :

// Supprime les routes par défaut


$router->removeDefaultRoutes();

5.5. Base URL et sous dossiers


Le routeur de réécriture peut être utilisé dans des sous dossiers (comme http://
domain.com/~user/application-root/), dans un tél cas, l'URL de base de
l'application (/~user/application-root) devrait être automatiquement détectée par
Zend_Controller_Request_Http et utilisée ensuite.

Si ça n'était pas le cas, vous pouvez spécifier votre propre base URL dans
Zend_Controller_Request_Http en appelant setBaseUrl() (voyez Base de l'URL et
sous-dossiers) :

303
Zend_Controller

$request->setBaseUrl('/~user/application-root/');

5.6. Paramètres globaux


Vous pouvez régler des paramètres globaux dans un routeur, qui sont automatiquement fournis
à la route lors de son assemblage, grâce à la fonction setGlobalParam(). Si un paramètre
global est réglé mais qu'il est aussi fourni directement à la méthode d'assemblage, le paramètre
utilisateur écrase le paramètre global. Vous pouvez régler un paramètre global de cette manière :

$router->setGlobalParam('lang', 'en');

5.7. Types de route


5.7.1. Zend_Controller_Router_Route
Zend_Controller_Router_Route est la route par défaut intégrée dans le routeur de
réécriture (RewriteRouter). Ce routeur combine les deux avantages que sont la simplicité
d'utilisation et la flexibilité. Chaque route est définie par une correspondance d'URL, statique
ou dynamique, et des valeurs par défaut peuvent être fournies, de même que des valeurs
obligatoires.

Imaginons une application ayant besoin de posséder une page en décrivant l'auteur. Nous
voulons que lorsque le navigateur pointe vers http://domaine.fr/auteur/martel, la
page d'informations en question puisse apparaître, au sujet de "martel". La route pour une telle
URL pourrait être :

$route = new Zend_Controller_Router_Route(


'auteur/:username',
array(
'controller' => 'profile',
'action' => 'userinfo'
)
);

$router->addRoute('user', $route);

Le premier paramètre du constructeur de Zend_Controller_Router_Route est la définition


de la route à analyser avec l'URL. Les définitions des routes sont des parties statiques et
dynamiques, séparées par des slashs ("/"). Les parties statiques sont juste du texte brut : auteur.
Les dynamiques, appelées variables, sont repérées grâce à un caractère deux-points (:) devant
la variable : :username.

Utilisation des caractères


Pour identifier une variable dans un schéma de routage (après le deux-points),
en théorie n'importe quel caractère fait l'affaire (sauf le slash "/"). Cependant il
est conseillé de n'utiliser que des caractères que PHP comprend comme étant
des noms de variables valides. Les implémentations futures de ce comportement
peuvent changer, altérant ainsi votre code.

Cette route exemple devrait être utilisée lorsque le navigateur pointe vers http://
domaine.fr/auteur/martel, et dans un tel cas, tous les paramètres de la requête seront
injectés dans l'objet Zend_Controller_Request et seront accessibles à travers votre
ProfileController. Les variables retournées par cet exemple peuvent être représentées
par le tableau suivant :

304
Zend_Controller

$values = array(
'username' => 'martel',
'controller' => 'profile',
'action' => 'userinfo'
);

Plus tard, Zend_Controller_Dispatcher_Standard va distribuer vers la méthode


userinfoAction() de ProfileController (dans le module par défaut)
selon ces valeurs. A cet endroit, il sera possible d'accéder à toutes les
variables de la requête grâce à Zend_Controller_Action::_getParam() ou
Zend_Controller_Request::getParam() :

public function userinfoAction()


{
$request = $this->getRequest();
$username = $request->getParam('username');

$username = $this->_getParam('username');
}

La définition des routes peut contenir un ou plusieurs caractères spéciaux - des jokers -
représentés par le symbole '*'. Il est utilisé pour collecter des paramètres. L'exemple suivant
représente plus ou moins le comportement par défaut de la route "Module" :

$route = new Zend_Controller_Router_Route(


':module/:controller/:action/*',
array('module' => 'default')
);
$router->addRoute('default', $route);

5.7.1.1. Variables par défaut

Chaque variable dynamique dans la définition des routes peut avoir une valeur par défaut. C'est
à cela que sert le second paramètre du constructeur de Zend_Controller_Router_Route.
Il s'agit d'un tableau avec comme clés les noms des variables, et comme valeurs, leurs valeurs
par défaut :

$route = new Zend_Controller_Router_Route(


'archive/:annee',
array('annee' => 2006)
);
$router->addRoute('archive', $route);

L'exemple ci-dessus établira une correspondance avec les URL comme http://
domaine.fr/archive/2005 et http://exemple.fr/archive. Dans ce dernier cas, la
variable de l'année (annee) aura la valeur 2006.

L'exemple ci-dessus injecte ainsi un paramètre représentant une année (annee). Si aucune
information de contrôleur ou d'actions n'est présente, alors ceux par défaut seront utilisés (ils
sont définis dans Zend_Controller_Dispatcher_Abstract). Pour que l'exemple soit plus
intuitif, spécifions des paires contrôleur et action par défaut dans notre route :

$route = new Zend_Controller_Router_Route(


'archive/:annee',
array(
'annee' => 2006,

305
Zend_Controller

'controller' => 'archive',


'action' => 'show'
)
);
$router->addRoute('archive', $route);

Cette route va alors donner une distribution vers la méthode showAction() de


ArchiveController.

5.7.1.2. Obligations et contraintes des variables

Vous pouvez ajouter un troisième paramètre au constructeur de


Zend_Controller_Router_Route pour spécifier une variable obligatoire. Ceci s'effectue au
moyen d'expressions régulières :

$route = new Zend_Controller_Router_Route(


'archive/:annee',
array(
'annee' => 2006,
'controller' => 'archive',
'action' => 'show'
),
array('year' => '\d+')
);
$router->addRoute('archive', $route);

Avec une telle définition de route, comme ci-dessus, le routeur n'établira une correspondance
que si la variable "annee" contient une donnée numérique : http://domaine.fr/
archive/2345. Une URL comme http://exemple.annee/archive/test ne sera pas
captée (matchée) par cette route, et le contrôle sera passé à la route suivante, etc.

5.7.2. Zend_Controller_Router_Route_Static
Les exemples ci-dessus utilisent des routes dynamiques - routes qui contiennent des motifs pour
chercher des correspondances. Seulement, parfois, une route particulière est marquée en dur,
et mettre en marche le moteur d'expression régulière serait inutile. La réponse à cette situation
est l'utilisation de routes statiques :

$route = new Zend_Controller_Router_Route_Static(


'login',
array('controller' => 'auth', 'action' => 'login')
);
$router->addRoute('login', $route);

La route ci-dessus correspond à l'URL http://domain.com/login, et distribue l'action


AuthController::loginAction().

ATTENTION : Les routes statiques doivent contenir des valeurs


par défaut saines

Puisqu'une route statique ne fournit aucune partie de l'URL à l'objet de requête


en tant que paramètres, vous devez fournir par défaut pour la route tous les
paramètres nécessaires à la distribution de la requête. Oubliez les valeurs par
défaut de "controller" ou "action" entraînera des résultats non attendus, et peut-
être une requête non-distribuable.

306
Zend_Controller

En général, fournissez toujours chacune des valeurs par défaut suivantes :

• controller

• action

• module (si différent de "default")

Optionnellement, vous pouvez activer le paramètre


"useDefaultControllerAlways" du contrôleur frontal lors de l'amorçage :

$front->setParam('useDefaultControllerAlways', true);

Cependant, ceci est considéré comme un contournement ; il vaut toujours mieux


définir explicitement des valeurs par défaut saines.

5.7.3. Zend_Controller_Router_Route_Regex
En plus des routes par défaut, et statique, les routes exprimées par expression régulière sont
acceptées. Ces routes sont plus puissantes que les autres, mais aussi plus complexes à mettre
en oeuvre et un peu plus lentes en matière d'analyse.

Comme les routes standards, cette route doit être initialisée avec une définition et des valeurs
par défaut. Créons par exemple avec une route "archive" en utilisant les routes par expressions
régulières :

$route = new Zend_Controller_Router_Route_Regex(


'archive/(\d+)',
array(
'controller' => 'archive',
'action' => 'show'
)
);
$router->addRoute('archive', $route);

Chaque motif d'expression régulière sera injecté dans l'objet de requête. Avec l'exemple
ci-dessus, en utilisant http://domain.com/archive/2006, la tableau résultat devrait
ressembler à :

$values = array(
1 => '2006',
'controller' => 'archive',
'action' => 'show'
);

Les slashs de début et de fin sont supprimés de l'URL dans le routeur


(avant l'intervention de la route).Ainsi, pour faire correspondre l'URL http://
domain.com/foo/bar/, il faudra une expression du style foo/bar, et non
pas /foo/bar.

Les caractères de spécification de début et fin d'expression sont


automatiquement rajoutés au motif ('^' et '$', respectivement). De ce fait, vous ne
devriez pas les utiliser manuellement.

307
Zend_Controller

Cette classe de route utilise le séparateur # comme délimiteur de motif. Vous


devrez donc échapper ce caractère si vous l'utilisez, et non pas le slash (par
défaut pour un motif d'expression régulière). Le caractère "#" est cependant
rarement utilisé dans une URL.

Vous pouvez retourner le contenu des sous-masques :

public function showAction()


{
$request = $this->getRequest();
$year = $request->getParam(1); // $year = '2006';
}

Attention, la clé est un entier (1), et non une chaîne ('1').

Cette route ne fonctionnera pas encore tout à fait comme la route standard, car la valeur par
défaut pour "year" n'est pas indiquée. Attention par contre, vous risquez d'avoir un problème
avec les slashs finaux même si nous déclarons une valeur par défaut pour "year" et que celui-
ci est facultatif. La solution consiste à traiter ce slash, mais sans le capturer :

$route = new Zend_Controller_Router_Route_Regex(


'archive(?:/(\d+))?',
array(
1 ' => '2006',
'controller' => 'archive',
'action' => 'show'
)
);
$router->addRoute('archive', $route);

Nous voyons apparaître tout de même un problème : gérer des chiffres, comme clés pour les
paramètres n'est pas très intuitif. C'est là qu'entre en jeu le troisième paramètre du constructeur
de Zend_Controller_Router_Route_Regex. Il accepte un tableau faisant correspondre les
numéros des paramètres et leur nom respectif :

$route = new Zend_Controller_Router_Route_Regex(


'archive/(\d+)',
array(
'controller' => 'archive',
'action' => 'show'
),
array(
1 => 'year'
)
);
$router->addRoute('archive', $route);

Les valeurs suivantes seront injectées dans l'objet de requête :

$values = array(
'year' => '2006',
'controller' => 'archive',

308
Zend_Controller

'action' => 'show'


);

Il est aussi possible d'inverser les clé et valeurs du tableau :

$route = new Zend_Controller_Router_Route_Regex(


'archive/(\d+)',
array( ... ),
array(1 => 'year')
);

// OU

$route = new Zend_Controller_Router_Route_Regex(


'archive/(\d+)',
array( ... ),
array('year' => 1)
);

Attention de toujours manipuler des entiers (1 et non "1")

Si vous inversez comme dans le deuxième cas de l'exemple ci-dessus, la clé alors reçue
par l'objet de requête ne représente plus un chiffre, mais le nom du paramètre. Vous pouvez
évidemment mixer les comportements :

$route = new Zend_Controller_Router_Route_Regex(


'archive/(\d+)/page/(\d+)',
array( ... ),
array('year' => 1)
);

Si nous appelons l'URL http://domain.com/archive/2006/page/10 avec la route définie


ci-dessus, les paramètres trouvés seront :

$values = array(
'year' => '2006',
2 => 10,
'controller' => 'archive',
'action' => 'show'
);

Étant donné que les route par expression régulière ne sont pas facilement réversible, vous
devrez préparer le motif vous-même dans le but d'utiliser l'aide de vue "url". Ce chemin inverse
doit être défini comme une chaîne traitable par la fonction sprintf() de PHP, et définie en
quatrième paramètre du constructeur de la route Regex :

$route = new Zend_Controller_Router_Route_Regex(


'archive/(\d+)',
array( ... ),
array('year' => 1),
'archive/%s'
);

Quels sont donc les avantages des routes par expressions régulières (Regex) ? C'est que vous
pouvez décrire n'importe quelle URL avec. Imaginez un blog, vous voulez créer des URLs du

309
Zend_Controller

type http://domain.com/blog/archive/01-Using_the_Regex_Router.html, afin


de décomposer la dernière partie de l'URL en un ID d'article, et un cours texte descriptif
(01-Using_the_Regex_Router.html). Ceci n'est pas possible avec la route standard. En
revanche, avec la route Regex, vous pouvez écrire :

$route = new Zend_Controller_Router_Route_Regex(


'blog/archive/(\d+)-(.+)\.html',
array(
'controller' => 'blog',
'action' => 'view'
),
array(
1 => 'id',
2 => 'description'
),
'blog/archive/%d-%s.html'
);
$router->addRoute('blogArchive', $route);

Comme vous le voyez, ce type de route ajoute une solution flexible concernant la gestion des
URLs et leur routage.

5.7.4. Zend_Controller_Router_Route_Hostname
Zend_Controller_Router_Route_Hostname est la route par nom d'hôte du framework.
Elle fonctionne de la même manière que la route standard, mais elle utilise le nom d'hôte de
l'URL appelé au lieu du chemin.

Utilisons l'exemple d'une route standard et regardons ce que cela donnerais en utilisant le nom
d'hôte. Au lieu d'appeler l'utilisateur par le chemin, nous voulons être capable d'appeler http://
toto.users.example.com pour voir les informations concernant l'utilisateur "toto"

$hostnameRoute = new Zend_Controller_Router_Route_Hostname(


':username.users.example.com',
array(
'controller' => 'profile',
'action' => 'userinfo'
)
);

$plainPathRoute = new Zend_Controller_Router_Route_Static('');

$router->addRoute('user', $hostnameRoute->chain($plainPathRoute);

Le premier paramètre dans le constructeur Zend_Controller_Router_Route_Hostname


est la définition d'une route qui correspondra à un nom d'hôte. Les définitions de route consistent
en des parties statiques et des parties dynamiques séparées par le caractère point ("."). Les
parties dynamiques, appelées variables, sont marquées en précédant le nom de variable par le
caractère deux-points (":") : :username. Les parties statiques sont de simples textes : user.

Les routes par nom d'hôtes peuvent, mais ne devraient pas être utilisées comme ceci.
La raison à cela est que qu'une route par nom d'hôte seule ne correspondra à aucun
chemin. Donc vous devez donc chaîner le chemin d'une route à une route par nom
d'hôte. Ceci est réalisé comme dans l'exemple ci-dessous en appelant $hostnameRoute-
>chain($pathRoute);. En faisant ceci, $hostnameRoute n'est pas modifié, mais une
nouvelle route (Zend_Controller_Router_Route_Chain) est retournée, qui peut ainsi être
fournie au routeur.

310
Zend_Controller

5.7.5. Zend_Controller_Router_Route_Chain
Zend_Controller_Router_Route_Chain est une route permettant le chainage d'autres
routes. Ceci permet de chainer des routes hostnames à des routes de chemin, ou de multiples
routes de chemin entre elles, par exemple. Le chainage se configure via des méthodes ou un
fichier de configuration.

Priorité des paramètres


En chainant des routes entre elles, les paramètres de la route la plus externe
(la plus proche) ont une prioprité supérieure aux paramètres des routes les plus
internes (encapsulées). Définir un contrôleur dans la route externe, puis dans la
route interne, c'est celui de la route externe qui sera sélectionné.

En réalisant le chainage via les méthodes, il existe 2 manières de procéder. La première


est de créer un objet Zend_Controller_Router_Route_Chain puis d'appeler la méthode
chain() plusieurs fois en lui passant les routes à chainer. La deuxième méthode consiste à
créer la première route, par exemple une route hostname, puis d'appeler sa méthode chain()
en passant comme paramètre la route qui devrait être ajoutée. Ceci ne modifiera pas la
route hostname, mais retournera une instance de Zend_Controller_Router_Route_Chain
possédant les 2 routes chainées:

// Créer deux routes


$hostnameRoute = new Zend_Controller_Router_Route_Hostname(...);
$pathRoute = new Zend_Controller_Router_Route(...);

// Première méthode, utiliser l'objet de chainage


$chainedRoute = new Zend_Controller_Router_Route_Chain();
$chainedRoute->chain($hostnameRoute)
->chain($pathRoute);

// Deuxième méthode, chainage direct


$chainedRoute = $hostnameRoute->chain($pathRoute);

Le chainage utilise le slash comme séparateur par défaut entre les routes. Pour utiliser un
séparateur différent, procédez comme suite:

// Créer deux routes


$firstRoute = new Zend_Controller_Router_Route('foo');
$secondRoute = new Zend_Controller_Router_Route('bar');

// Chainer les routes avec un séparateur particulier


$chainedRoute = $firstRoute->chain($secondRoute, '-');

// Assemble la route: "foo-bar"


echo $chainedRoute->assemble();

5.7.5.1. Chainer des routes via Zend_Config

Pour chainer les route grâce à un fichier de configuration, il faut considérer des paramètres
additionnels. L'approche la plus simple consiste à utiliser les paramètres de la section chains.
Il s'agit simplement d'une liste de routes qui seront chainées à la route parente. Ce n'est ni le
parent, ni un des enfants qui sera ajouté au routeur, mais bien le résultat de la chaine générale.
Le nom de cette chaine dans le routeur sera constitué du nom de la route parente séparé du
nom des enfants par un tiret (-) par défaut. Voici un exemple:

<routes>

311
Zend_Controller

<www type="Zend_Controller_Router_Route_Hostname">
<route>www.example.com</route>
<chains>
<language type="Zend_Controller_Router_Route">
<route>:language</route>
<reqs language="[a-z]{2}">
<chains>
<index type="Zend_Controller_Router_Route_Static">
<route></route>
<defaults module="default" controller="index" action="index" />
</index>
<imprint type="Zend_Controller_Router_Route_Static">
<route>imprint</route>
<defaults module="default" controller="index" action="index" />
</imprint>
</chains>
</language>
</chains>
</www>
<users type="Zend_Controller_Router_Route_Hostname">
<route>users.example.com</route>
<chains>
<profile type="Zend_Controller_Router_Route">
<route>:username</route>
<defaults module="users" controller="profile" action="index" />
</profile>
</chains>
</users>
<misc type="Zend_Controller_Router_Route_Static">
<route>misc</route>
</misc>
</routes>

Le résultat sera 3 routes www-language-index, www-language-imprint et users-


language-profile qui seront utilisées en fonction du nom d'hote et de la route misc, qui elle
sera utilisée pour tout nom d'hôte.

Autre manière de faire : utiliser les nom des routes directement. Cela ne peut se faire que pour
le niveau racine:

<routes>
<www type="Zend_Controller_Router_Route_Chain">
<route>www.example.com</route>
</www>
<language type="Zend_Controller_Router_Route">
<route>:language</route>
<reqs language="[a-z]{2}">
</language>
<index type="Zend_Controller_Router_Route_Static">
<route></route>
<defaults module="default" controller="index" action="index" />
</index>
<imprint type="Zend_Controller_Router_Route_Static">
<route>imprint</route>
<defaults module="default" controller="index" action="index" />
</imprint>

<www-index type="Zend_Controller_Router_Route_Chain">
<chain>www, language, index</chain>

312
Zend_Controller

</www-index>
<www-imprint type="Zend_Controller_Router_Route_Chain">
<chain>www, language, imprint</chain>
</www-imprint>
</routes>

On peut aussi passer un tableau à chain plutôt que les noms de route séparés par des virgules:

<routes>
<www-index type="Zend_Controller_Router_Route_Chain">
<chain>www</chain>
<chain>language</chain>
<chain>index</chain>
</www-index>
<www-imprint type="Zend_Controller_Router_Route_Chain">
<chain>www</chain>
<chain>language</chain>
<chain>imprint</chain>
</www-imprint>
</routes>

Pour spécifier le séparateur de routes avec Zend_Config , agissez comme suit:

$config = new Zend_Config(array(


'chainName' => array(
'type' => 'Zend_Controller_Router_Route_Static',
'route' => 'foo',
'chains' => array(
'subRouteName' => array(
'type' => 'Zend_Controller_Router_Route_Static',
'route' => 'bar',
'defaults' => array(
'module' => 'module',
'controller' => 'controller',
'action' => 'action'
)
)
)
)
));

// Affecte un séparateur avant configuration


$router->setChainNameSeparator('_separator_')

// Ajoute la configuration
$router->addConfig($config);

// La nom de notre route est maintenant: chainName_separator_subRouteName


echo $this->_router->assemble(array(), 'chainName_separator_subRouteName');

// La preuve: cela affiche /foo/bar

5.7.6. Zend_Rest_Route
Le composant Zend_Rest contient une route RESTful pour
Zend_Controller_Router_Rewrite. Cette route permet un schéma de routage fonction de
la méthode HTTP et de l'URI afin d'y faire correspondre un module, contrôleur, et action. Le
tableau suivant vous donne un aperçu du schéma de routage en fonction de l'URI.

313
Zend_Controller

Tableau 30. Comportement de Zend_Rest_Route

Méthode URI Module_Controller::action


GET /product/ratings/ Product_RatingsController::indexAct
GET /product/ratings/:id Product_RatingsController::getActio
POST /product/ratings Product_RatingsController::postActi
PUT /product/ratings/:id Product_RatingsController::putActio
DELETE /product/ratings/:id Product_RatingsController::deleteAc
POST /product/ratings/:id? Product_RatingsController::putActio
_method=PUT
POST /product/ratings/:id? Product_RatingsController::deleteAc
_method=DELETE

5.7.6.1. Utilisation de Zend_Rest_Route

Pour activer Zend_Rest_Route pour une application entière, construisez en un objet sans
paramètre spécifique et ajoutez le comme route par défaut dans le contrôleur frontal:

$front = Zend_Controller_Front::getInstance();
$restRoute = new Zend_Rest_Route($front);
$front->getRouter()->addRoute('default', $restRoute);

Si Zend_Rest_Route ne trouve aucun module, contrôleur, action valides, il


retournera FALSE et la route suivante sera alors analysée par le routeur.

Pour activer Zend_Rest_Route pour des modules spécifiques, construisez l'objet avec comme
troisième paramètre, un tableau de noms de modules :

$front = Zend_Controller_Front::getInstance();
$restRoute = new Zend_Rest_Route($front, array(), array('product'));
$front->getRouter()->addRoute('rest', $restRoute);

Pour activer Zend_Rest_Route pour des contrôleurs spécifiques, construisez l'objet avec
comme troisième paramètre, un tableau de noms de contrôleurs en correspondance avec des
noms de modules.

$front = Zend_Controller_Front::getInstance();
$restRoute = new Zend_Rest_Route($front, array(), array(
'product' => array('ratings')
));
$front->getRouter()->addRoute('rest', $restRoute);

5.7.6.2. Zend_Rest_Route avec Zend_Config_Ini

To use Zend_Rest_Route from an INI config file, use a route type parameter and set the config
options:

routes.rest.type = Zend_Rest_Route
routes.rest.defaults.controller = object
routes.rest.mod = project,user

314
Zend_Controller

The 'type' option designates the RESTful routing config type. The 'defaults' option is used to
specify custom default module, controller, and/or actions for the route. All other options in the
config group are treated as RESTful module names, and their values are RESTful controller
names. The example config defines Mod_ProjectController and Mod_UserController as RESTful
controllers.

Then use the addConfig() method of the Rewrite router object:

$config = new Zend_Config_Ini('path/to/routes.ini');


$router = new Zend_Controller_Router_Rewrite();
$router->addConfig($config, 'routes');

5.7.6.3. Zend_Rest_Controller

Pour vous aidez à utiliser des contrôleurs avec Zend_Rest_Route, faites les étendre
Zend_Rest_Controller. Zend_Rest_Controller définit les 5 opérations RESTful les plus
connues sous forme de méthodes abstraites.

• indexAction() - Devrait récupérer un index des ressources et le passer à la vue.

• getAction() - Devrait récupérer des données d'une ressource définie par URI et les passer
à la vue.

• postAction() - Devrait accepter une nouvelle ressource et la faire persister (la


sauvegarder).

• putAction() - Devrait accepter une ressource indentifiée par URI et la faire persister (la
sauvegarder).

• deleteAction() - Devrait supprimer la ressource identifiée par URI.

5.8. Utiliser Zend_Config avec le RewriteRouter


Il arrive qu'il soit plus commode d'éditer un fichier de configuration de routes, plutôt que d'éditer
un code source. Ceci est rendu possible par la méthode addConfig(). Vous créez un objet
compatible Zend_Config et vous le passez à cette méthode.

Par exemple, voyons un fichier INI :

[production]
routes.archive.route = "archive/:year/*"
routes.archive.defaults.controller = archive
routes.archive.defaults.action = show
routes.archive.defaults.year = 2000
routes.archive.reqs.year = "\d+"

routes.news.type = "Zend_Controller_Router_Route_Static"
routes.news.route = "news"
routes.news.defaults.controller = "news"
routes.news.defaults.action = "list"

routes.archive.type = "Zend_Controller_Router_Route_Regex"
routes.archive.route = "archive/(\d+)"
routes.archive.defaults.controller = "archive"
routes.archive.defaults.action = "show"

315
Zend_Controller

routes.archive.map.1 = "year"
; OU: routes.archive.map.year = 1

Ce fichier INI peut être lu dans grâce à un objet Zend_Config comme suit :

$config = new Zend_Config_Ini('/path/to/config.ini', 'production');


$router = new Zend_Controller_Router_Rewrite();
$router->addConfig($config, 'routes');

Nous indiquons au routeur d'utiliser la section "routes" du fichier INI. Chaque clé de
premier niveau représente le nom de la route, ainsi nous avons dans l'exemple ci dessus
"archive" et "news". Chaque route attend alors au moins une entrée "route" avec une
ou plusieurs entrées "defaults" ; optionnellement nous pouvons rajouter des paramètres
obligatoires. Tout ceci correspond aux trois arguments fournis par l'objet implémentant
Zend_Controller_Router_Route_Interface. Une entrée optionnelle "type" peut être
utilisée pour indiquer le type de classe de routage à utiliser, il s'agit par défaut de
Zend_Controller_Router_Route. Dans l'exemple au dessus, la route "news" va utiliser
Zend_Controller_Router_Route_Static.

5.9. Dérivation de l'objet Router


Le routeur par défaut, dit de réécriture, devrait suffire dans la majorité des projets. Tout ce qu'il
peut être nécessaire de faire, est d'ajouter des routes particulières selon vos besoins.

Cependant, si vous voulez utiliser votre propre logique de routage, une interface est disponible.
Zend_Controller_Router_Interface ne définit qu'une seule méthode :

interface Zend_Controller_Router_Interface
{
/**
* @param Zend_Controller_Request_Abstract $request
* @throws Zend_Controller_Router_Exception
* @return Zend_Controller_Request_Abstract
*/
public function route(Zend_Controller_Request_Abstract $request);
}

Le processus de routage n'intervient qu'une fois : lorsque la requête est reçue par le système. Le
routeur doit alors déterminer un contrôleur, une action et de paramètres optionnel et les spécifier
dans un objet de requête, qui est ensuite passé au distributeur. Si il n'est pas possible de router
une requête, alors l'objet de requête devrait être laissé tel-quel.

6. Le distributeur
6.1. Vue d'ensemble
La distribution est le processus de récupération de l'objet requête,
Zend_Controller_Request_Abstract, d'extraction du nom de module, du nom de
contrôleur, du nom d'action, et des paramètres facultatifs qui s'y trouvent, et enfin
d'instanciation du contrôleur et de l'appel d'une action de ce contrôleur. Si le module,
le contrôleur, ou l'action ne sont pas trouvés, il emploiera des valeurs par défaut pour
eux. Zend_Controller_Dispatcher_Standard indique index pour le contrôleur et
l'action par défaut et default pour le module par défaut, mais permet au développeur

316
Zend_Controller

de changer ces valeurs par défaut pour chacun en utilisant les méthodes respectives
setDefaultController(), setDefaultAction(), et setDefaultModule().

Le module "Default"

Quand vous créez des applications modulaires, vous pouvez constater que
vous voulez aussi que votre module par défaut ait son espace de noms
(dans la configuration par défaut, le module "default" n'a pas d'espace
de noms). A partir de la version 1.5.0, vous pouvez spécifier le paramètre
prefixDefaultModule à TRUE soit dans le contrôleur frontal soit dans le
distributeur :

// Dans le contrôleur frontal :


$front->setParam('prefixDefaultModule', true);

// Dans le distributeur :
$dispatcher->setParam('prefixDefaultModule', true);

Ceci vous permet de ré-utiliser un module existant en tant que module par défaut
d'une application.

La distribution se produit dans une boucle dans le contrôleur frontal. Avant que le distribution
ne se produise, le contrôleur frontal détermine la route de la requête pour récupérer les valeurs
spécifiées par l'utilisateur pour le module, le contrôleur , l'action , et les paramètres optionnels.
Il entre alors dans la boucle d'expédition, et distribue la requête.

Au début de chaque itération, il régle un drapeau dans l'objet requête indiquant que l'action a été
distribuée. Si une action ou un plugin pre/postDispatch remet à zéro ce drapeau, la boucle
de distribution continue et tente de distribuer la nouvelle requête. En changeant le contrôleur et/
ou l'action dans la requête et en effaçant le drapeau de distribution, le développeur peut définir
une chaîne de requêtes à réaliser.

La méthode du contrôleur d'action qui contrôle cette distribution est _forward() ; appelez
cette méthode à partir de pre/postDispatch() ou d'une méthode d'action, en fournissant
une action, un contrôleur, un module, et optionnellement des paramètres additionnels que vous
souhaitez passer à la nouvelle action :

public function fooAction()


{
// Transférer la nouvelle action dans le contrôleur
// et le module courant :
$this->_forward('bar', null, null, array('baz' => 'bogus'));
}

public function barAction()


{
// Transférer vers une action dans un autre contrôleur,
// FooController::bazAction(), dans le module courant :
$this->_forward('baz', 'foo', null, array('baz' => 'bogus'));
}

public function bazAction()


{
// Transférer vers une action dans un autre contrôleur
// dans un autre module, Foo_BarController::bazAction():
$this->_forward('baz', 'bar', 'foo', array('baz' => 'bogus'));

317
Zend_Controller

6.2. Sous-classer le distributeur


Zend_Controller_Front appelle en premier le routeur pour déterminer la première action
dans la requête. Il entre ensuite dans la boucle de distribution, qui demande au distributeur de
distribuer l'action.

Le distributeur a besoin de plusieurs données afin de réaliser son travail - il doit connaître le
format des noms d'actions et de contrôleur, où chercher les fichiers de classe des contrôleurs,
savoir si le nom de module fourni est valide, et il a besoin d'une API pour déterminer si une
requête donnée est distribuable suivant les informations disponibles.

Zend_Controller_Dispatcher_Interface définit les méthodes suivantes nécessaires


pour toute implémentation d'un distributeur :

interface Zend_Controller_Dispatcher_Interface
{
/**
* Formate une chaîne en un nom de classe de contrôleur
*
* @param string $unformatted
* @return string
*/
public function formatControllerName($unformatted);

/**
* Formate une chaîne en un nom de méthode d'action
*
* @param string $unformatted
* @return string
*/
public function formatActionName($unformatted);

/**
* Détermine si une requête est distribuable
*
* @param Zend_Controller_Request_Abstract $request
* @return boolean
*/
public function isDispatchable(
Zend_Controller_Request_Abstract $request);

/**
* Règle un paramètre utilisateur
* (via le contrôleur frontal, ou pour un usage local)
*
* @param string $name
* @param mixed $value
* @return Zend_Controller_Dispatcher_Interface
*/
public function setParam($name, $value);

/**
* Règle un tableau de paramètres utilisateur
*
* @param array $params
* @return Zend_Controller_Dispatcher_Interface

318
Zend_Controller

*/
public function setParams(array $params);

/**
* Récupère un paramètre utilisateur unique
*
* @param string $name
* @return mixed
*/
public function getParam($name);

/**
* Récupère tous les paramètres utilisateur
*
* @return array
*/
public function getParams();

/**
* Efface le tableau des paramètres utilisateur,
* ou un paramètre utilisateur unique :
*
* @param null|string|array single key or
* array of keys for params to clear
* @return Zend_Controller_Dispatcher_Interface
*/
public function clearParams($name = null);

/**
* Règle l'objet réponse à utiliser, s'il existe
*
* @param Zend_Controller_Response_Abstract|null $response
* @return void
*/
public function setResponse(
Zend_Controller_Response_Abstract $response = null);

/**
* Récupère l'objet réponse, s'il existe
*
* @return Zend_Controller_Response_Abstract|null
*/
public function getResponse();

/**
* Ajoute un dossier de contrôleur dans le tableau
* des dossiers de contrôleurs
*
* @param string $path
* @param string $args
* @return Zend_Controller_Dispatcher_Interface
*/
public function addControllerDirectory($path, $args = null);

/**
* Règle le(s) dossier(s) où les fichiers de contrôleurs
* sont stockés
*
* @param string|array $dir
* @return Zend_Controller_Dispatcher_Interface

319
Zend_Controller

*/
public function setControllerDirectory($path);

/**
* Retourne le(s) dossier(s) où les fichiers de contrôleurs
* sont stockés
*
* @return array
*/
public function getControllerDirectory();

/**
* Distribue une requête vers un (module/)contrôleur/action.
*
* @param Zend_Controller_Request_Abstract $request
* @param Zend_Controller_Response_Abstract $response
* @return Zend_Controller_Request_Abstract|boolean
*/
public function dispatch(Zend_Controller_Request_Abstract $request,
Zend_Controller_Response_Abstract $response);

/**
* Informe si un module donné est valide
*
* @param string $module
* @return boolean
*/
public function isValidModule($module);

/**
* Retourne le nom du module par défaut
*
* @return string
*/
public function getDefaultModule();

/**
* Retourne le nom du contrôleur par défaut
*
* @return string
*/
public function getDefaultControllerName();

/**
* Retourne le nom de l'action par défaut
*
* @return string
*/
public function getDefaultAction();
}

Cependant, dans la plupart des cas, vous devriez simplement étendre la classe abstraite
Zend_Controller_Dispatcher_Abstract, dans laquelle chacune de ces méthodes a déjà
été définie, ou Zend_Controller_Dispatcher_Standard pour modifier une fonctionnalité
du distributeur standard.

Les raisons possibles au sous-classement du distributeur incluent un désir d'employer une classe
ou un schéma différent de nommage des classes et/ou des méthodes dans vos contrôleurs
d'action, ou un désir d'employer un paradigme de distribution différent tel que la distribution

320
Zend_Controller

de fichiers de classe d'action dans des dossiers de contrôleur (au lieu de la distribution des
méthodes de classes).

7. Contrôleurs d'action
7.1. Introduction
Zend_Controller_Action est une classe abstraite que vous pouvez utiliser avec le
contrôleur frontal quand vous construisez un site Web basé sur le modèle de conception Modèle-
Vues-Contrôleurs (MVC).

Pour utiliser Zend_Controller_Action, vous devez la sous-classer dans vos propres classes
de contrôleurs d'action (ou la sous-classer pour créer votre propre classe de base pour vos
contrôleurs d'action). L'opération la plus basique est de la sous-classer, et de créer vos
méthodes d'action qui correspondent aux différentes actions que vous souhaitez gérer. La
gestion du routage et de la distribution des Zend_Controller va rechercher automatiquement
les méthodes dont le nom termine par 'Action' dans votre classe et les considérer comme des
actions potentiellement valides de votre contrôleur.

Par exemple, considérons une classe définie comme ceci :

class FooController extends Zend_Controller_Action


{
public function barAction()
{
// réalise quelquechose
}

public function bazAction()


{
// réalise quelquechose
}
}

La classe FooController (contrôleur foo) définit deux actions, bar et baz.

Il y a d'autres fonctionnalités qui peuvent être utilisées, comme personnaliser l'initialisation des
actions, gérer les actions par défaut quand aucune action ou une action invalide est fournie,
avoir la possibilité de hook ("détournement") en pre et post-dispatch, et une variété de méthodes
d'aides (helper). Ce chapitre fournit une vue d'ensemble des fonctionnalités du contrôleur
d'action.

Comportement par défaut

Par défaut, le contrôleur frontal active l'aide d'action ViewRenderer. Cette aide
s'occupe de l'injection automatique de l'objet de vue dans vos contrôleurs, ainsi
que du rendu de cette vue. Vous pouvez la désactiver au sein de vos contrôleurs
par l'une ou l'autre des actions suivantes :

class FooController extends Zend_Controller_Action


{
public function init()
{
// Locale à ce seul contrôleur ; affecte toutes les actions,
// si chargée dans l'init :

321
Zend_Controller

$this->_helper->viewRenderer->setNoRender(true);

// Global :
$this->_helper->removeHelper('viewRenderer');

// Global aussi, mais doit être réalisé en conjonction avec


// la version locale pour être propagé dans ce contrôleur:
Zend_Controller_Front::getInstance()->setParam('noViewRenderer',
true);
}
}

Les méthodes initView(), getViewScript(), render(), et


renderScript() sont affectées chacune au ViewRenderer à moins que l'aide
ne soit pas chargée dans le gestionnaire d'aide (helper broker) ou que l'option
noViewRenderer n'ait été réglée.

Vous pouvez simplement désactiver le rendu pour une vue individuelle grâce au
drapeau noRender du ViewRenderer :

class FooController extends Zend_Controller_Action


{
public function barAction()
{
// désactive le rendu automatique pour cette action seulement :
$this->_helper->viewRenderer->setNoRender();
}
}

Les raisons principales de désactiver le ViewRenderer sont l'absence de besoin


d'objets de vues ou si vous n'effectuez pas de rendu via des scripts de vues (par
exemple, quand vous utilisez un contrôleur d'action pour servir des protocoles
de service Web comme SOAP, XML-RPC, ou REST). Dans la plupart des cas, il
n'est pas nécessaire de désactiver globalement le ViewRenderer, seulement de
manière sélective pour des contrôleurs ou actions individuels.

7.2. Initialisation d'objet


Même si vous pouvez toujours surcharger le constructeur du contrôleur d'action, nous ne
vous le recommandons pas. Zend_Controller_Action::__construct() réalise certaines
tâches importantes, comme l'enregistrement des objets de requêtes et de réponses, ainsi que
l'invocation d'arguments personnalisés fourni par le contrôleur frontal. Si vous devez surcharger
le constructeur, n'oubliez pas d'appeler parent::__construct($request, $response,
$invokeArgs).

La manière la plus appropriée de personnaliser l'instanciation est d'utiliser la méthode init(),


qui est appelée en dernière tâche de __construct(). Par exemple, si vous voulez vous
connecter à une base de données à l'instanciation :

class FooController extends Zend_Controller_Action


{
public function init()
{
$this->db = Zend_Db::factory('Pdo_Mysql', array(
'host' => 'myhost',
'username' => 'user',

322
Zend_Controller

'password' => 'XXXXXXX',


'dbname' => 'website'
));
}
}

7.3. Détournement Pre et Post-Dispatch (Hook)


Zend_Controller_Action spécifie deux méthodes qui peuvent être appelées juste avant et
juste après une action, preDispatch() et postDispatch(). Celles-ci peuvent être pratiques
dans plusieurs cas : vérifier l'authentification et les ACL avant d'exécuter une action (en appelant
_forward() dans preDispatch(), l'action sera évitée), par exemple, ou en plaçant du
contenu généré dans une partie du modèle du site (postDispatch()).

Utilisation de init() ou de preDispatch()

Dans la section précédente, nous avons introduit la méthode init(), et dans


celle-ci, la méthode preDispatch(). Quelles sont leurs différences, et quelles
actions vont-elles réaliser chacune ?

La méthode init() a pour but principal d'étendre le constructeur. Typiquement,


votre constructeur devrait simplement paramétrer les états des objets, mais pas
réaliser d'opérations logiques. Ceci peut inclure l'initialisation des ressources
utilisées dans le contrôleur (comme des modèles, des objets de configuration,
etc.), ou assigner des valeurs issues du contrôleur frontal, du fichier d'amorçage,
ou d'un registre.

La méthode preDispatch() peut aussi être utilisée pour paramétrer un objet


ou un environnement (par exemple, une vue, une aide d'action, etc.), mais son
but principal est d'établir des décisions autorisant ou non une action requêtée à
être distribuée. Si elle ne l'est pas, vous pouvez alors utiliser _forward() vers
une autre action, ou lancer une exception.

Note: la méthode _forward() s'exécutera pas correctement si elle est appelée


depuis init(), ce qui est une formalisation des intentions de deux méthodes.

7.4. Accesseurs
Un certain nombre d'objets et de variables sont enregistrés avec l'objet et chacun possède des
méthodes accesseurs.

• Objet Requête : getRequest() peut être utilisé pour récupérer l'objet de requête utilisé pour
appeler l'action.

• Objet Réponse : getResponse() peut être utilisé pour récupérer l'objet de réponse
assemblant la réponse finale. Quelques appels typiques peuvent ressembler à ceci :

$this->getResponse()->setHeader('Content-Type', 'text/xml');
$this->getResponse()->appendBody($content);

• Arguments d'invocation : le contrôleur frontal peut transmettre des paramètres au


routeur, au distributeur, et au contrôleur d'action. Pour récupérer individuellement ceux-
ci utilisez getInvokeArg($key) ; alternativement, récupérer la liste entière en utilisant
getInvokeArgs().

323
Zend_Controller

• Paramètres de requêtes : l'objet de requête rassemble les paramètres de requête, comme les
paramètres _GET ou __POST, ou les paramètres utilisateurs spécifiés dans le chemin d'URL.
Pour récupérer ceux-ci utilisez _getParam($key) ou _getAllParams(). Vous pouvez
aussi régler ces paramètres en utilisant _setParam() ; ceci est pratique quand vous redirigez
vers des actions additionnelles.

Pour tester si un paramètre existe ou non (pratique pour les branchements logiques), utilisez
_hasParam($key).

_getParam() peut prendre un second paramètre optionnel contenant une


valeur par défaut à utiliser si le paramètre n'est pas réglé ou qu'il est vide.
Utiliser ceci élimine la nécessité d'appeler _hasParam() avant de récupérer
une valeur :

// Utilise une valeur par défaut de 1 si id n'est pas réglé


$id = $this->_getParam('id', 1);

// Au lieu de :
if ($this->_hasParam('id') {
$id = $this->_getParam('id');
} else {
$id = 1;
}

7.5. Intégration des Vues


Par défaut, l'intégration des vues est réalisé via le ViewRenderer

Le contenu de cette section n'est valable que si vous avez explicitement


désactivé le ViewRenderer. Sinon, vous pouvez passer à la section suivante.

Zend_Controller_Action fournit un mécanisme rudimentaire et flexible pour l'intégration


des vues. Deux méthodes accomplissent ceci, initView() et render() ; la première méthode
charge la propriété publique $view, et la dernière effectue le rendu d'une vue basé sur l'action
courante demandée dans la requête, en utilisant la hiérarchie des répertoires pour déterminer
le chemin du script.

7.5.1. Initialisation des Vues


initView() initialise l'objet Vue. render() appelle initView() dans le but de récupérer
l'objet de vue, mais il peut être initialisé à tout moment ; par défaut il remplit la propriété $view
avec un objet Zend_View, mais toute classe implémentant Zend_View_Interface peut être
utilisée. Si $view est déjà initialisé, il retourne simplement cette propriété.

La mise en oeuvre par défaut suppose la structure de répertoire suivante :

applicationOrModule/
controllers/
IndexController.php
views/
scripts/
index/
index.phtml

324
Zend_Controller

helpers/
filters/

En d'autres termes, les scripts de vues sont supposés être dans le sous-répertoire /views/
scripts/, et le sous-répertoire /views/ est censé contenir les fonctionnalités soeurs (aides
[helpers], filtres [filters]). En déterminant le script de vue et son chemin, le répertoire /views/
scripts/ est utilisé comme chemin de base, avec des dossiers nommés par le nom de
contrôleur fournissant ainsi la hiérarchie des scripts de vues.

7.5.2. Effectuer le rendu des Vues


render() a la signature suivante :

string render(string $action = null,


string $name = null,
bool $noController = false);

render() effectue le rendu d'un script de vue. Si aucun argument n'est fourni, la méthode
suppose que le script requêté est [controller]/[action].phtml (où .phtml est la valeur
de la propriété $viewSuffix). Fournir une valeur pour $action va effectuer le rendu du
script dans le sous-dossier /[controller]/. Pour surcharger l'utilisation du sous-dossier /
[controller]/, fournissez la valeur TRUE à $noController. Enfin, les scripts sont rendus
dans l'objet réponse ; si vous souhaitez effectuer le rendu dans un segment nomméspécifique
de l'objet réponse, fournissez une valeur à $name.

Puisque le contrôleur et des noms d'action peuvent contenir des caractères


délimiteurs de mot comme '_', '.' et '-', render() normalise ceux-ci à '-' en
déterminant le nom du script. En interne, il utilise le délimiteur de mot et de chemin
du istributeur pour faire cette normalisation. Ainsi, une requête pour /foo.bar/
baz-bat rendra le script foo-bar/baz-bat.phtml. Si votre méthode d'action
contient des notationsCamel, veuillez vous souvenir que ceci va résulter avec
des mots séparés par '-' en déterminant le nom de fichier du script de vue.

Quelques exemples :

class MonController extends Zend_Controller_Action


{
public function fooAction()
{
// Effectue le rendu de mon/foo.phtml
$this->render();

// Effectue le rendu de mon/bar.phtml


$this->render('bar');

// Effectue le rendu de baz.phtml


$this->render('baz', null, true);

// Effectue le rendu de mon/login.phtml vers le segment


// 'form' de l'objet réponse
$this->render('login', 'form');

// Effectue le rendu de site.phtml vers le segment


// 'page' de l'objet réponse ; sans utiliser
// le sous-dossier 'mon/'

325
Zend_Controller

$this->render('site', 'page', true);


}

public function bazBatAction()


{
// Effectue le rendu de mon/baz-bat.phtml
$this->render();
}
}

7.6. Méthodes utiles


En plus de l'accesseur et des méthodes d'intégration de vue, Zend_Controller_Action
possède plusieurs méthodes utiles pour exécuter des tâches communes de l'intérieur de vos
méthodes d'action (ou de pre- / post-dispatch).

• _forward($action, $controller = null, $module = null, array $params =


null) : exécute une autre action. Si appelé dans preDispatch(), la requête courante est
évitée en faveur de la nouvelle. Sinon, après que l'action courante ait été exécutée, l'action
demandée dans _forward() sera exécutée à son tour.

• _redirect($url, array $options = array()) : redirige vers une autre page. Cette
méthode prend un URL et un jeu d'options optionnel. Par défaut, il exécute une redirection
de type HTTP 302.

Les options peuvent inclure une ou plusieurs des clés suivantes :

• : avec ou sans sortie immédiate. Si appelée, la méthode fermera proprement toute session
ouverte et réalisera la redirection.

Vous pouvez régler cette option de manière globale dans le contrôleur en utilisant
l'accesseur setRedirectExit().

• prependBase : ajoute ou non l'URL de base enregistré dans l'objet requête à l'URL produit.

Vous pouvez régler cette option de manière globale dans le contrôleur en utilisant
l'accesseur setRedirectPrependBase().

• code : fournit le code HTTP à utiliser pour la redirection. Par défaut, un HTTP 302 est utilisé ;
tout code compris entre 301 et 306 peut être utilisé.

Vous pouvez régler cette option de manière globale dans le contrôleur en utilisant
l'accesseur setRedirectCode().

7.7. Sous-classer le contrôleur d'action


Par conception, Zend_Controller_Action doit être sous-classé pour créer un contrôleur
d'action. Au minimum, vous devez définir les méthodes d'action que le contrôleur d'action peut
appeler.

En plus de la création de fonctionnalité utile pour vos applications Web, vous pouvez aussi
constater que vous répétez souvent la même installation ou les mêmes méthodes utilitaires dans
vos contrôleurs divers ; s'il en est ainsi, créer une classe de contrôleur de base commune qui
étend Zend_Controller_Action peut résoudre une telle redondance.

326
Zend_Controller

Exemple 88. Comment gérer des actions non-existantes

Si une requête vers un contrôleur est faite en incluant une méthode d'action indéfinie,
Zend_Controller_Action::__call() sera invoqué. __call() est, bien sûr, la
méthode magique de PHP pour la surcharge de méthode.

Par défaut, cette méthode lève une Zend_Controller_Action_Exception indiquant


que la méthode requêtée n'a pas été trouvée dans le contrôleur. Si la méthode requêtée se
termine par "Action", on considère qu'une action était requêté et qu'elle n'existe pas ; un telle
erreur entraîne une exception ayant un code 404. Tout autre appel de méthode entraîne
une exception ayant un code 500. Ceci vous permet de facilement différencier une page
inconnue et une erreur de l'application dans votre gestionnaire d'erreur.

Vous pouvez surcharger cette fonctionnalité si vous souhaitez exécuter d'autres opérations.
Par exemple, si vous souhaitez afficher un message d'erreur, vous pouvez écrire quelque
chose comme ceci :

class MonController extends Zend_Controller_Action


{
public function __call($method, $args)
{
if ('Action' == substr($method, -6)) {
// Si une méthode d'action n'est pas trouvée,
// rendre le script d'erreur
return $this->render('error');
}

// pour toute autre méthode, levée d'une exception


throw new Exception('Méthode invalide "' . $method . '" appelée',
500);
}
}

Une autre possibilité est de rediriger vers une page de contrôleur par défaut :

class MyController extends Zend_Controller_Action


{
public function indexAction()
{
$this->render();
}

public function __call($method, $args)


{
if ('Action' == substr($method, -6)) {
// Si une méthode d'action n'est pas trouvée,
// rediriger vers l'action index
return $this->_forward('index');
}

// pour tout autre méthode, levée d'une exception


throw new Exception('Méthode invalide "' . $method . '" appelée',
500);
}
}

En plus de la surcharge de __call(), chacune des méthodes d'initialisation , utilitaires,


d'accesseurs, de vues et de détournement de la distribution mentionnées ci-dessus peuvent être

327
Zend_Controller

surchargées dans le but de personnaliser vos contrôleurs. Par exemple, si vous stockez votre
objet de vue dans le registre, vous pouvez vouloir modifier votre méthode initView() avec
une code comme celui-ci :

abstract class Ma_Base_Controller extends Zend_Controller_Action


{
public function initView()
{
if (null === $this->view) {
if (Zend_Registry::isRegistered('view')) {
$this->view = Zend_Registry::get('view');
} else {
$this->view = new Zend_View();
$this->view->setBasePath(dirname(__FILE__) . '/../views');
}
}

return $this->view;
}
}

En espérant que les informations de ce chapitre vous permettent de voir la flexibilité de


ce composant particulier et comment vous pouvez le modifier suivant les besoins de votre
application.

8. Aides d'action (Helper)


8.1. Introduction
Les aides d'action permettent aux développeurs d'injecter, en cours d'exécution et/
ou à la demande, des fonctionnalités dans tout contrôleur d'action qui étend
Zend_Controller_Action. Le but des aides d'action est de minimiser la nécessité d'étendre
le contrôleur d'action abstrait en y injectant des fonctionnalités communes de contrôleur d'action.

Il y a de nombreuses manières d'utiliser les aides d'action. Les aides d'action utilisent le système
de gestionnaire ("Broker"), similaire aux gestionnaires vus pour les Zend_View_Helper, et les
Zend_Controller_Plugin. Les aides d'action (comme les aides de vue Zend_View_Helper)
peuvent être chargées et appelées à la demande, ou elles peuvent être instanciées au début de
la requête ("bootstrap") ou au moment de la création des contrôleurs d'action (init()). Pour
mieux comprendre ceci, reportez vous à la section d'utilisation ci-dessous.

8.2. Initialisation des aides


Une aide peut être initialisée de plusieurs manières différentes, basées sur vos besoins aussi
bien que la fonctionnalité de l'aide.

Le gestionnaire d'aide est stocké en tant que membre $_helper du


Zend_Controller_Action ; utilisez le gestionnaire pour récupérer ou appeler les aides. Les
méthodes pour faire ceci incluent :

• L'utilisation explicite de getHelper(). Passez lui simplement un nom, et l'objet d'aide est
retourné :

$flashMessenger = $this->_helper->getHelper('FlashMessenger');
$message = 'Nous avons fait quelquechose lors de la dernière requête';
$flashMessenger->addMessage($message);

328
Zend_Controller

• L'utilisation de la fonctionnalité __get() du gestionnaire d'aide et récupérez l'aide comme si


elle était une propriété membre du gestionnaire :

$flashMessenger = $this->_helper->FlashMessenger;
$message = 'Nous avons fait quelquechose lors de la dernière requête';
$flashMessenger->addMessage($message);

• Enfin, la plupart des aides d'action implémente la méthode direct() qui va appeler une
méthode spécifique par défaut dans l'aide. Dans l'exemple de FlashMessenger, ceci appelle
addMessage() :

$message = 'Nous avons fait quelquechose lors de la dernière requête';


$this->_helper->FlashMessenger($message);

Tous les exemples ci-dessus sont équivalents.

Vous pouvez vouloir aussi instancier les aides explicitement. Vous pourriez avoir besoin de ceci
si vous utilisez l'aide hors du contexte du contrôleur d'action, ou si vous souhaitez fournir une
aide au gestionnaire d'aides à utiliser pour une action quelconque. L'instanciation se fait comme
toute autre classe PHP.

8.3. Le gestionnaire d'aide (Broker)


Zend_Controller_Action_HelperBroker gère les détails de l'enregistrement des objets
d'aide et les chemins de ces aides, ainsi que la récupération des aides à la demande.

Pour enregistrer une aide dans le gestionnaire, utilisez addHelper :

Zend_Controller_Action_HelperBroker::addHelper($helper);

Bien sûr, instancier et fournir des aides au gestionnaire est coûteux en temps et en ressource
donc deux méthodes existent pour automatiser les choses légèrement : addPrefix() et
addPath().

• addPrefix() prend un préfixe de classe et l'utilise pour déterminer le chemin des dossiers
dans lesquels les classes d'aides ont été définies. Ceci suppose que le préfixe de la classe
respecte la convention de nommage de Zend Framework.

// Ajoute les aides préfixées Mes_Action_Helpers dans Mes/Action/Helpers/


Zend_Controller_Action_HelperBroker::addPrefix('Mes_Action_Helpers');

• addPath() prend un répertoire en premier argument et un préfixe de classe en second


(par défaut réglé à "Zend_Controller_Action_Helper"). Ceci vous permet de faire
correspondre vos propres préfixes de classe à vos dossiers spécifiques.

// Ajoute les aides préfixées avec Aide dans Plugins/Aides/


Zend_Controller_Action_HelperBroker::addPath('./Plugins/Aides', 'Aide');

Puisque ces méthodes sont statiques, elles peuvent être appelées en tout point du déroulement
du contrôleur pour ajouter dynamiquement les aides nécessaires.

En interne, le gestionnaire d'aide utilise une instance de PluginLoaderpour conserver


les chemins. Vous pouvez récupérer le PluginLoader en utilisant la méthode statique

329
Zend_Controller

getPluginLoader(), ou alternativement, injecter une instance personnalisée de


PluginLoader en utilisant setPluginLoader().

Pour déterminer si une aide existe dans le gestionnaire d'aide, utilisez hasHelper($name), où
$name est le nom raccourci de l'aide (sans le préfixe) :

// Vérifie si l'aide 'redirector' est enregistrée dans le gestionnaire :


if (Zend_Controller_Action_HelperBroker::hasHelper('redirector')) {
echo 'L\'aide Redirector est enregistrée';
}

Il existe aussi deux méthodes statiques pour récupérer les aides issues du gestionnaire d'aide :
getExistingHelper() et getStaticHelper(). getExistingHelper() récupérera une
aide seulement si elle a précédemment été invoquée par ou explicitement enregistrée dans le
gestionnaire d'aides; la méthode lèvera une exception sinon. getStaticHelper() réalise la
même chose que getExistingHelper(), mais tentera d'instancier l'aide si elle n'a pas déjà
été enregistrée dans la pile des aides. getStaticHelper() est un bon choix pour récupérer
les aides que vous voulez configurer.

Les deux méthodes prennent un unique paramètre, $name, qui est le nom court de l'aide (c'est-
à-dire sans le préfixe).

// Vérifie si l'aide 'redirector' est enregistrée dans le gestionnaire,


// et l'extrait :
if (Zend_Controller_Action_HelperBroker::hasHelper('redirector')) {
$redirector =
Zend_Controller_Action_HelperBroker::getExistingHelper('redirector');
}

// Ou, simplement le récupère, sans se soucier s'il a ou non été


// enregistré précédemment :
$redirector =
Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
}

Enfin, pour effacer une aide enregistrée du gestionnaire, utilisez removeHelper($name), où


$name est le nom raccourci de l'aide (sans le préfixe) :

// Effacement conditionnel de l'aide 'redirector' du gestionnaire :


if (Zend_Controller_Action_HelperBroker::hasHelper('redirector')) {
Zend_Controller_Action_HelperBroker::removeHelper('redirector')
}

8.4. Aides d'action intégrées


Zend Framework inclue plusieurs aides d'action par défaut : AutoComplete pour des réponses
automatiques à des auto-complétions AJAX ; ContextSwitch et AjaxContext pour distribuer
des formats de réponse alternatifs pour vos actions ; FlashMessenger pour gérer des
messages entre les sessions ; Redirector, qui fournit différentes implémentations pour
rediriger vers des pages internes ou externes à votre application ; et ViewRenderer pour
automatiser le processus de paramétrage de vos objets de vues dans votre contrôleur et du
rendu de ces vues.

8.4.1. ActionStack
L'aide ActionStack vous permet d'empiler les requêtes dans le plugin de contrôleur frontal
ActionStack, vous aidant effectivement à créer une liste d'actions à exécuter durant la requête.

330
Zend_Controller

Cette aide vous permet d'ajouter des actions, soit en spécifiant de nouveaux objets de requêtes,
soit en paramétrant action / controller / module.

Invoquer l'aide ActionStack initialise le plugin ActionStack

L'appel de l'aide ActionStack enregistre implicitement le plugin ActionStack - ce


qui veut dire que vous n'avez pas besoin d'enregistrer explicitement le plugin
ActionStack pour utiliser cette fonctionnalité.

Exemple 89. Ajouter une tâche en utilisant une action, un contrôleur et un module

Souvent, il est plus simple de spécifier l'action, le contrôleur et le module (et


optionnellement des paramètres de requêtes), comme vous le feriez en appelant
Zend_Controller_Action::_forward() :

class FooController extends Zend_Controller_Action


{
public function barAction()
{
// Ajoute deux actions à la pile

// Ajoute un appel à /foo/baz/bar/baz (FooController::bazAction()


// avec une variable de requête bar == baz)
$this->_helper->actionStack('baz',
'foo',
'default',
array('bar' => 'baz'));

// Ajoute un appel à /bar/bat


// (BarController::batAction())
$this->_helper->actionStack('bat', 'bar');
}
}

331
Zend_Controller

Exemple 90. Ajouter une tâche en utilisant un objet de requête

Parfois la nature OO d'un objet de requête a plus de sens ; vous pouvez alors fournir l'objet
à l'aide ActionStack.

class FooController extends Zend_Controller_Action


{
public function barAction()
{
// Ajoute deux actions à la pile

// Ajoute un appel à /foo/baz/bar/baz (FooController::bazAction()


// avec une variable de requête bar == baz)
$request = clone $this->getRequest();
// sans régler le contrôleur ou le module,
// utilise les valeurs courantes
$request->setActionName('baz')
->setParams(array('bar' => 'baz'));
$this->_helper->actionStack($request);

// Ajoute un appel à /bar/bat


// (BarController::batAction())
$request = clone $this->getRequest();
// sans régler le module, utilise la valeur courante
$request->setActionName('bat')
->setControllerName('bar');
$this->_helper->actionStack($request);
}
}

8.4.2. AutoComplete

Beaucoup de librairies javascript AJAX propose une fonctionnalité dite d'auto-complétion. Une
liste de résultats possibles est chargée au fur et à mesure que l'utilisateur saisit. L'aide
AutoComplete est destinée à simplifier le retour de ces valeurs vers la librairie Javascript.

Toutes les librairies JS n'implémentant pas l'auto-complétion de la même manière, l'aide


AutoComplete propose une solution abstraite, ainsi que des implémentations concrètes pour
certaines librairies. Les types de valeur de retour sont en général des tableaux de chaînes
JSON, des tableaux de tableaux JSON (avec chaque membre étant un tableau associatif de
métadonnées utilisées pour créer la liste de sélection), ou du HTML.

L'utilisation basique ressemble à ceci :

class FooController extends Zend_Controller_Action


{
public function barAction()
{
// Ici du travail ....

// Encode et envoie la réponse


$this->_helper->autoCompleteDojo($data);

// Ou :
$response = $this->_helper
->autoCompleteDojo
->sendAutoCompletion($data);

332
Zend_Controller

// Ou alors prépare simplement les données :


$response = $this->_helper
->autoCompleteDojo
->prepareAutoCompletion($data);
}
}

Par défaut, l'auto-complétion :

• Désactive les layouts et le ViewRenderer.

• Affecte des en-têtes de réponse appropriés.

• Remplit le corps de la réponse avec les données d'auto-complétion encodées/formatées.

• Envoie la réponse.

Les méthodes disponibles sont :

• disableLayouts() est utilisée pour désactiver les layouts et le ViewRenderer. Cette


méthode est appelées par prepareAutoCompletion().

• encodeJson($data, $keepLayouts = false) va encoder les données en JSON. Cette


méthode est appelées par prepareAutoCompletion().

• prepareAutoCompletion($data, $keepLayouts = false) prépare les données


dans le format de réponse nécessaire à une implémentation concrète. La valeur de retour va
changer en fonction de l'implémentation (de la librairie utilisée).

• sendAutoCompletion($data, $keepLayouts = false) Va appeler


prepareAutoCompletion(), puis envoyer la réponse.

• direct($data, $sendNow = true, $keepLayouts = false) est une méthode


utilisée par le gestionnaire d'aides (helper broker). La valeur de $sendNow va déterminer si
c'est sendAutoCompletion() ou prepareAutoCompletion(), qui doit être appelée.

Actuellement, AutoComplete supporte les librairies AJAX Dojo et Scriptaculous.

8.4.2.1. AutoCompletion avec Dojo

Dojo n'a pas une fonctionnalité d'auto-complétion, mais deux : ComboBox et FilteringSelect.
Dans les deux cas, elle demande une structure de données qui implémente QueryReadStore ;
voyez la documentation de dojo.data

Dans Zend Framework, vous pouvez passer un simple tableau indexé à l'aide
AutoCompleteDojo, elle retournera une réponse JSON compatible avec la structure de données
Dojo :

// à l'intérieur d'une action de contrôleur :


$this->_helper->autoCompleteDojo($data);

333
{
Voyons le javascript
protected nécessaire. Dojo est une librairie complète pour la création de javascript
$_form;
dojo.provide("custom.TestNameReadStore");
OO, un peu comme
L'auto-complétion avecZend Framework
Dojo via MVCpour PHP. plusieurs
requière Il est possible
choses de : créer des un
générer pseudo-
objet
dojo.declare("custom.TestNameReadStore",
Ensuite, créons le formulaire sur lequelvous
nous souhaitons une auto-complétion : répertoire
namespaces
formulaire
public en utilisant
surfunction l'arborescence
ledojox.data.QueryReadStore,
ComboBox sur
getForm() lequel des
Zend_Controller répertoires.
voulez Nous allons créer
de l'auto-complétion, un
un contrôleur avec
"custom"
{
une action aupour
mêmeservir
{ niveau
les que le
résultats, répertoire
la Dojo.
création d'un A l'intérieur,
QueryReadStorenous allons
à créer
connecter un
à fichier
l'action
Cette classe
javascript, if estfetch:function
(nullune simple
===
TestNameReadStore.js,
et la génération du javascript extension
$this->_form)
à utiliser de {QueryReadStore,
avec
pour
(request) le{contenu
initialiser suivantqui
: est une
l'auto-complétion classe
coté abstraite.
serveur.
NousExemple
définissonsrequire_once
simplement 'Zend/Form.php';
une
request.serverQueryméthode de
= { requête, et on lui assigne
test:request.query.name notre
}; élément
91. AutoCompletion
$this->_form
avec Dojo en utilisant MVC
= new Zend_Form();
"test". return this.inherited("fetch", arguments);
$this->_form->setMethod('get')
}
}); ->setAction($this->getRequest()->getBaseUrl()
. '/test/process')
->addElements(array(
'test' => array('type' => 'text', 'options' => array(
'filters' => array('StringTrim'),
'dojoType' => array('dijit.form.ComboBox'),
'store' => 'testStore',
'autoComplete' => 'false',
'hasDownArrow' => 'true',
'label' => 'Your input:',
)),
'go' => array('type' => 'submit',
'options' => array('label' => 'Go!'))
class TestController extends Zend_Controller_Action
Ici,
{
nous créons simplement
)); un formulaire avec des méthodes "test" et "go". La méthode
"test"//ajoute
}
... plusieurs attributs Dojo spéciaux : dojoType, store, autoComplete, et
Ajoutons une méthode
hasDownArrow.
return dojoType pour afficherpour
est utilisé
$this->_form; le indiquer
formulaire, et une entrée
la création pour traiteretl'auto-
d'une ComboBox, nous
complétion
allons/**
} :
la relier au conteneur de données ("store") de "testStore". Mettre "autoComplete" à
}
FALSE*ditLanding
à Dojo de ne pas sélectionner automatiquement la première valeur, mais de plutôt
page
montrer */une liste de valeurs possibles. Enfin, "hasDownArrow" crée une flèche bas comme
public
sur les select function
box. indexAction()
{
$this->view->form = $this->getForm();
}

public function autocompleteAction()


{
if ('ajax' != $this->_getParam('format', false)) {
return $this->_helper->redirector('index');
}
if ($this->getRequest()->isPost()) {
return $this->_helper->redirector('index');
}

$match = trim($this->getRequest()->getQuery('test', ''));

$matches = array();
<?php //foreach
configuration de l'entrepôt
($this->getData() de données
as $datum) { : ?>
<div dojoType="custom.TestNameReadStore"
if (0 === strpos($datum, $match)) jsId="testStore"
{
Voyons maintenant notre$this->baseUrl()
url="<?php echo
script de vue. Nous devons configurer notre entrepôt de données,
$matches[] = $datum; ?>/unit-test/autocomplete/format/ajax"
puis
Dansrendre le formulaire,
autocompleteAction(),et s'assurer
requestMethod="get"></div>
} quevérifions
nous les librairies
que Dojo
nousappropriées
avons bien sont
une bien chargées
requête post,
(ainsi
et un que }notre
paramètre entrepôt).
"format" Voici
avec le
la script
valeur de vue
"ajax".: Ensuite, nous vérifions la présence d'un
paramètre "test", et
duleformulaire
comparons avec: ?>nos données. (getData() retourne des données
<?php //$this->_helper->autoCompleteDojo($matches);
rendu
quelconques).
<?php Enfin, nous envoyons
} echo $this->form ?> nos résultats à notre aide AutoCompletion.
<?php
} // configuration des CSS de Dojo dans le head HTML : ?>
<?php $this->headStyle()->captureStart() ?>
@import "<?php echo $this->baseUrl()
?>/javascript/dijit/themes/tundra/tundra.css";
@import "<?php echo $this->baseUrl() ?>/javascript/dojo/resources/dojo.css";
<?php $this->headStyle()->captureEnd() ?>
<?php // configuration de javascript pour charger
// les librairies Dojo dans le head HTML : ?>
<?php $this->headScript()
->setAllowArbitraryAttributes(true)
->appendFile($this->baseUrl() . '/javascript/dojo/dojo.js',
'text/javascript',
array('djConfig' => 'parseOnLoad: true'))
Nous pouvons->captureStart() ?>
dès lors faire fonctionner l'auto-complétion Dojo.
djConfig.usePlainJson=true;
dojo.registerModulePath("custom","../custom");
Notez les appels aux aides de vue comme headStyle et headScript ; celles-ci sont des
dojo.require("dojo.parser");
emplacements réservés, que nous pouvons ensuite utiliser pour effectuer le rendu dans la
dojo.require("dojox.data.QueryReadStore");
section "head" du HTML de votre script
dojo.require("dijit.form.ComboBox"); 334 de layout.
dojo.require("custom.TestNameReadStore");
<?php $this->headScript()->captureEnd() ?>
Zend_Controller

8.4.2.2. AutoCompletion avec Scriptaculous

Scriptaculous attend une réponse HTML dans un format spécifique.

Utilisez l'aide "AutoCompleteScriptaculous". Passez lui un tableau de données et l'aide créera


une réponse HTML compatible avec "Ajax.Autocompleter".

8.4.3. ContextSwitch et AjaxContext


L'aide d'action ContextSwitch est destinée à faciliter le retour de différents formats de réponse
à une requête.L'AjaxContext est une aide spécialisée de ContextSwitch qui permet le renvoi de
réponses à XmlHttpRequest.

Pour l'activer, vous devez indiquer à votre contrôleur quelles actions répondent à quel contexte.
Si une requête d'entrée indique un contexte valide pour une action, alors l'aide d'action en
charge :

• Va désactiver les layouts, si elles sont activées.

• Va changer le suffixe de la vue à rendre, il faudra donc créer une vue par contexte.

• Va envoyer les bons en-têtes de réponse en fonction du contexte désiré.

• Va éventuellement en option appeler des fonctions pour configurer le contexte, ou des


fonctions de post-processing.

Comme exemple, prenons le contrôleur suivant :

class NewsController extends Zend_Controller_Action


{
/**
* page d'arrivée; forward vers listAction()
*/
public function indexAction()
{
$this->_forward('list');
}

/**
* Liste les news
*/
public function listAction()
{
}

/**
* Affiche une new particulière
*/
public function viewAction()
{
}
}

Imaginons que nous voulions que listAction() soit aussi accessible au format XML. Plutôt
que de créer une autre action, nous pouvons lui indiquer qu'elle doit retourner du XML :

class NewsController extends Zend_Controller_Action


{

335
Zend_Controller

public function init()


{
$contextSwitch = $this->_helper->getHelper('contextSwitch');
$contextSwitch->addActionContext('list', 'xml')
->initContext();
}

// ...
}

Ce code aura pour effet :

• De changer le "Content-Type" de la réponse en "text/xml".

• De changer le suffixe de vue vers "xml.phtml" (ou un autre suffixe si vous en utilisez un
personnalisé "xml.[votre suffixe]").

Il est donc nécessaire de créer un nouveau script de vue, "news/list.xml.phtml", qui créera
et rendra le XML.

Pour savoir si la requête doit utiliser un contexte switch, l'aide vérifie un jeton dans l'objet
de requête. Par défaut, l'aide va chercher le paramètre de requête "format", ceci peut être
changé. Ceci signifie que dans la plupart des cas, pour changer le contexte d'une réponse, il
faut simplement injecter un paramètre "format" à la requête:

• Via l'URL : /news/list/format/xml (le routeur par défaut utilise les paires clés et valeurs
fournies après l'action)

• Via un paramètre GET : /news/list?format=xml

ContextSwitch vous permet d'écrire des contextes, ceux-ci spécifient le suffixe de vue qui
change, les en-têtes de réponse à modifier, et les fonctions de rappel éventuelles.

8.4.3.1. Contextes inclus par défaut

Par défaut, il existe 2 contextes dans l'aide ContextSwitch : json et xml.

• JSON. Le contexte JSON met le "Content-Type" de la réponse à "application/json", et


le suffixe de la vue est "json.phtml".

Par défaut cependant, aucun script de vue n'est nécessaire, il va simplement sérialiser en
JSON toutes les variables de vues, et les envoyer en tant que réponse.

Ce comportement peut être désactivé en éteigant le paramètre de sérialisation JSON :

$this->_helper->contextSwitch()->setAutoJsonSerialization(false);

• XML. Le contexte XML met le "Content-Type" de la réponse à "text/xml", et utilise un suffixe


de vue "xml.phtml". Vous devrez créer une nouvelle vue pour ce contexte.

8.4.3.2. Créer ses propres contextes

Vous pouvez créer vos propres contextes d'action. Par exemple pour retourner du YAML, du
PHP sérialisé, ou encore du RSS ou du ATOM. ContextSwitch est là pour cela.

La manière la plus simple d'ajouter un nouveau contexte d'action est la méthode


addContext(). Elle prend 2 paramètres : le nom du contexte, et un tableau d'options. Ce
tableau d'option doit comporter au moins une des clés suivantes :

336
Zend_Controller

• suffix : Le préfixe qui va s'ajouter au suffixe de vue. Il sera utiliser par le ViewRenderer.

• headers : un tableau d'en-têtes et de valeurs que vous voulez ajouter à la réponse.

• callbacks : un tableau dont les clés peuvent être "init" ou "post", et les valeurs représentent des
noms de fonctions PHP valides, qui seront utilisées pour initialiser ou traiter la fin du contexte.

Les fonctions d'initialisation interviennent lorsque le contexte est détecté par ContextSwitch.
Par exemple dans le contexte intégré JSON, la fonction désactive le ViewRenderer lorsque la
sérialisation automatique JSON est activée.

Les fonctions de traitement de fin de contexte (Post processing) interviennent durant le


processus de postDispatch() de l'action en cours. Par exemple pour le contexte intégré
JSON, la fonction de post process regarde si la sérialisation automatique JSON est active, si
c'est le cas, elle va sérialiser les variables de la vue en JSON, et envoyer la réponse ; mais
dans le cas contraire, elle va réactiver le ViewRenderer.

Voici les méthodes d'interaction avec les contextes :

• addContext($context, array $spec) : Ajoute un nouveau contexte. Si celui-ci existe


déjà, une exception sera lancée.

• setContext($context, array $spec) : Ajoute un nouveau contexte, mais écrase celui-


ci s'il existait déjà. Utilise les mêmes spécifications que addContext().

• addContexts(array $contexts) : Ajoute plusieurs contextes d'un coup. Le tableau


$contexts doit être un tableau de paires contexte et specifications. Si un des contextes
existe déjà, une exception est lancée.

• setContexts(array $contexts) : Ajoute des nouveaux contextes, mais écrase ceux


déjà présents éventuellement. Utilise les mêmes spécifications que addContexts().

• hasContext($context) : retourne TRUE si le contexte existe déjà, FALSE sinon.

• getContext($context) : retourne un contexte par son nom. Le retour est un tableau qui
a la même syntaxe que celui utilisé par addContext().

• getContexts() : retourne tous les contextes. Le tableau de retour est de la forme contexte
=> spécifications.

• removeContext($context) : Supprime un contexte grâce à son nom. Retourne TRUE si


réussi, FALSE si le contexte n'a pas été trouvé.

• clearContexts() : Supprime tous les contextes.

8.4.3.3. Affecter des contextes par action

Il existe deux mécanismes pour créer et affecter des contextes. Vous pouvez créer des tableaux
dans vos contrôleurs, ou utiliser plusieurs méthodes de ContextSwitch pour les assembler.

La méthode principale pour ajouter des contextes à des actions est addActionContext().
Elle attend 2 arguments, l'action et le contexte (ou un tableau de contextes). Par exemple,
considérons la classe suivante :

class FooController extends Zend_Controller_Action


{

337
Zend_Controller

public function listAction()


{
}

public function viewAction()


{
}

public function commentsAction()


{
}

public function updateAction()


{
}
}

Imaginons que nous voulions ajouter un contexte XML à l'action "list", et deux contextes XML et
JSON à l'action "comments". Nous pourrions faire ceci dans la méthode init() :

class FooController extends Zend_Controller_Action


{
public function init()
{
$this->_helper->contextSwitch()
->addActionContext('list', 'xml')
->addActionContext('comments', array('xml', 'json'))
->initContext();
}
}

De la même manière, il est aussi possible de simplement définir la propriété $contexts :

class FooController extends Zend_Controller_Action


{
public $contexts = array(
'list' => array('xml'),
'comments' => array('xml', 'json')
);

public function init()


{
$this->_helper->contextSwitch()->initContext();
}
}

Cette syntaxe est simplement moins pratique et plus prompte aux erreurs.

Pour construire vos contextes, les méthodes suivantes vous seront utiles :

• addActionContext($action, $context) : Ajoute un ou plusieurs contextes à une


action. $context doit donc être une chaîne, ou un tableau de chaînes.

Passer la valeur TRUE comme contexte marquera tous les contextes comme disponibles pour
cette action.

Une valeur vide pour $context désactivera tous les contextes donnés à cette action.

338
Zend_Controller

• setActionContext($action, $context) : Marque un ou plusieurs contextes comme


disponibles pour cette action. Si ceux-ci existent déjà, ils seront remplacés. $context doit
être une chaîne ou un tableau de chaînes.

• addActionContexts(array $contexts) : Ajoute plusieurs paires action et contexte en


une fois. $contexts doit être un tableau associatif action et contexte. Cette méthode proxie
vers addActionContext().

• setActionContexts(array $contexts) : agit comme addActionContexts(), mais


écrase les paires action et contexte existantes.

• hasActionContext($action, $context) : détermine si une action possède un contexte


donné.

• getActionContexts($action = null) : Retourne tous les contextes d'une action


donnée, si pas d'action passée, retourne alors toutes les paires action et contexte.

• removeActionContext($action, $context) : Supprime un ou plusieurs contextes pour


une action. $context doit être une chaîne ou un tableau de chaînes.

• clearActionContexts($action = null) : Supprime tous les contextes d'une action. Si


aucune action n'est spécifiée, supprime alors tous les contextes de toutes les actions.

8.4.3.4. Initialiser le Context Switch

Pour initialiser la permutation de contextes (contexte switching), vous devez appeler


initContext() dans vos contrôleurs d'action :

class NewsController extends Zend_Controller_Action


{
public function init()
{
$this->_helper->contextSwitch()->initContext();
}
}

Dans certains cas, vous voudriez forcer un contexte pour une action ; par exemple vous pouvez
vouloir seulement le contexte XML si la permutation de contexte est active. Passez le alors à
initContext() :

$contextSwitch->initContext('xml');

8.4.3.5. Fonctionnalités avancées

Voici quelques méthodes qui peuvent être utilisées pour changer le comportement de l'aide
ContextSwitch :

• setAutoJsonSerialization($flag): Par défaut, le contexte JSON va sérialiser toute


variable en notation JSON et les retourner en tant que réponse. Si vous voulez créer
votre propre réponse, vous voudriez désactiver cet effet. Ceci doit être fait avant l'appel à
initContext().

$contextSwitch->setAutoJsonSerialization(false);
$contextSwitch->initContext();

339
Zend_Controller

Pour récupérer la valeur actuelle, utilisez getAutoJsonSerialization().

• setSuffix($context, $suffix, $prependViewRendererSuffix) : Cette méthode


permet de personnaliser le suffixe de vue d'un contexte. Le troisième argument indique si le
suffixe actuel du ViewRenderer doit être utilisé comme préfixe de votre suffixe. Par défaut,
c'est le cas.

Passer une valeur vide au suffixe aura pour effet de n'utiliser que le suffixe du ViewRenderer.

• addHeader($context, $header, $content) : Ajoute un en-tête à la réponse pour un


contexte donné. $header est le nom de l'en-tête et $content sa valeur.

Chaque contexte peut posséder plusieurs en-têtes, addHeader() ajoute des en-têtes dans
une pile, pour un contexte donné.

Si l'en-tête $header spécifié pour le contexte existe déjà, une exception sera alors levée.

• setHeader($context, $header, $content) : setHeader() agit comme


addHeader(), sauf qu'il va écraser un en-tête qui aurait déjà été présent.

• addHeaders($context, array $headers) : Ajoute plusieurs en-têtes en une seule fois.


Proxie vers addHeader().$headers est un tableau de paires header => contexte.

• setHeaders($context, array $headers.) : comme addHeaders(), sauf que cette


méthode proxie vers setHeader(), vous permettant d'écraser des en-têtes déjà présents.

• getHeader($context, $header) : retourne une valeur d'en-tête pour un contexte.


Retourne NULL si non trouvé.

• removeHeader($context, $header) : supprime un en-tête d'un contexte.

• clearHeaders($context, $header) : supprime tous les en-têtes d'un contexte.

• setCallback($context, $trigger, $callback) : affecte une fonction de rappel


(callback) pour un contexte. Le déclencheur peut être soit "init" ou "post" (la fonction de rappel
sera appelée soit à l'initialisation du contexte, ou à la fin, en postDispatch). $callback doit
être un nom de fonction PHP valide.

• setCallbacks($context, array $callbacks) : affecte plusieurs fonctions de rappel


pour un contexte. $callbacks doit être un tableau de paires trigger et callback. Actuellement,
seules deux fonctions maximum peuvent être enregistrées car il n'existe que 2 déclencheurs
(triggers) : "init" et "post".

• getCallback($context, $trigger) : retourne un nom de fonction de rappel affectée


à un contexte.

• getCallbacks($context) : retourne un tableau de paires trigger et callback pour un


contexte.

• removeCallback($context, $trigger) : supprime une fonction de rappel d'un


contexte.

• clearCallbacks($context) : supprime toutes les fonctions de rappel d'un contexte.

• setContextParam($name) : affecte le paramètre de requête à vérifier pour savoir si un


contexte a été appelé. La valeur par défaut est "format".

340
Zend_Controller

getContextParam() en retourne la valeur actuelle.

• setAutoDisableLayout($flag) : Par défaut, les layouts sont désactivées lorsqu'un


contexte intervient, ceci provient du fait que les layouts n'ont en théorie pas de signification
particulière pour un contexte, mais plutôt pour une réponse 'normale'. Cependant si
vous désirez utiliser les layouts pour des contexte, passez alors la valeur FALSE à
setAutoDisableLayout(). Ceci devant être fait avant l'appel à initContext().

Pour récupérer la valeur de ce paramètre, utilisez getAutoDisableLayout().

• getCurrentContext() est utilisée pour savoir quel contexte a été détecté (si c'est le cas).
Cette méthode retourne NULL si aucune permutation de contexte a été détectée, ou si elle est
appelée avant initContext().

8.4.3.6. Fonctionnalité AjaxContext

L'aide AjaxContext étend l'aide de permutation de contexte ContextSwitch, donc toutes les
fonctionnalités de ContextSwitch s'y retrouvent. Il y a cependant quelques différences :

Cette aide utilise une propriété de contrôleur d'action différente pour déterminer les contextes,
$ajaxable. Vous pouvez avoir différents contextes utilisés avec les requêtes AJAX ou HTTP.
Les différentes méthodes ActionContext() de AjaxContext vont écrire dans cette propriété.

De plus, cette aide ne sera déclenchée que si la requête répond au critère


isXmlHttpRequest(). Donc même si le paramètre "format" est passée à la requête, il faut
nécessairement que celle ci soit une requête XmlHttpRequest, sinon la permutation de contexte
n'aura pas lieu.

Enfin, AjaxContext ajoute un contexte, HTML. Dans ce contexte, le suffixe de vue est
"ajax.phtml". Il n'y a pas d'en-tête particulier ajouté à la réponse.

341
Zend_Controller

Exemple 92. Autoriser les actions à répondre aux requêtes AJAX

Dans l'exemple qui suit, nous autorisons les actions "view", "form", et "process" à répondre
aux requêtes AJAX. Dans les actions, "view" et "form", nous retournerons des portions de
HTML ; dans "process", nous retournerons du JSON.

class CommentController extends Zend_Controller_Action


{
public function init()
{
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('view', 'html')
->addActionContext('form', 'html')
->addActionContext('process', 'json')
->initContext();
}

public function viewAction()


{
// Voir les commentaires.
// Quand le AjaxContext est détecté, il utilise le script de vue
// comment/view.ajax.phtml
}

public function formAction()


{
// Rend les formulaire "ajoutez un commentaire".
// Lorsque le AjaxContext est détecté, il utilise le script de
// vue : comment/form.ajax.phtml
}

public function processAction()


{
// Traite un commentaire
// Retourne les résultats sous forme JSON ; assignez simplement
// vos résultats comme variables de vues.
}
}

Coté client, votre bibliothèque AJAX requêtera simplement "/comment/view", "/


comment/form", et "/comment/process", en passant le paramètre "format" :
"/comment/view/format/html", "/comment/form/format/html", "/comment/
process/format/json". (Ceci fonctionne aussi avec "?format=json".)

Il est nécessaire que votre bibliothèque envoie l'en-tête "X-Requested-With:


XmlHttpRequest", ce qui est en général le cas.

8.4.4. FlashMessenger
8.4.4.1. Introduction

L'aide FlashMessenger vous permet de fournir les messages dont l'utilisateur pourrait
avoir besoin dans la requête suivante. Pour accomplir ceci, FlashMessenger utilise
Zend_Session_Namespace pour stocker les messages à retrouver dans la prochaine
requête. C'est généralement une bonne idée si vous planifiez d'utiliser Zend_Session ou
Zend_Session_Namespace, que vous initialisez avec Zend_Session::start() dans votre
fichier d'amorçage. (Reportez vous à la documentation de Zend_Sessionpour plus de détails sur
son utilisation.)

342
Zend_Controller

8.4.4.2. Exemple d'utilisation basique

L'exemple ci-dessous vous montre l'utilisation du flash messenger dans sa forme la plus basique.
Quand l'action /some/my est appelée, il ajoute le message "Sauvegarde réalisée !". Une requête
suivante vers l'action /some/my-next-request le retrouvera (ainsi que le détruira).

class SomeController extends Zend_Controller_Action


{
/**
* FlashMessenger
*
* @var Zend_Controller_Action_Helper_FlashMessenger
*/
protected $_flashMessenger = null;

public function init()


{
$this->_flashMessenger = $this->_helper
->getHelper('FlashMessenger');
$this->initView();
}

public function myAction()


{
/**
* Méthode par défaut por obtenir l'instance de
* Zend_Controller_Action_Helper_FlashMessenger à la demande
*/
$this->_flashMessenger->addMessage('Sauvegarde réalisée !');
}

public function myNextRequestAction()


{
$this->view->messages = $this->_flashMessenger->getMessages();
$this->render();
}
}

8.4.5. JSON
Les réponses JSON sont les réponses de choix dans une architecture de type AJAX qui attend
des données structurées. JSON peut être immédiatement interprété du coté du client, ce qui
rend la tâche plus simple et plus rapide.

L'aide d'action JSON effectue plusieurs traitements :

• Désactive les layouts si elles sont activées.

• Optionnellement, un tableau d'options en second argument de Zend_Json::encode(). Ce


tableau d'options permet l'activation des layouts et l'encodage en utilisant Zend_Json_Expr.

$this->_helper->json($data, array('enableJsonExprFinder' => true));

• Désactive le ViewRenderer s'il est activé.

• Envoie à la réponse un en-tête 'Content-Type' à application/json.

• Par défaut, retourne immédiatement la réponse, sans attendre la fin de l'exécution de l'action.

343
Zend_Controller

Son utilisation est toute simple, appelez le depuis le gestionnaire d'aides (Broker), ou appelez
une de ses méthodes encodeJson() ou sendJson() :

class FooController extends Zend_Controller_Action


{
public function barAction()
{
// Effectue des traitements ici ...
// Envoie la réponse JSON :
$this->_helper->json($data);

// ou...
$this->_helper->json->sendJson($data);

// ou retourne la chaine json:


$json = $this->_helper->json->encodeJson($data);
}
}

Conserver les Layouts

Si vous avez besoin des layouts séparés pour les réponses JSON, pour par
exemple générer vos réponses JSON dans un contexte particulier, chaque
méthode de l'aide JSON accepte un second paramètre booléen. A TRUE, les
layouts resteront activées :

$this->_helper->json($data, true);

Optionnellement, vous pouvez fournir un tableau en tant que second paramètre.


Ce tableau peut conftenir une variété d'options, incluant l'option keepLayouts :

$this->_helper->json($data, array('keepLayouts' => true);

Activer l'encodage en utilisant Zend_Json_Expr

Zend_Json::encode() permet l'encodage des expressions JSON natives


en utilisant des objets Zend_Json_Expr. Cette option est désactivée
par défaut. Pour l'activer, fournissez la valeur booléenne TRUE à l'option
enableJsonExprFinder :

$this->_helper->json($data, array('enableJsonExprFinder' => true);

Si vous souhaitez faire ceci, vous devez un tableau en tant que second argument.
Ceci vous permet aussi de combiner avec les autres options, comme l'option
keepLayouts. Toutes ces options sont alors fournies à Zend_Json::encode().

$this->_helper->json($data, array(
'enableJsonExprFinder' => true,
'keepLayouts' => true,
));

344
Zend_Controller

8.4.6. Redirector

8.4.6.1. Introduction

L'aide Redirector vous permet d'utiliser un objet de redirection qui remplit tous les
besoins de votre application, nécessaires à une redirection vers une nouvelle URL. Il fournit
de nombreux avantages par rapport à la méthode _redirect(), comme la capacité de
préconfigurer le comportement du site dans l'objet Redirector ou d'utiliser l'interface
intégrée gotoSimple($action, $controller, $module, $params) similaire à
Zend_Controller_Action::_forward().

Redirector possède une certain nombre de méthodes qui peuvent être utilisées pour affecter
le comportement de la redirection :

• setCode() peut être utilisée pour paramétrer le code HTTP de la réponse à utiliser pendant
la redirection.

• setExit() peut être utilisée pour forcer un exit() juste après la redirection. Par défaut
ceci vaut TRUE.

• setGotoSimple() peut être utilisée pour paramétrer l'URL par défaut


à utiliser si aucune n'est fournie à gotoSimple(). Elle utilise les
API de Zend_Controller_Action::_forward() : setGotoSimple($action,
$controller = null, $module = null, array $params = array());

• setGotoRoute() peut être utilisée pour paramétrer une URL basée sur une route
enregistrée. Fournissez un tableau de paires clé/valeur et une route nommée, et elle
assemblera une URL suivant le type de la route et sa définition.

• setGotoUrl() peut être utilisée pour paramétrer l'URL par défaut à utiliser si aucune n'est
fournie à gotoUrl(). Accepte une chaîne unique correspondant à une URL.

• setPrependBase() peut être utilisée pour ajouter une chaîne au début de l'URL de
base de l'objet requête pour les URLs spécifiées avec setGotoUrl(), gotoUrl(), ou
gotoUrlAndExit().

• setUseAbsoluteUri() peut être utilisée pour forcer le Redirector à utiliser des URI
absolus pour la redirection. Quand cette option est choisie, elle utilise les valeurs de
$_SERVER['HTTP_HOST'], $_SERVER['SERVER_PORT'], et $_SERVER['HTTPS'] pour
former un URI complet à partir de l'URL spécifiée par une des méthodes de redirection.
Cette option est inactive par défaut, mais pourra être activée par défaut dans les prochaines
releases.

De plus, il y a une variété de méthodes dans le Redirector pour réaliser les redirections
actuelles :

• gotoSimple() utilise setGotoSimple() (API de type _forward()) pour construire


une URL et réaliser une redirection.

• gotoRoute() utilise setGotoRoute() (assemblage de route) pour construire une URL


et réaliser une redirection.

• gotoUrl() utilise setGotoUrl() (URL sous forme de chaîne) pour construire une
URL et réaliser une redirection.

345
Zend_Controller

Enfin, vous pouvez déterminer l'URL de la redirection courante à tout moment en utilisant
getRedirectUrl().

8.4.6.2. Exemples d'utilisation basique

Exemple 93. Options de réglage

Cet exemple surcharge de multiples options, incluant le réglage du code de statut HTTP à
utiliser dans la redirection ("303"), le retrait du exit par défaut après la redirection, et la
définition d'une URL par défaut à utiliser lors d'une redirection.

class SomeController extends Zend_Controller_Action


{
/**
* Redirector - défini pour l'auto-complétion
*
* @var Zend_Controller_Action_Helper_Redirector
*/
protected $_redirector = null;

public function init()


{
$this->_redirector = $this->_helper->getHelper('Redirector');

// Régle les options par défaut pour le redirector


// Puisque l'objet est enregistré dans le gestionnaire d'aide,
// ceci sera effectif pour toutes les actions réalisées après
// ce point
$this->_redirector->setCode(303)
->setExit(false)
->setGotoSimple("this-action", "some-controller");
}

public function myAction()


{
/* Faire quelquechose */

// Redirige vers une URL enregistrée précédemment,


// et force une sortie pour finir
$this->_redirector->redirectAndExit();
return; // jamais atteint
}
}

346
Zend_Controller

Exemple 94. Utiliser les valeurs par défaut

Cet exemple suppose que vous utilisez les paramètres par défaut, ce qui inclut que toute
redirection sera suivie d'un exit() immédiat.

// EXEMPLE ALTERNATIF
class AlternativeController extends Zend_Controller_Action
{
/**
* Redirector - défini pour l'auto-complétion
*
* @var Zend_Controller_Action_Helper_Redirector
*/
protected $_redirector = null;

public function init()


{
$this->_redirector = $this->_helper->getHelper('Redirector');
}

public function myAction()


{
/* Faire quelquechose */

$url = '/my-controller/my-action/param1/test/param2/test2';
$this->_redirector->gotoUrl($url);
return;
// jamais atteint puisque les paramètres par défaut
// sont à goto et exit
}
}

347
Zend_Controller

Exemple 95. Utilisation de l'API _forward() de goto()

L'API de gotoSimple() imite celle de Zend_Controller_Action::_forward(). La


différence principale est qu'elle construit une URL à partir des paramètres fournis, et du
format de route par défaut :module/:controller/:action/* du routeur. Il réalise alors
une redirection au lieu d'enchaîner l'action.

class ForwardController extends Zend_Controller_Action


{
/**
* Redirector - défini pour l'auto-complétion
*
* @var Zend_Controller_Action_Helper_Redirector
*/
protected $_redirector = null;

public function init()


{
$this->_redirector = $this->_helper->getHelper('Redirector');
}

public function myAction()


{
/* Faire quelquechose */

// Redirige vers 'my-action' de 'my-controller' dans le module


// courant en utilisant les paramètres :
// param1 => test et param2 => test2
$this->_redirector->gotoSimple('my-action',
'my-controller',
null,
array('param1' => 'test',
'param2' => 'test2'));
}
}

348
Zend_Controller

Exemple 96. Utilisation de l'assemblage de la route avec gotoRoute()

L'exemple suivant utilise la méthode assemble() du routeurpour créer une URL basée
sur un tableau associatif de paramètres fournis. Il suppose que la route suivante a été
enregistrée :

$route = new Zend_Controller_Router_Route(


'blog/:year/:month/:day/:id',
array('controller' => 'archive',
'module' => 'blog',
'action' => 'view')
);
$router->addRoute('blogArchive', $route);

En donnant un tableau avec l'année réglée à 2006, le mois à 4, le jour à 24 et l'ID à 42, il
construira l'URL /blog/2006/4/24/42.

class BlogAdminController extends Zend_Controller_Action


{
/**
* Redirector - défini pour l'auto-complétion
*
* @var Zend_Controller_Action_Helper_Redirector
*/
protected $_redirector = null;

public function init()


{
$this->_redirector = $this->_helper->getHelper('Redirector');
}

public function returnAction()


{
/* Faire quelquechose */

// Redirige vers les archives de blog. Construit l'URL suivante:


// /blog/2006/4/24/42
$this->_redirector->gotoRoute(
array('year' => 2006, 'month' => 4, 'day' => 24, 'id' => 42),
'blogArchive'
);
}
}

8.4.7. ViewRenderer
8.4.7.1. Introduction

L'aide ViewRenderer apporte les comportements suivants :

• Élimine le besoin d'instancier un objet de vue dans ses contrôleurs. Ceci devient automatique.

• Configure automatiquement les chemins vers les scripts de vue, les aides, et les filtres, en
se basant sur le module actuel et associe le nom du module comme préfixe de classe pour
les aides et les filtres.

• Créer un objet de vue général accessible pour tous les contrôleurs et donc pour toutes les
actions disptachées.

349
Zend_Controller

• Autorise le développeur à personnaliser les options de rendu de la vue.

• Donne la possibilité de rendre automatiquement un script de vue.

• Donne accès aux paramètres configurant le chemin de base (base path) et le chemin des
scripts (script path), de la vue.

Su vous utilisez _forward(), redirect(), ou render() manuellement, le


rendu automatique sera annulé car ViewRenderer saura que vous prenez la
main.

Le ViewRenderer est activé par défaut dans le


contrôleur frontal. Pour le désactiver, utilisez le
paramètre noViewRenderer ($front->setParam('noViewRenderer',
true)) ou retirez l'objet du gestionnaire d'aides
(Zend_Controller_Action_HelperBroker::removeHelper('viewRenderer')).

Si vous voulez modifier un paramètre du ViewRenderer avant la distribution du


contrôleur frontal, il existe deux moyens :

• Instanciez et enregistrez votre propre objet ViewRenderer et passez le au


gestionnaire d'aides :

$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer();


$viewRenderer->setView($view)
->setViewSuffix('php');
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);

• Initialisez et/ou récupérez l'objet ViewRenderer via le gestionnaire d'aides :

$viewRenderer =
Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$viewRenderer->setView($view)
->setViewSuffix('php');

8.4.7.2. API

L'usage le plus banal consiste à instancier et passer l'objet ViewRenderer au gestionnaire


d'aides. La manière la plus simple est d'utiliser la méthode statique getStaticHelper() du
gestionnaire, qui s'occupe de tout ceci en une passe :

Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');

La première action demandée instancie ou récupère l'objet de vue. A chaque instanciation de


contrôleur, la méthode init() de l'objet ViewRenderer est appelée. Elle va configurer la vue
et appeler addScriptPath() avec un chemin relatif au dossier courant. Ceci a pour effet de
"namespacer" toutes les aides et les filtres de vue pour le module en cours.

A chaque postDispatch() d'action, render() est appelée.

Voici un exemple :

// Bar controller , module foo :

350
Zend_Controller

class Foo_BarController extends Zend_Controller_Action


{
// Rend bar/index.phtml par défaut; rien à faire c'est automatique
public function indexAction()
{
}

// Rend bar/populate.phtml avec une variable 'foo' à la valeur 'bar'.


// l'objet de vue est défini dans le preDispatch(), il est donc
// accessible.
public function populateAction()
{
$this->view->foo = 'bar';
}
}

...

// Dans un des scripts de vue :


$this->foo(); // appelle Foo_View_Helper_Foo::foo()

Le ViewRenderer définit de même des accesseurs pour configurer la vue qu'il encapsule :

• setView($view) Passage de l'objet de vue. Il devient accessible comme une propriété


publique de l'objet : $view.

• setNeverRender($flag = true) peut être utilisée pour désactiver le rendu


automatique de la vue dans tous les contrôleurs. postDispatch() est alors court-circuitée.
getNeverRender() retourne ce paramètre.

• setNoRender($flag = true) peut être utilisée pour désactiver le rendu automatique


de la vue dans le contrôleur actuel. postDispatch() est alors court-circuitée, mais
preDispatch() réactive le paramètre pour l'action suivante. getNoRender() retourne
cette option.

• setNoController($flag = true) est utilisée pour spécifier à render() de ne pas


chercher le script de vue dans le sous répertoire après le contrôleur (correspondant à l'action).
Par défaut, cette recherche est effectuée. getNoController() retourne ce paramètre.

• setNeverController($flag = true) fonctionne de manière similaire à


setNoController(), mais pour tous les contrôleurs.getNeverController() est l'autre
accesseur.

• setScriptAction($name) peut être utilisée pour spécifier le script de vue d'une action
à rendre. $name doit être le nom de l'action sans le suffixe (et sans le nom du contrôleur
sauf si noController a été activé). Si vous n'utilisez pas cette méthode elle cherchera
le script de vue correspondant au nom de l'action en cours (issue de l'objet de requête).
getScriptAction() retourne la valeur actuelle de ce paramètre.

• setResponseSegment($name) dit dans quel segment de la réponse rendre le script. Par


défaut, la vue est rendue dans le segment par défaut. getResponseSegment() retourne
cette valeur.

• initView($path, $prefix, $options) doit être appelée pour configurer la vue : son
"base path", le préfixe de classe pour les filtres et aides, et des options matérialisées par :
neverRender, noRender, noController, scriptAction, et responseSegment.

351
Zend_Controller

• setRender($action = null, $name = null, $noController = false) vous


permet de spécifier les paramètres scriptAction, responseSegment, et noController
en une fois. direct() est un alias qui permet un appel rapide depuis le contrôleur :

// Rend 'foo' au lieu du script correspondant à l'action courante


$this->_helper->viewRenderer('foo');

// rend form.phtml dans le segment 'html' de la réponse sans utiliser le


// sous repertoire contrôleur pour chercher le script de vue :
$this->_helper->viewRenderer('form', 'html', true);

setRender() et direct() ne rendent pas un script de vue à proprement


parler, mais elles notifient au postDispatch() de le faire.

Le constructeur de ViewRenderer accepte aussi un objet de vue et un tableau d'options, de


la même manière que initView() :

$view = new Zend_View(array('encoding' => 'UTF-8'));


$options = array('noController' => true, 'neverRender' => true);
$viewRenderer =
new Zend_Controller_Action_Helper_ViewRenderer($view, $options);

Il est aussi possible de personnaliser les chemins utilisés pour déterminer le base path (chemin
de base) de la vue ainsi que le script path (chemin vers les scripts de vue). Des méthodes le
permettent, utilisez les options suivantes avec :

• :moduleDir représente le module courant (par convention le dossier parent au dossier


contrôleur).

• :module pointe vers le module actuel.

• :controller pointe vers le contrôleur actuel.

• :action représente l'action actuellement traitée.

• :suffix est utilisée pour le suffixe du script de vue. setViewSuffix() permet aussi de
le modifier.

Toutes ces options s'utilisent avec les méthodes ci-après :

• setViewBasePathSpec($spec) vous permet de changer le dossier donnant accès aux


dossiers de la vue : le base path. Par défaut il s'agit de :moduleDir/views. L'accesseur de
récupération est getViewBasePathSpec().

• setViewScriptPathSpec($spec) : une fois dans le base path, le rendu cherche le script


de vue dans le script path, que cette méthode permet de définir. La valeur par défaut est
:controller/:action.:suffix et l'autre accesseur est getViewScriptPathSpec().

• setViewScriptPathNoControllerSpec($spec) Une fois dans le base path, si


noController est activé, le rendu cherche le script de vue dans le chemin que cette
méthode permet de définir. La valeur par défaut est :action.:suffix et l'autre accesseur
est getViewScriptPathNoControllerSpec().

ViewRenderer utilise un inflecteur : Zend_Filter_Inflector, pour résoudre les options de chemin,


en chemins réels. Pour une personnalisation maximale, vous pouvez interagir avec cet inflecteur
à l'aide des méthodes suivantes :

352
Zend_Controller

• getInflector() retourne l'inflecteur. Si aucun n'existe, ViewRenderer en crée un avec


des options par défaut.

Par défaut, les règles de l'inflecteur sont statiques autant pour le suffixe et le répertoire module,
que pour la cible. Ceci permet au ViewRenderer de modifier ces valeurs dynamiquement.

• setInflector($inflector, $reference) peut être utilisée pour passer son propre


inflecteur à ViewRenderer. Si $reference est à TRUE, alors le suffixe, le répertoire du
module et la cible seront affectés en fonction des propriétés de ViewRenderer.

Règles de résolution par défaut

Le ViewRenderer utilise certaines règles par défaut pour chercher ses scripts
de vue, voyez plutôt :

• :module : casseMélangée et motsEnNotationCamel qui deviennent des mots


séparés par des tirets, et en minuscules. "FooBarBaz" devient "foo-bar-baz".

En interne, l'inflecteur utilise les filtres


Zend_Filter_Word_CamelCaseToDash et
Zend_Filter_StringToLower.

• :controller : casseMélangée et motsEnNotationCamel qui deviennent des


mots séparés par des tirets; les tirets bas eux, se transforment en séparateur
de dossier et tout est passé en minuscules. "FooBar" devient "foo-bar";
"FooBar_Admin" devient "foo-bar/admin".

En interne, l'inflecteur utilise les filtres


Zend_Filter_Word_CamelCaseToDash,
Zend_Filter_Word_UnderscoreToSeparator, et
Zend_Filter_StringToLower.

• :action : casseMélangée et motsEnNotationCamel qui se transforment en


mots séparés par des tirets, minuscules. Les caractères non alphanumériques
deviennent des tirets. "fooBar" devient "foo-bar"; "foo-barBaz" devient "foo-bar-
baz".

Pour ceci, l'inflecteur interne utilise les filtres


Zend_Filter_Word_CamelCaseToDash, Zend_Filter_PregReplace,
et Zend_Filter_StringToLower.

Enfin, l'API ViewRenderer vous propose aussi des méthodes pour déterminer les scripts de
vue, et rendre la vue. Celles-ci se décomposent en :

• renderScript($script, $name) va vous permettre de spécifier pleinement le script


de vue à rendre, et éventuellement un nom de segment de réponse dans lequel rendre.
ViewRenderer s'attend à un paramètre $script représentant un chemin complet vers un
script de vue, telle que la méthode de la vue render() l'attend.

Une fois rendue, la vue utilise noRender pour éviter un double rendu
automatisé.

353
Zend_Controller

Par défaut, Zend_Controller_Action::renderScript() est un proxy


vers la méthode renderScript() de ViewRenderer.

• getViewScript($action, $vars) récupère le chemin du script de vue en se basant


sur les paramètres $action et $vars. $vars peut contenir "moduleDir", "module", "controller",
"action", et "suffix"), sinon les valeurs de la requête actuelle seront utilisées.

getViewScript() utilisera viewScriptPathSpec ou


viewScriptPathNoControllerSpec selon le paramètre noController.

Les délimiteurs apparaissant dans les modules, contrôleurs ou actions seront remplacés par
des tirets ("-"). Ainsi pour un un contrôleur "foo.bar" et une action "baz:bat", il résultera un
chemin de vue "foo-bar/baz-bat.phtml".

Par défaut Zend_Controller_Action::getViewScript() est un proxy


vers la méthode getViewScript() de ViewRenderer.

• render($action, $name, $noController) a beaucoup de responsabilités : d'abord,


elle vérifie si $name ou $noController lui ont été passés, si c'est le cas, elle configure
correctement les paramètres responseSegment et noController dans le ViewRenderer.
Elle passe ensuite $action, si spécifié, à getViewScript(). Enfin, elle passe le script de
vue calculé à renderScript().

Attention aux effets secondaires avec render() : les valeurs segment de


réponse, et noController vont persister dans l'objet ViewRenderer. De plus,
noRender() va être appelée.

Par défaut, Zend_Controller_Action::render() est un proxy vers


render() de ViewRenderer.

• renderBySpec($action, $vars, $name) vous fournit le moyen de passer des


paramètres de spécification pour le dossier de script de vue. Cette méthode passe $action
et $vars à getScriptPath(), pour en déduire un chemin qu'elle envoie alors avec $name
à renderScript().

354
Zend_Controller

8.4.7.3. Exemples

Exemple 97. Usage de base

L'utilisation la plus basique consiste à initialiser ou et enregistrer un objet ViewRenderer


dans le gestionnaire d'aides (helper broker), et ensuite lui passer des variables dans vos
contrôleurs.

// Dans le fichier de démarrage :


Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');

...

// 'foo' module, contrôleur 'bar' :


class Foo_BarController extends Zend_Controller_Action
{
// Rend bar/index.phtml par défaut, rien à faire
public function indexAction()
{
}

// Rend bar/populate.phtml avec la variable 'foo' à la valeur 'bar'.


// L'objet de vue est rendu disponible en preDispatch().
public function populateAction()
{
$this->view->foo = 'bar';
}

// Ne rend rien, car on demande un nouveau jeton de distribution


public function bazAction()
{
$this->_forward('index');
}

// Ne rend rien, une redirection est demandée


public function batAction()
{
$this->_redirect('/index');
}
}

Conventions de noms : délimiteurs de mots dans les noms de


contrôleur et d'action

Si les noms de votre contrôleur ou de votre action sont


composés de plusieurs mots, le distributeur s'attend à ce qu'ils
soient séparés par des caractères bien définis, dans l'URL. Le
ViewRenderer les transforme alors en '/' pour les chemins, ou tirets
'-' pour les mots. Ainsi, un appel à /foo.bar/baz.bat distribuera
FooBarController::bazBatAction() dans FooBarController.php, et
ceci rendra foo-bar/baz-bat.phtml. Un appel à /bar_baz/baz-
bat distribuera vers Bar_BazController::bazBatAction() dans Bar/
BazController.php (notez la séparation du chemin), et rend bar/baz/baz-
bat.phtml.

355
Zend_Controller

Notez dans le second exemple, le module est celui par défaut, mais comme un
séparateur de chemin (tiret bas ou "_") est donné, alors le contrôleur distribué
devient Bar_BazController, dans Bar/BazController.php.

Exemple 98. Désactivation du rendu automatique

Il peut être nécessaire dans certains cas de désactiver manuellement le rendu automatique
de vue effectué par ViewRenderer. Par exemple, si le contrôleur doit retourner une sortie
spéciale, comme XML ou JSON. Deux options s'offrent à vous : setNeverRender()) et
setNoRender().

// Baz controller class, bar module :


class Bar_BazController extends Zend_Controller_Action
{
public function fooAction()
{
// Ne rend pas automatiquement cette action
$this->_helper->viewRenderer->setNoRender();
}
}

// Bat controller class, bar module :


class Bar_BatController extends Zend_Controller_Action
{
public function preDispatch()
{
// Ne rend plus aucune action de ce contrôleur
$this->_helper->viewRenderer->setNoRender();
}
}

Utiliser setNeverRender()), pour désactiver totalement le rendu automatique


de vue vous fera perdre un des avantages majeur de ViewRenderer.

356
Zend_Controller

Exemple 99. Choix d'un script de vue différent

Il peut arriver que vous éprouviez le besoin de rendre un script de vue différent de
celui correspondant à l'action en cours de distribution. Par exemple, un contrôleur qui
possède deux actions ajout et édition, qui sont susceptibles toutes les deux de rendre le
même script de vue. Utilisez alors setScriptAction(), setRender(), ou appelez l'aide
ViewRenderer directement :

// Bar controller class, foo module :


class Foo_BarController extends Zend_Controller_Action
{
public function addAction()
{
// Rend 'bar/form.phtml' plutôt que 'bar/add.phtml'
$this->_helper->viewRenderer('form');
}

public function editAction()


{
// Rend 'bar/form.phtml' au lieu de 'bar/edit.phtml'
$this->_helper->viewRenderer->setScriptAction('form');
}

public function processAction()


{
// un peu de validation...
if (!$valid) {
// Rend 'bar/form.phtml' à la place de 'bar/process.phtml'
$this->_helper->viewRenderer->setRender('form');
return;
}

// continue le processus...
}
}

Exemple 100. Modification de l'objet de vue

Si vous désirez modifier l'objet de vue absorbé par ViewRenderer, pour par exemple
ajouter un chemin vers des aides spécifique, ou spécifier l'encodage, vous pourriez par
exemple récupérer l'objet de vue depuis le ViewRenderer, ou dans un contrôleur.

// Bar controller class, foo module :


class Foo_BarController extends Zend_Controller_Action
{
public function preDispatch()
{
// change l'encodage de la vue
$this->view->setEncoding('UTF-8');
}

public function bazAction()


{
// Récupère l'objet de vue, et lui passe la fonction
// d'2chappement 'htmlspecialchars'
$view = $this->_helper->viewRenderer->view;
$view->setEscape('htmlspecialchars');
}
}

357
Zend_Controller

8.4.7.4. Utilisation avancée

Exemple 101. Changement des spécifications de dossier

Dans certains cas, il peut être nécessaire d'utiliser un chemin absolu, fixe. Par exemple
si vous ne donnez accès à vos graphistes qu'à un seul dossier, en utilisant un moteur de
template tel que Smarty.

Pour ceci, imaginons que le base path soit fixé à "/opt/vendor/templates", et que vous
voulez que vos scripts de vues soit référencés par ":moduleDir/:controller/:action.:suffix";
si le paramètre noController est activé, vous désirez utiliser le dossier plus haut
":action.:suffix". Enfin, vous désirez un suffixe en "tpl" :

/**
* Dans le fichier de démarrage :
*/

// Une implémentation personnalisée de la vue


$view = new ZF_Smarty();

$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view);


$viewRenderer->setViewBasePathSpec('/opt/vendor/templates')
->setViewScriptPathSpec(':module/:controller/:action.:suffix')
->setViewScriptPathNoControllerSpec(':action.:suffix')
->setViewSuffix('tpl');
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);

Exemple 102. Rendu de plusieurs scripts de vue dans une même action

Afin de rendre plusieurs scripts de vue dans une même action, appelez tout simplement
plusieurs fois render() :

class SearchController extends Zend_Controller_Action


{
public function resultsAction()
{
// Considérons $this->model comme étant un modèle valide
$this->view->results = $this->model
->find($this->_getParam('query', '');

// render() est proxiée vers ViewRenderer


// Rend d'abord un formulaire, puis un résultat
$this->render('form');
$this->render('results');
}

public function formAction()


{
// Rien : ViewRenderer rend automatiquement un script de vue
}
}

8.5. Écrire vos propres aides


Les aides d'action étendent Zend_Controller_Action_Helper_Abstract, une classe
abstraite qui fournit l'interface basique et les fonctionnalités requises par le gestionnaire d'aides.
Ceci inclue les méthodes suivantes :

• setActionController() est utilisée pour paramétrer le contrôleur d'action courant.

358
Zend_Controller

• init(), déclenchée par le gestionnaire d'aides à l'instanciation, peut être utilisée pour
déclencher l'initialisation dans l'aide ; ceci peut être pratique pour remettre dans l'état initial
quand de multiples contrôleurs utilisent la même aide dans des actions enchaînées.

• preDispatch() est déclenchée avant la distribution d'une action.

• postDispatch() est déclenchée quand une action a été distribuée - même si un plugin
preDispatch() a évité l'action. Principalement utile pour le nettoyage.

• getRequest() récupère l'objet de requête courant.

• getResponse() récupère l'objet de réponse courant.

• getName() récupère le nom de l'aide. Elle récupère la portion du nom de la classe qui suit
le dernier tiret bas ("_"), ou le nom de la classe entier sinon. Pour exemple, si la classe est
nommée Zend_Controller_Action_Helper_Redirector, elle retourne Redirector ;
une classe nommée FooMessage retournera FooMessage.

Vous pouvez optionnellement inclure une méthode direct() dans votre classe d'aide. Si
définie, ceci vous permet de traiter l'aide comme une méthode du gestionnaire, dans le but de
faciliter un usage unique de l'aide. Pour exemple, l'aide Redirectordéfinit direct() comme un
alias de goto(), vous permettant d'utiliser l'aide comme ceci :

// Redirige vers /blog/view/item/id/42


$this->_helper->redirector('item', 'view', 'blog', array('id' => 42));

En interne, la méthode __call() du gestionnaire d'aides cherche une aide nommée


redirector, puis vérifie si cette aide possède une méthode direct(), et enfin appelle cette
méthode avec les arguments fournis.

Une fois que vous avez créé vos propres classes d'aide, vous pouvez en fournir l'accès comme
décrit dans les sections ci-dessus.

9. Objet de réponse
9.1. Utilisation
L'objet de réponse équilibre la balance du modèle MVC avec l'objet de requête. Son
but est de collecter du contenu et des en-têtes, afin d'être rendue. De plus, le
contrôleur frontal passe les exceptions qu'il a rencontré à l'objet de réponse, vous
offrant une possibilité élégante de les gérer. Ce comportement peut être changé avec
Zend_Controller_Front::throwExceptions(true) :

$front->throwExceptions(true);

Pour rendre toute la réponse : corps et en-têtes, utilisez sendResponse().

$response->sendResponse();

Par défaut le contrôleur frontal appelle sendResponse() lorsque la


distribution est terminée. Vous pouvez changer ce comportement avec
Zend_Controller_Front::returnResponse(true) :

$front->returnResponse(true);
$response = $front->dispatch();

359
Zend_Controller

// opérations, comme une historisation...


// et rendu de la réponse:
$response->sendResponse();

Vous ne devriez pas afficher du contenu directement dans un contrôleur. Empiler plutôt les
affichages dans l'objet de réponse :

// Dans une action d'un contrôleur:


$this->getResponse()
->setHeader('Content-Type', 'text/html')
->appendBody($content);

Grâce à cela, tous les en-têtes sont envoyés d'un coup, juste avant l'affichage du contenu.

Si vous utilisez des vues dans vos action, vous n'avez pas besoin d'ajouter le
rendu de la vue dans la réponse, car Zend_Controller_Action::render()
le fait par défaut.

Si une exception est ajoutée par le contrôleur frontal à la réponse, utilisez isException() pour
vérifier ceci, et récupérez les exceptions avec getException(). Vous pourriez par exemple
créer un objet de réponse d'erreur, comme un 404, et journaliser l'exception, etc.

Pour prendre la main sur l'objet de réponse, demandez le au contrôleur frontal via un accesseur,
ou commandez lui de vous retourner la celle-ci lors après la distribution.

// récupère la réponse après distribution et affichage:


$front->dispatch();
$response = $front->getResponse();
if ($response->isException()) {
// log, mail, etc...
}

// Demande au contrôleur frontal de ne pas afficher, mais retourner :


$front->returnResponse(true);
$response = $front->dispatch();

// du code ici

// enfin, affichage:
$response->sendResponse();

Par défaut, les messages d'exceptions ne sont pas affichés. Utilisez renderExceptions()
si vous le voulez. Aussi, vous pouvez activer leur rendu grâce à
Zend_Controller_Front::throwExceptions() :

$response->renderExceptions(true);
$front->dispatch($request, $response);

// ou:
$front->returnResponse(true);
$response = $front->dispatch();
$response->renderExceptions();
$response->sendResponse();

// ou:

360
Zend_Controller

$front->throwExceptions(true);
$front->dispatch();

9.2. Manipulation des en-têtes


Comme nous l'avons vu, un des rôles de l'objet de réponse est de gérer les en-têtes HTTP. Une
variété de méthodes permet de contrôler cette gestion :

• canSendHeaders($throw = false) est utilisée pour déterminer si les en-têtes n'ont pas
déjà été envoyés. Si le paramètre optionnel $throw est à TRUE, alors une exception sera
envoyée si c'est le cas. L'attribut headersSentThrowsException permet aussi de gérer
ce comportement.

• setHeader($name, $value, $replace = false) est utilisée pour affecter un en-tête


unique. Par défaut, il n'écrase un éventuel précédent du même nom, sauf si $replace est
mis à TRUE.

Avant d'affecter un en-tête, cette méthode utilise canSendHeaders() pour voir si à ce point
l'en-tête peut être envoyé.

• setRedirect($url, $code = 302) envoie un en-tête HTTP Location indiquant une


redirection. Si un code de statut est passé, il sera utilisé.

En interne, cette méthode appelle setHeader() avec $replace à TRUE, pour s'assurer de
l'unicité de cet en-tête.

• getHeaders() retourne un tableau contenant tous les en-têtes. Chaque élément est un
tableau "nom" 'valeur.

• clearHeaders() efface tous les en-têtes enregistrés.

• setRawHeader() s'utilise pour affecter un en-tête brut, n'utilisant pas la syntaxe clé/valeur,
comme un statut.

• getRawHeaders() retourne tous les en-têtes bruts enregistrés.

• clearRawHeaders() efface tous les en-têtes bruts enregistrés.

• clearAllHeaders() efface tous les en-têtes bruts et réguliers enregistrés.

De plus, des accesseurs spéciaux sont disponibles pour manipuler le code de réponse HTTP :
setHttpResponseCode() et getHttpResponseCode().

9.3. Segments nommés


L'objet de réponse propose une fragmentation par segments. Ceci permet de séparer le corps
de la réponse dans plusieurs segments réceptacles, que vous pouvez afficher dans un ordre
précis. En interne, il s'agit d'un tableau namespacé qui dispose de méthodes de manipulation.

Par exemple, vous pourriez utiliser l'évènement preDispatch() pour rajouter un bandeau de
header au corps de la réponse, et l'évènement postDispatch() pour en ajouter un bandeau
de footer :

// Considérons ce plugin comme étant enregistré


// auprès du contrôleur frontal
class MyPlugin extends Zend_Controller_Plugin_Abstract
{

361
Zend_Controller

public function preDispatch(Zend_Controller_Request_Abstract $request)


{
$response = $this->getResponse();
$view = new Zend_View();
$view->setBasePath('../views/scripts');

$response->prepend('header', $view->render('header.phtml'));
}

public function postDispatch(Zend_Controller_Request_Abstract $request)


{
$response = $this->getResponse();
$view = new Zend_View();
$view->setBasePath('../views/scripts');

$response->append('footer', $view->render('footer.phtml'));
}
}

// un contrôleur d'action
class MyController extends Zend_Controller_Action
{
public function fooAction()
{
$this->render();
}
}

Un appel à /my/foo dans ce cas là, générera un objet de réponse ressemblant à ceci :

array(
'header' => ..., // contenu du segment header
'default' => ..., // corps, contenu de MyController::fooAction()
'footer' => ... // contenu du segment footer
);

Lorsque ceci est rendu, ça l'est dans l'ordre dans lequel les segments sont rangés dans la
réponse.

Voici quelques méthodes permettant de manipuler les segments de la réponse :

• setBody() et appendBody() effacent et écrivent, ou rajoutent un contenu à un segment


qu'on leur indique en deuxième paramètre ($name). Si celui-ci n'existe pas, il sera crée en fin
de pile. Si le paramètre segment n'est pas défini, alors le segment "default"est utilisé.

• prepend($name, $content) va créer un segment appelé $name et le placé au début du


tableau. Si le segment existe, il sera écrasé.

• append($name, $content) va créer un segment appelé $name et le placer à la fin du


tableau. Si le segment existe, il sera écrasé.

• insert($name, $content, $parent = null, $before = false) va créer un


segment appelé $name. Si $parent est renseigné, le nouveau segment sera placé avant ou
après le segment $parent, ceci dépendant de la valeur de $before. Si le segment existe,
il sera écrasé.

• clearBody($name = null) va vider le contenu du segment qui lui est passé en paramètre
via $name. Par défaut, il vide tout le tableau (détruit tous les segments).

362
Zend_Controller

• getBody($spec = false) retourne le contenu du segment $spec. Si $spec vaut FALSE,


il retourne le contenu de tous les segments. Si TRUE, c'est le tableau de segments qui est
retourné.

9.4. Manipulation des exceptions dans l'objet de réponse


Comme déjà mentionné, par défaut, les exceptions rencontrées durant le processus MVC de
distribution, sont ajoutées à l'objet de réponse. Elles le sont dans une pile, ce qui vous permet de
toutes les garder -- les exceptions d'application, les exceptions de distribution, les exceptions de
plugin -- etc... Si vous voulez manipuler finement celles-ci, voyez plutôt les méthodes ci-après :

• setException(Exception $e) enregistre une exception.

• isException() est utilisée pour déterminer si il existe au moins une exception.

• getException() retourne toutes les exceptions sous forme de tableau.

• hasExceptionOfType($type) sert à déterminer si des exceptions d'une classe spécifique


existent.

• hasExceptionOfMessage($message) sert à déterminer si des exceptions ayant un


message spécifique existent.

• hasExceptionOfCode($code) sert à déterminer si des exceptions ayant un code


spécifique existent.

• getExceptionByType($type) retourne toutes les exceptions d'une classe spécifique. Un


tableau est retourné, ou FALSE si aucun exception ne correspond

• getExceptionByMessage($message) retourne toutes les exceptions ayant un message


spécifique. Un tableau est retourné, ou FALSE si aucun exception ne correspond

• getExceptionByCode($code) retourne toutes les exceptions ayant un code spécifique.


Un tableau est retourné, ou FALSE si aucun exception ne correspond.

• renderExceptions($flag) vous permet de définir si les exceptions doivent être envoyées


lorsque la réponse est rendue.

9.5. Dériver l'objet de réponse


L'objet de réponse sert à collecter les en-têtes HTTP de la réponse, ainsi que son contenu,
depuis le système MVC mais aussi de l'afficher au client. De plus, l'objet collecte les exceptions
et permet de les gérer, de les retourner, ou de les garder sous silence.

La classe de base est Zend_Controller_Response_Abstract, et toute dérivation devra


en hériter directement ou indirectement. Les méthodes qu'elle propose ont été vues dans les
sections précédentes.

Vous pouvez dériver l'objet de réponse pour plusieurs raisons, incluant la volonté de modifier le
retour de la sortie, pour ne pas envoyer d'en-têtes dans un environnement de requête CLI ou
PHP-GTK, la gestion de templates, etc.

10. Plugins
10.1. Introduction
L'architecture MVC de Zend Framework propose l'injection de plugins de code, qui vont intervenir
à différents niveaux dans le processus complet. Le contrôleur frontal enregistre des plugins, et

363
Zend_Controller

utilise un gestionnaire de plugins ("plugin broker"), qui va se charger de faire intervenir chaque
plugin, à chacun des instants clés à votre disposition.

Les instants clés sont des méthodes événementielles définies dans la classe abstraite
Zend_Controller_Plugin_Abstract, dont tous les plugins doivent hériter :

• routeStartup() est appelée avant que Zend_Controller_Front n'appelle le routeur


pour évaluer ses routes et remplir la requête.

• routeShutdown() est appelée après que le routeur aie fini de router la requête.

• dispatchLoopStartup() est appelée juste avant que Zend_Controller_Front n'entre


en boucle de distribution.

• preDispatch() est appelée avant qu'une action ne soit distribuée par le distributeur.
Cette méthode permet un filtrage ou un proxy. En jouant sur la requête à
ce niveau là, vous êtes capable de changer le processus, et en vous aidant
de Zend_Controller_Request_Abstract::setDispatched(true)), vous supprimez
l'ordre de distribution de celle-ci.

• postDispatch() est appelée après qu'une action n'ait été distribuée par le distributeur.
Cette méthode permet un filtrage ou un proxy. En jouant sur la requête à ce
niveau là, vous êtes capable de changer le processus, et en vous aidant de
Zend_Controller_Request_Abstract::setDispatched(false)), vous ordonnez
une redistribution de celle-ci.

• dispatchLoopShutdown() est appelée par Zend_Controller_Front lorsque celui-ci


sort de la boucle de distribution.

10.2. Écrire des plugins


Tous les plugins doivent hériter de Zend_Controller_Plugin_Abstract:

class MyPlugin extends Zend_Controller_Plugin_Abstract


{
// ...
}

Comme aucune des méthodes de Zend_Controller_Plugin_Abstract n'est abstraite,


vous n'êtes pas obligé dans vos plugins de toutes les définir. Vous agissez aux endroits que
vous voulez.

Zend_Controller_Plugin_Abstract vous donne aussi accès aux objets de réponse et


de requête, dans vos plugins.getRequest() et getResponse() sont là pour ça. Cependant,
l'objet de requête est de toute façon passé en paramètre à vos méthodes. Veillez à le récupérer
dans la définition de vos méthodes sinon une erreur E_STRICT sera levée.

10.3. Utilisation des plugins


Les plugins sont enregistrés avec Zend_Controller_Front::registerPlugin(), et
peuvent l'être n'importe quand. Voici un exemple :

class MyPlugin extends Zend_Controller_Plugin_Abstract


{
public function routeStartup(
Zend_Controller_Request_Abstract $request)
{

364
Zend_Controller

$this->getResponse()
->appendBody("<p>routeStartup() appelée</p>\n");
}

public function routeShutdown(


Zend_Controller_Request_Abstract $request)
{
$this->getResponse()
->appendBody("<p>routeShutdown() appelée</p>\n");
}

public function dispatchLoopStartup(


Zend_Controller_Request_Abstract $request)
{
$this->getResponse()
->appendBody("<p>dispatchLoopStartup() appelée</p>\n");
}

public function preDispatch(


Zend_Controller_Request_Abstract $request)
{
$this->getResponse()
->appendBody("<p>preDispatch() appelée</p>\n");
}

public function postDispatch(


Zend_Controller_Request_Abstract $request)
{
$this->getResponse()
->appendBody("<p>postDispatch() appelée</p>\n");
}

public function dispatchLoopShutdown()


{
$this->getResponse()
->appendBody("<p>dispatchLoopShutdown() appelée</p>\n");
}
}

$front = Zend_Controller_Front::getInstance();
$front->setControllerDirectory('/path/to/controllers')
->setRouter(new Zend_Controller_Router_Rewrite())
->registerPlugin(new MyPlugin());
$front->dispatch();

Si aucune autre action ne génère une sortie (typiquement, un rendu de vue), alors le résultat
suivant devrait s'afficher :

<p>routeStartup() appelée</p>

<p>routeShutdown() appelée</p>

<p>dispatchLoopStartup() appelée</p>

<p>preDispatch() appelée</p>

<p>postDispatch() appelée</p>

<p>dispatchLoopShutdown() appelée</p>

365
Zend_Controller

Enregistrez vos plugins où vous voulez dans votre code, mais faites attention de
ne pas leur faire sauter de méthodes, selon l'endroit où vous les enregistrez.

10.4. Récupération et manipulations des plugins


Il peut arriver que vous ayez besoin de récupérer des plugins, ou d'en supprimer. Les méthodes
suivantes vous seront alors utiles :

• getPlugin($class) vous retourne l'objet de plugin correspondant à la chaîne passée en


paramètre. Si il n'y a pas de correspondance, FALSE est retourné. Un tableau est retourné s'il
y a plusieurs plugins de cette classe.

• getPlugins() retourne toute la pile de plugins.

• unregisterPlugin($plugin) supprime un plugin du processus. Passez un nom de


classe, et tous les plugins de cette classe seront alors enlevés de la pile. Vous pouvez aussi
passer un objet.

10.5. Plugins inclus dans Zend Framework


Zend Framework possède des plugins dans sa distribution :

10.5.1. ActionStack
Le plugin ActionStack vous permet de gérer une pile de requêtes en opérant en
postDispatch. Si un forward (un appel à une autre action) est détecté, alors le plugin n'agira
pas. Dans le cas contraire cependant, sa pile est analysée (en ordre LIFO : dernier empilé,
premier dépilé) et une nouvelle action est distribuée. Ce plugin est commandé par l'aide d'action
du même nom ActionStack

Vous pouvez récupérer ce plugin grâce à


Zend_Controller_Front::getPlugin('Zend_Controller_Plugin_ActionStack').
Une fois l'objet retourné, voici les méthodes qui y sont proposées :

• getRegistry() et setRegistry(). En interne, ActionStack utilise Zend_Registry


pour stocker sa pile. Vous pouvez manipuler l'instance du registre utilisée grâce à ces
méthodes.

• getRegistryKey() et setRegistryKey(). Ces méthodes vous donnent accès à la clé


utilisée dans le registre, pour stocker la pile d'actions de ActionStack. Par défaut, il s'agit de
Zend_Controller_Plugin_ActionStack.

• getStack() retourne la pile (entière) d'actions.

• pushStack() et popStack() contrôlent la pile. popStack() supprime l'action la plus haute


dans la pile (l'action à venir), et vous la retourne. pushStack() rajoute une action sur la pile.
Vous devez la passer en paramètre donc.

La méthode forward(), elle, est directe : elle attend un objet de requête qu'elle passe
immédiatement au contrôleur frontal en redemandant un jeton de distribution.

10.5.2. Zend_Controller_Plugin_ErrorHandler
Zend_Controller_Plugin_ErrorHandler est un plugin intégré par défaut pour gérer les
exceptions levées par votre application, il sert à gérer les exceptions envoyées par l'application,

366
Zend_Controller

en particulier celles concernant des contrôleurs ou des actions manquants. C'est une manière
rejoignant la section Exceptions MVC.

Les principaux objectifs de ce plugin sont :

• Intercepter les exceptions envoyées si aucune route ne correspond

• Intercepter les exceptions envoyées si un contrôleur ou une action ne peuvent être trouvés

• Intercepte les exceptions envoyées dans les contrôleurs

Globalement, ErrorHandler sert à gérer les erreurs HTTP 404 ou 500. Attention, le plugin n'est
pas destiné à intervenir sur les exceptions envoyées dans d'autres plugins. Des effets de bords
peuvent apparaître, veillez à les gérer.

Par défaut, Zend_Controller_Plugin_ErrorHandler redirige vers


ErrorController::errorAction() dans le module par défaut. Vous pouvez passer
d'autres valeurs via les accesseurs du plugin :

• setErrorHandlerModule() définit le module à utiliser.

• setErrorHandlerController() définit le contrôleur à utiliser.

• setErrorHandlerAction() définit l'action à utiliser.

• setErrorHandler() est un raccourci des trois précédantes. Passez un tableau avec les
clés "module", "controller", or "action", et leurs valeurs appropriées.

Ce comportement fonctionne aussi avec le constructeur du plugin. Celui-ci agit comme un proxy
vers setErrorHandler().

Zend_Controller_Plugin_ErrorHandler agit en postDispatch() et analyse l'objet de


réponseà la recherche d'éventuelles exceptions. Si il y en a, alors le plugin modifie la requête
pour distribuer le contrôleur et l'action d'erreur.

Si une exception arrive lorsque le plugin agit, alors celui-ci ordonne au contrôleur frontal de
renvoyer l'exception, et relance la dernière exception enregistrée dans l'objet de réponse.

10.5.2.1. Utilisation de ErrorHandler pour gérer les erreurs 404

Comme ErrorHandler capture les exceptions relatives à un problème de contrôleur ou action


manquants, vous pouvez donc l'utiliser comme un gestionnaire d'erreurs 404. Pour cela, il faut
analyser le type d'exception ayant mené à l'erreur.

Les exceptions capturées sont enregistrées en tant que paramètre d'action.


Zend_Controller_Action::_getParam('error_handler'):

class ErrorController extends Zend_Controller_Action


{
public function errorAction()
{
$errors = $this->_getParam('error_handler');
}
}

Une fois que vous possédez l'objet contenant l'exception, inspectez son type avec $errors-
>type;. Des constantes sont à votre disposition :

• Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE, indique
qu'aucune route correspondante n'a été trouvée.

367
Zend_Controller

• Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER, indique un
contrôleur non trouvé.

• Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION, indique qu'une


action est absente.

• Zend_Controller_Plugin_ErrorHandler::EXCEPTION_OTHER, indique une autre


exception.

Les trois premiers types pourraient mener à une erreur 404 :

class ErrorController extends Zend_Controller_Action


{
public function errorAction()
{
$errors = $this->_getParam('error_handler');

switch ($errors->type) {
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
// erreur 404 -- contrôleur ou action introuvable
$this->getResponse()->setRawHeader('HTTP/1.1 404 Not Found');

// ... ici, de l'affichage (du rendu)


break;
default:
// erreur applicative; affiche une page d'erreur,
// mais sans changer le code de retour HTTP
break;
}
}
}

Enfin, il est possible de récupérer l'exception ayant menée au contrôleur d'erreur. Ceci afin de
l'analyser. L'attribut exception de l'objet error_handler le permet :

public function errorAction()


{
$errors = $this->_getParam('error_handler');

switch ($errors->type) {
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
// erreur 404 -- contrôleur ou action introuvable
$this->getResponse()->setRawHeader('HTTP/1.1 404 Not Found');

// ... ici, de l'affichage (du rendu)


break;
default:
// erreur applicative; affiche une page d'erreur,
// mais sans changer le code de retour HTTP

// ...

// Sauve l'exception en log:


$exception = $errors->exception;
$log =

368
Zend_Controller

new Zend_Log(
new Zend_Log_Writer_Stream(
'/tmp/applicationException.log')
);
$log->debug($exception->getMessage()
. "\n"
. $exception->getTraceAsString());
break;
}
}

10.5.2.2. Gestion des rendus précédants de la réponse

Si vous décomposez vos processus en plusieurs actions ou plusieurs appels à render(), il est
possible que la réponse contienne déjà des éléments. Ceci peut introduire un mélange entre le
rendu attendu et le contenu de l'erreur.

Si vous désirez rendre votre contrôleur d'erreur dans ce contenu, alors il n'y a rien à faire de
spécial. En revanche, il peut aussi être judicieux de vider totalement la réponse afin de rendre
le contrôleur d'erreurs. Procédez alors comme suit :

$this->getResponse()->clearBody();

10.5.2.3. Exemples d'utilisation

Exemple 103. Utilisation standard et désactivation

$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new Zend_Controller_Plugin_ErrorHandler());

Exemple 104. Paramétrage du plugin

$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new Zend_Controller_Plugin_ErrorHandler(array(
'module' => 'mystuff',
'controller' => 'static',
'action' => 'error'
)));

Exemple 105. Utilisation des accesseurs

$plugin = new Zend_Controller_Plugin_ErrorHandler();


$plugin->setErrorHandlerModule('mystuff')
->setErrorHandlerController('static')
->setErrorHandlerAction('error');

$front = Zend_Controller_Front::getInstance();
$front->registerPlugin($plugin);

10.5.2.4. Exemple de contrôleur d'erreurs

Pour utiliser le plugin de gestion d'erreurs, un contrôleur d'erreurs est requis. En voici un
exemple :

class ErrorController extends Zend_Controller_Action


{
public function errorAction()

369
Zend_Controller

{
$errors = $this->_getParam('error_handler');

switch ($errors->type) {
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
// 404 error -- controller or action not found
$this->getResponse()->setRawHeader('HTTP/1.1 404 Not Found');

$content =<<<EOH
<h1>Erreur !</h1>
<p>Page introuvable.</p>
EOH;
break;
default:
// application error
$content =<<<EOH
<h1>Erreur !</h1>
<p>Une erreur innatendue est survenue</p>
EOH;
break;
}

// Vide le contenu de la réponse


$this->getResponse()->clearBody();

$this->view->content = $content;
}
}

10.5.3. Zend_Controller_Plugin_PutHandler
Zend_Controller_Plugin_PutHandler fournit un plugin intégré pour la gestion du corps
des requêtes PUT en tant que paramètres de requête, tout comme le corps d'une requête
POST. Il va inspecter la requête et, s'il s'agit d'une requête PUT, va utiliser la fonction parse_str
pour découper le contenu brut de la requête PUT en un tableau de paramètres qui est ensuite
enregistré dans l'objet de requête. Par exemple :

PUT /notes/5.xml HTTP/1.1

title=Hello&body=World

Pour recevoir les paramètres "title" et "body" comme des paramètres de requête habituels, vous
devez enregistrer le plugin :

$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new Zend_Controller_Plugin_PutHandler());

Ensuite vous pouvez accéder aux paramètres du corps de la requête PUT par leur nom à
l'intérieur de votre contrôleur :

...
public function putAction()
{
$title = $this->getRequest()->getParam('title'); // $title = "Hello"
$body = $this->getRequest()->getParam('body'); // $body = "World"
}

370
Zend_Controller

...

11. Utilisation de conventions de dossiers modulaires


11.1. Introduction
Les conventions de dossiers vous permettent de séparer les différentes applications MVC dans
des unités isolées et les réutiliser dans le contrôleur frontal. Voici une illustration :

docroot/
index.php
application/
default/
controllers/
IndexController.php
FooController.php
models/
views/
scripts/
index/
foo/
helpers/
filters/
blog/
controllers/
IndexController.php
models/
views/
scripts/
index/
helpers/
filters/
news/
controllers/
IndexController.php
ListController.php
models/
views/
scripts/
index/
list/
helpers/
filters/

Ci dessus, le nom du module est utilisé comme préfixe pour les contrôleurs qu'il
possède. Il y a donc trois contrôleurs : "Blog_IndexController", "News_IndexController",
et "News_ListController". Deux contrôleurs dans le module par défaut sont aussi définis,
"IndexController" et "FooController". Ceux-ci ne possèdent pas le nom du module dans leur nom.
Cet exemple d'arborescence conseillée sera utilisé dans ce chapitre.

Pas de namespace pour le module par défaut


Notez que dans le module par défaut, les contrôleurs n'ont pas besoin d'être
préfixés par le nom du module ("Default_"). Ils sont simplement distribués tels
quels. Ce n'est pas le cas pour les autres contrôleurs.

Alors, comment utiliser une structure telle que celle-ci ?

371
Zend_Controller

11.2. Spécification des dossiers de modules


La première chose à faire est d'indiquer au contrôleur frontal où se trouvent les
dossiers contenant les contrôleurs d'action. Passez un array ou une string à
setControllerDirectory(), ou alors une string à addControllerDirectory(). Si
vous utilisez les modules, ces appels de méthodes changent quelque peu.

Pour setControllerDirectory(), un tableau est requis. Les paires clé/valeur représentent


le nom du module, et le chemin des contrôleurs. La clé default est utilisée pour indiquer les
contrôleurs globaux (dont le nom ne comporte pas le module). Chaque option doit comporter
une indication vers un chemin, et la clé default doit être présente :

$front->setControllerDirectory(array(
'default' => '/path/to/application/controllers',
'blog' => '/path/to/application/blog/controllers'
));

addControllerDirectory() prend en paramètre une string décrivant un chemin vers des


contrôleurs. Si vous voulez indiquer un module, passez le en second paramètre. Sinon, le chemin
sera ajouté au module default.

$front->addControllerDirectory('/path/to/application/news/controllers',
'news');

Enfin, si vous avez un dossier spécial regroupant tous vos modules, indiquez le grâce à
addModuleDirectory() :

/**
* Sur cet exemple :
* application/
* modules/
* default/
* controllers/
* foo/
* controllers/
* bar/
* controllers/
*/
$front->addModuleDirectory('/path/to/application/modules');

Dans le code ci dessus, vous déclarez 3 modules en une méthodes. Celle-ci s'attend à la
structure comprenant les modules default, foo, et bar, chacun devant posséder un dossier
controllers

Si le dossier "controllers" ne vous convient pas, changez son nom à l'aide de


setModuleControllerDirectoryName() :

/**
* Le dossier des contrôleurs s'appelle désormais 'con'
* application/
* modules/
* default/
* con/
* foo/
* con/
* bar/
* con/

372
Zend_Controller

*/
$front->setModuleControllerDirectoryName('con');
$front->addModuleDirectory('/path/to/application/modules');

Si vos dossiers de modules ne doivent pas utiliser de sous


dossier pour les contrôleurs, alors passez une valeur vide à
setModuleControllerDirectoryName().

11.3. Routage des modules


La route par défaut, Zend_Controller_Router_Rewrite est un objet de type
Zend_Controller_Router_Route_Module. Cette route traite les schémas de routage
suivants :

• :module/:controller/:action/*

• :controller/:action/*

Ainsi, elle va trouver les contrôleurs et actions, avec ou sans module les précédant. Un module
ne sera trouvé que si sa clé existe dans le tableau d'options passé au contrôleur frontal ou au
distributeur.

11.4. Module ou contrôleur Default global


Dans le routeur par défaut, si aucun contrôleur n'est indiqué dans l'URL, un contrôleur par
défaut sera utilisé (IndexController, sauf si l'on décide de changer ce paramètre). Avec des
modules indiqués dans l'URL, si aucun contrôleur n'est indiqué, alors le distributeur cherchera
dans le module demandé le contrôleur par défaut. Si celui-ci est absent, c'est celui du module
"default" qui sera utilisé.

Si vous voulez renvoyer directement vers le contrôleur par défaut du module "default", passez
le paramètre useDefaultControllerAlways à TRUE dans le contrôleur frontal :

$front->setParam('useDefaultControllerAlways', true);

12. Exceptions avec MVC


12.1. Introduction
Les composants MVC de Zend Framework utilisent un contrôleur frontal, ce qui veut dire que
toute requête envoyée à l'application entre par ce point unique. Ainsi, toutes les exceptions sont
encapsulées dans le contrôleur frontal, ceci vous permet de toutes les traiter dans un seul endroit.

Cependant, les exceptions peuvent contenir des messages ou des traces plutôt sensibles pour
le système, comme des requêtes SQL, l'emplacement de certains fichiers ... Pour vous aider à
protéger votre site, par défaut, Zend_Controller_Front attrape toutes les exceptions et les
enregistre dans l'objet de réponse ; et bien entendu, par défaut, cet objet de réponse n'affiche
pas ces exceptions.

12.2. Gestion des exceptions


Plusieurs mécanismes vont vous permettre de traiter les exceptions dans le modèle MVC de
Zend Framework.

• Par défaut, le plugin error handlerest présent, et activé. Ce plugin a été conçu pour gérer :

373
Zend_Controller

• Les erreurs d'absence de contrôleurs ou d'actions

• Erreurs survenant dans un contrôleur

ErrorHandler agit dans le postDispatch(), et analyse si une exception a été levée (en
gérant son type). Si c'est le cas, alors le plugin renvoie un jeton vers un contrôleur de gestion
des erreurs.

Ce contrôleur couvrira la majorité des cas d'utilisation. Il parvient à gérer les cas "contrôleur
absent", "action absente", ou "autre cas".

• Zend_Controller_Front::throwExceptions()

En passant la valeur TRUE à cette méthode, vous indiquez au contrôleur frontal que vous
souhaitez qu'il vous retourne les exceptions qu'il rencontre. Ainsi, il ne les ajoutera pas à la
réponse, et il ne fera pas intervenir le plugin "Error handler". Exemple :

$front->throwExceptions(true);
try {
$front->dispatch();
} catch (Exception $e) {
// A vous de gérer ici
}

Cette méthode vous permet d'utiliser une gestion personnalisée des exceptions dans votre
application, de manière simple.

• Zend_Controller_Response_Abstract::renderExceptions()

En passant un paramètre TRUE à cette méthode, vous indiquez à la réponse d'afficher


les exceptions qu'elle reçoit (du contrôleur frontal, ou du plugin "Error handler", par
exemple), lorsque son rendu est appelé. Ceci ne devrait être activé qu'en environnement de
développement.

• Zend_Controller_Front::returnResponse() et
Zend_Controller_Response_Abstract::isException().

En passant le booléen TRUE à Zend_Controller_Front::returnResponse(),


Zend_Controller_Front::dispatch() ne commandera pas l'affichage de la réponse
automatiquement. Au lieu de cela, l'objet de réponse sera retourné. Vous pouvez alors
tester celui-ci pour voir s'il contient des exceptions, ceci grâce à isException() et
getException(). Voyez :

$front->returnResponse(true);
$response = $front->dispatch();
if ($response->isException()) {
$exceptions = $response->getException();
// Gestion des exceptions ici
} else {
$response->sendHeaders();
$response->outputBody();
}

Par rapport à Zend_Controller_Front::throwExceptions(), cette utilisation vous


permet de ne rendre la réponse que lorsque vous le décidez, selon la présence de telle ou
telle exception, ou pas.

374
Zend_Controller

12.3. Différents types d'exceptions que vous pouvez rencontrer


Les composants MVC sont nombreux, - requête, routeur, distributeur, contrôleur, et réponse -
chaque objet risque de renvoyer une exception qui lui est propre. Certaines peuvent être créées
ou dérivées, d'autres par défaut indiquent un problème de l'application.

Comme exemples :

• Zend_Controller_Dispatcher::dispatch() va envoyer une exception, par défaut, si


un contrôleur invalide est demandé. Vous pouvez jouer sur ce paramètre :

• Initialisez le paramètre useDefaultControllerAlways

Dans votre contrôleur frontal, ou distributeur, ajoutez la directive suivante :

$front->setParam('useDefaultControllerAlways', true);
// ou
$dispatcher->setParam('useDefaultControllerAlways', true);

Lorsque ceci est injecté, le distributeur utilisera le contrôleur par défaut s'il s'aperçoit qu'il
ne peut distribuer un contrôleur spécifique, plutôt que de renvoyer une exception. Méfiez
vous des moteurs de recherche qui n'aiment pas que plusieurs URI pointent sur un même
contenu. En effet, avec ce paramètre activé, les utilisateurs orthographiant mal votre site,
seront redirigés vers la page d'accueil de celui-ci, ce qui peut aboutir à du "duplicate
content" (contenu dupliqué).

• L'exception envoyée par dispatch() est de type


Zend_Controller_Dispatcher_Exception et contient le message "Invalid controller
specified". Utilisez une méthode comme vu dans la section précédentepour attraper celle-
ci et rediriger vers une page d'erreur générique.

• Zend_Controller_Action::__call() enverra une


Zend_Controller_Action_Exception s'il n'est pas possible de distribuer l'action
demandée. Il est facile de changer ce comportement :

• Dérivez la classe Zend_Controller_Action en redéfinissant sa méthode __call(),


voyez plutôt :

class My_Controller_Action extends Zend_Controller_Action


{
public function __call($method, $args)
{
if ('Action' == substr($method, -6)) {
$controller = $this->getRequest()->getControllerName();
$url = '/' . $controller . '/index';
return $this->_redirect($url);
}

throw new Exception('Invalid method');


}
}

Cet exemple intercepte les actions non existantes, et redirige vers l'action principale du
contrôleur actuel.

• Dérivez Zend_Controller_Dispatcher et redéfinissez getAction() pour vérifier si


l'action existe bien :

375
Zend_Controller

class My_Controller_Dispatcher extends Zend_Controller_Dispatcher


{
public function getAction($request)
{
$action = $request->getActionName();
if (empty($action)) {
$action = $this->getDefaultAction();
$request->setActionName($action);
$action = $this->formatActionName($action);
} else {
$controller = $this->getController();
$action = $this->formatActionName($action);
if (!method_exists($controller, $action)) {
$action = $this->getDefaultAction();
$request->setActionName($action);
$action = $this->formatActionName($action);
}
}

return $action;
}
}

L'exemple précédant vérifie si l'action existe dans le contrôleur demandé. Si ce n'est pas le
cas, il redéfinit l'action en spécifiant celle par défaut.

Cette méthode permet de changer l'action avant la distribution. Attention une fois encore aux
erreurs de syntaxes dans l'URL, qui devraient mener vers une page d'erreur quelconque.

• Utilisez Zend_Controller_Action::preDispatch() ou
Zend_Controller_Plugin_Abstract::preDispatch() pour identifier les actions
invalides.

En dérivant Zend_Controller_Action pour y modifier preDispatch(), vous agissez


sur la globalité de vos contrôleurs, avant même la distribution de l'action demandée.

L'utilisation d'un plugin offre une flexibilité supplémentaire : Si tous vos contrôleurs n'héritent
pas de la même classe, plutôt que de dupliquer du code, un plugin va agir indépendamment
de vos contrôleurs. En preDispatch(), il agit avant ceux-ci.

Par exemple :

class My_Controller_PreDispatchPlugin
extends Zend_Controller_Plugin_Abstract
{
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$front = Zend_Controller_Front::getInstance();
$dispatcher = $front->getDispatcher();
$class = $dispatcher->getControllerClass($request);
if (!$controller) {
$class = $dispatcher->getDefaultControllerClass($request);
}

$r = new ReflectionClass($class);
$action = $dispatcher->getActionMethod($request);

376
Zend_Controller

if (!$r->hasMethod($action)) {
$defaultAction = $dispatcher->getDefaultAction();
$controllerName = $request->getControllerName();
$response = $front->getResponse();
$response->setRedirect('/' . $controllerName
. '/' . $defaultAction);
$response->sendHeaders();
exit;
}
}
}

Dans cet exemple, nous vérifions si l'action demandée existe dans le contrôleur distribué.
Si ce n'est pas le cas, nous exécutons une redirection immédiate.

377
Zend_Currency
1. Introduction à Zend_Currency
Zend_Currency est une partie du coeur de l'i18n ("internationalisation") de Zend Framework.
Elle permet le traitement de toutes les questions liées à la monnaie, à la représentation de
l'argent, son formatage, les services d'échange et les calculs.

1.1. Pourquoi devriez-vous utiliser Zend_Currency ?


Zend_Currency voues offre les bénéfices suivants :

• Support complet de la régionalisation

Ce composant fonctionne avec toutes les régions disponibles et a donc la capacité de


connaître plus de 100 informations de monnaie localisées différentes. Cela inclut par exemple
des noms de monnaie, des abréviations, des signes d'argent et plus.

• Définition de monnaie réutilisable

Zend_Currency a l'avantage que les représentations de monnaie qui ont déjà été définies
peuvent être réutilisés. Vous pouvez ainsi deux représentations différentes de la même
monnaie.

• Calculs avec les monnaies

Zend_Currency vous permet de faire des calculs avec les valeurs de monnaie. De plus il
vous fournit une interface pour l'échange de devises.

• Méthodes additionnelles

Zend_Currency inclue plusieurs méthodes additionnelles qui donnent des informations


concernant les régions dans lesquelles une monnaie est utilisée ou quelle monnaie est utilisée
dans une région spécifiée.

2. Utiliser Zend_Currency
2.1. Utilisation de base
La manière la plus simple consiste à se reposer sur la locale de l'utilisateur. Lorsque vous créez
une instance de Zend_Currency sans préciser d'options, la locale du client sera alors utilisée.

Exemple 106. Créer une monnaie avec les paramètres du client

Imaginons un client dont la locale est "en_US" dans son navigateur. Dans ce cas,
Zend_Currency détectera automatiquement la monnaie à utiliser.

$currency = new Zend_Currency();

// Voyons les paramètres par défaut régis par la locale utilisateur


// var_dump($currency);

L'objet crée va alors contenir une monnaie "US Dollar" car il s'agit de la monnaie affectée aux
USA. D'autres options ont aussi été affectées comme le signe "$" ou l'abbréviation "USD".

378
Zend_Currency

La détection automatique par locale ne fonctionne pas toujours


La détection automatique par locale ne fonctionne pas toujours car
Zend_Currency nécessite une locale incluant la région. Si le client utilise une
locale courte ("en"), Zend_Currency ne sait pas quelle région parmi les 30
possibles choisir. Une exception sera alors levée.

Un client peut aussi déregler la locale dans son navigateur, ou la supprimer.


Ainsi le paramètre de l'environnement sera alors utilisé pour la locale, ce qui peut
mener à des comportements non attendus ou des exceptions.

2.2. Créer une monnaie basée sur une locale


Pour éviter ce genre de problème, précisez manuellement la locale à utiliser.

$currency = new Zend_Currency('en_US');

// Utilisation de l'option 'locale'


// $currency = new Zend_Currency(array('locale' => 'en_US'));

// Voir la monnaie avec les paramètres actuels fixés à 'en_US'


// var_dump($currency);

Dans l'exemple ci-dessus, nous ne sommes plus dépendant du client.

Zend_Currency supporte aussi l'utilisation d'une locale globale. Mettez une instance de
Zend_Locale dans le registre comme montré ci-après. Dans un tel cas, l'option locale n'est
plus obligatoire pour chaque instance et la même locale sera utilisée partout, tout le temps.

// dans le bootstrap
$locale = new Zend_Locale('de_AT');
Zend_Registry::set('Zend_Locale', $locale);

// quelque part dans l'application


$currency = new Zend_Currency();

3. Options des monnaies


En fonction de vos besoins, certaines options peuvent être passées à l'instanciation, elles ont
toutes des valeurs par défaut. Voici quelques exemples:

• Symbole des monnaies, noms courts ou noms:

Zend_Currency connait tous les noms, abbréviations et signes des monnaies mais il peut
s'avérer nécessaire de devoir remplacer la représentation visuelle d'une monnaie.

• Position du symbole de monnaie:

La position du symbole de la monnaie est défini automatiquement. Il peut cependant être


précisé manuellement.

• Script:

Vous pouvez définit les scripts à utiliser pour le rendu des chiffres des monnaies. Vous
trouverez des détails sur les scripts dans le chapitre de Zend_Locale concernant Les
systèmes de conversion des nombres.

379
Zend_Currency

• Formatter les nombres:

Le nombre qui représente la somme est par défaut formatté via les valeurs que fournit la
locale en cours. Par exemple, la virgule ',' est utilisée pour séparer les milliers dans la langue
anglaise, mais en français il s'agit du séparateur des décimales.

La liste suivante précise les options disponibles qui peuvent être passées en constructeur ou via
la méthode setFormat(), sous forme de tableau.

• currency: Précise l'abbréviation.

• display: Définit la partie de la monnaie utilisée pour le rendu visuel. Il y a 4 représentations


disponibles, précisées dansce tableau.

• format: Précise le format pour représenter les nombres. Ce format inclut par exemple le
séparateur des milliers. Vous pouvez vous reposer sur la locale en passant un identifiant
de locale, ou définir un format manuellement. Si aucun format n'est précisé, la locale dans
Zend_Currency sera utilisée. Voyez le chapitre sur le formattage des nombres.

• locale: Définit la locale à utiliser pour cette monnaie. Elle sera utilisée pour les paramètres par
défaut si il faut les utiliser. Notez que si vous ne passez pas de locale vous-même, elle sera
alors détectée de manière automatique, ce qui pourrait créer des problèmes.

• name: Définit le nom long de la monnaie.

• position: Définit la position de la monnaie. Pour plus d'informations, voyez cette section.

• precision: Définit la précision à utiliser pour représenter la monnaie. La valeur par défaut
dépend de la locale et vaut la plupart du temps 2.

• script: Indique le script à utiliser pour représenter les chiffres. Souvent par défaut 'Latn', qui
inclut les chiffres de 0 à 9. Les autres scripts comme 'Arab' utilisent d'autres chiffres. Voyez
Le chapitre sur les système numérraires pour plus de détails.

• service: Définit le service de change à consulter lors de conversions entre monnaies.

• symbol: Précise le symbole de la monnaie.

• value: Indique le montant (la valeur de la monnaie). S'utilise avec l'option service.

Beaucoup d'options sont donc ajustables, et la plupart trouvent leurs valeurs par défaut dans les
représentations normalisées de la monnaie utilisée.

4. Qu'est ce qui définit une monnaie?


Une monnaie consiste en plusieurs informations. Un nom, une abbréviation et un signe. Chacune
de ces informations n'est pertinente à l'affichage que si elle est seule, par exemple il est un peu
idiot d'écrire "USD 1.000 $" ou "EUR 1.000 €"

De ce fait,Zend_Currency garde en mémoire l'information pertinente pour la monnaie en cours


à l'affichage. Les constantes suivantes sont utilisées:

Tableau 31. Informations rendues pour une monnaie


Constante Description
NO_SYMBOL Aucun symbole de représentation de la
monnaie

380
Zend_Currency

Constante Description
USE_SYMBOL Le symbole de la monnaie sera rendu. Pour
l'Euro : '€'
USE_SHORTNAME L'abbréviation sera utilisée pour le rendu
visuel. L'Euro aura 'EUR' comme abbréviation
par exemple. La plupart des abbréviations
tiennent sur 3 caractères.
USE_NAME Le nom complet de la monnaie sera utilisé.
Pour le dollar américain : "US Dollar".

Exemple 107. Sélectionner la description de la monnaie

Imaginons que le client utilise la locale "en_US". Sans autre option, la valeur de monnaie
retournée ressemblerait à ceci:

$currency = new Zend_Currency(


array(
'value' => 100,
)
);

print $currency; // Pourrait afficher '$ 100'

En donnant des options vous précisez quelle information afficher.

$currency = new Zend_Currency(


array(
'value' => 100,
'display' => Zend_Currency::USE_SHORTNAME,
)
);

print $currency; // Pourrait retourner 'USD 100'

Sans le paramètre display, le signe de la monnaie sera utilisé lors du rendu visuel. Si la
monnaie n'a pas de signe, son abbréviation sera utilisée à la place.

Toutes les monnaies n'ont pas de signe

Toutes les monnaies ne possèdent pas forcément un signe. Ceci signifie que
s'il n'y a pas de signe par défaut pour la monnaie, et que vous spécifiez
manuellement de rendre un signe, alors le rendu de la monnaie sera nul car le
signe serait alors une chaine vide.

Pour changer des options concernant les monnaies, voyez le paragraphe ci-après.

381
Zend_Currency

Exemple 108. Changer la description de la monnaie

Imaginons que le client utilise la locale "en_US". Nous ne voulons pas des paramètres par
défaut, mais nous voulons préciser manuellement notre propre description. Ceci s'applique
au moyen d'une option simple:

$currency = new Zend_Currency(


array(
'value' => 100,
'name' => 'Dollar',
)
);

print $currency; // Retournerait 'Dollar 100'

Vous pourriez aussi passer un signe et une abbréviation spécifiques.

$currency = new Zend_Currency(


array(
'value' => 100,
'symbol' => '$$$',
)
);

print $currency; // Retournerait '$$$ 100'

Paramètres de rendu automatiques

Lorsque vous précisez un nom, une abbréviation ou un signe, alors ces


informations seront rendues automatiquement. Cette supposition simplifie les
traitements car vous n'avez de ce fait pas à toucher à l'option display.

Ainsi, utiliser l'option sign peut se faire en évitant de toucher à display, nul besoin
de passer cette dernière à 'USE_SYMBOL'.

5. Où est le symbole monnétaire?


Le signe symbolique de la monnaie est positionné par rapport à sa valeur en fonction de la
locale utilisée. Cependant, vous pouvez forcer ce positionnement grâce à l'option display qui se
configure au moyen de constantes:

Tableau 32. Positions disponibles pour la monnaie

Constante Description
STANDARD Affiche le symbole de la monnaie dans une
position standard, conforme à la locale
RIGHT Affiche le symbole de la monnaie à droite de
sa valeur
LEFT Affiche le symbole de la monnaie à gauche de
sa valeur

382
Zend_Currency

Exemple 109. Paramétrer la position du symbole monnétaire

Imaginons que le client utilise la locale "en_US". Sans option, la valeur retournée serait par
exemple:

$currency = new Zend_Currency(


array(
'value' => 100,
)
);

print $currency; // Retournerait '$ 100'

En utilisant la valeur par défaut, le symbole pourrait être retourné à gauche ou à droite de
la valeur de monnaie. Voyons comment fixer cette position:

$currency = new Zend_Currency(


array(
'value' => 100,
'position' => Zend_Currency::RIGHT,
)
);

print $currency; // Retournerait '100 $';

Notez que dans le deuxième exemple, la position de USD est fixée quelle que soit la locale
ou la monnaie considérée.

6. A quoi ressemble une monnaie?


Le rendu visuel d'une monnaie va dépendre de la locale. La locale stocke plusieurs informations
qui peuvent chacune être redéfinies par vos propres options si besoin.

Par exemple, la plupart des locales utilisent le script latin pour rendre les nombres. Mais certaines
langues, comme l'arabe, utilisent d'autres chiffres. Et un site Web Arabe va utiliser le rendu arabe
pour toutes les monnaies, voyez l'exemple:

Exemple 110. Utiliser un script personnalisé

Imagnons que nous utisons la monnaie "Dollar". Mais nous voulons rendre notre page avec
des scripts arabes.

$currency = new Zend_Currency(


array(
'value' => 1000,
'script' => 'Arab',
)
);

print $currency; // Retournerait '$ ########'

Pour plus d'informations sur les scripts disponibles, voyez le manuel de Zend_Localesur les
systèmes des nombres.

Le formattage d'une monnaie peut être changé. Par défaut, la locale est utilisée. Elle indique le
séparateur des milliers, le point de la décimale et la précision.

$currency = new Zend_Currency(

383
Zend_Currency

array(
'value' => 1000,
'currency' => 'USD'
'format' => 'de',
)
);

print $currency; // Retournerait '$ 1.000'

Il existe deux manières de préciser le format à utiliser, manuellement ou via une locale.

Utiliser la locale vous permet de bénéficier de certains automatismes. Par exemple la locale 'de'
definit le point '.' comme séparateur des milliers, et la virgule ',' comme séparateur décimal. En
anglais, c'est l'inverse.

$currency_1 = new Zend_Currency(


array(
'value' => 1000,
'currency' => 'USD'
'format' => 'de',
)
);

$currency_2 = new Zend_Currency(


array(
'value' => 1000,
'currency' => 'USD'
'format' => 'en',
)
);

print $currency_1; // Retournerait '$ 1.000'


print $currency_2; // Retournerait '$ 1,000'

Si vous les définissez manuellement, vous devez alors respecter le format décrit dans ce chapitre
de la localisation . Voyez plutôt:

$currency = new Zend_Currency(


array(
'value' => 1000,
'currency' => 'USD'
'format' => '#0',
)
);

print $currency; // Retournerait '$ 1000'

Dans l'exemple ci-dessus nous avons supprimé le séparateur et l'indicateur de précision.

7. Travailler avec les valeurs des monnaies (les montants)


Travailler avec des monnaies c'est avant tout travailler avec des valeurs, des "prix", un montant.
Il faut ainsi travailler avec le montant (la valeur), la précision et l'éventuel taux de change.

7.1. Travailler avec les valeurs des monnaies


La valeur de la monnaie (le montant) se précise grâce à l'option value.

384
Zend_Currency

$currency = new Zend_Currency(


array(
'value' => 1000,
'currency' => 'USD',
)
);

print $currency; // Retournerait '$ 1.000'

Vous pouvez changer la valeur en utilisant les méthodes setFormat() ou setValue().

$currency = new Zend_Currency(


array(
'value' => 1000,
'currency' => 'USD',
)
);

print $currency->setValue(2000); // Retournerait '$ 2.000'

getValue() existe aussi.

7.2. Utiliser la précision des monnaies


La plupart des monnaies utilisent une précision de 2, ce qui signifie qu'avec 100 dollars US vous
pouvez rajouter 50 cents. C'est simplement le paramètre après la virgule.

$currency = new Zend_Currency(


array(
'value' => 1000.50,
'currency' => 'USD',
)
);

print $currency; // Retournerait '$ 1.000,50'

Comme la précision est de 2, vous obtiendrez des décimales à '00' pour un chiffre rond.

$currency = new Zend_Currency(


array(
'value' => 1000,
'currency' => 'USD',
)
);

print $currency; // Retournerait '$ 1.000,00'

Pour pallier à ce problème de précision, vous pouvez simplement utiliser l'option precision avec la
valeur '0'. La précision prend une valeur entre 0 et 9. Les valeurs des monnaies seront arrondies
lorsqu'elles ne tiennent pas dans la précision demandée.

$currency = new Zend_Currency(


array(
'value' => 1000,30,
'currency' => 'USD',
'precision' => 0
)

385
Zend_Currency

);

print $currency; // Retournerait '$ 1.000'

8. Calculs avec les monnaies


Il est possible en travaillant avec des monnaies, d'effectuer des calculs. Zend_Currency permet
d'effectuer de tels calculs très facilement. Les méthodes suivantes sont supportées:

• add(): Ajoute la valeur de la monnaie à celle actuellement stockée en mémoire dans l'objet

• sub(): Soustrait la valeur de la monnaie à celle actuellement stockée en mémoire dans l'objet

• div(): Divise la valeur de la monnaie à celle actuellement stockée en mémoire dans l'objet.

• mul(): Multiplie la valeur de la monnaie à celle actuellement stockée en mémoire dans l'objet.

• mod(): Calcul le modulo de la valeur de la monnaie à celle actuellement stockée en mémoire


dans l'objet.

• compare(): Compare la valeur de la monnaie à celle actuellement stockée en mémoire dans


l'objet. Si les deux valeurs sont égales, '0' est retourné. Si la monnaie actuelle est plus grande
que celle fournie, '1' sera retourné. Dans l'autre cas, '-1' sera retourné.

• equals(): Compare la valeur de la monnaie à celle actuellement stockée en mémoire dans


l'objet. Si les deux valeurs sont égales, TRUE est retourné, FALSE sinon.

• isMore(): Compare la valeur de la monnaie à celle actuellement stockée en mémoire dans


l'objet. Si la monnaie interne à l'objet est supérieure à la valeur passée, TRUE est retourné,
FALSE sinon.

• isLess(): Compare la valeur de la monnaie à celle actuellement stockée en mémoire dans


l'objet. Si la monnaie interne à l'objet est inférieure à la valeur passée, TRUE est retourné,
FALSE sinon.

Comme vous le voyez ces méthodes permettent n'importe quel calcul avec Zend_Currency.
Voici quelques exemples:

$currency = new Zend_Currency(


array(
'value' => 1000,
'currency' => 'USD',
)
);

print $currency; // Pourrait retourner '$ 1.000,00'

$currency->add(500);
print $currency; // Pourrait retourner '$ 1.500,00'

$currency_2 = new Zend_Currency(


array(
'value' => 500,
'currency' => 'USD',
)
);

386
Zend_Currency

if ($currency->isMore($currency_2)) {
print "First is more";
}

$currency->div(5);
print $currency; // Pourrait retourner '$ 200,00'

9. Echanger (convertir) des monnaies


Dans la section précédente, nous avons parlé des calculs sur les monnaies. Mais comme vous
pouvez imaginer, calculer des monnaies peut vite mener à des calculs internationnaux (entre
pays différents).

Dans un tel cas, les monnaies doivent être converties avec un taux. Les taux officiels sont
conservés par les banques ou encore les journaux. Dans le Web, des services de conversion
existent. Zend_Currency permet leur utilisation par fonction de rappel.

D'abord, écrivons un service de change simple.

class SimpleExchange implements Zend_Currency_CurrencyInterface


{
public function getRate($from, $to)
{
if ($from !== "USD") {
throw new Exception('On ne change que des USD');
}

switch ($to) {
case 'EUR':
return 0.5;
case 'JPE':
return 0.7;
}

throw new Exception('Impossible de changer vers $to');


}
}

Nous venons de créer un service de change manuellement.

Votre classe de service de change doit implémenter Zend_Currency_CurrencyInterface.


Cette interface définit une seule méthode getRate(), qui prend deux paramètres : les noms
courts des monnaies. Zend_Currency a besoin que le taux de change soit retourné.

Dans un service réel, vous demanderiez au fournisseur les taux de change, dans notre exemple
nous les codons en dur.

Attachons maintenant notre classe avec Zend_Currency. Ceci se fait de deux manières , soit
en attachant l'objet ou en attachant le nom de sa classe.

$currency = new Zend_Currency(


array(
'value' => 1000,
'currency' => 'USD',
)
);

387
Zend_Currency

$service = new SimpleExchange();

// attachons le service de change


$currency->setService($service);

$currency_2 = new Zend_Currency(


array(
'value' => 1000,
'currency' => 'EUR',
)
);

print $currency->add($currency2);

L'exemple ci-dessus retournera '$ 3.000' car 1.000 EUR seront convertis avec un taux de 2 vers
2.000 USD.

Calcul sans service de change


Si vous tentez des calculs avec deux monnaies de types différents et qu'aucun
service de change n'a été précisé, une exception sera levée.Zend_Currency
ne sait pas nativement passer d'une monnaie à une autre.

10. Informations complémentaires pour Zend_Currency


10.1. Informations sur les monnaies
Il peut être utilie de récupérer des données concernant une monnaie. Zend_Currency propose
différentes méthodes dans ce but dont voici une liste:

• getCurrencyList(): Retourne un tableau listant toutes les monnaies utilisées dans une
région donnée. La locale par défaut est utilisée si aucune information de région n'est fournie.

• getLocale(): Retourne la locale utilisée actuellement pour la monnaie.

• getName(): Retourne le nom complet de la monnaie actuelle. Si aucun nom complet n'est
trouvé, l'abbréviation sera retournée.

• getRegionList(): Retourne un tableau de toutes les régions où est utilisée la monnaie


actuelle. Toutes les régions sont listées si aucune monnaie n'a été donnée.

• getService(): Retourne l'objet de service d'échange de la monnaie courante.

• getShortName(): Retourne l'abbréviation de la monnaie courante.

• getSymbol(): Retourne le symbole de la monnaie. Si aucun symbole n'existe, l'abbréviation


de la monnaie sera retournée.

• getValue(): Retourne la valeur affectée à la monnaie en cours.

Voyons quelques exemples:

$currency = new Zend_Currency();

var_dump($currency->getValue());
// retourne 0

388
Zend_Currency

var_dump($currency->getRegionList());
// retourne un tableau représentant toutes les régions dans lesquelles USD est utilisé

var_dump($currency->getRegionList('EUR'));
// retourne un tableau avec toutes les régions utilisant l'EUR

var_dump($currency->getName());
// pourrait retourner 'US Dollar'

var_dump($currency->getName('EUR'));
// Retourne 'Euro'

Comme vous le voyez, beaucoup de méthodes prennent des paramètres supplémentaires pour
surcharger l'objet actuel et le faire travailler sur une autre monnaie que celle stockée en interne.

10.2. Optimisation des performances des monnaies


Les performances de Zend_Currency peuvent être optimisées au moyen de Zend_Cache. La
méthode statique Zend_Currency::setCache($cache) prend une options : un adaptateur
Zend_Cache. S'il est utilisé, les données de localisation utilisées au sein de Zend_Currency
seront mises en cache. Aussi, il y a des méthodes statiques pour manipuler le cache :
getCache(), hasCache(), clearCache() et removeCache().

Exemple 111. Mettre les monnaies en cache

// Création d'un objet de cache


$cache = Zend_Cache::factory('Core',
'File',
array('lifetime' => 120,
'automatic_serialization' => true),
array('cache_dir'
=> dirname(__FILE__) . '/_files/'));
Zend_Currency::setCache($cache);

389
Zend_Date
1. Introduction
Le composant Zend_Date fournit une API simple de manipulation des dates et des temps. Ses
méthodes acceptent un grand nombre de paramètres formatés, comme des parties de dates, et
complètent bien le support natif des dates de PHP.

Même si rester simple est un objectif, manipuler des dates et des temps localisés, les additionner,
par parties, les convertir ... mène vers une certaine complexité inévitable. Les dates et les
temps sont souvent notés de manière très différente selon la locale. Par exemple, certaines
locales placent le mois en premier, d'autres l'année. Pour plus d'information sur la gestion de la
localisation et de la normalisation, voyez le manuel de Zend_Locale.

Zend_Date supporte aussi les noms abrégés des mois dans beaucoup de
langues.Zend_Locale facilite la localisation et la normalisation des mois localisés et des jours
de semaines, leur conversion vers des timestamps.

1.1. Définissez toujours un fuseau horaire par défaut


Avant toute manipulation de date, que ce soit par les fonctions PHP, ou par Zend
Framework, soyez sûrs que votre fuseau horaire par défaut est défini. Configurez votre variable
d'environnement TZ, date.timezone dans le php.ini, ou utilisez date_default_timezone_set().
En PHP nous pouvons ajuster les fonctions de date et temps pour fonctionner selon un certain
fuseau horaire. Pour les options et la liste des fuseaux, consultez La liste des identifiants de
fuseaux horaires.

Exemple 112. Spécifier un fuseau par défaut

// timezone pour un américain en Californie


date_default_timezone_set('America/Los_Angeles');
// timezone pour un allemand en Allemagne
date_default_timezone_set('Europe/Berlin');

Lorsque vous créez des instances de Zend_Date, leur fuseau sera automatiquement mis à celui
par défaut ! Ainsi, le paramètre de fuseau horaire prendre en compte le DST si besoin, vous
n'aurez donc pas besoin de leconfigurer.

Souvenez vous que les fuseaux UTC et GMT n'incluent pas la notion "d'heure d'hiver"(Daylight
Saving Time, DST). Donc même si vous dites à Zend_Date de prendre en compte le DST, il
sera annulé pour les futures instances de Zend_Date utilisant UTC ou GMT.

1.2. Pourquoi utiliser Zend_Date ?


Zend_Date a les caractéristiques suivantes, qui étendent et complètent les fonctions de date
de PHP :

• API simple

Zend_Date propose une API simple, qui combine les meilleures fonctionnalités depuis 4
langages de programmation. Il est par exemple possible de comparer ou ajouter 2 dates.

• Internationalisé

390
Zend_Date

Toutes les abréviations des noms des mois ou des jours sont traduits dans plus de 130
langues. Les méthodes supportent des entrées et sorties de dates utilisant ces noms localisés.

• Timestamps infinis

La documentation de PHP 5.2 indique, "L'intervalle de validité des timestamps est du 13


Dec 1901 20:45:54 GMT au 19 Jan 2038 03:14:07 GMT", Zend_Date supporte un intervalle
quasi illimité grâce à l'extension BCMath. Si l'extension BCMath n'est pas disponible, alors le
support des timestamp sera réduit à la valeur maximale du type PHP float supporté par le
serveur. "La taille du float est dépendant de la plate-forme, un maximum de ~1.8e308 avec
une précision d'environ 14 décimales est une valeur connue (64 bit IEEE format)." [ http://
www.php.net/float]. Aussi, des limitations dans le calcul des flottants, comme des arrondis
non désirables, peuvent apparaître. Ces problèmes sont évités grâce à l'extension BCMath,
si disponible.

• Support des dates ISO_8601

Le support complet de ISO_8601 est pris en charge. Même les données partiellement
ISO_8601 seront identifiées correctement. Ces formats sont utiles pour le travail avec des
bases de données. Par exemple MSSQL et MySQLles utilise mais diffèrent légèrement dans
leur format, cependant ils sont supportés par Zend_Date grâce à la constante de spécification
de format Zend_Date::ISO_8601. Si les chaînes des dates sont conformes à "Y/m/d" ou "Y-
m-d H:i:s", selon les formats de date() de PHP, utilisez le support de Zend_Date pour le
format ISO 8601.

• Calculer le sunrise et sunset

N'importe où dans la journée, les temps du sunrise (levé de soleil) et sunset (couché de soleil)
peuvent être affichés.

2. Aspect théorique
Pourquoi n'existe-il que l'unique classe Zend_Date pour gérer les dates et les heures dans
Zend Framework ?

Beaucoup de langages divisent la gestion des heures et des dates de calendrier en deux classes.
Cependant Zend Framework lutte pour une extrême simplicité, et forcer le développeur à gérer
différents objets avec différentes méthodes pour les heures et les dates entraîne un fardeau
dans beaucoup de situations. Puisque les méthodes de Zend_Date supporte le travail avec des
dates ambiguës qui n'incluraient pas toutes les parties (ère, année, mois, jour, heure, minute,
seconde, décalage horaire), les développeurs aiment la flexibilité et la facilité d'utilisation d'une
même classe et des mêmes méthodes afin de réaliser les mêmes actions par exemple addition,
soustraction, comparaison, fusion de parties de dates, etc.). Diviser la gestion de ces fragments
de date dans de multiples classes pourraient entraîner des complications quand on souhaite
réaliser des inter-opérations. Une unique classe réduit la duplication de code pour des opérations
similaires, sans l'obligation d'une hiérarchie d'héritage complexe.

2.1. Fonctionnement interne


• Référence temporelle UNIX (timestamp) :

Toutes les dates et heures, même celles ambiguës (par exemple sans année), sont
représentées en interne par des moments absolus dans le temps, stockés en tant que
référence temporelle UNIX exprimant la différence entre le moment désiré et le 1er janvier

391
Zend_Date

1970 à 00:00:00 GMT. Ceci est seulement possible, parce que Zend_Date n'est pas limité aux
références temporelles UNIX ou aux valeurs entières. L'extension BCMath est requise pour
supporter les très grandes dates hors de la plage du Vendredi 13 décembre 1901 à 20:45:54
GMT au Mardi 19 janvier 2038 à 03:14:07 GMT. De plus de petites erreurs mathématiques
peuvent apparaître causées par les limitations inhérentes aux types de données float et aux
arrondis, à moins d'utiliser l'extension BCMath.

• Parties de date en tant que décalages de référence temporelle :

Ainsi, une instance d'objet représentant trois heures peut être exprimé en tant que trois heures
après le 1er janvier 1970 à 00:00:00 GMT - c'est-à-dire 0 + 3 * 60 * 60 = 10800.

• Fonctions PHP :

Quand cela est possible, Zend_Date utilise actuellement les fonctions PHP pour améliorer
les performances.

3. Méthodes de base
Les sections qui suivent montrent l'utilisation de base de Zend_Date au travers d'exemples.
Dans ce manuel, une "date" représente toujours une date calendaire et un temps, même lorsque
cela n'est pas mentionné spécifiquement. La partie (date calendaire, ou temps) non spécifiée
prend la valeur par défaut "zéro". Ainsi additionner une date ayant une date calendaire mais pas
de temps, à un temps "12 heures" n'ayant pas de date calendaire, résultera en la combinaison
des deux : la date calendaire connue avec une partie temps de 12 heures, soit midi.

Paramétrer une date sans temps implique un temps par défaut de 00:00:00. Inversement
paramétrer un temps mais sans date calendaire lui verra affectée la valeur de 01.01.1970 plus
le temps. La plupart des ordinateurs entendent la date "nulle" comme étant la première seconde
de l'année 1970. La notion de timestamp est un nombre de secondes depuis cette date dite
"EPOCH".

3.1. La date courante


Sans argument, construire un objet correspond à la date courante du système d'exploitation telle
que retournée par la fonction PHP time(), pour obtenir un timestamp UNIX pour l'objet. Prenez
garde à la locale et au fuseau horaire (timezone) par défaut.

Exemple 113. Créer la date courante

$date = new Zend_Date();

// Affiche le timestamp actuel


print $date;

3.2. Zend_Date : exemples


Les exemples sont le meilleur moyen de prendre en main Zend_Date, particulièrement pour les
personnes non habituées à la notion de date dans d'autres langages ou frameworks.

3.2.1. Afficher une date


La date contenue dans l'objet Zend_Date est obtenue en tant qu'entier ou chaîne de caractères
localisée, grâce à la méthode get(). Il y a des options disponibles, nous les détaillerons
ultérieurement.

392
Zend_Date

Exemple 114. get() - affiche une date

$date = new Zend_Date();

// Affiche la date désirée


print $date->get();

3.2.2. Spécifier une date


La méthode set() modifie la date dans l'objet et retourne la date affectée comme un timestamp
(et non un objet). Là aussi des options sont disponibles, nous y reviendrons.

Exemple 115. set() - affecte une date

$date = new Zend_Date();

// Affecter une nouvelle date


$date->set('13:00:00',Zend_Date::TIMES);
print $date->get(Zend_Date::W3C);

3.2.3. Ajouter et soustraire des dates


Ajouter deux dates avec add() signifie souvent ajouter une date réelle plus un timestamp
artificiel représentant une partie de date, comme 12 heures par exemple. add() et sub()
utilisent les mêmes paramètres que set(), sur lesquels nous reviendrons plus tard.

Exemple 116. add() - ajouter des dates

$date = new Zend_Date();

// modifie $date en ajoutant 12 heures


$date->add('12:00:00', Zend_Date::TIMES);

echo "Date via get() = ", $date->get(Zend_Date::W3C), "\n";

// utilise __toString()
echo "Date via toString() = ", $date, "\n";

3.2.4. Comparaison de dates


Toutes les méthodes basiques de Zend_Date peuvent opérer sur des dates complètes, ou des
parties de dates. Par exemple, comparer la date dans l'objet à une certaines valeur de minutes,
peut être effectué grâce à la méthode compare().

Exemple 117. compare() - comparer des dates

$date = new Zend_Date(); // date actuelle

// Comparaison des 2 temps


if ($date->compare(10, Zend_Date::MINUTE) == -1) {
print "Cette heure n'a pas encore dépassé 10 minutes";
} else {
print "Cette heure a au plus dépassé les 10 minutes";
}

Pour demander une simple égalité, utilisez equals(), qui retourne un booléen.

393
Zend_Date

Exemple 118. equals() - identifie une date ou partie de date

$date = new Zend_Date(); // date actuelle

// Identification, demande d'égalité


if ($date->equals(10, Zend_Date::HOUR)) {
print "Il est 10 heures.";
} else {
print "Il n'est pas 10 heures.";
}

4. Zend_Date API Overview


While the Zend_Date API remains simplistic and unitary, its design remains flexible and powerful
through the rich permutations of operations and operands.

4.1. Zend_Date Options


4.1.1. Selecting the Date Format Type
Several methods use date format strings, in a way similar to PHP's date(). If you are
more comfortable with PHP's date format specifier than with ISO format specifiers, then you
can use Zend_Date::setOptions(array('format_type' => 'php')). Afterward,
use PHP's date format specifiers for all functions which accept a $format parameter. Use
Zend_Date::setOptions(array('format_type' => 'iso')) to switch back to the
default mode of supporting only ISO date format tokens. For a list of supported format codes,
see Self-Defined OUTPUT Formats Using PHP's date() Format Specifiers

4.1.2. DST and Date Math


When dates are manipulated, sometimes they cross over a DST change, normally resulting in
the date losing or gaining an hour. For exmaple, when adding months to a date before a DST
change, if the resulting date is after the DST change, then the resulting date will appear to lose
or gain an hour, resulting in the time value of the date changing. For boundary dates, such as
midnight of the first or last day of a month, adding enough months to cross a date boundary
results in the date losing an hour and becoming the last hour of the preceding month, giving
the appearance of an "off by 1" error. To avoid this situation, the DST change ignored by using
the fix_dst option. When crossing the Summer or Winter DST boundary, normally an hour is
substracted or added depending on the date. For example, date math crossing the Spring DST
leads to a date having a day value one less than expected, if the time part of the date was
originally 00:00:00. Since Zend_Date is based on timestamps, and not calendar dates with
a time component, the timestamp loses an hour, resulting in the date having a calendar day
value one less than expected. To prevent such problems use the option fix_dst, which defaults
to TRUE, causing DST to have no effect on date "math" (addMonth(), subMonth()). Use
Zend_Date::setOptions(array('fix_dst' => false)) to enable the subtraction or
addition of the DST adjustment when performing date "math".

If your actual timezone within the instance of Zend_Date is set to UTC or GMT the option 'fix_dst'
will not be used because these two timezones do not work with DST. When you change the
timezone for this instance again to a timezone which is not UTC or GMT the previous set 'fix_dst'
option will be used again for date "math".

4.1.3. Month Calculations


When adding or substracting months from an existing date, the resulting value for the day of
the month might be unexpected, if the original date fell on a day close to the end of the month.

394
Zend_Date

For example, when adding one month to January 31st, people familiar with SQL will expect
February 28th as the result. On the other side, people familiar with Excel and OpenOffice will
expect March 3rd as the result. The problem only occurs, if the resulting month does not have the
day, which is set in the original date. For Zend Framework developers, the desired behavior is
selectable using the extend_month option to choose either the SQL behaviour, if set to FALSE, or
the spreadsheet behaviour when set to TRUE. The default behaviour for extend_month is FALSE,
providing behavior compatible to SQL. By default, Zend_Date computes month calculations by
truncating dates to the end of the month (if necessary), without wrapping into the next month
when the original date designates a day of the month exceeding the number of days in the
resulting month. Use Zend_Date::setOptions(array('extend_month' => true)) to
make month calculations work like popular spreadsheet programs.

4.1.4. Speed up Date Localization and Normalization with Zend_Cache

You can speed up Zend_Date by using an Zend_Cache adapter. This speeds up all methods
of Zend_Date when you are using localized data. For example all methods which accept
Zend_Date::DATE and Zend_Date::TIME constants would benefit from this. To set an
Zend_Cache adapter to Zend_Date just use Zend_Date::setOptions(array('cache'
=> $adapter)).

4.1.5. Receiving Syncronised Timestamps with Zend_TimeSync

Normally the clocks from servers and computers differ from each other. Zend_Date is able
to handle such problems with the help of Zend_TimeSync. You can set a timeserver with
Zend_Date::setOptions(array('timesync' => $timeserver)) which will set the
offset between the own actual timestamp and the real actual timestamp for all instances of
Zend_Date. Using this option does not change the timestamp of existing instances. So best
usage is to set it within the bootstrap file.

4.2. Working with Date Values


Once input has been normalized via the creation of a Zend_Date object, it will have an
associated timezone, but an internal representation using standard UNIX timestamps. In order for
a date to be rendered in a localized manner, a timezone must be known first. The default timezone
is always GMT or UTC. To examine an object's timezone use getTimeZone(). To change an
object's timezone, use setTimeZone(). All manipulations of these objects are assumed to be
relative to this timezone.

Beware of mixing and matching operations with date parts between date objects for different
timezones, which generally produce undesireable results, unless the manipulations are only
related to the timestamp. Operating on Zend_Date objects having different timezones generally
works, except as just noted, since dates are normalized to UNIX timestamps on instantiation of
Zend_Date.

Most methods expect a constant selecting the desired $part of a date, such as
Zend_Date::HOUR. These constants are valid for all of the functions below. A list of
all available constants is provided in list of all constants. If no $part is specified,
then Zend_Date::TIMESTAMP is assumed. Alternatively, a user-specified format may
be used for $part, using the same underlying mechanism and format codes as
Zend_Locale_Format::getDate(). If a date object is constructed using an obviously invalid
date (e.g. a month number greater than 12), then Zend_Date will throw an exception, unless
no specific date format has been selected -i.e. $part is either NULL or Zend_Date::DATES
(a "loose" format).

395
Zend_Date

Exemple 119. User-Specified Input Date Format

$date1 = new Zend_Date('Feb 31, 2007', null, 'en_US');


echo $date1, "\n"; // outputs "Mar 3, 2007 12:00:00 AM"

$date2 = new Zend_Date('Feb 31, 2007', Zend_Date::DATES, 'en_US');


echo $date2, "\n"; // outputs "Mar 3, 2007 12:00:00 AM"

// strictly restricts interpretation to specified format


$date3 = new Zend_Date('Feb 31, 2007', 'MM.dd.yyyy');
echo $date3, "\n"; // outputs "Mar 3, 2007 12:00:00 AM"

If the optional $locale parameter is provided, then the $locale disambiguates the
$date operand by replacing month and weekday names for string $date operands, and
even parsing date strings expressed according to the conventions of that locale (see
Zend_Locale_Format::getDate()). The automatic normalization of localized $date operands of
a string type occurs when $part is one of the Zend_Date::DATE* or Zend_Date::TIME*
constants. The locale identifies which language should be used to parse month names and
weekday names, if the $date is a string containing a date. If there is no $date input parameter,
then the $locale parameter specifies the locale to use for localizing output (e.g. the date format
for a string representation). Note that the $date input parameter might actually have a type name
instead (e.g. $hour for addHour()), although that does not prevent the use of Zend_Date
objects as arguments for that parameter. If no $locale was specified, then the locale of the
current object is used to interpret $date, or select the localized format for output.

Since Zend Framework 1.7.0 Zend_Date does also support the usage of an application wide
locale. You can simply set a Zend_Locale instance to the registry like shown below. With this
notation you can forget about setting the locale manually with each instance when you want to
use the same locale multiple times.

// in your bootstrap file


$locale = new Zend_Locale('de_AT');
Zend_Registry::set('Zend_Locale', $locale);

// somewhere in your application


$date = new Zend_Date('31.Feb.2007');

4.3. Basic Zend_Date Operations Common to Many Date Parts


The methods add(), sub(), compare(), get(), and set() operate generically on dates.
In each case, the operation is performed on the date held in the instance object. The $date
operand is required for all of these methods, except get(), and may be a Zend_Date instance
object, a numeric string, or an integer. These methods assume $date is a timestamp, if it is
not an object. However, the $part operand controls which logical part of the two dates are
operated on, allowing operations on parts of the object's date, such as year or minute, even when
$date contains a long form date string, such as, "December 31, 2007 23:59:59". The result of
the operation changes the date in the object, except for compare(), and get().

Exemple 120. Operating on Parts of Dates

$date = new Zend_Date(); // $date's timestamp === time()

// changes $date by adding 12 hours


$date->add('12', Zend_Date::HOUR);
print $date;

396
Zend_Date

Convenience methods exist for each combination of the basic operations and several common
date parts as shown in the tables below. These convenience methods help us lazy programmers
avoid having to type out the date part constants when using the general methods above.
Conveniently, they are named by combining a prefix (name of a basic operation) with a suffix
(type of date part), such as addYear(). In the list below, all combinations of "Date Parts" and
"Basic Operations" exist. For example, the operation "add" exists for each of these date parts,
including addDay(), addYear(), etc.

These convenience methods have the same equivalent functionality as the basic operation
methods, but expect string and integer $date operands containing only the values representing
the type indicated by the suffix of the convenience method. Thus, the names of these methods
(e.g. "Year" or "Minute") identify the units of the $date operand, when $date is a string or
integer.

4.3.1. List of Date Parts

Tableau 33. Date Parts

Date Part Explanation


Timestamp UNIX timestamp, expressed in seconds
elapsed since January 1st, 1970 00:00:00
GMT.
Year Gregorian calendar year (e.g. 2006)
Month Gregorian calendar month (1-12, localized
names supported)
24 hour clock Hours of the day (0-23) denote the hours
elapsed, since the start of the day.
minute Minutes of the hour (0-59) denote minutes
elapsed, since the start of the hour.
Second Seconds of the minute (0-59) denote the
elapsed seconds, since the start of the minute.
millisecond Milliseconds denote thousandths of a
second (0-999). Zend_Date supports two
additional methods for working with
time units smaller than seconds. By
default, Zend_Date instances use a
precision defaulting to milliseconds, as
seen using getFractionalPrecision().
To change the precision use
setFractionalPrecision($precision).
However, precision is limited practically
to microseconds, since Zend_Date uses
microtime().
Day Zend_Date::DAY_SHORT is extracted from
$date if the $date operand is an instance of
Zend_Date or a numeric string. Otherwise, an
attempt is made to extract the day according
to the conventions documented for these
constants: Zend_Date::WEEKDAY_NARROW,
Zend_Date::WEEKDAY_NAME,
Zend_Date::WEEKDAY_SHORT,

397
Zend_Date

Date Part Explanation


Zend_Date::WEEKDAY (Gregorian calendar
assumed)
Week Zend_Date::WEEK is extracted from $date
if the $date operand is an instance of
Zend_Date or a numeric string. Otherwise
an exception is raised. (Gregorian calendar
assumed)
Date Zend_Date::DAY_MEDIUM is extracted from
$date if the $date operand is an instance
of Zend_Date. Otherwise, an attempt is
made to normalize the $date string into a
Zend_Date::DATE_MEDIUM formatted date.
The format of Zend_Date::DAY_MEDIUM
depends on the object's locale.
Weekday Weekdays are represented numerically as
0 (for Sunday) through 6 (for Saturday).
Zend_Date::WEEKDAY_DIGIT is extracted
from $date, if the $date operand
is an instance of Zend_Date or a
numeric string. Otherwise, an attempt is
made to extract the day according to
the conventions documented for these
constants: Zend_Date::WEEKDAY_NARROW,
Zend_Date::WEEKDAY_NAME,
Zend_Date::WEEKDAY_SHORT,
Zend_Date::WEEKDAY (Gregorian calendar
assumed)
DayOfYear In Zend_Date, the day of the year represents
the number of calendar days elapsed since
the start of the year (0-365). As with other
units above, fractions are rounded down to
the nearest whole number. (Gregorian calendar
assumed)
Arpa Arpa dates (i.e. RFC 822 formatted dates)
are supported. Output uses either a "GMT"
or "Local differential hours+min" format (see
section 5 of RFC 822). Before PHP 5.2.2,
using the DATE_RFC822 constant with PHP
date functions sometimes produces incorrect
results. Zend_Date's results are correct.
Example: Mon, 31 Dec 06 23:59:59 GMT
Iso Only complete ISO 8601 dates
are supported for output. Example:
2009-02-14T00:31:30+01:00

4.3.2. List of Date Operations

The basic operations below can be used instead of the convenience operations for specific date
parts, if the appropriate constant is used for the $part parameter.

398
Zend_Date

Tableau 34. Basic Operations


Basic Operation Explanation
get() get($part = null, $locale = null)

Use get($part) to retrieve the date $part


of this object's date localized to $locale as
a formatted string or integer. When using the
BCMath extension, numeric strings might be
returned instead of integers for large values.

Behaviour of get()
Unlike get(), the other get*()
convenience methods only
return instances of Zend_Date
containing a date representing
the selected or computed date
or time.
set() set($date, $part = null, $locale =
null)

Sets the $part of the current object to the


corresponding value for that part found in the
input $date having a locale $locale.
add() add($date, $part = null, $locale =
null)

Adds the $part of $date having a locale


$locale to the current object's date.
sub() sub($date, $part = null, $locale =
null)

Subtracts the $part of $date having a locale


$locale from the current object's date.
copyPart() copyPart($part, $locale = null)

Returns a cloned object, with only $part of


the object's date copied to the clone, with the
clone have its locale arbitrarily set to $locale
(if specified).
compare() compare($date, $part = null,
$locale = null)

compares $part of $date to this object's


timestamp, returning 0 if they are equal, 1 if
this object's part was more recent than $date's
part, otherwise -1.

4.4. Comparing Dates


The following basic operations do not have corresponding convenience methods for the date
parts listed in Zend_Date API Overview.

399
Zend_Date

Tableau 35. Date Comparison Methods

Method Explanation
equals() equals($date, $part = null, $locale
= null)

returns TRUE, if $part of $date having locale


$locale is the same as this object's date
$part, otherwise FALSE
isEarlier() isEarlier($date, $part = null,
$locale = null)

returns TRUE, if $part of this object's date is


earlier than $part of $date having a locale
$locale
isLater() isLater($date, $part = null,
$locale = null)

returns TRUE, if $part of this object's date


is later than $part of $date having a locale
$locale
isToday() isToday()

Tests if today's year, month, and day match


this object's date value, using this object's
timezone.
isTomorrow() isTomorrow()

Tests if tomorrow's year, month, and day match


this object's date value, using this object's
timezone.
isYesterday() isYesterday()

Tests if yesterday's year, month, and day


match this object's date value, using this
object's timezone.
isLeapYear() isLeapYear()

Use isLeapYear() to determine if the


current object is a leap year, or use
Zend_Date::checkLeapYear($year) to
check $year, which can be a string, integer,
or instance of Zend_Date. Is the year a leap
year?
isDate() isDate($date, $format = null,
$locale = null)

This method checks if a given date is a real date


and returns TRUE if all checks are ok. It works
like PHP's checkdate() function but can also
check for localized month names and for dates
extending the range of checkdate()

400
Zend_Date

4.5. Getting Dates and Date Parts


Several methods support retrieving values related to a Zend_Date instance.

Tableau 36. Date Output Methods


Method Explanation
toString() toString($format = null, $locale =
null)

Invoke directly or via the magic method


__toString(). The toString() method
automatically formats the date object's value
according to the conventions of the object's
locale, or an optionally specified $locale. For
a list of supported format codes, see Self-
Defined OUTPUT Formats with ISO.
toArray() toArray()

Returns an array representation of the selected


date according to the conventions of the
object's locale. The returned array is equivalent
to PHP's getdate() function and includes:

• Number of day as
'day' (Zend_Date::DAY_SHORT)

• Number of month as
'month' (Zend_Date::MONTH_SHORT)

• Year as 'year' (Zend_Date::YEAR)

• Hour as 'hour' (Zend_Date::HOUR_SHORT)

• Minute as
'minute' (Zend_Date::MINUTE_SHORT)

• Second as
'second' (Zend_Date::SECOND_SHORT)

• Abbreviated timezone as
'timezone' (Zend_Date::TIMEZONE)

• Unix timestamp as
'timestamp' (Zend_Date::TIMESTAMP)

• Number of weekday as
'weekday' (Zend_Date::WEEKDAY_DIGIT)

• Day of year as
'dayofyear' (Zend_Date::DAY_OF_YEAR)

• Week as 'week' (Zend_Date::WEEK)

• Delay of timezone to GMT as


'gmtsecs' (Zend_Date::GMT_SECS)

401
Zend_Date

Method Explanation
toValue() toValue($part = null)

Returns an integer representation of


the selected date $part according
to the conventions of the object's
locale. Returns FALSE when $part
selects a non-numeric value, such as
Zend_Date::MONTH_NAME_SHORT.

Limitation of toValue()
This method calls get()
and casts the result to
a PHP integer, which will
give unpredictable results, if
get() returns a numeric string
containing a number too large
for a PHP integer on your
system. Use get() instead.
get() get($part = null, $locale = null)

This method returns the $part of object's date


localized to $locale as a formatted string or
integer. See get() for more information.
now() now($locale = null)

This convenience function is equivalent to new


Zend_Date(). It returns the current date as a
Zend_Date object, having $locale

4.6. Working with Fractions of Seconds


Several methods support retrieving values related to a Zend_Date instance.

Tableau 37. Date Output Methods

Method Explanation
getFractionalPrecision() Return the precision of the part seconds
setFractionalPrecision() Set the precision of the part seconds

4.7. Sunrise / Sunset


Three methods provide access to geographically localized information about the Sun, including
the time of sunrise and sunset.

Tableau 38. Miscellaneous Methods

Method Explanation
getSunrise($location) Return the date's time of sunrise
getSunset($location) Return the date's time of sunset

402
Zend_Date

Method Explanation
getSunInfo($location) Return an array with the date's sun dates

5. Créer des dates


Zend_Date permet de créer des instances d'elle même de plusieurs manières différentes. Nous
allons voir ceci.

5.1. Créer la date actuelle


La manière la plus simple de créer la date actuelle est d'utiliser le constructeur new
Zend_Date() ou encore la méthode statique Zend_Date::now(). Toutes les deux retournent
une instance de Zend_Date avec la date actuelle. Elle est représentée par une date calendaire
et un temps pour le fuseau horaire actuel du serveur.

Exemple 121. Créer une date par instance

Il n'y a pas de paramètres à passer au constructeur pour récupérer un objet Zend_Date.


Certains paramètres sont cependant disponibles et nous y reviendrons.

$date = new Zend_Date();

Exemple 122. Créer une date par méthode statique

La méthode statique now() a exactement le même effet qu'un passage par le constructeur.
Cependant la méthode statique, elle, ne peut pas prendre de paramètres additionnels.

$date = Zend_Date::now();

5.2. Créer une date depuis une base de données


Les bases de données sont souvent utilisées pour stocker des informations de dates. Mais
elles ont toutes une implémentation et une représentation qui leur est propre. MSSQL par
exemple manipule les dates de manières significativement différente de MySQL, par exemple.
Heureusement, Zend_Date aide à simplifier le processus de création d'une date depuis une
base de données.

Il est possible de demander au serveur de base de données de formater la date dans un certain
format. Mais ceci reste en général assez lourd, et doit être pensé à chaque fois.

Nous avons donc des méthodes très pratiques et rapides dans Zend_Date, pour récupérer les
dates depuis une base de données.

Exemple 123. Création d'une date depuis une base de données

Toutes les bases de données doivent répondre extrêmement rapidement à leurs requêtes.
Pour stocker une date de manière optimale dans une base, il faut utiliser un timestamp. En
interne, tous les SGBDs représentent les dates sous forme de timestamp (non Unix). Ainsi,
leur demander un timestamp sera toujours plus performant que de leur demander une date
dans un format précis.

// SELECT UNIX_TIMESTAMP(my_datetime_column) FROM my_table


$date = new Zend_Date($unixtimestamp, Zend_Date::TIMESTAMP);

403
Zend_Date

Exemple 124. Création d'une date depuis une base de données dans un format

La sortie de chaque base de données est différente même si elles se ressemblent.


Cependant elles ont toutes des formats compatibles ISO. La manière la plus simple de
créer une date depuis une base de données est d'utiliser Zend_Date::ISO_8601. Les
SGBDs connus pour être conformes pour Zend_Date::ISO_8601 sont MySQL, MSSQL
par exemple, mais ils sont tous capables de retourner une représentation ISO8601 d'une
donnée date. ISO8601 possède l'avantage d'être lisible et compréhensible par un humain.
Son inconvénient est qu'il est légèrement plus lourd à traiter qu'un simple timestamp UNIX.
En revanche ceux-ci ne supportent pas les dates inférieures au 1er Janvier 1970.

// SELECT datecolumn FROM my_table


$date = new Zend_Date($datecolumn, Zend_Date::ISO_8601);

5.3. Créer des dates depuis un tableau


Créer une date depuis un tableau est fréquent et pratique. Les clés du tableau sont :

• day : jour de la date, un nombre

• month : mois de la date, un nombre

• year : année complète de la date

• hour : heures de la date

• minute : minutes de la date

• second : secondes de la date

Exemple 125. Créer une date depuis un tableau

En temps normal on utilisera un tableau avec toutes ses clés. Si une clé est absente, la
valeur qu'elle représente sera mise à la valeur zéro par défaut. Par exemple une tableau
ne comportant pas la clé "hour", donnera naissance à une date ayant une partie heures
à la valeur "0".

$datearray = array('year' => 2006,


'month' => 4,
'day' => 18,
'hour' => 12,
'minute' => 3,
'second' => 10);
$date = new Zend_Date($datearray);

$datearray = array('year' => 2006, 'month' => 4, 'day' => 18);


$date = new Zend_Date($datearray);

6. Constants for General Date Functions


Whenever a Zend_Date method has a $parts parameter, one of the constants below can be
used as the argument for that parameter, in order to select a specific part of a date or indicate
the date format used or desired (e.g. RFC 822).

6.1. Using Constants


For example, the constant Zend_Date::HOUR can be used in the ways shown below. When
working with days of the week, calendar dates, hours, minutes, seconds, and any other date

404
Zend_Date

parts that are expressed differently when in different parts of the world, the object's timezone
will automatically be used to compute the correct value, even though the internal timestamp is
the same for the same moment in time, regardless of the user's physical location in the world.
Regardless of the units involved, output must be expressed either as GMT or UTC or localized to
a locale. The example output below reflects localization to Europe/GMT+1 hour (e.g. Germany,
Austria, France).

Tableau 39. Operations Involving Zend_Date::HOUR

Method Description Original date Result


Output of the hour
get(Zend_Date::HOUR) 2009-02-13T14:53:27+01:00
14
set(12, Set new hour 2009-02-13T14:53:27+01:00
2009-02-13T12:53:27+01:00
Zend_Date::HOUR)
add(12, Add hours 2009-02-13T14:53:27+01:00
2009-02-14T02:53:27+01:00
Zend_Date::HOUR)
sub(12, Subtract hours 2009-02-13T14:53:27+01:00
2009-02-13T02:53:27+01:00
Zend_Date::HOUR)
compare(12, Compare hour, returns 2009-02-13T14:53:27+01:00
1 (if object > argument)
Zend_Date::HOUR) 0, 1 or -1
Copies only the hour 2009-02-13T14:53:27+01:00
copy(Zend_Date::HOUR) 1970-01-01T14:00:00+01:00
part
equals(14, Compares the hour, 2009-02-13T14:53:27+01:00
TRUE
Zend_Date::HOUR) returns TRUE or FALSE
isEarlier(12, Compares the hour, 2009-02-13T14:53:27+01:00
TRUE
Zend_Date::HOUR) returns TRUE or FALSE
isLater(12, Compares the hour, 2009-02-13T14:53:27+01:00
FALSE
Zend_Date::HOUR) returns TRUE or FALSE

6.2. List of All Constants


Each part of a date or time has a unique constant in Zend_Date. All constants supported by
Zend_Date are listed below.

Tableau 40. Day Constants

Constant Description Date Result


Zend_Date::DAY Day (as number, two 2009-02-13T14:53:27+01:00
13
digits)
Day (as number, one 2009-02-06T14:53:27+01:00
Zend_Date::DAY_SHORT 6
or two digits)
Zend_Date::WEEKDAYWeekday (Name of 2009-02-13T14:53:27+01:00
Friday
the day, localized,
complete)
Weekday (Name of 2009-02-13T14:53:27+01:00
Zend_Date::WEEKDAY_SHORT Fri for Friday
the day, localized,
abbreviated, two to
four chars)
Weekday (Name of 2009-02-13T14:53:27+01:00
Zend_Date::WEEKDAY_NAME Fr for Friday
the day, localized,

405
Zend_Date

Constant Description Date Result


abbreviated, one or
two chars)
Weekday (Name of 2009-02-13T14:53:27+01:00
Zend_Date::WEEKDAY_NARROW F for Friday
the day, localized,
abbreviated, one char)
Weekday (0 = Sunday, 2009-02-13T14:53:27+01:00
Zend_Date::WEEKDAY_DIGIT 5 for Friday
6 = Saturday)
Weekday according to 2009-02-13T14:53:27+01:00
Zend_Date::WEEKDAY_8601 5 for Friday
ISO 8601 (1 = Monday,
7 = Sunday)
Day (as a number, one 2009-02-13T14:53:27+01:00
Zend_Date::DAY_OF_YEAR 43
or two digits)
English addendum for 2009-02-13T14:53:27+01:00
Zend_Date::DAY_SUFFIX th
the day (st, nd, rd, th)

Tableau 41. Week Constants


Constant Description Date Result
Zend_Date::WEEK Week (as number, 2009-02-13T14:53:27+01:00
8
1-53)

Tableau 42. Month Constants


Constant Description Date Result
Month
Zend_Date::MONTH_NAME (Name of 2009-02-13T14:53:27+01:00
February
the month, localized,
complete)
Month
Zend_Date::MONTH_NAME_SHORT (Name of 2009-02-13T14:53:27+01:00
Feb
the month, localized,
abbreviated, two to
four chars)
Month
Zend_Date::MONTH_NAME_NARROW(Name of 2009-02-13T14:53:27+01:00
F
the month, localized,
abbreviated, one or
two chars)
Zend_Date::MONTH Month (Number of the 2009-02-13T14:53:27+01:00
02
month, two digits)
Month (Number of the 2009-02-13T14:53:27+01:00
Zend_Date::MONTH_SHORT 2
month, one or two
digits)
Number of days for this 2009-02-13T14:53:27+01:00
Zend_Date::MONTH_DAYS 28
month (number)

Tableau 43. Year Constants


Constant Description Date Result
Zend_Date::YEAR Year (number) 2009-02-13T14:53:27+01:00
2009
Year according to ISO 2009-02-13T14:53:27+01:00
Zend_Date::YEAR_8601 2009
8601 (number)

406
Zend_Date

Constant Description Date Result


Year (number,
Zend_Date::YEAR_SHORT two 2009-02-13T14:53:27+01:00
09
digits)
Year according to ISO 2009-02-13T14:53:27+01:00
Zend_Date::YEAR_SHORT_8601 09
8601 (number, two
digits)
Is the year a leap year? 2009-02-13T14:53:27+01:00
Zend_Date::LEAPYEAR FALSE
(TRUE or FALSE)

Tableau 44. Time Constants

Constant Description Date Result


Zend_Date::HOUR Hour (00-23, two 2009-02-13T14:53:27+01:00
14
digits)
Hour (0-23, one or two 2009-02-13T14:53:27+01:00
Zend_Date::HOUR_SHORT 14
digits)
Hour (1-12, one or two 2009-02-13T14:53:27+01:00
Zend_Date::HOUR_SHORT_AM 2
digits)
Zend_Date::HOUR_AMHour (01-12, two 2009-02-13T14:53:27+01:00
02
digits)
Zend_Date::MINUTE Minute (00-59, two 2009-02-13T14:53:27+01:00
53
digits)
Minute (0-59, one or 2009-02-13T14:03:27+01:00
Zend_Date::MINUTE_SHORT 3
two digits)
Zend_Date::SECOND Second (00-59, two 2009-02-13T14:53:27+01:00
27
digits)
Second (0-59, one or 2009-02-13T14:53:07+01:00
Zend_Date::SECOND_SHORT 7
two digits)
Millisecond
Zend_Date::MILLISECOND 2009-02-06T14:53:27.20546
20546
(theoretically infinite)
Time of day (forenoon 2009-02-13T14:53:27+01:00
Zend_Date::MERIDIEM afternoon
or afternoon)
Zend_Date::SWATCH Swatch Internet Time 2009-02-13T14:53:27+01:00
620

Tableau 45. Timezone Constants

Constant Description Date Result


Name der time zone 2009-02-13T14:53:27+01:00
Zend_Date::TIMEZONE CET
(string, abbreviated)
Name of the time zone 2009-02-13T14:53:27+01:00
Zend_Date::TIMEZONE_NAME Europe/Paris
(string, complete)
Difference of the time 2009-02-13T14:53:27+01:00
Zend_Date::TIMEZONE_SECS 3600 (seconds to
zone to GMT in GMT)
seconds (integer)
Difference to GMT in 2009-02-13T14:53:27+01:00
Zend_Date::GMT_DIFF +0100
seconds (string)

407
Zend_Date

Constant Description Date Result


Difference to GMT 2009-02-13T14:53:27+01:00
Zend_Date::GMT_DIFF_SEP +01:00
in seconds (string,
separated)
Summer time or Winter 2009-02-13T14:53:27+01:00
Zend_Date::DAYLIGHT FALSE
time? (TRUE or FALSE)

Tableau 46. Date Format Constants (formats include timezone)


Constant Description Date Result
Date according to ISO 2009-02-13T14:53:27+01:00
Zend_Date::ISO_8601 2009-02-13T14:53:27+01:00
8601 (string, complete)
Date according to RFC 2009-02-13T14:53:27+01:00
Zend_Date::RFC_2822 Fri, 13 Feb 2009
2822 (string) 14:53:27 +0100
Unix time (seconds 2009-02-13T14:53:27+01:00
Zend_Date::TIMESTAMP 1234533207
since 1.1.1970, mixed)
Zend_Date::ATOM Date according to 2009-02-13T14:53:27+01:00
2009-02-13T14:53:27+01:00
ATOM (string)
Zend_Date::COOKIE Date for Cookies 2009-02-13T14:53:27+01:00
Friday, 13-Feb-09
(string, for Cookies) 14:53:27 Europe/
Paris
Zend_Date::RFC_822Date according to RFC 2009-02-13T14:53:27+01:00
Fri, 13 Feb 09 14:53:27
822 (string) +0100
Zend_Date::RFC_850Date according to RFC 2009-02-13T14:53:27+01:00
Friday, 13-Feb-09
850 (string) 14:53:27 Europe/
Paris
Date according to RFC 2009-02-13T14:53:27+01:00
Zend_Date::RFC_1036 Fri, 13 Feb 09 14:53:27
1036 (string) +0100
Date according to RFC 2009-02-13T14:53:27+01:00
Zend_Date::RFC_1123 Fri, 13 Feb 2009
1123 (string) 14:53:27 +0100
Zend_Date::RSS Date for RSS Feeds 2009-02-13T14:53:27+01:00
Fri, 13 Feb 2009
(string) 14:53:27 +0100
Zend_Date::W3C Date for HTML or 2009-02-13T14:53:27+01:00
2009-02-13T14:53:27+01:00
HTTP according to
W3C (string)

Especially note Zend_Date::DATES, since this format specifier has a unique property within
Zend_Date as an input format specifier. When used as an input format for $part, this constant
provides the most flexible acceptance of a variety of similar date formats. Heuristics are used to
automatically extract dates from an input string and then "fix" simple errors in dates (if any), such
as swapping of years, months, and days, when possible.

Tableau 47. Date and Time Formats (format varies by locale)


Constant Description Date Result
Zend_Date::ERA Epoch (string, 2009-02-13T14:53:27+01:00
AD (anno Domini)
localized, abbreviated)
Epoch
Zend_Date::ERA_NAME (string, 2009-02-13T14:53:27+01:00
anno domini (anno
localized, complete) Domini)

408
Zend_Date

Constant Description Date Result


Zend_Date::DATES Standard date (string, 2009-02-13T14:53:27+01:00
13.02.2009
localized, default
value).
Complete date (string, 2009-02-13T14:53:27+01:00
Zend_Date::DATE_FULL Friday, 13. February
localized, complete) 2009
Long date (string, 2009-02-13T14:53:27+01:00
Zend_Date::DATE_LONG 13. February 2009
localized, long)
Normal date (string, 2009-02-13T14:53:27+01:00
Zend_Date::DATE_MEDIUM 13.02.2009
localized, normal)
Abbreviated
Zend_Date::DATE_SHORT Date 2009-02-13T14:53:27+01:00
13.02.09
(string, localized,
abbreviated)
Zend_Date::TIMES Standard time (string, 2009-02-13T14:53:27+01:00
14:53:27
localized, default
value)
Complete time (string, 2009-02-13T14:53:27+01:00
Zend_Date::TIME_FULL 14:53 Uhr CET
localized, complete)
Long time (string, 2009-02-13T14:53:27+01:00
Zend_Date::TIME_LONG 14:53:27 CET
localized, Long)
Normal time (string, 2009-02-13T14:53:27+01:00
Zend_Date::TIME_MEDIUM 14:53:27
localized, normal)
Abbreviated
Zend_Date::TIME_SHORT time 2009-02-13T14:53:27+01:00
14:53
(string, localized,
abbreviated)
Standard date with 2009-02-13T14:53:27+01:00
Zend_Date::DATETIME 13.02.2009 14:53:27
time (string, localized,
default value).
Complete date with 2009-02-13T14:53:27+01:00
Zend_Date::DATETIME_FULL Friday, 13. February
time (string, localized, 2009 14:53 Uhr CET
complete)
Long date with time 2009-02-13T14:53:27+01:00
Zend_Date::DATETIME_LONG 13. February 2009
(string, localized, long) 14:53:27 CET
Normal
Zend_Date::DATETIME_MEDIUM date with 2009-02-13T14:53:27+01:00
13.02.2009 14:53:27
time (string, localized,
normal)
Abbreviated date with 2009-02-13T14:53:27+01:00
Zend_Date::DATETIME_SHORT 13.02.09 14:53
time (string, localized,
abbreviated)

6.3. Self-Defined OUTPUT Formats with ISO


If you need a date format not shown above, then use a self-defined format composed from the
ISO format token specifiers below. The following examples illustrate the usage of constants from
the table below to create self-defined ISO formats. The format length is unlimited. Also, multiple
usage of format constants is allowed.

409
Zend_Date

The accepted format specifiers can be changed from ISO Format to PHP's date format if you are
more comfortable with it. However, not all formats defined in the ISO norm are supported with
PHP's date format specifiers. Use the Zend_Date::setOptions(array('format_type'
=> 'php')) method to switch Zend_Date methods from supporting ISO format specifiers to
PHP date() type specifiers (see Self-Defined OUTPUT Formats Using PHP's date() Format
Specifiers below).

Exemple 126. Self-Defined ISO Formats

$locale = new Zend_Locale('de_AT');


$date = new Zend_Date(1234567890, false, $locale);
print $date->toString("'Era:GGGG='GGGG, ' Date:yy.MMMM.dd'yy.MMMM.dd");

Tableau 48. Constants for ISO 8601 Date Output

Constant Description Corresponds best to Result


G Epoch, localized, Zend_Date::ERA AD
abbreviated
GG Epoch, localized, Zend_Date::ERA AD
abbreviated
GGG Epoch, localized, Zend_Date::ERA AD
abbreviated
GGGG Epoch, localized, Zend_Date::ERA_NAME
anno domini
complete
GGGGG Epoch, localized, Zend_Date::ERA a
abbreviated
y Year, at least one digit Zend_Date::YEAR 9
yy Year, at least two digit Zend_Date::YEAR_SHORT
09
yyy Year, at least three Zend_Date::YEAR 2009
digit
yyyy Year, at least four digit Zend_Date::YEAR 2009
yyyyy Year, at least five digit Zend_Date::YEAR 02009
Y Year according to ISO Zend_Date::YEAR_8601
9
8601, at least one digit
YY Year according to ISO Zend_Date::YEAR_SHORT_8601
09
8601, at least two digit
YYY Year according to ISO Zend_Date::YEAR_8601
2009
8601, at least three
digit
YYYY Year according to ISO Zend_Date::YEAR_8601
2009
8601, at least four digit
YYYYY Year according to ISO Zend_Date::YEAR_8601
02009
8601, at least five digit
M Month, one or two digit Zend_Date::MONTH_SHORT
2
MM Month, two digit Zend_Date::MONTH 02
MMM Month, localized, Zend_Date::MONTH_NAME_SHORT
Feb
abbreviated

410
Zend_Date

Constant Description Corresponds best to Result


MMMM Month, localized, Zend_Date::MONTH_NAME
February
complete
MMMMM Month, localized, Zend_Date::MONTH_NAME_NARROW
F
abbreviated, one digit
w Week, one or two digit Zend_Date::WEEK 5
ww Week, two digit Zend_Date::WEEK 05
d Day of the month, one Zend_Date::DAY_SHORT
9
or two digit
dd Day of the month, two Zend_Date::DAY 09
digit
D Day of the year, one, Zend_Date::DAY_OF_YEAR
7
two or three digit
DD Day of the year, two or Zend_Date::DAY_OF_YEAR
07
three digit
DDD Day of the year, three Zend_Date::DAY_OF_YEAR
007
digit
E Day of the week, Zend_Date::WEEKDAY_NARROW
M
localized, abbreviated,
one char
EE Day of the week, Zend_Date::WEEKDAY_NAME
Mo
localized, abbreviated,
two or more chars
EEE Day of the week, Zend_Date::WEEKDAY_SHORT
Mon
localized, abbreviated,
three chars
EEEE Day of the week, Zend_Date::WEEKDAYMonday
localized, complete
EEEEE Day of the week, Zend_Date::WEEKDAY_NARROW
M
localized, abbreviated,
one digit
e Number of the day, Zend_Date::WEEKDAY_DIGIT
4
one digit
ee Number of the day, two Zend_Date::WEEKDAY_NARROW
04
digit
a Time of day, localized Zend_Date::MERIDIEM
vorm.
h Hour, (1-12), one or Zend_Date::HOUR_SHORT_AM
2
two digit
hh Hour, (01-12), two digit Zend_Date::HOUR_AM02
H Hour, (0-23), one or Zend_Date::HOUR_SHORT
2
two digit
HH Hour, (00-23), two digit Zend_Date::HOUR 02
m Minute, (0-59), one or Zend_Date::MINUTE_SHORT
2
two digit

411
Zend_Date

Constant Description Corresponds best to Result


mm Minute, (00-59), two Zend_Date::MINUTE 02
digit
s Second, (0-59), one or Zend_Date::SECOND_SHORT
2
two digit
ss Second, (00-59), two Zend_Date::SECOND 02
digit
S Millisecond 20536
Zend_Date::MILLISECOND
z Time zone, localized, Zend_Date::TIMEZONE
CET
abbreviated
zz Time zone, localized, Zend_Date::TIMEZONE
CET
abbreviated
zzz Time zone, localized, Zend_Date::TIMEZONE
CET
abbreviated
zzzz Time zone, localized, Zend_Date::TIMEZONE_NAME
Europe/Paris
complete
Z Difference of time zone Zend_Date::GMT_DIFF
+0100
ZZ Difference of time zone Zend_Date::GMT_DIFF
+0100
ZZZ Difference of time zone Zend_Date::GMT_DIFF
+0100
ZZZZ Difference of time Zend_Date::GMT_DIFF_SEP
+01:00
zone, separated
A Millisecond 20563
Zend_Date::MILLISECOND

Note that the default ISO format differs from PHP's format which can be irritating
if you have not used in previous. Especially the format specifiers for Year and
Minute are often not used in the intended way.

For year there are two specifiers available which are often mistaken. The Y
specifier for the ISO year and the y specifier for the real year. The difference is
small but significant. Y calculates the ISO year, which is often used for calendar
formats. See for example the 31. December 2007. The real year is 2007, but it is
the first day of the first week in the week 1 of the year 2008. So, if you are using
'dd.MM.yyyy' you will get '31.December.2007' but if you use 'dd.MM.YYYY' you
will get '31.December.2008'. As you see this is no bug but a expected behaviour
depending on the used specifiers.

For minute the difference is not so big. ISO uses the specifier m for the minute,
unlike PHP which uses i. So if you are getting no minute in your format check if
you have used the right specifier.

6.4. Self-Defined OUTPUT Formats Using PHP's date() Format


Specifiers
If you are more comfortable with PHP's date format specifier than with ISO format specifiers,
then you can use the Zend_Date::setOptions(array('format_type' => 'php'))
method to switch Zend_Date methods from supporting ISO format specifiers to PHP date()
type specifiers. Afterwards, all format parameters must be given with PHP's date() format
specifiers. The PHP date format lacks some of the formats supported by the ISO Format, and

412
Zend_Date

vice-versa. If you are not already comfortable with it, then use the standard ISO format instead.
Also, if you have legacy code using PHP's date format, then either manually convert it to the
ISO format using Zend_Locale_Format::convertPhpToIsoFormat(), or use setOptions(). The
following examples illustrate the usage of constants from the table below to create self-defined
formats.

Exemple 127. Self-Defined Formats with PHP Specifier

$locale = new Zend_Locale('de_AT');


Zend_Date::setOptions(array('format_type' => 'php'));
$date = new Zend_Date(1234567890, false, $locale);

// outputs something like 'February 16, 2007, 3:36 am'


print $date->toString('F j, Y, g:i a');

print $date->toString("'Format:D M j G:i:s T Y='D M j G:i:s T Y");

PHP Date format and using constants


It is important to note that Zend_Date's constants are using the ISO notation.
This means, that when you set Zend_Date to use the PHP notation, you should
not use Zend_Date's constants, but define the wished format manually. If you
don't follow this recommendation, you can get unexpected results.

The following table shows the list of PHP date format specifiers with their equivalent Zend_Date
constants and CLDR and ISO equivalent format specifiers. In most cases, when the CLDR and
ISO format does not have an equivalent format specifier, the PHP format specifier is not altered by
Zend_Locale_Format::convertPhpToIsoFormat(), and the Zend_Date methods then
recognize these "peculiar" PHP format specifiers, even when in the default "ISO" format mode.

Tableau 49. Constants for PHP Date Output


Constant Description Corresponds closest CLDR Result
best to equivalent
d Day of the month, Zend_Date::DAYdd 09
two digit
D Day of the Zend_Date::WEEKDAY_SHORT
EEE Mon
week, localized,
abbreviated,
three digit
j Day of the month, Zend_Date::DAY_SHORT
d 9
one or two digit
l (lowercase L) Day of the Zend_Date::WEEKDAY
EEEE Monday
week, localized,
complete
N Number of the Zend_Date::WEEKDAY_8601
e 4
weekday, one
digit
S English suffixes no equivalent no equivalent st
for day of month,
two chars
w Number of the Zend_Date::WEEKDAY_DIGIT
no equivalent 4
weekday,

413
Zend_Date

Constant Description Corresponds closest CLDR Result


best to equivalent
0=sunday,
6=saturday
z Day of the year, Zend_Date::DAY_OF_YEAR
D 7
one, two or three
digit
W Week, one or two Zend_Date::WEEK
w 5
digit
F Month, localized, Zend_Date::MONTH_NAME
MMMM February
complete
m Month, two digit MM
Zend_Date::MONTH 02
M Month, localized, Zend_Date::MONTH_NAME_SHORT
MMM Feb
abbreviated
n Month, one or two Zend_Date::MONTH_SHORT
M 2
digit
t Number of days Zend_Date::MONTH_DAYS
no equivalent 30
per month, one or
two digits
L Leapyear, no equivalent
Zend_Date::LEAPYEAR TRUE
boolean
o Year according to Zend_Date::YEAR_8601
YYYY 2009
ISO 8601, at least
four digit
Y Year, at least four Zend_Date::YEAR
yyyy 2009
digit
y Year, at least two Zend_Date::YEAR_SHORT
yy 09
digit
a Time of day, Zend_Date::MERIDIEM
a (sort of, but vorm.
localized likely to be
uppercase)
A Time of day, Zend_Date::MERIDIEM
a (sort of, but VORM.
localized no guarantee that
the format is
uppercase)
B Swatch internet Zend_Date::SWATCH
no equivalent 1463
time
g Hour, (1-12), one Zend_Date::HOUR_SHORT_AM
h 2
or two digit
G Hour, (0-23), one Zend_Date::HOUR_SHORT
H 2
or two digit
h Hour, (01-12), two Zend_Date::HOUR_AM
hh 02
digit
H Hour, (00-23), two Zend_Date::HOUR
HH 02
digit

414
Zend_Date

Constant Description Corresponds closest CLDR Result


best to equivalent
i Minute, (00-59), Zend_Date::MINUTE
mm 02
two digit
s Second, (00-59), Zend_Date::SECOND
ss 02
two digit
e Time zone, Zend_Date::TIMEZONE_NAME
zzzz Europe/Paris
localized,
complete
I Daylight no equivalent
Zend_Date::DAYLIGHT 1
O Difference of time Zend_Date::GMT_DIFF
Z or ZZ or ZZZ +0100
zone
P Difference of time Zend_Date::GMT_DIFF_SEP
ZZZZ +01:00
zone, separated
T Time zone, Zend_Date::TIMEZONE
z or zz or zzz CET
localized,
abbreviated
Z Time zone offset Zend_Date::TIMEZONE_SECS
no equivalent 3600
in seconds
c Standard Iso Zend_Date::ISO_8601
no equivalent 2004-02-13T15:19:21+00:00
format output
r Standard Rfc Zend_Date::RFC_2822
no equivalent Thu, 21 Dec 2000
2822 format 16:01:07 +0200
output
U Unix timestamp no equivalent
Zend_Date::TIMESTAMP 15275422364

7. Exemples concrets
Dans ce chapitre, nous décrirons plusieurs fonctionnalités disponibles dans Zend_Date. Ceci
sera fait au travers d'exemples concrets.

7.1. Vérifier des dates


La plupart du temps vous devrez traiter des dates issues d'entrées de vos scripts, sous
forme de chaînes de caractères. Le problème avec les chaînes est que l'on ne sait pas si
elles représentent réellement une date. Ainsi, Zend_Date possède une méthode statique
pour vérifier cela. Zend_Locale a aussi une fonction getDate($date, $locale); qui
analyse et retourne la date correctement normalisée. Le nom d'un mois, par exemple, sera
reconnu et sera retourné comme entier. Étant donnée que le rôle de Zend_Locale est
l'aide à la localisation et l'internationalisation, c'est Zend_Date qui propose une fonction de
vérification :isDate($date).

isDate($date, $format, $locale); peut prendre jusqu'à 3 paramètres, 1 seul est


obligatoire. Le second paramètre exprime le format dans lequel la date doit se trouver. Si aucun
format n'est spécifié, alors le format par défaut de la locale en cours sera utilisé. Plus d'infos
sur les formats.

Le 3ème paramètre est aussi optionnel et peut être utilisé pour spécifier une locale. Celle-ci est
nécessaire afin de normaliser les noms des mois et des jours. Avec le 3ème paramètre fourni,

415
Zend_Date

des dates comme "01.Jänner.2000" ou "01.January.2000" pourront être reconnues en fonction


de la locale passée.

isDate(); bien sûr, vérifie que la date existe. Zend_Date ne vérifie pas une date elle-même.
Il est possible de créer une date avec "31.February.2000" dans Zend_Date, simplement la date
sera convertie automatiquement par Zend_Date en "03.March.2000". isDate() effectue cette
vérification et retournera FALSE sur "31.February.2000" car cette date n'existe pas.

Exemple 128. Vérifier des dates

// Vérification de dates
$date = '01.03.2000';
if (Zend_Date::isDate($date)) {
print "la chaine $date est une date";
} else {
print "la chaine $date n'est PAS une date";
}

// Vérification de dates localisées


$date = '01 February 2000';
if (Zend_Date::isDate($date,'dd MMMM yyyy', 'en')) {
print "la chaine $date est une date";
} else {
print "la chaine $date n'est PAS une date";
}

// Vérification de fausses dates


$date = '30 February 2000';
if (Zend_Date::isDate($date,'dd MMMM yyyy', 'en')) {
print "String $date is a date";
} else {
print "String $date is NO date";
}

7.2. Levé et couché du soleil


Zend_Date possède aussi des fonctionnalités pour se renseigner sur le soleil. Il peut être utile
dans une zone donnée, de savoir l'heure de levé et de couché du soleil. C'est très simple avec
Zend_Date, il suffit de lui fournir une date, certes, mais aussi un endroit depuis lequel ces
calculs seront faits.

Comme presque personne ne connaît la localisation précise d'une ville sur la planète, nous avons
aussi écrit une classe qui donne ces coordonnées, pour plus de 250 grandes villes et capitales.
Ainsi la plupart des gens pourra utiliser des villes proches de chez eux.

A cet effet, Zend_Date_Cities::getCityList peut être utilisée, cette méthode retourne les
noms de toutes les villes prédéfinies dans la classe d'aide.

Exemple 129. Récupérer toutes les villes disponibles

// Affiche la liste complète de toutes les villes disponibles


// dans la classe d'aide
print_r (Zend_Date_Cities::getCityList());

La localisation peut être récupérée avec Zend_Date_Cities::City(). Cette méthode prend


en paramètre le nom d'une ville, tel que retourné par Zend_Date_Cities::getCityList(),
et un second paramètre optionnel pour l'horizon.

416
Zend_Date

Il y a 4 horizons définis, qui peuvent être utilisés avec des lieux pour déterminer la date exacte
de levé et couché du soleil. Le paramètre "horizon" est toujours optionnel, quelle que soit la
fonction dans laquelle il est utilisé. S'il n'est pas précisé, la valeur "effective" lui sera attribuée
par défaut.

Tableau 50. Valeurs d'horizons supportées pour les levé et couché de soleil

Horizon Description Usage


effective Standard horizon Traite la Terre comme une
balle. C'est la valeur par
défaut.
civil Common horizon Utilisé dans les médias
courants, comme la TV ou la
radio
nautic Nautic horizon Utilisé en navigation
astronomic Astronomic horizon Utilisé pour le calcul avec des
étoiles

Évidemment, un endroit personnalisé peut aussi être utilisé pour le calcul. Une "latitude" et
une "longitude" seront alors nécessaires, en plus du paramètre optionnel "horizon".

Exemple 130. Trouver la localisation d'une ville

// Trouve la localisation d'une ville avec l'horizon effectif


print_r (Zend_Date_Cities::city('Vienna'));

// utilise l'horizon nautique


print_r (Zend_Date_Cities::city('Vienna', 'nautic'));

// Voici une ville personnalisée qui n'est pas dans la liste prédéfinie
$mylocation = array('latitude' => 41.5, 'longitude' => 13.2446);

Dès lors, il faut créer un objet Zend_Date contenant la date dont on veut connaître les
informations de levé et de couché du soleil. 3 méthodes nous seront proposées : getSunset(),
getSunrise() et getSunInfo(). Ces 3 méthodes s'appliquent sur un objet Zend_Date et
retournent un objet Zend_Date.

Exemple 131. Calculer les informations relatives au soleil

// Retrouve la localisation d'une ville


$city = Zend_Date_Cities::city('Vienna');

// Créer une date à partir de laquelle extraire


// les informations relatives au soleil
$date = new Zend_Date('10.03.2007', Zend_Date::ISO_8601, 'de');

// calcul du levé du soleil


$sunset = $date->getSunset($city);
print $sunset->get(Zend_Date::ISO_8601);

// calcul de toutes les informations solaires


$info = $date->getSunInfo($city);
foreach ($info as $sun) {
print "\n" . $sun->get(Zend_Date::ISO_8601);
}

417
Zend_Date

7.3. Fuseaux horaires (Timezones)


Les zones de temps (Timezones) sont aussi importantes que les dates en elles-mêmes. Il existe
plusieurs zones de temps (fuseaux horaires) sur la planète, et travailler avec des dates implique
de définir un fuseau horaire pour cette date. Ceci semble complexe mais c'est plutôt simple.
Comme déjà dit dans le premier chapitre sur Zend_Date, le fuseau horaire par défaut de PHP
doit être configuré. En général, le fichier php.ini est utilisé à cet effet, mais ce n'est pas l'unique
moyen.

Un objet Zend_Date encapsule son propre fuseau horaire. Même en changeant le fuseau après
la création de l'objet, celui-ci s'en souviendra. De même, changer le fuseau via PHP n'aura
aucun impact sur l'objet Zend_Date avec lequel un travail est en cours, c'est celui-ci qui va vous
permettre via des méthodes de gérer son fuseau.

getTimezone() retourne le fuseau horaire actuel sur lequel travaille Zend_Date. Souvenez
vous que Zend_Date n'est pas lié aux mécanismes interne de PHP, ainsi le fuseau retourné
peut être différent de celui sur lequel PHP est réglé.setTimezone($zone) change le fuseau
horaire actuel de l'objet Zend_Date. Le fuseau ainsi fournit est toujours vérifié, s'il n'existe pas,
une exception sera levée. Si vous ne spécifiez pas de fuseau à cette méthode, alors c'est le
fuseau interne de PHP qui sera utilisé par défaut, comme c'est le cas lors de la création d'un
objet Zend_Date banal.

Exemple 132. Travailler avec les fuseaux horaires (timezones)

// Règle le fuseau horaire PHP par défaut.


// En général, celui-ci est réglé dans php.ini.
// Ici nous le faisons pour l'exemple
date_default_timezone_set('Europe/Vienna');

// creation d'un objet date


$date = new Zend_Date('10.03.2007', Zend_Date::DATES, 'de');

// affichage de notre date


print $date->getIso();

// quel est son fuseau horaire ?


print $date->getTimezone();

// affectons un autre fuseau


$date->setTimezone('America/Chicago');

// quel est le fuseau ?


print $date->getTimezone();

// voyons les changements dans la date retournée


print $date->getIso();

Zend_Date utilise toujours le fuseau par défaut (de PHP) lors de la création de l'instance.
Remarquez que changer le fuseau de l'objet a un impact sur la date s'y trouvant. Une date est
toujours exprimée relativement à un fuseau horaire, changer le fuseau dans l'objet ne change
pas la date de l'objet, mais bien sa représentation. Rappelez vous qu'en interne, les dates sont
représentées comme des timestamps GMT. Le fuseau donne une information de décalage par
rapport à GMT, en positif ou négatif.

Coupler le fuseau dans l'objet Zend_Date a un autre effet positif : il est possible de posséder
plusieurs objets de date, avec chacun un fuseau horaire différent.

418
Zend_Date

Exemple 133. Plusieurs fuseaux horaires

// Règle le fuseau horaire PHP par défaut.


// En général, celui-ci est réglé dans php.ini
// Ici nous le faisons pour l'exemple
date_default_timezone_set('Europe/Vienna');

// creation d'un objet date


$date = new Zend_Date('10.03.2007 00:00:00', Zend_Date::ISO_8601, 'de');

// affichage de notre date


print $date->getIso();

// La date est inchangée, même si le fuseau PHP l'est


date_default_timezone_set('America/Chicago');
print $date->getIso();

$otherdate = clone $date;


$otherdate->setTimezone('Brazil/Acre');

// affichage de notre date


print $otherdate->getIso();

// affecte le fuseau horaire actuel de PHP, à notre objet date


$lastdate = clone $date;
$lastdate->setTimezone();

// affichage de notre date


print $lastdate->getIso();

419
Zend_Db
1. Zend_Db_Adapter
Zend_Db et ses autres sous classes proposent une interface de connexion aux bases de
données avec Zend Framework. Zend_Db_Adapter est la classe de base que vous utilisez
pour vous connecter aux bases de données (SGBDs). Il y a différentes classes d'adaptateur
par SGBD.

Les classes Adapters de Zend_Db créent un pont entre les extensions PHP et une interface
commune. Ceci vous aide à écrire des applications déployables avec de multiples SGBDs,
demandant peu d'efforts.

L'interface de la classe d'adaptateur est semblable à celle de l'extension PHP Data Objects.
Zend_Db propose des classes d'adaptateurs vers les drivers PDO pour les SGBDs suivants :

• IBM DB2 et Informix Dynamic Server (IDS), en utilisant l'extension PHP pdo_ibm.

• MySQL, utilisant l'extension PHP pdo_mysql.

• Microsoft SQL Server, utilisant l'extension PHP pdo_dblib.

• Oracle, utilisant l'extension PHP pdo_oci.

• PostgreSQL, grâce à l'extension PHP pdo_pgsql.

• SQLite, avec l'extension PHP pdo_sqlite.

De plus, Zend_Db fournit aussi des classes se connectant avec les extensions PHP propres aux
SGBDs (hors PDO donc), pour les SGBDs suivants :

• MySQL, utilisant l'extension PHP mysqli.

• Oracle, utilisant l'extension PHP oci8.

• IBM DB2, utilisant l'extension PHP ibm_db2.

• Firebird/Interbase, utilisant l'extension PHP php_interbase

Chaque Zend_Db_Adapter utilise une extension PHP. Vous devez donc les
avoir activées pour utiliser les classes en question. Par exemple, si vous voulez
utiliser une classe Zend_Db_Adapter basée sur PDO, vous devrez alors avoir
l'extension PDO d'installée, ainsi que l'extension représentant le driver spécifique
à votre SGBD.

1.1. Se connecter à un SGBD en utilisant un adaptateur


Cette section décrit comment créer une instance d'un adaptateur Zend_Db de base de données.

1.1.1. Utilisation du constructeur du Zend_Db Adapter


Vous pouvez créer une instance d'un adaptateur en utilisant son constructeur. Celui-ci accepte
un paramètre représentant un tableau d'options.

420
Zend_Db

Exemple 134. Utiliser le constructeur de l'adaptateur

$db = new Zend_Db_Adapter_Pdo_Mysql(array(


'host' => '127.0.0.1',
'username' => 'webuser',
'password' => 'xxxxxxxx',
'dbname' => 'test'
));

1.1.2. Utiliser la fabrique (Factory) de Zend_Db


Alternativement, il est possible d'utiliser la méthode statique Zend_Db::factory().
Celle-ci charge dynamiquement la classe d'adaptateur correspondant en utilisant
Zend_Loader::loadClass().

Le premier argument est une chaîne désignant l'adaptateur souhaité. Par exemple,
"Pdo_Mysql" va correspondre à la classe Zend_Db_Adapter_Pdo_Mysql. Le second
paramètre est un tableau d'options. C'est le même que celui que vous auriez passé au
constructeur de la classe directement.

Exemple 135. Utilisation de la méthode statique de fabrique de Zend_Db

// Nous n'avons pas besoin de la ligne suivante car Zend_Db_Adapter_Pdo_Mysql


// sera automatiquement chargé par la fabrique Zend_Db.

// require_once 'Zend/Db/Adapter/Pdo/Mysql.php';

// Charge automatiquement la classe Zend_Db_Adapter_Pdo_Mysql


// et en créer une instance.
$db = Zend_Db::factory('Pdo_Mysql', array(
'host' => '127.0.0.1',
'username' => 'webuser',
'password' => 'xxxxxxxx',
'dbname' => 'test'
));

Si vous créez votre propre classe d'adaptateur qui étend Zend_Db_Adapter_Abstract et que
celle-ci ne respecte pas la syntaxe du préfixe package "Zend_Db_Adapter", utilisez alors la clé
"adapterNamespace" dans le tableau de configuration passé à la méthode factory() afin
de charger votre adaptateur.

Exemple 136. Utilisation de la fabrique avec une classe personnalisée

// Charge automatiquement la classe MyProject_Db_Adapter_Pdo_Mysql


// et l'instantie.
$db = Zend_Db::factory('Pdo_Mysql', array(
'host' => '127.0.0.1',
'username' => 'webuser',
'password' => 'xxxxxxxx',
'dbname' => 'test',
'adapterNamespace' => 'MyProject_Db_Adapter'
));

1.1.3. Utiliser Zend_Config avec la fabrique Zend_Db


Optionnellement, vous pouvez passer un objet de type Zend_Config en tant qu'argument de la
méthode factory(), concernant la configuration.

421
Zend_Db

Il est alors nécessaire que l'objet de configuration contienne une propriété adapter, qui
représente une chaîne de caractères décrivant l'adaptateur à utiliser. De plus, l'objet peut aussi
contenir une propriété nommée params, avec toutes les sous propriétés requises pour la
configuration de l'adaptateur.

Exemple 137. Utilisation de la fabrique avec un objet de type Zend_Config

Dans l'exemple qui va suivre, l'objet Zend_Config est crée à partir d'un tableau. Il
eut été possible de le créer à partir de fichiers externes, grâce à Zend_Config_Ini ou
Zend_Config_Xml.

$config = new Zend_Config(


array(
'database' => array(
'adapter' => 'Mysqli',
'params' => array(
'host' => '127.0.0.1',
'dbname' => 'test',
'username' => 'webuser',
'password' => 'secret',
)
)
)
);

$db = Zend_Db::factory($config->database);

Le second paramètre de la méthode factory() doit être un tableau associatif décrivant


les paramètres de l'adaptateur à utiliser. Cet argument est optionnel, si un objet de type
Zend_Config est utilisé en premier paramètre, alors il est supposé contenir les paramètres, et
le second paramètre de factory() est alors ignoré.

1.1.4. Paramètres de l'adaptateur (Adapter)


La liste ci dessous explique les différents paramètres acceptés par les classes d'adaptateur
Zend_Db.

• host : le nom de l'hôte hébergeant le SGBD. Vous pouvez aussi spécifier une adresse IP.
Si le SGBD se situe sur la même machine que l'application PHP, "localhost" ou "127.0.0.1"
devraient alors être utilisés.

• username : nom d'utilisateur du compte de connexion au SGBD.

• password : mot de passe de l'utilisateur du compte de connexion au SGBD.

• dbname : nom de la base de données située dans le SGBD.

• port : Certains SGBDs acceptent que l'on spécifie un port pour d'y connecter. Indiquez le alors
ici.

• charset : encodage utilisé pour la connexion.

• options : Ce paramètre est un tableau associatif d'options génériques à toutes les classes
Zend_Db_Adapter.

• driver_options : Ce paramètre est un tableau associatif d'options spécifiques à une extension


de SGBD spécifique. Typiquement, il est possible avec ce paramètre de passer des options
(attributs) au driver PDO.

422
Zend_Db

• adapterNamespace : fournit le commencement du nom de la classe d'adaptateur, à utiliser


la place de "Zend_Db_Adapter". Utilisez ceci si vous désirez que factory() charge une
classe non Zend.

Exemple 138. Passer l'option de gestion de la casse à la fabrique

Vous pouvez spécifier cette option avec la constante Zend_Db::CASE_FOLDING.


Ceci correspond à l'attribut ATTR_CASE dans les drivers PDO et IBM DB2, ce
qui ajuste la casse des clés dans les jeux de résultats. Les valeurs possibles
possibles sont Zend_Db::CASE_NATURAL (défaut), Zend_Db::CASE_UPPER, et
Zend_Db::CASE_LOWER.

$options = array(
Zend_Db::CASE_FOLDING => Zend_Db::CASE_UPPER
);

$params = array(
'host' => '127.0.0.1',
'username' => 'webuser',
'password' => 'xxxxxxxx',
'dbname' => 'test',
'options' => $options
);

$db = Zend_Db::factory('Db2', $params);

Exemple 139. Passer l'option d'auto-échappement à la fabrique

Vous pouvez spécifier cette option avec le paramètre


Zend_Db::AUTO_QUOTE_IDENTIFIERS. Si la valeur passée est TRUE (par défaut), alors
les identifiants tels que les noms de tables, de colonnes, ou encore les alias SQL, sont
échappés (délimités) dans la syntaxe de la requête SQL générée par l'objet d'adaptateur.
Ceci rend l'utilisation de mots SQL contenant des identifiant spéciaux plus simple. Dans
le cas de FALSE, vous devrez vous-même délimiter ces identifiant avec la méthode
quoteIdentifier().

$options = array(
Zend_Db::AUTO_QUOTE_IDENTIFIERS => false
);

$params = array(
'host' => '127.0.0.1',
'username' => 'webuser',
'password' => 'xxxxxxxx',
'dbname' => 'test',
'options' => $options
);

$db = Zend_Db::factory('Pdo_Mysql', $params);

423
Zend_Db

Exemple 140. Passer des options de driver PDO à la fabrique

$pdoParams = array(
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
);

$params = array(
'host' => '127.0.0.1',
'username' => 'webuser',
'password' => 'xxxxxxxx',
'dbname' => 'test',
'driver_options' => $pdoParams
);

$db = Zend_Db::factory('Pdo_Mysql', $params);

echo $db->getConnection()
->getAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY);

Exemple 141. Passer des options de sérialisation à la fabrique

$options = array(
Zend_Db::ALLOW_SERIALIZATION => false
);

$params = array(
'host' => '127.0.0.1',
'username' => 'webuser',
'password' => 'xxxxxxxx',
'dbname' => 'test',
'options' => $options
);

$db = Zend_Db::factory('Pdo_Mysql', $params);

1.1.5. Gestion des connexions dites paresseuses


La création d'une instance d'une classe d'adaptateur ne crée pas physiquement une connexion
au SGBD. L'adaptateur sauvegarde les paramètres et se connectera physiquement à la
demande, la première fois que vous aurez besoin d'exécuter une requête. Ceci permet d'assurer
que la création de l'instance elle-même est rapide, et ne coûte rien en performances. Vous
pouvez donc créer une instance de l'adaptateur, même si vous ne savez pas si vous allez
l'utiliser. Ainsi, si vos paramètres sont incorrects, il faudra attendre la tentative de connexion au
SGBD pour le vérifier réellement.

Si vous voulez forcer l'adaptateur à se connecter au SGBD, utilisez sa méthode


getConnection(). Elle retournera alors un objet représentant la connexion, en fonction de
l'extension PHP utilisée, ou une exception si la connexion n'a pas été réalisée. Par exemple,
si votre adaptateur utilise PDO, le retour sera un objet PDO. La connexion physique au SGBD
est alors réalisée.

Afin de vérifier si les paramètres de connexion au SGBD sont corrects, surveillez les exceptions
envoyées par la méthode getConnection().

De plus, un adaptateur peut être sérialisé pour être stocké, par exemple, dans une variable
de session. Ceci peut être utile non seulement pour l'adaptateur lui-même, mais aussi
pour les autres objets qui l'agrègent, comme un objet Zend_Db_Select. Par défaut, les

424
Zend_Db

adaptateurs sont autorisés à être sérialisés, si vous ne le voulez pas, vous devez passer
l'option Zend_Db::ALLOW_SERIALIZATION=false, regardez l'exemple ci-dessus. Afin de
respecter le principe de connexions paresseuses, l'adaptateur ne se reconnectera pas
après la désérialisation. Vous devez appeler vous-même getConnection(). Vous pouvez
permettre à l'adaptateur de se reconnecter automatiquement en utilisant l'option d'adaptateur
Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE=true.

Exemple 142. Gérer les exceptions de connexion

try {
$db = Zend_Db::factory('Pdo_Mysql', $parameters);
$db->getConnection();
} catch (Zend_Db_Adapter_Exception $e) {
// probablement mauvais identifiants,
// ou alors le SGBD n'est pas joignable
} catch (Zend_Exception $e) {
// probablement que factory() n'a pas réussi à charger
// la classe de l'adaptateur demandé
}

1.2. La base de données d'exemple


Dans cette documentation concernant Zend_Db, nous utilisons un exemple simple de tables
pour illustrer nos exemples. Ces tables peuvent servir à stocker des informations sur la gestion
des bugs dans une application. La base de données contient quatre tables :

• accounts correspond aux informations sur les utilisateurs qui gèrent les bugs.

• products enregistre les produits pour lesquels des bugs vont être relevés.

• bugs est la table qui contient les bugs, à savoir leur état actuel, la personne ayant relevé le
bug, la personne en charge de le corriger, et la personne chargée de vérifier le correctif.

• bugs_products enregistre les relations entre les bugs, et les produits. C'est une relation
plusieurs à plusieurs car un même bug peut faire partie de plusieurs produits, et un produit
peut évidemment posséder plusieurs bugs.

Le pseudo-code SQL suivant représente les tables de notre base de données d'exemple. Ces
tables sont utilisées aussi pour les tests unitaires automatisés de Zend_Db.

CREATE TABLE accounts (


account_name VARCHAR(100) NOT NULL PRIMARY KEY
);

CREATE TABLE products (


product_id INTEGER NOT NULL PRIMARY KEY,
product_name VARCHAR(100)
);

CREATE TABLE bugs (


bug_id INTEGER NOT NULL PRIMARY KEY,
bug_description VARCHAR(100),
bug_status VARCHAR(20),
reported_by VARCHAR(100) REFERENCES accounts(account_name),
assigned_to VARCHAR(100) REFERENCES accounts(account_name),
verified_by VARCHAR(100) REFERENCES accounts(account_name)
);

425
Zend_Db

CREATE TABLE bugs_products (


bug_id INTEGER NOT NULL REFERENCES bugs,
product_id INTEGER NOT NULL REFERENCES products,
PRIMARY KEY (bug_id, product_id)
);

Notez aussi que la table bugs contient plusieurs référence (clés étrangères) vers la table
accounts. Chacune de ces clés peut référencer un enregistrement différent de la table
accounts, pour un bug donné.

Le diagramme qui suit illustre le modèle physique des données.

1.3. Lecture de résultats de requête


Cette section décrit des méthodes de la classe d'adaptateur permettant l'obtention de résultats
suivants une requête SELECT.

1.3.1. Récupérer tous les résultats


Vous pouvez à la fois exécuter une requête SELECT et récupérer tous ses résultats en une
seule manipulation, grâce à la méthode fetchAll().

Le premier paramètre de cette méthode est une chaîne représentant la requête SELECT à
exécuter. Aussi, ce premier paramètre peut être un objet Zend_Db_Select, qui sera alors converti
en une chaîne automatiquement.

Le second paramètre de de fetchAll() est un tableau de substitutions des éventuels jokers


présents dans la syntaxe SQL.

426
Zend_Db

Exemple 143. Utiliser fetchAll()

$sql = 'SELECT * FROM bugs WHERE bug_id = ?';

$result = $db->fetchAll($sql, 2);

1.3.2. Changer le mode de récupération (Fetch Mode)


Par défaut, fetchAll() retourne un tableau d'enregistrements. Chaque enregistrement étant
un tableau associatif dont les clés sont les noms des colonnes SQL désirées, ou leurs alias.

Vous pouvez spécifier un mode de récupération de résultats différent, ceci par la méthode
setFetchMode(). Les modes supportés sont identifiés par des constantes :

• Zend_Db::FETCH_ASSOC : Retourne un tableau d'enregistrements. Chaque enregistrement


étant un tableau associatif dont les clés sont les noms des colonnes SQL désirées, ou leurs
alias. Il s'agit du mode par défaut utilisé par les classes Zend_Db_Adapter.

Notez que si votre résultat comporte plusieurs colonnes avec le même nom, par exemple lors
d'une jointure, il ne peut y avoir qu'un clé avec un nom définit dans le tableau de résultat. Vous
devriez toujours utiliser des alias avec le mode FETCH_ASSOC.

Les noms des clés des tableaux correspondants aux noms des colonnes SQL telles que
retournées par le SGBD, vous pouvez spécifier la casse pour ces noms, grâce à l'option
Zend_Db::CASE_FOLDING. Spécifiez ceci lors de l'instanciation de votre adaptateur. Voyez
Exemple 138, « Passer l'option de gestion de la casse à la fabrique ».

• Zend_Db::FETCH_NUM : Retourne les enregistrements dans un tableau de tableaux. Les


tableaux nichés sont indexés par des entiers correspondants à la position du champ dans la
syntaxe SQL SELECT.

• Zend_Db::FETCH_BOTH : Retourne les enregistrements dans un tableau de tableaux. Les


tableaux nichés sont indexés à la fois numériquement et lexicalement. C'est un mode qui réunit
FETCH_ASSOC et FETCH_NUM. Ainsi, vous avez deux fois plus d'enregistrements, chacun
d'entre eux étant doublé.

• Zend_Db::FETCH_COLUMN: Retourne les enregistrements dans un tableau de valeurs. Les


valeurs correspondent à une des colonnes utilisées dans la requête SQL SELECT. Par défaut,
il s'agit de la colonne à l'index 0.

• Zend_Db::FETCH_OBJ : Retourne les enregistrements dans un tableau d'objets. La classe


de ces objets par défaut est la classe intégrée à PHP : stdClass. Les colonnes des
enregistrements sont représentées par les propriétés publiques des objets.

Exemple 144. Utiliser setFetchMode()

$db->setFetchMode(Zend_Db::FETCH_OBJ);

$result = $db->fetchAll('SELECT * FROM bugs WHERE bug_id = ?', 2);

// $result est un tableau d'objets


echo $result[0]->bug_description;

1.3.3. Récupérer un enregistrement comme tableau associatif


La méthode fetchAssoc() retourne des enregistrements sous forme de tableau de tableaux
associatifs, quelque soit la valeur de "fetch mode".

427
Zend_Db

Exemple 145. Utiliser fetchAssoc()

$db->setFetchMode(Zend_Db::FETCH_OBJ);

$result = $db->fetchAssoc('SELECT * FROM bugs WHERE bug_id = ?', 2);

// $result est un tableau de tableaux associatifs


echo $result[0]['bug_description'];

1.3.4. Récupérer une seule colonne d'un enregistrement


La méthode fetchCol() retourne les enregistrements dans un tableau de valeurs. Les valeurs
correspondent à une des colonnes utilisées dans la requête SQL SELECT, par défaut : la
première. Toute autre colonne sera ignorée. Si vous avez besoin de retourner une autre colonne,
voyez Section 2.3.4, « Récupérer une colonne simple depuis un statement exécuté ». Cette
méthode est indépendante de la valeur de "fetch mode".

Exemple 146. Utiliser fetchCol()

$db->setFetchMode(Zend_Db::FETCH_OBJ);

$sql = 'SELECT bug_description, bug_id FROM bugs WHERE bug_id = ?';


$result = $db->fetchCol($sql, 2);

// Contient bug_description ; bug_id n'est pas retourné


echo $result[0];

1.3.5. Récupérer des paires Clé-Valeur d'enregistrements


La méthode fetchPairs() retourne un tableau de paires clés/valeurs. La clé est le résultat
de la première colonne sélectionnée dans la requête, la valeur est le résultat de la deuxième
colonne sélectionnée dans la requête. Il est donc inutile de sélectionner plus de deux colonnes
avec cette méthode. De même, vous devez sélectionner exactement deux colonnes avec cette
méthode, pas moins. Si des clés ont des doublons, alors ils seront écrasés.

Vous devriez réfléchir votre requête SELECT de manière à ce que la première colonne
sélectionnée, correspondant à la clé du tableau de résultat, soit unique (une clé primaire par
exemple). Cette méthode est indépendante de "fetch mode" éventuellement précédemment
défini.

Exemple 147. Utilisation de fetchPairs()

$db->setFetchMode(Zend_Db::FETCH_OBJ);

$result = $db->fetchPairs('SELECT bug_id, bug_status FROM bugs');

echo $result[2]; // le bug_status correspondant au bug_id numéro 2

1.3.6. Récupérer un seul enregistrement complet


La méthode fetchRow() retourne un et un seul enregistrement (le premier si plusieurs
correspondent), en fonction de "fetch mode" que vous aurez précédemment défini. Cette
méthode ressemble donc à fetchAll() si ce n'est qu'elle ne retournera jamais plus d'un seul
enregistrement. Arrangez vous donc pour que votre SELECT possède une clause WHERE sur
une clé primaire.

428
Zend_Db

Exemple 148. Utiliser fetchRow()

$db->setFetchMode(Zend_Db::FETCH_OBJ);

$result = $db->fetchRow('SELECT * FROM bugs WHERE bug_id = 2');

// Ce résultat sera un objet, car le fetch mode en a décidé ainsi


echo $result->bug_description;

1.3.7. Récupérer une colonne d'un enregistrement


La méthode fetchOne() est une combinaison des méthodes fetchRow() et fetchCol(),
ainsi elle ne retourne que la première colonne, du premier enregistrement retourné. La valeur
de retour est donc une chaîne de caractères. Toute requête retournant plusieurs colonnes et/ou
plusieurs résultats est donc inutile avec cette méthode.

Exemple 149. Utiliser fetchOne()

$result = $db->fetchOne('SELECT bug_status FROM bugs WHERE bug_id = 2');

// ceci est une chaine


echo $result;

1.4. Effectuer des changements dans la base de données


Il est bien entendu possible d'utiliser la classe d'adaptateur pour effectuer des changements
dans vos données. Cette section décrit les manières de procéder.

1.4.1. Insérer des données


Vous pouvez ajouter de nouveaux enregistrements dans une table, grâce à la méthode
insert(). Son premier paramètre est une chaîne qui représente le nom de la table ciblée, le
second paramètre est un tableau associatif liant les noms des colonnes de la table, aux valeurs
souhaitées.

Exemple 150. Insertion dans une table

$data = array(
'created_on' => '2007-03-22',
'bug_description' => 'Something wrong',
'bug_status' => 'NEW'
);

$db->insert('bugs', $data);

Les colonnes non citées dans le tableau associatif sont laissées telles quelles. Ainsi, si le SGBD
possède une valeur DEFAULT pour les colonnes concernées, celle-ci sera utilisée, autrement,
NULL sera utilisé.

Par défaut, les valeurs insérées avec cette méthode sont automatiquement échappées. Ceci
pour des raisons de sécurité, vous n'avez donc pas besoin de vous occuper de ce point là.

Si vous avez besoin d'écrire de la syntaxe SQL, comme des mots réservés, des noms de
fonctions SQL, vous voulez que ceux-ci ne soient pas échappés, et ne soient pas traités comme
de vulgaires chaînes de caractères, mais plutôt comme des expressions. Pour ceci, vous devriez
passer ces valeurs dans votre tableau de données, en tant qu'objets de type Zend_Db_Expr
au lieu de chaînes de caractères banales.

429
Zend_Db

Exemple 151. Insérer des expressions dans une table

$data = array(
'created_on' => new Zend_Db_Expr('CURDATE()'),
'bug_description' => 'Something wrong',
'bug_status' => 'NEW'
);

$db->insert('bugs', $data);

1.4.2. Récupérer une valeur générée


Certains SGBDs supportent les clé primaires auto-incrémentées. Une table qui utilise un tel
procédé génère la valeur de la clé automatiquement lors d'une insertion (INSERT). La valeur de
retour de la méthode insert() n'est pas le dernier ID inséré car la table peut ne pas avoir de clé
auto-incrémentée. La valeur de retour est le nombres d'enregistrements affectés (théoriquement
1).

Si votre table a été définie avec une clé auto-incrémentée, alors vous pouvez appeler la méthode
lastInsertId() après une opération d'insertion. Cette méthode retourne la valeur auto-
incrémentée, générée dans le cadre de la connexion au SGBD.

Exemple 152. Utiliser lastInsertId() pour les clés auto-incrémentées

$db->insert('bugs', $data);

// retourne la dernière valeur générée par la clé auto-incrémentée


$id = $db->lastInsertId();

Certains SGBD supporte un objet de séquence, qui sert à générer des valeurs uniques qui vont
servir pour les clé primaires. Pour supporter ce procédé, la méthode lastInsertId() accepte
deux paramètres optionnels (chaînes de caractères). Ces paramètres nomment la table et la
colonne en supposant que vous ayez respecté la convention qui définit que la séquence est
nommée en utilisant le nom de la table et des colonnes utilisées, avec le suffixe "_seq". Ces
conventions sont celles de PostgreSQL pour les colonnes de type SERIAL. Par exemple, une
table "bugs" avec une clé primaire "bug_id" utilisera une séquence nommée "bugs_bug_id_seq".

Exemple 153. Utiliser lastInsertId() avec une séquence

$db->insert('bugs', $data);

// retourne la dernière valeur générée par la séquence 'bugs_bug_id_seq'.


$id = $db->lastInsertId('bugs', 'bug_id');

// ceci retourne la dernière valeur générée par la séquence 'bugs_seq'.


$id = $db->lastInsertId('bugs');

Si le nom de votre objet de séquence ne suit pas ces conventions de nommage, utilisez
alors lastSequenceId(). Cette méthode prend un paramètre qui nomme la séquence
explicitement.

Exemple 154. Utilisation de lastSequenceId()

$db->insert('bugs', $data);

// retourne la dernière valeur générée par la séquence 'bugs_id_gen'.


$id = $db->lastSequenceId('bugs_id_gen');

430
Zend_Db

Pour les SGBDs ne supportant pas les séquences, comme MySQL, Microsoft SQL Server, et
SQLite, les arguments passés à la méthode lastInsertId() sont ignorés. La valeur retournée
est la dernière valeur générée pour la dernière requête INSERT, quelque soit la table concernée
(pour cette connexion). Aussi, pour ces SGBDs, la méthode lastSequenceId() retournera
toujours NULL.

Pourquoi ne pas utiliser "SELECT MAX(id) FROM table"?


Quelques fois, cette requête retourne la valeur la plus récente de clé primaire
insérée dans la table en question. Cependant, cette technique n'est pas
pertinente dans un environnement où beaucoup de clients insèrent beaucoup
de données dans une même table. Il est donc possible qu'un client insère une
donnée entre le moment où la dernière insertion est effectuée, et l'appel de
MAX(id), aboutissant ainsi à un résultat erroné. Il est très difficile de se rendre
compte d'un tel comportement.

Utiliser un mode d'isolation transactionnelle très élevé, comme "repeatable read"


peut mitiger plus ou moins les risques, mais certains SGBDs ne supportent pas
ce mode de transactions.

De plus, utiliser une requête du type "MAX(id)+1" pour générer une nouvelle
valeur de clé primaire n'est pas sécurisé non plus, car deux client peuvent se
connecter simultanément et créer des effets indésirables.

Tous les SGBDs fournissent un mécanisme de génération de valeurs uniques, et


une méthode pour les récupérer. Ces mécanismes travaillent en dehors du mode
transactionnel, et empêchent ainsi deux clients de générer la même valeur, ou
de "se marcher dessus".

1.4.3. Mettre à jour des données


Vous pouvez mettre à jour des données dans une table en utilisant la méthode update()
de l'adaptateur. Cette méthode accepte trois arguments : le premier est le nom de la table,
le deuxième est un tableau faisant correspondre les noms des colonnes SQL à leurs valeurs
désirées.

Les valeurs dans ce tableau sont traitées comme des chaînes. Voyez Section 1.4.1, « Insérer
des données » pour plus d'informations sur la gestion des expressions SQL dans ce tableau.

Le troisième argument est une chaîne contenant l'expression SQL utilisée comme critère pour
la mise à jour des données dans la table. Les valeurs et les arguments dans ce paramètre ne
sont pas échappés pour vous. Vous devez donc vous assurer de l'éventuel bon échappement
des caractères. Voyez Section 1.5, « Échapper des valeurs ou des identifiants » pour plus
d'informations.

La valeur de retour de cette méthode est le nombre d'enregistrements affectés par l'opération
de mise à jour (UPDATE).

Exemple 155. Mettre à jour des enregistrements

$data = array(
'updated_on' => '2007-03-23',
'bug_status' => 'FIXED'
);

$n = $db->update('bugs', $data, 'bug_id = 2');

431
Zend_Db

Si vous oubliez le troisième paramètre, alors tous les enregistrements de la table sont mis à jour
avec les valeurs spécifiées dans le tableau de données.

Si vous spécifiez un tableau de chaîne en tant que troisième paramètre, alors ces chaînes sont
jointes entre elles avec une opération AND.

Si vous fournissez un tableau de tableaux en tant que troisième argument, les valeurs seront
automatiquement échappées dans les clés. Elles seront ensuite jointes ensemble, séparées par
des opérateurs AND.

Exemple 156. Mettre à jour des enregistrements avec un tableau de données

$data = array(
'updated_on' => '2007-03-23',
'bug_status' => 'FIXED'
);

$where[] = "reported_by = 'goofy'";


$where[] = "bug_status = 'OPEN'";

$n = $db->update('bugs', $data, $where);

// la requête SQL executée est :


// UPDATE "bugs" SET "update_on" = '2007-03-23', "bug_status" = 'FIXED'
// WHERE ("reported_by" = 'goofy') AND ("bug_status" = 'OPEN')

Exemple 157. UMettre à jour des enregistrements avec un tableau de tableaux

$data = array(
'updated_on' => '2007-03-23',
'bug_status' => 'FIXED'
);

$where['reported_by = ?'] = 'goofy';


$where['bug_status = ?'] = 'OPEN';

$n = $db->update('bugs', $data, $where);

// la requête SQL executée est :


// UPDATE "bugs" SET "update_on" = '2007-03-23', "bug_status" = 'FIXED'
// WHERE ("reported_by" = 'goofy') AND ("bug_status" = 'OPEN')

1.4.4. Supprimer des enregistrements


Il est possible de supprimer des enregistrements dans une table. La méthode delete() est
faite pour cela. Elle accepte deux paramètres, le premier est une chaîne désignant la table.

Le second paramètre est une chaîne contenant l'expression SQL utilisée comme critère
pour effacer les enregistrements. Les valeurs de cette expression de sont pas échappées
automatiquement, vous devez donc vous en occuper le cas échéant. Voyez Section 1.5,
« Échapper des valeurs ou des identifiants » pour les méthodes concernant l'échappement.

La valeur retournée par la méthode delete() est le nombre d'enregistrements affectés


(effacés).

Exemple 158. Supprimer des enregistrements

$n = $db->delete('bugs', 'bug_id = 3');

432
Zend_Db

Si vous ne spécifiez pas le second paramètres, tous les enregistrements de la table seront alors
supprimés.

Si le second paramètre est un tableau de chaînes, alors celles ci seront jointe en une expression
SQL, séparées par l'opérateur AND.

Si vous fournissez un tableau de tableaux en tant que troisième argument, les valeurs seront
automatiquement échappées dans les clés. Elles seront ensuite jointes ensemble, séparées par
des opérateurs AND.

1.5. Échapper des valeurs ou des identifiants


Lorsque vous envoyez des requêtes SQL au SGBD, il est souvent nécessaire d'y inclure des
paramètres dynamiques, PHP. Ceci est risqué car si un des paramètres contient certains
caractères, comme l'apostrophe ('), alors la requête résultante risque d'être mal formée. Par
exemple, notez le caractère indésirable dans la requête suivante :

$name = "O'Reilly";
$sql = "SELECT * FROM bugs WHERE reported_by = '$name'";

echo $sql;
// SELECT * FROM bugs WHERE reported_by = 'O'Reilly'

Pire encore est le cas où de telles erreurs SQL peuvent être utilisées délibérément par une
personne afin de manipuler la logique de votre requête. Si une personne peut manipuler un
paramètre de votre requête, par exemple via un paramètre HTTP ou une autre méthode, alors il
peut y avoir une fuite de données, voire même une corruption totale de votre base de données.
Cette technique très préoccupante de violation de la sécurité d'un SGBD, est appelée "injection
SQL" (voyez http://en.wikipedia.org/wiki/SQL_Injection).

La classe Zend_Db Adapter possède des méthodes adaptées pour vous aider à faire face à
de telles vulnérabilités. La solution proposée est l'échappement de tels caractères (comme la
"quote" = ') dans les valeurs PHP avant leur passage dans la chaîne de requête. Ceci vous
protège de l'insertion malveillante ou involontaires, de caractères spéciaux dans les variables
PHP faisant partie d'une requête SQL.

1.5.1. Utilisation de quote()


La méthode quote() accepte un seul paramètre, une chaîne de caractère. Elle retourne une
chaîne dont les caractères spéciaux ont été échappés d'une manière convenable en fonction du
SGBD sous-jacent. De plus, la chaîne échappée est entourée d'apostrophes ("'").C'est la valeur
standard de délimitations des chaînes en SQL.

Exemple 159. Utiliser quote()

$name = $db->quote("O'Reilly");
echo $name;
// 'O\'Reilly'

$sql = "SELECT * FROM bugs WHERE reported_by = $name";

echo $sql;
// SELECT * FROM bugs WHERE reported_by = 'O\'Reilly'

Notez que la valeur de retour contient les apostrophes de délimitation autour de la chaîne. Ceci
est différent de certaines fonctions qui se contentent juste d'échapper les caractères spéciaux,
telle que mysql_real_escape_string().

433
Zend_Db

Certaines valeurs en revanche n'ont pas besoin d'être délimitées. Certains SGBDs n'acceptent
pas que les valeurs correspondant à des champs de type entier, soient délimitées. Autrement
dit, l'exemple suivant est erroné dans certaines implémentations de SQL. Nous supposons
intColumn ayant un type SQL INTEGER :

SELECT * FROM atable WHERE intColumn = '123'

Le second paramètre optionnel de quote() permet de spécifier un type SQL.

Exemple 160. Utiliser quote() avec un type SQL

$value = '1234';
$sql = 'SELECT * FROM atable WHERE intColumn = '
. $db->quote($value, 'INTEGER');

De plus, chaque classe Zend_Db_Adapter possèdent des constantes représentant les


différents type SQL des SGBDs respectifs qu'elles représentent. Ainsi, les constantes
Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, et Zend_Db::FLOAT_TYPE peuvent vous
permettre d'écrire un code portable entre différents SGBDs.

Zend_Db_Table fournit les types SQL à quote() automatiquement en fonction des colonnes
utilisées par la table référencée.

1.5.2. Utilisation de quoteInto()


Une autre manière est d'échapper une expression SQL contenant une variable PHP. Vous
pouvez utiliser quoteInto() pour cela. Cette méthode accepte trois arguments. Le premier
est la chaîne représentant l'expression SQL dont les paramètres variables sont remplacés par
un joker(?), et le second argument est la variable PHP à utiliser pour le remplacement du joker.

Le joker est le même symbole que celui utilisé par beaucoup de SGBDs pour la substitution de
paramètre dans une requête préparée.quoteInto() ne fait qu'émuler ce comportement : la
méthode ne fait que remplacer le joker par la valeur PHP, en lui appliquant la méthode quote.
De vrais paramètres de requêtes préparées conservent une réelle isolation entre la requête et
ses paramètres.

Exemple 161. Utiliser quoteInto()

$sql = $db->quoteInto("SELECT * FROM bugs WHERE reported_by = ?",


"O'Reilly");

echo $sql;
// SELECT * FROM bugs WHERE reported_by = 'O\'Reilly'

Le troisième paramètre optionnel s'utilise comme avec la méthode quote. Il sert à spécifier un
type SQL, les types numériques ne sont pas délimités.

Exemple 162. Utiliser quoteInto() avec un type SQL

$sql = $db->quoteInto("SELECT * FROM bugs WHERE bug_id = ?",


'1234',
'INTEGER');

echo $sql;
// SELECT * FROM bugs WHERE reported_by = 1234

434
Zend_Db

1.5.3. Utilisation de quoteIdentifier()

Les valeurs ne sont pas les seuls données qui peuvent être dynamiques dans une requête
SQL,et donc passées par des variables PHP. Les noms des tables, des colonnes, ou tout autre
identifiant SQL spécial de la requête peuvent aussi être dynamiques. En général, les identifiant
spéciaux d'une requête ont une syntaxe identique à celle des variables PHP : pas d'espaces
dans les noms, certains autres caractères interdits, la ponctuation est interdite, etc... Aussi, les
identifiants ne peuvent valoir certaines valeurs de mots réservés : une table ne peut s'appeler
"FROM". Il se peut donc que vous ayez besoin aussi d'échapper des paramètres voués à être
substitués à des identifiant dans la requête SQL, et non plus à des valeurs.

Le langage SQL possède une caractéristique appelée identifiant délimités. Si vous entourez un
identifiant SQL dans un type spécial de délimiteurs, alors vous pouvez écrire des requêtes qui
auraient été invalides autrement. Ainsi, vous pouvez inclure des espaces, de la ponctuation ou
des caractères internationaux dans vos identifiant, et aussi utiliser des mots réservés.

La méthode quoteIdentifier() fonctionne comme quote(), mais elle utilise un caractère


de délimitation spécial, en fonction du SGBD sous-jacent. Par exemple, le standard SQL spécifie
des doubles quotes (") et beaucoup de SGBDs utilisent ceci. MySQL utilise les apostrophes
inverses (back-quotes) (`) par défaut. Les caractères spéciaux sont aussi échappés.

Exemple 163. Utiliser quoteIdentifier()

// nous possédons une table ayant un nom correspondant


// à un mot reservé en SQL
$tableName = $db->quoteIdentifier("order");

$sql = "SELECT * FROM $tableName";

echo $sql
// SELECT * FROM "order"

Les identifiant SQL délimités sont sensibles à la casse. Vous devriez toujours utiliser la casse
telle qu'elle est utilisée dans votre base de données (nom des tables, des colonnes ...).

Dans les cas où le SQL est généré à l'intérieur des classes Zend_Db, alors les identifiant
SQL seront automatiquement échappés. Vous pouvez changer ce comportement avec l'option
Zend_Db::AUTO_QUOTE_IDENTIFIERS.Spécifiez la lors de l'instanciation de l'adaptateur.
Voyez Exemple 139, « Passer l'option d'auto-échappement à la fabrique ».

1.6. Gérer les transactions dans une base de données


Les bases de données définissent les transactions comme étant des unités logiques de travail
qui peuvent êtres validées ("commit") ou annulées ("rollback") en tant qu'une seule opération,
même sur de multiples tables. Toutes les requêtes aux bases de données sont considérées
comme faisant partie d'une transaction, même si le driver de base de données fait ceci
implicitement. Ceci s'appelle le mode auto-commit, dans lequel le driver de base de données
créer une transaction pour chaque requête exécutée et la valide. Par défaut toutes les classes
Zend_Db_Adapter fonctionnent en mode auto-commit.

Vous pouvez manuellement spécifier lorsque vous voulez démarrer une transaction. Vous
contrôler ainsi combien de requêtes doivent y être exécutées, et valider ou annuler ce groupe de
requêtes. Utilisez beginTransaction() pour démarrer une transaction. Toutes les requêtes
suivantes seront alors exécutées dans cette transaction avant que vous ne l'annuliez, ou validiez.

435
Zend_Db

Pour terminer une transaction, utilisez les méthodes commit() ou rollBack(). commit()
validera et appliquera les changements de la transaction au SGBD, ils deviendront alors visibles
dans les autres transactions.

rollBack() fait le contraire : elle annule les changements qu'ont générés les requêtes dans
la transaction. L'annulation n'a aucun effet sur les changements qui ont été opérés par d'autres
transactions parallèles.

Après qu'une transaction soit terminées, Zend_Db_Adapter retourne en mode auto-commit


jusqu'à un nouvel appel à beginTransaction().

Exemple 164. Manipuler les transactions pour assurer l'intégrité de la logique

// Démarre explicitement une transaction.


$db->beginTransaction();

try {
// Essaye d'executer une ou plusieurs requêtes :
$db->query(...);
$db->query(...);
$db->query(...);

// Si toutes ont réussi, valide les changements en une seule passe.


$db->commit();

} catch (Exception $e) {


// Si une des requête s'est mal déroulée, alors nous voulons
// annuler les changements de toutes les requêtes faisant partie
// de la transaction, même celles qui se sont bien déroulées.
// Tous les changements sont annulés d'un seul coup.
$db->rollBack();
echo $e->getMessage();
}

1.7. Lister et décrire les tables


La méthode listTables() retourne un tableau de chaînes décrivant les tables de la base de
données courante.

La méthode describeTable() retourne un tableau associatif de métadonnées sur une table.


Spécifiez en le nom en paramètre. Le second paramètre est optionnel et définit la base de
données à utiliser, comme par exemple si aucune n'a été sélectionnée précédemment.

Les clés de ce tableau représentent les noms des colonnes, les valeurs sont un tableau avec
les clés suivantes :

Tableau 51. Champs de métadonnées retournés par describeTable()


clé type description
SCHEMA_NAME (chaîne) Nom de la base de données
dans laquelle la table existe.
TABLE_NAME (chaîne) Nom de la table dans laquelle
la colonne existe.
COLUMN_NAME (chaîne) Nom de la colonne.
COLUMN_POSITION (entier) Position de la colonne dans la
table.

436
Zend_Db

clé type description


DATA_TYPE (chaîne) Nom du type de données tel
que renvoyé par le SGBD.
DEFAULT (chaîne) Valeur par défaut de la
colonne, si une existe.
NULLABLE (booléen) TRUE si la colonne accepte
la valeur SQL 'NULL', FALSE
sinon.
LENGTH (entier) Longueur ou taille de la
colonne telle que reportée par
le SGBD.
SCALE (entier) Échelle du type SQL
NUMERIC ou DECIMAL.
PRECISION (entier) Précision du type SQL
NUMERIC ou DECIMAL.
UNSIGNED (booléen) TRUE si le type est un
entier non signé, défini par
UNSIGNED.
PRIMARY (booléen) TRUE si la colonne fait partie
d'une clé primaire.
PRIMARY_POSITION (entier) Position de la colonne dans la
clé primaire.
IDENTITY (booléen) TRUE si la colonne utilise une
valeur auto-générée.

A quoi correspond le champs de métadonnées "IDENTITY" en


fonction du SGBD ?

Le champs de métadonnées "IDENTITY" a été choisi en tant que terme


idiomatique pour représenter une relation de substitution de clés. Ce champ est
généralement connu par les valeurs suivantes :

• IDENTITY - DB2, MSSQL

• AUTO_INCREMENT - MySQL

• SERIAL - PostgreSQL

• SEQUENCE - Oracle

Si aucune table ne correspond à votre demande, alors describeTable() retourne un tableau


vide.

1.8. Fermer une connexion


Normalement, il n'est pas nécessaire de fermer explicitement sa connexion. PHP nettoie
automatiquement les ressources laissées ouvertes en fin de traitement. Les extensions des
SGBDs ferment alors les connexions respectives pour les ressources détruites par PHP.

437
Zend_Db

Cependant, il se peut que vous trouviez utile de fermer la connexion manuellement. Vous pouvez
alors utiliser la méthode de l'adaptateur closeConnection() afin de fermer explicitement la
connexion vers le SGBD.

A partir de la version 1.7.2, vous pouvez vérifier si vous êtes actuellement connecté au serveur
SGBD grâce à la méthode isConnected(). Ceci correspond à une ressource de connexion
qui a été initiée et qui n'est pas close. Cette fonction ne permet pas actuellement de tester la
fermeture de la connexion au niveau du SGBD par exemple. Cette fonction est utilisée en interne
pour fermer la connexion. Elle vous permet entre autres de fermer plusieurs fois une connexion
sans erreurs. C'était déjà le cas avant la version 1.7.2 pour les adaptateurs de type PDO mais
pas pour les autres.

Exemple 165. Fermer une connexion à un SGBD

$db->closeConnection();

Zend_Db supporte-t-il les connexions persistantes ?


Oui, la persistance est supportée grace à l'addition de l'option persistent
quand il est à une valeur true dans la configuration (pas celle du driver) d'un
adaptateur de Zend_Db.

Exemple 166. Utiliser l'option de persistance avec l'adaptateur


Oracle

$db = Zend_Db::factory('Oracle', array(


'host' => '127.0.0.1',
'username' => 'webuser',
'password' => 'xxxxxxxx',
'dbname' => 'test',
'persistent' => true
));

Notez cependant qu'utiliser des connexions persistantes peut mener à un trop


grand nombre de connexions en attente (idle), ce qui causera plus de problème
que cela n'est sensé en résoudre.

Les connexions aux bases de données possède un état. Dans cet état sont
mémorisés des objets propres au SGBD. Par exemples des verrous, des
variables utilisateur, des tables temporaires, des informations sur les requêtes
récentes, les derniers enregistrements affectés, les dernières valeurs auto-
générées, etc. Avec des connexions persistantes, il se peut que vous accédiez
à des données ne faisant pas partie de votre session de travail avec le SGBD,
ce qui peut s'avérer dangereux.

Actuellement, seuls les adpatateurs Oracle, DB2 et PDO (si spécifiés par PHP)
supportent la persistance avec Zend_Db.

1.9. Exécuter des requêtes sur le driver directement


Il peut y avoir des cas où vous souhaitez accéder directement à la connexion 'bas niveau', sous
Zend_Db_Adapter.

Par exemple, toute requête effectuée par Zend_Db est préparée, et exécutée. Cependant,
certaines caractéristiques des bases de données ne sont pas compatibles avec les requêtes

438
Zend_Db

préparées. Par exemple, des requêtes du type CREATE ou ALTER ne peuvent pas être
préparées sous MySQL. De même, les requêtes préparées ne bénéficient pas du cache de
requêtes, avant MySQL 5.1.17.

La plupart des extensions PHP pour les bases de données proposent une méthode permettant
d'envoyer une requête directe, sans préparation. Par exemple, PDO propose pour ceci la
méthode exec(). Vous pouvez récupérer l'objet de connexion "bas niveau" grâce à la méthode
de l'adaptateur getConnection().

Exemple 167. Envoyer une requête directe dans un adaptateur PDO

$result = $db->getConnection()->exec('DROP TABLE bugs');

De la même manière, vous pouvez accéder à toutes les propriétés ou méthodes de l'objet "bas
niveau", utilisé par Zend_Db. Attention toutefois en utilisant ce procédé, vous risquez de rendre
votre application dépendante du SGBD qu'elle utilise, en manipulant des méthodes propres à
l'extension utilisée.

Dans de futures versions de Zend_Db, il sera possible d'ajouter des méthodes pour des
fonctionnalités communes aux extensions de bases de données de PHP. Ceci ne rompra pas
la compatibilité.

1.10. Récupérer la version du serveur SGBD


A partir de la version 1.7.2, vous pouvez récupérer la version du serveur avec le style de syntaxe
PHP ce qui permet d'utiliser version_compare(). Si cette information n'est pas disponible,
vous recevrez un NULL.

Exemple 168. Vérifier la version du serveur avant de lancer une requête

$version = $db->getServerVersion();
if (!is_null($version)) {
if (version_compare($version, '5.0.0', '>=')) {
// faire quelquechose
} else {
// faire autre chose
}
} else {
// impossible de lire la version du serveur
}

1.11. Notes sur des adaptateur spécifiques


Cette section liste des différences entre les adaptateurs, que vous devriez considérer.

1.11.1. IBM DB2


• Passez le paramètre 'Db2' à la méthode factory().

• Cet adaptateur utilise l'extension PHP ibm_db2.

• IBM DB2 supporte les séquences et les clés auto-incrémentées. Les arguments de
lastInsertId() sont donc optionnels. Si vous ne passez pas de paramètres, alors
l'adaptateur retourne la dernière valeur de clé auto- incrémentée. Sinon, il retourne la

439
Zend_Db

dernière valeur de la séquence passée en paramètre, en se référant à la convention


'table_colonne_seq'.

1.11.2. MySQLi
• Passez le paramètre 'Mysqli' à la méthode factory().

• Cet adaptateur utilise l'extension PHP mysqli.

• MySQL ne supporte pas les séquences, donc lastInsertId() ignore tout paramètre
qu'on lui passe. Elle retourne toujours la valeur de la dernière clé auto-incrémentée.
lastSequenceId(), elle, retourne toujours NULL.

1.11.3. Oracle
• Passez le paramètre 'Oracle' à la méthode factory().

• Cet adaptateur utilise l'extension PHP oci8.

• Oracle ne supporte pas les clé auto-incrémentées, donc vous devriez spécifier un paramètre
de séquence à lastInsertId() ou lastSequenceId().

• L'extension Oracle ne supporte pas les paramètres positionnés (?). Vous devez utiliser des
paramètres nommés (:name).

• Actuellement l'option Zend_Db::CASE_FOLDING n'est pas supportée par l'adaptateur


Oracle. Pour l'utiliser, vous devez utiliser l'adaptateur basé sur PDO et OCI.

• Par défaut les champs LOB ("Large Objet Binaire") sont retournés sous la forme d'objets OCI-
Lob. Vous pouvez les récupérer sous forme de chaînes pour toutes les requêtes en utilisant
l'option de driver 'lob_as_string' ou pour une requête en particulier en utilisant la méthode
setLobAsString(boolean) de l'adaptateur ou de l'objet statement.

1.11.4. Microsoft SQL Server


• Specify this Adapter to the factory() method with the name 'Sqlsrv'.

• This Adapter uses the PHP extension sqlsrv

• Microsoft SQL Server does not support sequences, so lastInsertId() ignores primary key
argument and returns the last value generated for an auto-increment key if a table name is
specified or a last insert query returned id. The lastSequenceId() method returns NULL.

• Zend_Db_Adapter_Sqlsrv sets QUOTED_IDENTIFIER ON immediately after connecting


to a SQL Server database. This makes the driver use the standard SQL identifier delimiter
symbol (") instead of the proprietary square-brackets syntax SQL Server uses for delimiting
identifiers.

• You can specify driver_options as a key in the options array. The value can be a anything from
here http://msdn.microsoft.com/en-us/library/cc296161(SQL.90).aspx.

• You can use setTransactionIsolationLevel() to set isolation level


for current connection. The value can be SQLSRV_TXN_READ_UNCOMMITTED,
SQLSRV_TXN_READ_COMMITTED, SQLSRV_TXN_REPEATABLE_READ,
SQLSRV_TXN_SNAPSHOT or SQLSRV_TXN_SERIALIZABLE.

440
Zend_Db

• As of Zend Framework 1.9, the minimal supported build of the PHP SQL Server extension
from Microsoft is 1.0.1924.0. and the MSSQL Server Native Client version 9.00.3042.00.

1.11.5. PDO pour IBM DB2 et Informix Dynamic Server (IDS)


• Passez le paramètre 'Pdo_Ibm' à la méthode factory().

• Cet adaptateur utilise les extensions PHP pdo et pdo_ibm.

• Vous devez possédez l'extension PDO_IBM en version 1.2.2 minimum. Si ce n'est pas le cas,
vous devrez la mettre à jour via PECL.

1.11.6. PDO Microsoft SQL Server


• Passez le paramètre 'Pdo_Mssql' à la méthode factory().

• Cet adaptateur utilise les extensions PHP pdo et pdo_dblib.

• Microsoft SQL Server ne supporte pas les séquences, ainsi lastInsertId() ignore les
paramètres qu'on lui passe et retourne toujours la valeur de la dernière clé auto-incrémentée.
lastSequenceId() retourne toujours NULL.

• Si vous travaillez avec des chaînes Unicode avec un encodage autre que UCS-2 (comme
UTF-8), vous devrez peut-être réaliser une conversion dans votre code d'application ou stocker
les données dans un champs binaire. Reportez vous à la base de connaissance Microsoft
pour plus d'informations.

• Zend_Db_Adapter_Pdo_Mssql met QUOTED_IDENTIFIER à ON dès que la connexion a été


effectuée. Le driver utilise donc le délimiteur d'identifiant SQL " au lieu de son délimiteur
habituel.

• Vous pouvez spécifier la clé pdoType dans le tableau d'options de construction de


l'adaptateur. La valeur peut être "mssql" (défaut), "dblib", "freetds", ou "sybase". Cette option
affecte la syntaxe du préfixe DSN que l'adaptateur utilisera. "freetds" et "sybase" impliquent
un préfixe "sybase:", qui est utilisé par les librairies FreeTDS.Voyez aussi http://www.php.net/
manual/en/ref.pdo-dblib.connection.php pour plus d'informations sur les DSN pour ce driver.

1.11.7. PDO MySQL


• Passez le paramètre 'Pdo_Mysql' à la méthode factory().

• Cet adaptateur utilise les extensions PHP pdo et pdo_mysql.

• MySQL ne supporte pas les séquences, ainsi lastInsertId() ignore les paramètres
qu'on lui passe et retourne toujours la valeur de la dernière clé auto-incrémentée.
lastSequenceId() retourne toujours NULL.

1.11.8. PDO Oracle


• Passez le paramètre 'Pdo_Oci' à la méthode factory().

• Cet adaptateur utilise les extensions PHP pdo et pdo_oci.

• Oracle ne supporte pas les clé auto-incrémentées, donc vous devriez spécifier un paramètre
de séquence à lastInsertId() ou lastSequenceId().

441
Zend_Db

1.11.9. PDO PostgreSQL


• Passez le paramètre 'PDO_Pgsql' à la méthode factory().

• Cet adaptateur utilise les extensions PHP pdo et pdo_pgsql.

• PostgreSQL supporte les séquences et les clés auto-incrémentées. Les arguments de


lastInsertId() sont donc optionnels. Si vous ne passez pas de paramètres, alors
l'adaptateur retourne la dernière valeur de clé auto- incrémentée. Sinon, il retourne la
dernière valeur de la séquence passée en paramètre, en se référant à la convention
'table_colonne_seq'.

1.11.10. PDO SQLite


• Passez le paramètre 'PDO_Sqlite' à la méthode factory().

• Cet adaptateur utilise les extensions PHP pdo et pdo_sqlite.

• SQLite ne supporte pas les séquences, ainsi lastInsertId() ignore les paramètres
qu'on lui passe et retourne toujours la valeur de la dernière clé auto-incrémentée.
lastSequenceId() retourne toujours NULL.

• Pour vous connecter à une base de données SQLite2, spécifiez le paramètre


'sqlite2'=>true dans le tableau d'options passé à l'adaptateur, lors de la création de
l'instance de Pdo_Sqlite Adapter.

• Pour vous connecter à une base de données SQLite en mémoire, spécifiez le paramètre
'dsnprefix'=>':memory:' dans le tableau d'options passé à l'adaptateur, lors de la
création de l'instance de Pdo_Sqlite Adapter.

• Les anciennes versions du driver SQLite pour PHP ne semblent pas supporter les commandes
PRAGMA nécessaires pour s'assurer que les colonnes ayant un nom court soient utilisées
dans les résultats. Si vous avez des problèmes, tels que vos enregistrements sont retournés
avec une forme "nomtable.nomcolonne" lors de vos jointures, vous devriez alors mettre à jour
votre version de PHP.

1.11.11. Firebird/Interbase
• Cet adaptateur utilise l'extension PHP php_interbase.

• Firebird/interbase ne supporte pas les clé auto-incrémentées, donc vous devez spécifier un
paramètre de séquence à lastInsertId() ou lastSequenceId().

• Pour l'instant l'option Zend_Db::CASE_FOLDING n'est pas supportée par l'adaptateur


Firebird/interbase. Tout identificateur non échappé sera automatiquement retourné en
majuscules.

• Le nom de l'adaptateur est ZendX_Db_Adapter_Firebird.

Rappelez vous qu'il est nécessaire d'utiliser le paramètre 'adapterNamespace' avec la valeur
ZendX_Db_Adapter.

Nous recommandons de mettre à jour gds32.dll (ou l'équivalent linux) embarqué avec
PHP, à la même version que celle du serveur. Pour Firebird l'équivalent à gds32.dll est
fbclient.dll.

Par défaut tous les identifiants (nomde tables, de cahmps) sont retournés en majuscules.

442
Zend_Db

2. Zend_Db_Statement
En plus des méthodes telles que fetchAll() et insert() documentée dans Section 1,
« Zend_Db_Adapter », vous pouvez utiliser un objet statement pour l'analyser de manière plus
complète et récupérer vos résultats. Cette section décrit la marche à suivre pour obtenir un
statement et utiliser ses méthodes propres.

Zend_Db_Statement est basé sur l'objet PDOStatement dans l'extension PHP PHP Data Objects
(PDO).

2.1. Créer un statement


Cet objet est typiquement retourné par la méthode query() de votre objet adaptateur de base
de données. Cette méthode prépare un statement SQL : le premier argument est une chaîne
représentant la requête préparée, le second, un tableau de paramètres liés.

Exemple 169. Création d'un objet statement avec query()

$sql = 'SELECT * FROM bugs WHERE reported_by = ? AND bug_status = ?';


$stmt = $db->query($sql, array('goofy', 'FIXED'));

L'objet statement représente un statement SQL qui a été préparé, et exécuté une fois avec les
paramètres de liaison ("bind") spécifiés. S'il s'agissait d'une requête SELECT par exemple, alors
les résultats sont prêts à être récupérés.

Vous pouvez créer un statement avec son constructeur, mais c'est assez peu usuel. Passez
alors l'objet adaptateur en premier argument, et la chaîne représentant la requête en second.
Un fois construit, le statement est préparé automatiquement, mais pas exécuté.

Exemple 170. Utilisation du constructeur de statement

$sql = 'SELECT * FROM bugs WHERE reported_by = ? AND bug_status = ?';

$stmt = new Zend_Db_Statement_Mysqli($db, $sql);

2.2. Exécuter un statement


Vous aurez besoin d'exécuter un statement si vous l'avez crée explicitement avec son
constructeur. Utilisez sa méthode execute() pour ceci. Le seul argument que cette méthode
accepte est le tableau de "binds" (paramètres préparés).

Si vous utilisez les paramètres positionnés, ceux utilisés avec le point d'interrogation (?), passez
simplement les valeurs dans le tableau.

Exemple 171. Exécuter un statement avec des paramètres positionnés

$sql = 'SELECT * FROM bugs WHERE reported_by = ? AND bug_status = ?';

$stmt = new Zend_Db_Statement_Mysqli($db, $sql);

$stmt->execute(array('goofy', 'FIXED'));

Si vous utilisez les paramètres nommés, ceux définis avec un identifiant chaîne de caractère
précédée d'un (:), passez les valeurs liées sous forme de tableau associatif.

443
Zend_Db

Exemple 172. Exécution d'un statement avec paramètres nommés

$sql = 'SELECT * FROM bugs'


. ' WHERE reported_by = :reporter'
. ' AND bug_status = :status';

$stmt = new Zend_Db_Statement_Mysqli($db, $sql);

$stmt->execute(array(':reporter' => 'goofy', ':status' => 'FIXED'));

Les statements PDO acceptent les paramètres positionnés, ou nommés, mais pas les deux types
en même temps. Certaines classes Zend_Db_Statement pour les extensions non PDO peuvent
ne supporter qu'un seul de ces types.

2.3. Récupérer des résultats depuis un statement SELECT


Vous disposez de méthodes sur l'objet statement lorsque celui-ci a été exécuté sur une requête
SQL de type SELECT, SHOW, DESCRIBE ou EXPLAIN (qui produisent des résultats). Aussi,
INSERT, UPDATE et DELETE sont des exemples de requêtes ne produisant pas de résultats.
Vous pouvez donc les exécuter avec Zend_Db_Statement, mais vous ne pourrez pas appeler
les méthodes de récupération de résultats.

2.3.1. Récupérer un enregistrement unique depuis un statement


La méthode fetch() permet de ne récupérer qu'un seul résultat dans le statement
précédemment exécuté. Trois paramètres sont disponibles pour cette méthode, tous optionnels :

• Fetch style en premier, permet de spécifier le mode de capture du résultat. C'est la structure
dans laquelle celui-ci vous sera retourné. Voyez Section 1.3.2, « Changer le mode de
récupération (Fetch Mode) » pour une description des valeurs valides et de la forme des
résultats alors renvoyés.

• Cursor orientation est le second paramètre. Par défaut il vaut Zend_Db::FETCH_ORI_NEXT,


ce qui signifie que chaque appel futur à fetch() retourne l'enregistrement suivant.

• Offset, en troisième paramètre. Si le paramètre "cursor orientation" est réglé sur


Zend_Db::FETCH_ORI_ABS, alors le numéro d'offset est le numéro du résultat à retourner,
dans le statement. Si c'est Zend_Db::FETCH_ORI_REL, le numéro d'offset est relatif à la
position du curseur avant l'appel à fetch().

fetch() retourne FALSE si il n'y a plus de résultats restants dans le statement.

Exemple 173. Utiliser fetch() dans une boucle

$stmt = $db->query('SELECT * FROM bugs');

while ($row = $stmt->fetch()) {


echo $row['bug_description'];
}

Voyez aussi PDOStatement::fetch().

2.3.2. Récupérer un jeu de résultat complet


Pour récupérer tous les résultats d'un statement, utilisez fetchAll(). Ceci est équivalent à
appeler fetch() dans un boucle et retourner tous les résultats dans un tableau. La méthode

444
Zend_Db

fetchAll() accepte deux paramètres. Le premier est le mode de capture (fetch style), le
deuxième est le numéro de la colonne à retourner, si Zend_Db::FETCH_COLUMN est utilisé.

Exemple 174. Utilisation de fetchAll()

$stmt = $db->query('SELECT * FROM bugs');

$rows = $stmt->fetchAll();

echo $rows[0]['bug_description'];

Voyez aussi PDOStatement::fetchAll().

2.3.3. Changer le mode de capture (Fetch Mode)


Par défaut l'objet statement retourne les colonnes du jeu de résultat en tant que tableau
associatif, en faisant correspondre les noms des colonne et leur valeur. Vous pouvez
cependant spécifier un format différent, comme il est possible de faire avec la classe de
l'adaptateur. La méthode setFetchMode() permet ceci. Indiquez un mode de capture en
utilisant les constantes de la classe Zend_Db : FETCH_ASSOC, FETCH_NUM, FETCH_BOTH,
FETCH_COLUMN, et FETCH_OBJ. Voyez Section 1.3.2, « Changer le mode de récupération
(Fetch Mode) » pour plus d'informations sur ces modes de capture. Les appels suivants à
fetch() ou fetchAll() utiliseront le mode spécifié auparavant.

Exemple 175. Paramétrer le mode de capture (fetch mode)

$stmt = $db->query('SELECT * FROM bugs');

$stmt->setFetchMode(Zend_Db::FETCH_NUM);

$rows = $stmt->fetchAll();

echo $rows[0][0];

Voyez aussi PDOStatement::setFetchMode().

2.3.4. Récupérer une colonne simple depuis un statement exécuté


Pour retourner une colonne de résultat depuis un statement, utilisez la méthode
fetchColumn(). Le paramètre optionnel est un entier représentant l'index de la colonne
désirée, par défaut zéro. Cette méthode retourne un type scalaire, ou FALSE s'il n'y a plus de
résultats dans le statement.

Notez que cette méthode se comporte différemment de fetchCol() de l'adaptateur.


La méthode fetchColumn() du statement retourne une seule valeur d'un seul résultat.
fetchCol() de l'adaptateur retourne un tableau de valeurs issues de la première colonne du
jeu résultat.

Exemple 176. Utiliser fetchColumn()

$sql = 'SELECT bug_id, bug_description, bug_status FROM bugs';

$stmt = $db->query($sql);

$bug_status = $stmt->fetchColumn(2);

Voyez aussi PDOStatement::fetchColumn().

445
Zend_Db

2.3.5. Récupérer un résultat (Row) sous forme d'objet


Pour récupérer une ligne de résultat en tant qu'objet, depuis un statement exécuté, utilisez
la méthode fetchObject(). Celle-ci prend deux paramètres optionnels. Le premier est une
chaîne indiquant le nom de la classe que l'on souhaite se voir retourner, par défaut il s'agit
de "stdClass". Le deuxième paramètre est un tableau de paramètres qui sera passé au
constructeur de cette classe.

Exemple 177. Utiliser fetchObject()

$sql = 'SELECT bug_id, bug_description, bug_status FROM bugs';

$stmt = $db->query($sql);

$obj = $stmt->fetchObject();

echo $obj->bug_description;

Voyez aussi PDOStatement::fetchObject().

3. Zend_Db_Profiler
3.1. Introduction
Zend_Db_Profiler peut être activé pour permettre le profilage de requête. Les profils incluent
les requêtes exécutées par l'adaptateur, ainsi que leur temps d'exécution, permettant l'inspection
des requêtes qui ont été exécutées sans avoir besoin de rajouter le code spécifique de débogage
aux classes. L'utilisation avancée permet aussi au développeur de filtrer quelles requêtes il
souhaite profiler.

Le profileur s'active soit en passant une directive au constructeur de l'adaptateur, soit en


spécifiant à l'adaptateur de l'activer plus tard.

$params = array(
'host' => '127.0.0.1',
'username' => 'webuser',
'password' => 'xxxxxxxx',
'dbname' => 'test',
'profiler' => true // active le profileur ;
// mettre à false pour désactiver
// (désactivé par défaut)
);

$db = Zend_Db::factory('PDO_MYSQL', $params);

// stoppe le profileur :
$db->getProfiler()->setEnabled(false);

// active le profileur :
$db->getProfiler()->setEnabled(true);

La valeur de l'option profiler est souple. Elle est interprétée différemment suivant son type. La
plupart du temps, vous devriez simplement utiliser une variable booléenne, mais d'autres valeurs
vous permettent de personnaliser le comportement du profileur.

Un argument booléen active le profileur si c'est une valeur TRUE, ou le désactive si FALSE. La
classe de profileur est celle par défaut, par exemple Zend_Db_Profiler.

446
Zend_Db

$params['profiler'] = true;
$db = Zend_Db::factory('PDO_MYSQL', $params);

Une instance d'un objet profileur fait que l'adaptateur utilise cet objet. L'objet doit être de type
Zend_Db_Profiler ou une sous-classe. L'activation du profileur est faite séparément.

$profiler = Mon_Db_Profiler();
$profiler->setEnabled(true);
$params['profiler'] = $profiler;
$db = Zend_Db::factory('PDO_MYSQL', $params);

L'argument peut être un tableau associatif contenant une ou toutes les clés suivantes : "enabled",
"instance", et "class". Les clés "enabled" et "instance" correspondent aux types booléen et
instance décrites ci-dessus. La clé "class" est utilisée pour nommer une classe à prendre en tant
que profileur personnalisé. La classe doit être de type Zend_Db_Profiler ou une sous-classe.
La classe est instanciée sans aucun argument de constructeur. L'option "class" est ignorée
quand l'option "instance" est fournie.

$params['profiler'] = array(
'enabled' => true,
'class' => 'Mon_Db_Profiler'
);
$db = Zend_Db::factory('PDO_MYSQL', $params);

Enfin, l'argument peut être un objet de type Zend_Config contenant des propriétés, qui sont
traitées comme les clés de tableaux décrites ci-dessus. Par exemple, un fichier "config.ini"
peut contenir les données suivantes :

[main]
db.profiler.class = "Mon_Db_Profiler"
db.profiler.enabled = true

Cette configuration peut être appliquée par le code PHP suivant :

$config = new Zend_Config_Ini('config.ini', 'main');


$params['profiler'] = $config->db->profiler;
$db = Zend_Db::factory('PDO_MYSQL', $params);

La propriété "instance" peut être utilisée comme ceci :

$profiler = new Mon_Db_Profiler();


$profiler->setEnabled(true);
$configData = array(
'instance' => $profiler
);
$config = new Zend_Config($configData);
$params['profiler'] = $config;
$db = Zend_Db::factory('PDO_MYSQL', $params);

3.2. Utiliser le profileur


A n'importe quel moment, vous pouvez récupérer le profileur en utilisant la méthode
getProfiler() de l'adaptateur :

$profileur = $db->getProfiler();

447
Zend_Db

Ceci retourne une instance de Zend_Db_Profiler. Avec cette instance, le développeur peut
examiner les requêtes en utilisant un éventail de méthodes :

• getTotalNumQueries() retourne le nombre total de requêtes profilées.

• getTotalElapsedSecs() retourne le nombre total de secondes écoulées pour chaque


requête profilée.

• getQueryProfiles() retourne un tableau de tous les profils de requêtes.

• getLastQueryProfile() retourne le profil de requête le plus récent, peut importe si la


requête à fini de s'exécuter ou pas (si l'exécution n'est pas finie, le temps de fin sera NULL).

• clear() nettoie tous les anciens profils de la pile.

La valeur de retour de getLastQueryProfile() et les éléments individuels de


getQueryProfiles() sont des objets de type Zend_Db_Profiler_Query qui permettent
d'inspecter les requêtes :

• getQuery() retourne le SQL de la requête sous forme de texte. Le texte de SQL d'une
requête préparée avec des paramètres est le texte au moment où la requête a été préparée,
donc il contient les emplacements de paramètre, mais pas les valeurs utilisées quand la
déclaration est exécutée.

• getQueryParams() retourne un tableau des valeurs de paramètres utilisées lors de


l'exécution d'une requête préparée. Ceci inclue à la fois les paramètres attachés et les
arguments de la méthode execute(). Les clés du tableau sont les positions (base 1) ou les
noms des paramètres.

• getElapsedSecs() retourne le nombre de secondes d'exécution de la requête.

L'information que Zend_Db_Profiler fourni est utile pour profiler des goulots d'étranglement
dans les applications, ainsi que pour déboguer les requêtes qui viennent d'être exécutées. Par
exemple, pour voir la dernière requête qui vient de s'exécuter :

$query = $profileur->getLastQueryProfile();
echo $query->getQuery();

Si une page se génère lentement, utilisez le profileur pour déterminer le nombre total de requêtes,
et ensuite passer d'une requête à l'autre pour voir laquelle a été la plus longue :

$tempsTotal = $profileur->getTotalElapsedSecs();
$nombreRequetes = $profileur->getTotalNumQueries();
$tempsLePlusLong = 0;
$requeteLaPlusLongue = null;

foreach ($profileur->getQueryProfiles() as $query) {


if ($query->getElapsedSecs() > $tempsLePlusLong) {
$tempsLePlusLong = $query->getElapsedSecs();
$requeteLaPlusLongue = $query->getQuery();
}
}

echo 'Exécution de '


. $nombreRequetes
. ' requêtes en '
. $tempsTotal
. ' secondes' . "\n";

448
Zend_Db

echo 'Temps moyen : '


. $tempsTotal / $nombreRequetes
. ' secondes' . "\n";
echo 'Requêtes par seconde: '
. $nombreRequetes / $tempsTotal
. ' seconds' . "\n";
echo 'Requête la plus lente (secondes) : '
. $tempsLePlusLong . "\n";
echo "Requête la plus lente (SQL) : \n"
. $requeteLaPlusLongue . "\n";

3.3. Utilisation avancée du profileur


En plus de l'inspection de requête, le profileur permet aussi au développeur de filtrer
quelles requêtes il veut profiler. Les méthodes suivantes fonctionnent avec une instance de
Zend_Db_Profiler :

3.3.1. Filtrer par temps d'exécution


setFilterElapsedSecs() permet au développeur de définir un temps minimum d'exécution
de la requête avant que celle-ci soit profilée. Pour retirer le filtre, passez une valeur NULL à la
méthode.

// Seules les requêtes qui durent au moins 5 secondes sont profilées :


$profileur->setFilterElapsedSecs(5);

// Profil de toutes les requêtes, peu importe leur durée :


$profileur->setFilterElapsedSecs(null);

3.3.2. Filtrer par type de requête


setFilterQueryType() permet au développeur de définir quels types de requêtes doivent
être profilées ; pour profiler des types multiples vous pouvez utiliser le OU logique. Les types de
requêtes sont définis sous forme de constantes de Zend_Db_Profiler :

• Zend_Db_Profiler::CONNECT : opérations de connexion ou de sélection de base de


données.

• Zend_Db_Profiler::QUERY : requête générale qui ne correspond pas aux autres types.

• Zend_Db_Profiler::INSERT : toute requête qui ajoute des données dans la base de


données, généralement du SQL INSERT.

• Zend_Db_Profiler::UPDATE : toute requête qui met à jour des données, généralement


du SQL UPDATE.

• Zend_Db_Profiler::DELETE : toute requête qui efface des données, généralement du


SQL DELETE.

• Zend_Db_Profiler::SELECT : toute requête qui récupère des données, généralement du


SQL SELECT.

• Zend_Db_Profiler::TRANSACTION : toute requête qui concerne des opérations de


transaction, comme start transaction, commit, ou rollback.

Comme avec setFilterElapsedSecs(), vous pouvez retirer tous les filtres en passant NULL
comme unique argument.

449
Zend_Db

// profile uniquement les requêtes SELECT


$profileur->setFilterQueryType(Zend_Db_Profiler::SELECT);

// profile les requêtes SELECT, INSERT, et UPDATE


$profileur->setFilterQueryType(Zend_Db_Profiler::SELECT
| Zend_Db_Profiler::INSERT
| Zend_Db_Profiler::UPDATE);

// profile les requêtes DELETE


$profileur->setFilterQueryType(Zend_Db_Profiler::DELETE);

// Efface tous les filtres


$profileur->setFilterQueryType(null);

3.3.3. Récupérer les profils par type de requête


Utiliser setFilterQueryType() peut réduire les profils générés. Cependant il est parfois utile
de garder tous les profils et voir uniquement ceux dont on a besoin, à un moment donné. Une
autre possibilité de getQueryProfiles() est qu'il est possible de filtrer à la volée, en passant
un type de requête (ou une combinaison logique de types de requête) comme premier argument ;
voir cette section pour la liste des constantes de types de requête.

// Récupère uniquement les profils des requêtes SELECT


$profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::SELECT);

// Récupère uniquement les profils des requêtes :


// SELECT, INSERT, et UPDATE
$profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::SELECT
| Zend_Db_Profiler::INSERT
| Zend_Db_Profiler::UPDATE);

// Récupère uniquement les profils des requêtes DELETE


// (on peut donc comprendre pourquoi les données disparaissent)
$profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::DELETE);

3.4. Profileurs spécialisés


Un profileur spécialisé est un objet qui hérite de Zend_Db_Profiler. Les profileurs spécialisés
traitent les informations de profilage de manière spécifique.

3.4.1. Profiler avec Firebug


Zend_Db_Profiler_Firebug envoie des informations de profilage vers la console Firebug.

Toutes les données sont envoyées via le composant


Zend_Wildfire_Channel_HttpHeaders qui utilise les en-têtes HTTP pour s'assurer que
le contenu de la page n'est pas perturbé. Déboguer les requêtes AJAX qui requière du JSON
"propre" ou un réponse XML est possible avec cette approche.

Éléments requis :

• Navigateur Firefox idéalement en version 3 mais la version 2 est aussi supportée.

• L'extension Firefox nommée Firebug qui peut être téléchargée à cette adresse https://
addons.mozilla.org/en-US/firefox/addon/1843.

• L'extension Firefox nommée FirePHP qui peut être téléchargée à cette adresse https://
addons.mozilla.org/en-US/firefox/addon/6149.

450
Zend_Db

Exemple 178. Profilage de base de données avec Zend_Controller_Front

// Dans votre fichier d'amorçage


$profiler = new Zend_Db_Profiler_Firebug('All DB Queries');
$profiler->setEnabled(true);

// Attacher le profileur à votre adaptateur de base de données


$db->setProfiler($profiler)

// Distribuer votre contrôleur frontal

// Toutes les requêtes dans vos fichiers de modèles, vues et


// contrôleurs seront maintenant profilées et envoyées à Firebug

Exemple 179. Profilage de base de données sans Zend_Controller_Front

$profiler = new Zend_Db_Profiler_Firebug('All DB Queries');


$profiler->setEnabled(true);

// Attacher le profileur à votre adaptateur de base de données


$db->setProfiler($profiler)

$request = new Zend_Controller_Request_Http();


$response = new Zend_Controller_Response_Http();
$channel = Zend_Wildfire_Channel_HttpHeaders::getInstance();
$channel->setRequest($request);
$channel->setResponse($response);

// Démarrer l'output buffering


ob_start();

// Maintenant vous pouvez lancer les requêtes


// qui doivent être profilées

// Envoi des données de profiling vers le navigateur


$channel->flush();
$response->sendHeaders();

4. Zend_Db_Select
4.1. Introduction
L'objet Zend_Db_Select représente une instruction de requête SQL de type SELECT. La classe
a des méthodes pour ajouter différentes parties à la requête. Vous pouvez indiquer quelques
parties de la requête en utilisant des structures de données et des méthodes de PHP, et la classe
forme la syntaxe correcte de SQL pour vous. Après avoir construit une requête, vous pouvez
l'exécuter comme si vous l'aviez écrite comme une chaîne de caractères.

Les possibilités offertes par Zend_Db_Select inclut :

• des méthodes orientées objet pour spécifier des requêtes SQL morceau par morceau ;

• l'abstraction de certaines parties de la requête SQL indépendamment de la base de données ;

• l'échappement automatique des identificateurs de méta-données dans la plupart des cas, pour
supporter les identificateurs contenant les mots réservés SQL et les caractères spéciaux ;

451
Zend_Db

• l'échappement des identificateurs et des valeurs, afin de réduire les risques d'attaques par
injection SQL.

L'utilisation de Zend_Db_Select n'est pas obligatoire. Pour de très simple requêtes SELECT ,
il est d'habitude plus simple de spécifier la requête SQL entière comme une chaîne et l'exécuter
en utilisant des méthodes de l'adaptateur comme query() ou fetchAll(). L'utilisation de
Zend_Db_Select est utile si vous devez assembler une requête SELECT par procédure, ou
basé sur une logique conditionnelle dans votre application.

4.2. Créer un objet Select


Vous pouvez créer une instance d'un objet Zend_Db_Select en utilisant la méthode select()
de l'objet Zend_Db_Adapter_Abstract.

Exemple 180. Exemple d'utilisation de la méthode select()

$db = Zend_Db::factory( ...options... );


$select = $db->select();

Une autre manière de créer un objet Zend_Db_Select est avec son constructeur, en indiquant
l'adaptateur de base de données comme argument.

Exemple 181. Exemple de création d'un nouvel objet Select

$db = Zend_Db::factory( ...options... );


$select = new Zend_Db_Select($db);

4.3. Construction de requêtes Select


En construisant la requête, vous pouvez ajouter des clauses à la requête une par une. Il y a une
méthode séparée pour ajouter chaque clause à l'objet Zend_Db_Select.

Exemple 182. Exemple d'utilisation des méthodes d'ajout de clauses

// Créer un objet Zend_Db_Select


$select = $db->select();

// Ajouter une clause FROM


$select->from( ...spécifiez une table et des colonnes... )

// Ajouter une clause WHERE


$select->where( ...spécifiez des critères de recherche... )

// Ajouter une clause ORDER BY


$select->order( ...spécifiez des critères de tri... );

Vous pouvez également employer la plupart des méthodes de l'objet Zend_Db_Select avec une
interface fluide et simple. Une interface fluide signifie que chaque méthode renvoie une référence
à l'objet qui a été appelé, ainsi vous pouvez immédiatement appeler une autre méthode.

Exemple 183. Exemple d'utilisation de l'interface fluide

$select = $db->select()
->from( ...spécifiez une table et des colonnes... )
->where( ...spécifiez des critères de recherche... )
->order( ...spécifiez des critères de tri... );

452
Zend_Db

Les exemples de cette section montrent l'utilisation de l'interface fluide, mais vous pouvez
employer une interface non-fluide dans tous les cas. Il est souvent nécessaire d'employer
l'interface non-fluide, par exemple, si votre application doit exécuter de la logique avant d'ajouter
une clause à une requête.

4.3.1. Ajouter une clause FROM

Indiquez la table pour la requête en utilisant la méthode from(). Vous pouvez indiquer le
nom de table comme une chaîne de caractères. Zend_Db_Select applique l'échappement des
identificateurs autour du nom de table, ainsi vous pouvez employer les caractères spéciaux.

Exemple 184. Exemple d'utilisation de la méthode from()

// Construire cette requête :


// SELECT *
// FROM "produits"

$select = $db->select()
->from( 'produits' );

Vous pouvez également indiquer le nom de corrélation (parfois appelé "l'alias de table") pour
une table. Au lieu d'une chaîne de caractère simple, employez un tableau associatif faisant
correspondre le nom de corrélation au nom de table. Dans d'autres clauses de la requête SQL,
employez ce nom de corrélation. Si votre requête réalise des jointures sur plus d'une table,
Zend_Db_Select produit des noms uniques de corrélation basés sur les noms de table, pour
chaque table pour lesquelles vous n'indiquez pas le nom de corrélation.

Exemple 185. Exemple d'utilisation d'un alias de nom de table

// Construire cette requête :


// SELECT p.*
// FROM "produits" AS p

$select = $db->select()
->from( array('p' => 'produits') );

Certaines marques de SGBDR supportent un spécificateur de schéma principal pour une


table. Vous pouvez spécifiez un nom de table comme "nomDuSchema.nomDeTable", où
Zend_Db_Select échappera chaque partie individuellement, ou vous pouvez spécifier le nom
du schéma séparément. Un nom de schéma spécifié dans le nom de table sera prioritaire sur
un schéma fourni séparément dans les cas où les deux seraient fournis.

Exemple 186. Exemple d'utilisation d'un nom de schéma

// Construire cette requête :


// SELECT *
// FROM "monschema"."produits"

$select = $db->select()
->from( 'monschema.produits' );

// ou

$select = $db->select()
->from('produits', '*', 'monschema');

453
Zend_Db

4.3.2. Ajouter des colonnes


Dans le deuxième argument de la méthode from(), vous pouvez indiquer les colonnes à choisir
parmi les tables respectives. Si vous n'indiquez aucune colonne, la valeur par défaut est "*", la
caractère de remplacement SQL pour "toutes les colonnes".

Vous pouvez énumérer les colonnes dans un tableau simple de chaîne de caractère, ou en
tant que tableau associatif faisant correspondre l'alias de la colonne au nom de la colonne. Si
vous avez seulement une colonne à requêter, et vous n'avez pas besoin d'indiquer un alias de
colonne, vous pouvez l'énumérer comme une chaîne simple au lieu d'un tableau.

Si vous passez un tableau comme argument pour les colonnes, aucune colonne pour la table
correspondante ne sera inclus dans le jeu de résultat. Voir un exemple de code sous la section
concernant la méthode join().

Vous pouvez indiquer le nom de colonne en tant que "aliasDeTable.nomDeColonne".


Zend_Db_Select échappera chaque partie individuellement. Si vous n'indiquez pas un nom
d'alias pour une colonne, elle emploie le nom de corrélation de la table nommée dans la méthode
courante from().

Exemple 187. Exemples de spécification de colonnes

// Construire cette requête :


// SELECT p."produit_id", p."produit_nom"
// FROM "produits" AS p

$select = $db->select()
->from(array('p' => 'produits'),
array('produit_id', 'produit_nom'));

// Construire la même requête, en spécifiant l'alias de table :


// SELECT p."produit_id", p."produit_nom"
// FROM "produits" AS p

$select = $db->select()
->from(array('p' => 'produits'),
array('p.produit_id', 'p.produit_nom'));

// Construire cette requête avec un alias pour une colonne :


// SELECT p."produit_id" AS prodno, p."produit_nom"
// FROM "produits" AS p

$select = $db->select()
->from(array('p' => 'produits'),
array('prodno' => 'produit_id', 'produit_nom'));

4.3.3. Ajouter une expression de colonne


Les colonnes dans les requêtes SQL sont parfois des expressions, pas simplement des noms
de colonnes d'une table. Les expressions peuvent avoir des noms d'alias ou peuvent nécessiter
d'être échappées. Si la chaîne de caractère désignant votre colonne contient des parenthèses,
Zend_Db_Select la reconnaît comme une expression.

Vous pouvez aussi créer un objet de type Zend_Db_Expr explicitement, pour éviter qu'une
chaîne soit traitée comme un nom de colonne. Zend_Db_Expr est une classe minimale qui
contient une unique chaîne de caractère. Zend_Db_Select reconnaît les objets de type

454
Zend_Db

Zend_Db_Expr et les convertit en chaînes de caractères, mais n'applique aucun changement,


tel qu'un échappement ou un alias.

Utiliser Zend_Db_Expr pour les noms de colonnes n'est pas nécessaire si


votre expression de colonne contient des parenthèses ; Zend_Db_Select
reconnaît les parenthèses et traite la chaîne comme une expression en omettant
l'échappement et les alias.

Exemple 188. Exemples d'utilisation de colonnes contenant des expressions

// Construire cette requête :


// SELECT p."produit_id", LOWER(produit_nom)
// FROM "produits" AS p
// Une expression avec parenthèses devient implicitement
// un objet Zend_Db_Expr.

$select = $db->select()
->from(array('p' => 'produits'),
array('produit_id', 'LOWER(produit_nom)'));

// Construire cette requête :


// SELECT p."produit_id", (p.prix * 1.08) AS prix_avec_taxe
// FROM "produits" AS p

$select = $db->select()
->from(array('p' => 'produits'),
array('produit_id',
'prix_avec_taxe' => '(p.prix * 1.08)'));

// Construire cette requête en utilisant explicitement Zend_Db_Expr :


// SELECT p."produit_id", p.prix * 1.08 AS prix_avec_taxe
// FROM "produits" AS p

$select = $db->select()
->from(array('p' => 'produits'),
array('produit_id',
'prix_avec_taxe' =>
new Zend_Db_Expr('p.prix * 1.08')));

Dans les cas ci-dessus, Zend_Db_Select ne change pas la chaîne pour appliquer des alias ou
échapper les identificateurs. Si ces changements sont nécessaires pour résoudre l'ambiguïté,
vous devez faire manuellement les changements dans la chaîne de caractères.

Si vos noms de colonne sont des mots-clés de SQL ou contiennent les caractères spéciaux,
vous devriez employer la méthode quoteIdentifier() de l'adaptateur et interpoler le résultat
dans la chaîne de caractères. La méthode quoteIdentifier() utilise l'échappement SQL
pour délimiter les identificateurs, qui indique clairement que c'est un identificateur pour une table
ou une colonne, et non n'importe quelle autre partie de la syntaxe de SQL.

Votre code est plus indépendant du SGBDR si vous utilisez la méthode quoteIdentifier()
au lieu d'échapper littéralement dans votre chaîne, car quelques marques de SGBDR
utilisent des symboles non standards pour échapper les identificateurs. La méthode
quoteIdentifier() est conçue pour utiliser le symbole d'échappement approprié basé
sur le type d'adaptateur. La méthode quoteIdentifier() échappe aussi tout caractère
d'échappement qui apparaissent dans l'identificateur lui-même.

455
Zend_Db

Exemple 189. Exemples d'échappement de colonnes dans une expression

// Construire cette requête, en échappant une colonne spéciale


// nommée "from" dans une expression :
// SELECT p."from" + 10 AS origine
// FROM "produits" AS p

$select = $db->select()
->from(array('p' => 'produits'),
array('origine' => '(p.'
. $db->quoteIdentifier('from')
. ' + 10)'));

4.3.4. Ajouter des colonnes à une table FROM ou JOIN existante

Il peut y avoir des cas où vous souhaitez ajouter des colonnes à une table FROM ou
JOIN existante après que ces méthodes aient été appelées. La méthode columns() vous
permet d'ajouter des colonnes spécifiques à n'importe quel moment avant que la requête ne
soit exécutée. Vous pouvez fournir les colonnes en tant qu'une chaîne de caractères, une
Zend_Db_Expr ou un tableau de ces derniers. Le second argument de cette méthode peut être
omis, impliquant que les colonnes sont ajoutées à la table FROM, sinon un alias déjà défini doit
être utilisé.

Exemple 190. Exemples d'ajout de colonnes avec la méthode columns()

// Construire cette requête :


// SELECT p."produit_id", p."produit_nom"
// FROM "produits" AS p

$select = $db->select()
->from(array('p' => 'produits'), 'produit_id')
->columns('produit_nom');

// Construire la même requête, en spécifiant l'alias :


// SELECT p."produit_id", p."produit_nom"
// FROM "produits" AS p

$select = $db->select()
->from(array('p' => 'produits'), 'p.produit_id')
->columns('produit_nom', 'p');
// Ou alternativement columns('p.produit_nom')

4.3.5. Ajouter une autre table à la requête avec JOIN

Beaucoup de requêtes utiles impliquent l'utilisation de JOIN pour combiner les lignes issues de
tables multiples. Vous pouvez ajouter des tables à une requête en utilisant la méthode join().
L'utilisation de cette méthode est similaire à la méthode from(), excepté que vous pouvez aussi
spécifier une condition join dans la plupart des cas.

456
Zend_Db

Exemple 191. Exemple d'utilisation de la méthode join()

// Construire cette requête :


// SELECT p."produit_id", p."produit_nom", l.*
// FROM "produits" AS p JOIN "ligne_items" AS l
// ON p.produit_id = l.produit_id

$select = $db->select()
->from(array('p' => 'produits'),
array('produit_id', 'produit_nom'))
->join(array('l' => 'ligne_items'),
'p.produit_id = l.produit_id');

Le deuxième argument de join() est une chaîne qui représente la condition join. C'est une
expression qui déclare les critères par lesquels les lignes d'une table correspondent aux lignes
dans une autre table. Vous pouvez utiliser un nom d'alias dans cette expression.

Aucun échappement n'est appliqué à une expression que vous spécifiez pour
une condition join ; si vous avez des noms de colonnes qui nécessitent d'être
échappées, vous devez utiliser quoteIdentifier() quand vous préparez la
chaîne pour une condition join.

Le troisième argument de join() est un tableau des noms de colonnes, comme c'est utilisé
dans la méthode from(). La valeur par défaut est "*", la méthode supporte les alias, les
expressions, et les objets Zend_Db_Expr de la même manière que le tableau de noms de
colonnes de la méthode from().

Pour ne choisir aucune colonne à partir d'une table, utilisez un tableau vide pour la liste de
colonnes. Cette utilisation fonctionnerait aussi avec la méthode from(), mais typiquement vous
pouvez avoir besoin de colonnes issues de la table primaire dans vos requêtes, tandis que vous
pourriez ne vouloir aucune colonne de la table jointe.

Exemple 192. Exemple avec aucune colonne spécifiée

// Construire cette requête :


// SELECT p."produit_id", p."produit_nom"
// FROM "produits" AS p JOIN "ligne_items" AS l
// ON p.produit_id = l.produit_id

$select = $db->select()
->from(array('p' => 'produits'),
array('produit_id', 'produit_name'))
->join(array('l' => 'ligne_items'),
'p.produit_id = l.produit_id',
array() ); // liste de colonnes vide

Notez le tableau vide (array()) dans l'exemple ci-dessus à la place de la liste de colonnes
de la table jointe.

Le SQL a plusieurs types de jointures. Voyez la liste ci-dessous des méthodes supportant les
différents types de jointures dans Zend_Db_Select.

• INNER JOIN avec les méthodes join(table, jointure, [colonnes]) ou


joinInner(table, jointure, [colonnes]).

457
Zend_Db

Ceci est le type de jointure le plus commun. Les lignes de chaque table sont comparées
en utilisant la condition join spécifiée. Le résultat inclut seulement les lignes qui vérifient la
condition join. Le résultat peut être vide si aucune ligne ne satisfait la condition.

Tous les marques de SGBDR supportent ce type de jointure.

• LEFT JOIN avec la méthode joinLeft(table, condition, [colonnes]).

Toutes les lignes issues de la table opérande de gauche sont inclues, les lignes
correspondantes de la table de droite sont inclues, et les colonnes de la table opérande de
droite sont remplies de NULL si aucune ligne existante ne correspond à la table de gauche.
Tous les marques de SGBDR supportent ce type de jointure.

• RIGHT JOIN avec la méthode joinRight(table, condition, [colonnes]).

La jointure étrangère droite est le complément de la jointure étrangère gauche. Toutes les
lignes issues de la table opérande de droite sont inclues, les lignes correspondantes de la
table de gauche sont inclues, et les colonnes de la table opérande de gauche sont remplies
de NULL si aucune ligne existante ne correspond à la table de droite.

Certaines marques de SGBDR ne supportent pas ce type de jointure, mais en général toute
jointure droite peut être représentée comme une jointure gauche en inversant l'ordre des
tables.

• FULL JOIN avec la méthode joinFull(table, condition, [colonnes]).

Une jointure étrangère complète est comme la combinaison d'une jointure étrangère gauche
et d'une jointure étrangère droite. Toutes les lignes des deux tables sont inclues, appairées
ensemble dans la même ligne de résultat si elles satisfont la condition de jointure, et sinon
appairées avec des valeurs NULL à la place des colonnes de l'autre table.

Certaines marques de SGBDR ne supportent pas ce type de jointure.

• CROSS JOIN avec la méthode joinCross(table, [colonnes]).

Une jointure croisée est un produit cartésien. Chaque ligne de la première table est assortie
avec chaque ligne de la seconde. Ainsi le nombre de lignes du résultat est équivalent au
produit du nombre de lignes de chacune des tables. Vous pouvez filtrer le résultat en utilisant
une clause WHERE ; dans ce cas une jointure croisée est semblable à l'ancienne syntaxe
de jointure SQL-89.

La méthode joinCross() n'a pas de paramètres pour spécifier la condition de jointure.


Certaines marques de SGBDR ne supportent pas ce type de jointure.

• NATURAL JOIN avec la méthode joinNatural(table, [colonnes]).

Une jointure naturelle compare chaque(s) colonne(s) qui apparaissent avec le même nom
dans les deux tables. La comparaison est l'égalité pour toute(s) la(es) colonne(s) ; la
comparaison des colonnes utilisant l'inégalité n'est pas une jointure naturelle. Seules les
jointures internes (NdT : INNER) naturelles sont supportées par cette API, même si la syntaxe
SQL permet aussi bien des jointures naturelles étrangères (NdT : OUTER).

La méthode joinNatural() n'a pas de paramètres pour spécifier la condition de jointure.

En plus de ces méthodes join, vous pouvez simplifier vos requêtes en utilisant les méthodes de
type join*Using. Au lieu de fournir une condition complète à votre jointure, vous fournissez

458
Zend_Db

simplement le nom de la colonne sur laquelle réaliser la jointure et l'objet Zend_Db_Select


complète la condition pour vous.

Exemple 193. Exemple avec la méthode joinUsing()

// Construire cette requête :


// SELECT *
// FROM "table1"
// JOIN "table2"
// ON "table1".colonne1 = "table2".colonne1
// WHERE colonne2 = 'foo'

$select = $db->select()
->from('table1')
->joinUsing('table2', 'colonne1')
->where('column2 = ?', 'foo');

Chacune des méthodes join applicables du composant Zend_Db_Select possède une


méthode correspondante "using".

• joinUsing(table, join, [columns]) et joinInnerUsing(table, join,


[columns])

• joinLeftUsing(table, join, [columns])

• joinRightUsing(table, join, [columns])

• joinFullUsing(table, join, [columns])

4.3.6. Ajouter une clause WHERE


Vous pouvez spécifier des critères pour restreindre le nombre de lignes du résultat en utilisant
la méthode where(). Le premier argument de cette méthode est une expression SQL, et cette
expression est utilisée dans une clause WHERE dans la requête.

Exemple 194. Exemple d'utilisation de la méthode where()

// Construire cette requête :


// SELECT produit_id, produit_nom, prix
// FROM "produits"
// WHERE prix > 100.00

$select = $db->select()
->from('produits',
array('produit_id', 'produit_nom', 'prix'))
->where('prix > 100.00');

Aucun échappement n'est appliqué aux expressions passées aux méthodes


where() ou orWhere(). Si vous avez des noms de colonnes qui nécessitent
d'être échappés, vous devez utiliser quoteIdentifier() quand vous générez
la chaîne pour la condition.

Le second argument de la méthode where() est optionnel. C'est une valeur à substituer dans
l'expression. Zend_Db_Select échappe cette valeur et la substitue au caractère point ("?")
d'interrogation dans l'expression.

459
Zend_Db

Exemple 195. Exemple d'un paramètre dans la méthode where()

// Construire cette requête :


// SELECT produit_id, produit_nom, prix
// FROM "produits"
// WHERE (prix > 100.00)

$prixminimum = 100;

$select = $db->select()
->from('produits',
array('produit_id', 'produit_nom', 'prix'))
->where('prix > ?', $prixminimum);

Vous pouvez fournir un tableau en tant que second paramètre de la méthode where() quand
vous utilisez l'opérateur SQL "IN".

Exemple 196. Exemple d'un paramètre de type tableau pour la méthode where()

// Construire cette requête :


// SELECT produit_id, produit_nom, prix
// FROM "produits"
// WHERE (produit_id IN (1, 2, 3))

$productIds = array(1, 2, 3);

$select = $db->select()
->from('produits',
array('produit_id', 'produit_nom', 'prix'))
->where('produit_id IN (?)', $productIds);

Vous pouvez appeler la méthode where() plusieurs fois sur la même objet Zend_Db_Select.
La requête résultante combine les différents termes ensemble en utilisant AND entre eux.

Exemple 197. Exemple avec plusieurs appels de where()

// Construire cette requête :


// SELECT produit_id, produit_nom, prix
// FROM "produits"
// WHERE (prix > 100.00)
// AND (prix < 500.00)

$prixminimum = 100;
$prixmaximum = 500;

$select = $db->select()
->from('produits',
array('produit_id', 'produit_nom', 'prix'))
->where('prix > ?', $prixminimum)
->where('prix < ?', $prixmaximum);

Si vous devez combiner ensemble des termes en utilisant OR, utilisez la méthode orWhere().
Cette méthode est utilisée de la même manière que la méthode where(), excepté que le terme
spécifié est précédé par OR, au lieu de AND.

460
Zend_Db

Exemple 198. Exemple d'utilisation de la méthode orWhere()

// Construire cette requête :


// SELECT produit_id, produit_nom, prix
// FROM "produits"
// WHERE (prix < 100.00)
// OR (prix > 500.00)

$prixminimum = 100;
$prixmaximum = 500;

$select = $db->select()
->from('produits',
array('produit_id', 'produit_nom', 'prix'))
->where('prix < ?', $prixminimum)
->orWhere('prix > ?', $prixmaximum);

Zend_Db_Select met automatiquement des parenthèses autour de chaque expression


spécifiée en utilisant les méthodes where() ou orWhere(). Ceci permet de s'assurer que la
priorité de l'opérateur booléen n'entraîne pas de résultats inattendus.

Exemple 199. Exemple de mise en parenthèse d'expressions booléennes

// Construire cette requête :


// SELECT produit_id, produit_nom, prix
// FROM "produits"
// WHERE (prix < 100.00 OR prix > 500.00)
// AND (produit_nom = 'Pomme')

$prixminimum = 100;
$prixmaximum = 500;
$prod = 'Pomme';

$select = $db->select()
->from('produits',
array('produit_id', 'produit_nom', 'prix'))
->where("prix < $prixminimum OR prix > $prixmaximum")
->where('produit_nom = ?', $prod);

Dans l'exemple ci-dessus, le résultat serait tout à fait différent sans parenthèses, car AND a
une plus grande priorité que OR. Zend_Db_Select applique les parenthèses avec pour effet
de relier de manière plus étroite chaque expression dans les appels successifs de where()
qu'avec AND qui combine les expressions.

4.3.7. Ajouter une clause GROUP BY

Dans la syntaxe SQL, la clause GROUP BY vous permet de réduire le nombre de lignes du
résultat de la requête à une ligne par valeur unique trouvé dans une(des) colonne(s) nommées)
dans la clause GROUP BY.

Dans Zend_Db_Select, vous pouvez spécifier la(es) colonne(s) à utiliser pour calculer les
groupes de lignes en utilisant la méthode group(). L'argument de cette méthode est une
colonne ou un tableau de colonnes à utiliser dans la clause GROUP BY.

461
Zend_Db

Exemple 200. Exemple d'utilisation de la méthode group()

// Construire cette requête :


// SELECT p."produit_id", COUNT(*) AS ligne_items_par_produit
// FROM "produits" AS p JOIN "ligne_items" AS l
// ON p.produit_id = l.produit_id
// GROUP BY p.produit_id

$select = $db->select()
->from(array('p' => 'produits'),
array('produit_id'))
->join(array('l' => 'ligne_items'),
'p.produit_id = l.produit_id',
array('ligne_items_par_produit' => 'COUNT(*)'))
->group('p.produit_id');

Comme le tableau de colonnes de la méthode from(), vous pouvez utiliser des noms d'alias
dans le nom de la colonne, et la colonne est échappée comme un identificateur à moins que la
chaîne ne contiennent des parenthèses ou que ce soit un objet de type Zend_Db_Expr.

4.3.8. Ajouter une clause HAVING


Dans la syntaxe SQL, la clause HAVING applique une restriction sur un groupe de lignes. Ceci
est similaire à la manière dont la clause WHERE applique une restriction sur des lignes. Mais les
deux clauses sont différentes car les conditions WHERE sont appliquées avant que les groupes de
lignes ne soient définis, alors que les conditions HAVING sont appliquées après que les groupes
aient été définis.

Dans Zend_Db_Select, vous pouvez spécifier des conditions pour restreindre des groupes
en utilisant la méthode having(). Son utilisation est similaire à celle de la méthode where().
Le premier argument est une chaîne contenant une expression SQL. Le second argument
facultatif est une valeur qui est utilisé pour remplacer le caractère de substitution positionné dans
l'expression SQL. Les expressions passées dans de multiples appels de la méthode having()
sont combinées en utilisant l'opérateur booléen AND, ou l'opérateur OR si vous utilisez la méthode
orHaving().

Exemple 201. Exemple d'utilisation de la méthode having()

// Construire cette requête :


// SELECT p."produit_id", COUNT(*) AS ligne_items_par_produit
// FROM "produits" AS p JOIN "ligne_items" AS l
// ON p.produit_id = l.produit_id
// GROUP BY p.produit_id
// HAVING ligne_items_par_produit > 10

$select = $db->select()
->from(array('p' => 'produits'),
array('produit_id'))
->join(array('l' => 'ligne_items'),
'p.produit_id = l.produit_id',
array('ligne_items_par_produit' => 'COUNT(*)'))
->group('p.produit_id')
->having('ligne_items_par_produit > 10');

Aucun échappement n'est appliqué aux expressions fournies aux méthodes


having() ou orHaving(). Si vous avez des noms de colonnes qui nécessitent

462
Zend_Db

d'être échappées, vous devez utiliser quoteIdentifier() quand vous


générez la chaîne de cette condition.

4.3.9. Ajouter une clause ORDER BY

Dans la syntaxe SQL, la clause ORDER BY spécifie une ou plusieurs colonnes ou expressions
suivant lesquelles le résultat d'une requête doit être trié. Si plusieurs colonnes sont listées, les
colonnes secondaires sont utilisées pour résoudre les égalités ; l'ordre du tri est déterminé par
les colonnes secondaires si les colonnes précédentes contiennent des valeurs identiques. Le
tri par défaut est ascendant (du plus petit vers le plus grand). Vous pouvez aussi appliqué un
tri descendant (du plus grand vers le plus petit) pour une colonne en spécifiant le mot-clé DESC
après la colonne.

Dans Zend_Db_Select, vous pouvez utiliser la méthode order() pour spécifier une colonne
ou un tableau de colonnes par lesquelles vous voulez trier. Chaque élément du tableau est une
chaîne nommant une colonne, facultativement suivi les mots-clés ASC ou DESC en séparant avec
un espace.

Comme pour les méthodes from() et group(), les noms de colonnes sont échappées comme
des identificateurs, à moins qu'elles ne contiennent des parenthèses ou ne soient des objets de
type Zend_Db_Expr.

Exemple 202. Exemple d'utilisation de la méthode order()

// Construire cette requête :


// SELECT p."produit_id", COUNT(*) AS ligne_items_par_produit
// FROM "produits" AS p JOIN "ligne_items" AS l
// ON p.produit_id = l.produit_id
// GROUP BY p.produit_id
// ORDER BY "ligne_items_par_produit" DESC, "produit_id"

$select = $db->select()
->from(array('p' => 'produits'),
array('produit_id'))
->join(array('l' => 'ligne_items'),
'p.produit_id = l.produit_id',
array('ligne_items_par_produit' => 'COUNT(*)'))
->group('p.produit_id')
->order(array('ligne_items_par_produit DESC',
'produit_id'));

4.3.10. Ajouter une clause LIMIT

Certaines marques de SGBDR étendent la syntaxe SQL avec une clause LIMIT. Cette clause
réduit le nombre de lignes d'un résultat à un nombre maximum que vous spécifiez. Vous pouvez
de plus indiquer un nombre de lignes à éviter avant de commencer à produire le résultat. Cette
fonctionnalité facilite l'extraction d'un sous-ensemble d'un résultat, par exemple quand vous
affichez des résultats avec un défilement de pages.

Dans Zend_Db_Select, vous pouvez utiliser la méthode limit() pour spécifier le nombre de
lignes ainsi que le nombre de lignes à omettre. Le premier argument de cette méthode est le
nombre de lignes désirées. Le second argument est le nombre de lignes à omettre.

463
Zend_Db

Exemple 203. Exemple d'utilisation de la méthode limit()

// Construire cette requête :


// SELECT p."produit_id", p."produit_nom"
// FROM "produits" AS p
// LIMIT 10, 20

$select = $db->select()
->from(array('p' => 'produits'),
array('produit_id', 'produit_nom'))
->limit(10, 20);

La syntaxe LIMIT n'est pas supporté par toutes les marques de SGBDR.
Quelques SGBDR nécessite une syntaxe différente pour supporter une
fonctionnalité similaire. Chaque classe Zend_Db_Adapter_Abstract inclue
une méthode pour produire le code SQL approprié à ce SGBDR.

Utilisez de manière alternative la méthode limitPage() pour spécifier le nombre de lignes et


le décalage. Cette méthode vous permet de limiter le jeu de résultats à une série d'un nombre
fixé de résultats issus du jeu total de résultats de la requête. En d'autres termes, vous spécifiez
la taille de la "page" de résultats, et le nombre ordinal de la page unique de résultats que vous
souhaitez voir retourner par la requête. Le numéro de la page est le premier argument de la
méthode limitPage(), et la taille de la page est le second argument. Les deux arguments
sont obligatoires ; ils n'ont pas de valeurs par défaut.

Exemple 204. Exemple d'utilisation de la méthode limitPage()

// Construire cette requête :


// SELECT p."product_id", p."product_name"
// FROM "products" AS p
// LIMIT 10, 20

$select = $db->select()
->from(array('p' => 'products'),
array('product_id', 'product_name'))
->limitPage(2, 10);

4.3.11. Ajouter le modificateur de requête DISTINCT


La méthode distinct() vous permet d'ajouter le mot-clé DISTINCT à votre requête SQL.

Exemple 205. Exemple d'utilisation de la méthode distinct()

// Construire cette requête :


// SELECT DISTINCT p."produit_nom"
// FROM "produits" AS p

$select = $db->select()
->distinct()
->from(array('p' => 'produits'), 'produit_nom');

4.3.12. Ajouter le modificateur de requête FOR UPDATE


La méthode forUpdate() vous permet d'ajouter le modificateur FOR UPDATE à votre requête
SQL.

464
Zend_Db

Exemple 206. Exemple d'utilisation de la méthode forUpdate()

// Construire cette requête :


// SELECT FOR UPDATE p.*
// FROM "produits" AS p

$select = $db->select()
->forUpdate()
->from(array('p' => 'produits'));

4.3.13. Construire une requête UNION

Vous pouvez construire des requêtes de type union avec Zend_Db_Select en fournissant
un tableau de Zend_Db_Select ou de chaînes de requêtes SQL à la méthode union().
En second paramètre, vous pouvez fournir les constantes Zend_Db_Select::SQL_UNION
ou Zend_Db_Select::SQL_UNION_ALL pour spécifier le type d'union que vous souhaitez
réaliser.

Exemple 207. Exemple avec la méthode union()

$sql1 = $db->select();
$sql2 = "SELECT ...";

$select = $db->select()
->union(array($sql1, $sql2))
->order("id");

4.4. Exécuter des requêtes Select


Cette section décrit comment exécuter une requête représentée par un objet Zend_Db_Select.

4.4.1. Exécuter des requêtes Select à partir de l'adaptateur Db

Vous pouvez exécuter la requête représentée par l'objet Zend_Db_Select en le passant


comme premier argument de la méthode query() d'un objet Zend_Db_Adapter_Abstract.
Utilisez les objets Zend_Db_Select plutôt qu'une simple chaîne de requête.

La méthode query() retourne un objet de type Zend_Db_Statement ou PDOStatement,


dépendant du type d'adaptateur.

Exemple 208. Exemple d'utilisation de la méthode query() de l'adaptateur Db

$select = $db->select()
->from('produits');

$stmt = $db->query($select);
$result = $stmt->fetchAll();

4.4.2. Exécuter des requêtes Select à partir de objet Select

Comme alternative à l'emploi de la méthode query()de l'objet adaptateur, vous pouvez utiliser
la méthode query() de l'objet Zend_Db_Select. Les deux méthodes retourne un objet de
type Zend_Db_Statement ou PDOStatement, dépendant du type d'adaptateur.

465
Zend_Db

Exemple 209. Exemple d'utilisation de la méthode query() de l'objet Select

$select = $db->select()
->from('produits');

$stmt = $select->query();
$result = $stmt->fetchAll();

4.4.3. Convertir un objet Select en une chaîne SQL


Si vous devez accéder à la chaîne représentant la requête SQL correspondant à un objet
Zend_Db_Select, utilisez la méthode __toString().

Exemple 210. Exemple d'utilisation de la méthode __toString()

$select = $db->select()
->from('produits');

$sql = $select->__toString();
echo "$sql\n";

// L'affichage est la chaîne :


// SELECT * FROM "produits"

4.5. Autres méthodes


Cette section décrit les autres méthodes de la classe Zend_Db_Select qui ne sont pas
couvertes ci-dessus : getPart() et reset().

4.5.1. Récupérer des parties de l'objet Select


La méthode getPart() retourne une représentation d'une partie de votre requête SQL. Par
exemple, vous pouvez utiliser cette méthode pour retourner un tableau d'expressions pour la
clause WHERE, ou un tableau de colonnes (ou d'expressions de colonnes) qui sont dans l'élément
SELECT, ou les valeurs de nombre et de décalage pour la clause LIMIT.

La valeur retournée n'est pas une chaîne de caractère contenant un fragment de syntaxe SQL.
La valeur retournée est une représentation interne, qui est typiquement une structure de type
tableau contenant des valeurs et des expressions. Chaque partie de la requête a une structure
différente.

L'argument unique de la méthode getPart() est une chaîne qui identifie quelle partie de la
requête Select doit être retournée. Par exemple, la chaîne "from" identifie la partie de l'objet
Select qui stocke l'information concernant les tables dans la clause FROM, incluant les tables
jointes.

La classe Zend_Db_Select définit des constantes que vous pouvez utiliser pour les parties de
la requête SQL. Vous pouvez utiliser ces constantes ou des chaînes de caractères littérales.

Tableau 52. Constantes utilisées par getPart() et reset()

Constante Chaîne correspondante


Zend_Db_Select::DISTINCT 'distinct'
Zend_Db_Select::FOR_UPDATE 'forupdate'

466
Zend_Db

Constante Chaîne correspondante


Zend_Db_Select::COLUMNS 'columns'
Zend_Db_Select::FROM 'from'
Zend_Db_Select::WHERE 'where'
Zend_Db_Select::GROUP 'group'
Zend_Db_Select::HAVING 'having'
Zend_Db_Select::ORDER 'order'
Zend_Db_Select::LIMIT_COUNT 'limitcount'
Zend_Db_Select::LIMIT_OFFSET 'limitoffset'

Exemple 211. Exemple d'utilisation de la méthode getPart()

$select = $db->select()
->from('produits')
->order('produit_id');

// Vous pouvez spécifier une chaîne littérale


$orderData = $select->getPart( 'order' );

// Vous pouvez utiliser une constante


$orderData = $select->getPart( Zend_Db_Select::ORDER );

// La valeur retournée peut être une structure tableau, pas une chaîne.
// Chaque partie a une structure différente
print_r( $orderData );

4.5.2. Effacer des parties de l'objet Select

La méthode reset() vous permet de vider une partie spécifique de la requête SQL, ou toutes
les parties si vous omettez l'argument.

L'argument unique est facultatif. Vous pouvez spécifier la partie de la requête à effacer, en
utilisant les mêmes chaînes que vous utilisez en tant qu'argument de la méthode getPart().
La partie de la requête que vous spécifiez est initialisée à l'état par défaut.

Si vous omettez le paramètre, reset() initialise toutes les parties de la requête à leurs valeurs
par défaut. Ceci rend l'objet Zend_Db_Select équivalent à un nouvel objet, comme si vous l'aviez
tout juste instancié.

467
Zend_Db

Exemple 212. Exemple d'utilisation de la méthode reset()

// Construire cette requête :


// SELECT p.*
// FROM "produits" AS p
// ORDER BY "produit_nom"

$select = $db->select()
->from(array('p' => 'produits')
->order('produit_nom');

// Changer la condition d'ordre avec une colonne différente :


// SELECT p.*
// FROM "produits" AS p
// ORDER BY "produit_id"

// Vider la partie afin de la redéfinir


$select->reset( Zend_Db_Select::ORDER );

// Et spécifier une colonne différente


$select->order('produit_id');

// Vider toutes les parties de la requête


$select->reset();

5. Zend_Db_Table
5.1. Introduction
La classe Zend_Db_Table est une interface orientée objet vers les tables d'une base de
données. Elle fournit des méthodes pour la gestion de la plupart des opérations concernant
une table. Bien entendu, vous pouvez étendre la classe de base pour ajouter une logique
personnalisée.

La solution que représente Zend_Db_Table est basée sur le motif de conception Table Data
Gateway. Cette solution inclut aussi une classe implémentant le motif Row Data Gateway.

5.2. Définir une classe de Table


Pour chaque table de la base de données envers laquelle vous souhaitez un accès, définissez
une classe étendant Zend_Db_Table_Abstract.

5.2.1. Définir le nom de la table, et de la base de données


Déclarez le nom de la table pour laquelle la classe va agir, en utilisant la propriété protégée
$_name. C'est une chaîne, elle doit contenir le nom de la table tel qu'il apparaît dans la base
de données.

Exemple 213. Déclarer une classe de Table avec un nom de table spécifique

class Bugs extends Zend_Db_Table_Abstract


{
protected $_name = 'bugs';
}

Si vous ne spécifiez pas le nom de la table, le nom de la classe sera alors utilisé comme nom
de table par défaut.

468
Zend_Db

Exemple 214. Déclarer une classe de Table sans nom de table spécifique

class bugs extends Zend_Db_Table_Abstract


{
// le nom de la table est ici supposé être le nom de la classe
}

Vous pouvez aussi déclarer le nom de la base de données contenant la table, toujours au moyen
d'une propriété protégée de la classe : $_schema, ou avec le nom de la base précédant le nom
de la table dans la propriété $_name. Si vous choisissez de définir le nom de la base de données
dans la propriété $_name, alors ce choix sera prioritaire sur celui utilisant $_schema.

Exemple 215. Déclarer une classe de Table avec un nom de base de données

// Première alternative :
class Bugs extends Zend_Db_Table_Abstract
{
protected $_schema = 'bug_db';
protected $_name = 'bugs';
}

// Seconde alternative :
class Bugs extends Zend_Db_Table_Abstract
{
protected $_name = 'bug_db.bugs';
}

// Si le nom de la base est spécifiée dans $_name ET $_schema,


// alors c'est celui spécifié dans $_name qui prime :

class Bugs extends Zend_Db_Table_Abstract


{
protected $_name = 'bug_db.bugs';
protected $_schema = 'ignored';
}

Les noms de la base de données et de la table peuvent aussi être définis via le constructeur
de la classe de Table. Ils écrasent alors ceux éventuellement définis dans les propriétés de la
classe (avec $_name et $_schema).

469
Zend_Db

Exemple 216. Déclarer les noms de table et base de donnée à l'instanciation

class Bugs extends Zend_Db_Table_Abstract


{
}

// Première alternative :

$tableBugs = new Bugs(array('name' => 'bugs', 'schema' => 'bug_db'));

// Seconde alternative :

$tableBugs = new Bugs(array('name' => 'bug_db.bugs'));

// Si le nom de la base est spécifié dans name ET schema, alors c'est


// celui spécifié dans name qui prime :

$tableBugs = new Bugs(array('name' => 'bug_db.bugs',


'schema' => 'ignored'));

Si vous n'indiquez pas de base de données, c'est celle utilisée par l'adaptateur qui sera utilisée.

5.2.2. Définir la clé primaire d'une table

Toute table doit posséder une clé primaire. Zend_Db_Table ne fonctionne pas avec les tables
sans clé primaire. Vous pouvez les déclarer la(les) colonne servant de clé primaire grâce à la
propriété protégée de la classe $_primary. Celle-ci peut être soit une chaîne, dans le cas d'une
clé sur une colonne, ou un tableau de chaînes pour une clé sur plusieurs colonnes (clé primaire
composée).

Exemple 217. Exemple de spécification de la clé primaire

class Bugs extends Zend_Db_Table_Abstract


{
protected $_name = 'bugs';
protected $_primary = 'bug_id';
}

Si vous ne spécifiez pas explicitement de clé primaire, alors Zend_Db_Table_Abstract va


essayer de la trouver lui-même en utilisant les informations renvoyées par describeTable().

Toute classe de table doit, par un moyen ou un autre, connaître la clé primaire de
la table ciblée. Si la clé primaire ne peut être trouvée ( spécifiée dans la classe,
ou découverte par describeTable()), alors la table ne va pas pouvoir être
utilisée avec Zend_Db_Table.

5.2.3. Redéfinir les méthodes de configuration de la classe de Table

Lorsque vous créez votre instance de classe Zend_Db_Table, le constructeur décompose


le processus via plusieurs méthodes permettant l'initialisation des métadonnées de la table.
Chacune de ces étapes est matérialisée par une méthode de la classe, surchargeable. N'oubliez
cependant pas d'appeler la méthode parente respective à la fin de votre traitement.

470
Zend_Db

Exemple 218. Exemple de redéfinition de la méthode _setupTableName()

class Bugs extends Zend_Db_Table_Abstract


{
protected function _setupTableName()
{
$this->_name = 'bugs';
parent::_setupTableName();
}
}

Les méthodes de configuration que vous pouvez redéfinir sont :

• _setupDatabaseAdapter() vérifie si un adaptateur a été passé à la classe, éventuellement


en récupère un depuis le registre. En redéfinissant cette méthode, vous pouvez ajouter une
source de recherche pour l'adaptateur.

• _setupTableName() donne le nom de la table par défaut comme étant le nom de la


classe. En redéfinissant cette méthode, vous pouvez spécifier le nom de la table avant son
intervention.

• _setupMetadata() définit le nom de la base de données si le nom de la table est de la


forme "base.table"; appelle describeTable() pour récupérer les méta-données; remplir le
tableau $_cols avec les noms des colonnes reçus via describeTable(). La redéfinition
de cette méthode permet de spécifier soi-même les noms des colonnes de la table.

• _setupPrimaryKey() donne le nom de la clé primaire par défaut en cherchant dans


describeTable(); vérifie que la clé primaire fait bien partie du tableau $_cols. En
redéfinissant cette méthode, vous pouvez spécifier une clé primaire manuellement.

5.2.4. Initialisation de la Table


Si lors de la construction de l'objet représentant votre Table, vous avez besoin d'implémenter
une logique spécifique, vous devriez utiliser la méthode init(), qui est appelée juste après le
constructeur, donc une fois la table correctement créée.

Exemple 219. Exemple d'utilisation de la méthode init()

class Bugs extends Zend_Db_Table_Abstract


{
protected $_observer;

public function init()


{
$this->_observer = new MyObserverClass();
}
}

5.3. Créer une instance de la classe de Table


Avant d'utiliser votre classe de Table, il faut en créer une instance, via son constructeur. Celui-
ci accepte un tableau d'options. La plus importante d'entre elles est l'adaptateur de base de
données, qui représente la connexion au SGBD. Il y a trois façon de le spécifier :

5.3.1. Spécifier l'adaptateur de base de données


La première manière de spécifier l'objet d'adaptateur à la classe de Table, est de le passer dans
le tableau d'options, à l'index "db".

471
Zend_Db

Exemple 220. Exemple de construction d'un objet Table avec l'objet adaptateur

$db = Zend_Db::factory('PDO_MYSQL', $options);

$table = new Bugs(array('db' => $db));

5.3.2. Spécifier un adaptateur par défaut


La deuxième manière de donner un objet adaptateur à la classe de Table est de le déclarer
comme étant l'objet adaptateur par défaut pour toutes les classes de Table. Vous pouvez faire
ceci en utilisant la méthode statique Zend_Db_Table_Abstract::setDefaultAdapter().
Son argument est un objet de type Zend_Db_Adapter_Abstract.

Exemple 221. Exemple de construction d'un objet Table en utilisant l'adaptateur


par défaut

$db = Zend_Db::factory('PDO_MYSQL', $options);


Zend_Db_Table_Abstract::setDefaultAdapter($db);

// Plus tard...

$table = new Bugs();

Il peut être intéressant de créer son objet adaptateur de base de données en un lieu approprié,
comme le fichier d'amorçage ("bootstrap"), et ensuite de le spécifier comme adaptateur par
défaut pour toutes les tables, à travers toute l'application. Attention toutefois, ce procédé fixe un et
un seul adaptateur, pour toutes les classes de table (héritant de Zend_Db_Table_Abstract).

5.3.3. Stocker l'objet adaptateur dans le registre


La troisième manière de passer l'objet adaptateur de base de données à votre classe de Table,
est de passer une chaîne de caractères dans la clé "db" du tableau de configuration accepté
par le constructeur. Cette chaîne représente alors l'index auquel est stocké l'adaptateur, dans
le registre statique.

Exemple 222. Exemple de construction de l'objet Table avec le registre

$db = Zend_Db::factory('PDO_MYSQL', $options);


Zend_Registry::set('my_db', $db);

// Plus tard...

$table = new Bugs(array('db' => 'my_db'));

Cette option est très semblable à celle qui consiste à définir un adaptateur par défaut à toutes
les classes. Le registre est en revanche plus flexible, car vous pouvez y stocker plusieurs
adaptateurs, correspondants à plusieurs SGBD différents. Changer de SGBD pour ses classes
de Table est alors aussi simple que de changer de valeur de registre.

5.4. Insérer des enregistrement dans une table


Vous pouvez utiliser votre objet de Table pour insérer des données dans la table sur laquelle
l'objet se base. Utilisez sa méthode insert() qui accepte un seul paramètre : c'est un tableau
dont les clés sont les noms des colonnes de la table, et les valeurs les valeurs souhaitées pour
insertions.

472
Zend_Db

Exemple 223. Exemple d'insertion de données dans la table

$table = new Bugs();

$data = array(
'created_on' => '2007-03-22',
'bug_description' => 'Something wrong',
'bug_status' => 'NEW'
);

$table->insert($data);

Par défaut les paramètres sont traités comme des valeurs littérales. Si vous souhaitez utiliser
une expression SQL à la place, manipulez un objet Zend_Db_Expr plutôt.

Exemple 224. Exemple d'insertion d'expressions dans une table

$table = new Bugs();

$data = array(
'created_on' => new Zend_Db_Expr('CURDATE()'),
'bug_description' => 'Something wrong',
'bug_status' => 'NEW'
);

Dans les exemples ci-dessus, il est supposé que la table possède une clé primaire auto-
incrémentée. C'est le comportement par défaut que gère Zend_Db_Table_Abstract, mais il
y a d'autres comportements valides, qui sont détaillés ci-dessous.

5.4.1. Utiliser une table avec une clé primaire auto-incrémentée


Une clé primaire auto-incrémentée génère une valeur entière unique si vous omettez la colonne
de la clé primaire dans une requête SQL de type INSERT.

Dans Zend_Db_Table_Abstract, si vous définissez la variable protégée $_sequence à un


booléen TRUE (défaut), alors la classe va supposer que la table qu'elle représente possède une
clé primaire auto-incrémentée.

Exemple 225. Exemple de déclaration d'une clé primaire auto-incrémentée

class Bugs extends Zend_Db_Table_Abstract


{
protected $_name = 'bugs';

// Ce comportement est celui par défaut, il est noté ici


// uniquement pour l'exemple, mais non necéssaire
protected $_sequence = true;
}

MySQL, MSSQL, et SQLite sont des exemples de SGBD supportant les clé primaires auto-
incrémentées.

PostgreSQL a une propriété SERIAL qui définit une séquence automatiquement, basée sur le
nom de la table et d'une colonne, et utilise cette séquence pour générer des valeurs de clés
pour les nouveaux enregistrements. IBM DB2 a une propriété IDENTITY qui fonctionne de
la même manière. Si vous utilisez ces propriétés d'automatisme, considérez votre classe de

473
Zend_Db

Table (Zend_Db_Table) comme si elle avait une clé primaire auto-incrémentée. Déclarez ainsi
$_sequence à TRUE.

5.4.2. Utiliser une Table avec une séquence


Une séquence est un objet de base de données qui génère des valeurs uniques pouvant être
utilisées comme clés primaires dans une ou plusieurs tables de la base de données.

Si vous définissez $_sequence avec une chaîne de caractères, Zend_Db_Table_Abstract


va alors supposer que cette chaîne représente le nom de l'objet de séquence. Elle sera donc
utilisée pour générer une valeur lors de requêtes INSERT le nécessitant.

Exemple 226. Exemple de déclaration d'une séquence dans une classe de Table

class Bugs extends Zend_Db_Table_Abstract


{
protected $_name = 'bugs';

protected $_sequence = 'bug_sequence';


}

Oracle, PostgreSQL, et IBM DB2 sont des SGBDs qui supportent les séquences.

PostgreSQL et IBM DB2 ont aussi des mécanismes définissant implicitement la séquence et les
colonnes associées. Si vous utilisez un de ces procédés, considérez votre classe de table comme
ayant une clé primaire auto-incrémentée. N'utilisez la chaîne de la séquence dans $_sequence
que si vous voulez explicitement utiliser cette séquence pour générer la valeur suivante de clé.

5.4.3. Utiliser une classe de Table avec une clé naturelle


Certaines tables ont des clé naturelles, c'est à dire que vous devez fournir vous même,
manuellement, la valeur de la clé concernée. Aucun mécanisme automatique (auto-
incrémentation ou séquence) ne le fait pour vous.

Si vous utilisez $_sequence avec la valeur booléenne FALSE, alors


Zend_Db_Table_Abstract se comportera comme si une clé naturelle est utilisée. Ainsi, lors
de l'appel de la méthode insert(), vous devrez spécifier la valeur de la clé primaire vous
même, autrement une Zend_Db_Table_Exception sera levée.

Exemple 227. Exemple de déclaration d'une clé naturelle

class BugStatus extends Zend_Db_Table_Abstract


{
protected $_name = 'bug_status';

protected $_sequence = false;


}

Tous les SGBDs gère ce cas. Les tables d'intersection dans les relations de
type "plusieurs à plusieurs" sont de bons exemples de clés naturelles, souvent
composées d'autres clés étrangères.

5.5. Mettre à jour des enregistrements dans une table


Vous pouvez mettre à jour des enregistrements de votre table en utilisant la méthode update
de votre classe de Table. Elle accepte deux paramètres. Le premier est un tableau associatifs

474
Zend_Db

des colonnes concernées, et de leurs valeurs respectives. Le deuxième est une expression SQL
qui sera utiliser comme clause WHERE dans la requête UPDATE.

Exemple 228. Exemple de mise à jour d'enregistrements dans une table

$table = new Bugs();

$data = array(
'updated_on' => '2007-03-23',
'bug_status' => 'FIXED'
);

$where = $table->getAdapter()->quoteInto('bug_id = ?', 1234);

$table->update($data, $where);

La méthode de la classe de Table update() est proxiées vers la méthode update() de


l'adaptateur. Le deuxième paramètre peut donc être un tableau d'arguments pour la clause
WHERE. Chaque élément du tableau sera joint au suivant avec une opération AND.

Les valeurs et les identifiants SQL ne sont pas échappés automatiquement.


Si vous voulez échapper des valeurs, vous devrez utiliser quote(),
quoteInto(), et quoteIdentifier() de l'adaptateur.

5.6. Supprimer des enregistrements d'une Table


Pour effacer des enregistrements de votre table en utilisant sa classe de Table, utilisez sa
méthode delete(). Son seul paramètre est une chaîne ou un tableau définissant la clause
WHERE à utiliser lors de la requête DELETE.

Exemple 229. Exemple de suppression d'enregistrements

$table = new Bugs();

$where = $table->getAdapter()->quoteInto('bug_id = ?', 1235);

$table->delete($where);

Cette méthode est proxiée vers delete() de l'adaptateur. Si le paramètre est un tableau,
chacun des éléments du tableau sera joint au suivant avec l'opération AND pour former la clause
WHERE.

Les valeurs et les identifiants SQL ne sont pas échappés automatiquement.


Si vous voulez échapper des valeurs, vous devrez utiliser quote(),
quoteInto(), et quoteIdentifier() de l'adaptateur.

5.7. Récupérer des enregistrements par clé primaire


Vous pouvez interroger votre table afin de récupérer des enregistrements en spécifiant une ou
plusieurs valeurs de clé primaire. La méthode find() permet ceci, elle prend comme premier
paramètre une valeur ou un tableau de valeurs de clé primaire.

475
Zend_Db

Exemple 230. Exemple de récupération d'enregistrements par clé primaire

$table = new Bugs();

// Récupère un enregistrement, mais


// retourne un Rowset
$rows = $table->find(1234);

// Récupère plusieurs enregistrement


// retourne un Rowset
$rows = $table->find(array(1234, 5678));

Si une seule clé est passée en paramètre, la méthode retournera au plus un résultat (car
par définition, une clé primaire assure l'unicité d'un enregistrement). Si vous passez plusieurs
valeurs de clés, alors la méthode pourra retourner plusieurs enregistrements. Cette méthode
pourra aussi retourner zéro enregistrement. Quoiqu'il en soit, l'objet de retour est bien un
Zend_Db_Table_Rowset_Abstract.

Si votre clé primaire est une clé composée de plusieurs colonnes, passez alors les autres valeurs
de colonne comme paramètres à la méthode find(). Il doit y avoir autant de paramètres passés
à la méthode, que de colonnes composant la clé.

Ainsi, pour trouver plusieurs enregistrements en passant plusieurs valeurs de clés primaires
composées, passez autant de tableaux composés, que de colonnes représentant les clés. Les
tableaux doivent donc, comporter le même nombre de valeurs. Celles-ci vont ainsi fonctionner
par tuples : tous les premiers éléments des tableaux seront évalués pour la première recherche,
et chacun représentera une colonne composant la clé primaire. Puis ainsi de suite, jusqu'à la
fin des tableaux.

Exemple 231. Exemple de recherche avec une clé primaire composée

L'exemple suivant appelle find() pour récupérer deux enregistrements en se basant sur
une clé à deux colonnes. Le premier enregistrement aura une clé primaire (1234, 'ABC'), et
le second une valeur de clé primaire (5678, 'DEF').

class BugsProducts extends Zend_Db_Table_Abstract


{
protected $_name = 'bugs_products';
protected $_primary = array('bug_id', 'product_id');
}

$table = new BugsProducts();

// Retourne un enregistrement unique, basé sur une clé


// primaire à deux colonnes
$rows = $table->find(1234, 'ABC');

// Retourne deux enregistrements, basés sur une clé


// primaire à deux colonnes
$rows = $table->find(array(1234, 5678), array('ABC', 'DEF'));

476
Zend_Db

5.8. Requêter pour plusieurs enregistrements


5.8.1. API de l'objet Select

L'API pour les opérations de récupération d'enregistrements a été améliorée


afin d'autoriser un objet Zend_Db_Table_Select à modifier la requête. Les
anciens comportements de fetchRow() et fetchAll() sont désormais
dépréciés, mais toujours fonctionnels à ce jour.

Les requêtes suivantes sont sémantiquement identiques et fonctionnent. Il est


conseillé cependant d'utiliser l'implémentation avec l'objet select.

// Récupérer un rowset
$rows = $table->fetchAll('bug_status = "NEW"', 'bug_id ASC', 10, 0);
$rows = $table->fetchAll($table->select()->where('bug_status = ?', 'NEW')
->order('bug_id ASC')
->limit(10, 0));
// ou avec liaison :
$rows = $table->fetchAll(
$table->select()
->where('bug_status = :status')
->bind(array(':status'=>'NEW')
->order('bug_id ASC')
->limit(10, 0)
);

// Récupérer un row
$row = $table->fetchRow('bug_status = "NEW"', 'bug_id ASC');
$row = $table->fetchRow($table->select()->where('bug_status = ?', 'NEW')
->order('bug_id ASC'));
// ou avec liaison :
$row = $table->fetchRow(
$table->select()
->where('bug_status = :status')
->bind(array(':status'=>'NEW')
->order('bug_id ASC')
);

L'objet Zend_Db_Table_Select est une extension de Zend_Db_Select mais qui applique


des restrictions particulières à la requête. Les restrictions sont :

• Vous pouvez utiliser l'objet pour ne sélectionner que certaines colonnes de l'enregistrement à
retourner. Ceci est pratique dans le cas où vous n'avez pas besoin spécifiquement de toutes
les colonnes d'une table.

• Vous pouvez spécifier des colonnes avec des évaluations envers des expressions SQL.
Cependant, l'enregistrement résultant sera alors en mode lecture seule (readOnly) et ne pourra
pas être propagé en base de données (save()). Un appel à save() lèvera une exception.

• Vous pouvez utiliser des jointures JOIN vers d'autres tables, mais uniquement pour des
critères de jointure, et non sélectionner des colonnes jointes.

• Vous ne pouvez pas spécifier de colonnes JOINtes comme faisant partie du résultat de la
requête. L'objet row/rowset serait alors corrompu, et contiendrait des données d'une table
étrangère à sa table originale. Une erreur sera renvoyée dans un tel cas.

477
Zend_Db

Exemple 232. Utilisation simple

$table = new Bugs();

$select = $table->select();
$select->where('bug_status = ?', 'NEW');

$rows = $table->fetchAll($select);

L'objet Select utilise une interface fluide (fluent interface), permettant le chaînage des
méthodes.

Exemple 233. Exemple d'interface fluide

$table = new Bugs();

$rows = $table->fetchAll($table->select()
->where('bug_status = ?', 'NEW'));

5.8.2. Récupérer un jeu d'enregistrements :

Vous pouvez demander une requête qui retourne plusieurs enregistrements. La méthode
fetchAll() de votre classe de Table permet ceci. Elle retourne un objet de type
Zend_Db_Table_Rowset_Abstract, même si aucun enregistrement ne correspond à la
requête.

Exemple 234. Exemple de récupération d'enregistrements

$table = new Bugs();

$select = $table->select()->where('bug_status = ?', 'NEW');

$rows = $table->fetchAll($select);

Vous pouvez aussi définir les clauses SQL ORDER BY ou encore LIMIT (ou autre équivalent
comme OFFSET).

Exemple 235. Exemple de récupération d'enregistrements avec des clauses SQL

$table = new Bugs();

$order = 'bug_id';

// Retourne les enregistrements du 21ème au 30ème


$count = 10;
$offset = 20;

$select = $table->select()->where('bug_status = ?', 'NEW')


->order($order)
->limit($count, $offset);

$rows = $table->fetchAll($select);

Tous les arguments de requêtes sont optionnels. Vous pouvez écrire une requête sans clause
WHERE ni LIMIT ou encore ORDER.

478
Zend_Db

5.8.3. Utilisation avancée


Pour une utilisation plus avancée, vous pourriez vouloir spécifier une à une les colonnes
que les enregistrements trouvés doivent comporter. Ceci se fait au moyen de la clause
FROM de l'objet select. Le premier paramètre dans la clause FROM est le même que celui
d'un objet Zend_Db_Select, cependant l'objet Zend_Db_Table_Select admet une instance de
Zend_Db_Table_Abstract pour définir le nom de la table.

Exemple 236. Récupérer des colonnes spécifiques sur les enregistrements

$table = new Bugs();

$select = $table->select();
$select->from($table, array('bug_id', 'bug_description'))
->where('bug_status = ?', 'NEW');

$rows = $table->fetchAll($select);

Le jeu de résultats retourné est tout de même valide. Il ne possède en revanche


que certaines colonnes de la table. La méthode save() est appelable, mais elle
ne mettre à jour que ces colonnes.

Il est aussi possible de spécifier des expressions dans une clause FROM, et donc récupérer un
objet row/rowset en lecture seule. Dans l'exemple ci-après, nous retournons un enregistrement
de la table "bugs" qui représente un agrégat du nombre de nouveaux bugs reportés. Regardez
la clause GROUP. L'alias SQL "count" sera accessible dans le row/rowset résultant, comme si
il faisait parti de la table en tant que colonne.

Exemple 237. Récupérer des enregistrements avec des requêtes incluant des
expressions

$table = new Bugs();

$select = $table->select();
$select->from($table,
array('COUNT(reported_by) as `count`', 'reported_by'))
->where('bug_status = ?', 'NEW')
->group('reported_by');

$rows = $table->fetchAll($select);

Vous pouvez aussi utiliser une table de jointure comme partie de votre requête. Dans l'exemple
ci-dessous, nous utilisons la table "accounts" comme partie de la recherche, pour tous les bugs
reportés par "Bob".

Exemple 238. Utiliser une table intermédiaire par jointure avec fetchAll()

$table = new Bugs();

// Récupération avec la partie from déjà spécifié, important lors des jointures
$select = $table->select(Zend_Db_Table::SELECT_WITH_FROM_PART);
$select->setIntegrityCheck(false)
->where('bug_status = ?', 'NEW')
->join('accounts', 'accounts.account_name = bugs.reported_by')
->where('accounts.account_name = ?', 'Bob');

$rows = $table->fetchAll($select);

479
Zend_Db

L'objet Zend_Db_Table_Select est destiné à sélectionner des données sur une table précise.
Des jointures peuvent être faites, mais il n'est pas possible de sélectionner des colonnes ne
faisant pas partie de la table sous-jacente. Cependant, ceci aurait pu être utile dans certains
cas, et l'objet Zend_Db_Table_Select possède une clause spéciale déverrouillant cette
limitation. Passez la valeur FALSE à sa méthode setIntegrityCheck. Il est alors possible
de sélectionner des colonnes hors table. Attention toutefois, l'objet row/rowset résultant sera
verrouillé. Impossible d'y appeler save(), delete() ou même d'affecter une valeur à certains
de ses champs. Une exception sera systématiquement levée.

Exemple 239. Déverrouiller un objet Zend_Db_Table_Select pour récupérer des


colonnes JOINtes

$table = new Bugs();

$select = $table->select(Zend_Db_Table::SELECT_WITH_FROM_PART)
->setIntegrityCheck(false);
$select->where('bug_status = ?', 'NEW')
->join('accounts',
'accounts.account_name = bugs.reported_by',
'account_name')
->where('accounts.account_name = ?', 'Bob');

$rows = $table->fetchAll($select);

5.9. Récupérer un seul enregistrement


Vous pouvez demander à ne récupérer qu'un seul résultat, en requêtant de manière similaire
à la méthode fetchAll().

Exemple 240. Exemple de récupération d'un seul enregistrement

$table = new Bugs();

$select = $table->select()->where('bug_status = ?', 'NEW')


->order('bug_id');

$row = $table->fetchRow($select);

Cette méthode retourne un objet de type Zend_Db_Table_Row_Abstract. Si la requête ne trouve


aucun enregistrement, alors fetchRow() retournera NULL.

5.10. Récupérer les méta données d'une Table


La classe Zend_Db_Table_Abstract propose des informations concernant ses méta données.La
méthode info() retourne un tableau d'informations sur les colonnes, la clé primaire, etc. de
la table.

Exemple 241. Exemple de récupération du nom de la table

$table = new Bugs();

$info = $table->info();

echo "The table name is " . $info['name'] . "\n";

Les clés du tableau retourné par info() sont les suivantes :

480
Zend_Db

• name => nom de la table.

• cols => un tableau contenant les colonnes de la table.

• primary => un tableau contenant la(les) colonnes utilisée(s) pour définir la clé primaire de la
table.

• metadata => un tableau associatif, associant les noms des colonnes de la tables, à
leurs informations intrinsèques. Les données sont les mêmes que celles retournée par
describeTable().

• rowClass => le nom de la classe concrète servant les objets représentants les enregistrements
de la table. Par défaut : Zend_Db_Table_Row.

• rowsetClass => le nom de la classe concrète servant de conteneur d'objets représentants les
enregistrements de la table. Par défaut : Zend_Db_Table_Rowset.

• referenceMap => un tableau associatif. Il représente les références de cette table vers ses
parents éventuelles. Voyez Section 8.2, « Définir ses relations ».

• dependentTables => un tableau de noms de classes de tables qui référencent cette table.
Voyez Section 8.2, « Définir ses relations ».

• schema => Le nom de la base de données comportant cette table.

5.11. Cacher les méta données de la table


Par défaut, Zend_Db_Table_Abstract demande à la base de données les méta données de
table, à chaque instanciation d'objet de table. L'objet de table analyse les métadonnées de la
table dans le SGDB en utilisant la méthode describeTable() de l'adaptateur. Les opérations
nécessitant cette introspection incluent :

• insert()

• find()

• info()

Cependant, il peut être dégradant pour les performances du SGBD de lui demander ces
informations à chaque instanciation de chaque objet de chaque table. Ainsi, un système de cache
pour les méta données a été mis en place.

La mise en cache des méta données des tables peut être contrôlée de deux manières :

• Un appel à la méthode statique Zend_Db_Table_Abstract::setDefaultMetadataCache() - Ceci


permet d'enregistrer une fois pour toutes l'objet de cache que toutes les tables devront utiliser.

• L'appel au constructeur Zend_Db_Table_Abstract::__construct() - Il va permettre de spécifier


l'objet de cache pour une table en particulier.

Dans tous les cas, vous devrez passer soit NULL (et ainsi désactiver le cache des méta
données des tables), soit une instance de Zend_Cache_Core. Il est possible d'utiliser à la fois
setDefaultMetadataCache et le constructeur afin d'avoir un objet de cache par défaut, puis
un spécifique pour certaines classes.

481
Zend_Db

Exemple 242. Utiliser un objet de cache de méta données pour toutes les classes

L'exemple qui suit illustre la manière de passer un objet de cache de méta données général,
pour toutes les classes de table :

// D'abord, configurons le cache


$frontendOptions = array(
'automatic_serialization' => true
);

$backendOptions = array(
'cache_dir' => 'cacheDir'
);

$cache = Zend_Cache::factory('Core',
'File',
$frontendOptions,
$backendOptions);

// Puis passons le comme objet de cache par défaut


Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);

// Testons avec une classe


class Bugs extends Zend_Db_Table_Abstract
{
// ...
}

// Chaque instance utilise l'objet par défaut


$bugs = new Bugs();

482
Zend_Db

Exemple 243. Utiliser un objet de cache de métadonnées pour une instance


précise

L'exemple qui suit illustre la manière de passer un objet de cache de méta données
spécifique, pour une instance précise :

// D'abord, configurons le cache


$frontendOptions = array(
'automatic_serialization' => true
);

$backendOptions = array(
'cache_dir' => 'cacheDir'
);

$cache = Zend_Cache::factory('Core',
'File',
$frontendOptions,
$backendOptions);

// Testons avec une classe


class Bugs extends Zend_Db_Table_Abstract
{
// ...
}

// Lors de son instanciation, il est possible


// de lui passer l'objet de cache
$bugs = new Bugs(array('metadataCache' => $cache));

Sérialisation automatique avec Cache Frontend

Étant donné que les informations retournées par describeTable()


le sont sous forme de tableau, assurez vous que le paramètre
automatic_serialization est à TRUE pour l'objet de la classe
Zend_Cache_Core.

Dans nos exemples, nous utilisons Zend_Cache_Backend_File, mais vous pouvez utiliser le
backend que vous souhaitez, voyez Zend_Cache pour plus d'informations.

5.11.1. Coder en dur les métadonnées de tables

Pour cacher les métadonnées une étape plus avant, vous pouvez aussi choisir de coder en dur
ces métadonnées. Dans ce cas particulier, cependant, tout changement au schéma de la table
requerra un changement dans votre code. Ainsi, il est seulement recommandé pour ceux qui
sont dans la phase d'optimisation pour un usage en production.

La structure des métadonnées est comme ceci :

protected $_metadata = array(


'<column_name>' => array(
'SCHEMA_NAME' => <string>,
'TABLE_NAME' => <string>,
'COLUMN_NAME' => <string>,
'COLUMN_POSITION' => <int>,
'DATA_TYPE' => <string>,

483
Zend_Db

'DEFAULT' => NULL|<value>,


'NULLABLE' => <bool>,
'LENGTH' => <string - length>,
'SCALE' => NULL|<value>,
'PRECISION' => NULL|<value>,
'UNSIGNED' => NULL|<bool>,
'PRIMARY' => <bool>,
'PRIMARY_POSITION' => <int>,
'IDENTITY' => <bool>,
),
// additional columns...
);

Une manière simple de récupérer les valeurs appropriées est d'activer le cache des
métadonnées et d'utiliser celles présentes dans votre cache.

Vous pouvez désactiver cette optimisation en mettant à FALSE le paramètre


metadataCacheInClass :

// Lors de l'instanciation :
$bugs = new Bugs(array('metadataCacheInClass' => false));

// Ou plus tard :
$bugs->setMetadataCacheInClass(false);

Ce paramètre est activé par défaut, ce qui assure que le tableau $_metadata n'est chargé
qu'une seule fois par instance

5.12. Personnaliser et étendre une classe de Table


5.12.1. Utiliser des objets Row ou Rowset personnalisés

Par défaut, les méthodes de la classe de Table retourne des jeux d'enregistrements
comme étant des instances de la classe Zend_Db_Table_Rowset, ces "Rowsets"
contiennent des enregistrements de la table, représentés par des objets instances de
Zend_Db_Table_Row. Vous pouvez spécifier vos propres classes pour row/rowset, mais elles
doivent étendre Zend_Db_Table_Rowset_Abstract ou Zend_Db_Table_Row_Abstract,
respectivement.

Vous pouvez spécifier vos classes row/rowset en utilisant le constructeur de la classe de Table,
via le tableau d'options, aux clés "rowClass" et "rowsetClass". Indiquez les noms des
classes sous forme de chaînes de caractères.

484
Zend_Db

Exemple 244. Exemple de spécification de ses propres classes Row et Rowset

class My_Row extends Zend_Db_Table_Row_Abstract


{
...
}

class My_Rowset extends Zend_Db_Table_Rowset_Abstract


{
...
}

$table = new Bugs(


array(
'rowClass' => 'My_Row',
'rowsetClass' => 'My_Rowset'
)
);

$where = $table->getAdapter()->quoteInto('bug_status = ?', 'NEW')

// Retourne un objet de type My_Rowset,


// contenant des objets de type My_Row.
$rows = $table->fetchAll($where);

Vous pouvez aussi utiliser les méthodes setRowClass() et setRowsetClass(). Ceci


s'applique alors de manière ponctuelle, et non plus globale pour toute la classe de Table en
tout point.

Exemple 245. Exemple de changement ponctuel des classes de Row et Rowset

$table = new Bugs();

$where = $table->getAdapter()->quoteInto('bug_status = ?', 'NEW')

// Retourne un objet de type Zend_Db_Table_Rowset


// contenant des objets de type Zend_Db_Table_Row.
$rowsStandard = $table->fetchAll($where);

$table->setRowClass('My_Row');
$table->setRowsetClass('My_Rowset');

// Retourne un objet de type My_Rowset,


// contenant des objets de type My_Row.
$rowsCustom = $table->fetchAll($where);

// L'objet $rowsStandard existe toujours et n'a pas changé d'état.

Pour des informations détaillées concernant les classes Row et Rowset, voyez Section 6,
« Zend_Db_Table_Row » et Section 7, « Zend_Db_Table_Rowset ».

5.12.2. Personnaliser les logiques Insert, Update, et Delete

Vous pouvez redéfinir les méthodes insert() et update() afin d'y ajouter votre propre
logique. Assurez vous d'appeler les méthodes parentes une fois votre code écrit.

485
Zend_Db

Exemple 246. Exemple d'implémentation d'une logique personnalisée gérant des


timestamps

class Bugs extends Zend_Db_Table_Abstract


{
protected $_name = 'bugs';

public function insert(array $data)


{
// Ajout d'un timestamp
if (empty($data['created_on'])) {
$data['created_on'] = time();
}
return parent::insert($data);
}

public function update(array $data, $where)


{
// Ajout d'un timestamp
if (empty($data['updated_on'])) {
$data['updated_on'] = time();
}
return parent::update($data, $where);
}
}

Il est aussi possible de redéfinir la méthode delete().

5.12.3. Définir des méthodes de recherches personnalisées dans


Zend_Db_Table
Bien que fetchAll() fonctionne très bien, si vous avez plusieurs appels similaires à cette
méthode (ou une autre), il peut être intéressant de factoriser du code en créant votre propre
méthode de récupération d'enregistrements, utilisant fetchAll() ou une autre méthode.

Exemple 247. Méthode personnalisée de récupération d'enregistrements "bugs"


par critère "status"

class Bugs extends Zend_Db_Table_Abstract


{
protected $_name = 'bugs';

public function findByStatus($status)


{
$where = $this->getAdapter()->quoteInto('bug_status = ?',
$status);
return $this->fetchAll($where, 'bug_id');
}
}

5.12.4. Utiliser l'inflexion dans Zend_Db_Table


L'inflexion est un processus de transformations de caractères. Par défaut, si vous ne définissez
pas de nom à votre table via la propriété protégée $_name, Zend_Db_Table_Abstract va
utiliser le nom de la classe comme nom de table, sans effectuer aucune transformation.

Certaines personnes peuvent vouloir utiliser un mécanisme d'inflexion pour transformer le nom
de la classe d'une manière bien spécifique, afin de retrouver le nom de la table.

486
Zend_Db

Par exemple, une classe nommée "BugsProducts", peut vouloir refléter une table s'appelant
"bugs_products," sans utiliser la propriété de classe $_name. Dans cette règle d'inflexion, les
mots composant le nom de la classe sont écrits en "CamelCase", et seraient transformés en
mots en minuscules, et séparés par des tirets bas.

Vous pouvez aussi spécifier le nom de la table indépendamment du nom de la classe. Utilisez
pour cela la propriété $_name de la classe de Table.

Si vous voulez utiliser l'inflexion, vous devrez créer une classe (abstraite) étendant
Zend_Db_Table_Abstract, et redéfinissant sa méthode protégée _setupTableName().
Toutes les classes de Table devront alors hériter de cette nouvelle classe abstraite.

Exemple 248. Exemple d'une classe abstraite utilisant l'inflexion

abstract class MyAbstractTable extends Zend_Db_Table_Abstract


{
protected function _setupTableName()
{
if (!$this->_name) {
$this->_name = myCustomInflector(get_class($this));
}
parent::_setupTableName();
}
}

class BugsProducts extends MyAbstractTable


{
}

C'est à vous d'écrire les fonctions qui vont établir le mécanisme d'inflexion.

6. Zend_Db_Table_Row
6.1. Introduction
Zend_Db_Table_Row est la classe qui donne accès à chacun des résultats issus d'un objet
Zend_Db_Table. Lorsque vous exécutez une requête via une classe de Table, alors les
résultats sont des objets Zend_Db_Table_Row. Vous pouvez aussi utiliser ces objets comme
résultats vides : pour créer des nouveaux résultats à ajouter à la base de données.

Zend_Db_Table_Row est une implémentation du design pattern Row Data Gateway

6.2. Récupérer un résultat (un "Row")


Zend_Db_Table_Abstract possède des méthodes find() et fetchAll(), qui retournent
un objet de type Zend_Db_Table_Rowset, et une méthode fetchRow(), qui retourne un objet
de type Zend_Db_Table_Row.

Exemple 249. Exemple de récupération d'un Row

$bugs = new Bugs();


$row = $bugs->fetchRow($bugs->select()
->where('bug_id = ?', 1));

Un objet Zend_Db_Table_Rowset contient une collection d'objets Zend_Db_Table_Row.


Voyez Section 7, « Zend_Db_Table_Rowset ».

487
Zend_Db

Exemple 250. Exemple de lecture d'un Row dans un Rowset

$bugs = new Bugs();


$rowset = $bugs->fetchAll($bugs->select()
->where('bug_status = ?', 1));
$row = $rowset->current();

6.2.1. Lecture des valeurs des colonnes, dans un Row


Zend_Db_Table_Row_Abstract possède des accesseurs. Les colonnes SQL du résultat sont
disponibles en lecture et écriture, via des propriétés de classe.

Exemple 251. Lecture d'une colonne dans un Row

$bugs = new Bugs();


$row = $bugs->fetchRow($bugs->select()
->where('bug_id = ?', 1));

// Affiche la valeur de la colonne bug_description


echo $row->bug_description;

Les versions antérieures de Zend_Db_Table_Row utilisaient un processus de


transformation nommé inflexion pour récupérer les valeurs des colonnes dans
un résultat.

Actuellement, Zend_Db_Table_Row n'utilise pas d'inflexion. Les noms des


propriétés de l'objet doivent correspondre à l'orthographe des noms des colonnes
dans la base de données sous-jacente

6.2.2. Récupérer les valeurs des colonnes comme un tableau


Vous pouvez accéder aux données d'un row sous forme de tableau grâce à la méthode
toArray(). Celle-ci retourne un tableau associatif.

Exemple 252. Exemple avec toArray()

$bugs = new Bugs();


$row = $bugs->fetchRow($bugs->select()
->where('bug_id = ?', 1));

// Récupère un tableau associatif column/value


$rowArray = $row->toArray();

// Utilisation comme un tableau normal


foreach ($rowArray as $column => $value) {
echo "Column: $column\n";
echo "Value: $value\n";
}

Le tableau retourné par toArray() n'est pas une référence. Vous pouvez modifier ses valeurs,
cela n'aura aucune répercussion dans la base de données.

6.2.3. Récupérer des données des tables liées


Zend_Db_Table_Row_Abstract possède des méthodes permettant de récupérer des
données des tables liées à la table interrogée. Voyez Section 8, « Relations Zend_Db_Table »
pour plus d'informations sur les relations entre les tables.

488
Zend_Db

6.3. Sauvegarde un Row en base de données


6.3.1. Changement des valeurs des colonnes d'un Row
Vous pouvez changer les valeurs de chaque colonne du résultat Row, simplement avec les
accesseurs, comme en lecture. Effectuez une banale affectation.

Utiliser l'accesseur pour spécifier une valeur à une colonne d'un résultat Row ne répercute
pas le comportement immédiatement en base de données. Vous devez utiliser explicitement la
méthode save() pour ceci.

Exemple 253. Exemple de changement de la valeur d'une colonne dans un Row

$bugs = new Bugs();


$row = $bugs->fetchRow($bugs->select()
->where('bug_id = ?', 1));

// Change la valeur d'une ou plusieurs colonnes


$row->bug_status = 'FIXED';

// MET A JOUR l'enregistrement dans la base de données


$row->save();

6.3.2. Créer un Row vierge


Vous pouvez créer un nouvel enregistrement vierge (Row) pour une table avec la méthode
createRow() issue de la classe de cette Table. Vous pouvez alors affecter des valeurs à ses
colonnes grâce aux accesseurs, comme déjà vu, puis enregistrer le Row en base de données
avec sa méthode save().

Exemple 254. Exemple de création d'un Row vierge pour une table

$bugs = new Bugs();


$newRow = $bugs->createRow();

// affecte des valeurs aux colonnes


$newRow->bug_description = '...description...';
$newRow->bug_status = 'NEW';

// INSERT le nouvel enregistrement dans la base de données


$newRow->save();

L'argument optionnel de createRow() est un tableau associatif qui sert à peupler tout de suite
l'objet de valeurs.

Exemple 255. Exemple de remplissage des valeurs d'un nouveau Row vierge

$data = array(
'bug_description' => '...description...',
'bug_status' => 'NEW'
);

$bugs = new Bugs();


$newRow = $bugs->createRow($data);

// INSERT l'enregistrement en base de données


$newRow->save();

489
Zend_Db

La méthode createRow() était nommée fetchNew() dans les anciennes


version de Zend_Db_Table. Il est recommandé de ne plus utiliser cette
ancienne appellation, même si celle-ci fonctionne toujours actuellement.

6.3.3. Changement en masse des valeurs dans un Row


Zend_Db_Table_Row_Abstract possède une méthode setFromArray() qui permet de lui
peupler ses valeurs avec celles issues d'un tableau associatif nom de la colonne / valeur.

Exemple 256. Exemple d'utilisation de setFromArray() avec un enregistrement


(Row) vierge

$bugs = new Bugs();


$newRow = $bugs->createRow();

// Les données sont dans un tableau associatif


$data = array(
'bug_description' => '...description...',
'bug_status' => 'NEW'
);

// Affecte toutes les valeurs des colonnes en une seule fois


$newRow->setFromArray($data);

// INSERT l'enregistrement en base de données


$newRow->save();

6.3.4. Supprimer un Row


Vous pouvez appeler la méthode delete() d'un objet Row. Ceci supprime les lignes dans la
base de données qui correspondent à la clé primaire de l'objet Row.

Exemple 257. Effacer un Row

$bugs = new Bugs();


$row = $bugs->fetchRow('bug_id = 1');

// EFFACE cet enregistrement de la base de données


$row->delete();

Notez qu'il n'est pas nécessaire d'appeler save() pour un effacement. Celui-ci est à effet
immédiat.

6.4. Sérialisation et désérialisation d'un Row


Il peut être utile de sauvegarder le contenu d'un enregistrement (Row) sur un support
quelconque, pour une utilisation ultérieure. La sérialisation est le nom de l'opération qui consiste
à transformer un objet en une forme facilement stockable (dans un fichier par exemple). Les
objets du type Zend_Db_Table_Row_Abstract sont sérialisables.

6.4.1. Sérialiser un Row


Utilisez simplement la fonction PHP serialize() pour créer une chaîne de caractères
représentant votre objet Row.

490
Zend_Db

Exemple 258. Exemple de sérialisation d'un Row

$bugs = new Bugs();


$row = $bugs->fetchRow('bug_id = 1');

// Convertit l'objet en une forme sérialisée


$serializedRow = serialize($row);

// Maintenant vous pouvez utiliser $serializedRow


// pour l'écrire dans un fichier, etc.

6.4.2. Désérialiser les données d'un Row

Utilisez simplement la fonction PHP unserialize(). L'objet Row originel est alors recréé.

Notez que l'objet retourné fonctionne alors en mode déconnecté. Vous pouvez lire les valeurs
des colonnes, mais pas les modifier ni enregistrer l'objet en base de données (save()).

Exemple 259. Exemple de désérialisation d'un objet Row sérialisé

$rowClone = unserialize($serializedRow);

// Vous ne pouvez faire qu'une utilisation en lecture seule


echo $rowClone->bug_description;

Pourquoi ce mode déconnecté imposé ?

Un objet sérialisé est une chaîne de caractère, humainement visible. Il est donc
peu sécurisé d'y laisser un mot de passe vers un serveur de base de données.
Le lecteur d'un objet Row sérialisé ne devrait pas pouvoir accéder à la base
de données. De plus, une connexion à une base de données est un type non
sérialisable par PHP (ressource).

6.4.3. Reconnecter l'objet Row à la Table

Il est bien entendu possible de reconnecter l'objet Row à la base de données, et plus précisément
à la Table dont il fut issu. Utilisez la méthode setTable() et passez lui une instance héritant de
Zend_Db_Table_Abstract. Une fois reconnecté, l'objet Row possède de nouveau un accès
à la base de données, et n'est donc plus en mode lecture seule.

Exemple 260. Exemple de réactivation d'un Row

$rowClone = unserialize($serializedRow);

$bugs = new Bugs();

// Reconnecte le Row à la table et donc, à la base de données


$rowClone->setTable($bugs);

// Maintenant il est possible de l'utiliser en mode écriture


$rowClone->bug_status = 'FIXED';
$rowClone->save();

491
Zend_Db

6.5. Étendre la classe Row


Vous pouvez utilisez votre propre classe étendant Zend_Db_Table_Row_Abstract. Spécifiez
votre classe dans la propriété protégée $_rowClass de la classe de votre Table, ou dans le
tableau du constructeur de l'objet Table.

Exemple 261. Spécification d'une classe Row personnalisée

class MyRow extends Zend_Db_Table_Row_Abstract


{
// ...personnalisations
}

// Spécifie la classe de Row utilisée pour toutes les


// instance de la classe de Table
class Products extends Zend_Db_Table_Abstract
{
protected $_name = 'products';
protected $_rowClass = 'MyRow';
}

// Ou pour une classe de table spécifique, via son constructeur


$bugs = new Bugs(array('rowClass' => 'MyRow'));

6.5.1. Initialisation et pré-traitements d'un Row

Si vous avez un besoin spécifique d'implémenter une logique spéciale après la création
d'une instance de Row, vous pouvez utiliser sa méthode init(), qui est appelée dans son
constructeur, mais après que les méta données aient été calculées.

Exemple 262. Exemple d'utilisation de la méthode init()

class MyApplicationRow extends Zend_Db_Table_Row_Abstract


{
protected $_role;

public function init()


{
$this->_role = new MyRoleClass();
}
}

6.5.2. Définir sa propre logique pour Insert, Update, et Delete dans


Zend_Db_Table_Row

La classe des Rows appelle les méthodes protégées _insert(), _update(), et _delete()
avant d'effectuer chacune des opérations respectives INSERT, UPDATE, et DELETE. Il est donc
possible de définir sa propre logique dans votre sous-classe de Row.

Ci-dessous vous trouverez des exemples d'utilisation d'une logique personnalisée dans les
classes de Row :

492
Zend_Db

Exemple 263. Exemple de logique personnalisée dans une classe de Row

La logique personnelle peut donc être déportée dans une classe de Row qui ne s'appliquera
qu'à certaines tables, et pas à d'autres. Sinon, la classe de Table utilise le Row par défaut.

Par exemple, vous souhaitez historiser toutes les insertions sur une Table spécifique, mais
uniquement si la configuration du site le permet :

class MyLoggingRow extends Zend_Db_Table_Row_Abstract


{
protected function _insert()
{
$log = Zend_Registry::get('database_log');
$log->info(Zend_Debug::dump($this->_data,
"INSERT: $this->_tableClass",
false));
}
}

// $loggingEnabled est une variable d'exemple qui définit si


// l'historisation est activée ou pas
if ($loggingEnabled) {
$bugs = new Bugs(array('rowClass' => 'MyLoggingRow'));
} else {
$bugs = new Bugs();
}

Exemple 264. Exemple d'une classe de Row qui historise les insertions de
plusieurs tables

En passant l'objet Row personnalisé à chacune des Tables concernées, alors vous n'aurez
pas besoin de définir cette logique dans chacune des classes des Tables.

Dans cet exemple, le code qui effectue l'historisation est identique à celui de l'exemple
précédent.

class MyLoggingRow extends Zend_Db_Table_Row_Abstract


{
protected function _insert()
{
$log = Zend_Registry::get('database_log');
$log->info(Zend_Debug::dump($this->_data,
"INSERT: $this->_tableClass",
false));
}
}

class Bugs extends Zend_Db_Table_Abstract


{
protected $_name = 'bugs';
protected $_rowClass = 'MyLoggingRow';
}

class Products extends Zend_Db_Table_Abstract


{
protected $_name = 'products';
protected $_rowClass = 'MyLoggingRow';
}

493
Zend_Db

6.5.3. Définir l'inflexion dans Zend_Db_Table_Row


Il peut être intéressant de personnaliser l'accès aux colonnes de la table représentée par un
résultat Row, plutôt que d'utiliser le nom des colonnes telles que définies dans le SGBDR sous-
jacent. La transformation de l'un vers l'autre est appelée inflexion.

Les classes Zend_Db n'utilisent pas l'inflexion par défaut. Voyez Section 5.12.4, « Utiliser
l'inflexion dans Zend_Db_Table » pour plus de détails sur ce procédé.

Ainsi si vous voulez utiliser l'inflexion, vous devez implémenter vous-même la transformation à
effectuer en redéfinissant la méthode _transformColumn() dans votre classe de Row, et bien
entendu utiliser cette classe de Row pour votre Table.

Exemple 265. Exemple d'utilisation de l'inflexion

Ceci vous permet d'utiliser les accesseurs de votre Row de manière transformée. La classe
de votre Row utilisera _transformColumn() pour changer le nom de la colonne appelée,
avant de le faire correspondre à un nom dans la table réelle de la base de données.

class MyInflectedRow extends Zend_Db_Table_Row_Abstract


{
protected function _transformColumn($columnName)
{
$nativeColumnName = myCustomInflector($columnName);
return $nativeColumnName;
}
}

class Bugs extends Zend_Db_Table_Abstract


{
protected $_name = 'bugs';
protected $_rowClass = 'MyInflectedRow';
}

$bugs = new Bugs();


$row = $bugs->fetchNew();

// Utilisez des nom de colonnes CamelCase, l'inflecteur les


// transformera alors pour vous afin d'établir la correspondance
// avec les noms natifs des colonnes.
$row->bugDescription = 'New description';

En revanche, c'est à vous d'écrire votre mécanisme d'inflexion.

7. Zend_Db_Table_Rowset
7.1. Introduction
Lorsque vous effectuez une requête avec une classe de Table en utilisant
find() ou fetchAll() , le résultat retourné est alors un objet de type
Zend_Db_Table_Rowset_Abstract. Un Rowset est un conteneur d'objets descendants de
Zend_Db_Table_Row_Abstract. Vous pouvez itérer à travers ce conteneur et accéder aux
objet Row individuellement, en lecture ou écriture bien entendu.

7.2. Récupérer un Rowset


Zend_Db_Table_Abstract possède des méthodes find() et fetchAll(), chacune
retourne un objet de type Zend_Db_Table_Rowset_Abstract.

494
Zend_Db

Exemple 266. Exemple de récupération d'un rowset

$bugs = new Bugs();


$rowset = $bugs->fetchAll("bug_status = 'NEW'");

7.3. Atteindre les Rows depuis un Rowset


L'objet Rowset en lui-même n'est pas très intéressant au regard des objets Rows qu'il contient,
qui eux, le sont bien plus.

Un requête légitime peut retourner zéro enregistrement, donc zéro Rows. De ce fait, un
objet Rowset peut contenir zéro objet Row. Comme Zend_Db_Table_Rowset_Abstract
implémente l'interface Countable, vous pouvez utiliser la fonction PHP count() dessus, pour
compter les Rows qu'il contient.

Exemple 267. Compter les Rows dans un Rowset

$rowset = $bugs->fetchAll("bug_status = 'FIXED'");

$rowCount = count($rowset);

if ($rowCount > 0) {
echo "$rowCount rows trouvés";
} else {
echo 'Pas de rows pour cette requête';
}

Exemple 268. Lecture d'un simple Row depuis un Rowset

La façon la plus simple d'accéder à un Row depuis l'objet Rowset est d'utiliser la méthode
current(). C'est tout à fait adapté lorsque le Rowset ne contient qu'un résultat (Row).

$bugs = new Bugs();


$rowset = $bugs->fetchAll("bug_id = 1");
$row = $rowset->current();

Si le Rowset ne contient aucun Row, current() retourne NULL.

495
Zend_Db

Exemple 269. Itération à travers un Rowset

Les objets descendants de Zend_Db_Table_Rowset_Abstract implémentent l'interface


Iterator, ce qui veut dire qu'ils peuvent être utilisés dans la structure PHP foreach.
Chaque valeur récupérée représente alors un objet de Zend_Db_Table_Row_Abstract
qui correspond à un enregistrement dans la table.

$bugs = new Bugs();

// récupère tous les enregistrements de la table


$rowset = $bugs->fetchAll();

foreach ($rowset as $row) {

// affiche 'Zend_Db_Table_Row' par défaut


echo get_class($row) . "\n";

// lit une colonne dans le résultat Row


$status = $row->bug_status;

// modifie une colonne dans le résultat courant


$row->assigned_to = 'mmouse';

// Enregistre en base de données


$row->save();
}

Exemple 270. Déplacement vers une position précise dans le Rowset

SeekableIterator vous permet de vus déplacer à une position précise dans l'itérateur.
Utilisez pour ceci la méthode seek(). Elle prend en paramètre un entier représentant le
numéro de la position désirée. N'oubliez pas que le premier enregistrement est stocké à
la position zéro. Si vous spécifiez une position qui n'existe pas, une exception sera levée.
Vous devriez utiliser count() pour vérifier le nombre d'enregistrements Rows présents.

$bugs = new Bugs();

// récupère tous les enregistrements de la table


$rowset = $bugs->fetchAll();

// Déplace l'itérateur à l'enregistrement 8 (le neuvième donc) :


$rowset->seek(8);

// récupèration de cet enregistrement


$row9 = $rowset->current();

// et utilisation
$row9->assigned_to = 'mmouse';
$row9->save();

getRow() permet de retourner directement un enregistrement en fonction de sa position dans


l'itérateur Rowset. Le premier paramètre est un entier représentant cette position. Le second
paramètre est optionnel, et indique si oui ou non l'itérateur doit rester sur cette position, après
avoir retourné le Row correspondant. Par défaut, il est à FALSE. Cette méthode retourne donc
un objet Zend_Db_Table_Row. Si la position demandée n'existe pas, une exception est levée :

$bugs = new Bugs();

496
Zend_Db

// récupère tous les enregistrements de la table


$rowset = $bugs->fetchAll();

// récupère le neuvième enregistrement immédiatement


$row9->getRow(8);

// utilisation de l'enregistrement récupéré :


$row9->assigned_to = 'mmouse';
$row9->save();

Dès que vous avez accès à un objet individuel Row, vous pouvez le piloter comme présenté
dans la section Section 6, « Zend_Db_Table_Row ».

7.4. Récupérer un Rowset en tant que tableau (Array)


Vous pouvez accéder à toutes les données d'un Rowset au moyen d'un tableau PHP avec
la méthode toArray(). Ce tableau possède deux dimensions. Chaque entrée du tableau
représente un tableau de l'objet Row. Les clés sont les noms des champs, et les valeurs leurs
valeurs.

Exemple 271. Utiliser toArray()

$bugs = new Bugs();


$rowset = $bugs->fetchAll();

$rowsetArray = $rowset->toArray();

$rowCount = 1;
foreach ($rowsetArray as $rowArray) {
echo "row #$rowCount:\n";
foreach ($rowArray as $column => $value) {
echo "\t$column => $value\n";
}
++$rowCount;
echo "\n";
}

Le tableau retourné par toArray() n'est pas une référence. Le modifier ne modifiera en aucun
cas les données réelles dans la base de données.

7.5. Sérialisation et Désérialisation d'un Rowset


Les objets de type Zend_Db_Table_Rowset_Abstract sont sérialisables. De la même
manière que vous sérialisez un objet Row individuel, le Rowset est sérialisable et désérialisable.

Exemple 272. Sérialiser d'un Rowset

Utilisez simplement la fonction PHP serialize() pour créer une chaîne de caractères
représentant votre objet Rowset.

$bugs = new Bugs();


$rowset = $bugs->fetchAll();

// Convertit l'objet en sa forme sérialisée


$serializedRowset = serialize($rowset);

// Maintenant vous pouvez écrire $serializedRowset


// dans un fichier, etc.

497
Zend_Db

Exemple 273. Désérialisation d'un objet Rowset sérialisé

Utilisez simplement la fonction PHP unserialize().

Notez que l'objet retourné fonctionne alors en mode déconnecté. Vous pouvez itérer à
travers, et lire les objets Row qu'il contient, mais vous ne pouvez plus faire intervenir la base
de données, ni changer de valeurs dans les Rows.

$rowsetDisconnected = unserialize($serializedRowset);

// Maintenant vous pouvez utiliser l'objet, mais en lecture seule


$row = $rowsetDisconnected->current();
echo $row->bug_description;

Pourquoi ce mode déconnecté imposé ?

Un objet sérialisé est une chaîne de caractère, humainement visible. Il est donc
peut sécurisé d'y laisser un mot de passe vers un serveur de base de données.
Le lecteur d'un objet Rowset sérialisé ne devrait pas pouvoir accéder à la base
de données. De plus, une connexion à une base de données est un type non
sérialisable par PHP (ressource).

Il est bien entendu possible de reconnecter l'objet Rowset à la base de données, et plus
précisément à la Table dont il fut issu. Utilisez la méthode setTable() et passez lui une
instance héritant de Zend_Db_Table_Abstract. Une fois reconnecté, l'objet Rowset possède
de nouveau un accès à la base de données, et n'est donc plus en mode lecture seule.

Exemple 274. Réactivation d'un Rowset

$rowset = unserialize($serializedRowset);

$bugs = new Bugs();

// Reconnecte le rowset à une table, et par


// conséquent, à la connexion vers la base de données active
$rowset->setTable($bugs);

$row = $rowset->current();

// Maintenant vous pouvez modifier les objets Row et les sauvegarder


$row->bug_status = 'FIXED';
$row->save();

Réactiver un Rowset avec setTable() réactive tous les Rows le composant.

7.6. Étendre la classe Rowset


Vous pouvez utilisez votre propre classe étendant Zend_Db_Table_Rowset_Abstract.
Spécifiez votre classe dans la propriété protégée $_rowsetClass de la classe de votre Table,
ou dans le tableau du constructeur de l'objet Table.

498
Zend_Db

Exemple 275. Spécifier sa propre classe de Rowset

class MyRowset extends Zend_Db_Table_Rowset_Abstract


{
// ...personnalisations
}

// Spécifie la classe de Rowset utilisée pour toutes les


// instance de la classe de Table
class Products extends Zend_Db_Table_Abstract
{
protected $_name = 'products';
protected $_rowsetClass = 'MyRowset';
}

// Ou pour une classe de table spécifique, via son constructeur


$bugs = new Bugs(array('rowsetClass' => 'MyRowset'));

En temps normal, la classe standard Zend_Db_Rowset est suffisante. Cependant, il peut être
judicieux de rajouter de la logique dans son Rowset, pour une table précise. Par exemple, une
nouvelle méthode pourrait effectuer des calculs.

Exemple 276. Exemple d'une classe Rowset personnalisée avec une nouvelle
méthode

class MyBugsRowset extends Zend_Db_Table_Rowset_Abstract


{
/**
* Trouve les Rows dans le Rowset courant avec la plus grande
* valeur pour la colonne 'updated_at'.
*/
public function getLatestUpdatedRow()
{
$max_updated_at = 0;
$latestRow = null;
foreach ($this as $row) {
if ($row->updated_at > $max_updated_at) {
$latestRow = $row;
}
}
return $latestRow;
}
}

class Bugs extends Zend_Db_Table_Abstract


{
protected $_name = 'bugs';
protected $_rowsetClass = 'MyBugsRowset';
}

8. Relations Zend_Db_Table
8.1. Introduction
Les tables possèdent des relations entre elles, dans une base de données relationnelle. Une
entité d'une table peut être liée à une autre entité d'une autre table, via un procédé appelé
contrainte d'intégrité référentielle

499
Zend_Db

La classe Zend_Db_Table_Row possède des méthodes pour récupérer des enregistrement


dans d'autres tables, liées à celle en cours.

8.2. Définir ses relations


Chaque table doit avoir sa classe étendant Zend_Db_Table_Abstract, comme décrit dans
Section 5.2, « Définir une classe de Table ». Voyez aussi Section 1.2, « La base de données
d'exemple » pour une description de la base de donnée qui servira d'exemple pour la suite de
ce chapitre.

Voici les classes correspondantes à ces tables :

class Accounts extends Zend_Db_Table_Abstract


{
protected $_name = 'accounts';
protected $_dependentTables = array('Bugs');
}

class Products extends Zend_Db_Table_Abstract


{
protected $_name = 'products';
protected $_dependentTables = array('BugsProducts');
}

class Bugs extends Zend_Db_Table_Abstract


{
protected $_name = 'bugs';

protected $_dependentTables = array('BugsProducts');

protected $_referenceMap = array(


'Reporter' => array(
'columns' => 'reported_by',
'refTableClass' => 'Accounts',
'refColumns' => 'account_name'
),
'Engineer' => array(
'columns' => 'assigned_to',
'refTableClass' => 'Accounts',
'refColumns' => 'account_name'
),
'Verifier' => array(
'columns' => array('verified_by'),
'refTableClass' => 'Accounts',
'refColumns' => array('account_name')
)
);
}

class BugsProducts extends Zend_Db_Table_Abstract


{
protected $_name = 'bugs_products';

protected $_referenceMap = array(


'Bug' => array(
'columns' => array('bug_id'),
'refTableClass' => 'Bugs',
'refColumns' => array('bug_id')
),

500
Zend_Db

'Product' => array(


'columns' => array('product_id'),
'refTableClass' => 'Products',
'refColumns' => array('product_id')
)
);

Si vous utilisez Zend_Db_Table pour émuler les cascades UPDATE et DELETE, alors déclarez
$_dependentTables en tant que tableau dans la classe des tables parentes. Listez ainsi le
nom de chaque table dépendante. Utilisez bien le nom des classes, et non les noms physiques
des tables.

Si votre SGBD implémente le mécanisme des cascades, alors vous n'avez pas
besoin de déclarer $_dependentTables. Voyez Section 8.6, « Opérations
d'écritures en cascade » pour plus d'informations.

Déclarez un tableau $_referenceMap dans les classes de chaque table dépendante (qui
"reçoit une clé"). C'est un tableau associatif, dit de "rôles". Un rôle définit quelle table est parente
dans la relation, et quelle est sa colonne de parenté.

Le rôle est utilisé comme index du tableau $_referenceMap. Il est utilisé pour définir la
relation, et pourra faire partie du nom de certaines méthodes, comme nous le verrons plus tard.
Choisissez ainsi un nom de rôle de manière intelligente.

Dans l'exemple du dessus, les rôles dans la classe Bugs sont : "Reporter", "Engineer",
"Verifier" et "Product".

La valeur de chaque rôle dans le tableau $_referenceMap est aussi un tableau associatif. Les
éléments de chaque rôle sont décrits ci-après.

• columns => une chaîne de caractères ou un tableau de chaînes désignant le(s) nom(s) des
clés étrangères dans la table dépendante (la table actuelle donc).

Il est courant qu'il s'agisse d'une seule colonne, mais on peut rencontrer le cas de clés
composées de multiples colonnes.

• refTableClass => désigne la classe de la table parente, liée à cette colonne. Utilisez le nom
de la classe et non le nom de la table physique.

Il est courant qu'une table dépendante n'ait qu'une seule référence d'une même table parente.
Cependant certaines tables peuvent avoir plusieurs références vers une même table parente.
Dans notre base de données d'exemple, c'est le cas avec la table bugs. Elle possède soit
une et une seule colonne référençant la table parente products, mais elle possède trois
références (donc trois colonnes) vers la table parente accounts. Chaque référence doit être
matérialisée par un rôle unique dans le tableau $_referenceMap.

• refColumns => c'est une chaîne de caractères ou un tableau de chaînes nommant la(es)
colonne(s) (clé primaire) de la table parente.

Si vous devez utiliser de multiples colonnes parentes pour une seule clé, alors veillez à bien
les entrer dans 'columns' dans le même ordre que dans 'refColumns'.

Il est optionnel de spécifier la refColumns. La clé primaire est utilisée par défaut comme
colonne parente dans une relation.

501
Zend_Db

• onDelete => le nom de l'action à exécuter si un enregistrement est supprimé de la table


parente. Voyez Section 8.6, « Opérations d'écritures en cascade » pour plus d'informations.

• onUpdate => le nom de l'action à exécuter si un enregistrement est mis à jour dans la table
parente. VoyezSection 8.6, « Opérations d'écritures en cascade » pour plus d'informations.

8.3. Récupérer des enregistrements dépendants (enfants)


Si vous possédez un enregistrement actif (Row), il est possible de récupérer ses enfants
dépendants, si les dépendances ont été déclarées suivant la procédure ci-dessus. Utilisez la
méthode :

$row->findDependentRowset($table, [$rule]);

Cette méthode retourne un objet instance de Zend_Db_Table_Rowset_Abstract, qui


contient tous les enregistrements (Row) de la table dépendante $table faisant référence à
l'enregistrement actif actuel $row.

Le paramètre $table désigne la table dépendante à utiliser. Ceci peut être une chaîne de
caractères aussi bien qu'un objet de la classe de cette table.

Exemple 277. Récupérer des enregistrements dépendants

Cet exemple montre comment obtenir un enregistrement actif (objet Row) de la table
Accounts, et comment en récupérer les enfants dépendants de la table Bugs. (les bugs
reportés par ce compte)

$accountsTable = new Accounts();


$accountsRowset = $accountsTable->find(1234);
$user1234 = $accountsRowset->current();

$bugsReportedByUser = $user1234->findDependentRowset('Bugs');

Le second paramètre $rule est optionnel. Il s'agit du nom du rôle à utiliser depuis le tableau
$_referenceMap de la classe de la table dépendante. Si vous ne le spécifiez pas, le premier
rôle sera utilisé. Il n'y a dans la majorité des cas qu'un seul rôle.

Dans l'exemple ci dessus, nous ne fournissons pas de nom de rôle, le premier est donc pris en
considération, et il s'agit de "Reporter".

Exemple 278. Récupérer des enregistrements dépendants avec un rôle


spécifique

Dans cet exemple nous montrons comment obtenir un enregistrement (Row) depuis la table
Accounts, et comment trouver les Bugs assignés à ce compte (Account). Nous devrons
alors nommer le rôle "Engineer".

$accountsTable = new Accounts();


$accountsRowset = $accountsTable->find(1234);
$user1234 = $accountsRowset->current();

$bugsAssignedToUser = $user1234->findDependentRowset('Bugs',
'Engineer');

Vous pouvez rajouter des critères à vos relations, comme l'ordre ou la limite, ceci en utilisant
l'objet select de l'enregistrement parent.

502
Zend_Db

Exemple 279. Récupérer des enregistrements dépendants en utilisant un objet


Zend_Db_Table_Select

Dans cet exemple nous montrons comment obtenir un enregistrement (Row) depuis la table
Accounts, et comment trouver les Bugs assignés à ce compte (Account), mais limités
seulement à trois enregistrements, et ordonnés par nom. Nous devrons nommer le rôle
"Engineer".

$accountsTable = new Accounts();


$accountsRowset = $accountsTable->find(1234);
$user1234 = $accountsRowset->current();
$select = $accountsTable->select()->order('name ASC')
->limit(3);

$bugsAssignedToUser = $user1234->findDependentRowset('Bugs',
'Engineer',
$select);

Vous pouvez récupérer les enregistrements dépendants d'une autre manière. En utilisant
les "méthodes magiques". En effet, Zend_Db_Table_Row_Abstract va utiliser la
méthode findDependentRowset('<TableClass>', '<Rule>') si vous appelez sur
l'enregistrement une méthode correspondante à un de ces motifs :

• $row->find<TableClass>()

• $row->find<TableClass>By<Rule>()

Dans les motifs ci-dessus, <TableClass> et <Rule> désignent respectivement le nom de la


table dépendante et le rôle à utiliser.

Certains frameworks tels que Rails pour Ruby, utilise un mécanisme dit
d'inflexion, qui permet de transformer les noms des identifiants (nom de table,
de rôle...) d'une certaine manière bien spécifique dans les méthodes appelées.
Cela n'est pas le cas de Zend Framework : vous devez, dans vos méthodes
magiques, utiliser l'orthographe exacte des noms des rôles et classes, tels que
vous les définissez.

Exemple 280. Récupérer des enregistrements dépendants en utilisant les


méthodes magiques

Cet exemple a le même effet que le précédent. Il utilise simplement les méthodes magiques
pour récupérer les enregistrements dépendants.

$accountsTable = new Accounts();


$accountsRowset = $accountsTable->find(1234);
$user1234 = $accountsRowset->current();

// Utilise le rôle par défaut (le premier de la liste)


$bugsReportedBy = $user1234->findBugs();

// Utilise un rôle spécifique


$bugsAssignedTo = $user1234->findBugsByEngineer();

8.4. Récupérer l'enregistrement parent


Si vous possédez un enregistrement (Row) dont la table possède une table parente, il est possible
alors de récupérer l'enregistrement parent. Utilisez pour cela la méthode :

503
Zend_Db

$row->findParentRow($table, [$rule]);

La logique veut qu'il ne puisse y avoir qu'un et un seul parent par enregistrement. Ainsi, cette
méthode retourne un objet Row et non un objet Rowset

Le premier paramètre $table désigne la table parente. Ceci peut être une chaîne de caractères,
ou un objet instance de la classe de la table parente.

Exemple 281. Récupérer l'enregistrement parent

Cet exemple illustre la récupération d'un enregistrement Bugs (disons par exemple ceux
avec le statut "NEW"), et l'obtention de l'enregistrement parent correspondant à Accounts
(la personne ayant reporté le bug)

$bugsTable = new Bugs();


$bugsRowset = $bugsTable->fetchAll(array('bug_status = ?' => 'NEW'));
$bug1 = $bugsRowset->current();

$reporter = $bug1->findParentRow('Accounts');

Le second paramètre $rule est optionnel. Il s'agit du nom du rôle à utiliser depuis le tableau
$_referenceMap de la classe de la table dépendante. Si vous ne le spécifiez pas, le premier
rôle sera utilisé. Il n'y a dans la majorité des cas qu'un seul rôle.

Dans l'exemple ci dessus, nous ne fournissons pas de nom de rôle, le premier est donc pris en
considération, et il s'agit de "Reporter".

Exemple 282. Récupérer un enregistrement parent avec un rôle spécifique

Cet exemple va démontrer comment, à partir d'un enregistrement de Bugs, récupérer la


personne en étant assignée. Il va falloir utiliser le rôle "Engineer".

$bugsTable = new Bugs();


$bugsRowset = $bugsTable->fetchAll(array('bug_status = ?', 'NEW'));
$bug1 = $bugsRowset->current();

$engineer = $bug1->findParentRow('Accounts', 'Engineer');

Vous pouvez récupérer l'enregistrement parent d'une autre manière. En utilisant


les "méthodes magiques". En effet, Zend_Db_Table_Row_Abstract va utiliser la
méthodefindParentRow('<TableClass>', '<Rule>') si vous appelez sur
l'enregistrement une méthode correspondante à un de ces motifs :

• $row->findParent<TableClass>([Zend_Db_Table_Select $select])

• $row->findParent<TableClass>By<Rule>([Zend_Db_Table_Select $select])

Dans les motifs ci-dessus, <TableClass> et <Rule> représentent respectivement le nom de


la classe de la table parente, et le rôle à utiliser éventuellement.

Les noms de la table et du rôle doivent être orthographiés de la même manière


qu'ils ne le sont lors de leur définition dans la table.

504
Zend_Db

Exemple 283. Récupérer un enregistrement parent en utilisant les méthodes


magiques

Cet exemple a le même effet que le précédent. Il utilise simplement les méthodes magiques
pour récupérer l'enregistrement parent.

$bugsTable = new Bugs();


$bugsRowset = $bugsTable->fetchAll(array('bug_status = ?', 'NEW'));
$bug1 = $bugsRowset->current();

// Utilise le rôle par défaut ( le premier déclaré)


$reporter = $bug1->findParentAccounts();

// Utilise un rôle spécifique


$engineer = $bug1->findParentAccountsByEngineer();

8.5. Récupérer des enregistrements dans une relation N-N


(plusieurs-à-plusieurs ou "many-to-many")
Si vous possédez un enregistrement sur une table (appelons la "table d'origine") ayant une
relation plusieurs à plusieurs vers une autre table (appelons la "table de destination"), vous
pouvez alors accéder aux enregistrements de la table de destination, via une table dite
"d'intersection". Utilisez la méthode :

$row->findManyToManyRowset($table,
$intersectionTable,
[$rule1,
[$rule2,
[Zend_Db_Table_Select $select]]]);

Cette méthode retourne un objet instance de Zend_Db_Table_Rowset_Abstract qui


contient les enregistrements de la table $table qui correspondent à la relation plusieurs à
plusieurs. L'enregistrement courant de la table courante, $row, est utilisé comme point de départ
pour effectuer une jointure vers la table de destination, via la table d'intersection.

Le premier paramètre $table peut être soit une chaîne soit un objet instance de la classe de
la table de destination dans la relation plusieurs à plusieurs.

Le second paramètre $intersectionTable peut être soit une chaîne soit un objet instance
de la classe de la table d'intersection dans la relation plusieurs à plusieurs.

Exemple 284. Récupérer des enregistrements dans une relation plusieurs-à-


plusieurs

Cet exemple montre comment posséder un enregistrement de la table d'origine Bugs, et


comment en récupérer les enregistrements de Products, qui représentent les produits qui
font référence à ce bug.

$bugsTable = new Bugs();


$bugsRowset = $bugsTable->find(1234);
$bug1234 = $bugsRowset->current();

$productsRowset = $bug1234->findManyToManyRowset('Products',
'BugsProducts');

505
Zend_Db

Les troisième et quatrième paramètres, $rule1 et $rule2, sont optionnels. Ce sont des
chaînes de caractères qui désignent les rôles à utiliser dans le tableau $_referenceMap de
la table d'intersection.

$rule1 nomme le rôle dans la relation entre la table d'origine et la table d'intersection. Dans
notre exemple, il s'agit donc de la relation de Bugs à BugsProducts.

$rule2nomme le rôle dans la relation entre la table d'origine et la table d'intersection. Dans
notre exemple, il s'agit donc de la relation de BugsProducts à Products.

Si vous ne spécifiez pas de rôles, alors le premier rôle trouvé pour la table, dans le tableau
$_referenceMap, sera utilisé. Dans la grande majorité des cas, il n'y a qu'un rôle.

Dans l'exemple ci-dessus, les rôles ne sont pas spécifiés. Ainsi $rule1 prend la valeur
"Reporter" et $rule2 prend la valeur "Product".

Exemple 285. Récupérer des enregistrements dans une relation plusieurs-à-


plusieurs avec un rôle spécifique

Cet exemple montre comment à partir d'un enregistrement de Bugs, récupérer les
enregistrements de Products, représentant les produits comportant ce bug.

$bugsTable = new Bugs();


$bugsRowset = $bugsTable->find(1234);
$bug1234 = $bugsRowset->current();

$productsRowset = $bug1234->findManyToManyRowset('Products',
'BugsProducts',
'Bug');

Vous pouvez récupérer l'enregistrement de destination d'une autre manière. En utilisant les
"méthodes magiques". En effet, Zend_Db_Table_Row_Abstract va utiliser la méthode
findManyToManyRowset('<TableClass>', '<IntersectionTableClass>',
'<Rule1>', '<Rule2>') si vous appelez sur l'enregistrement une méthode correspondante
à un de ces motifs :

• $row-
>find<TableClass>Via<IntersectionTableClass>([Zend_Db_Table_Select
$select])

• $row-
>find<TableClass>Via<IntersectionTableClass>By<Rule1>([Zend_Db_Table_Select
$select])

• $row-
>find<TableClass>Via<IntersectionTableClass>By<Rule1>And<Rule2>([Zend_Db_Table_Se
$select])

Dans les motifs ci dessus, <TableClass> et <IntersectionTableClass> sont des chaînes


de caractères correspondantes aux noms des classes des tables de destination et d'intersection
(respectivement). <Rule1> et <Rule2> sont respectivement des chaînes désignant les rôles
dans la table d'intersection pour la table de référence, et de destination.

Les noms de la table et des rôles doivent être orthographiés de manière exacte,
tel qu'ils le sont lors de leurs définitions respectives.

506
Zend_Db

Exemple 286. Récupérer des enregistrements dans une relation plusieurs-à-


plusieurs avec les méthodes magiques

Cet exemple illustre la récupération d'enregistrements dans une table de destination, bugs,
depuis un produit, en passant par une table d'intersection, le tout, via des méthodes
magiques.

$bugsTable = new Bugs();


$bugsRowset = $bugsTable->find(1234);
$bug1234 = $bugsRowset->current();

// Utilisation des rôles par défaut


$products = $bug1234->findProductsViaBugsProducts();

// Utilisation d'un rôle spécifique


$products = $bug1234->findProductsViaBugsProductsByBug();

8.6. Opérations d'écritures en cascade


Déclarer l'intégrité référentielle

Déclarer les opérations de cascades dûes à l'intégrité référentielle dans


Zend_Db_Table directement, ne doit se faire seulement si votre SGBD ne
supporte pas nativement ce genre d'opérations.

C'est le cas par exemple de MySQL utilisant le stockage de tables MyISAM,


ou encore SQLite. Ces solutions là ne supportent pas l'intégrité référentielle.
Il peut alors être intéressant d'utiliser Zend_Db_Table pour émuler un tel
comportement

Si votre SGBD en revanche supporte les clauses ON DELETE et ON UPDATE,


alors vous devriez les déclarer directement dans le SGBD plutôt que de vous fier
à l'émulation proposée par Zend_Db_Table. Déclarer son intégrité référentielle
dans son SGBD directement est tout à fait recommandé pour les performances,
l'intégrité (l'atomicité des opérations), et la logique de base de données.

Il est très important de ne pas déclarer ses règles d'intégrité référentielle à la fois
dans son SGBD et dans les classes Zend_Db_Table.

Vous pouvez déclarer des opérations de cascade sur un UPDATE ou un DELETE, à appliquer sur
les enregistrements dépendants à la table en cours.

Exemple 287. Exemple de DELETE cascade

Cet exemple montre l'effacement d'un enregistrement de Products, qui va propager


l'effacement des enregistrements dépendants dans la table Bugs.

$productsTable = new Products();


$productsRowset = $productsTable->find(1234);
$product1234 = $productsRowset->current();

$product1234->delete();
// Cascades automatiques vers le table Bugs
// et suppression des enregistrements dépendants.

507
Zend_Db

De la même manière, si vous utilisez un UPDATE pour changer la valeur de la clé primaire d'une
table parente, vous pourriez nécessiter que les clés étrangères des tables dépendantes soient
mises à jour.

En général s'il s'agit d'une séquence, il n'est pas nécessaire de mettre à jour les enregistrements
dépendants. En revanche concernant les clé dites naturelles , il peut s'avérer nécessaire de
propager un changement de valeur.

Afin de déclarer une relation de cascades dans Zend_Db_Table, éditer les rôles dans
$_referenceMap. Ajoutez les clés 'onDelete' et 'onUpdate' et donnez leur la valeur
'cascade' (ou la constante self::CASCADE). Avant qu'un enregistrement ne soit modifié(sa clé
primaire) / supprimé, tous les enregistrements dans les tables dépendantes seront modifiés /
supprimés.

Exemple 288. Exemple de déclaration des opérations de cascade

Dans l'exemple ci-après, les enregistrements de Bugs sont automatiquement supprimés si


l'enregistrement dans la table Products auquel ils font référence est supprimé. L'élément
"onDelete" de la $_referenceMap est mis à self::CASCADE.

Pas de mise à jour en cascade en revanche pour cette table, si la clé primaire de la table
parente est changée. En effet, l'élément "onUpdate" est mis à self::RESTRICT. Vous
auriez aussi pu tout simplement ne pas spécifier "onUpdate" .

class BugsProducts extends Zend_Db_Table_Abstract


{
...
protected $_referenceMap = array(
'Product' => array(
'columns' => array('product_id'),
'refTableClass' => 'Products',
'refColumns' => array('product_id'),
'onDelete' => self::CASCADE,
'onUpdate' => self::RESTRICT
),
...
);
}

8.6.1. Notes concernant les opérations de cascade

Les opérations de cascades déclenchées par Zend_Db_Table ne sont pas atomiques.

Ceci signifie que si votre SGBD possède un moyen de gérer les cascades, comme l'intégrité
référentielle (et les clés étrangères), alors vous ne devriez pas utiliser les cascades INSERT
via Zend_Db_Table, car elles vont entrer en conflit avec le système d'intégrité référentielle du
SGBD qui lui, est atomique.

Le problème est plus mitigé concernant DELETE. Vous pouvez détruire de manière non atomique
un enregistrement dépendant, avant de détruire son parent.

Cependant, les deux opérations UPDATE et DELETE utilisées de manière non atomique(que),
c'est à dire avec le mécanisme de Zend_Db_Table, peuvent laisser la base de données dans un
état non désiré, ou état intermédiaire. Supposez que vous supprimiez tous les enregistrements
dépendants, pour finir par leur parent unique. A un moment donnée, la base de donnée sera dans

508
Zend_Db

un état tel que le parent sera sans enfants, mais toujours bel et bien présent. Si un autre client
se connecte exactement à ce moment là, il va pouvoir requêter éventuellement le parent, en
croyant que celui-ci n'a plus d'enfant, ce qui normalement n'est pas le cas. Il est alors totalement
impossible pour ce client là de se rendre compte qu'il a effectuer une lecture au beau milieu
d'une plus vaste opération d'effacement.

Les problèmes de changements non-atomique peuvent être anéantis en utilisant les transactions
isolantes, c'est d'ailleurs un de leur rôle clé. Cependant certains SGBDs ne supportent pas
encore les transactions, et autorisent leurs clients à lire des changements incomplets pas validés
en totalité.

Les opérations de cascades de Zend_Db_Table ne sont utilisées que par Zend_Db_Table.

Les cascades pour DELETE et UPDATE définies dans vos classes Zend_Db_Table ne sont
utilisées que lors du recours aux méthodes save() ou delete() sur les enregistrements
Row. Si vous utilisez une autre interface pour vos UPDATE ou DELETE, comme par exemple un
outil de requêtes, ou une autre application, les opérations de cascades ne sont bien sûr pas
appliquées. C'est même le cas si vous utilisez les méthodes update() et delete() dans la
classe Zend_Db_Adapter.

Pas d'INSERT en cascade

Le support pour les cascades d'INSERT n'est pas assuré. Vous devez explicitement insérer les
enregistrements dépendants à un enregistrement parent.

9. Zend_Db_Table_Definition
9.1. Introduction
Zend_Db_Table_Definition est une classe qui peut être utilisée pour décrire les relations et
les options de configuration qui devraient être utilisées lorsque Zend_Db_Table est manipulée
par instantiation concrête.

9.2. Utilisation de base


Les options décrites dans un objet de définition sont les mêmes que celles qu'utilisent les classes
étendant Zend_Db_Table_Abstract. Votre objet de définition peut alors être passé à la classe à
l'instanciation, celle-ci connaitra alors la définition de toutes les tables concernées.

Voici un exemple d'objet de définition qui va décrire les noms des tables et les relations entre
les objets supports de ces tables. Note: Si 'name' n'est pas précisé, la clé servira alors de nom
à la table, c'est le cas dans notre exemple avec 'genre'.

509
Zend_Db

Exemple 289. Décrire un modèle de base de données

$definition = new Zend_Db_Table_Definition(array(


'author' => array(
'name' => 'author',
'dependentTables' => array('book')
),
'book' => array(
'name' => 'book',
'referenceMap' => array(
'author' => array(
'columns' => 'author_id',
'refTableClass' => 'author',
'refColumns' => 'id'
)
)
),
'genre' => null,
'book_to_genre' => array(
'referenceMap' => array(
'book' => array(
'columns' => 'book_id',
'refTableClass' => 'book',
'refColumns' => 'id'
),
'genre' => array(
'columns' => 'genre_id',
'refTableClass' => 'genre',
'refColumns' => 'id'
)
)
)
));

Comme vous le voyez, les mêmes options que vous utilisez en général en étendant
Zend_Db_Table_Abstract sont présentes dans ce tableau. Cette définition va persister vers
toutes les tables qui seront créees par votre objet, ceci assure une isolation et un bon
fonctionnement.

Ci-après un exemple d'instanciation d'une table et de l'utilisation de findDependentRowset() et


findManyToManyRowset() qui vont correspondre au modèle de données:

Exemple 290. Intéragir avec la définition utilisée

$authorTable = new Zend_Db_Table('author', $definition);


$authors = $authorTable->fetchAll();

foreach ($authors as $author) {


echo $author->id . ': ' . $author->first_name . ' ' . $author->last_name . PHP_EOL;
$books = $author->findDependentRowset('book');
foreach ($books as $book) {
echo ' Book: ' . $book->title . PHP_EOL;
$genreOutputArray = array();
foreach ($book->findManyToManyRowset('genre', 'book_to_genre') as $genreRow) {
$genreOutputArray[] = $genreRow->name;
}
echo ' Genre: ' . implode(', ', $genreOutputArray) . PHP_EOL;
}
}

510
Zend_Db

9.3. Utilisation avancée


Quelques fois vous voudriez mixer les utilisations, via la définition et une extension concrête de
Zend_Db_Table_Abstract. Pour ce faire, omettez de spécifier une définition concernant la classe
concrête. Zend_Db_Table utiisera alors l'instance que vous lui passerez.

Dans l'exemple d'après, nous allons placer une des tables sous forme de classe concrête, et
laisser les autres sous forme de définitions. Nous allons voir alors comment les faire intéragir.

511
Zend_Db

Exemple 291. Mixer la définition et l'extension concrête

class MyBook extends Zend_Db_Table_Abstract


{
protected $_name = 'book';
protected $_referenceMap = array(
'author' => array(
'columns' => 'author_id',
'refTableClass' => 'author',
'refColumns' => 'id'
)
);
}

$definition = new Zend_Db_Table_Definition(array(


'author' => array(
'name' => 'author',
'dependentTables' => array('MyBook')
),
'genre' => null,
'book_to_genre' => array(
'referenceMap' => array(
'book' => array(
'columns' => 'book_id',
'refTableClass' => 'MyBook',
'refColumns' => 'id'
),
'genre' => array(
'columns' => 'genre_id',
'refTableClass' => 'genre',
'refColumns' => 'id'
)
)
)
));

$authorTable = new Zend_Db_Table('author', $definition);


$authors = $authorTable->fetchAll();

foreach ($authors as $author) {


echo $author->id . ': ' . $author->first_name . ' ' . $author->last_name . PHP_EOL;
$books = $author->findDependentRowset(new MyBook());
foreach ($books as $book) {
echo ' Book: ' . $book->title . PHP_EOL;
$genreOutputArray = array();
foreach ($book->findManyToManyRowset('genre', 'book_to_genre') as $genreRow) {
$genreOutputArray[] = $genreRow->name;
}
echo ' Genre: ' . implode(', ', $genreOutputArray) . PHP_EOL;
}
}

512
Zend_Debug
1. Afficher des informations
La méthode statique Zend_Debug::dump() affiche et/ou retourne les informations concernant
une expression. Cette technique simple de débogage est commune, parce que facile à utiliser
de façon ad hoc et n'exigeant aucune initialisation, aucun outils spéciaux, ou environnement de
mise au point.

Exemple 292. Exemple avec la méthode dump()

Zend_Debug::dump($var, $label = null, $echo = true);

L'argument $var définit l'expression ou la variable que l'on veut examiner avec
Zend_Debug::dump().

L'argument $label est un texte arbitraire à placer avant la sortie de Zend_Debug::dump().


Ceci est utile lorsque vous souhaitez afficher à l'écran des informations concernant plusieurs
variables.

Le booléen $echo indique s'il faut (ou non) afficher la sortie de Zend_Debug::dump(). Si
TRUE, la sortie sera affichée. Quel que soit l'état de $echo, la sortie est toujours retournée.

Il peut être utile de savoir que la méthode Zend_Debug::dump() enveloppe la fonction PHP
var_dump(). Si le flux est reconnu à destination d'un contenu Web, l'affichage de var_dump()
est échappé avec htmlspecialchars() et est enveloppé entre des balises (X)HTML <pre>
et </pre>.

Déboguer avec Zend_Log


Utiliser Zend_Debug::dump() est ce qui convient le mieux pour le débogage
durant le développement de l'application. Vous pouvez facilement ajouter ou
retirer du code que vous souhaitez visualiser.

Vous pouvez aussi considérer le composant Zend_Logsi vous souhaitez rendre


permanent du code de débogage. Par exemple, vous pouvez utiliser le niveau
de log DEBUG et le flux d'écriture Stream du log pour afficher la chaîne retournée
par Zend_Debug::dump().

513
Zend_Dojo
1. Introduction
A partir de la version 1.6.0, Zend Framework contient Dojo Toolkitpour permettre le
développement rapide d'applications internet riche (RIA). Les points d'intégration avec Dojo
incluent :

• le support de JSON-RPC ;

• la compatibilité avec dojo.data ;

• des aides de vues pour aider au paramétrage de l'environnement Dojo ;

• des aides de vues spécifiques à Dijit ;

• des éléments de formulaires et des décorateurs spécifiques à Dijit.

La distribution Dojo elle-même peut être trouvée dans le dossier externals/dojo/ de la


distribution de Zend Framework. Il s'agit d'une distribution source, qui inclue le code source
javascript complet de Dojo, les tests unitaires et les outils de construction. Vous pouvez créer un
lien symbolique dans votre répertoire javascript, le copier ou utiliser l'outil de construction pour
créer votre propre paquet que vous pourrez inclure dans votre projet. De manière alternative,
vous pouvez utiliser l'un des Content Delivery Network qui offre Dojo (le ZF supporte à la fois le
CDN officiel AOL ainsi que celui de Google).

2. Zend_Dojo_Data: dojo.data Envelopes


Dojo provides data abstractions for data-enabled widgets via its dojo.data component. This
component provides the ability to attach a data store, provide some metadata regarding the
identity field and optionally a label field, and an API for querying, sorting, and retrieving records
and sets of records from the datastore.

dojo.data is often used with XmlHttpRequest to pull dynamic data from the server. The primary
mechanism for this is to extend the QueryReadStore to point at a URL and specify the query
information. The server side then returns data in the following JSON format:

{
identifier: '<name>',
<label: '<label>',>
items: [
{ name: '...', label: '...', someKey: '...' },
...
]
}

Zend_Dojo_Data provides a simple interface for building such structures programmatically,


interacting with them, and serializing them to an array or JSON.

2.1. Zend_Dojo_Data Usage


At its simplest, dojo.data requires that you provide the name of the identifier field in each item,
and a set of items (data). You can either pass these in via the constructor, or via mutators:

514
Zend_Dojo

Exemple 293. Zend_Dojo_Data initialization via constructor

$data = new Zend_Dojo_Data('id', $items);

Exemple 294. Zend_Dojo_Data initialization via mutators

$data = new Zend_Dojo_Data();


$data->setIdentifier('id')
->addItems($items);

You can also add a single item at a time, or append items, using addItem() and addItems().

Exemple 295. Appending data to Zend_Dojo_Data

$data = new Zend_Dojo_Data($identifier, $items);


$data->addItem($someItem);

$data->addItems($someMoreItems);

Always use an identifier!

Every dojo.data datastore requires that the identifier column be provided as


metadata, including Zend_Dojo_Data. In fact, if you attempt to add items
without an identifier, it will raise an exception.

Individual items may be one of the following:

• Associative arrays

• Objects implementing a toArray() method

• Any other objects (will serialize via get_object_vars())

You can attach collections of the above items via addItems() or setItems() (overwrites all
previously set items); when doing so, you may pass a single argument:

• Arrays

• Objects implementing the Traversable interface ,which includes the interfaces Iterator
and ArrayAccess.

If you want to specify a field that will act as a label for the item, call setLabel():

Exemple 296. Specifying a label field in Zend_Dojo_Data

$data->setLabel('name');

Finally, you can also load a Zend_Dojo_Data item from a dojo.data JSON array, using the
fromJson() method.

Exemple 297. Populating Zend_Dojo_Data from JSON

$data->fromJson($json);

515
Zend_Dojo

2.2. Adding metadata to your containers


Some Dojo components require additional metadata along with the dojo.data payload. As an
example, dojox.grid.Grid can pull data dynamically from a dojox.data.QueryReadStore. For
pagination to work correctly, each return payload should contain a numRows key with the total
number of rows that could be returned by the query. With this data, the grid knows when to
continue making small requests to the server for subsets of data and when to stop making more
requests (i.e., it has reached the last page of data). This technique is useful for serving large sets
of data in your grids without loading the entire set at once.

Zend_Dojo_Data allows assigning metadata properties as to the object. The following


illustrates usage:

// Set the "numRows" to 100


$data->setMetadata('numRows', 100);

// Set several items at once:


$data->setMetadata(array(
'numRows' => 100,
'sort' => 'name',
));

// Inspect a single metadata value:


$numRows = $data->getMetadata('numRows');

// Inspect all metadata:


$metadata = $data->getMetadata();

// Remove a metadata item:


$data->clearMetadata('numRows');

// Remove all metadata:


$data->clearMetadata();

2.3. Advanced Use Cases


Besides acting as a serializable data container, Zend_Dojo_Data also provides the ability to
manipulate and traverse the data in a variety of ways.

Zend_Dojo_Data implements the interfaces ArrayAccess, Iterator, and Countable. You


can therefore use the data collection almost as if it were an array.

All items are referenced by the identifier field. Since identifiers must be unique, you can use the
values of this field to pull individual records. There are two ways to do this: with the getItem()
method, or via array notation.

// Using getItem():
$item = $data->getItem('foo');

// Or use array notation:


$item = $data['foo'];

If you know the identifier, you can use it to retrieve an item, update it, delete it, create it, or test
for it:

// Update or create an item:

516
Zend_Dojo

$data['foo'] = array('title' => 'Foo', 'email' => 'foo@foo.com');

// Delete an item:
unset($data['foo']);

// Test for an item:


if (isset($data[foo])) {
}

You can loop over all items as well. Internally, all items are stored as arrays.

foreach ($data as $item) {


echo $item['title'] . ': ' . $item['description'] . "\n";
}

Or even count to see how many items you have:

echo count($data), " items found!";

Finally, as the class implements __toString(), you can also cast it to JSON simply by echoing
it or casting to string:

echo $data; // echo as JSON string

$json = (string) $data; // cast to string == cast to JSON

2.3.1. Available Methods

Besides the methods necessary for implementing the interfaces listed above, the following
methods are available.

• setItems($items): set multiple items at once, overwriting any items that were previously
set in the object. $items should be an array or a Traversable object.

• setItem($item, $id = null): set an individual item, optionally passing an explicit


identifier. Overwrites the item if it is already in the collection. Valid items include associative
arrays, objects implementing toArray(), or any object with public properties.

• addItem($item, $id = null): add an individual item, optionally passing an explicit


identifier. Will raise an exception if the item already exists in the collection. Valid items include
associative arrays, objects implementing toArray(), or any object with public properties.

• addItems($items): add multiple items at once, appending them to any current items. Will
raise an exception if any of the new items have an identifier matching an identifier already in
the collection. $items should be an array or a Traversable object.

• getItems(): retrieve all items as an array of arrays.

• hasItem($id): determine whether an item with the given identifier exists in the collection.

• getItem($id): retrieve an item with the given identifier from the collection; the item returned
will be an associative array. If no item matches, a NULL value is returned.

• removeItem($id): remove an item with the given identifier from the collection.

517
Zend_Dojo

• clearItems(): remove all items from the collection.

• setIdentifier($identifier): set the name of the field that represents the unique
identifier for each item in the collection.

• getIdentifier(): retrieve the name of the identifier field.

• setLabel($label): set the name of a field to be used as a display label for an item.

• getLabel(): retrieve the label field name.

• toArray(): cast the object to an array. At a minimum, the array will contain the keys
'identifier', 'items', and 'label' if a label field has been set in the object.

• toJson(): cast the object to a JSON representation.

3. Les aides de vues Dojo


Zend Framework fournit les aides de vues spécifiques à Dojo suivantes :

• dojo(): paramètre l'environnement Dojo de votre page, incluant les valeurs de configuration
dojo, les chemins de modules personnalisés, les appels de chargement des modules requis,
les feuilles de styles des thêmes, l'utilisation ou non d'un CDN, et d'autres encore.

Exemple 298. Utilisation des aides de vues Dojo

Pour utiliser les aides de vues Dojo, vous devrez informer votre objet de vue de leur
localisation. Vous pouvez faire ceci en appelant addHelperPath() :

$view->addHelperPath('Zend/Dojo/View/Helper/',
'Zend_Dojo_View_Helper');

De manière alternative, vous pouvez utiliser la méthode enableView() de Zend_Dojo


qui le fait pour vous :

Zend_Dojo::enableView($view);

3.1. dojo() View Helper


The dojo() view helper is intended to simplify setting up the Dojo environment, including the
following responsibilities:

• Specifying either a CDN or a local path to a Dojo install.

• Specifying paths to custom Dojo modules.

• Specifying dojo.require statements.

• Specifying dijit stylesheet themes to use.

• Specifying dojo.addOnLoad() events.

The dojo() view helper implementation is an example of a placeholder implementation. The


data set in it persists between view objects and may be directly echoed from your layout script.

518
Zend_Dojo

Exemple 299. dojo() View Helper Usage Example


For this example, let's assume the developer will be using Dojo from a local path, will require
several dijits, and will be utilizing the Tundra dijit theme.
On many pages, the developer may not utilize Dojo at all. So, we will first focus on a view
script where Dojo is needed and then on the layout script, where we will setup some of the
Dojo environment and then render it.
First, we need to tell our view object to use the Dojo view helper paths. This can be done
in your bootstrap or an early-running plugin; simply grab your view object and execute the
following:
$view->addHelperPath('Zend/Dojo/View/Helper/', 'Zend_Dojo_View_Helper');

Next, the view script. In this case, we're going to specify that we will be using a
FilteringSelect -- which will consume a custom store based on QueryReadStore, which we'll
call 'PairedStore' and store in our 'custom' module.
<?php // setup data store for FilteringSelect ?>
<div dojoType="custom.PairedStore" jsId="stateStore"
url="/data/autocomplete/type/state/format/ajax"
requestMethod="get"></div>

<?php // Input element: ?>


State: <input id="state" dojoType="dijit.form.FilteringSelect"
store="stateStore" pageSize="5" />

<?php // setup required dojo elements:


$this->dojo()->enable()
->setDjConfigOption('parseOnLoad', true)
->registerModulePath('custom', '../custom/')
->requireModule('dijit.form.FilteringSelect')
->requireModule('custom.PairedStore'); ?>

In our layout script, we'll then check to see if Dojo is enabled, and, if so, we'll do some more
general configuration and assemble it:
<?php echo $this->doctype() ?>
<html>
<head>
<?php echo $this->headTitle() ?>
<?php echo $this->headMeta() ?>
<?php echo $this->headLink() ?>
<?php echo $this->headStyle() ?>
<?php if ($this->dojo()->isEnabled()){
$this->dojo()->setLocalPath('/js/dojo/dojo.js')
->addStyleSheetModule('dijit.themes.tundra');
echo $this->dojo();
}
?>
<?php echo $this->headScript() ?>
</head>
<body class="tundra">
<?php echo $this->layout()->content ?>
<?php echo $this->inlineScript() ?>
</body>
</html>

At this point, you only need to ensure that your files are in the correct locations and that
you've created the end point action for your FilteringSelect!

519
Zend_Dojo

UTF-8 encoding used by default

By default, Zend Framework uses UTF-8 as its default encoding, and, specific to
this case, Zend_View does as well. Character encoding can be set differently on
the view object itself using the setEncoding() method (or the the encoding
instantiation parameter). However, since Zend_View_Interface does not
define accessors for encoding, it's possible that if you are using a custom view
implementation with the Dojo view helper, you will not have a getEncoding()
method, which is what the view helper uses internally for determining the
character set in which to encode.

If you do not want to utilize UTF-8 in such a situation, you will need to implement
a getEncoding() method in your custom view implementation.

3.1.1. Programmatic and Declarative Usage of Dojo

Dojo allows both declarative and programmatic usage of many of its features. Declarative usage
uses standard HTML elements with non-standard attributes that are parsed when the page is
loaded. While this is a powerful and simple syntax to utilize, for many developers this can cause
issues with page validation.

Programmatic usage allows the developer to decorate existing elements by pulling them by ID
or CSS selectors and passing them to the appropriate object constructors in Dojo. Because no
non-standard HTML attributes are used, pages continue to validate.

In practice, both use cases allow for graceful degradation when javascript is disabled or the
various Dojo script resources are unreachable. To promote standards and document validation,
Zend Framework uses programmatic usage by default; the various view helpers will generate
javascript and push it to the dojo() view helper for inclusion when rendered.

Developers using this technique may also wish to explore the option of writing their own
programmatic decoration of the page. One benefit would be the ability to specify handlers for
dijit events.

To allow this, as well as the ability to use declarative syntax, there are a number of static methods
available to set this behavior globally.

Exemple 300. Specifying Declarative and Programmatic Dojo Usage

To specify declarative usage, simply call the static setUseDeclarative() method:

Zend_Dojo_View_Helper_Dojo::setUseDeclarative();

If you decide instead to use programmatic usage, call the static setUseProgrammatic()
method:

Zend_Dojo_View_Helper_Dojo::setUseProgrammatic();

Finally, if you want to create your own programmatic rules, you should specify programmatic
usage, but pass in the value '-1'; in this situation, no javascript for decorating any dijits used
will be created.

Zend_Dojo_View_Helper_Dojo::setUseProgrammatic(-1);

520
Zend_Dojo

3.1.2. Themes
Dojo allows the creation of themes for its dijits (widgets). You may select one by passing in a
module path:

$view->dojo()->addStylesheetModule('dijit.themes.tundra');

The module path is discovered by using the character '.' as a directory separator and using the
last value in the list as the name of the CSS file in that theme directory to use; in the example
above, Dojo will look for the theme in 'dijit/themes/tundra/tundra.css'.

When using a theme, it is important to remember to pass the theme class to, at the least, a
container surrounding any dijits you are using; the most common use case is to pass it in the
body:

<body class="tundra">

3.1.3. Using Layers (Custom Builds)


By default, when you use a dojo.require statement, dojo will make a request back to the server to
grab the appropriate javascript file. If you have many dijits in place, this results in many requests
to the server -- which is not optimal.

Dojo's answer to this is to provide the ability to create custom builds. Builds do several things:

• Groups required files into layers; a layer lumps all required files into a single JS file. (Hence
the name of this section.)

• "Interns" non-javascript files used by dijits (typically, template files). These are also grouped
in the same JS file as the layer.

• Passes the file through ShrinkSafe, which strips whitespace and comments, as well as
shortens variable names.

Some files can not be layered, but the build process will create a special release directory with
the layer file and all other files. This allows you to have a slimmed-down distribution customized
for your site or application needs.

To use a layer, the dojo() view helper has a addLayer() method for adding paths to required
layers:

$view->dojo()->addLayer('/js/foo/foo.js');

For more information on creating custom builds, please refer to the Dojo build documentation.

3.1.4. Methods Available


The dojo() view helper always returns an instance of the dojo placeholder container. That
container object has the following methods available:

• setView(Zend_View_Interface $view): set a view instance in the container.

• enable(): explicitly enable Dojo integration.

• disable(): disable Dojo integration.

521
Zend_Dojo

• isEnabled(): determine whether or not Dojo integration is enabled.

• requireModule($module): setup a dojo.require statement.

• getModules(): determine what modules have been required.

• registerModulePath($module, $path): register a custom Dojo module path.

• getModulePaths(): get list of registered module paths.

• addLayer($path): add a layer (custom build) path to use.

• getLayers(): get a list of all registered layer paths (custom builds).

• removeLayer($path): remove the layer that matches $path from the list of registered
layers (custom builds).

• setCdnBase($url): set the base URL for a CDN; typically, one of the
Zend_Dojo::CDN_BASE_AOL or Zend_Dojo::CDN_BASE_GOOGLE, but it only needs to be
the URL string prior to the version number.

• getCdnBase(): retrieve the base CDN url to utilize.

• setCdnVersion($version = null): set which version of Dojo to utilize from the CDN.

• getCdnVersion(): retrieve what version of Dojo from the CDN will be used.

• setCdnDojoPath($path): set the relative path to the dojo.js or dojo.xd.js


file on a CDN; typically, one of the Zend_Dojo::CDN_DOJO_PATH_AOL or
Zend_Dojo::CDN_DOJO_PATH_GOOGLE, but it only needs to be the path string following the
version number.

• getCdnDojoPath(): retrieve the last path segment of the CDN url pointing to the dojo.js file.

• useCdn(): tell the container to utilize the CDN; implicitly enables integration.

• setLocalPath($path): tell the container the path to a local Dojo install (should be a path
relative to the server, and contain the dojo.js file itself); implicitly enables integration.

• getLocalPath(): determine what local path to Dojo is being used.

• useLocalPath(): is the integration utilizing a Dojo local path?

• setDjConfig(array $config): set dojo/dijit configuration values (expects assoc array).

• setDjConfigOption($option, $value): set a single dojo/dijit configuration value.

• getDjConfig(): get all dojo/dijit configuration values.

• getDjConfigOption($option, $default = null): get a single dojo/dijit configuration


value.

• addStylesheetModule($module): add a stylesheet based on a module theme.

• getStylesheetModules(): get stylesheets registered as module themes.

522
Zend_Dojo

• addStylesheet($path): add a local stylesheet for use with Dojo.

• getStylesheets(): get local Dojo stylesheets.

• addOnLoad($spec, $function = null): add a lambda for dojo.onLoad to call. If one


argument is passed, it is assumed to be either a function name or a javascript closure. If two
arguments are passed, the first is assumed to be the name of an object instance variable and
the second either a method name in that object or a closure to utilize with that object.

• prependOnLoad($spec, $function = null): exactly like addOnLoad(), excepts


prepends to beginning of onLoad stack.

• getOnLoadActions(): retrieve all dojo.onLoad actions registered with the container. This
will be an array of arrays.

• onLoadCaptureStart($obj = null): capture data to be used as a lambda for


dojo.onLoad(). If $obj is provided, the captured JS code will be considered a closure to use
with that Javascript object.

• onLoadCaptureEnd($obj = null): finish capturing data for use with dojo.onLoad().

• javascriptCaptureStart(): capture arbitrary javascript to be included with Dojo JS


(onLoad, require, etc. statements).

• javascriptCaptureEnd(): finish capturing javascript.

• __toString(): cast the container to a string; renders all HTML style and script elements.

3.2. Dijit-Specific View Helpers


From the Dojo manual: "Dijit is a widget system layered on top of dojo." Dijit includes a variety of
layout and form widgets designed to provide accessibility features, localization, and standardized
(and themeable) look-and-feel.

Zend Framework ships a variety of view helpers that allow you to render and utilize dijits within
your view scripts. There are three basic types:

• Layout Containers: these are designed to be used within your view scripts or consumed by form
decorators for forms, sub forms, and display groups. They wrap the various classes offerred
in dijit.layout. Each dijit layout view helper expects the following arguments:

• $id: the container name or DOM ID.

• $content: the content to wrap in the layout container.

• $params (optional): dijit-specific parameters. Basically, any non-HTML attribute that can be
used to configure the dijit layout container.

• $attribs (optional): any additional HTML attributes that should be used to render the
container div. If the key 'id' is passed in this array, it will be used for the form element DOM
id, and $id will be used for its name.

If you pass no arguments to a dijit layout view helper, the helper itself will be returned. This
allows you to capture content, which is often an easier way to pass content to the layout
container. Examples of this functionality will be shown later in this section.

523
Zend_Dojo

• Form Dijit: the dijit.form.Form dijit, while not completely necessary for use with dijit form
elements, will ensure that if an attempt is made to submit a form that does not validate against
client-side validations, submission will be halted and validation error messages raised. The
form dijit view helper expects the following arguments:

• $id: the container name or DOM ID.

• $attribs (optional): any additional HTML attributes that should be used to render the
container div.

• $content (optional): the content to wrap in the form. If none is passed, an empty string
will be used.

The argument order varies from the other dijits in order to keep compatibility with the standard
form() view helper.

• Form Elements: these are designed to be consumed with Zend_Form, but can be used
standalone within view scripts as well. Each dijit element view helper expects the following
arguments:

• $id: the element name or DOM ID.

• $value (optional): the current value of the element.

• $params (optional): dijit-specific parameters. Basically, any non-HTML attribute that can be
used to configure a dijit.

• $attribs (optional): any additional HTML attributes that should be used to render the dijit.
If the key 'id' is passed in this array, it will be used for the form element DOM id, and $id
will be used for its name.

Some elements require more arguments; these will be noted with the individual element helper
descriptions.

In order to utilize these view helpers, you need to register the path to the dojo view helpers with
your view object.

Exemple 301. Registering the Dojo View Helper Prefix Path

$view->addHelperPath('Zend/Dojo/View/Helper', 'Zend_Dojo_View_Helper');

3.2.1. Dijit Layout Elements

The dijit.layout family of elements are for creating custom, predictable layouts for your site. For
any questions on general usage, read more about them in the Dojo manual.

All dijit layout elements have the signature string ($id = null, $content = '', array $params =
array(), array $attribs = array()). In all caess, if you pass no arguments, the helper object itself
will be returned. This gives you access to the captureStart() and captureEnd() methods,
which allow you to capture content instead of passing it to the layout container.

• AccordionContainer: dijit.layout.AccordionContainer. Stack all panes together vertically;


clicking on a pane titlebar will expand and display that particular pane.

<?php echo $view->accordionContainer(

524
Zend_Dojo

'foo',
$content,
array(
'duration' => 200,
),
array(
'style' => 'width: 200px; height: 300px;',
),
); ?>

• AccordionPane: dijit.layout.AccordionPane. For use within AccordionContainer.

<?php echo $view->accordionPane(


'foo',
$content,
array(
'title' => 'Pane Title',
),
array(
'style' => 'background-color: lightgray;',
),
); ?>

• BorderContainer: dijit.layout.BorderContainer. Achieve layouts with optionally resizable panes


such as you might see in a traditional application.

<?php echo $view->borderContainer(


'foo',
$content,
array(
'design' => 'headline',
),
array(
'style' => 'width: 100%; height: 100%',
),
); ?>

• ContentPane: dijit.layout.ContentPane. Use inside any container except AccordionContainer.

<?php echo $view->contentPane(


'foo',
$content,
array(
'title' => 'Pane Title',
'region' => 'left',
),
array(
'style' => 'width: 120px; background-color: lightgray;',
),
); ?>

• SplitContainer: dijit.layout.SplitContainer. Allows resizable content panes; deprecated in Dojo


in favor of BorderContainer.

<?php echo $view->splitContainer(


'foo',
$content,

525
Zend_Dojo

array(
'orientation' => 'horizontal',
'sizerWidth' => 7,
'activeSizing' => true,
),
array(
'style' => 'width: 400px; height: 500px;',
),
); ?>

• StackContainer: dijit.layout.StackContainer. All panes within a StackContainer are placed in a


stack; build buttons or functionality to reveal one at a time.

<?php echo $view->stackContainer(


'foo',
$content,
array(),
array(
'style' => 'width: 400px; height: 500px; border: 1px;',
),
); ?>

• TabContainer: dijit.layout.TabContainer. All panes within a TabContainer are placed in a stack,


with tabs positioned on one side for switching between them.

<?php echo $view->tabContainer(


'foo',
$content,
array(),
array(
'style' => 'width: 400px; height: 500px; border: 1px;',
),
); ?>

The following capture methods are available for all layout containers:

• captureStart($id, array $params = array(), array $attribs = array()): begin capturing content
to include in a container. $params refers to the dijit params to use with the container, while
$attribs refer to any general HTML attributes to use.

Containers may be nested when capturing, so long as no ids are duplicated.

• captureEnd($id): finish capturing content to include in a container. $id should refer to an


id previously used with a captureStart() call. Returns a string representing the container
and its contents, just as if you'd simply passed content to the helper itself.

526
Zend_Dojo

Exemple 302. BorderContainer layout dijit example

BorderContainers, particularly when coupled with the ability to capture content, are
especially useful for achieving complex layout effects.

$view->borderContainer()->captureStart('masterLayout',
array('design' => 'headline'));

echo $view->contentPane(
'menuPane',
'This is the menu pane',
array('region' => 'top'),
array('style' => 'background-color: darkblue;')
);

echo $view->contentPane(
'navPane',
'This is the navigation pane',
array('region' => 'left'),
array('style' => 'width: 200px; background-color: lightblue;')
);

echo $view->contentPane(
'mainPane',
'This is the main content pane area',
array('region' => 'center'),
array('style' => 'background-color: white;')
);

echo $view->contentPane(
'statusPane',
'Status area',
array('region' => 'bottom'),
array('style' => 'background-color: lightgray;')
);

echo $view->borderContainer()->captureEnd('masterLayout');

3.2.2. Dijit Form Elements

Dojo's form validation and input dijits are in the dijit.form tree. For more information on
general usage of these elements, as well as accepted parameters, please visit the dijit.form
documentation.

The following dijit form elements are available in Zend Framework. Except where noted, all have
the signature string ($id, $value = '', array $params = array(), array $attribs = array()).

• Button: dijit.form.Button. Display a form button.

<?php echo $view->button(


'foo',
'Show Me!',
array('iconClass' => 'myButtons'),
); ?>

• CheckBox: dijit.form.CheckBox. Display a checkbox. Accepts an optional fifth argument, the


array $checkedOptions, which may contain either:

527
Zend_Dojo

• an indexed array with two values, a checked value and unchecked value, in that order; or

• an associative array with the keys 'checkedValue' and 'unCheckedValue'.

If $checkedOptions is not provided, 1 and 0 are assumed.

<?php echo $view->checkBox(


'foo',
'bar',
array(),
array(),
array('checkedValue' => 'foo', 'unCheckedValue' => 'bar')
); ?>

• ComboBox: dijit.layout.ComboBox. ComboBoxes are a hybrid between a select and a text box
with autocompletion. The key difference is that you may type an option that is not in the list
of available options, and it will still consider it valid input. It accepts an optional fifth argument,
an associative array $options; if provided, ComboBox will be rendered as a select. Note
also that the label values of the $options array will be returned in the form -- not the values
themselves.

Alternately, you may pass information regarding a dojo.data datastore to use with the element.
If provided, the ComboBox will be rendered as a text input, and will pull its options via that
datastore.

To specify a datastore, provide one of the following $params key combinations:

• The key 'store', with an array value; the array should contain the keys:

• store: the name of the javascript variable representing the datastore (this could be the
name you would like for it to use).

• type: the datastore type to use; e.g., 'dojo.data.ItemFileReadStore'.

• params (optional): an associative array of key/value pairs to use to configure the datastore.
The 'url' param is a typical example.

• The keys:

• store: a string indicating the datastore name to use.

• storeType: a string indicating the datastore dojo.data type to use (e.g.,


'dojo.data.ItemFileReadStore').

• storeParams: an associative array of key/value pairs with which to configure the datastore.

// As a select element:
echo $view->comboBox(
'foo',
'bar',
array(
'autocomplete' => false,
),
array(),
array(
'foo' => 'Foo',

528
Zend_Dojo

'bar' => 'Bar',


'baz' => 'Baz',
)
);

// As a dojo.data-enabled element:
echo $view->comboBox(
'foo',
'bar',
array(
'autocomplete' => false,
'store' => 'stateStore',
'storeType' => 'dojo.data.ItemFileReadStore',
'storeParams' => array('url' => '/js/states.json'),
),
);

• CurrencyTextBox: dijit.form.CurrencyTextBox. Inherits from ValidationTextBox, and provides


client-side validation of currency. It expects that the dijit parameter 'currency' will be provided
with an appropriate 3-character currency code. You may also specify any dijit parameters valid
for ValidationTextBox and TextBox.

echo $view->currencyTextBox(
'foo',
'$25.00',
array('currency' => 'USD'),
array('maxlength' => 20)
);

Issues with Builds


There are currently known issues with using CurrencyTextBox with build layers.
A known work-around is to ensure that your document's Content-Type http-
equiv meta tag sets the character set to utf-8, which you can do by calling:

$view->headMeta()->appendHttpEquiv('Content-Type',
'text/html; charset=utf-8');

This will mean, of course, that you will need to ensure that the headMeta()
placeholder is echoed in your layout script.

• DateTextBox: dijit.form.DateTextBox. Inherits from ValidationTextBox, and provides both


client-side validation of dates, as well as a dropdown calendar from which to select a date.
You may specify any dijit parameters available to ValidationTextBox or TextBox.

echo $view->dateTextBox(
'foo',
'2008-07-11',
array('required' => true)
);

• Editor: dijit.Editor. Provides a WYSIWYG editor via which users may create or edit content.
dijit.Editor is a pluggable, extensible editor with a variety of parameters you can utilize for
customization; see the dijit.Editor documentation for more details.

echo $view->editor('foo');

529
Zend_Dojo

Editor Dijit uses div by default

The Editor dijit uses an HTML DIV by default. The


dijit._editor.RichText documentation indicates that having it built on
an HTML TEXTAREA can potentially have security implications.

In order to allow graceful degradation in environments where Javascript


is unavailable, Zend_Dojo_View_Helper_Editor also wraps a textarea
within a noscript tag; the content of this textarea will be properly escaped to
avoid security vulnerability vectors.

• FilteringSelect: dijit.form.FilteringSelect. Similar to ComboBox, this is a select/text hybrid


that can either render a provided list of options or those fetched via a dojo.data datastore.
Unlike ComboBox, however, FilteringSelect does not allow typing in an option not in its list.
Additionally, it operates like a standard select in that the option values, not the labels, are
returned when the form is submitted.

Please see the information above on ComboBox for examples and available options for
defining datastores.

• HorizontalSlider and VerticalSlider: dijit.form.HorizontalSlider and dijit.form.VerticalSlider.


Sliders allow are UI widgets for selecting numbers in a given range; these are horizontal and
vertical variants.

At their most basic, they require the dijit parameters 'minimum', 'maximum', and
'discreteValues'. These define the range of values. Other common options are:

• 'intermediateChanges' can be set to indicate whether or not to fire onChange events while
the handle is being dragged.

• 'clickSelect' can be set to allow clicking a location on the slider to set the value.

• 'pageIncrement' can specify the value by which to increase/decrease when pageUp and
pageDown are used.

• 'showButtons' can be set to allow displaying buttons on either end of the slider for
manipulating the value.

The Zend Framework implementation creates a hidden element to store the value of the slider.

You may optionally desire to show a rule or labels for the slider. To do so, you will assign
one or more of the dijit params 'topDecoration' and/or 'bottomDecoration' (HorizontalSlider)
or 'leftDecoration' and/or 'rightDecoration' (VerticalSlider). Each of these expects the following
options:

• container: name of the container.

• labels (optional): an array of labels to utilize. Use empty strings on either end to provide
labels for inner values only. Required when specifying one of the 'Labels' dijit variants.

• dijit (optional): one of HorizontalRule, HorizontalRuleLabels, VerticalRule, or


VerticalRuleLabels, Defaults to one of the Rule dijits.

• params (optional): dijit params for configuring the Rule dijit in use. Parameters specific to
these dijits include:

530
Zend_Dojo

• container (optional): array of parameters and attributes for the rule container.

• labels (optional): array of parameters and attributes for the labels list container.

• attribs (optional): HTML attributes to use with the rules/labels. This should follow the params
option format and be an associative array with the keys 'container' and 'labels'.

echo $view->horizontalSlider(
'foo',
1,
array(
'minimum' => -10,
'maximum' => 10,
'discreteValues' => 11,
'intermediateChanges' => true,
'showButtons' => true,
'topDecoration' => array(
'container' => 'topContainer'
'dijit' => 'HorizontalRuleLabels',
'labels' => array(
' ',
'20%',
'40%',
'60%',
'80%',
' ',
),
'params' => array(
'container' => array(
'style' => 'height:1.2em; font-size=75%;color:gray;',
),
'labels' => array(
'style' => 'height:1em; font-size=75%;color:gray;',
),
),
),
'bottomDecoration' => array(
'container' => 'bottomContainer'
'labels' => array(
'0%',
'50%',
'100%',
),
'params' => array(
'container' => array(
'style' => 'height:1.2em; font-size=75%;color:gray;',
),
'labels' => array(
'style' => 'height:1em; font-size=75%;color:gray;',
),
),
),
)
);

• NumberSpinner: dijit.form.NumberSpinner. Text box for numeric entry, with buttons for
incrementing and decrementing.

531
Zend_Dojo

Expects either an associative array for the dijit parameter 'constraints', or simply the keys 'min',
'max', and 'places' (these would be the expected entries of the constraints parameter as well).
'places' can be used to indicate how much the number spinner will increment and decrement.

echo $view->numberSpinner(
'foo',
5,
array(
'min' => -10,
'max' => 10,
'places' => 2,
),
array(
'maxlenth' => 3,
)
);

• NumberTextBox: dijit.form.NumberTextBox. NumberTextBox provides the ability to format and


display number entries in a localized fashion, as well as validate numerical entries, optionally
against given constraints.

echo $view->numberTextBox(
'foo',
5,
array(
'places' => 4,
'type' => 'percent',
),
array(
'maxlength' => 20,
)
);

• PasswordTextBox: dijit.form.ValidationTextBox tied to a password input. PasswordTextBox


provides the ability to create password input that adheres to the current dijit theme, as well
as allow for client-side validation.

echo $view->passwordTextBox(
'foo',
'',
array(
'required' => true,
),
array(
'maxlength' => 20,
)
);

• RadioButton: dijit.form.RadioButton. A set of options from which only one may be selected.
This behaves in every way like a regular radio, but has a look-and-feel consistent with other
dijits.

RadioButton accepts an optional fifth argument, $options, an associative array of value/label


pairs used as the radio options. You may also pass these as the $attribs key options.

echo $view->radioButton(

532
Zend_Dojo

'foo',
'bar',
array(),
array(),
array(
'foo' => 'Foo',
'bar' => 'Bar',
'baz' => 'Baz',
)
);

• SimpleTextarea: dijit.form.SimpleTextarea. These act like normal textareas, but are styled
using the current dijit theme. You do not need to specify either the rows or columns attributes;
use ems or percentages for the width and height, instead.

echo $view->simpleTextarea(
'foo',
'Start writing here...',
array(),
array('style' => 'width: 90%; height: 5ems;')
);

• SubmitButton: a dijit.form.Button tied to a submit input element. See the Button view helper
for more details; the key difference is that this button can submit a form.

• Textarea: dijit.form.Textarea. These act like normal textareas, except that instead of having
a set number of rows, they expand as the user types. The width should be specified via a
style setting.

echo $view->textarea(
'foo',
'Start writing here...',
array(),
array('style' => 'width: 300px;')
);

• TextBox: dijit.form.TextBox. This element is primarily present to provide a common look-and-


feel between various dijit elements, and to provide base functionality for the other TextBox-
derived classes (ValidationTextBox, NumberTextBox, CurrencyTextBox, DateTextBox, and
TimeTextBox).

Common dijit parameter flags include 'lowercase' (cast to lowercase), 'uppercase' (cast
to UPPERCASE), 'propercase' (cast to Proper Case), and trim (trim leading and trailing
whitespace); all accept boolean values. Additionally, you may specifiy the parameters 'size'
and 'maxLength'.

echo $view->textBox(
'foo',
'some text',
array(
'trim' => true,
'propercase' => true,
'maxLength' => 20,
),
array(
'size' => 20,
)

533
Zend_Dojo

);

• TimeTextBox: dijit.form.TimeTextBox. Also in the TextBox family, TimeTextBox provides a


scrollable drop down selection of times from which a user may select. Dijit parameters allow
you to specify the time increments available in the select as well as the visible range of times
available.

echo $view->timeTextBox(
'foo',
'',
array(
'am.pm' => true,
'visibleIncrement' => 'T00:05:00', // 5-minute increments
'visibleRange' => 'T02:00:00', // show 2 hours of increments
),
array(
'size' => 20,
)
);

• ValidationTextBox: dijit.form.ValidateTextBox. Provide client-side validations for a text


element. Inherits from TextBox.

Common dijit parameters include:

• invalidMessage: a message to display when an invalid entry is detected.

• promptMessage: a tooltip help message to use.

• regExp: a regular expression to use to validate the text. Regular expression does not require
boundary markers.

• required: whether or not the element is required. If so, and the element is embedded in a
dijit.form.Form, it will be flagged as invalid and prevent submission.

echo $view->validationTextBox(
'foo',
'',
array(
'required' => true,
'regExp' => '[\w]+',
'invalidMessage' => 'No spaces or non-word characters allowed',
'promptMessage' => 'Single word consisting of alphanumeric ' .
'characters and underscores only',
),
array(
'maxlength' => 20,
)
);

3.2.3. Custom Dijits

If you delve into Dojo much at all, you'll find yourself writing custom dijits, or using experimental
dijits from Dojox. While Zend Framework cannot support every dijit directly, it does provide some
rudimentary support for arbitrary dijit types via the CustomDijit view helper.

534
Zend_Dojo

The CustomDijit view helper's API is exactly that of any other dijit, with one major difference:
the third "params" argument must contain the attribute "dojotype". The value of this attribute
should be the Dijit class you plan to use.

CustomDijit extends the base DijitContainer view helper, which also allows it to capture
content (using the captureStart()/captureEnd() pair of methods). captureStart() also
expects that you pass the "dojoType" attribute to its "params" argument.

535
Zend_Dojo

Exemple 303. Using CustomDijit to render a dojox.layout.ContentPane

dojox.layout.ContentPane is a next-generation iteration of dijit.layout.ContentPane, and


provides a superset of that class's capabilities. Until it's functionality stabilizes, it will continue
to live in Dojox. However, if you want to use it in Zend Framework today, you can, using
the CustomDijit view helper.

At its most basic, you can do the following:

<?php echo $this->customDijit(


'foo',
$content,
array(
'dojoType' => 'dojox.layout.ContentPane',
'title' => 'Custom pane',
'region' => 'center'
)
); ?>

If you wanted to capture content instead, simply use the captureStart() method, and
pass the "dojoType" to the "params" argument:

<?php $this->customDijit()->captureStart(
'foo',
array(
'dojoType' => 'dojox.layout.ContentPane',
'title' => 'Custom pane',
'region' => 'center'
)
); ?>
This is the content of the pane
<?php echo $this->customDijit()->captureEnd('foo'); ?>

You can also extend CustomDijit easily to create support for your own custom dijits. As an
example, if you extended dijit.layout.ContentPane to create your own foo.ContentPane
class, you could create the following helper to support it:

class My_View_Helper_FooContentPane
extends Zend_Dojo_View_Helper_CustomDijit
{
protected $_defaultDojoType = 'foo.ContentPane';

public function fooContentPane(


$id = null, $value = null,
array $params = array(), array $attribs = array()
) {
return $this->customDijit($id, $value, $params, $attribs);
}
}

As long as your custom dijit follows the same basic API as official dijits, using or extending
CustomDijit should work correctly.

4. Les éléments de formulaire et les décorateurs Dojo


Bâtie sur les aides de vues dijit, la famille des classes Zend_Dojo_Form fournit la possibilité
d'utiliser les Dijits nativement dans vos formulaires.

536
Zend_Dojo

Il existe trois options pour utiliser les éléments de formulaires Dojo avec vos formulaires :

• Utilisez Zend_Dojo::enableForm(). Ceci ajoutera, de manière récursive, les chemins de


plugin des éléments et des décorateurs pour tous les éléments de formulaires attachés. De
plus, ceci active dojo dans l'objet de vue. Notez, cependant, que tout sous-formulaire que vous
attacherez après cet appel devront eux aussi faire leur appel à Zend_Dojo::enableForm().

• Utilisez les implémentations de formulaires et sous-formulaires spécifiques à Dojo,


respectivement Zend_Dojo_Form et Zend_Dojo_Form_SubForm. Ceux-ci peuvent être
utilisés en lieu et place de Zend_Form et Zend_Form_SubForm, ils contiennent tous les
chemins appropriés des éléments et décorateurs, ils paramètrent une classe par défaut pour
les DisplayGroup spécifique à Dojo et activent dojo dans l'objet de vue.

• En dernier, et le plus pénible, vous pouvez régler vous même les chemins appropriés vers
les décorateurs et les éléments, régler la classe de DisplayGroup par défaut, et activer dojo
dans l'objet de vue. Puisque Zend_Dojo::enableForm() fait déjà ceci, il n'y a que peu de
raisons d'utiliser cette voie.

Exemple 304. Activation de Dojo dans vos formulaires existants

"Mais attendez," vous allez me dire ; "j'étends déjà Zend_Form avec ma propre classe de
formulaire personnalisé ! Comment puis-je activer Dojo ?'"

Premièrement, et sans doute le plus simple, étendez Zend_Dojo_Form au lieu de


Zend_Form, et mettez à jour tous les endroits où vous intanciez Zend_Form_SubForm en
le remplaçant par Zend_Dojo_Form_SubForm.

Une seconde approche consiste en un appel à Zend_Dojo::enableForm() dans la


méthode init() de vos formulaires ; quand la définition du formulaire est complète,
bouclez à travers tous les sous-formulaires pour y activer dojo pour chacun :

class My_Form_Custom extends Zend_Form


{
public function init()
{
// Activer Dojo pour le formulaire :
Zend_Dojo::enableForm($this);

// ... continuez la définition du formulaire ici

// Activer Dojo pour tous les formulaires :


foreach ($this->getSubForms() as $subForm) {
Zend_Dojo::enableForm($subForm);
}
}
}

L'utilisation des éléments de formulaires et les décorateurs spécifiques à Dijit est identique à
l'utilisation de tous autres éléments de formulaires ou décorateurs.

4.1. Dijit-Specific Form Decorators


Most form elements can use the DijitElement decorator, which will grab the dijit parameters from
the elements, and pass these and other metadata to the view helper specified by the element.
For decorating forms, sub forms, and display groups, however, there are a set of decorators
corresponding to the various layout dijits.

537
Zend_Dojo

All dijit decorators look for the dijitParams property of the given element being decorated, and
push them as the $params array to the dijit view helper being used; these are then separated
from any other properties so that no duplication of information occurs.

4.1.1. DijitElement Decorator


Just like the ViewHelper decorator, DijitElement expects a helper property in the element which
it will then use as the view helper when rendering. Dijit parameters will typically be pulled directly
from the element, but may also be passed in as options via the dijitParams key (the value of that
key should be an associative array of options).

It is important that each element have a unique ID (as fetched from the element's getId()
method). If duplicates are detected within the dojo() view helper, the decorator will trigger a
notice, but then create a unique ID by appending the return of uniqid() to the identifier.

Standard usage is to simply associate this decorator as the first in your decorator chain, with
no additional options.

Exemple 305. DijitElement Decorator Usage

$element->setDecorators(array(
'DijitElement',
'Errors',
'Label',
'ContentPane',
));

4.1.2. DijitForm Decorator


The DijitForm decorator is very similar to the Form decorator; in fact, it can be used basically
interchangeably with it, as it utilizes the same view helper name ('form').

Since dijit.form.Form does not require any dijit parameters for configuration, the main difference
is that the dijit form view helper require that a DOM ID is passed to ensure that programmatic
dijit creation can work. The decorator ensures this, by passing the form name as the identifier.

4.1.3. DijitContainer-based Decorators


The DijitContainer decorator is actually an abstract class from which a variety of other
decorators derive. It offers the same functionality of DijitElement, with the addition of title support.
Many layout dijits require or can utilize a title; DijitContainer will utilize the element's legend
property, if available, and can also utilize either the 'legend' or 'title' decorator option, if passed.
The title will be translated if a translation adapter with a corresponding translation is present.

The following is a list of decorators that inherit from DijitContainer:

• AccordionContainer

• AccordionPane

• BorderContainer

• ContentPane

• SplitContainer

538
Zend_Dojo

• StackContainer

• TabContainer

Exemple 306. DijitContainer Decorator Usage

// Use a TabContainer for your form:


$form->setDecorators(array(
'FormElements',
array('TabContainer', array(
'id' => 'tabContainer',
'style' => 'width: 600px; height: 500px;',
'dijitParams' => array(
'tabPosition' => 'top'
),
)),
'DijitForm',
));

// Use a ContentPane in your sub form (which can be used with all but
// AccordionContainer):
$subForm->setDecorators(array(
'FormElements',
array('HtmlTag', array('tag' => 'dl')),
'ContentPane',
));

4.2. Dijit-Specific Form Elements


Each form dijit for which a view helper is provided has a corresponding Zend_Form element. All
of them have the following methods available for manipulating dijit parameters:

• setDijitParam($key, $value): set a single dijit parameter. If the dijit parameter already
exists, it will be overwritten.

• setDijitParams(array $params): set several dijit parameters at once. Any passed


parameters matching those already present will overwrite.

• hasDijitParam($key): If a given dijit parameter is defined and present, return TRUE,


otherwise return FALSE.

• getDijitParam($key): retrieve the given dijit parameter. If not available, a NULL value is
returned.

• getDijitParams(): retrieve all dijit parameters.

• removeDijitParam($key): remove the given dijit parameter.

• clearDijitParams(): clear all currently defined dijit parameters.

Dijit parameters are stored in the dijitParams public property. Thus, you can dijit-enable an
existing form element simply by setting this property on the element; you simply will not have the
above accessors to facilitate manipulating the parameters.

Additionally, dijit-specific elements implement a different list of decorators, corresponding to the


following:

539
Zend_Dojo

$element->addDecorator('DijitElement')
->addDecorator('Errors')
->addDecorator('HtmlTag', array('tag' => 'dd'))
->addDecorator('Label', array('tag' => 'dt'));

In effect, the DijitElement decorator is used in place of the standard ViewHelper decorator.

Finally, the base Dijit element ensures that the Dojo view helper path is set on the view.

A variant on DijitElement, DijitMulti, provides the functionality of the Multi abstract form element,
allowing the developer to specify 'multiOptions' -- typically select options or radio options.

The following dijit elements are shipped in the standard Zend Framework distribution.

4.2.1. Button
While not deriving from the standard Button element, it does implement the same functionality,
and can be used as a drop-in replacement for it. The following functionality is exposed:

• getLabel() will utilize the element name as the button label if no name is provided.
Additionally, it will translate the name if a translation adapter with a matching translation
message is available.

• isChecked() determines if the value submitted matches the label; if so, it returns TRUE. This
is useful for determining which button was used when a form was submitted.

Additionally, only the decorators DijitElement and DtDdWrapper are utilized for Button
elements.

Exemple 307. Example Button dijit element usage

$form->addElement(
'Button',
'foo',
array(
'label' => 'Button Label',
)
);

4.2.2. CheckBox
While not deriving from the standard Checkbox element, it does implement the same
functionality. This means that the following methods are exposed:

• setCheckedValue($value): set the value to use when the element is checked.

• getCheckedValue(): get the value of the item to use when checked.

• setUncheckedValue($value): set the value of the item to use when it is unchecked.

• getUncheckedValue(): get the value of the item to use when it is unchecked.

• setChecked($flag): mark the element as checked or unchecked.

• isChecked(): determine if the element is currently checked.

540
Zend_Dojo

Exemple 308. Example CheckBox dijit element usage

$form->addElement(
'CheckBox',
'foo',
array(
'label' => 'A check box',
'checkedValue' => 'foo',
'uncheckedValue' => 'bar',
'checked' => true,
)
);

4.2.3. ComboBox and FilteringSelect

As noted in the ComboBox dijit view helper documentation, ComboBoxes are a hybrid between
select and text input, allowing for autocompletion and the ability to specify an alternate to the
options provided. FilteringSelects are the same, but do not allow arbitrary input.

ComboBoxes return the label values

ComboBoxes return the label values, and not the option values, which can lead to
a disconnect in expectations. For this reason, ComboBoxes do not auto-register
an InArray validator (though FilteringSelects do).

The ComboBox and FilteringSelect form elements provide accessors and mutators for examining
and setting the select options as well as specifying a dojo.data datastore (if used). They extend
from DijitMulti, which allows you to specify select options via the setMultiOptions() and
setMultiOption() methods. In addition, the following methods are available:

• getStoreInfo(): get all datastore information currently set. Returns an empty array if no
data is currently set.

• setStoreId($identifier): set the store identifier variable (usually referred to by the


attribute 'jsId' in Dojo). This should be a valid javascript variable name.

• getStoreId(): retrieve the store identifier variable name.

• setStoreType($dojoType): set the datastore class to use; e.g.,


"dojo.data.ItemFileReadStore".

• getStoreType(): get the dojo datastore class to use.

• setStoreParams(array $params): set any parameters used to configure the datastore


object. As an example, dojo.data.ItemFileReadStore datastore would expect a 'url' parameter
pointing to a location that would return the dojo.data object.

• getStoreParams(): get any datastore parameters currently set; if none, an empty array is
returned.

• setAutocomplete($flag): indicate whether or not the selected item will be used when the
user leaves the element.

• getAutocomplete(): get the value of the autocomplete flag.

541
Zend_Dojo

By default, if no dojo.data store is registered with the element, this element registers an InArray
validator which validates against the array keys of registered options. You can disable this
behavior by either calling setRegisterInArrayValidator(false), or by passing a FALSE
value to the registerInArrayValidator configuration key.

Exemple 309. ComboBox dijit element usage as select input

$form->addElement(
'ComboBox',
'foo',
array(
'label' => 'ComboBox (select)',
'value' => 'blue',
'autocomplete' => false,
'multiOptions' => array(
'red' => 'Rouge',
'blue' => 'Bleu',
'white' => 'Blanc',
'orange' => 'Orange',
'black' => 'Noir',
'green' => 'Vert',
),
)
);

Exemple 310. ComboBox dijit element usage with datastore

$form->addElement(
'ComboBox',
'foo',
array(
'label' => 'ComboBox (datastore)',
'storeId' => 'stateStore',
'storeType' => 'dojo.data.ItemFileReadStore',
'storeParams' => array(
'url' => '/js/states.txt',
),
'dijitParams' => array(
'searchAttr' => 'name',
),
)
);

The above examples could also utilize FilteringSelect instead of ComboBox.

4.2.4. CurrencyTextBox
The CurrencyTextBox is primarily for supporting currency input. The currency may be localized,
and can support both fractional and non-fractional values.

Internally, CurrencyTextBox derives from NumberTextBox, ValidationTextBox, and TextBox; all


methods available to those classes are available. In addition, the following constraint methods
can be used:

• setCurrency($currency): set the currency type to use; should follow the ISO-4217
specification.

• getCurrency(): retrieve the current currency type.

542
Zend_Dojo

• setSymbol($symbol): set the 3-letter ISO-4217 currency symbol to use.

• getSymbol(): get the current currency symbol.

• setFractional($flag): set whether or not the currency should allow for fractional values.

• getFractional(): retrieve the status of the fractional flag.

Exemple 311. Example CurrencyTextBox dijit element usage

$form->addElement(
'CurrencyTextBox',
'foo',
array(
'label' => 'Currency:',
'required' => true,
'currency' => 'USD',
'invalidMessage' => 'Invalid amount. ' .
'Include dollar sign, commas, and cents.',
'fractional' => false,
)
);

4.2.5. DateTextBox

DateTextBox provides a calendar drop-down for selecting a date, as well as client-side date
validation and formatting.

Internally, DateTextBox derives from ValidationTextBox and TextBox; all methods available to
those classes are available. In addition, the following methods can be used to set individual
constraints:

• setAmPm($flag) and getAmPm(): Whether or not to use AM/PM strings in times.

• setStrict($flag) and getStrict(): whether or not to use strict regular expression


matching when validating input. If FALSE, which is the default, it will be lenient about
whitespace and some abbreviations.

• setLocale($locale) and getLocale(): Set and retrieve the locale to use with this
specific element.

• setDatePattern($pattern) and getDatePattern(): provide and retrieve the unicode


date format pattern for formatting the date.

• setFormatLength($formatLength) and getFormatLength(): provide and retrieve the


format length type to use; should be one of "long", "short", "medium" or "full".

• setSelector($selector) and getSelector(): provide and retrieve the style of selector;


should be either "date" or "time".

543
Zend_Dojo

Exemple 312. Example DateTextBox dijit element usage

$form->addElement(
'DateTextBox',
'foo',
array(
'label' => 'Date:',
'required' => true,
'invalidMessage' => 'Invalid date specified.',
'formatLength' => 'long',
)
);

4.2.6. Editor
Editor provides a WYSIWYG editor that can be used to both create and edit rich HTML content.
dijit.Editor is pluggable and may be extended with custom plugins if desired; see the dijit.Editor
documentation for more details.

The Editor form element provides a number of accessors and mutators for manipulating various
dijit parameters, as follows:

• captureEvents are events that connect to the editing area itself. The following accessors and
mutators are available for manipulating capture events:

• addCaptureEvent($event)

• addCaptureEvents(array $events)

• setCaptureEvents(array $events)

• getCaptureEvents()

• hasCaptureEvent($event)

• removeCaptureEvent($event)

• clearCaptureEvents()

• events are standard DOM events, such as onClick, onKeyUp, etc. The following accessors
and mutators are available for manipulating events:

• addEvent($event)

• addEvents(array $events)

• setEvents(array $events)

• getEvents()

• hasEvent($event)

• removeEvent($event)

• clearEvents()

• plugins add functionality to the Editor -- additional tools for the toolbar, additional styles to
allow, etc. The following accessors and mutators are available for manipulating plugins:

544
Zend_Dojo

• addPlugin($plugin)

• addPlugins(array $plugins)

• setPlugins(array $plugins)

• getPlugins()

• hasPlugin($plugin)

• removePlugin($plugin)

• clearPlugins()

• editActionInterval is used to group events for undo operations. By default, this value is 3
seconds. The method setEditActionInterval($interval) may be used to set the
value, while getEditActionInterval() will retrieve it.

• focusOnLoad is used to determine whether this particular editor will receive focus when the
page has loaded. By default, this is FALSE. The method setFocusOnLoad($flag) may be
used to set the value, while getFocusOnLoad() will retrieve it.

• height specifies the height of the editor; by default, this is 300px. The method
setHeight($height) may be used to set the value, while getHeight() will retrieve it.

• inheritWidth is used to determine whether the editor will use the parent container's width
or simply default to 100% width. By default, this is FALSE (i.e., it will fill the width of the
window). The method setInheritWidth($flag) may be used to set the value, while
getInheritWidth() will retrieve it.

• minHeight indicates the minimum height of the editor; by default, this is 1em. The method
setMinHeight($height) may be used to set the value, while getMinHeight() will
retrieve it.

• styleSheets indicate what additional CSS stylesheets should be used to affect the display of the
Editor. By default, none are registered, and it inherits the page styles. The following accessors
and mutators are available for manipulating editor stylesheets:

• addStyleSheet($styleSheet)

• addStyleSheets(array $styleSheets)

• setStyleSheets(array $styleSheets)

• getStyleSheets()

• hasStyleSheet($styleSheet)

• removeStyleSheet($styleSheet)

• clearStyleSheets()

545
Zend_Dojo

Exemple 313. Example Editor dijit element usage

$form->addElement('editor', 'content', array(


'plugins' => array('undo', '|', 'bold', 'italic'),
'editActionInterval' => 2,
'focusOnLoad' => true,
'height' => '250px',
'inheritWidth' => true,
'styleSheets' => array('/js/custom/editor.css'),
));

Editor Dijit uses div by default

The Editor dijit uses an HTML DIV by default. The dijit._editor.RichText


documentation indicates that having it built on an HTML TEXTAREA can
potentially have security implications.

That said, there may be times when you want an Editor widget that can gracefully
degrade to a TEXTAREA. In such situations, you can do so by setting the
degrade property to TRUE:

// At instantiation:
$editor = new Zend_Dojo_Form_Element_Editor('foo', array(
'degrade' => true,
));

// Construction via the form:


$form->addElement('editor', 'content', array(
'degrade' => true,
));

// Or after instantiation:
$editor->degrade = true;

4.2.7. HorizontalSlider
HorizontalSlider provides a slider UI widget for selecting a numeric value in a range. Internally,
it sets the value of a hidden element which is submitted by the form.

HorizontalSlider derives from the abstract Slider dijit element. Additionally, it has a variety of
methods for setting and configuring slider rules and rule labels.

• setTopDecorationDijit($dijit) and setBottomDecorationDijit($dijit): set


the name of the dijit to use for either the top or bottom of the slider. This should not
include the "dijit.form." prefix, but rather only the final name -- one of "HorizontalRule" or
"HorizontalRuleLabels".

• setTopDecorationContainer($container) and
setBottomDecorationContainer($container): specify the name to use for the
container element of the rules; e.g. 'topRule', 'topContainer', etc.

• setTopDecorationLabels(array $labels) and


setBottomDecorationLabels(array $labels): set the labels to use for one of the
RuleLabels dijit types. These should be an indexed array; specify a single empty space to skip
a given label position (such as the beginning or end).

546
Zend_Dojo

• setTopDecorationParams(array $params) and


setBottomDecorationParams(array $params): dijit parameters to use when
configuring the given Rule or RuleLabels dijit.

• setTopDecorationAttribs(array $attribs) and


setBottomDecorationAttribs(array $attribs): HTML attributes to specify for the
given Rule or RuleLabels HTML element container.

• getTopDecoration() and getBottomDecoration(): retrieve all metadata for a given


Rule or RuleLabels definition, as provided by the above mutators.

547
Zend_Dojo

Exemple 314. Example HorizontalSlider dijit element usage

The following will create a horizontal slider selection with integer values ranging from -10 to
10. The top will have labels at the 20%, 40%, 60%, and 80% marks. The bottom will have
rules at 0, 50%, and 100%. Each time the value is changed, the hidden element storing the
value will be updated.

$form->addElement(
'HorizontalSlider',
'horizontal',
array(
'label' => 'HorizontalSlider',
'value' => 5,
'minimum' => -10,
'maximum' => 10,
'discreteValues' => 11,
'intermediateChanges' => true,
'showButtons' => true,
'topDecorationDijit' => 'HorizontalRuleLabels',
'topDecorationContainer' => 'topContainer',
'topDecorationLabels' => array(
' ',
'20%',
'40%',
'60%',
'80%',
' ',
),
'topDecorationParams' => array(
'container' => array(
'style' => 'height:1.2em; font-size=75%;color:gray;',
),
'list' => array(
'style' => 'height:1em; font-size=75%;color:gray;',
),
),
'bottomDecorationDijit' => 'HorizontalRule',
'bottomDecorationContainer' => 'bottomContainer',
'bottomDecorationLabels' => array(
'0%',
'50%',
'100%',
),
'bottomDecorationParams' => array(
'list' => array(
'style' => 'height:1em; font-size=75%;color:gray;',
),
),
)
);

4.2.8. NumberSpinner

A number spinner is a text element for entering numeric values; it also includes elements for
incrementing and decrementing the value by a set amount.

The following methods are available:

548
Zend_Dojo

• setDefaultTimeout($timeout) and getDefaultTimeout(): set and retrieve the


default timeout, in milliseconds, between when the button is held pressed and the value is
changed.

• setTimeoutChangeRate($rate) and getTimeoutChangeRate(): set and retrieve the


rate, in milliseconds, at which changes will be made when a button is held pressed.

• setLargeDelta($delta) and getLargeDelta(): set and retrieve the amount by which


the numeric value should change when a button is held pressed.

• setSmallDelta($delta) and getSmallDelta(): set and retrieve the delta by which the
number should change when a button is pressed once.

• setIntermediateChanges($flag) and getIntermediateChanges(): set and


retrieve the flag indicating whether or not each value change should be shown when a button
is held pressed.

• setRangeMessage($message) and getRangeMessage(): set and retrieve the message


indicating the range of values available.

• setMin($value) and getMin(): set and retrieve the minimum value possible.

• setMax($value) and getMax(): set and retrieve the maximum value possible.

Exemple 315. Example NumberSpinner dijit element usage

$form->addElement(
'NumberSpinner',
'foo',
array(
'value' => '7',
'label' => 'NumberSpinner',
'smallDelta' => 5,
'largeDelta' => 25,
'defaultTimeout' => 500,
'timeoutChangeRate' => 100,
'min' => 9,
'max' => 1550,
'places' => 0,
'maxlength' => 20,
)
);

4.2.9. NumberTextBox
A number text box is a text element for entering numeric values; unlike NumberSpinner, numbers
are entered manually. Validations and constraints can be provided to ensure the number stays
in a particular range or format.

Internally, NumberTextBox derives from ValidationTextBox and TextBox; all methods available
to those classes are available. In addition, the following methods can be used to set individual
constraints:

• setLocale($locale) and getLocale(): specify and retrieve a specific or alternate locale


to use with this dijit.

• setPattern($pattern) and getPattern(): set and retrieve a number pattern format to


use to format the number.

549
Zend_Dojo

• setType($type) and getType(): set and retrieve the numeric format type to use (should
be one of 'decimal', 'percent', or 'currency').

• setPlaces($places) and getPlaces(): set and retrieve the number of decimal places
to support.

• setStrict($flag) and getStrict(): set and retrieve the value of the strict flag, which
indicates how much leniency is allowed in relation to whitespace and non-numeric characters.

Exemple 316. Example NumberTextBox dijit element usage

$form->addElement(
'NumberTextBox',
'elevation',
array(
'label' => 'NumberTextBox',
'required' => true,
'invalidMessage' => 'Invalid elevation.',
'places' => 0,
'constraints' => array(
'min' => -20000,
'max' => 20000,
),
)
);

4.2.10. PasswordTextBox
PasswordTextBox is simply a ValidationTextBox that is tied to a password input; its sole purpose
is to allow for a dijit-themed text entry for passwords that also provides client-side validation.

Internally, PasswordTextBox derives from ValidationTextBox and TextBox; all methods available
to those classes are available.

Exemple 317. Example PasswordTextBox dijit element usage

$form->addElement(
'PasswordTextBox',
'password',
array(
'label' => 'Password',
'required' => true,
'trim' => true,
'lowercase' => true,
'regExp' => '^[a-z0-9]{6,}$',
'invalidMessage' => 'Invalid password; ' .
'must be at least 6 alphanumeric characters',
)
);

4.2.11. RadioButton
RadioButton wraps standard radio input elements to provide a consistent look and feel with other
dojo dijits.

RadioButton extends from DijitMulti, which allows you to specify select options via the
setMultiOptions() and setMultiOption() methods.

550
Zend_Dojo

By default, this element registers an InArray validator which validates against the
array keys of registered options. You can disable this behavior by either calling
setRegisterInArrayValidator(false), or by passing a FALSE value to the
registerInArrayValidator configuration key.

Exemple 318. Example RadioButton dijit element usage

$form->addElement(
'RadioButton',
'foo',
array(
'label' => 'RadioButton',
'multiOptions' => array(
'foo' => 'Foo',
'bar' => 'Bar',
'baz' => 'Baz',
),
'value' => 'bar',
)
);

4.2.12. SimpleTextarea
SimpleTextarea acts primarily like a standard HTML textarea. However, it does not support either
the rows or cols settings. Instead, the textarea width should be specified using standard CSS
measurements. Unlike Textarea, it will not grow automatically

Exemple 319. Example SimpleTextarea dijit element usage

$form->addElement(
'SimpleTextarea',
'simpletextarea',
array(
'label' => 'SimpleTextarea',
'required' => true,
'style' => 'width: 80em; height: 25em;',
)
);

4.2.13. Slider abstract element


Slider is an abstract element from which HorizontalSlider and VerticalSlider both derive. It
exposes a number of common methods for configuring your sliders, including:

• setClickSelect($flag) and getClickSelect(): set and retrieve the flag indicating


whether or not clicking the slider changes the value.

• setIntermediateChanges($flag) and getIntermediateChanges(): set and


retrieve the flag indicating whether or not the dijit will send a notification on each slider change
event.

• setShowButtons($flag) and getShowButtons(): set and retrieve the flag indicating


whether or not buttons on either end will be displayed; if so, the user can click on these to
change the value of the slider.

• setDiscreteValues($value) and getDiscreteValues(): set and retrieve the number


of discrete values represented by the slider.

• setMaximum($value) and getMaximum(): set the maximum value of the slider.

551
Zend_Dojo

• setMinimum($value) and getMinimum(): set the minimum value of the slider.

• setPageIncrement($value) and getPageIncrement(): set the amount by which the


slider will change on keyboard events.

Example usage is provided with each concrete extending class.

4.2.14. SubmitButton
While there is no Dijit named SubmitButton, we include one here to provide a button dijit capable
of submitting a form without requiring any additional javascript bindings. It works exactly like the
Button dijit.

Exemple 320. Example SubmitButton dijit element usage

$form->addElement(
'SubmitButton',
'foo',
array(
'required' => false,
'ignore' => true,
'label' => 'Submit Button!',
)
);

4.2.15. TextBox
TextBox is included primarily to provide a text input with consistent look-and-feel to the other
dijits. However, it also includes some minor filtering and validation capabilities, represented in
the following methods:

• setLowercase($flag) and getLowercase(): set and retrieve the flag indicating whether
or not input should be cast to lowercase.

• setPropercase($flag) and getPropercase(): set and retrieve the flag indicating


whether or not the input should be cast to Proper Case.

• setUppercase($flag) and getUppercase(): set and retrieve the flag indicating whether
or not the input should be cast to UPPERCASE.

• setTrim($flag) and getTrim(): set and retrieve the flag indicating whether or not leading
or trailing whitespace should be stripped.

• setMaxLength($length) and getMaxLength(): set and retrieve the maximum length of


input.

Exemple 321. Example TextBox dijit element usage

$form->addElement(
'TextBox',
'foo',
array(
'value' => 'some text',
'label' => 'TextBox',
'trim' => true,
'propercase' => true,
)
);

552
Zend_Dojo

4.2.16. Textarea
Textarea acts primarily like a standard HTML textarea. However, it does not support either
the rows or cols settings. Instead, the textarea width should be specified using standard CSS
measurements; rows should be omitted entirely. The textarea will then grow vertically as text
is added to it.

Exemple 322. Example Textarea dijit element usage

$form->addElement(
'Textarea',
'textarea',
array(
'label' => 'Textarea',
'required' => true,
'style' => 'width: 200px;',
)
);

4.2.17. TimeTextBox
TimeTextBox is a text input that provides a drop-down for selecting a time. The drop-down may
be configured to show a certain window of time, with specified increments.

Internally, TimeTextBox derives from DateTextBox, ValidationTextBox and TextBox; all methods
available to those classes are available. In addition, the following methods can be used to set
individual constraints:

• setTimePattern($pattern) and getTimePattern(): set and retrieve the unicode time


format pattern for formatting the time.

• setClickableIncrement($format) and getClickableIncrement(): set the


ISO-8601 string representing the amount by which every clickable element in the time picker
increases.

• setVisibleIncrement($format) and getVisibleIncrement(): set the increment


visible in the time chooser; must follow ISO-8601 formats.

• setVisibleRange($format) and getVisibleRange(): set and retrieve the range of


time visible in the time chooser at any given moment; must follow ISO-8601 formats.

Exemple 323. Example TimeTextBox dijit element usage

The following will create a TimeTextBox that displays 2 hours at a time, with increments of
10 minutes.

$form->addElement(
'TimeTextBox',
'foo',
array(
'label' => 'TimeTextBox',
'required' => true,
'visibleRange' => 'T04:00:00',
'visibleIncrement' => 'T00:10:00',
'clickableIncrement' => 'T00:10:00',
)
);

553
Zend_Dojo

4.2.18. ValidationTextBox

ValidationTextBox provides the ability to add validations and constraints to a text input. Internally,
it derives from TextBox, and adds the following accessors and mutators for manipulating dijit
parameters:

• setInvalidMessage($message) and getInvalidMessage(): set and retrieve the


tooltip message to display when the value does not validate.

• setPromptMessage($message) and getPromptMessage(): set and retrieve the tooltip


message to display for element usage.

• setRegExp($regexp) and getRegExp(): set and retrieve the regular expression to use
for validating the element. The regular expression does not need boundaries (unlike PHP's
preg* family of functions).

• setConstraint($key, $value) and getConstraint($key): set and retrieve


additional constraints to use when validating the element; used primarily with subclasses.
Constraints are stored in the 'constraints' key of the dijit parameters.

• setConstraints(array $constraints) and getConstraints(): set and retrieve


individual constraints to use when validating the element; used primarily with subclasses.

• hasConstraint($key): test whether a given constraint exists.

• removeConstraint($key) and clearConstraints(): remove an individual or all


constraints for the element.

Exemple 324. Example ValidationTextBox dijit element usage

The following will create a ValidationTextBox that requires a single string consisting solely
of word characters (i.e., no spaces, most punctuation is invalid).

$form->addElement(
'ValidationTextBox',
'foo',
array(
'label' => 'ValidationTextBox',
'required' => true,
'regExp' => '[\w]+',
'invalidMessage' => 'Invalid non-space text.',
)
);

4.2.19. VerticalSlider

VerticalSlider is the sibling of HorizontalSlider, and operates in every way like that element. The
only real difference is that the 'top*' and 'bottom*' methods are replaced by 'left*' and 'right*', and
instead of using HorizontalRule and HorizontalRuleLabels, VerticalRule and VerticalRuleLabels
should be used.

554
Zend_Dojo

Exemple 325. Example VerticalSlider dijit element usage

The following will create a vertical slider selection with integer values ranging from -10 to
10. The left will have labels at the 20%, 40%, 60%, and 80% marks. The right will have rules
at 0, 50%, and 100%. Each time the value is changed, the hidden element storing the value
will be updated.

$form->addElement(
'VerticalSlider',
'foo',
array(
'label' => 'VerticalSlider',
'value' => 5,
'style' => 'height: 200px; width: 3em;',
'minimum' => -10,
'maximum' => 10,
'discreteValues' => 11,
'intermediateChanges' => true,
'showButtons' => true,
'leftDecorationDijit' => 'VerticalRuleLabels',
'leftDecorationContainer' => 'leftContainer',
'leftDecorationLabels' => array(
' ',
'20%',
'40%',
'60%',
'80%',
' ',
),
'rightDecorationDijit' => 'VerticalRule',
'rightDecorationContainer' => 'rightContainer',
'rightDecorationLabels' => array(
'0%',
'50%',
'100%',
),
)
);

555
'80%',
' ',
),
'topDecorationParams' => array(
Zend_Dojo => array(
'container'
'style' => 'height:1.2em; ' .
'font-size=75%;color:gray;',
),
4.3. Dojo Form Examples 'list' => array(
'style' => 'height:1em; ' .
'font-size=75%;color:gray;',
),
),
'bottomDecorationDijit' => 'HorizontalRule',
'bottomDecorationContainer' => 'bottomContainer',
'bottomDecorationLabels' => array(
'0%',
'50%',
'100%',
),
'bottomDecorationParams' => array(
'list' => array(
'style' => 'height:1em; ' .
'font-size=75%;color:gray;',
),
),
)
)
->addElement(
'VerticalSlider',
'vertical',
array(
'label' => 'VerticalSlider',
'value' => 5,
'style' => 'height: 200px; width: 3em;',
'minimum' => -10,
'maximum' => 10,
'discreteValues' => 11,
'intermediateChanges' => true,
'showButtons' => true,
'leftDecorationDijit' => 'VerticalRuleLabels',
'leftDecorationContainer' => 'leftContainer',
'leftDecorationLabels' => array(
' ',
'20%',
'40%',
'60%',
'80%',
' ',
),
'rightDecorationDijit' => 'VerticalRule',
'rightDecorationContainer' => 'rightContainer',
'rightDecorationLabels' => array(
'0%',
'50%',
'100%',
),
)
);

$this->addSubForm($textForm, 'textboxtab')
->addSubForm($editorForm, 'editortab')
->addSubForm($toggleForm, 'toggletab')
->addSubForm($selectForm, 'selecttab')
->addSubForm($sliderForm, 'slidertab');
}
}

556
Zend_Dojo

Exemple 327. Modifying an existing form to utilize Dojo

Existing forms can be modified to utilize Dojo as well, by use of the


Zend_Dojo::enableForm() static method.

This first example shows decorating an existing form instance:

$form = new My_Custom_Form();


Zend_Dojo::enableForm($form);
$form->addElement(
'ComboBox',
'query',
array(
'label' => 'Color:',
'value' => 'blue',
'autocomplete' => false,
'multiOptions' => array(
'red' => 'Rouge',
'blue' => 'Bleu',
'white' => 'Blanc',
'orange' => 'Orange',
'black' => 'Noir',
'green' => 'Vert',
),
)
);

Alternately, you can make a slight tweak to your form initialization:

class My_Custom_Form extends Zend_Form


{
public function init()
{
Zend_Dojo::enableForm($this);

// ...
}
}

Of course, if you can do that... you could and should simply alter the class to inherit from
Zend_Dojo_Form, which is a drop-in replacement of Zend_Form that's already Dojo-
enabled...

5. Zend_Dojo build layer support


5.1. Introduction
Dojo build layers provide a clean path from development to production when using Dojo for
your UI layer. In development, you can have load-on-demand, rapid application prototyping; a
build layer takes all Dojo dependencies and compiles them to a single file, optionally stripping
whitespace and comments, and performing code heuristics to allow further minification of variable
names. Additionally, it can do CSS minification.

In order to create a build layer, you would traditionally create a JavaScript file that has
dojo.require statements for each dependency, and optionally some additional code that might
run when the script is loaded. As an example:

557
Zend_Dojo

dojo.provide("custom.main");

dojo.require("dijit.layout.TabContainer");
dojo.require("dijit.layout.ContentPane");
dojo.require("dijit.form.Form");
dojo.require("dijit.form.Button");
dojo.require("dijit.form.TextBox");

This script is generally referred to as a "layer" script.

Then, in your application's layout, you'd instruct Dojo to load this module:

<html>
<head>
<script type="text/javascript" src="/js/dojo/dojo.js"></script>
<script type="text/javascript">
dojo.registerModulePath("custom", "../custom/");
dojo.require("custom.main");
</script>

If you use Zend_Dojo to do this, you'd do the following:

$view->dojo()->registerModulePath('custom', '../custom/')
->requireModule('custom.main');

But since Zend_Dojo aggregates your various dojo.require statements, how do you create
your layer script? You could open each page and view the generated dojo.require statements,
and cut and paste them into a layer script file manually.

However, a better solution exists: since Zend_Dojo aggregates this information already,
you can simply pull that information and build your layer file. This is the purpose of
Zend_Dojo_BuildLayer.

5.2. Generating Custom Module Layers with


Zend_Dojo_BuildLayer
At its simplest, you simply instantiate Zend_Dojo_BuildLayer, feed it the view object and the
name of your custom module layer, and have it generate the content of the layer file; it is up to
you to then write it to disk.

As an example, let's say you wanted to create the module layer "custom.main". Assuming you
follow the recommended project directory structure, and that you are storing your JavaScript files
under public/js/, you could do the following:

$build = new Zend_Dojo_BuildLayer(array(


'view' => $view,
'layerName' => 'custom.main',
));

$layerContents = $build->generateLayerScript();
$filename = APPLICATION_PATH . '/../public/js/custom/main.js';
if (!dir_exists(dirname($filename))) {
mkdir(dirname($filename));
}
file_put_contents($filename, $layerContents);

558
Zend_Dojo

When should you do the above? For it to work correctly, you need to do it after all view scripts
and the layout have been rendered, to ensure that the dojo() helper is fully populated. One
easy way to do so is using a front controller plugin, with a dispatchLoopShutdown() hook:

class App_Plugin_DojoLayer extends Zend_Controller_Plugin_Abstract


{
public $layerScript = APPLICATION_PATH . '/../public/js/custom/main.js';
protected $_build;

public function dispatchLoopShutdown()


{
if (!file_exists($this->layerScript)) {
$this->generateDojoLayer();
}
}

public function getBuild()


{
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(
'ViewRenderer'
);
$viewRenderer->initView();
if (null === $this->_build) {
$this->_build = new Zend_Dojo_BuildLayer(array(
'view' => $viewRenderer->view,
'layerName' => 'custom.main',
));
}
return $this->_build;
}

public function generateDojoLayer()


{
$build = $this->getBuild();
$layerContents = $build->generateLayerScript();
if (!dir_exists(dirname($this->layerScript))) {
mkdir(dirname($this->layerScript));
}
file_put_contents($this->layerScript, $layerContents);
}
}

Do not generate the layer on every page


It's tempting to generate the layer script on each and every page. However, this
is resource intensive, as it must write to the disk on each page. Additionally, since
the mtime of the file will keep changing, you will get no benefits of client-side
caching. Write the file once.

5.2.1. BuildLayer options


The above functionality will suffice for most situations. For those needing more customization,
a variety of options may be invoked.

5.2.1.1. Setting the view object

While the view object may be passed during instantiation, you may also pass it in to an instance
via the setView() method:

559
Zend_Dojo

$build->setView($view);

5.2.1.2. Setting the layer name

While the layer name may be passed during instantiation, you may also pass it in to an instance
via the setLayerName() method:

$build->setLayerName("custom.main");

5.2.1.3. Including onLoad events in the generated layer

dojo.addOnLoad is a useful utility for specifying actions that should trigger when the DOM has
finished loading. The dojo() view helper can create these statements via its addOnLoad()
and onLoadCapture() methods. In some cases, it makes sense to push these into your layer
file instead of rendering them via your view scripts.

By default, these are not rendered; to enable them, pass the consumeOnLoad configuration key
during instantiation:

$build = new Zend_Dojo_BuildLayer(array(


'view' => $view,
'layerName' => 'custom.main',
'consumeOnLoad' => true,
));

Alternately, you can use the setConsumeOnLoad() method after instantiation:

$build->setConsumeOnLoad(true);

5.2.1.4. Including captured JavaScript in the generated layer

The dojo() view helper includes methods for capturing arbitrary JavaScript to include in the
<script> tag containing the various dojo.require and dojo.addOnLoad statements. This can
be useful when creating default data stores or globally scoped objects used throughout your
application.

By default, these are not rendered; to enable them, pass the consumeJavascript configuration
key during instantiation:

$build = new Zend_Dojo_BuildLayer(array(


'view' => $view,
'layerName' => 'custom.main',
'consumeJavascript' => true,
));

Alternately, you can use the setConsumeJavascript() method after instantiation:

$build->setConsumeJavascript(true);

5.3. Generating Build Profiles with Zend_Dojo_BuildLayer


One of the chief benefits of a Dojo module layer is that it facilitates the creation of a custom build.
Zend_Dojo_BuildLayer has functionality for generate build profiles.

The simplest use case is to utilize the generateBuildProfile() method and send the output
to a file:

560
Zend_Dojo

$build = new Zend_Dojo_BuildLayer(array(


'view' => $view,
'layerName' => 'custom.main',
));

$profile = $build->generateBuildProfile();
$filename = APPLICATION_PATH . '/../misc/scripts/custom.profile.js';
file_put_contents($filename, $profile);

Just like generating layers, you may want to automate this via a dispatchLoopShutdown()
plugin hook; you could even simply modify the one shown for generating layers to read as follows:

class App_Plugin_DojoLayer extends Zend_Controller_Plugin_Abstract


{
public $layerScript = APPLICATION_PATH
. '/../public/js/custom/main.js';
public $buildProfile = APPLICATION_PATH
. '/../misc/scripts/custom.profile.js';
protected $_build;

public function dispatchLoopShutdown()


{
if (!file_exists($this->layerScript)) {
$this->generateDojoLayer();
}
if (!file_exists($this->buildProfile)) {
$this->generateBuildProfile();
}
}

public function generateDojoLayer() { /* ... */ }

public function generateBuildProfile()


{
$profile = $this->getBuild()->generateBuildProfile();
file_put_contents($this->buildProfile, $profile);
}

As noted, with module layers, you should only create the file once.

5.3.1. Build Profile options


The above functionality will suffice for most situations. The only way to customize build profile
generation is to provide additional build profile options to utilize.

As an example, you may want to specify what type of optimizations should be performed, whether
or not to optimize CSS files in the layer, whether or not to copy tests into the build, etc. For a
listing of available options, you should read the Dojo Build documentation and accompanying
documentation.

Setting these options is trivial: use the addProfileOption(), addProfileOptions(), or


setProfileOptions() methods. The first method adds a single key and value option pair,
the second will add several, and the third will overwrite any options with the list of key and value
pairs provided.

By default, the following options are set:

561
Zend_Dojo

{
action: "release",
optimize: "shrinksafe",
layerOptimize: "shrinksafe",
copyTests: false,
loader: "default",
cssOptimize: "comments"
}

You can pass in whatever key and value pairs you want; the Dojo build script will ignore those
it does not understand.

As an example of setting options:

// A single option:
$build->addProfileOption('version', 'zend-1.3.1');

// Several options:
$build->addProfileOptions(array(
'loader' => 'xdomain',
'optimize' => 'packer',
));

// Or overwrite options:
$build->setProfileOptions(array(
'version' => 'custom-1.3.1',
'loader' => 'shrinksafe',
'optimize' => 'shrinksafe',
));

562
Zend_Dom
1. Introduction
Zend_Dom fournit les outils pour travailler avec les documents et les structures de types DOM.
Actuellement, il existe Zend_Dom_Query, qui offre une interface unifiée pour requêter dans les
documents DOM en utilisant à la fois XPath et les sélecteurs CSS.

2. Zend_Dom_Query
Zend_Dom_Query fournit des mécanismes pour requêter dans les documents XML et (X)HTML
en utilisant soit XPath ou les sélecteurs CSS. Il a été développé pour faciliter les tests fonctionnels
des applications MVC, mais pourrait également être employé pour le développement rapide de
"screen scrapers".

La notation de type sélecteur CSS est fournie comme notation plus simple et plus familière
pour les développeurs Web à utiliser lors de la requête de documents ayant une structure de
type XML. La notation devrait être familière pour n'importe qui ayant écrit des feuilles de styles
CSS ou ayant utiliser des librairies Javascript qui fournissent pour sélectionner des noeuds en
utilisant des sélecteurs CSS ( Prototype's $$()et Dojo's dojo.queryont tous les deux inspirer ce
composant).

2.1. Aspect théorique


Pour utiliser Zend_Dom_Query, vous instanciez un objet Zend_Dom_Query, en fournissant
optionnellement un document à analyser (sous la forme d'une chaîne). Une fois que vous avez
un document, vous pouvez utiliser indifféremment les méthodes query() ou queryXpath() ;
chaque méthode retournera un objet Zend_Dom_Query_Result avec tout noeud trouvé.

La différence principale entre Zend_Dom_Query et l'utilisation de DOMDocument + DOMXPath


est la possibilité de requêter avec les sélecteurs CSS. Vous pouvez utiliser n'importe quel
élément suivant, dans n'importe quelle combinaison :

• types de l'élément : fourni un type d'élément à rechercher : "div", "a", "span", "h2", etc.

• attributs de style : les classes CSS à rechercher : ".error", "div.error", "label.required", etc. Si
un élément défini plus qu'une classe, la correspondance sera trouvé si la classe est présente
quelque part dans la déclaration de l'attribut.

• attribut id : ID de l'élément à rechercher : "#content", "div#nav", etc.

• attributs arbitraires : tout attribut arbitraire de l'élément à rechercher. Trois types de recherche
sont possibles :

• correspondance exacte : l'attribut vaut exactement la chaîne fournie : "div[bar="baz"]"


trouvera un élément div qui possède un attribut "bar" dont la valeur vaut exactement "baz".

• correspondance de mot : l'attribut contient un mot correspondant à la chaîne fournie :


"div[bar~="baz"]" trouvera un élément div qui possède un attribut "bar" dont la valeur contient
le mot "baz". "<div bar="foo baz">" trouvera, mais pas "<div bar="foo bazbat">".

• correspondance de parties de chaînes : l'attribut contient la chaîne fournie : "div[bar*="baz"]"


trouvera un élément div qui possède un attribut "bar" dont la valeur contient la chaîne "baz".

563
Zend_Dom

• Descendants directs : utilise ">" entre les sélecteurs pour représenter une descendance direct.
"div > span" trouvera seulement les éléments "span" qui sont des descendants directs d'un
élément "div". Peut aussi être utilisé avec chacun des sélecteurs ci-dessus.

• Descendants : une chaîne avec des sélecteurs multiples ensemble pour indiquer hiérarchie à
rechercher. "div .foo span #one" trouvera un élément avec un id "one" qui est un descendant
avec un profondeur arbitraire d'un élément "span", qui est lui-même un descendant avec un
profondeur arbitraire d'un élément ayant une classe "foo", qui est un descendant avec un
profondeur arbitraire d'un élément "div". Par exemple, il trouvera le lien vers le mot "One" dans
le code ci-dessous :

<div>
<table>
<tr>
<td class="foo">
<div>
Lorem ipsum <span class="bar">
<a href="/foo/bar" id="one">One</a>
<a href="/foo/baz" id="two">Two</a>
<a href="/foo/bat" id="three">Three</a>
<a href="/foo/bla" id="four">Four</a>
</span>
</div>
</td>
</tr>
</table>
</div>

Une fois que vous avez réalisé votre recherche, vous pouvez ensuite travailler avec l'objet de
résultat pour déterminer les informations sur les noeuds, ainsi que pour les récupérer eux et/ou
leurs contenus directement afin de les examiner et les manipuler. Zend_Dom_Query_Result
implémente Countable and Iterator, et stocke le résultat en interne sous la forme
DOMNodes/DOMElements. En exemple, considérons l'appel suivant sur l'HTML ci-dessus :

$dom = new Zend_Dom_Query($html);


$results = $dom->query('.foo .bar a');

$count = count($results); // trouvera 4 correspondances


foreach ($results as $result) {
// $result is a DOMElement
}

Zend_Dom_Query permet aussi de faire directement des recherches de type XPath en utilisant
la méthode queryXpath() ; vous pouvez fournir toute requête XPath valide à cette méthode,
et elle retournera un objet Zend_Dom_Query_Result.

2.2. Méthodes disponibles


La famille des classes Zend_Dom_Query possèdent les méthodes suivantes.

2.2.1. Zend_Dom_Query
Ces méthodes sont disponibles pour Zend_Dom_Query :

• setDocumentXml($document) : spécifie une chaîne XML dans laquelle requêter.

• setDocumentXhtml($document) : spécifie une chaîne XHTML dans laquelle requêter.

564
Zend_Dom

• setDocumentHtml($document) : spécifie une chaîne HTML dans laquelle requêter.

• setDocument($document) : spécifie une chaîne dans laquelle requêter ;


Zend_Dom_Query tentera alors de détecter automatiquement le type de document.

• getDocument() : récupère le document original fourni à l'objet.

• getDocumentType() : récupère le type de document fourni à l'objet ; sera une des


constantes de classe : DOC_XML, DOC_XHTML, ou DOC_HTML.

• query($query) : recherche dans le document en utilisant la notation de type sélecteur CSS.

• queryXpath($xPathQuery) : recherche dans le document en utilisant la notation XPath.

2.2.2. Zend_Dom_Query_Result
Comme mentionné auparavant, Zend_Dom_Query_Result implémente à la fois Iterator
et Countable, et en tant que tel peut être utilisé dans une boucle foreach ainsi qu'avec la
fonction count(). De plus il expose les méthodes suivantes :

• getCssQuery() : retourne le sélecteur CSS utilisé pour produire le résultat (si fourni).

• getXpathQuery() : retourne la requête XPath utilisé pour produire le résultat,


Zend_Dom_Query convertit les recherches de type sélecteur CSS en notation XPath, donc
cette valeur sera toujours présente.

• getDocument() : récupère l'élément DOMDocument dans lequel la recherche à été


effectuée.

565
Zend_Exception
1. Utiliser les exceptions
Zend_Exception est la classe de base dont dérivent toutes les exceptions levées par les
classes de Zend Framework.

Exemple 328. Récupération d'une exception

Le code suivant montre comment attraper une exception levée par une classe de Zend
Framework :

try {
Zend_Loader::loadClass('classnonexistante');
} catch (Zend_Exception $e) {
// Appeler Zend_Loader::loadClass() sur une classe non-existante
//entrainera la levée d'une exception dans Zend_Loader
echo "Récupère exception: " . get_class($e) . "\n";
echo "Message: " . $e->getMessage() . "\n";
// puis tout le code nécessaire pour récupérer l'erreur
}

Zend_Exception peut être comme une classe d'exception catch-all dans un bloc catch pour
traquer toues les exceptions levées par les classes de Zend Framework. Ceci peut être utile
quand un programme n'arrive pas à fonctionner en essayant d'attraper un type d'exception
spécifique.

La documentation pour chaque composant de Zend Framework et de ses classes contient les
informations plus spécifiques sur les méthodes qui lèvent des exceptions, les circonstances de
lancement de ces exceptions et quelles types declasses d'exception peuvent être levées.

2. Utilisation classique
Zend_Exception est le classe de base concernant toutes les exceptions envoyées par Zend
Framework. Cette classe étend la classe PHP Exception.

Exemple 329. Attraper toutes les exceptions du Zend Framework

try {
// votre code
} catch (Zend_Exception $e) {
// faire quelque chose
}

Exemple 330. Attraper les exceptions envoyées par un composant spécifique de


Zend Framework

try {
// Votre code
} catch (Zend_Db_Exception $e) {
// faire quelque chose
}

566
Zend_Exception

3. Exceptions précédentes
Depuis Zend Framework 1.10, Zend_Exception utilise les exceptions PHP 5.3 concernant
l'exception précédente. Simplement, dans un bloc catch, il est possible d'envoyer une exception
faisant référence à la précédente, ce qui améliore le contexte de débogage. Ce support dans
Zend Framework apporte le support complet de PHP 5.3 concernant les exceptions.

L'exception précedente s'utilise comme troisième paramètre du constructeur de la classe


Exception.

Exemple 331. Exceptions précedentes

try {
$db->query($sql);
} catch (Zend_Db_Statement_Exception $e) {
if ($e->getPrevious()) {
echo '[' . get_class($e)
. '] a comme exception précédente ['
. get_class($e->getPrevious())
. ']' . PHP_EOL;
} else {
echo '[' . get_class($e)
. '] n'a pas d'exception qui la précède'
. PHP_EOL;
}

echo $e;
// affiche toutes les exception à commencer par la première, puis
// dépile.
}

567
Zend_Feed
1. Introduction
Le composant Zend_Feed offre des services permettant de traiter des flux RSS et Atom. Il
permet d'accéder aux éléments d'un flux, aux attributs d'un flux et aux attributs des entrées
d'un flux, tout cela au moyen d'une syntaxe intuitive. Zend_Feed prend aussi complètement en
charge la modification de la structure des flux et des entrées, avec la même syntaxe intuitive
que précédemment, et il sait transformer le résultat en XML. À l'avenir, la prise en charge des
modifications pourrait aussi inclure la prise en charge du protocole de publication Atom.

Sur le plan de la programmation, Zend_Feed est constitué d'une classe de base Zend_Feed
et de classes de base abstraites Zend_Feed_Abstract et Zend_Feed_Entry_Abstract,
permettant de représenter respectivement des flux et des entrées ; Zend_Feed contient aussi
des implémentations particulières de ces classes abstraites pour les flux et entrées RSS et Atom
ainsi qu'un assistant en coulisses qui assure le bon fonctionnement de la syntaxe intuitive.

Dans l'exemple ci-dessous, nous illustrons une utilisation simple de Zend_Feed : on obtient un
flux RSS et on enregistre les portions du flux qui nous intéressent dans un tableau PHP simple,
qui pourra ensuite être utilisé pour afficher les données, les stocker dans une base de données
etc.

Attention

Beaucoup de flux RSS ont à leur disposition différentes propriétés, pour les
canaux comme pour les éléments. La spécification RSS spécifie beaucoup de
propriétés optionnelles et gardez donc cela à l'esprit lorsque vous écrivez du
code qui manipule des données RSS.

568
Zend_Feed

Exemple 332. Manipuler des données RSS avec Zend_Feed

// on va chercher les dernières news de Slashdot


try {
$rssSlashdot =
Zend_Feed::import('http://rss.slashdot.org/Slashdot/slashdot');
} catch (Zend_Feed_Exception $e) {
// l'importation du flux a échoué
echo "Une exception a été interceptée lors de l'importation "
. "du flux : {$e->getMessage()}\n";
exit;
}

// on initialise un tableau contenant les données du canal RSS


$canal = array(
'titre' => $rssSlashdot->title(),
'lien' => $rssSlashdot->link(),
'description' => $rssSlashdot->description(),
'elements' => array()
);

// on itère sur chaque élément du canal et


// on stocke les données qui nous intéressent
foreach ($rssSlashdot as $elem) {
$canal['elements'][] = array(
'titre' => $elem->title(),
'lien' => $elem->link(),
'description' => $elem->description()
);
}

2. Importer des flux


Zend_Feed permet aux développeurs d'obtenir très facilement des flux. Si vous connaissez
l'URI d'un flux, utilisez simplement la méthode Zend_Feed::import() :

$flux = Zend_Feed::import('http://flux.example.com/nomDuFlux');

Vous pouvez aussi utiliser Zend_Feed pour aller chercher le contenu d'un flux à partir d'un fichier
ou d'une chaîne PHP :

// on importe un flux à partir d'un fichier texte


$fluxAPartirDeFichierTexte = Zend_Feed::importFile('flux.xml');

// on importe un flux à partir d'une variable PHP de type chaîne


$fluxAPartirDePHP = Zend_Feed::importString($chaineFlux);

Dans chacun des exemples ci-dessus, une instance d'une classe étendant
Zend_Feed_Abstract est renvoyée en cas de succès, selon le type du flux. Si un flux
RSS a été obtenu au moyen de l'une des méthodes d'importation décrites ci-dessus, alors un
objet Zend_Feed_Rss sera renvoyé. Par contre, si un flux Atom a été importé, alors un objet
Zend_Feed_Atom est renvoyé. Les méthodes d'importation déclencheront aussi une exception
Zend_Feed_Exception en cas d'échec, par exemple si le flux est illisible ou malformé.

569
Zend_Feed

2.1. Flux personnalisés


Zend_Feed permet aux développeurs de créer du flux personnalisé très facilement. Vous
devez juste créer un tableau et l'importer avec Zend_Feed. Ce tableau peut être importé
avec Zend_Feed::importArray() ou avec Zend_Feed::importBuilder(). Dans ce
dernier cas, le tableau sera calculé instantanément par une source de données personnalisée
implémentant Zend_Feed_Builder_Interface.

2.1.1. Importer un tableau personnalisé

// on importe un flux atom à partir d'un tableau


$atomFeedFromArray = Zend_Feed::importArray($array);

// la ligne suivante est équivalente à celle ci-dessus ;


// par défaut l'instance Zend_Feed_Atom est retournée
$atomFeedFromArray = Zend_Feed::importArray($array, 'atom');

// on importe un flux rss à partir d'un tableau


$rssFeedFromArray = Zend_Feed::importArray($array, 'rss');

Le format du tableau doit être conforme à cette structure :

array(
// obligatoire
'title' => 'titre du flux',
'link' => 'url canonique du flux',

// optionel
'lastUpdate' => 'date de la mise à jour au format timestamp',
'published' => 'date de la publication au format timestamp',

// obligatoire
'charset' => 'charset des données textuelles',

// optionel
'description' => 'description courte du flux',
'author' => 'auteur du flux',
'email' => 'email de l'auteur du flux',

// optionel, ignoré si le flux est de type atom


'webmaster' => 'email de la personne responsable'
. 'en cas de problème technique'

// optionel
'copyright' => 'informations de copyright',
'image' => 'url de l'image',
'generator' => 'générateur du flux',
'language' => 'langue dans la quelle le flux est écrit',

// optionel, ignoré si le flux est de type atom


'ttl' => 'combien de temps en minutes un flux peut être'
. 'mis en cache avant rafraichissement',
'rating' => 'l'évaluation PICS du canal',

// optionel, ignoré si le flux est de type atom


// un nuage pour être averti des mises à jour
'cloud' => array(
// obligatoire

570
Zend_Feed

'domain' => 'domaine du nuage, ex. rpc.sys.com',

// optionel, par défault port 80


'port' => 'port de connexion',

// obligatoire
'path' => 'chemin du nuage, ex. /RPC2',
'registerProcedure' => 'procédure à appeler, '
. 'ex. myCloud.rssPleaseNotify',
'protocol' => 'protocole à utiliser , ex. soap ou xml-rpc',
),

// optionel, ignoré si le flux est de type atom


// une boîte de saisie qui peut être montrée avec le flux
'textInput' => array(
// obligatoire
'title' => 'l'intitulé du bouton de validation '
. 'de la boîte de saisie',
'description' => 'explication de la boîte de saisie',
'name' => 'le nom de l'objet texte',
'link' => 'l'URL du CGI qui va analyser la requête',
)

// optionel, ignoré si le flux est de type atom


// Information disant aux aggrégateurs quelles heures ils peuvent ignorer
'skipHours' => array(
// jusqu'à 24 lignes dont les valeurs
// sont des nombres commpris entre 0 et 23
// ex. 13 (1pm)
'heures dans le format 24H',
)

// optionel, ignoré si le flux est de type atom


// Information disant aux aggrégateurs quels jours ils peuvent ignorer
'skipDays ' => array(
// jusqu'à 7 lignes dont les valeurs peuvent être
// Monday, Tuesday, Wednesday, Thursday, Friday, Saturday or Sunday
// ex. Monday
'jour'
)

// optionel, ignoré si le flux est de type atom


// Données d'extension iTunes
'itunes' => array(
// optionel, par défaut l'auteur principal
'author' => 'nom de l'artiste',

// optionel, default l'auteur principal


'owner' => array(
'name' => 'nom du propriétaire' ,
'email' => 'email du propriétaire',
)

// optionel, default to the main image value


'image' => 'image de l'album/podcast',

// optionel, default to the main description value


'subtitle' => 'description courte',

// optionel, default to the main description value

571
Zend_Feed

'summary' => 'description longue',

// optionel
'block' => 'empêcher l'apparition d'un épisode (yes|no)',

// obligatoire, catégorie et information de recherche


// dans iTunes Music Store
'category' => array(
// jusqu'à 3 lignes
array(
// obligatoire
'main' => 'catégorie principale',
// optionel
'sub' => 'sous-catégorie'
),
)

// optionel
'explicit' => 'graphique d'avertissement parental (yes|no|clean)',
'keywords' => 'une liste d'au maximum 12 mot clés'
. 'séparés par des virgules',
'new-feed-url' => 'utiliser pour informer iTunes'
. 'd'un nouvel URL de flux',
)

'entries' => array(


array(
// obligatoire
'title' => 'titre de l'item',
'link' => 'url de cet item',

// obligatoire, seulement du text, pas d'html


'description' => 'version raccourci du texte',

// optionel
'guid' => 'id de l'article, si aucun alors'
. 'la valeur link est utilisée',

// optionel, peut contenir html


'content' => 'version complète de l'information',

// optionel
'lastUpdate' => 'date de publication au format timestamp',
'comments' => 'page de commentaires de l'item',
'commentRss' => 'l'url du flux des commentaires associés',

// optionel, source originale de l'item


'source' => array(
// obligatoire
'title' => 'titre de la source originale',
'url' => 'url de la source originale'
)

// optionel, liste des catégories attachées


'category' => array(
array(
// obligatoire
'term' => 'intitulé de la première catégorie',

// optionel

572
Zend_Feed

'scheme' => 'url qui décrit l'organisation de la catégorie'


),
array(
//données de la seconde catégorie et ainsi de suite
)
),

// optionel, liste des pièces jointes à l'item


'enclosure' => array(
array(
// obligatoire
'url' => 'url de la pièce jointe',

// optionel
'type' => 'type mime de la pièce jointe',
'length' => 'length de la pièce jointe en octets'
),
array(
//données de la seconde pièce jointe et ainsi de suite
)
)
),

array(
//données du second item et ainsi de suite
)
)
);

Références :

• Spécification RSS 2.0 : RSS 2.0

• Spécification Atom : RFC 4287

• Spécification WFW : Well Formed Web

• Spécification iTunes : iTunes Technical Specifications

2.1.2. Importer une source de données personnalisée


Vous pouvez créer une instance Zeed_Feed à partir de n'importe quelle source de
données implémentant Zend_Feed_Builder_Interface. Vous devez juste implémenter
les méthodes getHeader() et getEntries() pour pouvoir utiliser votre objet avec
Zend_Feed::importBuilder(). Par une simple référence d'implémentation vous pouvez
utiliser Zend_Feed_Builder, qui prend un tableau dans son constructeur, réalise quelques
validations mineures, et peut être utilisé dans la méthode importBuilder(). La
méthode getHeader() doit retourner une instance de Zend_Feed_Builder_Header, et
getEntries() doit retourner un tableau d'instances Zend_Feed_Builder_Entry

Zend_Feed_Builder fournit une mise en oeuvre concrète afin de montrer


l'utilisation. Les utilisateurs sont encouragés à faire leurs classes propres mettre
en oeuvre Zend_Feed_Builder_Interface.

Voici un exemple d'utilisation de Zend_Feed::importBuilder() :

// importe un flux atom à partir d'un constructeur personnalisé

573
Zend_Feed

$atomFeedFromArray =
Zend_Feed::importBuilder(new Zend_Feed_Builder($array));

// la ligne suivante est équivalente à celle ci-dessus ;


// par défaut l'instance Zend_Feed_Atom est retournée
$atomFeedFromArray =
Zend_Feed::importBuilder(new Zend_Feed_Builder($array), 'atom');

// importe un flux rss à partir d'un constructeur personnalisé


$rssFeedFromArray =
Zend_Feed::importBuilder(new Zend_Feed_Builder($array), 'rss');

2.1.3. Décharger le contenu d'un flux

Pour décharger le contenu d'une instance Zend_Feed_Abstract, vous pouvez utiliser les
méthodes send() ou saveXml().

assert($feed instanceof Zend_Feed_Abstract);

// décharge le flux dans l'affichage standard


print $feed->saveXML();

// envoie les en-têtes et décharge le flux


$feed->send();

3. Obtenir des flux à partir de pages Web


Les pages Web contiennent souvent des balises <link> qui font référence à des flux dont le
contenu est lié à la page. Zend_Feed vous permet d'obtenir tous les flux référencés par une
page Web en appelant simplement une méthode :

$tableauFlux =
Zend_Feed::findFeeds('http://www.exemple.com/news.html');

La méthode findFeeds() renvoie ici un tableau d'objets Zend_Feed_Abstract associés


aux flux référencés par les balises <link> de la page Web news.html. Selon le
type de chaque flux, chaque entrée respective du tableau $tableauFlux peut être une
instance de Zend_Feed_Rss ou Zend_Feed_Atom. Zend_Feed déclenchera une exception
Zend_Feed_Exception en cas d'échec, par exemple en cas de code HTTP 404 renvoyé en
réponse ou si le flux est malformé.

4. Consommer un flux RSS


Lire un flux RSS se résume à instancier un objet Zend_Feed_Rss en passant l'URL du flux :

$canal = new Zend_Feed_Rss('http://rss.exemple.com/nomDuCanal');

Si une erreur a lieu lors de l'obtention du flux, une Zend_Feed_Exception sera déclenchée.

Une fois que vous disposez d'un objet "flux RSS", vous pouvez accéder aux propriétés RSS
standard du canal, et ce directement à partir de l'objet :

echo $canal->title();

574
Zend_Feed

Notez la syntaxe utilisée : un appel de fonction. Zend_Feed utilise une convention selon laquelle
les propriétés sont traitées comme des objets XML si elles sont demandées au moyen de la
syntaxe $obj->propriété et comme des chaînes si elles sont demandées au moyen de la
syntaxe $obj->propriété(). Ceci permet d'accéder à la totalité du contenu textuel d'un nœud
particulier tout comme à l'ensemble des enfants de ce nœud.

Si les propriétés du canal possèdent des attributs, ils sont accessibles à l'aide de l'indexage PHP :

echo $canal->category['domain'];

Comme les attributs XML ne peuvent avoir des enfants, la syntaxe $obj-
>propriété['attribut']() n'est pas nécessaire pour accéder aux valeurs des attributs.

La plupart du temps vous voudrez itérer sur le flux et réaliser quelque chose avec ses entrées.
Zend_Feed_Abstract implémente l'interface iterator de PHP, ce qui résume au code
suivant l'affichage des titres de tous les articles du canal :

foreach ($canal as $element) {


echo $element->title() . "\n";
}

Si vous n'êtes pas un familier de RSS, voici les éléments standard associés au canal RSS et à
ses éléments pris séparément (les entrées).

Les éléments requis pour les canaux sont :

• title (titre) : le nom du canal

• link (lien) : l'URL du site Web correspondant au canal

• description : une ou plusieurs phrases décrivant le canal

Les éléments optionnels pour les canaux sont :

• pubDate (date de publication) : la date de publication de l'ensemble, au format RFC 822

• language (langue) : la langue dans laquelle est écrit le canal

• category (catégorie) : un ou plusieurs noms de catégorie (spécifiés au moyen de plusieurs


balises) auquel appartient le canal

Les éléments RSS <item> n'ont pas d'éléments requis particulier. Cependant soit title soit
description doivent être présents.

Les éléments communs sont :

• title (titre) : le titre de l'élément

• link (lien) : l'URL de l'élément

• description : un résumé de l'élément

• author (auteur) : l'adresse e-mail de l'auteur

• category (catégorie) : une ou plusieurs catégories auquel appartient l'élément

575
Zend_Feed

• comments (commentaires) : l'URL des commentaires relatifs à cet élément

• pubDate (date de publication) : la date à laquelle l'élément a été publié, au format RFC 822

Dans votre code vous pouvez toujours tester si un élément est non-vide au moyen du test
suivant :

if ($element->nomPropriete()) {
// ... traitement
}

Si vous utilisez à la place de la condition $element->nomPropriete, vous obtiendrez toujours


un objet qui, même vide, sera évalué comme TRUE, donc le test échouera.

Pour plus d'informations, la spécification RSS 2.0 officielle est disponible à l'adresse : http://
blogs.law.harvard.edu/tech/rss

5. Consommer un flux Atom


La classe Zend_Feed_Atom est utilisée pratiquement de la même manière que
Zend_Feed_Rss. Tout comme Zend_Feed_Rss, elle offre aussi un accès aux propriétés du
flux et elle permet d'itérer sur les entrées du flux. La différence principale réside dans la structure
du protocole Atom lui-même. Atom est le successeur de RSS ; c'est un protocole plus général
et il est conçu pour prendre en charge plus facilement les flux qui incluent directement leur
contenu, et ce en divisant la balise RSS description en deux éléments : summary (résumé)
et content (contenu).

Exemple 333. Emploi basique de Zend_Feed_Atom

Pour lire un flux Atom et afficher le titre (propriété title) et le résumé (propriété summary)
de chaque entrée :

$flux = new Zend_Feed_Atom('http://atom.exemple.com/flux/');


echo 'Le flux contient ' . $flux->count() . ' entrée(s).' . "\n\n";
foreach ($flux as $entree) {
echo 'Titre : ' . $entree->title() . "\n";
echo 'Résumé : ' . $entree->summary() . "\n\n";
}

Voici les propriétés liées au flux que vous pourrez trouver dans un flux Atom :

• title (titre) : le titre du flux, la même chose que le titre d'un canal RSS

• id (identifiant) : avec Atom, chaque flux et entrée possède un identifiant unique

• link (lien) : les flux peuvent posséder plusieurs liens, qui se distinguent les uns des autres
par un attribut type

Le lien équivalent au lien d'un canal RSS aurait pour type "text/html". Si le lien
désigne une version alternative du contenu présent dans le flux, il possédera un attribut
rel="alternate"

• subtitle (sous-titre) : la description du flux, qui équivaut à la description d'un canal RSS

author->name() : le nom de l'auteur du flux

576
Zend_Feed

author->email() : l'adresse e-mail de l'auteur du flux

Les entrées Atom possèdent généralement les propriétés suivantes :

• id (identifiant) : l'identifiant unique de l'entrée

• title (titre) : le titre de l'entrée, la même chose que le titre d'un élément RSS

• link (lien) : un lien vers un autre format ou une vue alternative de l'entrée

• summary (résumé) : un résumé du contenu de l'entrée

• content (contenu) : le contenu de l'entrée dans son entier ; vous pouvez l'ignorer si le flux
ne contient que des résumés

• author (auteur) : avec les sous-balises name (nom) et email

• published (publié) : la date à laquelle l'entrée a été publiée, au format RFC 3339

• updated (publié) : la date à laquelle l'entrée a été mise à jour, au format RFC 3339

Pour plus d'informations sur Atom ainsi qu'un grand nombre de ressources, voyez le site http://
www.atomenabled.org/.

6. Consommer une entrée Atom particulière


Les éléments Atom <entry> sont aussi valides tout seuls. Généralement l'URL d'une entrée
constitue l'URL du flux suivie de /<idEntree>, par exemple http://atom.exemple.com/
flux/1 si on reprend l'URL que nous avons utilisée ci-dessus.

Si vous lisez une entrée seule, vous obtiendrez toujours un objet Zend_Feed_Atom mais cette
classe créera automatiquement un flux "anonyme" pour contenir l'entrée.

Exemple 334. Lire un flux Atom constitué d'une seule entrée

$flux = new Zend_Feed_Atom('http://atom.exemple.com/flux/1');


echo 'Le flux possède : ' . $flux->count() . ' entrée(s).';

$entree = $flux->current();

Vous pouvez aussi instancier directement la classe représentant les entrées si vous êtes sûr
que vous accédez à un document contenant une seule balise <entry> :

Exemple 335. Utiliser directement l'objet Zend_Feed_Entry_Atom

$entree = new Zend_Feed_Entry_Atom('http://atom.exemple.com/flux/1');


echo $entree->title();

7. Modifier la structure du flux ou des entrées


La syntaxe intuitive de Zend_Feed peut aussi bien servir à lire des flux ou des entrées qu'à les
construire et les modifier. Vous pouvez facilement transformer vos nouveaux objets (ou objets
modifiés) en code XML bien formé et enregistrer ensuite ce code dans un fichier ou le renvoyer
au serveur.

577
Zend_Feed

Exemple 336. Modifier l'entrée existante d'un flux

$flux = new Zend_Feed_Atom('http://atom.exemple.com/flux/1');


$entree = $flux->current();

$entree->title = 'Ceci est un nouveau titre';


$entree->author->email = 'mon_email@exemple.com';

echo $entree->saveXML();

Ce code affichera une représentation XML complète (y compris le prologue <?xml ...>)
de la nouvelle entrée, avec les espaces de noms XML nécessaires.

Notez que le code ci-dessus fonctionnera même si l'entrée existante ne possédait pas de
balise author. Vous pouvez utiliser autant de fois que vous le souhaitez l'opérateur d'accès
-> dans une instruction d'affectation ; si nécessaire, les niveaux intermédiaires seront créés
pour vous automatiquement.

Si vous souhaitez utiliser dans votre entrée un espace de noms autre que atom:, rss: ou
osrss:, vous devez enregistrer cet espace de noms auprès de Zend_Feed à l'aide de la
méthode Zend_Feed::registerNamespace(). Lorsque vous modifiez un élément existant,
il gardera toujours son espace de noms d'origine. Lorsque vous ajoutez un élément, il utilisera
l'espace de noms par défaut si vous ne spécifiez pas explicitement un autre espace de noms.

Exemple 337. Créer une entrée Atom dont les éléments appartiennent à un
espace de noms personnalisé

$entree = new Zend_Feed_Entry_Atom();


// en Atom, id est toujours affecté par le serveur
$entree->title = 'mon entrée perso';
$entree->author->name = 'Auteur';
$entree->author->email = 'moi@exemple.com';

// maintenant on s'occupe de la partie personnalisée


Zend_Feed::registerNamespace('monen',
'http://www.exemple.com/monen/1.0');

$entree->{'monen:monelement_un'} = 'ma première valeur personnalisée';


$entree->{'monen:conteneur_elt'}
->partie1 = 'première partie imbriquée personnalisée';
$entree->{'monen:conteneur_elt'}
->partie2 = 'deuxième partie imbriquée personnalisée';

echo $entree->saveXML();

8. Classes personnalisées pour les flux et entrées


Pour finir, vous pouvez étendre les classes de Zend_Feed si vous souhaitez créer votre propre
format ou implémenter des améliorations comme par exemple la gestion automatique des
éléments situés dans un espace de noms personnalisé.

Voici un exemple d'entrée Atom personnalisée qui gère son propre espace de noms monen.
Notez aussi que la classe se charge d'appeler la méthode registerNamespace() pour que
l'utilisateur n'ait au final pas du tout à se soucier des espaces de noms.

578
Zend_Feed

/** Exemple 338. Étendre la classe représentant les entrées Atom pour ajouter la
gestion
* La classed'un espace de noms
personnalisée personnalisé
connaît automatiquement l'URI du flux
* (qui est optionnelle) et elle peut ajouter automatiquement
* des espaces de noms supplémentaires.
*/
class MonEntree extends Zend_Feed_Entry_Atom
{

public function __construct($uri = 'http://www.exemple.com/monflux/',


$xml = null)
{
parent::__construct($uri, $xml);
Zend_Feed::registerNamespace('monen',
'http://www.exemple.com/monen/1.0');
}

public function __get($var)


{
switch ($var) {
case 'maMiseAJour':
// On traduit maMiseAJour en monen:maj
return parent::__get('monen:maj');

default:
return parent::__get($var);
}
}

public function __set($var, $valeur)


{
switch ($var) {
case 'maMiseAJour':
// On traduit maMiseAJour en monen:maj
parent::__set('monen:maj', $valeur);
break;

default:
parent::__set($var, $valeur);
}
}

public function __call($var, $unused)


{
switch ($var) {
case 'maMiseAJour':
// On traduit maMiseAJour en monen:maMiseAJour.
return parent::__call('monen:maMiseAJour', $unused);

default:
return parent::__call($var, $unused);
}
Puis }pour= utiliser
$entree cette classe, instanciez-la directement et définissez la propriété
new MonEntree();
}
maMiseAJour :
$entree->maMiseAJour = '2005-04-19T15:30';

// appel de type méthode géré par __call


$entree->maMiseAJour();

// appel de type propriété géré par __get


$entree->maMiseAJour;

579
Zend_Feed

9. Zend_Feed_Reader
9.1. Introduction
Zend_Feed_Reader is a component used to consume RSS and Atom feeds of any version,
including RDF/RSS 1.0, RSS 2.0 and Atom 0.3/1.0. The API for retrieving feed data is deliberately
simple since Zend_Feed_Reader is capable of searching any feed of any type for the
information requested through the API. If the typical elements containing this information are not
present, it will adapt and fall back on a variety of alternative elements instead. This ability to
choose from alternatives removes the need for users to create their own abstraction layer on top
of the component to make it useful or have any in-depth knowledge of the underlying standards,
current alternatives, and namespaced extensions.

Internally, Zend_Feed_Reader works almost entirely on the basis of making XPath queries
against the feed XML's Document Object Model. The DOM is not exposed though a
chained property API like Zend_Feed though the underlying DOMDocument, DOMElement and
DOMXPath objects are exposed for external manipulation. This singular approach to parsing is
consistent and the component offers a plugin system to add to the Feed and Entry level API by
writing Extensions on a similar basis.

Performance is assisted in three ways. First of all, Zend_Feed_Reader supports caching using
Zend_Cache to maintain a copy of the original feed XML. This allows you to skip network
requests for a feed URI if the cache is valid. Second, the Feed and Entry level API is backed
by an internal cache (non-persistant) so repeat API calls for the same feed will avoid additional
DOM/XPath use. Thirdly, importing feeds from a URI can take advantage of HTTP Conditional
GET requests which allow servers to issue an empty 304 response when the requested feed has
not changed since the last time you requested it. In the final case, an instance of Zend_Cache
will hold the last received feed along with the ETag and Last-Modified header values sent in the
HTTP response.

In relation to Zend_Feed, Zend_Feed_Reader was formulated as a free standing replacement


for Zend_Feed but it is not backwards compatible with Zend_Feed. Rather it is an alternative
following a different ideology focused on being simple to use, flexible, consistent and extendable
through the plugin system. Zend_Feed_Reader is also not capable of constructing feeds and
delegates this responsibility to Zend_Feed_Writer, its sibling in arms.

9.2. Importing Feeds


Importing a feed with Zend_Feed_Reader is not that much different to Zend_Feed. Feeds
can be imported from a string, file, URI or an instance of type Zend_Feed_Abstract.
Importing from a URI can additionally utilise a HTTP Conditional GET request. If
importing fails, an exception will be raised. The end result will be an object of
type Zend_Feed_Reader_FeedInterface, the core implementations of which are
Zend_Feed_Reader_Feed_Rss and Zend_Feed_Reader_Feed_Atom (Zend_Feed took all
the short names!). Both objects support multiple (all existing) versions of these broad feed types.

In the following example, we import an RDF/RSS 1.0 feed and extract some basic information
that can be saved to a database or elsewhere.

$feed = Zend_Feed_Reader::import('http://www.planet-php.net/rdf/');
$data = array(
'title' => $feed->getTitle(),
'link' => $feed->getLink(),
'dateModified' => $feed->getDateModified(),
'description' => $feed->getDescription(),

580
Zend_Feed

'language' => $feed->getLanguage(),


'entries' => array(),
);

foreach ($feed as $entry) {


$edata = array(
'title' => $entry->getTitle(),
'description' => $entry->getDescription(),
'dateModified' => $entry->getDateModified(),
'authors' => $entry->getAuthors(),
'link' => $entry->getLink(),
'content' => $entry->getContent()
);
$data['entries'][] = $edata;
}

The example above demonstrates Zend_Feed_Reader's API, and it also demonstrates some
of its internal operation. In reality, the RDF feed selected does not have any native date or author
elements, however it does utilise the Dublin Core 1.1 module which offers namespaced creator
and date elements. Zend_Feed_Reader falls back on these and similar options if no relevant
native elements exist. If it absolutely cannot find an alternative it will return NULL, indicating
the information could not be found in the feed. You should note that classes implementing
Zend_Feed_Reader_FeedInterface also implement the SPL Iterator and Countable
interfaces.

Feeds can also be imported from strings, files, and even objects of type Zend_Feed_Abstract.

// from a URI
$feed = Zend_Feed_Reader::import('http://www.planet-php.net/rdf/');

// from a String
$feed = Zend_Feed_Reader::importString($feedXmlString);

// from a file
$feed = Zend_Feed_Reader::importFile('./feed.xml');

// from a Zend_Feed_Abstract object


$zfeed = Zend_Feed::import('http://www.planet-php.net/atom/');
$feed = Zend_Feed_Reader::importFeed($zfeed);

9.3. Retrieving Underlying Feed and Entry Sources


Zend_Feed_Reader does its best not to stick you in a narrow confine. If you need to work on a
feed outside of Zend_Feed_Reader, you can extract the base DOMDocument or DOMElement
objects from any class, or even an XML string containing these. Also provided are methods to
extract the current DOMXPath object (with all core and Extension namespaces registered) and
the correct prefix used in all XPath queries for the current Feed or Entry. The basic methods to
use (on any object) are saveXml(), getDomDocument(), getElement(), getXpath() and
getXpathPrefix(). These will let you break free of Zend_Feed_Reader and do whatever
else you want.

• saveXml() returns an XML string containing only the element representing the current object.

• getDomDocument() returns the DOMDocument object representing the entire feed (even if
called from an Entry object).

• getElement() returns the DOMElement of the current object (i.e. the Feed or current Entry).

581
Zend_Feed

• getXpath() returns the DOMXPath object for the current feed (even if called from an Entry
object) with the namespaces of the current feed type and all loaded Extensions pre-registered.

• getXpathPrefix() returns the query prefix for the current object (i.e. the Feed or current
Entry) which includes the correct XPath query path for that specific Feed or Entry.

Here's an example where a feed might include an RSS Extension not supported by
Zend_Feed_Reader out of the box. Notably, you could write and register an Extension
(covered later) to do this, but that's not always warranted for a quick check. You must register
any new namespaces on the DOMXPath object before use unless they are registered by
Zend_Feed_Reader or an Extension beforehand.

$feed = Zend_Feed_Reader::import('http://www.planet-php.net/rdf/');
$xpathPrefix = $feed->getXpathPrefix();
$xpath = $feed->getXpath();
$xpath->registerNamespace('admin', 'http://webns.net/mvcb/');
$reportErrorsTo = $xpath->evaluate('string('
. $xpathPrefix
. '/admin:errorReportsTo)');

If you register an already registered namespace with a different prefix name to


that used internally by Zend_Feed_Reader, it will break the internal operation
of this component.

9.4. Cache Support and Intelligent Requests


9.4.1. Adding Cache Support to Zend_Feed_Reader
Zend_Feed_Reader supports using an instance of Zend_Cache to cache feeds (as XML) to
avoid unnecessary network requests. Adding a cache is as simple here as it is for other Zend
Framework components, create and configure your cache and then tell Zend_Feed_Reader to
use it! The cache key used is "Zend_Feed_Reader_" followed by the MD5 hash of the feed's
URI.

$frontendOptions = array(
'lifetime' => 7200,
'automatic_serialization' => true
);
$backendOptions = array('cache_dir' => './tmp/');
$cache = Zend_Cache::factory(
'Core', 'File', $frontendOptions, $backendOptions
);

Zend_Feed_Reader::setCache($cache);

While it's a little off track, you should also consider adding a cache to
Zend_Loader_PluginLoader which is used by Zend_Feed_Reader to load
Extensions.

9.4.2. HTTP Conditional GET Support


The big question often asked when importing a feed frequently, is if it has even changed. With
a cache enabled, you can add HTTP Conditional GET support to your arsenal to answer that
question.

582
Zend_Feed

Using this method, you can request feeds from URIs and include their last known ETag and
Last-Modified response header values with the request (using the If-None-Match and If-Modified-
Since headers). If the feed on the server remains unchanged, you should receive a 304 response
which tells Zend_Feed_Reader to use the cached version. If a full feed is sent in a response
with a status code of 200, this means the feed has changed and Zend_Feed_Reader will parse
the new version and save it to the cache. It will also cache the new ETag and Last-Modified
header values for future use.

These "conditional" requests are not guaranteed to be supported by the server you request
a URI of, but can be attempted regardless. Most common feed sources like blogs should
however have this supported. To enable conditional requests, you will need to provide a cache
to Zend_Feed_Reader.

$frontendOptions = array(
'lifetime' => 86400,
'automatic_serialization' => true
);
$backendOptions = array('cache_dir' => './tmp/');
$cache = Zend_Cache::factory(
'Core', 'File', $frontendOptions, $backendOptions
);

Zend_Feed_Reader::setCache($cache);
Zend_Feed_Reader::useHttpConditionalGet();

$feed = Zend_Feed_Reader::import('http://www.planet-php.net/rdf/');

In the example above, with HTTP Conditional GET requests enabled, the response header
values for ETag and Last-Modified will be cached along with the feed. For the next 24hrs (the
cache lifetime), feeds will only be updated on the cache if a non-304 response is received
containing a valid RSS or Atom XML document.

If you intend on managing request headers from outside Zend_Feed_Reader, you can set the
relevant If-None-Matches and If-Modified-Since request headers via the URI import method.

$lastEtagReceived = '5e6cefe7df5a7e95c8b1ba1a2ccaff3d';
$lastModifiedDateReceived = 'Wed, 08 Jul 2009 13:37:22 GMT';
$feed = Zend_Feed_Reader::import(
$uri, $lastEtagReceived, $lastModifiedDateReceived
);

9.5. Locating Feed URIs from Websites


These days, many websites are aware that the location of their XML feeds is not always
obvious. A small RDF, RSS or Atom graphic helps when the user is reading the page, but what
about when a machine visits trying to identify where your feeds are located? To assist in this,
websites may point to their feeds using <link> tags in the <head> section of their HTML. To
take advantage of this, you can use Zend_Feed_Reader to locate these feeds using the static
findFeedLinks() method.

This method calls any URI and searches for the location of RSS, RDF and Atom feeds assuming
the website's HTML contains the relevant links. It then returns a value object where you can
check for the existence of a RSS, RDF or Atom feed URI.

The returned object is an ArrayObject subclass called


Zend_Feed_Reader_Collection_FeedLink so you can cast it to an array, or iterate over it,

583
Zend_Feed

to access all the detected links. However, as a simple shortcut, you can just grab the first RSS,
RDF or Atom link using its public properties as in the example below. Otherwise, each element
of the ArrayObject is a simple array with the keys "type" and "uri" where the type is one of
"rdf", "rss" or "atom".

$links = Zend_Feed_Reader::findFeedLinks('http://www.planet-php.net');

if(isset($links->rdf)) {
echo $links->rdf, "\n"; // http://www.planet-php.org/rdf/
}
if(isset($links->rss)) {
echo $links->rss, "\n"; // http://www.planet-php.org/rss/
}
if(isset($links->atom)) {
echo $links->atom, "\n"; // http://www.planet-php.org/atom/
}

Based on these links, you can then import from whichever source you wish in the usual manner.

This quick method only gives you one link for each feed type, but websites may indicate many
links of any type. Perhaps it's a news site with a RSS feed for each news category. You can
iterate over all links using the ArrayObject's iterator.

$links = Zend_Feed_Reader::findFeedLinks('http://www.planet-php.net');

foreach ($links as $link) {


echo $link['uri'], "\n";
}

9.6. Attribute Collections


In an attempt to simplify return types, with Zend Framework 1.10 return types
from the various feed and entry level methods may include an object of type
Zend_Feed_Reader_Collection_CollectionAbstract. Despite the special class name
which I'll explain below, this is just a simple subclass of SPL's ArrayObject.

The main purpose here is to allow the presentation of as much data as possible from the
requested elements, while still allowing access to the most relevant data as a simple array. This
also enforces a standard approach to returning such data which previously may have wandered
between arrays and objects.

The new class type acts identically to ArrayObject with the sole addition being a new method
getValues() which returns a simple flat array containing the most relevant information.

A simple example of this is Zend_Feed_Reader_FeedInterface::getCategories().


When used with any RSS or Atom feed, this method will return category data as a container
object called Zend_Feed_Reader_Collection_Category. The container object will contain,
per category, three fields of data: term, scheme and label. The "term" is the basic category name,
often machine readable (i.e. plays nice with URIs). The scheme represents a categorisation
scheme (usually a URI identifier) also known as a "domain" in RSS 2.0. The "label" is a human
readable category name which supports html entities. In RSS 2.0, there is no label attribute so
it is always set to the same value as the term for convenience.

To access category labels by themselves in a simple value array, you might commit to something
like:

584
Zend_Feed

$feed = Zend_Feed_Reader::import('http://www.example.com/atom.xml');
$categories = $feed->getCategories();
$labels = array();
foreach ($categories as $cat) {
$labels[] = $cat['label']
}

It's a contrived example, but the point is that the labels are tied up with other information.

However, the container class allows you to access the "most relevant" data as a simple array
using the getValues() method. The concept of "most relevant" is obviously a judgement call.
For categories it means the category labels (not the terms or schemes) while for authors it would
be the authors' names (not their email addresses or URIs). The simple array is flat (just values)
and passed through array_unique() to remove duplication.

$feed = Zend_Feed_Reader::import('http://www.example.com/atom.xml');
$categories = $feed->getCategories();
$labels = $categories->getValues();

The above example shows how to extract only labels and nothing else thus giving simple access
to the category labels without any additional work to extract that data by itself.

9.7. Retrieving Feed Information


Retrieving information from a feed (we'll cover entries/items in the next section though they follow
identical principals) uses a clearly defined API which is exactly the same regardless of whether
the feed in question is RSS/RDF/Atom. The same goes for sub-versions of these standards
and we've tested every single RSS and Atom version. While the underlying feed XML can differ
substantially in terms of the tags and elements they present, they nonetheless are all trying to
convey similar information and to reflect this all the differences and wrangling over alternative
tags are handled internally by Zend_Feed_Reader presenting you with an identical interface
for each. Ideally, you should not have to care whether a feed is RSS or Atom so long as you
can extract the information you want.

While determining common ground between feed types is itself complex, it should
be noted that RSS in particular is a constantly disputed "specification". This has its
roots in the original RSS 2.0 document which contains ambiguities and does not
detail the correct treatment of all elements. As a result, this component rigorously
applies the RSS 2.0.11 Specification published by the RSS Advisory Board and
its accompanying RSS Best Practices Profile. No other interpretation of RSS 2.0
will be supported though exceptions may be allowed where it does not directly
prevent the application of the two documents mentioned above.

Of course, we don't live in an ideal world so there may be times the API just does not cover what
you're looking for. To assist you, Zend_Feed_Reader offers a plugin system which allows you
to write Extensions to expand the core API and cover any additional data you are trying to extract
from feeds. If writing another Extension is too much trouble, you can simply grab the underlying
DOM or XPath objects and do it by hand in your application. Of course, we really do encourage
writing an Extension simply to make it more portable and reusable, and useful Extensions may
be proposed to the Framework for formal addition.

Here's a summary of the Core API for Feeds. You should note it comprises not only the basic
RSS and Atom standards, but also accounts for a number of included Extensions bundled with

585
Zend_Feed

Zend_Feed_Reader. The naming of these Extension sourced methods remain fairly generic
- all Extension methods operate at the same level as the Core API though we do allow you to
retrieve any specific Extension object separately if required.

Tableau 53. Feed Level API Methods

getId() Returns a unique ID associated with this feed


getTitle() Returns the title of the feed
getDescription() Returns the text description of the feed.
getLink() Returns a URI to the HTML website containing
the same or similar information as this feed
(i.e. if the feed is from a blog, it should provide
the blog's URI where the HTML version of the
entries can be read).
getFeedLink() Returns the URI of this feed, which may be the
same as the URI used to import the feed. There
are important cases where the feed link may
differ because the source URI is being updated
and is intended to be removed in the future.
getAuthors() Returns an object of type
Zend_Feed_Reader_Collection_Author
which is an ArrayObject whose elements are
each simple arrays containing any combination
of the keys "name", "email" and "uri". Where
irrelevant to the source data, some of these
keys may be omitted.
getAuthor(integer $index = 0) Returns either the first author known, or with the
optional $index parameter any specific index
on the array of Authors as described above
(returning NULL if an invalid index).
getDateCreated() Returns the date on which this feed was
created. Generally only applicable to Atom
where it represents the date the resource
described by an Atom 1.0 document was
created. The returned date will be a
Zend_Date object.
getDateModified() Returns the date on which this feed was
last modified. The returned date will be a
Zend_Date object.
getLanguage() Returns the language of the feed (if defined)
or simply the language noted in the XML
document.
getGenerator() Returns the generator of the feed, e.g. the
software which generated it. This may differ
between RSS and Atom since Atom defines a
different notation.
getCopyright() Returns any copyright notice associated with
the feed.
getHubs() Returns an array of all Hub Server URI
endpoints which are advertised by the feed for

586
Zend_Feed

use with the Pubsubhubbub Protocol, allowing


subscriptions to the feed for real-time updates.
getCategories() Returns a
Zend_Feed_Reader_Collection_Category
object containing the details of any categories
associated with the overall feed. The supported
fields include "term" (the machine readable
category name), "scheme" (the categorisation
scheme/domain for this category), and
"label" (a html decoded human readable
category name). Where any of the three fields
are absent from the field, they are either set to
the closest available alternative or, in the case
of "scheme", set to NULL.

Given the variety of feeds in the wild, some of these methods will undoubtedly return NULL
indicating the relevant information couldn't be located. Where possible, Zend_Feed_Reader
will fall back on alternative elements during its search. For example, searching an RSS feed
for a modification date is more complicated than it looks. RSS 2.0 feeds should include a
<lastBuildDate> tag and/or a <pubDate> element. But what if it doesn't, maybe this is an
RSS 1.0 feed? Perhaps it instead has an <atom:updated> element with identical information
(Atom may be used to supplement RSS's syntax)? Failing that, we could simply look at the
entries, pick the most recent, and use its <pubDate> element. Assuming it exists... Many feeds
also use Dublin Core 1.0/1.1 <dc:date> elements for feeds/entries. Or we could find Atom
lurking again.

The point is, Zend_Feed_Reader was designed to know this. When you ask for the modification
date (or anything else), it will run off and search for all these alternatives until it either gives up
and returns NULL, or finds an alternative that should have the right answer.

In addition to the above methods, all Feed objects implement methods for retrieving the DOM
and XPath objects for the current feeds as described earlier. Feed objects also implement the
SPL Iterator and Countable interfaces. The extended API is summarised below.

Tableau 54. Extended Feed Level API Methods


getDomDocument() Returns the parent DOMDocument object for
the entire source XML document
getElement() Returns the current feed level DOMElement
object
saveXml() Returns a string containing an XML document
of the entire feed element (this is not the original
document but a rebuilt version)
getXpath() Returns the DOMXPath object used internally to
run queries on the DOMDocument object (this
includes core and Extension namespaces pre-
registered)
getXpathPrefix() Returns the valid DOM path prefix prepended
to all XPath queries matching the feed being
queried
getEncoding() Returns the encoding of the source XML
document (note: this cannot account for errors
such as the server sending documents in a

587
Zend_Feed

different encoding). Where not defined, the


default UTF-8 encoding of Unicode is applied.
count() Returns a count of the entries or items this
feed contains (implements SPL Countable
interface)
current() Returns either the current entry (using the
current index from key())
key() Returns the current entry index
next() Increments the entry index value by one
rewind() Resets the entry index to 0
valid() Checks that the current entry index is valid, i.e.
it does fall below 0 and does not exceed the
number of entries existing.
getExtensions() Returns an array of all Extension objects
loaded for the current feed (note: both
feed-level and entry-level Extensions exist,
and only feed-level Extensions are returned
here). The array keys are of the form
{ExtensionName}_Feed.
getExtension(string $name) Returns an Extension object for the feed
registered under the provided name. This
allows more fine-grained access to Extensions
which may otherwise be hidden within the
implementation of the standard API methods.
getType() Returns a static class constant (e.g.
Zend_Feed_Reader::TYPE_ATOM_03, i.e.
Atom 0.3) indicating exactly what kind of feed
is being consumed.

9.8. Retrieving Entry/Item Information


Retrieving information for specific entries or items (depending on whether you speak Atom or
RSS) is identical to feed level data. Accessing entries is simply a matter of iterating over a Feed
object or using the SPL Iterator interface Feed objects implement and calling the appropriate
method on each.

Tableau 55. Entry Level API Methods

getId() Returns a unique ID for the current entry.


getTitle() Returns the title of the current entry.
getDescription() Returns a description of the current entry.
getLink() Returns a URI to the HTML version of the
current entry.
getPermaLink() Returns the permanent link to the current entry.
In most cases, this is the same as using
getLink().
getAuthors() Returns an object of type
Zend_Feed_Reader_Collection_Author
which is an ArrayObject whose elements are

588
Zend_Feed

each simple arrays containing any combination


of the keys "name", "email" and "uri". Where
irrelevant to the source data, some of these
keys may be omitted.
getAuthor(integer $index = 0) Returns either the first author known, or with the
optional $index parameter any specific index
on the array of Authors as described above
(returning NULL if an invalid index).
getDateCreated() Returns the date on which the current entry
was created. Generally only applicable to Atom
where it represents the date the resource
described by an Atom 1.0 document was
created.
getDateModified() Returns the date on which the current entry was
last modified
getContent() Returns the content of the current entry (this
has any entities reversed if possible assuming
the content type is HTML). The description is
returned if a separate content element does not
exist.
getEnclosure() Returns an array containing the value of
all attributes from a multi-media <enclosure>
element including as array keys: url, length,
type. In accordance with the RSS Best
Practices Profile of the RSS Advisory Board,
no support is offers for multiple enclosures
since such support forms no part of the RSS
specification.
getCommentCount() Returns the number of comments made on this
entry at the time the feed was last generated
getCommentLink() Returns a URI pointing to the HTML page
where comments can be made on this entry
getCommentFeedLink([string $type = Returns a URI pointing to a feed of the provided
'atom'|'rss']) type containing all comments for this entry (type
defaults to Atom/RSS depending on current
feed type).
getCategories() Returns a
Zend_Feed_Reader_Collection_Category
object containing the details of any categories
associated with the entry. The supported fields
include "term" (the machine readable category
name), "scheme" (the categorisation scheme/
domain for this category), and "label" (a html
decoded human readable category name).
Where any of the three fields are absent
from the field, they are either set to the
closest available alternative or, in the case of
"scheme", set to NULL.

589
Zend_Feed

The extended API for entries is identical to that for feeds with the exception of the Iterator methods
which are not needed here.

There is often confusion over the concepts of modified and created dates. In
Atom, these are two clearly defined concepts (so knock yourself out) but in RSS
they are vague. RSS 2.0 defines a single <pubDate> element which typically
refers to the date this entry was published, i.e. a creation date of sorts. This
is not always the case, and it may change with updates or not. As a result, if
you really want to check whether an entry has changed, don't rely on the results
of getDateModified(). Instead, consider tracking the MD5 hash of three
other elements concatenated, e.g. using getTitle(), getDescription()
and getContent(). If the entry was truly updated, this hash computation will
give a different result than previously saved hashes for the same entry. This
is obviously content oriented, and will not assist in detecting changes to other
relevant elements. Atom feeds should not require such steps.

Further muddying the waters, dates in feeds may follow different standards. Atom
and Dublin Core dates should follow ISO 8601, and RSS dates should follow RFC
822 or RFC 2822 which is also common. Date methods will throw an exception
if Zend_Date cannot load the date string using one of the above standards, or
the PHP recognised possibilities for RSS dates.

The values returned from these methods are not validated. This means users
must perform validation on all retrieved data including the filtering of any
HTML such as from getContent() before it is output from your application.
Remember that most feeds come from external sources, and therefore the default
assumption should be that they cannot be trusted.

Tableau 56. Extended Entry Level API Methods


getDomDocument() Returns the parent DOMDocument object for
the entire feed (not just the current entry)
getElement() Returns the current entry level DOMElement
object
getXpath() Returns the DOMXPath object used internally to
run queries on the DOMDocument object (this
includes core and Extension namespaces pre-
registered)
getXpathPrefix() Returns the valid DOM path prefix prepended
to all XPath queries matching the entry being
queried
getEncoding() Returns the encoding of the source XML
document (note: this cannot account for errors
such as the server sending documents in
a different encoding). The default encoding
applied in the absence of any other is the UTF-8
encoding of Unicode.
getExtensions() Returns an array of all Extension objects
loaded for the current entry (note: both
feed-level and entry-level Extensions exist,
and only entry-level Extensions are returned

590
Zend_Feed

here). The array keys are in the form


{ExtensionName}_Entry.
getExtension(string $name) Returns an Extension object for the entry
registered under the provided name. This
allows more fine-grained access to Extensions
which may otherwise be hidden within the
implementation of the standard API methods.
getType() Returns a static class constant (e.g.
Zend_Feed_Reader::TYPE_ATOM_03, i.e.
Atom 0.3) indicating exactly what kind of feed
is being consumed.

9.9. Extending Feed and Entry APIs


Extending Zend_Feed_Reader allows you to add methods at both the feed and entry level which
cover the retrieval of information not already supported by Zend_Feed_Reader. Given the
number of RSS and Atom extensions that exist, this is a good thing since Zend_Feed_Reader
couldn't possibly add everything.

There are two types of Extensions possible, those which retrieve information from
elements which are immediate children of the root element (e.g. <channel> for RSS
or <feed> for Atom) and those who retrieve information from child elements of an
entry (e.g. <item> for RSS or <entry> for Atom). On the filesystem these are
grouped as classes within a namespace based on the extension standard's name. For
example, internally we have Zend_Feed_Reader_Extension_DublinCore_Feed and
Zend_Feed_Reader_Extension_DublinCore_Entry classes which are two Extensions
implementing Dublin Core 1.0/1.1 support.

Extensions are loaded into Zend_Feed_Reader using Zend_Loader_PluginLoader, so


their operation will be familiar from other Zend Framework components. Zend_Feed_Reader
already bundles a number of these Extensions, however those which are not used internally and
registered by default (so called Core Extensions) must be registered to Zend_Feed_Reader
before they are used. The bundled Extensions include:

Tableau 57. Core Extensions (pre-registered)

DublinCore (Feed and Entry) Implements support for Dublin Core Metadata
Element Set 1.0 and 1.1
Content (Entry only) Implements support for Content 1.0
Atom (Feed and Entry) Implements support for Atom 0.3 and Atom 1.0
Slash Implements support for the Slash RSS 1.0
module
WellFormedWeb Implements support for the Well Formed Web
CommentAPI 1.0
Thread Implements support for Atom Threading
Extensions as described in RFC 4685
Podcast Implements support for the Podcast 1.0 DTD
from Apple

The Core Extensions are somewhat special since they are extremely common and multi-faceted.
For example, we have a Core Extension for Atom. Atom is implemented as an Extension (not

591
Zend_Feed

just a base class) because it doubles as a valid RSS module - you can insert Atom elements
into RSS feeds. I've even seen RDF feeds which use a lot of Atom in place of more common
Extensions like Dublin Core.

Tableau 58. Non-Core Extensions (must register manually)

Syndication Implements Syndication 1.0 support for RSS


feeds
CreativeCommons A RSS module that adds an element at the
<channel> or <item> level that specifies which
Creative Commons license applies.

The additional non-Core Extensions are offered but not registered to Zend_Feed_Reader by
default. If you want to use them, you'll need to tell Zend_Feed_Reader to load them in advance
of importing a feed. Additional non-Core Extensions will be included in future iterations of the
component.

Registering an Extension with Zend_Feed_Reader, so it is loaded and its API is available to


Feed and Entry objects, is a simple affair using the Zend_Loader_PluginLoader. Here we
register the optional Slash Extension, and discover that it can be directly called from the Entry
level API without any effort. Note that Extension names are case sensitive and use camel casing
for multiple terms.

Zend_Feed_Reader::registerExtension('Syndication');
$feed = Zend_Feed_Reader::import('http://rss.slashdot.org/Slashdot/slashdot');
$updatePeriod = $feed->current()->getUpdatePeriod();

In the simple example above, we checked how frequently a feed is being updated using the
getUpdatePeriod() method. Since it's not part of Zend_Feed_Reader's core API, it could
only be a method supported by the newly registered Syndication Extension.

As you can also notice, the new methods from Extensions are accessible from the main API
using PHP's magic methods. As an alternative, you can also directly access any Extension object
for a similar result as seen below.

Zend_Feed_Reader::registerExtension('Syndication');
$feed = Zend_Feed_Reader::import('http://rss.slashdot.org/Slashdot/slashdot');
$syndication = $feed->getExtension('Syndication');
$updatePeriod = $syndication->getUpdatePeriod();

9.9.1. Writing Zend_Feed_Reader Extensions


Inevitably, there will be times when the Zend_Feed_Reader API is just not capable of getting
something you need from a feed or entry. You can use the underlying source objects, like
DOMDocument, to get these by hand however there is a more reusable method available by
writing Extensions supporting these new queries.

As an example, let's take the case of a purely fictitious corporation named Jungle Books. Jungle
Books have been publishing a lot of reviews on books they sell (from external sources and
customers), which are distributed as an RSS 2.0 feed. Their marketing department realises that
web applications using this feed cannot currently figure out exactly what book is being reviewed.
To make life easier for everyone, they determine that the geek department needs to extend
RSS 2.0 to include a new element per entry supplying the ISBN-10 or ISBN-13 number of the
publication the entry concerns. They define the new <isbn> element quite simply with a standard
name and namespace URI:

592
Zend_Feed

JungleBooks 1.0:
http://example.com/junglebooks/rss/module/1.0/

A snippet of RSS containing this extension in practice could be something similar to:

<?xml version="1.0" encoding="utf-8" ?>


<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:jungle="http://example.com/junglebooks/rss/module/1.0/">
<channel>
<title>Jungle Books Customer Reviews</title>
<link>http://example.com/junglebooks</link>
<description>Many book reviews!</description>
<pubDate>Fri, 26 Jun 2009 19:15:10 GMT</pubDate>
<jungle:dayPopular>
http://example.com/junglebooks/book/938
</jungle:dayPopular>
<item>
<title>Review Of Flatland: A Romance of Many Dimensions</title>
<link>http://example.com/junglebooks/review/987</link>
<author>Confused Physics Student</author>
<content:encoded>
A romantic square?!
</content:encoded>
<pubDate>Thu, 25 Jun 2009 20:03:28 -0700</pubDate>
<jungle:isbn>048627263X</jungle:isbn>
</item>
</channel>
</rss>

Implementing this new ISBN element as a simple entry level extension would require the following
class (using your own class namespace outside of Zend).

class My_FeedReader_Extension_JungleBooks_Entry
extends Zend_Feed_Reader_Extension_EntryAbstract
{
public function getIsbn()
{
if (isset($this->_data['isbn'])) {
return $this->_data['isbn'];
}
$isbn = $this->_xpath->evaluate(
'string(' . $this->getXpathPrefix() . '/jungle:isbn)'
);
if (!$isbn) {
$isbn = null;
}
$this->_data['isbn'] = $isbn;
return $this->_data['isbn'];
}

protected function _registerNamespaces()


{
$this->_xpath->registerNamespace(
'jungle', 'http://example.com/junglebooks/rss/module/1.0/'
);
}
}

593
Zend_Feed

This extension is easy enough to follow. It creates a new method getIsbn() which runs an
XPath query on the current entry to extract the ISBN number enclosed by the <jungle:isbn>
element. It can optionally store this to the internal non-persistent cache (no need to keep querying
the DOM if it's called again on the same entry). The value is returned to the caller. At the end
we have a protected method (it's abstract so it must exist) which registers the Jungle Books
namespace for their custom RSS module. While we call this an RSS module, there's nothing to
prevent the same element being used in Atom feeds - and all Extensions which use the prefix
provided by getXpathPrefix() are actually neutral and work on RSS or Atom feeds with no
extra code.

Since this Extension is stored outside of Zend Framework, you'll need to register the path prefix
for your Extensions so Zend_Loader_PluginLoader can find them. After that, it's merely a
matter of registering the Extension, if it's not already loaded, and using it in practice.

if(!Zend_Feed_Reader::isRegistered('JungleBooks')) {
Zend_Feed_Reader::addPrefixPath(
'/path/to/My/FeedReader/Extension', 'My_FeedReader_Extension'
);
Zend_Feed_Reader::registerExtension('JungleBooks');
}
$feed = Zend_Feed_Reader::import('http://example.com/junglebooks/rss');

// ISBN for whatever book the first entry in the feed was concerned with
$firstIsbn = $feed->current()->getIsbn();

Writing a feed level Extension is not much different. The example feed from earlier included
an unmentioned <jungle:dayPopular> element which Jungle Books have added to their
standard to include a link to the day's most popular book (in terms of visitor traffic). Here's an
Extension which adds a getDaysPopularBookLink() method to the feel level API.

class My_FeedReader_Extension_JungleBooks_Feed
extends Zend_Feed_Reader_Extension_FeedAbstract
{
public function getDaysPopularBookLink()
{
if (isset($this->_data['dayPopular'])) {
return $this->_data['dayPopular'];
}
$dayPopular = $this->_xpath->evaluate(
'string(' . $this->getXpathPrefix() . '/jungle:dayPopular)'
);
if (!$dayPopular) {
$dayPopular = null;
}
$this->_data['dayPopular'] = $dayPopular;
return $this->_data['dayPopular'];
}

protected function _registerNamespaces()


{
$this->_xpath->registerNamespace(
'jungle', 'http://example.com/junglebooks/rss/module/1.0/'
);
}
}

Let's repeat the last example using a custom Extension to show the method being used.

594
Zend_Feed

if(!Zend_Feed_Reader::isRegistered('JungleBooks')) {
Zend_Feed_Reader::addPrefixPath(
'/path/to/My/FeedReader/Extension', 'My_FeedReader_Extension'
);
Zend_Feed_Reader::registerExtension('JungleBooks');
}
$feed = Zend_Feed_Reader::import('http://example.com/junglebooks/rss');

// URI to the information page of the day's most popular book with visitors
$daysPopularBookLink = $feed->getDaysPopularBookLink();

// ISBN for whatever book the first entry in the feed was concerned with
$firstIsbn = $feed->current()->getIsbn();

Going through these examples, you'll note that we don't register feed and entry Extensions
separately. Extensions within the same standard may or may not include both a feed and
entry class, so Zend_Feed_Reader only requires you to register the overall parent name, e.g.
JungleBooks, DublinCore, Slash. Internally, it can check at what level Extensions exist and load
them up if found. In our case, we have a full set of Extensions now: JungleBooks_Feed and
JungleBooks_Entry.

10. Zend_Feed_Writer
10.1. Introduction
Zend_Feed_Writer is the sibling component to Zend_Feed_Reader responsible for
generating feeds for output. It supports the Atom 1.0 specification (RFC 4287) and RSS 2.0 as
specified by the RSS Advisory Board (RSS 2.0.11). It does not deviate from these standards. It
does, however, offer a simple Extension system which allows for any extension/module for either
of these two specifications to be implemented if they are not provided out of the box.

In many ways, Zend_Feed_Writer is the inverse of Zend_Feed_Reader. Where


Zend_Feed_Reader focused on providing an easy to use architecture fronted by getter
methods, Zend_Feed_Writer is fronted by similarly named setters or mutators. This ensures
the API won't pose a learning curve to anyone familiar with Zend_Feed_Reader.

As a result of this design, the rest may even be obvious. Behind the scenes, data set on any
Zend_Feed_Reader object is translated at render time onto a DOMDocument object using the
necessary feed elements. For each supported feed type there is both an Atom 1.0 and RSS 2.0
renderer. Using a DOMDocument rather a templating solution has numerous advantages, the
most obvious being the ability to export the DOMDocument for additional processing and relying
on PHP DOM for correct and valid rendering.

As with Zend_Feed_Reader, Zend_Feed_Writer is a standalone replacement for


Zend_Feed's Builder architecture and is not compatible with those classes.

10.2. Architecture
The architecture of Zend_Feed_Writer is very simple. It has two core sets of classes:
containers and renderers.

The containers include the Zend_Feed_Writer_Feed and Zend_Feed_Writer_Entry


classes. The Entry classes can be attached to any Feed class. The sole purpose of these
containers is to collect data about the feed to generate using a simple interface of setter methods.
These methods perform some data validity testing. For example, it will validate any passed URIs,
dates, etc. These checks are not tied to any of the feed standards. The container objects also

595
Zend_Feed

contain methods to allow for fast rendering and export of the final feed, and these can be reused
at will.

While there are two data containers, there are four renderers - two matching container renderers
per support feed type. The renderer accept a container, and based on its content attempt to
generate a valid feed. If the renderer is unable to generate a valid feed, perhaps due to the
container missing an obligatory data point, it will report this by throwing an Exception. While
it is possible to ignore Exceptions, this removes the default safeguard of ensuring you have
sufficient data set to render a wholly valid feed.

Due to the system being divided between data containers and renderers, it can make Extensions
somewhat interesting. A typical Extension offering namespaced feed and entry level elements,
must itself reflect the exact same architecture, i.e. offer feed and entry level data containers,
and matching renderers. There is, fortunately, no complex integration work required since all
Extension classes are simply registered and automatically used by the core classes. We'll meet
Extensions in more detail at the end of this section.

10.3. Getting Started


Using Zend_Feed_Reader is as simple as setting data and triggering the renderer. Here is an
example to generate a minimal Atom 1.0 feed.

/**
* Create the parent feed
*/
$feed = new Zend_Feed_Writer_Feed;
$feed->setTitle('Paddy\'s Blog');
$feed->setLink('http://www.example.com');
$feed->setFeedLink('http://www.example.com/atom', 'atom');
$feed->addAuthor(array(
'name' => 'Paddy',
'email' => 'paddy@example.com',
'uri' => 'http://www.example.com',
));
$feed->setDateModified(time());
$feed->addHub('http://pubsubhubbub.appspot.com/');

/**
* Add one or more entries. Note that entries must
* be manually added once created.
*/
$entry = $feed->createEntry();
$entry->setTitle('All Your Base Are Belong To Us');
$entry->setLink('http://www.example.com/all-your-base-are-belong-to-us');
$entry->addAuthor(array(
'name' => 'Paddy',
'email' => 'paddy@example.com',
'uri' => 'http://www.example.com',
));
$entry->setDateModified(time());
$entry->setDateCreated(time());
$entry->setDescription('Exposing the difficultly of porting games to English.');
$entry->setContent('I am not writing the article. The example is long enough as is ;).');
$feed->addEntry($entry);

/**
* Render the resulting feed to Atom 1.0 and assign to $out.
* You can substitute "atom" with "rss" to generate an RSS 2.0 feed.

596
Zend_Feed

*/
$out = $feed->export('atom');

The output rendered should be as follows:

<?xml version="1.0" encoding="utf-8"?>


<feed xmlns="http://www.w3.org/2005/Atom">
<title type="text">Paddy's Blog</title>
<subtitle type="text">Writing about PC Games since 176 BC.</subtitle>
<updated>2009-12-14T20:28:18+00:00</updated>
<generator uri="http://framework.zend.com" version="1.10.0alpha">
Zend_Feed_Writer
</generator>
<link rel="alternate" type="text/html" href="http://www.example.com"/>
<link rel="self" type="application/atom+xml" href="http://www.example.com/atom"/>
<id>http://www.example.com</id>
<author>
<name>Paddy</name>
<email>paddy@example.com</email>
<uri>http://www.example.com</uri>
</author>
<link rel="hub" href="http://pubsubhubbub.appspot.com/"/>
<entry>
<title type="html"><![CDATA[All Your Base Are Belong To Us]]></title>
<summary type="html">
<![CDATA[Exposing the difficultly of porting games to English.]]>
</summary>
<published>2009-12-14T20:28:18+00:00</published>
<updated>2009-12-14T20:28:18+00:00</updated>
<link rel="alternate" type="text/html" href="http://www.example.com/all-your-base-ar
<id>http://www.example.com/all-your-base-are-belong-to-us</id>
<author>
<name>Paddy</name>
<email>paddy@example.com</email>
<uri>http://www.example.com</uri>
</author>
<content type="html">
<![CDATA[I am not writing the article. The example is long enough as is ;).]]>
</content>
</entry>
</feed>

This is a perfectly valid Atom 1.0 example. It should be noted that omitting an obligatory point
of data, such as a title, will trigger an Exception when rendering as Atom 1.0. This will differ
for RSS 2.0 since a title may be omitted so long as a description is present. This gives rise to
Exceptions that differ between the two standards depending on the renderer in use. By design,
Zend_Feed_Writer will not render an invalid feed for either standard unless the end-user
deliberately elects to ignore all Exceptions.

10.4. Setting Feed Data Points


Before you can render a feed, you must first setup the data necessary for the feed being rendered.
This utilises a simple setter style API which doubles as an initial method for validating the data
being set. By design, the API closely matches that for Zend_Feed_Reader to avoid undue
confusion and uncertainty.

Zend_Feed_Writer offers this API via its data container classes Zend_Feed_Writer_Feed
and Zend_Feed_Writer_Entry. These classes merely store all feed data in type-agnostic

597
Zend_Feed

manner, meaning you may reuse any data container with any renderer without requiring
additional work. Both classes are also amenable to Extensions, meaning that an Extension
may define its own container classes which are registered to the base container classes as
extensions, and are checked when any method call triggers the base container's __call()
method.

Here's a summary of the Core API for Feeds. You should note it comprises not only the basic
RSS and Atom standards, but also accounts for a number of included Extensions bundled with
Zend_Feed_Writer. The naming of these Extension sourced methods remain fairly generic
- all Extension methods operate at the same level as the Core API though we do allow you to
retrieve any specific Extension object separately if required.

Tableau 59. Feed Level API Methods

setId() Set a unique ID associated with this feed. For


Atom 1.0 this is an atom:id element, whereas
for RSS 2.0 it is added as a guid element.
These are optional so long as a link is added,
i.e. the link is set as the ID.
setTitle() Set the title of the feed.
setDescription() Set the text description of the feed.
setLink() Set a URI to the HTML website containing the
same or similar information as this feed (i.e.
if the feed is from a blog, it should provide
the blog's URI where the HTML version of the
entries can be read).
setFeedLinks() Add a link to an XML feed, whether the feed
being generated or an alternate URI pointing
to the same feed but in a different format.
At a minimum, it is recommended to include
a link to the feed being generated so it has
an identifiable final URI allowing a client to
track its location changes without necessitating
constant redirects. The parameter is an array
of arrays, where each sub-array contains the
keys "type" and "uri". The type should be one
of "atom", "rss", or "rdf". If a type is omitted, it
defaults to the type used when rendering the
feed.
setAuthors() Sets the data for authors. The parameter is
an array of arrays where each sub-array may
contain the keys "name", "email" and "uri".
The "uri" value is only applicable for Atom
feeds since RSS contains no facility to show
it. For RSS 2.0, rendering will create two
elements - an author element containing the
email reference with the name in brackets, and
a Dublin Core creator element only containing
the name.
setAuthor() Sets the data for a single author following the
same format as described above for a single
sub-array.

598
Zend_Feed

setDateCreated() Sets the date on which this feed was created.


Generally only applicable to Atom where it
represents the date the resource described
by an Atom 1.0 document was created. The
expected parameter may be a UNIX timestamp
or a Zend_Date object.
getDateModified() Sets the date on which this feed was last
modified. The expected parameter may be a
UNIX timestamp or a Zend_Date object.
setLanguage() Sets the language of the feed. This will be
omitted unless set.
getGenerator() Allows the setting of a generator. The
parameter should be an array containing
the keys "name", "version" and "uri". If
omitted a default generator will be added
referencing Zend_Feed_Writer, the current
Zend Framework version and the Framework's
URI.
setCopyright() Sets a copyright notice associated with the
feed.
setHubs() Accepts an array of Pubsubhubbub Hub
Endpoints to be rendered in the feed as
Atom links so that PuSH Subscribers may
subscribe to your feed. Note that you must
implement a Pubsubhubbub Publisher in
order for real-time updates to be enabled.
A Publisher may be implemented using
Zend_Feed_Pubsubhubbub_Publisher.
setCategories() Accepts an array of categories for rendering,
where each element is itself an array whose
possible keys include "term", "label" and
"scheme". The "term" is a typically a category
name suitable for inclusion in a URI. The "label"
may be a human readable category name
supporting special characters (it is encoded
during rendering) and is a required key. The
"scheme" (called the domain in RSS) is optional
but must be a valid URI.

10.5. Setting Entry Data Points


Here's a summary of the Core API for Entries/Items. You should note it comprises not only
the basic RSS and Atom standards, but also accounts for a number of included Extensions
bundled with Zend_Feed_Writer. The naming of these Extension sourced methods remain
fairly generic - all Extension methods operate at the same level as the Core API though we do
allow you to retrieve any specific Extension object separately if required.

Tableau 60. Entry Level API Methods


setId() Set a unique ID associated with this feed. For
Atom 1.0 this is an atom:id element, whereas
for RSS 2.0 it is added as a guid element.

599
Zend_Feed

These are optional so long as a link is added,


i.e. the link is set as the ID.
setTitle() Set the title of the feed.
setDescription() Set the text description of the feed.
setLink() Set a URI to the HTML website containing the
same or similar information as this feed (i.e.
if the feed is from a blog, it should provide
the blog's URI where the HTML version of the
entries can be read).
setFeedLinks() Add a link to an XML feed, whether the feed
being generated or an alternate URI pointing
to the same feed but in a different format.
At a minimum, it is recommended to include
a link to the feed being generated so it has
an identifiable final URI allowing a client to
track its location changes without necessitating
constant redirects. The parameter is an array
of arrays, where each sub-array contains the
keys "type" and "uri". The type should be one
of "atom", "rss", or "rdf". If a type is omitted, it
defaults to the type used when rendering the
feed.
setAuthors() Sets the data for authors. The parameter is
an array of arrays where each sub-array may
contain the keys "name", "email" and "uri".
The "uri" value is only applicable for Atom
feeds since RSS contains no facility to show
it. For RSS 2.0, rendering will create two
elements - an author element containing the
email reference with the name in brackets, and
a Dublin Core creator element only containing
the name.
setAuthor() Sets the data for a single author following the
same format as described above for a single
sub-array.
setDateCreated() Sets the date on which this feed was created.
Generally only applicable to Atom where it
represents the date the resource described
by an Atom 1.0 document was created. The
expected parameter may be a UNIX timestamp
or a Zend_Date object.
getDateModified() Sets the date on which this feed was last
modified. The expected parameter may be a
UNIX timestamp or a Zend_Date object.
setLanguage() Sets the language of the feed. This will be
omitted unless set.
getGenerator() Allows the setting of a generator. The
parameter should be an array containing
the keys "name", "version" and "uri". If
omitted a default generator will be added

600
Zend_Feed

referencing Zend_Feed_Writer, the current


Zend Framework version and the Framework's
URI.
setCopyright() Sets a copyright notice associated with the
feed.
setHubs() Accepts an array of Pubsubhubbub Hub
Endpoints to be rendered in the feed as
Atom links so that PuSH Subscribers may
subscribe to your feed. Note that you must
implement a Pubsubhubbub Publisher in
order for real-time updates to be enabled.
A Publisher may be implemented using
Zend_Feed_Pubsubhubbub_Publisher.
setCategories() Accepts an array of categories for rendering,
where each element is itself an array whose
possible keys include "term", "label" and
"scheme". The "term" is a typically a category
name suitable for inclusion in a URI. The "label"
may be a human readable category name
supporting special characters (it is encoded
during rendering) and is a required key. The
"scheme" (called the domain in RSS) is optional
but must be a valid URI.

11. Zend_Feed_Pubsubhubbub
Zend_Feed_Pubsubhubbub is an implementation of the PubSubHubbub Core 0.2 Specification
(Working Draft). It offers implementations of a Pubsubhubbub Publisher and Subscriber suited
to Zend Framework and other PHP applications.

11.1. What is Pubsubhubbub?


Pubsubhubbub is an open, simple web-scale pubsub protocol. A common use case to enable
blogs (Publishers) to "push" updates from their RSS or Atom feeds (Topics) to end Subscribers.
These Subscribers will have subscribed to the blog's RSS or Atom feed via a Hub, a central
server which is notified of any updates by the Publisher and which then distributes these updates
to all Subscribers. Any feed may advertise that it supports one or more Hubs using an Atom
namespaced link element with a rel attribute of "hub".

Pubsubhubbub has garnered attention because it is a pubsub protocol which is easy to


implement and which operates over HTTP. Its philosophy is to replace the traditional model
where blog feeds have been polled at regular intervals to detect and retrieve updates. Depending
on the frequency of polling, this can take a lot of time to propagate updates to interested parties
from planet aggregators to desktop readers. With a pubsub system in place, updates are not
simply polled by Subscribers, they are pushed to Subscribers, elimenating any delay. For this
reason, Pubsubhubbub forms part of what has been dubbed the real-time web.

The protocol does not exist in isolation. Pubsub systems have been around for a while, such
as the familiar Jabber Publish-Subscribe protocol, XEP-0060, or the less well known rssCloud
(described in 2001). However these have not achieved widespread adoption typically due to
either their complexity, poor timing or lack of suitability for web applications. rssCloud, which was
recently revived as a response to the appearance of Pubsubhubbub, has also seen its usage

601
Zend_Feed

increase significantly though it lacks a formal specification and currently does not support Atom
1.0 feeds.

Perhaps surprisingly given its relative early age, Pubsubhubbub is already in use including in
Google Reader, Feedburner, and there are plugins available for Wordpress blogs.

11.2. Architecture
Zend_Feed_Pubsubhubbub implements two sides of the Pubsubhubbub 0.2 Specification: a
Publisher and a Subscriber. It does not currently implement a Hub Server though this is in
progress for a future Zend Framework release.

A Publisher is responsible for notifying all supported Hubs (many can be supported to add
redundancy to the system) of any updates to its feeds, whether they be Atom or RSS based.
This is achieved by pinging the supported Hub Servers with the URL of the updated feed. In
Pubsubhubbub terminology, any updatable resource capable of being subscribed to is referred
to as a Topic. Once a ping is received, the Hub will request the updated feed, process it for
updated items, and forward all updates to all Subscribers subscribed to that feed.

A Subscriber is any party or application which subscribes to one or more Hubs to receive
updates from a Topic hosted by a Publisher. The Subscriber never directly communicates with the
Publisher since the Hub acts as an intermediary, accepting subscriptions and sending updates
to subscribed Subscribers. The Subscriber therefore communicates only with the Hub, either to
subscribe/unsubscribe to Topics, or when it receives updates from the Hub. This communication
design ("Fat Pings") effectively removes the possibility of a "Thundering Herd" issue. This occurs
in a pubsub system where the Hub merely informs Subscribers that an update is available,
prompting all Subscribers to immediately retrieve the feed from the Publisher giving rise to a traffic
spike. In Pubsubhubbub, the Hub distributes the actual update in a "Fat Ping" so the Publisher
is not subjected to any traffic spike.

Zend_Feed_Pubsubhubbub implements Pubsubhubbub Publishers and


Subscribers with the classes Zend_Feed_Pubsubhubbub_Publisher and
Zend_Feed_Pubsubhubbub_Subscriber. In addition, the Subscriber implementation
may handle any feed updates forwarded from a Hub by using
Zend_Feed_Pubsubhubbub_Subscriber_Callback. These classes, their use cases, and
APIs are covered in subsequent sections.

11.3. Zend_Feed_Pubsubhubbub_Publisher
In Pubsubhubbub, the Publisher is the party who publishes a live feed and frequently updates it
with new content. This may be a blog, an aggregator, or even a web service with a public feed
based API. In order for these updates to be pushed to Subscribers, the Publisher must notify all
of its supported Hubs that an update has occured using a simple HTTP POST request containing
the URI or the updated Topic (i.e the updated RSS or Atom feed). The Hub will confirm receipt of
the notification, fetch the updated feed, and forward any updates to any Subscribers who have
subscribed to that Hub for updates from the relevant feed.

By design, this means the Publisher has very little to do except send these Hub pings whenever
its feeds change. As a result, the Publisher implementation is extremely simple to use and
requires very little work to setup and use when feeds are updated.

Zend_Feed_Pubsubhubbub_Publisher implements a full Pubsubhubbub Publisher. Its


setup for use is also simple, requiring mainly that it is configured with the URI endpoint for all
Hubs to be notified of updates, and the URIs of all Topics to be included in the notifications.

602
Zend_Feed

The following example shows a Publisher notifying a collection of Hubs about updates to a pair of
local RSS and Atom feeds. The class retains a collection of errors which include the Hub URLs,
so the notification can be re-attempted later and/or logged if any notifications happen to fail. Each
resulting error array also includes a "response" key containing the related HTTP response object.
In the event of any errors, it is strongly recommended to attempt the operation for failed Hub
Endpoints at least once more at a future time. This may require the use of either a scheduled
task for this purpose or a job queue though such extra steps are optional.

$publisher = new Zend_Feed_Pubsubhubbub_Publisher;


$publisher->addHubUrls(array(
'http://pubsubhubbub.appspot.com/',
'http://hubbub.example.com',
));
$publisher->addUpdatedTopicUrls(array(
'http://www.example.net/rss',
'http://www.example.net/atom',
));
$publisher->notifyAll();

if (!$publisher->isSuccess()) {
// check for errors
$errors = $publisher->getErrors();
$failedHubs = array()
foreach ($errors as $error) {
$failedHubs[] = $error['hubUrl'];
}
}

// reschedule notifications for the failed Hubs in $failedHubs

If you prefer having more concrete control over the Publisher, the methods
addHubUrls() and addUpdatedTopicUrls() pass each array value to the singular
addHubUrl() and addUpdatedTopicUrl() public methods. There are also matching
removeUpdatedTopicUrl() and removeHubUrl() methods.

You can also skip setting Hub URIs, and notify each in turn using the notifyHub() method
which accepts the URI of a Hub endpoint as its only argument.

There are no other tasks to cover. The Publisher implementation is very simple since most of the
feed processing and distribution is handled by the selected Hubs. It is however important to detect
errors and reschedule notifications as soon as possible (with a reasonable maximum number of
retries) to ensure notifications reach all Subscribers. In many cases as a final alternative, Hubs
may frequently poll your feeds to offer some additional tolerance for failures both in terms of their
own temporary downtime or Publisher errors/downtime.

11.4. Zend_Feed_Pubsubhubbub_Subscriber
In Pubsubhubbub, the Subscriber is the party who wishes to receive updates to any Topic (RSS or
Atom feed). They achieve this by subscribing to one or more of the Hubs advertised by that Topic,
usually as a set of one or more Atom 1.0 links with a rel attribute of "hub". The Hub from that point
forward will send an Atom or RSS feed containing all updates to that Subscriber's Callback URL
when it receives an update notification from the Publisher. In this way, the Subscriber need never
actually visit the original feed (though it's still recommended at some level to ensure updates
are retrieved if ever a Hub goes offline). All subscription requests must contain the URI of the
Topic being subscribed and a Callback URL which the Hub will use to confirm the subscription
and to forward updates.

603
Zend_Feed

The Subsciber therefore has two roles. To create and manage subscriptions, including
subscribing for new Topics with a Hub, unsubscribing (if necessary), and periodically renewing
subscriptions since they may have a limited validity as set by the Hub. This is handled by
Zend_Feed_Pubsubhubbub_Subscriber.

The second role is to accept updates sent by a Hub to the Subscriber's Callback URL, i.e. the
URI the Subscriber has assigned to handle updates. The Callback URL also handles events
where the Hub contacts the Subscriber to confirm all subscriptions and unsubscriptions. This is
handled by using an instance of Zend_Feed_Pubsubhubbub_Subscriber_Callback when
the Callback URL is accessed.

Zend_Feed_Pubsubhubbub_Subscriber implements the Pubsubhubbub 0.2


Specification. As this is a new specification version not all Hubs currently
implement it. The new specification allows the Callback URL to include a query
string which is used by this class, but not supported by all Hubs. In the interests
of maximising compatibility it is therefore recommended that the query string
component of the Subscriber Callback URI be presented as a path element, i.e.
recognised as a parameter in the route associated with the Callback URI and
used by the application's Router.

11.4.1. Subscribing and Unsubscribing


Zend_Feed_Pubsubhubbub_Subscriber implements a full Pubsubhubbub Subscriber
capable of subscribing to, or unsubscribing from, any Topic via any Hub advertised by that Topic.
It operates in conjunction with Zend_Feed_Pubsubhubbub_Subscriber_Callback which
accepts requests from a Hub to confirm all subscription or unsubscription attempts (to prevent
third-party misuse).

Any subscription (or unsubscription) requires the relevant information before proceeding,
i.e. the URI of the Topic (Atom or RSS feed) to be subscribed to for updates, and the
URI of the endpoint for the Hub which will handle the subscription and forwarding of the
updates. The lifetime of a subscription may be determined by the Hub but most Hubs should
support automatic subscription refreshes by checking with the Subscriber. This is supported
by Zend_Feed_Pubsubhubbub_Subscriber_Callback and requires no other work on your
part. It is still strongly recommended that you use the Hub sourced subscription time to live
(ttl) to schedule the creation of new subscriptions (the process is identical to that for any new
subscription) to refresh it with the Hub. While it should not be necessary per se, it covers cases
where a Hub may not support automatic subscription refreshing and rules out Hub errors for
additional redundancy.

With the relevant information to hand, a subscription can be attempted as demonstrated below:

$storage = new Zend_Feed_Pubsubhubbub_Model_Subscription;

$subscriber = new Zend_Feed_Pubsubhubbub_Subscriber;


$subscriber->setStorage($storage);
$subscriber->addHubUrl('http://hubbub.example.com');
$subscriber->setTopicUrl('http://www.example.net/rss.xml');
$subscriber->setCallbackUrl('http://www.mydomain.com/hubbub/callback');
$subscriber->subscribeAll();

In order to store subscriptions and offer access to this data for general use, the component
requires a database (a schema is provided later in this section). By default, it is assumed
the table name is "subscription" and it utilises Zend_Db_Table_Abstract in the background

604
Zend_Feed

meaning it will use the default adapter you have set for your application. You may also
pass a specific custom Zend_Db_Table_Abstract instance into the associated model
Zend_Feed_Pubsubhubbub_Model_Subscription. This custom adapter may be as simple
in intent as changing the table name to use or as complex as you deem necessary.

While this Model is offered as a default ready-to-roll solution, you may create your own Model
using any other backend or database layer (e.g. Doctrine) so long as the resulting class
implements the interface Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface.

An example schema (MySQL) for a subscription table accessible by the provided model may
look similar to:

CREATE TABLE IF NOT EXISTS `subscription` (


`id` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`topic_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`hub_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`created_time` datetime DEFAULT NULL,
`lease_seconds` bigint(20) DEFAULT NULL,
`verify_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`secret` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`expiration_time` datetime DEFAULT NULL,
`subscription_state` varchar(12) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Behind the scenes, the Subscriber above will send a request to the Hub endpoint containing the
following parameters (based on the previous example):

Tableau 61. Subscription request parameters

Parameter Value Explanation


hub.callback http://www.mydomain.com/ The URI used by a Hub to
hubbub/callback? contact the Subscriber and
xhub.subscription=5536df06b5dcb966edab3a4c4d56213c16a8184
either request confirmation of
a (un)subscription request or
send updates from subscribed
feeds. The appended query
string contains a custom
parameter (hence the xhub
designation). It is a query
string parameter preserved by
the Hub and resent with
all Subscriber requests. Its
purpose is to allow the
Subscriber to identify and look
up the subscription associated
with any Hub request in a
backend storage medium. This
is a non-standard parameter
used by this component in
preference to encoding a
subscription key in the URI
path which is more difficult
to implement in a Zend
Framework application.

605
Zend_Feed

Parameter Value Explanation


Nevertheless, since not
all Hubs support query
string parameters, we still
strongly recommend adding
the subscription key as a path
component in the form http://
www.mydomain.com/hubbub/
callback/5536df06b5dcb966edab3a4c4d56213c
To accomplish this, it requires
defining a route capable of
parsing out the final value of
the key and then retrieving
the value and passing it
to the Subscriber Callback
object. The value would
be passed into the method
Zend_Pubsubhubbub_Subscriber_Callba
A detailed example is offered
later.
hub.lease_seconds 2592000 The number of seconds for
which the Subscriber would
like a new subscription to
remain valid for (i.e. a
TTL). Hubs may enforce their
own maximum subscription
period. All subscriptions should
be renewed by simply
re-subscribing before the
subscription period ends to
ensure continuity of updates.
Hubs should additionally
attempt to automatically
refresh subscriptions before
they expire by contacting
Subscribers (handled
automatically by the Callback
class).
hub.mode subscribe Simple value indicating this
is a subscription request.
Unsubscription requests would
use the "unsubscribe" value.
hub.topic http://www.example.net/ The URI of the topic (i.e.
rss.xml Atom or RSS feed) which the
Subscriber wishes to subscribe
to for updates.
hub.verify sync Indicates to the Hub
the preferred mode of
verifying subscriptions or
unsubscriptions. It is repeated
twice in order of preference.
Technically this component

606
Zend_Feed

Parameter Value Explanation


does not distinguish between
the two modes and treats both
equally.
hub.verify async Indicates to the Hub
the preferred mode of
verifying subscriptions or
unsubscriptions. It is repeated
twice in order of preference.
Technically this component
does not distinguish between
the two modes and treats both
equally.
hub.verify_token 3065919804abcaa7212ae89.879827871253878386
A verification token returned
to the Subscriber by the
Hub when it is confirming a
subscription or unsubscription.
Offers a measure of reliance
that the confirmation request
originates from the correct Hub
to prevent misuse.

You can modify several of these parameters to indicate a


different preference. For example, you can set a different lease
seconds value using Zend_Pubsubhubbub_Subscriber::setLeaseSeconds()
or show a preference for the async verify mode by using
setPreferredVerificationMode(Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_ASYNC).
However the Hubs retain the capability to enforce their own preferences and for this reason the
component is deliberately designed to work across almost any set of options with minimum end-
user configuration required. Conventions are great when they work!

While Hubs may require the use of a specific verification mode (both
are supported by Zend_Pubsubhubbub), you may indicate a specific
preference using the setPreferredVerificationMode() method. In
"sync" (synchronous) mode, the Hub attempts to confirm a subscription as
soon as it is received, and before responding to the subscription request. In
"async" (asynchronous) mode, the Hub will return a response to the subscription
request immediately, and its verification request may occur at a later time.
Since Zend_Pubsubhubbub implements the Subscriber verification role as a
separate callback class and requires the use of a backend storage medium, it
actually supports both transparently though in terms of end-user performance,
asynchronous verification is very much preferred to eliminate the impact of a
poorly performing Hub tying up end-user server resources and connections for
too long.

Unsubscribing from a Topic follows the exact same pattern as the previous example, with
the exception that we should call unsubscribeAll() instead. The parameters included are
identical to a subscription request with the exception that "hub.mode" is set to "unsubscribe".

By default, a new instance of Zend_Pubsubhubbub_Subscriber will attempt to use a


database backed storage medium which defaults to using the default Zend_Db adapter with a
table name of "subscription". It is recommended to set a custom storage solution where these

607
Zend_Feed

defaults are not apt either by passing in a new Model supporting the required interface or by
passing a new instance of Zend_Db_Table_Abstract to the default Model's constructor to
change the used table name.

11.4.2. Handling Subscriber Callbacks

Whenever a subscription or unsubscription request is made, the Hub must verify the request by
forwarding a new verification request to the Callback URL set in the subscription/unsubscription
parameters. To handle these Hub requests, which will include all future communications
containing Topic (feed) updates, the Callback URL should trigger the execution of an instance
of Zend_Pubsubhubbub_Subscriber_Callback to handle the request.

The Callback class should be configured to use the same storage medium as the Subscriber
class. Using it is quite simple since most of its work is performed internally.

$storage = new Zend_Feed_Pubsubhubbub_Model_Subscription;


$callback = new Zend_Feed_Pubsubhubbub_Subscriber_Callback;
$callback->setStorage($storage);
$callback->handle();
$callback->sendResponse();

/**
* Check if the callback resulting in the receipt of a feed update.
* Otherwise it was either a (un)sub verification request or invalid request.
* Typically we need do nothing other than add feed update handling - the rest
* is handled internally by the class.
*/
if ($callback->hasFeedUpdate()) {
$feedString = $callback->getFeedUpdate();
/**
* Process the feed update asynchronously to avoid a Hub timeout.
*/
}

It should be noted that Zend_Feed_Pubsubhubbub_Subscriber_Callback


may independently parse any incoming query string and other parameters. This
is necessary since PHP alters the structure and keys of a query string when it is
parsed into the $_GET or $_POST superglobals. For example, all duplicate keys
are ignored and periods are converted to underscores. Pubsubhubbub features
both of these in the query strings it generates.

It is essential that developers recognise that Hubs are only concerned with
sending requests and receiving a response which verifies its receipt. If a feed
update is received, it should never be processed on the spot since this leaves
the Hub waiting for a response. Rather, any processing should be offloaded
to another process or deferred until after a response has been returned to the
Hub. One symptom of a failure to promptly complete Hub requests is that a Hub
may continue to attempt delivery of the update/verification request leading to
duplicated update attempts being processed by the Subscriber. This appears
problematic - but in reality a Hub may apply a timeout of just a few seconds,
and if no response is received within that time it may disconnect (assuming
a delivery failure) and retry later. Note that Hubs are expected to distribute
vast volumes of updates so their resources are stretched - please do process

608
Zend_Feed

feeds asynchronously (e.g. in a separate process or a job queue or even a cron


scheduled task) as much as possible.

11.4.3. Setting Up And Using A Callback URL Route


As noted earlier, the Zend_Feed_Pubsubhubbub_Subscriber_Callback class receives
the combined key associated with any subscription from the Hub via one of two methods. The
technically preferred method is to add this key to the Callback URL employed by the Hub in all
future requests using a query string parameter with the key "xhub.subscription". However, for
historical reasons, primarily that this was not supported in Pubsubhubbub 0.1 (it was recently
added in 0.2 only), it is strongly recommended to use the most compatible means of adding this
key to the Callback URL by appending it to the URL's path.

Thus the URL http://www.example.com/callback?xhub.subscription=key would become http://


www.example.com/callback/key.

Since the query string method is the default in anticipation of a greater level of future support for
the full 0.2 specification, this requires some additional work to implement.

The first step to to make the Zend_Feed_Pubsubhubbub_Subscriber_Callback class


aware of the path contained subscription key. It's manually injected therefore since it also
requires manually defining a route for this purpose. This is achieved simply by called the method
Zend_Feed_Pubsubhubbub_Subscriber_Callback::setSubscriptionKey() with the
parameter being the key value available from the Router. The example below demonstrates this
using a Zend Framework controller.

class CallbackController extends Zend_Controller_Action


{

public function indexAction()


{
$storage = new Zend_Feed_Pubsubhubbub_Model_Subscription;
$callback = new Zend_Feed_Pubsubhubbub_Subscriber_Callback;
$callback->setStorage($storage);
/**
* Inject subscription key parsing from URL path using
* a parameter from Router.
*/
$subscriptionKey = $this->_getParam('subkey');
$callback->setSubscriptionKey($subscriptionKey);
$callback->handle();
$callback->sendResponse();

/**
* Check if the callback resulting in the receipt of a feed update.
* Otherwise it was either a (un)sub verification request or invalid request.
* Typically we need do nothing other than add feed update handling - the rest
* is handled internally by the class.
*/
if ($callback->hasFeedUpdate()) {
$feedString = $callback->getFeedUpdate();
/**
* Process the feed update asynchronously to avoid a Hub timeout.
*/
}
}

609
Zend_Feed

Actually adding the route which would map the path-appended key to a parameter for retrieval
from a controller can be accomplished using a Route configuration such as the INI formatted
example below for use with Zend_Application bootstrapping.

; Callback Route to enable appending a PuSH Subscription's lookup key


resources.router.routes.callback.route = "callback/:subkey"
resources.router.routes.callback.defaults.module = "default"
resources.router.routes.callback.defaults.controller = "callback"
resources.router.routes.callback.defaults.action = "index"

610
Zend_File
1. Zend_File_Transfer
Zend_File_Transfer permet aux développeurs de contrôler l'upload de fichiers mais aussi le
téléchargement. Il vous permet d'utiliser les validateurs incorporés pour le traitement de fichier et
même la possibilité de changer les fichiers avec des filtres. Zend_File_Transfer fonctionne
avec des adaptateurs ce qui vous permet d'utiliser la même API pour différents protocoles de
transfert HTTP, FTP, WEBDAV et plus encore.

Limitation

L'implémentation actuelle de Zend_File_Transfer est limitée aux uploads


de type HTTP Post. Le téléchargement de fichiers et les autres adaptateurs
seront ajoutés dans les prochaines versions. Les méthodes non implémentées
pour le moment lèveront une exception. Donc réellement vous devriez
directement utiliser une instance de Zend_File_Transfer_Adapter_Http.
Ceci changera dans le futur, dès qu'il existera des adaptateurs disponibles.

Formulaires

Quand vous utilisez Zend_Form vous devriez lire et suivre les exemples
décrits dans le chapitre Zend_Form et ne pas utiliser manuellement
Zend_File_Transfer. Mais les informations que vous pourrez lire dans le
présent chapitre vous seront malgré tout utile, même si vous ne l'utilisez pas
directement. Toutes les considérations, descriptions et solutions sont les mêmes
quand vous utilisez Zend_File_Transfer au travers de Zend_Form.

L'utilisation de Zend_File_Transfer est assez simple. Il consiste en deux parties.


Le formulaire HTTP qui réalise l'upload, et la gestion des fichiers uploadés avec
Zend_File_Transfer. Regardez l'exemple suivant :

611
Zend_File

Exemple 339. Formulaire simple d'upload de fichier

Cet exemple illustre un upload de fichier basique avec Zend_File_Transfer. La première


partie est le formulaire. Dans notre exemple, il n'y a qu'un seul fichier que nous souhaitons
uploadé.

<form enctype="multipart/form-data" action="/file/upload" method="POST">


<input type="hidden" name="MAX_FILE_SIZE" value="100000" />
Choose a file to upload:
<input name="uploadedfile" type="file" />
<br />
<input type="submit" value="Upload File" />
</form>

Notez que vous devriez utiliser Zend_Form_Element_File par simplicité plutôt que de créer
le HTML manuellement.

L'étape suivante est de créer le récepteur de l'upload. Dans notre exemple le récepteur est
"/file/upload". Donc nous créons le contrôleur file avec l'action upload.

$adapter = new Zend_File_Transfer_Adapter_Http();

$adapter->setDestination('C:\temp');

if (!$adapter->receive()) {
$messages = $adapter->getMessages();
echo implode("\n", $messages);
}

Comme vous le voyez, l'utilisation la plus simple est de définir une destination avec la
méthode setDestination et d'appeler la méthode receive(). S'il apparaît des erreurs
au cours de l'upload, alors vous les récupérerez grâce à une exception qui sera retournée.

Attention
Maintenez à l'esprit qu'il s'agit de l'utilisation la plus simple. Vous ne devez jamais
utiliser cet exemple en environnement de production car il causerait de graves
problèmes de sécurité. Vous devez toujours utiliser des validateurs pour accroître
la sécurité.

1.1. Adaptateurs supportés par Zend_File_Transfer


Zend_File_Transfer est construit pour supporter différents adaptateurs et différentes
directions. Il est conçu pour permettre l'upload, le téléchargement et même l'envoi bidirectionnel
(upload avec un adaptateur et télécharge avec un autre adaptateur en même temps) de fichiers.

1.2. Options de Zend_File_Transfer


Zend_File_Transfer et ses adaptateurs supportent plusieurs options. Vous pouvez
paramétrer toutes les options soit en les fournissant au constructeur, ou en utilisant
setOptions($options). getOptions() retournera les options actuellement paramétrées.
Ci-dessous, vous trouverez la liste des options supportées :

• ignoreNoFile : si cette option vaut TRUE, tous les validateurs ignoreront le fait que le fichier
à été uploadé ou non par le formulaire. Cette option vaut par défaut FALSE, ce qui lance une
erreur indiquant que le fichier n'a pas été fourni.

612
Zend_File

1.3. Vérification des fichiers


Zend_File_Transfer possède plusieurs méthodes qui permettent de vérifier suivant
différentes considérations. Ceci est particulièrement utile quand vous devez travailler avec des
fichiers qui ont été uploadés.

• isValid($files = null) : cette méthode vérifie si le(s) fichier(s) est(sont) valide(s), en


se basant sur les validateurs affectés à chacun de ces fichiers. Si aucun fichier n'est fourni,
tous les fichiers seront vérifiés. Notez que cette méthode sera appelée en dernier quand les
fichiers seront reçus.

• isUploaded($files = null) : cette méthode vérifie si le(s) fichier(s) fourni(s) a (ont)


été uploadé(s) par l'utilisateur. Ceci est utile si vous avez défini que certains fichiers sont
optionnels. Si aucun fichier n'est fourni, tous les fichiers seront vérifiés.

• isReceived($files = null) : cette méthode vérifie si le(s) fichier(s) fourni(s) a (ont) bien
été reçu(s). Si aucun fichier n'est fourni, tous les fichiers seront vérifiés.

Exemple 340. Vérification de fichiers

$upload = new Zend_File_Transfer();

// Retourne toutes les informations connues sur le fichier


$files = $upload->getFileInfo();

foreach ($files as $file => $info) {


// Fichier uploadé ?
if (!$upload->isUploaded($file)) {
print "Pourquoi n'avez-vous pas uploadé ce fichier ?";
continue;
}

// Les validateurs sont-ils OK ?


if (!$upload->isValid($file)) {
print "Désolé mais $file ne correspond à ce que nous attendons";
continue;
}
}

$upload->receive();

1.4. Informations complémentaires sur les fichiers


Zend_File_Transfer peut fournir de multiples informations complémentaires sur les fichiers.
Les méthodes suivantes sont disponibles :

• getFileName($file = null, $path = true) : cette méthode retourne le vrai nom


de fichier d'un fichier transféré.

• getFileInfo($file = null) : cette méthode retourne tous les informations internes


concernant un fichier transféré donné.

• getFileSize($file = null) : cette méthode retourne la taille réelle d'un fichier transféré
donné.

• getHash($hash = 'crc32', $files = null) : cette méthode retourne la valeur de


hachage du contenu d'un fichier transféré donné.

613
Zend_File

• getMimeType($files = null) : cette méthode retourne le type MIME d'un fichier transféré
donné.

getFileName() accepte le nom d'un élément entant que premier paramètre. Si aucun n'est
fourni, tous les fichiers connus seront retournées sous la forme d'un tableau. Si le fichier est un
"multifile", vous le récupérerez aussi sous la forme d'un tableau. S'il n'y a qu'un seul fichier alors
une chaîne sera retournée.

Par défaut les noms de fichier sont retournés avec leur chemin d'accès complet. Si vous
souhaitez seulement le nom de fichier sans le chemin, vous pouvez paramétrer le second
paramètre $path à FALSE ce qui tronquera le chemin.

Exemple 341. Récupération du nom de fichier

$upload = new Zend_File_Transfer();


$upload->receive();

// Retourne le nom de fichier pour tous les fichiers


$names = $upload->getFileName();

// Retourne le nom de fichier de l'élément de formulaire "foo"


$names = $upload->getFileName('foo');

Notez que le nom de fichier peut changer quand vous recevez le fichier. Ceci
est du au fait qu'après la réception, tous les filtres sot appliqués. Donc vous ne
devriez appeler getFileName() qu'après avoir reçu les fichiers.

getFileSize() retourne par défaut la taille réelle d'un fichier en notation SI ce qui signifie
que vous récupérerez 2kB au lieu de 2048. Si vous voulez la taille brute, utilisez l'option
useByteString à FALSE.

Exemple 342. Récupération de la taille de fichier

$upload = new Zend_File_Transfer();


$upload->receive();

// Retourne les tailles de tous les fichiers sous la forme


// d'un tableau si plus d'un fichier a été uploadé
$size = $upload->getFileSize();

// Bascule de la notation SI vers une taille brute


$upload->setOption(array('useByteString' => false));
$size = $upload->getFileSize();

Client given filesize

Note that the filesize which is given by the client is not seen as save input.
Therefor the real size of the file will be detected and returned instead of the filesize
sent by the client.

getHash() accepte le nom de l'algorithme de hachage en tant que premier paramètre. Pour
avoir une liste des algorithmes connus, regardez la méthode hash_algos de PHP. Si vous ne
fournissez aucun algorithme, celui par défaut sera crc32.

614
Zend_File

Exemple 343. Récupération d'un hash de fichier

$upload = new Zend_File_Transfer();


$upload->receive();

// Retourne le hachage de fichier pour tous les fichiers sous la forme


// d'un tableau si plusieurs fichiers sont fournis
$hash = $upload->getHash('md5');

// Retourne le hachage de l'élément de formulaire "foo"


$names = $upload->getHash('crc32', 'foo');

Valeur retournée
Notez que si un fichier ou un élément de formulaire donné contient plus d'un
fichier, la valeur retournée sera un tableau.

getMimeType() retourne le type MIME d'un fichier. Si plus d'un fichier a été uploadé, elle
retourne un tableau, sinon c'est une chaîne.

Exemple 344. Récupération du type MIME de fichier

$upload = new Zend_File_Transfer();


$upload->receive();

$mime = $upload->getMimeType();

// Retourne le type MIME pour l'élément de formulaire "foo"


$names = $upload->getMimeType('foo');

Client given mimetype


Note that the mimetype which is given by the client is not seen as save input.
Therefor the real mimetype of the file will be detected and returned instead of the
mimetype sent by the client.

Exception possible
Notez que cette méthode utilise l'extension fileinfo si elle est disponible. Si elle
n'est pas trouvé, elle utilise l'extension mimemagic. Quand aucune extension
n'est fournie, une exception est levée.

Original data within $_FILES


Due to security reasons also the original data within $_FILES will be overridden
as soon as Zend_File_Transfer is initiated. When you want to omit this
behaviour and have the original data simply set the detectInfos option to FALSE
at initiation.

This option will have no effect after you initiated Zend_File_Transfer.

1.5. Progress for file uploads


Zend_File_Transfer can give you the actual state of a fileupload in progress. To use this
feature you need either the APC extension which is provided with most default PHP installations,

615
Zend_File

or the uploadprogress extension. Both extensions are detected and used automatically. To
be able to get the progress you need to meet some prerequisites.

First, you need to have either APC or uploadprogress to be enabled. Note that you can disable
this feature of APC within your php.ini.

Second, you need to have the proper hidden fields added in the form which sends the files. When
you use Zend_Form_Element_File this hidden fields are automatically added by Zend_Form.

When the above two points are provided then you are able to get the actual progress of the file
upload by using the getProgress method. Actually there are 2 official ways to handle this.

1.5.1. Using a progressbar adapter


You can use the convinient Zend_ProgressBar to get the actual progress and can display it in
a simple manner to your user.

To archive this, you have to add the wished Zend_ProgressBar_Adapter to getProgress()


when you are calling it the first time. For details about the right adapter to use, look into the
chapter Zend_ProgressBar Standard Adapters.

Exemple 345. Using the progressbar adapter to retrieve the actual state

$adapter = new Zend_ProgressBar_Adapter_Console();


$upload = Zend_File_Transfer_Adapter_Http::getProgress($adapter);

$upload = null;
while (!$upload['done']) {
$upload = Zend_File_Transfer_Adapter_Http:getProgress($upload);
}

The complete handling is done by getProgress() for you in the background.

1.5.2. Using getProgress() manually


You can also work manually with getProgress() without the usage of Zend_ProgressBar.

Call getProgress() without settings. It will return you an array with several keys. They differ
according to the used PHP extension. But the following keys are given independently of the
extension:

• id: The ID of this upload. This ID identifies the upload within the extension. It is filled
automatically. You should never change or give this value yourself.

• total: The total filesize of the uploaded files in bytes as integer.

• current: The current uploaded filesize in bytes as integer.

• rate: The average upload speed in bytes per second as integer.

• done: Returns true when the upload is finished and false otherwise.

• message: The actual message. Eighter the progress as text in the form 10kB / 200kB, or
a helpful message in the case of a problem. Problems could be, that there is no upload in
progress, that there was a failure while retrieving the data for the progress, or that the upload
has been canceled.

616
Zend_File

• progress: This optional key takes a instance of Zend_ProgressBar_Adapter or


Zend_ProgressBar and allows to get the actual upload state within a progressbar.

• session: This optional key takes the name of a session namespace which will
be used within Zend_ProgressBar. When this key is not given it defaults to
Zend_File_Transfer_Adapter_Http_ProgressBar.

All other returned keys are provided directly from the extensions and will not be checked.

The following example shows a possible manual usage:

Exemple 346. Manual usage of the file progress

$upload = Zend_File_Transfer_Adapter_Http::getProgress();

while (!$upload['done']) {
$upload = Zend_File_Transfer_Adapter_Http:getProgress($upload);
print "\nActual progress:".$upload['message'];
// do whatever you need
}

2. Validateurs pour Zend_File_Transfer


Zend_File_Transfer est fourni avec de multiples validateurs liés qui doivent être utiliser
pour accroître la sécurité et prévenir les attaques possibles. Notez que les validateurs
ne sont bons que si vous les utilisez. Tous les validateurs qui sont fournis avec
Zend_File_Transfer peuvent être trouvés avec le composant Zend_Validator et sont
nommés Zend_Validate_File_*. Les validateurs suivants sont actuellement disponibles :

• Count : ce validateur vérifie le nombre de fichiers. Il est possible de définir un minimum et un


maximum et une erreur sera lancée s'ils sont dépassés.

• Crc32 : ce validateur vérifie la valeur de hachage crc32 du contenu d'un fichier. Il est basé
sur le validateur Hash et en simplifiant son utilisation par le support unique du Crc32.

• ExcludeExtension : ce validateur vérifie l'extension des fichiers. Il lancera une erreur quand
un fichier aura une extension non souhaitée. Ainsi vous pouvez empêcher la validation de
certaines extensions.

• ExcludeMimeType : ce validateur vérifie le type MIME des fichiers. Il est aussi capable de
valider un groupe de type MIME et générera une erreur quand le type MIME d'un fichier donné
correspond.

• Exists : ce validateur vérifie l'existence des fichiers. Il lancera une erreur quand un fichier
n'existera pas.

• Extension : ce validateur vérifie l'extension des fichiers. Il lancera une erreur quand un fichier
n'aura pas l'extension définie.

• FilesSize : ce validateur vérifie la taille complète de tous les fichiers à valider. Il conserve en
mémoire la taille de tous les fichiers chargés et lance une erreur quand la somme de tous les
fichiers dépasse la taille définie. Il est aussi possible de définir une taille minimum et maximum.

• ImageSize : ce validateur vérifie la taille des images. Il valide la largeur et la hauteur et permet
de paramétrer à la fois une valeur minimum et maximum.

617
Zend_File

• IsCompressed : ce validateur vérifie si le fichier est compressé. Il est basé sur le validateur
MimeType et valide les archives compressées comme zip ou arc. Vous pouvez aussi limiter
à des types d'archives particuliers.

• IsImage : ce validateur vérifie si un fichier est une image. Il est basé sur le validateur
MimeType et valide les images comme jpg ou gif. Vous pouvez aussi limiter à des types
d'images particuliers.

• Hash : ce validateur vérifie la valeur de hachage md5 du contenu d'un fichier. Il supporte de
multiples algorithmes.

• Md5 : ce validateur vérifie la valeur de hachage md5 du contenu d'un fichier. Il est basé sur le
validateur Hash et en simplifiant son utilisation par le support unique du Md5.

• MimeType : ce validateur vérifie le type MIME des fichiers. Il est aussi capable de valider des
groupes de type MIME et de générer une erreur quand le type MIME d'un fichier donné ne
correspond pas.

• NotExists : ce validateur vérifie l'existence des fichiers. Il lancera une erreur quand un fichier
existera déjà.

• Sha1 : ce validateur vérifie la valeur de hachage sha1 du contenu d'un fichier. Il est basé sur
le validateur Hash et en simplifiant son utilisation par le support unique du Sha1.

• Size : ce validateur permet de valider la taille d'un fichier en particulier. Il est possible de
définir un minimum et un maximum et une erreur sera lancée s'ils sont dépassés.

• Upload : ce validateur est interne, il vérifie si l'upload a produit une erreur. Vous ne devez
pas le paramétrer, il est automatiquement activé par Zend_File_Transfer lui-même. Vous
pouvez donc oublier ce validateur. Il faut juste savoir qu'il existe.

• WordCount : ce validateur est capable de vérifier le nombre de mots à l'intérieur du fichier.


Il permet de définir des valeurs minimum et maximum et émettra une erreur si l'un ou l'autre
des seuils est dépassé.

2.1. Utiliser les validateurs avec Zend_File_Transfer


L'utilisation des validateurs est assez simple. Il existe de multiples méthodes pour ajouter et
manipuler les validateurs.

• isValid($files = null) : vérifie le(s) fichier(s) fourni(s) avec tout le jeu de validateurs
paramétrés. $files peut être soit un vrai nom de fichier, soit des noms d'éléments de
formulaire ou des noms de fichiers temporaires.

• addValidator($validator, $breakChainOnFailure, $options = null, $files


= null) : ajoute le validateur à la pile des validateurs (optionnellement seul le(s) fichier(s)
spécifié(s)). $validator peut être soit une instance d'un validateur réel, ou un nom court
spécifiant le validateur (par exemple, "Count").

• addValidators(array $validators, $files = null) : ajoute les validateurs à la


pile des validateurs. Chaque entrée peut être soit une paire type/options, ou un tableau avec
la clé "validator" spécifiant le validateur (tous les autres options seront considérées comme
des options du validateur au moment de l'instanciation).

• setValidators(array $validators, $files = null) : surcharge les validateurs


existants avec les validateurs spécifiés. Les validateurs doivent respecter la même syntaxe
que addValidators().

618
Zend_File

• hasValidator($name) : indique si un validateur est enregistré.

• getValidator($name) : retourne un validateur préalablement enregistré.

• getValidators($files = null) : retourne les validateurs enregistrés ; si $files est


fourni, retourne les validateurs pour ce fichier en particulier ou pour tous les fichiers.

• removeValidator($name) : enlève le validateur préalablement enregistré.

• clearValidators() : efface tous les validateurs.

Exemple 347. Ajouter des validateurs au(x) fichier(s) transféré(s)

$upload = new Zend_File_Transfer();

// Paramètre un poids de fichier de 20000 octets


$upload->addValidator('Size', false, 20000);

// Paramètre un poids de fichier de 20 octets minimum


// et de 20000 octets maximum
$upload->addValidator('Size', false, array('min' => 20, 'max' => 20000));

// Paramètre un poids de fichier de 20 octets minimum et


// de 20000 octets maximum et un nombre de fichiers en une seule étape
$upload->setValidators(array(
'Size' => array('min' => 20, 'max' => 20000),
'Count' => array('min' => 1, 'max' => 3),
));

Exemple 348. Limiter les validateurs à des fichiers uniques

addValidator(), addValidators(), et setValidators() accepte chacun un


argument final $files. Cet argument peut être utilisé pour spécifier un fichier en particulier
ou un tableau de fichiers sur lequel appliqué le validateur donné.

$upload = new Zend_File_Transfer();

// Paramètre un poids de fichier de 20000 octets et


// limite celui-ci à 'file2'
$upload->addValidator('Size', false, 20000, 'file2');

Généralement vous devriez simplement utiliser la méthode addValidators(), qui peut être
appelée plusieurs fois.

Exemple 349. Ajouter des validateurs multiples

Souvent il est plus simple d'appeler plusieurs fois addValidator() : un appel pour chaque
validateur. Ceci améliore aussi la lisibilité et rend votre code plus maintenable. Comme
toutes les méthodes fournissent un interface fluide, vous pouvez enchaîner les appels
comme montré ci-dessous :

$upload = new Zend_File_Transfer();

// Paramètre un poids de fichier de 20000 octets


$upload->addValidator('Size', false, 20000)
->addValidator('Count', false, 2)
->addValidator('Filessize', false, 25000);

619
Zend_File

Notez que même si l'ajout du même validateur plusieurs fois est autorisé, faire
ceci peut entraîner des problèmes si vous utilisez différentes options pour le
même validateur.

Et pour finir vous pouvez tout simplement vérifier le(s) fichier(s) en appelant isValid().

Exemple 350. Valider les fichiers

isValid() accepte les fichiers uploadés ou télécharger, le nom de fichier temporaire et


bien sûr le nom de l'élément de formulaire. Si aucun paramètre ou NULL est fourni, tous
les fichiers seront vérifiés.

$upload = new Zend_File_Transfer();

// Paramètre un poids de fichier de 20000 octets


$upload->addValidator('Size', false, 20000)
->addValidator('Count', false, 2)
->addValidator('Filessize', false, 25000);

if ($upload->isValid()) {
print "Echec de validation";
}

Notez que isValid() sera automatiquement appelé quand vous recevez les
fichiers et qu'il n'a pas été appelé auparavant.

Quand une validation a échouée, c'est probablement intéressant d'avoir des informations sur
les problèmes rencontrés. A cette fin, vous pouvez utiliser la méthode getMessages() qui
retourne tous les messages de validation sous la forme d'un tableau, getErrors() qui retourne
tous les codes d'erreurs et hasErrors() qui retourne TRUE dès qu'une erreur de validation
est rencontrée.

2.2. Validateur Count


Le validateur Count vérifie le nombre de fichiers fournis. Il supporte les clés d'options suivantes :

• min : paramètre le nombre minimum de fichiers à transférer.

Attention : quand vous utilisez cette option vous devez donner le nombre
minimum au moment où vous appelez ce validateur la première fois ; sinon
vous aurez une erreur en retour.

Avec cette option vous pouvez définir le nombre de fichiers que vous souhaitez recevoir.

• max : paramètre le nombre maximum de fichiers à transférer.

Avec cette option vous pouvez limiter le nombre de fichiers que vous acceptez mais vous
permet aussi de détecter une possible attaque quand plus de fichiers, que votre formulaire
n'en définit, sont fournis.

Vous pouvez initialiser ce validateur avec une chaîne ou un entier, la valeur sera utilisée en tant
que max. Mais vous pouvez aussi utiliser les méthodes setMin() et setMax() pour paramétrer
ces options plus tard et getMin() et getMax() pour les récupérer.

620
Zend_File

Exemple 351. Utiliser le validateur Count

$upload = new Zend_File_Transfer();

// Limite le nombre de fichiers à 2 maximum


$upload->addValidator('Count', false, 2);

// Limite le nombre de fichiers à 5 maximum,


// tout en obligeant au moins 1 fichier
$upload->addValidator('Count', false, array('min' =>1, 'max' => 5));

Notez que ce validateur stocke le nombre de fichiers vérifiés en interne. Le fichier


qui excédera le maximum sera retourné en tant qu'erreur.

2.3. Validateur Crc32


Le validateur Crc32 vérifie le contenu du fichier transféré en le hachant. Ce validateur utilise
l'extension de hachage de PHP avec l'algorithme crc32. Il supporte les options suivantes :

• * : vous pouvez paramétrer n'importe quelle clé ou utiliser un tableau numérique. Les valeurs
seront utilisées pour vérifier la valeur de hachage.

Vous pouvez paramétrer de multiples hachages en utilisant différentes clés. Chacun sera
vérifié et seulement si tous échouent, la validation elle-même échouera.

Exemple 352. Utiliser le validateur Crc32

$upload = new Zend_File_Transfer();

// Vérifie si le contenu d'un fichier uploadé correspond au hachage fourni


$upload->addValidator('Crc32', false, '3b3652f');

// Limite ce validateur à deux différents hachages


$upload->addValidator('Crc32', false, array('3b3652f', 'e612b69'));

2.4. Validateur ExcludeExtension


Le validateur ExcludeExtension vérifie l'extension des fichiers fournis. Il supporte les options
suivantes :

• * : vous pouvez paramétrer n'importe quelle clé ou utiliser un tableau numérique. Les valeurs
seront utilisées en tant qu'extensions à vérifier que le fichier n'utilise pas.

• case : paramètre une validation qui tient compte de la casse. Par défaut, ce n'est pas sensible
à la casse. Notez que cette clé est utilisée pour toutes les extensions.

Ce validateur accepte des extensions multiples soit sous la forme d'une chaîne utilisant
le caractère virgule (",") comme séparateur ou sous la forme d'un tableau. Vous pouvez
aussi utiliser les méthodes setExtension(), addExtension(), et getExtension() pour
paramétrer et récupérer les extensions.

Dans certains cas, il est utile vérifier aussi la casse. A cette fin le constructeur autorise un second
paramètre $case qui, s'il est réglé à TRUE, validera l'extension en vérifiant aussi la casse.

621
Zend_File

Exemple 353. Utiliser le validateur ExcludeExtension

$upload = new Zend_File_Transfer();

// Refuser les fichiers avec l'extension php ou exe


$upload->addValidator('ExcludeExtension', false, 'php,exe');

// Refuser les fichiers avec l'extension php ou exe en utilisant


// la notation de type tableau
$upload->addValidator('ExcludeExtension', false, array('php', 'exe'));

// Vérifier aussi la casse


$upload->addValidator('ExcludeExtension', false, array('php', 'exe', 'case' => true));

Notez que ce validateur ne vérifie que l'extension de fichier. Il ne vérifie pas le


type MIME réel du fichier.

2.5. Validateur ExcludeMimeType


Le validateur ExcludeMimeType vérifie le type MIME des fichiers transférés. Il supporte les
options suivantes :

• * : vous pouvez paramétrer n'importe quelle clé ou utiliser un tableau numérique. Paramètre
le type MIME à vérifier.

Avec cette option vous pouvez définir le(s) type(s) MIME que vous souhaitez exclure.

• headerCheck : si spécifié à TRUE, cette option va vérifier l'information HTTP concernant le


type de fichier quand les extensions fileInfo ou mimeMagic ne seront pas trouvées. La valeur
par défaut de cette option est FALSE.

Ce validateur accepte des types MIME multiples soit sous la forme d'une chaîne utilisant le
caractère virgule (",") comme séparateur ou sous la forme d'un tableau. Vous pouvez aussi
utiliser les méthodes setMimeType(), addMimeType(), et getMimeType() pour paramétrer
et récupérer les types MIME.

Exemple 354. Utiliser le validateur ExcludeMimeType

$upload = new Zend_File_Transfer();

// Refuser le type MIME d'image gif pour tous les fichiers


$upload->addValidator('ExcludeMimeType', false, 'image/gif');

// Refuser le type MIME d'image gif et jpg pour tous les fichiers
$upload->addValidator('ExcludeMimeType', false, array('image/gif', 'image/jpeg');

// Refuser les types MIME du groupe image pour tous les fichiers
$upload->addValidator('ExcludeMimeType', false, 'image');

L'exemple ci-dessus montre qu'il est aussi possible de limiter le type MIME accepté à un groupe
de type MIME. Pour refuser toutes les images utilisez simplement "image" en tant que type MIME.
Ceci peut être appliqué à tous les groupes de type MIME comme "image", "audio", "video", "text"
et plus encore.

622
Zend_File

Notez que refuser un groupe de type MIME refusera tous les membres de ce
groupe même si ce n'est pas votre intention. Par exemple quand vous refusez
"image", vous refusez donc "image/jpeg" ou "image/vasa". Quand vous n'êtes
pas sûr de vouloir refuser tous les types, vous devriez définir individuellement
les types MIME plutôt que le groupe complet.

2.6. Validateur Exists


Le validateur Exists l'existence des fichiers fournis. Il supporte les options suivantes :

• * : vous pouvez paramétrer n'importe quelle clé ou utiliser un tableau numérique. Vérifie si le
fichier existe dans le dossier fourni.

Ce validateur accepte des extensions multiples soit sous la forme d'une chaîne utilisant
le caractère virgule (",") comme séparateur ou sous la forme d'un tableau. Vous pouvez
aussi utiliser les méthodes setDirectory(), addDirectory(), et getDirectory() pour
paramétrer et récupérer les extensions.

Exemple 355. Utiliser le validateur Exists

$upload = new Zend_File_Transfer();

// Ajoute le dossier temporaire à vérifier


$upload->addValidator('Exists', false, '\temp');

// Ajoute deux dossiers en utilsant la notation de type tableau


$upload->addValidator('Exists',
false,
array('\home\images', '\home\uploads'));

Notez que ce validateur vérifie si le fichier existe dans tous les dossiers fournis.
La validation échoue si le fichier est manquant dans l'un des dossiers.

2.7. Validateur Extension


Le validateur Extension vérifie l'=es extensions des fichiers qui ont été fournis. Il supporte les
options suivantes :

• * : vous pouvez paramétrer n'importe quelle clé ou utiliser un tableau numérique. Paramètre
l'extension à vérifier.

• case : paramètre une validation sensible à la casse. Par défaut, la validation n'est pas sensible
à la casse. Notez que cette clé est utilisée pour toutes les extensions.

Ce validateur accepte des extensions multiples soit sous la forme d'une chaîne utilisant
le caractère virgule (",") comme séparateur ou sous la forme d'un tableau. Vous pouvez
aussi utiliser les méthodes setExtension(), addExtension(), et getExtension() pour
paramétrer et récupérer les extensions.

Dans certains cas, il est utile vérifier aussi la casse. A cette fin le constructeur autorise un second
paramètre $case qui, s'il est réglé à TRUE, validera l'extension en vérifiant aussi la casse.

623
Zend_File

Exemple 356. Utiliser le validateur Extension

$upload = new Zend_File_Transfer();

// Limite les extensions à jpg et png


$upload->addValidator('Extension', false, 'jpg,png');

// Limite les extensions à jpg et png en utilisant


// la notation de type tableau
$upload->addValidator('Extension', false, array('jpg', 'png'));

// Vérifie aussi la casse


$upload->addValidator('Extension', false, array('mo', 'png', 'case' => true));
if (!$upload->isValid('C:\temp\myfile.MO')) {
print 'Non valide à cause de MO au lieu de mo';
}

Notez que ce validateur ne vérifie que l'extension de fichier. Il ne vérifie pas le


type MIME réel du fichier.

2.8. Validateur FilesSize


Le validateur FilesSize vérifie le poids total de tous les fichiers transférés. Il supporte les
options suivantes :

• min : paramètre le poids minimum de tous les fichiers.

Avec cette option vous pouvez définir le poids minimum de tous les fichiers que vous souhaitez
transférer.

• max : paramètre le poids maximum de tous les fichiers.

Avec cette option vous pouvez limiter le poids total des fichiers qui doivent être transférés,
mais pas la taille individuelle de chaque fichier.

• bytestring : définit si un échec est retourné avec un taille plus facilement lisible pour
l'utilisateur, ou avec une taille de fichier brute.

Avec cette option vous pouvez en fait définir si l'utilisateur récupérera "10864" ou "10MB". La
valeur par défaut est TRUE qui retournera "10MB".

Vous pouvez initialiser seulement avec une chaîne qui sera utilisée en tant que max. Mais vous
pouvez aussi utiliser les méthodes setMin() et setMax() pour paramétrer ces options plus
tard et getMin() et getMax() pour les récupérer.

La taille elle-même est acceptée en notation SI comme sur la plupart des systèmes d'exploitation.
Au lieu de 20000 octets (NdT. : "bytes" en anglais), vous pouvez utiliser 20kB. Toutes les unités
sont converties en utilisant 1024 comme valeur de base. Les unités suivantes sont acceptées :
kB, MB, GB, TB, PB et EB. Comme mentionné précédemment vous devez noter que 1kB équivaut
à 1024 octets.

624
Zend_File

Exemple 357. Utiliser le validateur FilesSize

$upload = new Zend_File_Transfer();

// Limite la taille de tous les fichiers à 40000 octets


$upload->addValidator('FilesSize', false, 40000);

// Limite la taille de tous les fichiers dans une plage de 10kB à 4MB
$upload->addValidator('FilesSize', false, array('min' => '10kB',
'max' => '4MB'));

// Comme ci-dessus, mais retourne la taille de fichier brute plutôt qu'une chaîne
$upload->addValidator('FilesSize', false, array('min' => '10kB',
'max' => '4MB',
'bytestring' => false));

Notez que ce validateur stocke le poids des fichiers vérifiés en interne. Le fichier
qui excédera le poids maximum sera retourné en tant qu'erreur.

2.9. Validateur ImageSize


Le validateur ImageSize vérifie la taille des images. Il supporte les options suivantes :

• minheight : paramètre la hauteur minimum d'une image.

• maxheight : paramètre la hauteur maximum d'une image.

• minwidth : paramètre la largeur minimum d'une image.

• maxwidth : paramètre la largeur maximum d'une image.

Vous pouvez aussi utiliser les méthodes setImageMin() et setImageMax() pour régler les
valeurs minimum et maximum plus tard et getMin() et getMax() pour les récupérer.

Par commodité, il existe aussi les méthodes setImageWidth et setImageHeight qui


paramètrent la largeur et la hauteur minimum et maximum. Bien sûr les méthodes associées
getImageWidth et getImageHeight sont aussi disponibles.

Pour désactiver la validation d'une dimension, ne paramétrez pas l'option correspondante.

Exemple 358. Utiliser le validateur ImageSize

$upload = new Zend_File_Transfer();

// Limite la taille de l'image à une hauteur de 100 à 200 et


// une largeur de 40 à 80 pixels
$upload->addValidator('ImageSize',
false,
array('minwidth' => 40,
'maxwidth' => 80,
'minheight' => 100,
'maxheight' => 200);

// Autre possibilité de réglage


$upload->setImageWidth(array('minwidth' => 20, 'maxwidth' => 200));

625
Zend_File

2.10. Validateur IsCompressed


Le validateur IsCompressed vérifie si un fichier transféré est une archive compressée comme
zip ou arc. Ce validateur est basée sur le validateur MimeType et supportent les mêmes
méthodes et options. Vous pouvez limiter ce validateur à des types de compression particuliers
avec les méthodes décrites ci-dessous.

Exemple 359. Utiliser le validateur IsCompressed

$upload = new Zend_File_Transfer();

// Vérifie si un fichier uploadé est une archive compressée


$upload->addValidator('IsCompressed', false);

// Limite ce validateur aux fichiers zip seulement


$upload->addValidator('IsCompressed', false, array('application/zip'));

// Limite ce validateur aux fichiers zip mais avec la notation simplifiée


$upload->addValidator('IsCompressed', false, 'zip');

Notez qu'il n'y a pas de vérification si vous paramétrez un type de fichier qui n'est
pas un type de compression. Ainsi il est donc possible de définir que les fichiers
gif sont acceptés par ce validateur même si ce n'est pas logique.

2.11. Validateur IsImage


Le validateur IsImage vérifie si un fichier transféré est une image comme gif ou jpeg. Ce
validateur est basée sur le validateur MimeType et supportent les mêmes méthodes et options.
Vous pouvez limiter ce validateur à des types d'image particuliers avec les méthodes décrites
ci-dessous.

Exemple 360. Utiliser le validateur IsImage

$upload = new Zend_File_Transfer();

// Vérifie si un fichier uploadé est une image


$upload->addValidator('IsImage', false);

// Limite ce validateur aux fichiers gif seulement


$upload->addValidator('IsImage', false, array('application/gif'));

// Limite ce validateur aux fichiers jpeg mais avec la notation simplifiée


$upload->addValidator('IsImage', false, 'jpeg');

Notez qu'il n'y a pas de vérification si vous paramétrez un type de fichier qui n'est
pas un type d'image. Ainsi il est donc possible de définir que les fichiers zip sont
acceptés par ce validateur même si ce n'est pas logique.

2.12. Validateur Hash


Le validateur Hash vérifie le contenu du fichier transféré en le hachant. Ce validateur utilise
l'extension de hachage de PHP. Il supporte les options suivantes :

• * : vous pouvez paramétrer n'importe quelle clé ou utiliser un tableau numérique. Paramètre
la valeur de hachage qui doit être vérifié.

626
Zend_File

Vous pouvez paramétrer de multiples hachages en les fournissant sous la forme d'un tableau.
Chacun sera vérifié et seulement si tous échouent, la validation elle-même échouera.

• algorithm : paramètre l'algorithme à utiliser pour hacher le contenu.

Vous pouvez paramétrer de multiples algorithmes en utilisant la méthode addHash()


plusieurs fois.

Exemple 361. Utiliser le validateur Hash

$upload = new Zend_File_Transfer();

// Vérifie si le contenu d'un fichier uploadé correspond au hachage fourni


$upload->addValidator('Hash', false, '3b3652f');

// Limite ce validateur à deux différents hachages


$upload->addValidator('Hash', false, array('3b3652f', 'e612b69'));

// Paramètre un algorithme différent pour effectuer le hachage


$upload->addValidator('Hash', false, array('315b3cd8273d44912a7', 'algorithm' => 'md5'))

Ce validateur supporte environ 34 algorithmes de hachage différents. Les plus


connus sont "crc32", "md5" and "sha1". Si vous souhaitez connaître les autres
algorithmes, voyez la méthode hash_algos de PHP.

2.13. Validateur Md5


Le validateur Md5 vérifie le contenu du fichier transféré en le hachant. Ce validateur utilise
l'extension de hachage de PHP avec l'algorithme md5. Il supporte les options suivantes :

• * : vous pouvez paramétrer n'importe quelle clé ou utiliser un tableau numérique. Paramètre
la valeur de hachage qui doit être vérifié.

Vous pouvez paramétrer de multiples hachages en les fournissant sous la forme d'un tableau.
Chacun sera vérifié et seulement si tous échouent, la validation elle-même échouera.

Exemple 362. Utiliser le validateur Md5

$upload = new Zend_File_Transfer();

// Vérifie si le contenu d'un fichier uploadé correspond au hachage fourni


$upload->addValidator('Md5', false, '3b3652f336522365223');

// Limite ce validateur à deux différents hachages


$upload->addValidator('Md5', false, array('3b3652f336522365223', 'eb3365f3365ddc65365'))

2.14. Validateur MimeType


Le validateur MimeType vérifie le type MIME des fichiers transférés. Il supporte les options
suivantes :

• * : vous pouvez paramétrer n'importe quelle clé ou utiliser un tableau numérique. Paramètre
le type MIME à contrôler.

Avec cette option vous pouvez définir le type MIME des fichiers qui seront acceptés.

627
Zend_File

• headerCheck : si spécifié à TRUE, cette option va vérifier l'information HTTP concernant le


type de fichier quand les extensions fileInfo ou mimeMagic ne seront pas trouvées. La valeur
par défaut de cette option est FALSE.

• magicfile : le magicfile qui sera utilisé.

Avec cette option vous pouvez définir le magicfile à utiliser. Quand il n'est pas utilisé ou vide,
la constante MAGIC sera utilisée. Cette option est disponible à partir de la version 1.7.1 de
Zend Framework.

Ce validateur accepte des types MIME multiples soit sous la forme d'une chaîne utilisant le
caractère virgule (",") comme séparateur ou sous la forme d'un tableau. Vous pouvez aussi
utiliser les méthodes setMimeType(), addMimeType(), et getMimeType() pour paramétrer
et récupérer les types MIME.

Vous pouvez aussi paramétrer le magicfile qui sera utilisé par fileinfo avec l'option magicfile.
De plus il existe les méthodes setMagicFile() et getMagicFile() qui permettent de
paramétrer ou récupérer plus tard le paramètre magicfile. Ces méthodes sont disponibles à
partir de la version Zend Framework 1.7.1.

Exemple 363. Utiliser le validateur MimeType

$upload = new Zend_File_Transfer();

// Limite le type MIME de tous les fichiers aux images gif


$upload->addValidator('MimeType', false, 'image/gif');

// Limite le type MIME de tous les fichiers aux images jpeg et gif
$upload->adValidator('MimeType', false, array('image/gif', 'image/jpeg');

// Limite le type MIME de tous les fichiers au groupe des images


$upload->addValidator('MimeType', false, 'image');

// Utilise un magicfile différent


$upload->addValidator('MimeType', false, array('image', 'magicfile' => '/path/to/magicfi

L'exemple ci-dessus montre qu'il est aussi possible de limiter le type MIME accepté à un groupe
de type MIME. Pour autoriser toutes les images utilisez simplement "image" en tant que type
MIME. Ceci peut être appliqué à tous les groupes de type MIME comme "image", "audio", "video",
"text" et plus encore.

Notez qu'autoriser un groupe de type MIME acceptera tous les membres de ce


groupe même si votre application ne les supporte pas. Par exemple quand vous
autorisez "image", vous autorisez donc "image/xpixmap" ou "image/vasa", ce
qui peut être problématique. Quand vous n'êtes pas sûr que votre application
supporte tous les types, vous devriez définir individuellement les types MIME
plutôt que le groupe complet.

Ce composant utilise l'extension fileinfo si elle est disponible. Si ce n'est pas


le cas, il utilisera alors la fonction mime_content_type. Et si l'appel de fonction
échoue, il utilisera le type MIME fourni par HTTP.

Vous devez cependant être averti de possibles problèmes de sécurité si, ni


fileinfo, ni mime_content_type ne sont disponibles : le type MIME fourni
pas HTTP n'étant pas sécurisé et pouvant être facilement manipulé.

628
Zend_File

2.15. Validateur NotExists


Le validateur NotExists l'existence des fichiers fournis. Il supporte les options suivantes :

• * : vous pouvez paramétrer n'importe quelle clé ou utiliser un tableau numérique. Vérifie si le
fichier n'existe pas dans le dossier fourni.

Ce validateur accepte des extensions multiples soit sous la forme d'une chaîne utilisant
le caractère virgule (",") comme séparateur ou sous la forme d'un tableau. Vous pouvez
aussi utiliser les méthodes setDirectory(), addDirectory(), et getDirectory() pour
paramétrer et récupérer les extensions.

Exemple 364. Utiliser le validateur NotExists

$upload = new Zend_File_Transfer();

// Ajoute le dossier temporaire à vérifier


$upload->addValidator('NotExists', false, '\temp');

// Ajoute deux dossiers en utilisant la notation de type tableau


$upload->addValidator('NotExists',
false,
array('\home\images',
'\home\uploads'));

Notez que ce validateur vérifie si le fichier n'existe dans aucun des dossiers
fournis. La validation échoue si le fichier existe dans l'un des dossiers.

2.16. Validateur Sha1


Le validateur Sha1 vérifie le contenu du fichier transféré en le hachant. Ce validateur utilise
l'extension de hachage de PHP avec l'algorithme sha1. Il supporte les options suivantes :

• * : vous pouvez paramétrer n'importe quelle clé ou utiliser un tableau numérique. Paramètre
la valeur de hachage qui doit être vérifié.

Vous pouvez paramétrer de multiples hachages en les fournissant sous la forme d'un tableau.
Chacun sera vérifié et seulement si tous échouent, la validation elle-même échouera.

Exemple 365. Utiliser le validateur Sha1

$upload = new Zend_File_Transfer();

// Vérifie si le contenu d'un fichier uploadé correspond au hachage fourni


$upload->addValidator('Sha1', false, '3b3652f336522365223');

// Limite ce validateur à deux différents hachages


$upload->addValidator('Sha1', false, array('3b3652f336522365223', 'eb3365f3365ddc65365')

2.17. Validateur Size


Le validateur Size vérifie le poids d'un fichier unique. Il supporte les options suivantes :

• min : paramètre le poids minimum du fichier.

629
Zend_File

• max : paramètre le poids maximum du fichier.

• bytestring : définit si un échec est retourné avec un taille plus facilement lisible pour
l'utilisateur, ou avec une taille de fichier brute.

Avec cette option vous pouvez en fait définir si l'utilisateur récupérera "10864" ou "10MB". La
valeur par défaut est TRUE qui retournera "10MB".

Vous pouvez initialiser seulement avec une chaîne qui sera utilisée en tant que max. Mais vous
pouvez aussi utiliser les méthodes setMin() et setMax() pour paramétrer ces options plus
tard et getMin() et getMax() pour les récupérer.

Quand seule une chaîne est fournie, elle est utilisée en tant que max. Mais vous pouvez
aussi utiliser les méthodes setMin() et setMax() pour paramétrer ces options plus tard et
getMin() et getMax() pour les récupérer.

La taille elle-même est acceptée en notation SI comme sur la plupart des systèmes d'exploitation.
Au lieu de 20000 octets, vous pouvez utiliser 20kB. Toutes les unités sont converties en utilisant
1024 comme valeur de base. Les unités suivantes sont acceptées : kB, MB, GB, TB, PB et EB.
Comme mentionné précédemment vous devez noter que 1kB équivaut à 1024 octets.

Exemple 366. Utiliser le validateur Size

$upload = new Zend_File_Transfer();

// Limite la taille d'un fichier à 40000 octets


$upload->addValidator('Size', false, 40000);

// Limite la taille du fichier 'uploadfile' dans une plage de 10kB à 4MB


// Additionally returns the plain number in case of an error instead of a userfriendly o
$upload->addValidator('Size', false, array('min' => '10kB',
'max' => '4MB',
'bytestring' => false));

2.18. Validateur WordCount


Le validateur WordCount vérifie le nombre de mots à l'intérieur des fichiers fournis. Il supporte
les options suivantes :

• min : spécifie le nombre de mots minimum qui doivent être trouvés.

• max : spécifie le nombre de mots maximum qui doivent être trouvés.

Si vous initialisez ce validateur avec une chaîne ou un entier, la valeur sera utilisée en tant que
max. Mais vous pouvez aussi utiliser les méthodes setMin() et setMax() pour paramétrer
ces options plus tard et getMin() et getMax() pour les récupérer.

Exemple 367. Utiliser le validateur WordCount

$upload = new Zend_File_Transfer();

// Limite le nombre maximum de mots dans les fichiers à 2000


$upload->addValidator('WordCount', false, 2000);

// Limite le nombre de mots dans les fichiers entre un minimum de 1000


// et un maximum de 5000 mots
$upload->addValidator('WordCount', false, array('min' => 1000, 'max' => 5000));

630
Zend_File

3. Filtres pour Zend_File_Transfer


Zend_File_Transfer est fourni avec de multiples filtres qui peuvent être utilisés pour réaliser
différentes tâches qui doivent être réalisées souvent sur les fichier. Notez que tout filtre est
appliqué après la validation. De plus les filtres de fichiers se comportent légèrement différemment
des autres filtres. Ils retourneront toujours le nom de fichier et non le contenu modifié (ce qui
serait une mauvaise idée en travaillant avec un fichier d'1Go par exemple). Tous les filtres fournis
avec Zend_File_Transfer peuvent être trouvés dans le composant Zend_Filter et sont
nommés Zend_Filter_File_*. Les filtres suivants sont actuellement disponibles :

• Decrypt : ce filtre peut décrypter un fichier.

• Encrypt : ce filtre peut crypter un fichier.

• LowerCase : ce filtre peut mettre en minuscule le contenu d'un fichier texte.

• Rename : ce filtre peut renommer les fichiers, changer leur localisation et même forcer
l'écrasement de fichiers existants.

• UpperCase : ce filtre peut mettre en majuscule le contenu d'un fichier texte.

3.1. Utiliser les filtres avec Zend_File_Transfer


L'utilisation des filtres est assez simple. Il existe de multiples méthodes pour ajouter et manipuler
les filtres.

• addFilter($filter, $options = null, $files = null) : ajoute le filtre à la pile des


filtres (optionnellement seul le(s) fichier(s) spécifié(s)). $filter peut être soit une instance
d'un filtre réel, ou un nom court spécifiant le filtre (par exemple, "Rename").

• addFilters(array $filters, $files = null) : ajoute les filtres à la pile des filtres.
Chaque entrée peut être soit une paire type/options, ou un tableau avec la clé "filtre" spécifiant
le filtre (tous les autres options seront considérées comme des options du filtre au moment
de l'instanciation).

• setFilters(array $filters, $files = null) : surcharge les filtres existants avec


les filtres spécifiés. Les filtres doivent respecter la même syntaxe addFilters().

• hasFilter($name) : indique si le filtre est enregistré.

• getFilter($name) : retourne un filtre préalablement enregistré.

• getFilters($files = null) : retourne les filtres enregistrés ; si $files est fourni,


retourne les filtres pour ce fichier en particulier ou pour tous les fichiers.

• removeFilter($name) : enlève le filtre préalablement enregistré.

• clearFilters() : efface tous les filtres.

Exemple 368. Ajouter les filtres au fichier transféré

$upload = new Zend_File_Transfer();

// Paramètre un dossier de destination


$upload->addFilter('Rename', 'C:\image\uploads');

// Paramètre un nouveau dossier de destination


// et surcharge pour les fichiers existants
$upload->addFilter('Rename', array('target' => 'C:\picture\uploads', 'overwrite' => true

631
Zend_File

Exemple 369. Limiter les filtres à des fichiers uniques

addFilter(), addFilters(), and setFilters() accepte chacun un argument final


$files. Cet argument peut être utilisé pour spécifier un fichier en particulier ou un tableau
de fichiers sur lequel appliqué le filtre donné.

$upload = new Zend_File_Transfer();

// Paramètre un nouveau dossier de destination et


// le limite seulement à "file2"
$upload->addFilter('Rename', 'C:\image\uploads', 'file2');

Généralement vous devriez simplement utiliser la méthode addFilters(), qui peut être
appelée plusieurs fois.

Exemple 370. Ajouter des filtres multiples

Souvent il est plus simple d'appeler plusieurs fois addFilter() : un appel pour chaque
filtre. Ceci améliore aussi la lisibilité et rend votre code plus maintenable. Comme toutes les
méthodes fournissent un interface fluide, vous pouvez enchaîner les appels comme montré
ci-dessous :

$upload = new Zend_File_Transfer();

// Renommer différemment chacun des fichiers


$upload->addFilter('Rename', 'file1', 'C:\picture\newjpg')
->addFilter('Rename', 'file2', 'C:\picture\newgif');

Notez que même si l'ajout du même filtre plusieurs fois est autorisé, faire ceci
peut entraîner des problèmes si vous utilisez différentes options pour le même
filtre.

3.2. Filtre Decrypt


Le filtre Decrypt permet de décrypter un fichier crypté.

Ce filtre se sert de Zend_Filter_Decrypt. Il supporte les extensions PHP Mcrypt et


OpenSSL. Reportez vous à la section associée pour voir les détails des possibilités d'options
pour le décryptage et connaître les options supportées.

Ce filtre supporte une option additionnelle qui peut être utilisée pour sauvegarder le fichier
décrypté avec un autre nom de fichier. Spécifiez l'option filename pour changer le nom de
fichier dans lequel le fichier décrypté sera stocké. Si vous supprimez cette option le fichier
décrypté écrasera le fichier chiffré original.

Exemple 371. Utiliser le filtre Decrypt avec Mcrypt

$upload = new Zend_File_Transfer_Adapter_Http();

// Adds a filter to decrypt the uploaded encrypted file


// with mcrypt and the key mykey
$upload->addFilter('Decrypt',
array('adapter' => 'mcrypt', 'key' => 'mykey'));

632
Zend_File

Exemple 372. Utiliser le filtre Decrypt avec OpenSSL

$upload = new Zend_File_Transfer_Adapter_Http();

// Adds a filter to decrypt the uploaded encrypted file


// with openssl and the provided keys
$upload->addFilter('Decrypt',
array('adapter' => 'openssl',
'private' => '/path/to/privatekey.pem',
'envelope' => '/path/to/envelopekey.pem'));

3.3. Filtre Encrypt


Le filtre Encrypt permet de crypter un fichier.

Ce filtre se sert de Zend_Filter_Encrypt. Il supporte les extensions PHP Mcrypt et


OpenSSL. Reportez vous à la section associée pour voir les détails des possibilités d'options
pour le chiffrement et connaître les options supportées.

Ce filtre supporte une option additionnelle qui peut être utilisée pour sauvegarder le fichier chiffré
avec un autre nom de fichier. Spécifiez l'option filename pour changer le nom de fichier dans
lequel le fichier chiffré sera stocké. Si vous supprimez cette option le fichier chiffré écrasera le
fichier original.

Exemple 373. Utiliser le filtre Encrypt avec Mcrypt

$upload = new Zend_File_Transfer_Adapter_Http();

// Adds a filter to encrypt the uploaded file


// with mcrypt and the key mykey
$upload->addFilter('Encrypt',
array('adapter' => 'mcrypt', 'key' => 'mykey'));

Exemple 374. Utiliser le filtre Encrypt avec OpenSSL

$upload = new Zend_File_Transfer_Adapter_Http();

// Adds a filter to encrypt the uploaded file


// with openssl and the provided keys
$upload->addFilter('Encrypt',
array('adapter' => 'openssl',
'public' => '/path/to/publickey.pem'));

3.4. Filtre LowerCase


Le filtre LowerCase vous permet de mettre en minuscule le contenu d'un fichier. Vous devriez
utiliser ce filtre seulement sur les fichiers texte.

Lors de l'initialisation vous pouvez fournir qui sera utilisée en tant qu'encodage. Ou vous pouvez
utiliser la méthode setEncoding() pour le paramétrer plus tard.

633
Zend_File

Exemple 375. Utiliser le filtre LowerCase

$upload = new Zend_File_Transfer_Adapter_Http();


$upload->addValidator('MimeType', 'text');

// Ajoute un filtre pour mettre en minuscule les fichiers texte uploadés


$upload->addFilter('LowerCase');

// Ajoute un filtre pour mettre en minuscule seulement le fichier uploadé "uploadfile1"


$upload->addFilter('LowerCase', null, 'uploadfile1');

// Ajoute un filtre pour mettre en minuscule avec un encodage ISO-8859-1


$upload->addFilter('LowerCase', 'ISO-8859-1');

Notez que les options du filtre LowerCase sont optionnelles, vous devez fournir
un NULL en second paramètre quand vous souhaitez limiter le filtre à un fichier
unique.

3.5. Filtre Rename


Le filtre Rename vous permet de changer le dossier de destination du fichier uploadé, de changer
le nom de fichier et aussi d'écraser des fichiers existants. Il supporte les options suivantes :

• source : le nom et le dossier de l'ancien fichier qui doit être renommé.

• target : le nouveau dossier ou nom du fichier.

• overwrite : paramètre si l'ancien fichier écrase le nouveau fichier s'il existe déjà. La valeur
par défaut est FALSE.

De plus vous pouvez utiliser la méthode setFile() pour paramétrer des fichiers, ce qui effacera
ceux précédemment paramétrés, addFile() pour ajouter un nouveau fichier à ceux déjà
présent, et getFile() pour récupérer les fichiers actuellement paramétrés. Pour simplifier les
choses, ce filtre accepte de multiples notations et ces méthodes et constructeur comprennent
les mêmes notations.

Exemple 376. Utiliser le filtre Rename

$upload = new Zend_File_Transfer_Adapter_Http();

// Paramètre un nouveau dossier pour tous les fichiers


$upload->addFilter('Rename', 'C:\mypics\new');

// Paramètre un nouveau dossier seulement pour uploadfile1


$upload->addFilter('Rename', 'C:\mypics\newgifs', 'uploadfile1');

Vous pouvez utiliser différentes notations. Ci-dessous vous trouverez une table fournissant la
description et le but des notations supportées. Notez que quand vous utilisez l'"Adapter" ou le
"Form Element", vous ne pourrez pas utiliser toutes les notations décrites.

Tableau 62. Notations différentes du filtre "Rename" et leurs significations

notation description
addFile('C:\uploads') Spécifie un nouveau dossier pour tous les
fichiers quand la chaîne est un dossier. Notez

634
Zend_File

notation description
que vous aurez une exception si le fichier
existe déjà, voir le paramètre d'écrasement.
addFile('C:\uploads\file.ext') Spécifie un nouveau dossier et un nom de
fichier pour tous les fichiers quand la chaîne
n'est pas un dossier. Notez que vous aurez
une exception si le fichier existe déjà, voir le
paramètre d'écrasement.
addFile('C:\uploads\file.ext', 'overwrite' => Spécifie un nouveau dossier et un nom
true) de fichier pour tous les fichiers quand la
chaîne n'est pas un dossier et écrase le
fichier existant si celui-ci existe. Notez
que vous aurez pas de notification en cas
d'écrasement.
addFile(array('source' => 'C:\temp\uploads', Spécifie un nouveau dossier pour tous les
'target' => 'C:\uploads')) fichiers qui sont présent dans l'ancien dossier
quand la chaîne est un dossier. Notez que
vous aurez une exception si le fichier existe
déjà, voir le paramètre d'écrasement.
addFile(array('source' => 'C:\temp\uploads', Spécifie un nouveau dossier pour tous
'target' => 'C:\uploads', 'overwrite' => true)) les fichiers qui sont présent dans l'ancien
dossier quand la chaîne est un dossier. Notez
que vous aurez pas de notification en cas
d'écrasement.

3.6. Filtre UpperCase


Le filtre UpperCase vous permet de mettre en minuscule le contenu d'un fichier. Vous devriez
utiliser ce filtre seulement sur les fichiers texte.

Lors de l'initialisation vous pouvez fournir qui sera utilisée en tant qu'encodage. Ou vous pouvez
utiliser la méthode setEncoding() pour le paramétrer plus tard.

Exemple 377. Utiliser le filtre UpperCase

$upload = new Zend_File_Transfer_Adapter_Http();


$upload->addValidator('MimeType', 'text');

// Ajoute un filtre pour mettre en majuscule les fichiers textes uploadés


$upload->addFilter('UpperCase');

// Ajoute un filtre pour mettre en majuscule seulement le fichier uploadé "uploadfile1"


$upload->addFilter('UpperCase', null, 'uploadfile1');

// Ajoute un filtre pour mettre en majuscule avec un encodage ISO-8859-1


$upload->addFilter('UpperCase', 'ISO-8859-1');

Notez que les options du filtre UpperCase sont optionnelles, vous devez fournir
un NULL en second paramètre quand vous souhaitez limiter le filtre à un fichier
unique.

635
Zend_Filter
1. Introduction
Le composant Zend_Filter fournit un ensemble de filtres de données usuel. Il fournit
également un mécanisme simple de chaînage par lequel plusieurs filtres peuvent être appliqués
à une donnée dans un ordre défini.

1.1. Qu'est-ce qu'un filtre ?


Généralement parlant, un filtre est utilisé pour supprimer les parties non désirées de ce qui lui est
soumis tout en laissant passer la partie désirée. Dans ce cas de figure, un filtre est une opération
qui restitue une partie de la donnée soumise. Ce type de filtrage est utile pour les applications
Web : suppression des données soumises non conformes, élimination des espaces inutiles, etc.

Cette définition simple d'un filtre peut être étendue pour inclure des transformations généralisées
aux données soumises. Une transformation communément requise dans les applications Web
consiste à échapper les entités HTML. Ainsi, si un champ de formulaire est automatiquement
transmis et contient des données non vérifiées (provenant par exemple d'un navigateur Web),
ces données doivent être purgées de leurs entités HTML ou bien contenir uniquement des
entités HTML échappées, de manière à se garantir contre des comportements non désirés
et les vulnérabilités de sécurité. Afin d'assurer cette opération, les entités HTML qui sont
présentes dans les données saisies doivent être soit supprimées soit échappées. Naturellement,
l'approche adéquate dépend du contexte. Un filtre de suppression des entités HTML opère
dans le contexte défini plus haut : une opération produisant un sous-ensemble à partir d'une
donnée soumise. Cependant, un filtre échappant les entités HTML transforme la valeur entrée
(par exemple, "&" sera transformé en "&amp;". Permettre de telles choses est important pour les
développeurs Web et "filtrer" dans le contexte d'utilisation de Zend_Filter consiste à réaliser
des transformations sur les données soumises.

1.2. Utilisation basique des filtres


Avoir cette définition d'un filtre établie fournit la base pour Zend_Filter_Interface, qui
nécessitent une méthode unique nommée filter() pour être implémentée par une classe de
filtre.

L'exemple simple ci-dessous démontre l'utilisation d'un filtre sur les caractères esperluette (&,
"ampersand" en anglais) et guillemet double (") :

$htmlEntities = new Zend_Filter_HtmlEntities();

echo $htmlEntities->filter('&'); // &


echo $htmlEntities->filter('"'); // >

1.3. Utilisation de la méthode statique staticFilter()


S'il est peu pratique de charger une classe de filtre donnée et créer une instance du filtre,
vous pouvez utiliser la méthode statique Zend_Filter::get() comme appel alternatif. Le
premier argument de cette méthode est une valeur de saisie de données, que vous passeriez
à la méthode filter(). Le deuxième argument est une chaîne, qui correspond au nom de
base de la classe de filtre, relativement dans l'espace de nommage Zend_Filter. La méthode

636
Zend_Filter

staticFilter() charge automatiquement la classe, crée une instance et applique la méthode


filter() à la donnée saisie.

echo Zend_Filter::get('&', 'HtmlEntities');

Vous pouvez aussi fournir un tableau de paramètres destinés au constructeur de la classe, s'ils
sont nécessaires pour votre classe de filtre.

echo Zend_Filter::filterStatic('"',
'HtmlEntities',
array('quotestyle' => ENT_QUOTES));

L'utilisation statique peut être pratique pour invoquer un filtre ad hoc, mais si vous avez besoin
d'exécuter un filtre pour des saisies multiples, il est plus efficace de suivre le premier exemple
ci-dessus, créant une instance de l'objet de filtre et appelant sa méthode filter().

De plus, la classe Zend_Filter_Input vous permet d'instancier et d'exécuter des filtres


multiples et des classes de validateurs sur demande pour traiter l'ensemble de données saisies.
Voir Section 5, « Zend_Filter_Input ».

2. Classes de filtre standards


Zend Framework est fourni avec un jeu de filtres standards, qui sont directement utilisables.

2.1. Alnum
Retourne la chaîne $value, en retirant tout sauf les caractères alphabétiques et numériques.
Ce filtre inclue une option permettant d'autoriser ou non les caractères espace.

Les caractères alphabétiques comprennent les caractères destinés à constituer


des mots dans chaque langue. Cependant l'alphabet anglais est aussi utilisé pour
les langues suivantes : chinois, japonais et coréen. La langue est spécifiée par
Zend_Locale.

2.2. Alpha
Retourne la chaîne $value, en retirant tout sauf les caractères alphabétiques. Ce filtre inclue
une option permettant d'autoriser ou non les caractères espace.

2.3. BaseName
En passant une chaîne contenant un chemin vers un fichier, ce filtre retourne le nom de base
du fichier.

2.4. Boolean
Ce filtre transforme toute donnée en valeur BOOLEENNE. Ce peut être utile en travaillant avec
des bases de données ou des formulaires.

2.4.1. Comportement par défaut de Zend_Filter_Boolean


Par défaut, ce filtre caste (transtype) sa valeur vers un BOOLEEN ; en d'autres termes, il fonctionne
comme un appel PHP (boolean) $value.

637
Zend_Filter

$filter = new Zend_Filter_Boolean();


$value = '';
$result = $filter->filter($value);
// retourne false

Ceci signifie que sans paramètre additionnel, Zend_Filter_Boolean prend toute valeur
d'entrée et retourne un BOOLEEN comme le cast PHP vers le BOOLEEN.

2.4.2. Changer le comportement de Zend_Filter_Boolean


Quelques fois, le cast vers tel que (boolean) peut ne pas suffire. Zend_Filter_Boolean
permet ainsi de configurer les types d'entrée à convertir, et ceux à ignorer.

Les types suivants sont acceptés:

• booléen: Retourne la valeur booléenne telle quelle.

• entier: Convertit l'entier 0 vers FALSE.

• flottant: Convertit le flottant 0.0 vers FALSE.

• chaine: Convertit la chaine vide '' vers FALSE.

• zero: Convertit la chaine contenant zéro ('0') vers FALSE.

• empty_array: Convertit la tableau vide array() vers FALSE.

• null: Convertit une valeur NULL vers FALSE.

• php: Convertit une valeur comme PHP le ferait vers le BOOLEEN.

• false_string: Convertit une chaine contenant le mot "false" vers le booléen FALSE.

• yes: Convertit une chaine localisée contenant le mot "no" vers FALSE.

• all: Convertit tous les types ci-dessus vers un BOOLEEN.

Toute autre valeur fournie retournera TRUE.

Pour préciser les optiosn ci-dessus, plusieurs manières sont données : utilisez des chaines, des
constantes, ajoutez les, utilisez des tableaux... Voyez l'exemple:

// convertit 0 vers false


$filter = new Zend_Filter_Boolean(Zend_Filter_Boolean::INTEGER);

// convertit 0 et '0' vers false


$filter = new Zend_Filter_Boolean(
Zend_Filter_Boolean::INTEGER + Zend_Filter_Boolean::ZERO
);

// convertit 0 et '0' vers false


$filter = new Zend_Filter_Boolean(array(
'type' => array(
Zend_Filter_Boolean::INTEGER,
Zend_Filter_Boolean::ZERO,
),
));

638
Zend_Filter

// convertit 0 et '0' vers false


$filter = new Zend_Filter_Boolean(array(
'type' => array(
'integer',
'zero',
),
));

Vous pouvez aussi passer une instance de Zend_Config pour préciser les options. Pour
préciser ces options après la création de votre objet, utilisez la méthode setType().

2.4.3. Booléens localisés


Comme déja précisé, Zend_Filter_Boolean reconnait les chaines localisées "yes" et "no".
Ceci signifie que vous pouvez demander au client au travers d'un formulaire "oui" ou "non" dans
sa propre langue et Zend_Filter_Boolean convertira la valeur vers le booléen approprié.

Préciser la locale s'effectue grâce à la clé de configuration locale ou la méthode setLocale().

$filter = new Zend_Filter_Boolean(array(


'type' => Zend_Filter_Boolean::ALL,
'locale' => 'de',
));

// retourne false
echo $filter->filter('nein');

$filter->setLocale('en');

// retourne true
$filter->filter('yes');

2.4.4. Désactiver le cast (transtypage)


Il peut arriver de ne vouloir que reconnaitre TRUE ou FALSE et donc retourner les autres valeurs
telles quelles. Zend_Filter_Boolean permet un tel comportement via son option casting
lorsque réglée sur FALSE.

Dans un tel cas, Zend_Filter_Boolean fonctionnera comme décrit dans le tableau ci-
dessous qui montre quelles valeurs retournent TRUE ou FALSE. Toute autre valeur non présente
dans ce tableau sera retournée telle quelle lorsque l'option casting est à FALSE

Tableau 63. Utilisation sans transtypage

Type True False


Zend_Filter_Boolean::BOOLEAN
TRUE FALSE
Zend_Filter_Boolean::INTEGER0 1
Zend_Filter_Boolean::FLOAT 0.0 1.0
Zend_Filter_Boolean::STRING ""
Zend_Filter_Boolean::ZERO "0" "1"
Zend_Filter_Boolean::EMPTY_ARRAY
array()
Zend_Filter_Boolean::NULL NULL

639
Zend_Filter

Type True False


Zend_Filter_Boolean::FALSE_STRING
"false" (non sensible à la "true" (non sensible à la casse)
casse)
Zend_Filter_Boolean::YES "oui" localisé (non sensible à la "non" localisé (non sensible à
casse) la casse)

L'exemple qui suit illustre l'utilisation de l'option casting:

$filter = new Zend_Filter_Boolean(array(


'type' => Zend_Filter_Boolean::ALL,
'casting' => false,
));

// retourne false
echo $filter->filter(0);

// retourne true
echo $filter->filter(1);

// retourne la valeur
echo $filter->filter(2);

2.5. Callback
Ce filtre vous permet d'utiliser votre propre fonction en tant que filtre de Zend_Filter. Nul
besoin de créer un filtre si une fonction ou méthode fait déja le travail.

Par exemple un filtre qui inverse une chaine.

$filter = new Zend_Filter_Callback('strrev');

print $filter->filter('Hello!');
// retourne "!olleH"

C'est très simple de passer une fonction à appliquer comme filtre. Dans le cas de méthodes de
classes, passez un tableau comme callback.

// Notre classe
class MyClass
{
public function Reverse($param);
}

// La définition du filtre
$filter = new Zend_Filter_Callback(array('MyClass', 'Reverse'));
print $filter->filter('Hello!');

Pour récupérer la fonction de filtrage actuelle, utilisez getCallback() et pour en affecter une
nouvelle, utilisez setCallback().

Il est aussi possible de définir des paramètres par défaut qui sont alors passés à la méthode
appelée lorsque le filtre est exécuté.

$filter = new Zend_Filter_Callback(


array(

640
Zend_Filter

'callback' => 'MyMethod',


'options' => array('key' => 'param1', 'key2' => 'param2')
)
);
$filter->filter(array('value' => 'Hello'));

L'appel manuel à une telle fonction se serait fait comme cela:

$value = MyMethod('Hello', 'param1', 'param2');

Notez que passer une fonction qui ne peut être appelée mènera à une exception.

2.6. Compression et décompression


Ces deux filtres sont capables de compresser et décompresser des chaines, des fichiers ou des
dossiers. Ils utilisent des adaptateurs dans ce but et supportent les formats suivants:

• Bz2

• Gz

• Lzf

• Rar

• Tar

• Zip

Chaque format de compression possède des caractéristiques propres et ils s'utilisent tous d'une
manière commune. Seules leurs options vont différer ainsi que les types de compressions qu'ils
offrent (algorithmes, fichiers, chaines et dossiers)

2.6.1. Les bases


Pour créer un filtre de compression vous devez sélectionner le format que vous désirez. La
description suivante utilisera l'adaptateur Bz2. Les détails des autres adaptateurs seront précisés
plus tard dans la section suivante.

Les deux filtres (compression et décompression) sont identiques lorsqu'ils utilisent le


même adaptateur. Simplement Zend_Filter_Compress est utilisé pour les opérations de
compression alors que Zend_Filter_Decompress est utilisé pour la décompression.

Par exemple, si nous voulons compresser une chaine nous devons instancier
Zend_Filter_Compress et indiquer un adaptateur.

$filter = new Zend_Filter_Compress('Bz2');

Les adaptateurs se spécifient donc dans le constructeur.

Il est aussi possible de passer des options sous forme de tableau ou d'objet Zend_Config. Si
vous souhaitez préciser des options, vous devez alors au minimum indiquer la clé "adapter".
Les clés "options" ou "adapterOptions" peuvent ensuite être utilisées et doivent représenter un
tableau.

641
Zend_Filter

$filter = new Zend_Filter_Compress(array(


'adapter' => 'Bz2',
'options' => array(
'blocksize' => 8,
),
));

Adaptateur de compression par défaut


Lorsque vous ne précisez aucun adaptateur, Gz sera utilisé par défaut.

Concernant la décompression, le principe est exactement identique.

$filter = new Zend_Filter_Decompress('Bz2');

Pour récupérer une chaine compressée, il faut indiquer la chaine originale. La valeur "filtrée"
récupérée sera alors la chaine compressée, tout simplement.

$filter = new Zend_Filter_Compress('Bz2');


$compressed = $filter->filter('Uncompressed string');
// Retourne la chaine compressée

La décompression suit exactement le même principe.

$filter = new Zend_Filter_Decompress('Bz2');


$compressed = $filter->filter('Compressed string');
// Retourne la chaine décompressée

Note sur la compression de chaines


Tous les adaptateurs ne supportent pas la compression de chaines. Les formats
tels que Rar ne savent que traiter des fichiers ou des répertoires. Pour les détails,
consultez la documentation relative à l'adaptateur en question.

2.6.2. Créer une archive


Créer une archive fonctionne quasiment de la même manière que la compression d'une chaine.
Cependant dans ce cas, nous devons préciser une options supplémentaire indiquant le nom de
l'archive à créer.

$filter = new Zend_Filter_Compress(array(


'adapter' => 'Bz2',
'options' => array(
'archive' => 'filename.bz2',
),
));
$compressed = $filter->filter('Uncompressed string');
// Retourne true en cas de succès et crée le fichier d'archive

Dans l'exemple ci-dessus, la chaine est compressée puis retournée dans une archive.

Les archives existantes seront écrasées


Si l'archive existe déja, elle sera écrasée.

642
Zend_Filter

Si vous souhaitez compresser un fichier, vous devez fournir son chemin.

$filter = new Zend_Filter_Compress(array(


'adapter' => 'Bz2',
'options' => array(
'archive' => 'filename.bz2'
),
));
$compressed = $filter->filter('C:\temp\compressme.txt');
// Retourne true en cas de succès et crée le fichier d'archive

Il est aussi possible de préciser le nom d'un dossier plutôt que d'un fichier. Dans ce cas, tout le
dossier sera compressé, récursivement.

$filter = new Zend_Filter_Compress(array(


'adapter' => 'Bz2',
'options' => array(
'archive' => 'filename.bz2'
),
));
$compressed = $filter->filter('C:\temp\somedir');
// Retourne true en cas de succès et crée le fichier d'archive

Ne compressez pas un dossier trop gros ou trop profond


Vous ne devriez jamais tenter de compresser un dossier trop gros ou trop
profond, comme par exemple une partition complète. Une telle opération s'avère
très longue et très couteuse en ressources ce qui peut provoquer des problèmes
sur votre serveur.

2.6.3. Décompresser une archive


Décompresser une archive s'éxecute d'une manière sensiblement identique à la compression.
Vous devez passer le paramètre archive ou préciser le nom du fichier.

$filter = new Zend_Filter_Decompress('Bz2');


$compressed = $filter->filter('filename.bz2');
// Retourne true en cas de succès et décompresse le fichier d'archive

Certains adaptateurs permettent la décompression d'une archive dans un dossier cible, dans ce
cas le paramètre target permet de l'indiquer.

$filter = new Zend_Filter_Decompress(array(


'adapter' => 'Zip',
'options' => array(
'target' => 'C:\temp',
)
));
$compressed = $filter->filter('filename.zip');
// Retourne true en cas de succès et décompresse le fichier d'archive
// dans le dossier spécifié

Les dossiers de cible doivent exister


Lorsque vous souhaitez décompresser une archive dans un dossier cible, vérifiez
bien que celui-ci existe déja.

643
Zend_Filter

2.6.4. Adaptateur Bz2


L'adaptateur Bz2 peut compresser et décompresser:

• Chaines

• Fichiers

• Dossiers

Cet adaptateur utilise l'extension PHP Bz2.

Pour personnaliser la compression, cet adaptateur utilise les options suivantes:

• Archive: Précise l'archive à utiliser ou à créer.

• Blocksize: Précise la taille des blocs. Des valeurs de '0' à '9' sont permises. La valeur par
défaut est '4'.

Toutes les options peuvent être passées à l'instanciation ou en utilisant des méthodes. Par
exemple pour la tailles des blocs, getBlocksize() et setBlocksize(). La méthode
setOptions() est aussi présente, elle accepte un tableau

2.6.5. Adaptateur Gz
L'adaptateur Bz2 peut compresser et décompresser:

• Chaines

• Fichiers

• Dossiers

Cet adaptateur utilise l'extension PHP Zlib.

Pour personnaliser la compression, cet adaptateur utilise les options suivantes:

• Archive: L'archive à créer ou à utiliser.

• Level: Niveau de compression. Des valeurs de '0' à '9' sont utilisables, par défaut : '9'.

• Mode: Il existe deux modes supportés : 'compress' et 'deflate'. La valeur par défaut est
'compress'.

Toutes les options peuvent être passées en constructeur ou en utilisant des méthodes. Par
exemple, pour l'option 'Level', getLevel() et setLevel(). La méthode setOptions() est
aussi présente et accepte un tableau.

2.6.6. Adaptateur Lzf


L'adaptateur Lzf peut compresser et décompresser:

• Chaines

Lzf ne supporte que les chaines de caractères


Lzf ne supporte pas les fichiers et les dossiers.

644
Zend_Filter

Cet adaptateur utilise l'extension PHPLzf.

Il n'existe pas d'options pour personnaliser cet adaptateur.

2.6.7. Adaptateur Rar


L'adaptateur Rar peut compresser et décompresser:

• Fichiers

• Dossiers

Rar ne supporte pas les chaines de caractères

L'adaptateur Rar ne supporte pas les chaines de caractères

Cet adaptateur utilise l'extension PHP Rar.

Compression Rar non supportée

Des restrictions du format Rar ne permettent pas la compression gratuite. Si vous


souhaitez compresser avec cet adaptateur, vous devrez passer une fonction de
callback qui utilisera un algorithme ou fera appel à un programme externe.

Cet adaptateur accepte les options suivantes:

• Archive: Précise l'archive à créer ou à utiliser.

• Callback: Une fonction de callback fournissant des services de compression à l'adaptateur.

• Password: Le mot de passe à utiliser éventuellement en cas de décompression.

• Target: La cible vers laquelle les fichiers décompressés seront écrits.

Toutes les options peuvent être passées au constructeurs ou via des méthodes. Par exemple,
pour l'option 'Target', getTarget() et setTarget().La méthode setOptions() est aussi
disponible et accepte un tableau.

2.6.8. Tar Adapter


L'adaptateur Tar peut compresser et décompresser:

• Fichiers

• Dossiers

Tar ne supporte pas les chaines de caractères

L'adaptateur Tar ne supporte pas les chaines de caractères

Cet adaptateur utilise le paquet PEAR Archive_Tar.

Cet adaptateur accepte les options suivantes:

• Archive: Précise l'archive à utiliser ou à créer.

645
Zend_Filter

• Mode: Mode de compression. Les modes supportés sont 'null' qui signifie pas de compression,
'Gz' qui utilisera l'extension PHP Zlib et 'Bz2' qui utilisera l'extension PHPBz2. La valeur par
défaut est 'null'.

• Target: La cible vers laquelle les fichier décompressés seront écrits.

Toutes les options peuvent être passées au constructeurs ou via des méthodes. Par exemple,
pour l'option 'Target', getTarget() et setTarget().La méthode setOptions() est aussi
disponible et accepte un tableau.

Utilisation avec des dossiers

La compression des dossiers avec Tar utilise le chemin complet comme nom de
fichier.

2.6.9. Adaptateur Zip


L'adaptateur Zip peut compresser et décompresser:

• Chaines

• Fichiers

• Dossiers

Zip ne supporte pas la décompression vers des chaines

L'adaptateur Zip ne supporte pas la décompression vers des chaines. Un fichier


sera systématiquement crée.

Cet adaptateur utilise l'extension PHP Zip.

Les options suivantes sont supportées :

• Archive: Précise l'archive qui sera utilisée ou créee.

• Target: La cible vers laquelle décompresser.

Toutes les options peuvent être passées au constructeurs ou via des méthodes. Par exemple,
pour l'option 'Target', getTarget() et setTarget().La méthode setOptions() est aussi
disponible et accepte un tableau.

2.7. Decrypt
Ce filtre va décrypter toute chaine grâce aux paramètres utilisés. Des adaptateurs sont utilisés.
Actuellement des aptateurs existent pour les extensions Mcrypt et OpenSSL de php.

Pour plus de détails sur l'encryptage de contenu, voyez le filtre Encrypt. La documentation
de celui-ci couvre les bases en matière de cryptage, nous n'aborderons ici que les méthodes
utilisées pour le décryptage.

2.7.1. Décryptage avec Mcrypt


Pour décrypter une données cryptées avec Mcrypt, vous avez besoin des paramètres utilisés
pour encrypter, ainsi que du vecteur.

646
Zend_Filter

Si vous n'aviez pas passé de vecteur spécifique à l'encryptage, alors vous devriez récupérer
le vecteur utilisé grâce à la méthode getVector(). Sans ce vecteur, aucun décryptage de la
données originale n'est possible.

Le décryptage s'effectue aussi simplement que l'encryptage.

// Utilisation des paramètres blowfish par défaut


$filter = new Zend_Filter_Decrypt('myencryptionkey');

// Utilisation du vecteur utilisé lors de l'encryptage


$filter->setVector('myvector');

$decrypted = $filter->filter('texte_encodé_non_lisible');
print $decrypted;

Si l'extension mcrypt n'est pas présente dans votre environement, une exception
sera levée.

Vos paramètres sont vérifiés à la création de l'instance ou à l'appel de


setEncryption(). Si mcrypt détecte des problèmes avec ces paramètres, une
exception sera levée.

2.7.2. Decryptage avec OpenSSL


Le décryptage avec OpenSSL est aussi simple que l'encryptage. Mais vous aurez besoin de
toutes les données concernant la personne ayant crypté la donnée de référence.

Pour décrypter avec OpenSSL vous devez posséder:

• private: Votre clé privée. Ce peut être un nom de fichier ou juste le contenu de ce fichier : la clé.

• envelope: La clé enveloppe cryptée de l'utilisateur qui a crypté le document. Un chemin de


fichier ou une chaine peuvent être utilisés.

// Utilise OpenSSL avec une clé spécifiée


$filter = new Zend_Filter_Decrypt(array(
'adapter' => 'openssl',
'private' => '/path/to/mykey/private.pem'
));

// Passage des clés enveloppe


$filter->setEnvelopeKey(array(
'/key/from/encoder/first.pem',
'/key/from/encoder/second.pem'
));

L'adaptateur OpenSSL ne fonctionnera pas avec des clés non valides.

Optionnellement il peut être nécessaire de passer la passphrase pour décrypter les clés elles-
mêmes. Utilisez alors setPassphrase().

// Utilise OpenSSL avec une clé spécifiée

647
Zend_Filter

$filter = new Zend_Filter_Decrypt(array(


'adapter' => 'openssl',
'private' => '/path/to/mykey/private.pem'
));

// Passage des clés enveloppe


$filter->setEnvelopeKey(array(
'/key/from/encoder/first.pem',
'/key/from/encoder/second.pem'
));
$filter->setPassphrase('mypassphrase');

Enfin, décryptez le contenu. Voici l'exemple complet:

// Utilise OpenSSL avec une clé spécifiée


$filter = new Zend_Filter_Decrypt(array(
'adapter' => 'openssl',
'private' => '/path/to/mykey/private.pem'
));

// Passage des clés enveloppe


$filter->setEnvelopeKey(array(
'/key/from/encoder/first.pem',
'/key/from/encoder/second.pem'
));
$filter->setPassphrase('mypassphrase');

$decrypted = $filter->filter('texte_encodé_illisible');
print $decrypted;

2.8. Digits
Retourne la chaîne $value, en retirant tout sauf les caractères numériques.

2.9. Dir
Retourne la partie correspondant au nom de dossier dans le chemin spécifié.

2.10. Encrypt
Ce filtre va crypter toute chaine avec les paramètres spécifiés. Des adaptateurs sont utilisés.
Actuellement, il existe des adaptateurs pour les extensions PHP Mcrypt et OpenSSL.

Comme ces deux méthodes d'encryptage sont très différentes, l'utilisation de leurs adaptateurs
l'est aussi.

// Utiliser Mcrypt
$filter1 = new Zend_Filter_Encrypt(array('adapter' => 'mcrypt'));

// Utiliser OpenSSL
$filter2 = new Zend_Filter_Encrypt(array('adapter' => 'openssl'));

Les méthodes setAdapter() et getAdapter() existent aussi.

// Utiliser Mcrypt
$filter = new Zend_Filter_Encrypt();
$filter->setAdapter('openssl');

648
Zend_Filter

Si vous ne précisez pas d'adaptateur, Mcrypt est utilisé par défaut.

2.10.1. Cryptage avec Mcrypt


Cet adaptateur nécessite la présence de l'extension PHP Mcrypt. Voici ses options:

• key: La clé d'encryptage. Cette même clé sera nécessaire pour le décryptage.

• algorithm: L'algorithme à utiliser pour le cryptage. Voyez PHP's mcrypt ciphers. Si non précisé,
blowfish sera utilisé par défaut.

• algorithm_directory: Le dossier dans lequel se trouve l'algorithme. Si non précisé, le dossier


spécifié par l'extension mcrypt est alors utilisé.

• mode: Le mode de cryptage à utiliser. Un des modes mcrypt doit être utilisé. Par défaut, cbc
est utilisé.

• mode_directory: Le dossier dans lequel se trouve le mode. Si non précisé, le dossier spécifié
par l'extension mcrypt est alors utilisé.

• vector: Le vecteur d'initialisation à utiliser. Un vecteur aléatoire est utilisé si non précisé.

• salt: Si la clé doit être utilisé comme grain de sel. Dans ce cas la clé utilisée pour le cryptage
sera elle même cryptée. Par défaut false : ce n'est pas le cas.

Si vous passez une chaine à la place d'un tableau pour la clé, celle-ci sera utilisée.

Les méthodes getEncryption() et setEncryption() sont aussi présentes.

Une exception sera levée si l'extension PHP mcrypt n'est pas disponible.

Notez aussi que tous vos paramètres utilisés à la création de l'instance ou avec
setEncryption() vont être vérifiés. Si mcrypt détecte un problème, une exception
sera levée.

getVector() et setVector() sont aussi disponibles si besoin. Une chaine passée sera mise
à la taille du vecteur pour être utilisée avec l'algorithme en cours.

Notez que si vous n'utilisez pas un vecteur spécifique, alors vous devrez le
récupérer et le stocker. En effet, celui-ci est indispensable pour décoder la valeur
dans le futur.

// Utilise blowfish par défaut


$filter = new Zend_Filter_Encrypt('myencryptionkey');

// Affecte un vecteur précis.


$filter->setVector('myvector');
// $filter->getVector(); est nécessaire sinon, pour décoder la valeur plus tard

649
Zend_Filter

$encrypted = $filter->filter('text_to_be_encoded');
print $encrypted;

// Pour le décryptage, voyez le code du filtre Decrypt

2.10.2. Cryptage avec OpenSSL


Lorsque vous avez installé l'extension PHP OpenSSL, vous pouvez utiliser l'adaptateur du même
nom, dont voici les options d'instanciation:

• public: La clé publique de l'utilisateur auquel vous voulez proposer du contenu crypté.
Plusieurs clés peuvent être spécifiées via un tableau. Il est possible de préciser le contenu de
la clé, ou alors un chemin vers une clé.

• private: Votre clé privée utilisée pour crypter le contenu. La encore la clé peut être précisée
sous forme textuelle, ou alors un chemin vers un fichier contenant la clé.

getPublicKey() et setPublicKey() sont aussi présentes, ainsi que getPrivateKey()


et setPrivateKey().

// Utiliser openssl
$filter = new Zend_Filter_Encrypt(array(
'adapter' => 'openssl',
'private' => '/path/to/mykey/private.pem'
));

// utilisation des méthodes


$filter->setPublicKey(array(
'/public/key/path/first.pem',
'/public/key/path/second.pem'
));

Attention l'adaptateur OpenSSL ne fonctionnera pas si vous ne passez pas des


clés valides.

Si vous souhaitez encoder aussi les clés, passez alors une passphrase via setPassphrase().
Attention, la passphrase sera nécessaire pour décoder les clés.

// Utilise openssl avec une clé privée


$filter = new Zend_Filter_Encrypt(array(
'adapter' => 'openssl',
'private' => '/path/to/mykey/private.pem'
));

// utilisation des méthodes pour specifier la clé publique


$filter->setPublicKey(array(
'/public/key/path/first.pem',
'/public/key/path/second.pem'
));
$filter->setPassphrase('mypassphrase');

Pour décrypter le document, la passphrase (si utilisée) et les clés enveloppe sont nécessaires.

Ceci signifie que vous devez appeler la méthode getEnvelopeKey() après le cryptage pour
récupérer l'enveloppe.

650
Zend_Filter

Voici donc un exemple complet de cryptage de données avec OpenSSL.

// Utilisons openssl avec une clé privée


$filter = new Zend_Filter_Encrypt(array(
'adapter' => 'openssl',
'private' => '/path/to/mykey/private.pem'
));

// Voici la clé publique


$filter->setPublicKey(array(
'/public/key/path/first.pem',
'/public/key/path/second.pem'
));
$filter->setPassphrase('mypassphrase');

$encrypted = $filter->filter('text_to_be_encoded');
$envelope = $filter->getEnvelopeKey();
print $encrypted;

// Le décryptage est expliqué dans le filtre Decrypt

2.11. HtmlEntities
Retourne la chaîne $value, en convertissant les caractères en leurs entités HTML
correspondantes quand elles existent.

2.12. Int
Retourne la valeur (int) $value.

2.13. LocalizedToNormalized
Ce filtre va transformer toute entrée localisée en sa représentation normalisée. La transformation
est effectuée grâce à Zend_Locale en interne.

Ceci permet à l'utilisateur de saisir des information dans sa propre locale, et du coté serveur de
stocker les informations normalisées relatives.

Attention la normalisation n'est pas de la traduction. Ce filtre ne sait pas traduire


des chaines d'un langage à un autre.

Les types suivants peuvent être normalisés:

• entiers: Nombres entiers localisés. Ils seront normalisés dans la notation anglaise
internationnale.

• float: Nombres flottants. Ils seront normalisés dans la notation anglaise internationnale.

• nombres: Nombres réels. Ils seront normalisés dans la notation anglaise internationnale.

• time: Valeurs de temps. Normalisées sous forme de tableaux.

• date: Valeurs de date. Normalisées sous forme de tableaux.

Tout autre type d'entrée sera retourné tel quel, sans tranformation, par ce filtre.

651
Zend_Filter

Notez bien que toute sortie normalisée de ce filtre est de type chaine de
caractères.

2.13.1. Normaliser des nombres


Tout type de nombre peut être normalisé, excepté les nombres représentant une notation
scientifique.

Voici un exemple:

// Initialise le filtre
$filter = new Zend_Filter_LocalizedToNormalized();
$filter->filter('123.456,78');
// retourne '123456.78'

Imaginons que nous utilisoons la locale 'de' de manière globale sur toute l'application.
Zend_Filter_LocalizedToNormalized va utiliser cette locale là pour calculer sa sortie.

Il est possible de contrôler la normalisation des nombres. Toute options accépté par
Zend_Locale_Format peut alors être utilisée. Les plus courantes sont:

• date_format

• locale

• precision

Pour plus de détails à ce sujet, voyez le chapitre Zend_Locale.

Voici un exemple utilisant la précision:

// Numeric Filter
$filter = new Zend_Filter_LocalizedToNormalized(array('precision' => 2));

$filter->filter('123.456');
// retourne '123456.00'

$filter->filter('123.456,78901');
// retourne '123456.79'

2.13.2. Normaliser des dates et des temps


Les dates et temps peuvent être normalisés eux aussi. La sortie du filtre sera alors toujours de
type tableau.

// Initialise le filtre
$filter = new Zend_Filter_LocalizedToNormalized();
$filter->filter('12.April.2009');
// retourne array('day' => '12', 'month' => '04', 'year' => '2009')

Imaginons une fois de plus une locale globale 'de'. L'entrée est donc automatiquement reconnue
comme date et vous aurez un tableau en sortie.

Vous pouvez contrôler la transformation du filtre grâce aux paramètres date_format et locale.

652
Zend_Filter

// Date Filter
$filter = new Zend_Filter_LocalizedToNormalized(
array('date_format' => 'ss:mm:HH')
);

$filter->filter('11:22:33');
// retourne array('hour' => '33', 'minute' => '22', 'second' => '11')

2.14. NormalizedToLocalized
Ce filtre est l'inverse de Zend_Filter_LocalizedToNormalized et convertira toute entrée
normalisée en entrée localisée. Il utilise Zend_Locale pour celà.

Ceci permet de représenter une valeur normalisée dans la locale de l'utilisateur, qu'il reconnaitra
donc sans problème.

Notez bien que la localisation n'est pas de la traduction, ce filtre ne sait pas
traduire des chaines d'une langue à l'autre (comme des noms de jours ou de
mois).

Les types suivants peuvent être localisés:

• entiers: Nombres entiers.

• float: Nombres flottants.

• nombres: Autres nombres, comme les réels.

• temps: Valeurs de temps, localisées sous forme de chaines.

• date: Valeurs de dates, localisées sour forme de chaines.

Tout autre type d'entrée sera retourné tel quel, sans transformation.

2.14.1. Localisation des nombres


Tout type de nombre peut être localisé, à l'exception des nombres représentant une notation
scientifique.

Comment fonctionne la localisation pour les nombres ?:

// Initialise le filtre
$filter = new Zend_Filter_NormalizedToLocalized();
$filter->filter(123456.78);
// retourne '123.456,78'

Imaginons que vous avez affecté une locale 'de' comme locale de l'application.
Zend_Filter_NormalizedToLocalized va utiliser cette locale pour détecter le type de
sortie à produire, ceci sous forme de chaine de caractères.

Il est aussi possible de contrôler le look de vos nombres localisés. Pour cela vous pouvez préciser
toute option que Zend_Locale_Format reconnait. Les plus courantes sont:

• date_format

653
Zend_Filter

• locale

• precision

Pour plus de détails sur ces options, voyez le chapitre sur Zend_Locale .

Voici un exemple utilisant ces options:

// Numeric Filter
$filter = new Zend_Filter_NormalizedToLocalized(array('precision' => 2));

$filter->filter(123456);
// retourne '123.456,00'

$filter->filter(123456.78901);
// retourne '123.456,79'

2.14.2. Localiser des dates et des temps


Les dates et les temps peuvent aussi être localisés. Des chaines de caractères sont alors
retournées, agissant avec la locale définie.

// Initialise le filtre
$filter = new Zend_Filter_NormalizedToLocalized();
$filter->filter(array('day' => '12', 'month' => '04', 'year' => '2009');
// retoures '12.04.2009'

Imaginons que vous ayiez spécifié la locale 'de' au niveau de l'application, celle-ci est alors
automatiquement détectée et utilisée pour localiser la date.

Bien sûr, vous pouvez contrôler le format d'affichage de vos dates, grâce aux paramètres
date_format et locale.

// Date Filter
$filter = new Zend_Filter_LocalizedToNormalized(
array('date_format' => 'ss:mm:HH')
);

$filter->filter(array('hour' => '33', 'minute' => '22', 'second' => '11'));


// retourne '11:22:33'

2.15. Null
Ce filtre retournera la valeur NULL si des critères précis sont rencontrés. C'est souvent
nécessaire lorsqu'on travaille avec des bases de données et que l'on souhaite une valeur NULL
plutôt qu'un booléen ou tout autre type.

2.15.1. Comportement par défaut de Zend_Filter_Null


Par défaut, ce filtre fonctionne comme la fonction PHP empty(). Donc si empty() retourne
true sur la valeur, alors NULL sera retourné par ce filtre

$filter = new Zend_Filter_Null();


$value = '';
$result = $filter->filter($value);
// retourne null plutôt que la chaine vide

654
Zend_Filter

Ceci signifie qu'en l'absence d'une configuration spéciale, Zend_Filter_Null accepte tout
type en entrée et retourne NULL dans les mêmes cas que empty().

Toute autre valeur sera retournée telle quelle, sans aucune modification.

2.15.2. Changer le comportement de Zend_Filter_Null


Quelques fois ça ne suffit pas de filtrer en se basant sur empty(). Ainsi, Zend_Filter_Null
permet de déclarer quels types seront convertis.

Les types suivants sont gérés:

• booleen: Convertit le booléen FALSE en NULL.

• entier: Convertit l'entier 0 en NULL.

• tableau_vide: Convertit le tableau vide en NULL.

• chaine: Convertit la chaine vide '' en NULL.

• zero: Convertit la chaine zéro ('0') en NULL.

• tout: Convertit tous les types cités en NULL. (comportement par défaut).

Il existe plusieurs manières de spécifier les types à filtrer, des constantes, des types ajoutés à
la suite, des chaines de caractères, un tableau... Voyez les exemples suivants:

// convertit false en null


$filter = new Zend_Filter_Null(Zend_Filter_Null::BOOLEAN);

// convertit false et 0 en null


$filter = new Zend_Filter_Null(
Zend_Filter_Null::BOOLEAN + Zend_Filter_Null::INTEGER
);

// convertit false et 0 en null


$filter = new Zend_Filter_Null( array(
Zend_Filter_Null::BOOLEAN,
Zend_Filter_Null::INTEGER
));

// convertit false et 0 en null


$filter = new Zend_Filter_Null(array(
'boolean',
'integer',
));

Un objet Zend_Config peut aussi être utilisé pour préciser les types. La méthode setType()
existe de même.

2.16. PregReplace
Zend_Filter_PregReplace performs a search using regular expressions and replaces all
found elements.

The option match has to be given to set the pattern which will be searched for. It can be a string
for a single pattern, or an array of strings for multiple pattern.

655
Zend_Filter

To set the pattern which will be used as replacement the option replace has to be used. It can
be a string for a single pattern, or an array of strings for multiple pattern.

$filter = new Zend_Filter_PregReplace(array('match' => 'bob',


'replace' => 'john'));
$input = 'Hy bob!";

$filter->filter($input);
// returns 'Hy john!'

You can use getMatchPattern() and setMatchPattern() to set the matching


pattern afterwards. To set the replacement pattern you can use getReplacement() and
setReplacement().

$filter = new Zend_Filter_PregReplace();


$filter->setMatchPattern(array('bob', 'Hy'))
->setReplacement(array('john', 'Bye'));
$input = 'Hy bob!";

$filter->filter($input);
// returns 'Bye john!'

For a more complex usage take a look into PHP's PCRE Pattern Chapter.

2.17. RealPath
Ce filtre va résoudre un lien ou un chemin en chemin absolu canonique. Toutes références à
'/./', '/../' et tout ajout supplémentaire de '/' sera résolu ou supprimé. Aucun caractère
de lien symbolique ne sera présent dans le résultat ('/./' ou '/../')

Zend_Filter_RealPath retourne FALSE en cas d'echec par exemple si le fichier n'existe pas.
Sur les systems BSD, Zend_Filter_RealPath n'échoue pas si seule la dernière partie du
chemin n'existe pas, les autres systèmes retourneront FALSE.

$filter = new Zend_Filter_RealPath();


$path = '/www/var/path/../../mypath';
$filtered = $filter->filter($path);

// retourne '/www/mypath'

Il peut être nécessaire quelques fois de vouloir utiliser ce filtre sur des chemins inexistants. Par
exemple récupérer le realpath d'un chemin à créer. Dans ce cas vous pouvez passer FALSE au
constructeur, ou utiliser setExists().

$filter = new Zend_Filter_RealPath(false);


$path = '/www/var/path/../../non/existing/path';
$filtered = $filter->filter($path);

// retourne '/www/non/existing/path' même si file_exists ou realpath retourneraient false

2.18. StringToLower
Ce filtre convertit toute entrée vers des caractères minuscules.

$filter = new Zend_Filter_StringToLower();

656
Zend_Filter

print $filter->filter('SAMPLE');
// retourne "sample"

Par défaut, seul le jeu de caractères de la locale en cours sera utilisé. Les caractères provenant
d'autres jeux seront ignorés. Cela reste possible de les passer en minuscules si l'extension
mbstring est présente dans votre environnement PHP. Indiquez l'encodage voulu à la création
du filtre StringToLower ou utilisez sa méthode setEncoding().

// utiliser UTF-8
$filter = new Zend_Filter_StringToLower('UTF-8');

// ou passer un tableau
$filter = new Zend_Filter_StringToLower(array('encoding' => 'UTF-8'));

// ou encore faire cela après coup


$filter->setEncoding('ISO-8859-1');

Préciser des mauvais encodages

Attention une exception sera levée si vous précisez un encodage alors que
l'extension mbstring est absente.

Une exception sera de même levée si l'encodage que vous précisez n'est pas
pris en compte par mbstring.

2.19. StringToUpper
Ce filtre convertit toute entrée vers une casse majuscule.

$filter = new Zend_Filter_StringToUpper();

print $filter->filter('Sample');
// retourne "SAMPLE"

Tout comme le filtre StringToLower, seul le jeu de caractères de la locale en cours sera utilisé.
Son fonctionnement est le même que celui de StringToLower.

$filter = new Zend_Filter_StringToUpper(array('encoding' => 'UTF-8'));

// ou encore
$filter->setEncoding('ISO-8859-1');

2.20. StringTrim
Retourne la chaîne $value en supprimant les caractères vides en début et fin de chaîne.

2.21. Int
Retourne la valeur $value en enlevant les caractères représentant une nouvelle ligne.

2.22. StripTags
Ce filtre retourne une chaîne, où toutes les balises HTML et PHP sont supprimées, exceptées
celles qui sont explicitement autorisées. En plus de pouvoir spécifier quelles balises sont

657
Zend_Filter

autorisées, les développeurs peuvent spécifier quels attributs sont autorisés soit pour toutes les
balises autorisées soit pour des balises spécifiques seulement.

3. Chaînes de filtrage
Souvent, de multiples filtres doivent être appliqués à une valeur dans un ordre particulier. Par
exemple, un formulaire d'authentification accepte un identifiant qui doit être en minuscule et
composé uniquement de caractères alphabétiques. Zend_Filter fournit un moyen simple
permettant de chaîner des filtres. Le code suivant illustre comment chaîner deux filtres pour
l'identifiant soumis :

// Création d'une chaine de filtrage et ajout de filtres à celle-ci


$filtreChaine = new Zend_Filter();
$filtreChaine->addFilter(new Zend_Filter_Alpha())
->addFilter(new Zend_Filter_StringToLower());

// Filtrage de l'identifiant
$identifiant = $filtreChaine->filter($_POST['identifiant']);

Les filtres sont exécutés dans leur ordre d'ajout à Zend_Filter. Dans l'exemple ci-dessus,
l'identifiant se voit d'abord retirer tout caractère non-alphabétique, les caractère majuscules
éventuels sont ensuite convertis en minuscules.

Tout objet implémentant Zend_Filter_Interface peut être utilisé comme chaîne de filtrage.

3.1. Changing filter chain order


Since 1.10, the Zend_Filter chain also supports altering the chain by prepending or appending
filters. For example, the next piece of code does exactly the same as the other username filter
chain example:

// Create a filter chain and add filters to the chain


$filterChain = new Zend_Filter();

// this filter will be appended to the filter chain


$filterChain->appendFilter(new Zend_Filter_StringToLower());

// this filter will be prepended at the beginning of the filter chain.


$filterChain->prependFilter(new Zend_Filter_Alpha());

// Filter the username


$username = $filterChain->filter($_POST['username']);

4. Écriture de filtres
Zend_Filter fournit un ensemble de filtres usuels. Cependant, les développeurs auront
souvent besoin d'écrire des filtres personnalisés pour leurs besoins propres. L'écriture de filtre
personnalisés est rendue plus facile via l'implémentation de Zend_Filter_Interface.

Zend_Filter_Interface définit une méthode unique, filter(), qui peut être implémentée
dans les classes créées. Un objet qui implémente cette interface peut être ajouté à une chaîne
de filtrage via Zend_Filter::addFilter().

L'exemple suivant démontre comment écrire un filtre personnalisé :

658
Zend_Filter

class MonFiltre implements Zend_Filter_Interface


{
public function filter($valeur)
{
// application de transformations sur $valeur
// pour parvenir à $valeurFiltree

return $valeurFiltree;
}
}

Pour ajouter une instance du filtre défini ci-dessus à une chaîne de filtrage :

$filtreChaine = new Zend_Filter();


$filtreChaine->addFilter(new MonFiltre());

5. Zend_Filter_Input
Zend_Filter_Input propose une manière générique de déclarer des filtres et des validateurs,
de les appliquer comme un ensemble, à une collection de données, et enfin de récupérer
ces données validées et filtrées. Les valeurs sont retournées échappées par défaut, pour une
meilleure sécurité relative au HTML.

Considérez cette classe comme une boite noire dans laquelle va passer une variable de
collection, typiquement un tableau PHP représentant des données externes. Les données
arrivent dans l'application depuis une source externe, donc potentiellement dangereuse, comme
des variables de requête HTTP, d'un service Web, d'un fichier, ou autre. L'application demande
alors à la boite noire l'accès à une ou plusieurs données, en spécifiant sous quelle forme elle
s'attend à voir la donnée. La boite inspecte alors la donnée pour la valider, et ne la laisse sortir
que si celle-ci respecte les règles que l'application demande. Grâce à une simple classe et un
mécanisme facile, ceci encourage les développeurs à prendre des bonnes pratiques au regard
de la sécurité des applications.

• Les filtres transforment les entrées en supprimant ou changeant des caractères dans leurs
valeurs. Le but est de "normaliser" les valeurs jusqu'à ce qu'elles correspondent aux attentes
exigées. Par exemple si une chaine d'entiers (numériques) est attendue, et que la donnée
d'entrée est "abc123", alors en sortie du filtre la valeur "123" sera proposée.

• Les validateurs vérifient la validité d'une donnée, sans la transformer. Si la validation échoue,
le validateur renseignera sur les problèmes rencontrés.

• Les échappeurs transforment une valeur en supprimant certains caractères qui peuvent
avoir une signification spéciale dans un contexte donné. Par exemple, les caractères '<' et
'>' délimitent les balises HTML, ainsi si une donnée contenant ces caractères est affichée
directement dans un navigateur, la sortie peut être corrompue et mener à des problèmes de
sécurité. Échapper les caractères est le fait de leur enlever toute signification spéciale, ils
seront traités comme des caractères tout à fait normaux.

Pour utiliser Zend_Filter_Input :

1. Déclarez des règles de filtre et de validateur

2. Ajoutez des filtres et des validateurs dans Zend_Filter_Input

3. Passer les données d'entrée à Zend_Filter_Input

659
Zend_Filter

4. Récupérez les données valides et/ou des rapports divers

Les sections suivantes expliquent comment manipuler la classe.

5.1. Déclarer des règles de filtre et de validateur


Avant de créer une instance de Zend_Filter_Input, déclarez deux tableaux de règles pour
les filtres, et les validateurs. Ce tableau associatif met en relation le champ de la donnée dans
le tableau originel et le nom du filtre/validateur.

L'exemple qui suit indique que le champ "month" est filtré par un Zend_Filter_Digits, et
le champ "account" est filtré par un Zend_Filter_StringTrim. Puis, une règle de validation
s'appliquera au champ "account", celui-ci sera validé s'il ne contient que des caractères
alphabétiques (lettres).

$filters = array(
'month' => 'Digits',
'account' => 'StringTrim'
);

$validators = array(
'account' => 'Alpha'
);

Chaque clé du tableau $filters représente une donnée à laquelle sera appliqué le filtre
correspondant en valeur de tableau.

Le filtre peut être déclaré selon différents formats :

• Une chaine de caractères, qui sera transformée en nom de classe.

$validators = array(
'month' => 'Digits',
);

• Un objet instance d'une classe implémentant Zend_Filter_Interface ou


Zend_Validate_Interface.

$digits = new Zend_Validate_Digits();

$validators = array(
'month' => $digits
);

• Un tableau, pour déclarer une chaine de filtres ou validateurs. Les éléments de ce tableau
peuvent être des chaînes représentant des noms de classe, ou des objets directement. Aussi,
vous pouvez utiliser comme valeur un tableau contenant le nom du filtre ou validateur, et
d'éventuels arguments à passer à son constructeur.

$validators = array(
'month' => array(
'Digits', // chaine
new Zend_Validate_Int(), // objet
array('Between', 1, 12) // chaine + arguments pour le constructeur
)
);

660
Zend_Filter

Si vous choisissez de déclarer un filtre ou validateur avec des arguments de


constructeur, alors la règle générale devra elle aussi utiliser un tableau pour sa/
ses déclarations de filtres ou validateurs.

Un joker "* " peut être utilisé dans le tableau des filtres ou des validateurs. Ceci aura pour effet
d'appliquer le validateur ou le filtre à toutes les entrées du tableau traité. Notez que l'ordre des
filtres / validateurs est important dans le tableau, car il seront appliqués dans l'ordre dans lequel
ils ont été déclarés.

$filters = array(
'*' => 'StringTrim',
'month' => 'Digits'
);

5.2. Créer le processeur de filtres et validateurs


Lorsque vos tableaux de filtres et de validateurs ont été construits, passez les en argument au
constructeur de Zend_Filter_Input. Ceci va retourner un objet pré-configuré qui saura alors
traiter tout un tableau de données d'entrée.

$input = new Zend_Filter_Input($filters, $validators);

Les données d'entrée peuvent être placées dans le troisième paramètre du constructeur.
Ces données possèdent en clé leur nom, et en valeur leur valeur. Typiquement, les
tableaux superglobaux $_GET et $_POST possèdent la structure idéale pour passer dans
Zend_Filter_Input.

$data = $_GET;
$input = new Zend_Filter_Input($filters, $validators, $data);

Aussi, la méthode setData() accepte les données de la même manière que le troisième
argument du constructeur.

$input = new Zend_Filter_Input($filters, $validators);


$newData = $_POST;
$input->setData($newData);

La méthode setData() réaffecte une nouveau tableau de valeurs d'entrée dans l'objet
Zend_Filter_Input, en écrasant toute autre source s'y trouvant. Ceci est pratique afin de
réutiliser des règles communes de filtres / validateurs, sur différentes sources.

5.3. Récupérer les champs validés/filtré, et les éventuels rapports


Une fois l'objet configuré, et le tableau de données d'entrée passé, vous pouvez récupérer les
rapports concernant les champs absents, invalides ou inconnus. Vous pouvez évidemment aussi
récupérer les valeurs validées/filtrées des champs d'entrée valides.

5.3.1. Demander si l'entrée est valide


Si toutes les données d'entrée passent les règles de validation la méthode isValid()
retourne TRUE. Si n'importe quelle donnée d'entrée n'est pas validée, ou est manquante, alors
isValid() retourne FALSE.

if ($input->isValid()) {

661
Zend_Filter

echo "OK\n";
}

Cette méthode accepte aussi un paramètre facultatif nommant un champ particulier dans la
donnée d'entrée. Ceci permet une vérification individuelle.

if ($input->isValid('month')) {
echo "Le champ 'month' est OK\n";
}

5.3.2. Récupérer les infos des champs invalides, absents ou inconnus


• Les champs invalides sont ceux qui ne passent pas un ou plusieurs critères définis par les
validateurs.

• Les champs absents sont ceux qui ne sont pas présents dans la donnée d'entrée, alors que la
méta commande 'presence'=>'required' était présente (voyez la section sur les méta
commandes).

• Les champs inconnus sont ceux présents dans la donnée d'entrée alors que aucun validateur
ni filtre ne lui avait attribué de règle.

if ($input->hasInvalid() || $input->hasMissing()) {
$messages = $input->getMessages();
}

// getMessages() retourne la fusion de getInvalid() et getMissing()

if ($input->hasInvalid()) {
$invalidFields = $input->getInvalid();
}

if ($input->hasMissing()) {
$missingFields = $input->getMissing();
}

if ($input->hasUnknown()) {
$unknownFields = $input->getUnknown();
}

Les valeurs retournées par getMessages() sont sous la forme d'un tableau dont la clé est la
règle concernée et la valeur un tableau d'erreurs la concernant. Le tableau d'erreurs comporte en
clé le nom de la règle déclarée qui peut être différent des noms de champs vérifiés par la règle.

La méthode getMessages() retourne la fusion des tableaux retournés par getInvalid() et


getMissing(). Ces méthodes retournent une sous-partie des messages correspondant soit
aux échecs de validation, soit aux champs qui sont déclarés requis mais qui sont absents.

La méthode getErrors() retourne un tableau associatif dont les clés sont des noms de règles
et les valeurs associées des tableaux identifiants les erreurs. Les identifiants d'erreurs sont des
chaînes constantes et figées, qui permettent d'identifier la raison de l'échec de validation, tandis
que les messages associés sont eux-mêmes personnalisables. Voir Section 1.2, « Utilisation
basique des validateurs » pour plus d'information.

Vous pouvez spécifier le message retourné par getMissing() en utilisant l'option


"missingMessage", en tant qu'argument du constructeur de Zend_Filter_Input ou en
utilisant l'option setOptions().

662
Zend_Filter

$options = array(
'missingMessage' => "Field '%field%' is required"
);

$input = new Zend_Filter_Input($filters, $validators, $data, $options);

// alternative method:

$input = new Zend_Filter_Input($filters, $validators, $data);


$input->setOptions($options);

And you can also add a translator which gives you the ability to provide multiple languages for
the messages which are returned by Zend_Filter_Input.

$translate = new Zend_Translate_Adapter_Array(array(


Zend_Filter_Input::MISSING_MESSAGE => "Where is the field?"
);

$input = new Zend_Filter_Input($filters, $validators, $data);


$input->setTranslator($translate);

When you are using an application wide translator, then it will also be used by
Zend_Filter_Input. In this case you will not have to set the translator manually.

Le résultat de la méthode getUnknown() est un tableau associatif dont les clés sont des noms
de champs et les valeurs sont les valeurs de champs correspondants. Les noms de champs
sont dans ce cas les clés du tableau au lieu des noms de règles, car tout champs n'ayant pas
de règles définies est considéré comme un champs inconnu.

5.3.3. Récupérer les champs valides


Tout champ non invalide, non absent et non inconnu, est considéré comme valide. Vous pouvez
alors en récupérer la valeur via un accesseur magique. Des méthodes classiques existent aussi,
comme getEscaped() et getUnescaped().

$m = $input->month; // donnée échappée (accesseur magique)


$m = $input->getEscaped('month'); // donnée échapée
$m = $input->getUnescaped('month'); // donnée non échappée

Par défaut, récupérer un champ le passe automatiquement au travers de


Zend_Filter_HtmlEntities. Ce comportement est considéré comme défaut pour un
affichage en HTML. Le filtre HtmlEntities réduit de manière significative les risques de
sécurité liés à un affichage involontaire d'une valeur.

La méthode getUnescaped() retourne le champ brut, vous devez alors prendre


vos précautions lors d'un affichage HTML. Attention aux problèmes de sécurité
XSS (Cross Site Scripting).

Escaping unvalidated fields


As mentioned before getEscaped() returns only validated fields. Fields which
do not have an associated validator can not be received this way. Still, there is a
possible way. You can add a empty validator for all fields.

$validators = array('*' => array());

663
Zend_Filter

$input = new Zend_Filter_Input($filters, $validators, $data, $options);

But be warned that using this notation introduces a security leak which could be
used for cross-site scripting attacks. Therefor you should always set individual
validators for each field.

Il est possible de définir un autre filtre comme filtre par défaut pour récupération des champs.
Ceci se fait via le constructeur :

$options = array('escapeFilter' => 'StringTrim');


$input = new Zend_Filter_Input($filters, $validators, $data, $options);

Aussi, la méthode setDefaultEscapeFilter() fait la même chose :

$input = new Zend_Filter_Input($filters, $validators, $data);


$input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());

Il est possible de passer une chaine, ou directement un objet instance de Zend_Filter.

Les filtres d'échappement comme vus juste précédemment, doivent être spécifiés de cette
manière là. S'ils avaient été spécifiés comme filtres dans le tableau de Zend_Filter_Input,
ils auraient pu faire échouer les validateurs, car les filtres sont exécutés AVANT les validateurs.
Aussi, il n'aurait plus été possible de proposer la donnée de sortie de manière échappée et non
échappée. Ainsi, déclarer un filtre d'échappement des données devrait toujours être effectué en
utilisant la méthode setDefaultEscapeFilter(), et non pas le tableau $filters.

Comme il n'y a qu'une seule méthode getEscaped(), il ne peut y avoir qu'un seul filtre utilisé
pour l'échappement. Il est cependant possible d'utiliser une chaine de filtre, ou encore de dériver
la classe Zend_Filter_Input en créant d'autres méthodes de récupération de données, plus
spécifiques.

5.4. Utiliser des méta commandes pour contrôler les règles des
filtres et validateurs
En plus de déclarer un mapping entre des champs d'un tableau, et des validateurs et des
filtres, il est possible d'utiliser des méta commandes pour contrôler le comportement de
Zend_Filter_Input. Les méta commandes se présentent sous la forme de chaînes dans le tableau
des filtres ou des validateurs.

5.4.1. La méta commande FIELDS


Si le nom de la règle d'un filtre ou validateur est différente du champs auquel elle doit s'appliquer,
vous pouvez spécifier le nom du champ avec la méta commande "fields".

Vous pouvez spécifier cette méta commande en utilisant la constante de classe


Zend_Filter_Input::FIELDS.

$filters = array(
'month' => array(
'Digits', // nom du filtre à l'index [0]
'fields' => 'mo' // nom du champ à l'index ['fields']
)
);

664
Zend_Filter

Dans l'exemple ci dessus, la règle applique le filtre "digits" au champ d'entrée nommé "mo".
La chaine "month" devient alors un simple mnémonique pour cette règle, elle n'est pas utilisée
comme nom de champ si celui-ci est renseigné avec la méta commande "fields", mais elle est
utilisée comme nom de règle.

La valeur par défaut de la méta commande "fields" est l'index de la règle courante. Dans
l'exemple ci dessus, si la méta commande "fields" est omise, la règle s'appliquerait au champ
"month".

Un autre usage de la méta commande "fields" est pour préciser les champs aux filtres ou
validateurs qui en attendent plusieurs en entrée. Si la méta commande "fields" est un tableau,
alors le filtre/validateur correspondant aura comme argument la valeur des champs. Pensez au
cas où l'on demande à l'utilisateur de saisir 2 fois son mot de passe. Imaginons un validateur qui
prend en paramètre un tableau de champs et retourne TRUE si les champs sont égaux.

$validators = array(
'password' => array(
'StringEquals',
'fields' => array('password1', 'password2')
)
);
// Invoque la classe Zend_Validate_StringEquals,
// en lui passant un tableau contenant les valeurs
// des champs 'password1' and 'password2'.

Si la validation échoue, alors le nom de la règle ('password') est utilisé dans le retour de
getInvalid(), et non pas les noms des champs spécifiés dans "fields".

5.4.2. Méta commande PRESENCE


Si la valeur de cette méta commande est "required", alors le champ doit exister dans la donnée
d'entrée. Autrement, il est reporté comme étant un champ manquant.

Vous pouvez spécifier cette méta commande avec la constante de classe


Zend_Filter_Input::PRESENCE.

$validators = array(
'month' => array(
'digits',
'presence' => 'required'
)
);

La valeur par défaut de cette méta commande est "optional".

5.4.3. La méta commande DEFAULT_VALUE


Si le champ n'est pas présent dans la donnée d'entrée mais que celui-ci possède une méta
commande "default", alors il obtient la valeur de la méta commande.

Vous pouvez spécifier cette méta commande avec la constante de classe


Zend_Filter_Input::DEFAULT_VALUE.

La valeur de cette méta commande ne s'applique qu'avant l'invocation des validateurs, et


seulement pour la règle en cours.

$validators = array(

665
Zend_Filter

'month' => array(


'digits',
'default' => '1'
)
);

// pas de valeur pour le champ 'month'


$data = array();

$input = new Zend_Filter_Input(null, $validators, $data);


echo $input->month; // affiche 1

Si vous utilisez pour une règle la méta commande FIELDS afin de définir un tableau de champs,
vous pouvez définir un tableau pour la méta commande DEFAULT_VALUE. Les valeurs par défaut
seront alors les clés correspondantes à chaque champ manquant. Si FIELDS définit de multiples
champs mais que DEFAULT_VALUE est un scalaire, alors cette valeur scalaire sera utilisée pour
tous les champs manquants.

Il n'y a pas de valeur par défaut pour cette méta commande.

5.4.4. La méta commande ALLOW_EMPTY


Par défaut, si un champ existe dans le tableau d'entrées, alors les validateurs lui sont appliqués,
même si la valeur de ce champs est la chaine vide (''). Ceci peut mener à des échecs de
validation. Par exemple un validateur digits (chiffres) va échouer sur une chaine vide (laissant
croire que la donnée puisse être composée de lettres).

Si la chaine vide doit pouvoir être considérée comme valide, utilisez la méta commande
"allowEmpty" avec la valeur TRUE.

Vous pouvez spécifier cette méta commande avec la constante de classe


Zend_Filter_Input::ALLOW_EMPTY

$validators = array(
'address2' => array(
'Alnum',
'allowEmpty' => true
)
);

La valeur par défaut de cette méta commande est FALSE.

Dans la cas peut commun ou vous déclarez une règle de validation avec aucun validateurs,
mais que la méta commande "allowEmpty" est mise à FALSE (le champ est considéré
invalide s'il est vide), Zend_Filter_Input retourne un message d'erreur par défaut que vous
pouvez récupérer avec la méthode getMessages(). Ce message se change grâce à l'option
"notEmptyMessage" spécifiée en constructeur de Zend_Filter_Input ou via la méthode
setOptions().

$options = array(
'notEmptyMessage' =>
"Une valeur non vide est requise pour le champ '%field%'"
);

$input = new Zend_Filter_Input($filters, $validators, $data, $options);

// Autre méthode :

666
Zend_Filter

$input = new Zend_Filter_Input($filters, $validators, $data);


$input->setOptions($options);

5.4.5. La méta commande BREAK_CHAIN


Par défaut, si une règle possède plus d'un validateur, tous sont appliqués à la donnée d'entrée,
et les éventuels messages d'erreur résultants sont la somme de tous les messages individuels
des validateurs.

Si la valeur de la méta commande "breakChainOnFailure" est TRUE, la chaine de validation


va se terminer dès lors qu'un des validateur termine sur un échec.

Vous pouvez spécifier cette méta commande au moyen de la constante de classe


Zend_Filter_Input::BREAK_CHAIN

$validators = array(
'month' => array(
'Digits',
new Zend_Validate_Between(1,12),
new Zend_Validate_GreaterThan(0),
'breakChainOnFailure' => true
)
);
$input = new Zend_Filter_Input(null, $validators);

La valeur par défaut de cette méta commande est FALSE.

La classe Zend_Validate est plus flexible lors du bris de la chaine d'exécution, par rapport
à Zend_Filter_Input. Avec Zend_Validate, vous pouvez mettre l'option pour casser
la chaine indépendamment pour chaque validateur. Avec Zend_Filter_Input, la méta
commande "breakChainOnFailure" s'applique à tous les validateurs dans la règle. Pour un usage
plus flexible, créez votre propre chaine de validation comme ceci :

// Créer une chaine de validation avec un attribut


// breakChainOnFailure non uniforme
$chain = new Zend_Validate();
$chain->addValidator(new Zend_Validate_Digits(), true);
$chain->addValidator(new Zend_Validate_Between(1,12), false);
$chain->addValidator(new Zend_Validate_GreaterThan(0), true);

// Déclare la règloe de validation en faisant référence


// à la chaine de validation ci dessus
$validators = array(
'month' => $chain
);
$input = new Zend_Filter_Input(null, $validators);

5.4.6. La méta commande MESSAGES


Vous pouvez attribuer des messages d'erreur pour chaque validateur d'une règle grâce à la
méta commande 'messages'. La valeur de cette méta commande varie si vous avez plusieurs
validateurs dans une règle ou si vous voulez spécifier le message pour une erreur particulière
concernant un des validateurs.

Vous pouvez utiliser la constante de classe Zend_Filter_Input::MESSAGES pour définir


cette méta commande.

Voici un exemple simple qui enregistre un message d'erreur pour une validateur de chiffres.

667
Zend_Filter

$validators = array(
'month' => array(
'digits',
'messages' => 'Un mois doit être un chiffre'
)
);

Si vous possédez plusieurs validateurs dont vous voulez personnaliser les messages d'erreur,
utilisez alors un tableau comme valeur de la méta commande 'messages'.

Chaque élément de ce tableau s'applique à un validateur au même niveau d'index. Ainsi, un


validateur à l'index n verra son message d'erreur modifié si vous utilisez l'index n dans le tableau
de la méta commande. Il est ainsi possible d'autoriser certains validateurs à faire usage de leur
message d'erreur par défaut, alors que d'autres posséderont un message personnalisé.

$validators = array(
'month' => array(
'digits',
new Zend_Validate_Between(1, 12),
'messages' => array(
// utilise le message par défaut du vaidateur [0]
// Affecte un nouveau message pour le validateur [1]
1 => 'Une valeur de mois doit être comprise entre 1 et 12'
)
)
);

Si un des validateurs a plusieurs messages d'erreur, ils sont identifiés par une clé. Il existe
différente clé dans chaque classe de validateur, ceux-ci servent d'identifiants pour les messages
d'erreur. Chaque classe validateur définit aussi des constante pour les clés des messages
d'erreur. Cette constante peut être utilisée dans la méta commande 'messages' en lui passant
un tableau associatif plutôt qu'une chaine.

$validators = array(
'month' => array(
'digits', new Zend_Validate_Between(1, 12),
'messages' => array(
'Un mois ne peut contenir que des chiffres',
array(
Zend_Validate_Between::NOT_BETWEEN =>
'La valeur %value% du mois doit être comprise'
. ' entre %min% et %max%',
Zend_Validate_Between::NOT_BETWEEN_STRICT =>
'La valeur %value% du mois doit être comprise'
. ' strictement entre %min% et %max%'
)
)
)
);

Vous devriez vous référer à la documentation de chaque validateur afin de savoir s'il retourne
plusieurs messages d'erreur, les clés de ces messages et les jetons utilisables dans les modèles
de message.

Si vous n'avez qu'un seul validateur dans vos règles de validation ou que tous les validateurs ont
le même message de paramétrer, alors ils peuvent être référencés la construction additionnelle
de type tableau :

668
Zend_Filter

$validators = array(
'month' => array(
new Zend_Validate_Between(1, 12),
'messages' => array(
Zend_Validate_Between::NOT_BETWEEN =>
'La valeur %value% du mois doit être comprise'
. ' entre %min% et %max%',
Zend_Validate_Between::NOT_BETWEEN_STRICT =>
'La valeur %value% du mois doit être comprise'
. ' strictement entre %min% et %max%'
)
)
);

5.4.7. Utiliser des options pour définir des méta commandes pour toutes
les règles
Les valeurs par défaut des méta commandes "allowEmpty", "breakChainOnFailure", et
"presence" peuvent être dictées pour toutes les règles en utilisant l'argument $options du
constructeur de Zend_Filter_Input.

// Tous les champs acceptent des valeurs vides


$options = array('allowEmpty' => true);

// Il est possible d'écraser le comportement pour une règle précise.


$validators = array(
'month' => array(
'Digits',
'allowEmpty' => false
)
);

$input = new Zend_Filter_Input($filters, $validators, $data, $options);

Les méta commandes "fields", "messages", et "default" ne bénéficient pas d'un tel raccourci.

5.5. Ajouter des espaces de noms comme noms de classes


Par défaut, l'ajout d'un validateur ou d'un filtre sous forme de chaine, va faire en sort que
Zend_Filter_Input cherche une correspondance sous l'espace de nom Zend_Filter_*
et Zend_Validate_*.

Si vous écrivez vos propres filtres (ou validateurs), la classe peut exister dans un autre
espace de nom que Zend_Filter ou Zend_Validate. Il est alors possible de dire à
Zend_Filter_Input de chercher dans ces espaces là. Ceci se fait via son constructeur :

$options = array('filterNamespace' => 'My_Namespace_Filter', 'validatorNamespace' => 'My_Nam


$input = new Zend_Filter_Input($filters, $validators, $data, $options);

Alternativement, vous pouvez utiliser les méthodes addValidatorPrefixPath($prefix,


$path) ou addFilterPrefixPath($prefix, $path), qui proxie directement le chargeur
de plugin utilisé par Zend_Filter_Input :

$input->addValidatorPrefixPath('Autre_Namespace', 'Autre/Namespace');
$input->addFilterPrefixPath('Foo_Namespace', 'Foo/Namespace');

// Maitenant l'ordre de recherche des validateurs est :

669
Zend_Filter

// 1. My_Namespace_Validate
// 2. Autre_Namespace
// 3. Zend_Validate

// L'ordre de recherche des filtres est :


// 1. My_Namespace_Filter
// 2. Foo_Namespace

Il n'est pas possible de supprimer les espaces de nommage Zend_Filter et Zend_Validate.


Les espaces définis par l'utilisateur sont cherchés en premiers, les espaces de nom Zend sont
cherchés en derniers.

A partir de la version 1.5, la fonction addNamespace($namespace) est


dépréciée et échangée avec le chargeur de plugin et les méthodes
addFilterPrefixPath et addValidatorPrefixPath ont été ajoutées.
De même la constante Zend_Filter_Input::INPUT_NAMESPACE est aussi
dépréciée. Les constantes Zend_Filter_Input::VALIDATOR_NAMESPACE
et Zend_Filter_Input::FILTER_NAMESPACE sont disponibles à partir de la
version 1.7.0.

A partir de la version 1.0.4, Zend_Filter_Input::NAMESPACE,


ayant une valeur namespace, a été changé par
Zend_Filter_Input::INPUT_NAMESPACE, ayant une valeur
inputNamespace, dans le but de se conformer à la réservation du mot clé
namespace par PHP 5.3.

6. Zend_Filter_Inflector
Zend_Filter_Inflector est un outil de conversion de règles (sous forme de chaîne de
caractères), vers une cible. Ce procédé est appelé inflexion.

Par exemple, transformer des MotsEncasseMélangée ou des motsEnCamelCase vers un


chemin. Vous pourriez avoir besoin de passer les caractères en minuscules, et séparer les mots
en utilisant un tiret ("-"). Un inflecteur sert à ceci.

Zend_Filter_Inflector implémente Zend_Filter_Interface ; pour utiliser l'inflexion,


vous appelez filter() sur votre instance.

Exemple 378. Transformer du texteEncasseMelangée ou du texteCamelCase


vers un autre format

$inflector = new Zend_Filter_Inflector('pages/:page.:suffix');


$inflector->setRules(array(
':page' => array('Word_CamelCaseToDash', 'StringToLower'),
'suffix' => 'html'
));

$string = 'motsEnNotationCamel';
$filtered = $inflector->filter(array('page' => $string));
// pages/mots-en-notation-camel.html

$string = 'ceci_n_est_pas_en_notation_camel';
$filtered = $inflector->filter(array('page' => $string));
// pages/ceci_n_est_pas_en_notation_camel.html

670
Zend_Filter

6.1. Opération
Un inflecteur a besoin d'une cible et d'une ou plusieurs règles. Une cible est une chaîne dans
laquelle des jokers pour les variables à remplacer sont présents. Ils sont préfixés de doubles-
points, par exemple :script.

L'appel à filter(), nécessite un tableau de clés/valeurs pour les jokers présents dans la cible.

Chaque variable dans la cible peut avoir zéro ou plusieurs règles associées. Les règles peuvent
être statiques ou faire référence à une classe Zend_Filter. Les règles statiques sont des
remplacements purs et simples. Sinon, la classe qui correspond à la règle sera utilisée pour
analyser le texte. Ces classes sont spécifiées par leur nom (du filtre), non préfixé.

Par exemple, vous pouvez utiliser n'importe quelle instance de Zend_Filter. Cependant, plutôt
que d'y faire référence via "Zend_Filter_Alpha" ou "Zend_Filter_StringToLower", vous
spécifierez seulement "Alpha" ou encore "StringToLower".

6.2. Créer des chemins vers des filtres alternatifs


Zend_Filter_Inflector utilise Zend_Loader_PluginLoader pour gérer les filtres
chargés. Par défaut, n'importe quel filtre préfixé par Zend_Filter sera disponible. Pour accéder
aux filtres ayant d'autres préfixes plus profonds, enlevez leur préfixe "Zend_Filter" tout
simplement :

// utilise Zend_Filter_Word_CamelCaseToDash comme règle


$inflector->addRules(array('script' => 'Word_CamelCaseToDash'));

Pour spécifier d'autres chemins, Zend_Filter_Inflector possède une méthode qui proxie
vers le plugin loader, addFilterPrefixPath() :

$inflector->addFilterPrefixPath('Mes_Filtres', 'Mes/Filtres/');

Il est possible également de récupérer le plugin loader, et d'intervenir sur son instance de manière
directe :

$loader = $inflector->getPluginLoader();
$loader->addPrefixPath('Mes_Filtres', 'Mes/Filtres/');

Pour plus d'informations sur la modification des chemins vers les filtres voyez la documentation
de PluginLoader.

6.3. Paramétrer la cible de l'inflecteur


La cible de l'inflecteur est un mot joker (ou un identifiant), précédé du caractère spécial, double-
point. ":script", ":path", etc. La méthode filter() cherche ces identifiants pour les traiter (les
remplacer).

Il est possible de changer le caractère spécial double-point avec


setTargetReplacementIdentifier(), ou en troisième paramètre de constructeur :

// Via le constructeur :
$inflector = new Zend_Filter_Inflector('#foo/#bar.#sfx', null, '#');

// Via l'accesseur :
$inflector->setTargetReplacementIdentifier('#');

671
Zend_Filter

En général, concernant la cible, on la passe en constructeur. C'est le cas classique. Il peut être en
revanche nécessaire de pouvoir passer une cible après la construction de l'objet. (Par exemple
modifier l'inflecteur des composants Zend intégrés tels que ViewRenderer ou Zend_Layout).
setTarget() peut vous y aider :

$inflector = $layout->getInflector();
$inflector->setTarget('layouts/:script.phtml');

De plus, vous pouvez agréger la cible dans un membre de votre classe, si cela vous permet
d'éviter trop d'appels de méthodes. setTargetReference() permet ceci :

class Foo
{
/**
* @var string Inflector target
*/
protected $_target = 'foo/:bar/:baz.:suffix';

/**
* Constructor
* @return void
*/
public function __construct()
{
$this->_inflector = new Zend_Filter_Inflector();
$this->_inflector->setTargetReference($this->_target);
}

/**
* Set target; updates target in inflector
*
* @param string $target
* @return Foo
*/
public function setTarget($target)
{
$this->_target = $target;
return $this;
}
}

6.4. Règles d'inflexion


Comme dit en introduction, il existe 2 types de règles : statiques et basées sur des filtres.

Notez bien que quelle que soit la méthode que vous utilisez pour spécifier vos
règles dans l'inflecteur, leur ordre est très important. Vous devez ajouter de la
règle la plus spécifique, à la plus générique. Par exemple, 2 règles nommées
"moduleDir" et "module", la règle "moduleDir" devrait être ajoutée avant la règle
"module", car cette dernière est contenue dans "moduleDir".

6.4.1. Règles statiques


Les règles statiques permettent des remplacements simples. Si vous avez un segment statique
dans votre cible, ce type de règle est idéal. setStaticRule() permet de les manipuler :

672
Zend_Filter

$inflector = new Zend_Filter_Inflector(':script.:suffix');


$inflector->setStaticRule('suffix', 'phtml');

// ici des opérations ...


// changement de la règle:
$inflector->setStaticRule('suffix', 'php');

Bien sur il est possible d'agréger la règle dans une propriété de classe, ceci permettra
d'éviter l'appel de méthodes. Ce cas se produit typiquement lorsque l'inflecteur est embarqué
(encapsulé) dans une classe. Vous pouvez à ce moment là interdire la récupération de l'inflecteur
depuis l'extérieur de la classe, par exemple. La méthode setStaticRuleReference() vous
y aidera :

class Foo
{
/**
* @var string Suffix
*/
protected $_suffix = 'phtml';

/**
* Constructor
* @return void
*/
public function __construct()
{
$this->_inflector =
new Zend_Filter_Inflector(':script.:suffix');
$this->_inflector
->setStaticRuleReference('suffix', $this->_suffix);
}

/**
* Set suffix; updates suffix static rule in inflector
*
* @param string $suffix
* @return Foo
*/
public function setSuffix($suffix)
{
$this->_suffix = $suffix;
return $this;
}
}

6.4.2. Règles non statiques : basées sur des filtres


Des filtres de type Zend_Filter peuvent être utilisés comme règles dans l'inflecteur. Ils sont
donc liés à des variables cibles, mais vous pouvez lier plusieurs filtres pour une même cible. Ils
sont alors procédés dans l'ordre (FIFO), prenez donc garde à ceci.

Les règles des filtres sont ajoutées avec setFilterRule(). Cette méthode écrase toute règle
déjà définie.addFilterRule() au contraire, n'écrase pas mais gère une pile de filtres pour
une variable. Les noms des filtres passés à ces 2 méthodes sont de la forme :

• String : une chaîne de caractères représentant le nom de la classe du filtre, ou alors le nom de
la classe moins le préfixe utilisé par le plugin loader. (le préfixe par défaut étant "Zend_Filter").

673
Zend_Filter

• Objet filtre : une instance d'objet implémentant Zend_Filter_Interface.

• Array : un tableau de chaînes ou d'objets.

$inflector = new Zend_Filter_Inflector(':script.:suffix');

// Affecte une règle pour utiliser le filtre


//Zend_Filter_Word_CamelCaseToDash
$inflector->setFilterRule('script', 'Word_CamelCaseToDash');

// Ajoute une règle vers un filtre de casse minuscule


$inflector->addFilterRule('script', new Zend_Filter_StringToLower());

// Affectation de plusieurs règles d'un coup


$inflector->setFilterRule('script', array(
'Word_CamelCaseToDash',
new Zend_Filter_StringToLower()
));

6.4.3. Paramétrer plusieurs règles en une seule fois


En temps normal il est plus pratique de spécifier ses règles (statiques et/ou filtres) en une
seule fois, plutôt qu'en plusieurs étapes. Les méthodes de Zend_Filter_Inflector comme
addRules() et setRules() permettent ceci.

Chacune de ces 2 méthodes prend en paramètre un tableau de variable/règle. La règle peut être
n'importe quel type accepté (string, objet filtre ou array). Les noms des variables proposent une
syntaxe spéciale pour différencier les règles statiques des filtres :

• ":" prefix : règle à base de filtre.

• Pas de prefix : règle statique.

Exemple 379. Paramétrer plusieurs règles en une seule fois

// setRules() accepte la même notation :


$inflector->addRules(array(
// règles filtres:
':controller' => array('CamelCaseToUnderscore','StringToLower'),
':action' => array('CamelCaseToUnderscore','StringToLower'),

// règles statiques :
'suffix' => 'phtml'
));

6.5. Autres méthodes utilitaires


Zend_Filter_Inflector possède d'autres méthodes pour changer le plugin loader,
manipuler des règles, et contrôler les exceptions.

• setPluginLoader() peut être utile si vous avez configuré votre propre chargeur de
plugins (plugin loader) et que vous voulez l'utiliser avec Zend_Filter_Inflector ;
getPluginLoader() retourne cette valeur.

• setThrowTargetExceptionsOn() accepte un booléen. Ceci spécifie qu'une exception


doit être lancée si une variable est toujours présente dans la cible après le passage de

674
Zend_Filter

l'inflecteur. Par défaut, ça n'est pas le cas. isThrowTargetExceptionsOn() retourne la


valeur actuelle.

• getRules($spec = null) récupère toutes les règles, ou les règles d'une certaine variable.

• getRule($spec, $index) récupère une règle précise, même dans une chaîne de
filtre.$index doit être précisé.

• clearRules() va effacer toutes les règles fixées préalablement.

6.6. Zend_Config avec Zend_Filter_Inflector


Zend_Config peut être utilisé pour spécifier les règles, les préfixes des filtres et d'autres
choses dans vos inflecteurs. Passez un objet Zend_Config au constructeur ou à la méthode
setConfig() :

• target définit la cible de l'inflecteur.

• filterPrefixPath définit le préfixe/chemins des filtres.

• throwTargetExceptionsOn est un booléen. Ceci spécifie qu'une exception doit être lancée
si une variable est toujours présente dans la cible après le passage de l'inflecteur.

• targetReplacementIdentifier spécifie le caractère à utiliser pour définir les variables


de remplacement.

• rules spécifie un tableau de règles, comme accepté par addRules().

Exemple 380. Utiliser Zend_Config avec Zend_Filter_Inflector

// Par le constructeur :
$config = new Zend_Config($options);
$inflector = new Zend_Filter_Inflector($config);

// Ou via setConfig() :
$inflector = new Zend_Filter_Inflector();
$inflector->setConfig($config);

675
Zend_Form
1. Zend_Form
Zend_Form simplifie la création et la gestion des formulaires dans vos applications Web. Il
accomplit les buts suivants :

• Validation et filtrage des éléments fournis

• Tri des éléments

• Rendu du formulaire et des éléments, incluant l'échappement

• Groupement des éléments et des formulaires

• Configuration des éléments et des sous-niveaux de formulaires

Il utilise fortement d'autres composants de Zend Framework pour accomplir ses buts,
incluant Zend_Config, Zend_Validate, Zend_Filter, Zend_Loader_PluginLoader, et
optionnellement Zend_View.

2. Zend_Form démarrage rapide


Ce guide rapide couvre les bases de la création, de la validation, et du rendu des formulaires
Zend_Form.

2.1. Créer un objet de formulaire


Instanciez simplement un objet Zend_Form :

$form = new Zend_Form;

Pour des usages avancés, vous voudriez probablement dériver Zend_Form, mais pour les
formulaires simples, vous pouvez créez un formulaire depuis une instance de Zend_Form.

Vous pouvez spécifier (c'est une bonne idée) l'action et la méthode d'envoi du formulaire grâce
à setAction() et setMethod() :

$form->setAction('/resource/process')
->setMethod('post');

Le code ci-dessus indique au formulaire d'être envoyé vers l'URL "/resource/process" avec la
méthode HTTP POST. Ceci va impacter le rendu du formulaire (la balise <form>).

Il est possible d'assigner les attributs HTML supplémentaires à la balise <form> via la méthode
setAttrib() ou encore setAttribs(). Par exemple, indiquons un attribut "id" au formulaire :

$form->setAttrib('id', 'login');

2.2. Ajouter des éléments au formulaire


Un formulaire ne sert à rien sans éléments. Le composant Zend_Form est fourni avec un
ensemble d'éléments qui rendent du code XHTML via les aides de Zend_View. Voici ces aides :

676
Zend_Form

• button

• checkbox (ou plusieurs checkboxes avec multiCheckbox)

• hidden

• image

• password

• radio

• reset

• select (régulier ou à selection multiple)

• submit

• text

• textarea

Vous avez 2 manières de procéder pour ajouter les éléments au formulaire : instanciez vous
même les objets des éléments, ou passer le type d'élément à Zend_Form, qui va alors créer
le bon objet pour vous.

Quelques exemples :

// Ajout d'un objet élément :


$form->addElement(new Zend_Form_Element_Text('username'));

// Passage d'un texte décrivant le futur objet élément, à Zend_Form :


$form->addElement('text', 'username');

Par défaut, ces éléments n'ont ni validateurs, ni filtres. Vous devrez donc ajoutez des validateurs
et/ou des filtres, manuellement. Ceci est possible soit (a) avant de passer l'élément au formulaire,
(b) via les options de configuration passés lors de la création de l'élément, ou (c) en récupérant
l'objet déjà enregistré, depuis le formulaire, et en le configurant ensuite.

Voyons comment passer un validateur à un élément dont nous créons l'objet. On peut passer
soit l'objet Zend_Validate_*, soit une chaîne le décrivant :

$username = new Zend_Form_Element_Text('username');

// Passage d'un objet Zend_Validate_*:


$username->addValidator(new Zend_Validate_Alnum());

// Passage du nom du validateur:


$username->addValidator('alnum');

En utilisant la technique de passage par le nom, vous pouvez ajouter un tableau d'options à
passer au constructeur de l'objet validateur. Ceci se fait en troisième paramètre :

// Passage d'options au validateur


$username->addValidator('regex', false, array('/^[a-z]/i'));

677
Zend_Form

(Le second paramètre permet d'indiquer au validateur s'il doit briser la chaîne de validation ou
non. Par défaut, FALSE : ce n'est donc pas le cas.)

Vous pouvez avoir besoin de spécifier qu'un élément est requis. Ceci peut être fait en utilisant
un accesseur ou en passant une option à la création de l'élément. Voici un exemple :

// Cet élément est requis:


$username->setRequired(true);

Lorsqu'un élément est requis, un validateur "NotEmpty" lui est ajouté, sur le dessus de sa pile
de validateurs.

La gestion des filtres est très semblable à celle des validateurs. Voyons comment ajouter un
filtre qui retourne la donnée en minuscules :

$username->addFilter('StringtoLower');

Finalement, la configuration complète de l'élément pourra ressembler à cela :

$username->addValidator('alnum')
->addValidator('regex', false, array('/^[a-z]/'))
->setRequired(true)
->addFilter('StringToLower');

// ou, de manière plus compacte:


$username->addValidators(array('alnum',
array('regex', false, '/^[a-z]/i')
))
->setRequired(true)
->addFilters(array('StringToLower'));

Aussi simple que cela puisse paraître, cela peut très vite devenir fastidieux de répéter ces
opérations sur tous les éléments du formulaire. Reprenons le cas (b) d'au dessus : lorsque l'on
crée un élément, Zend_Form::addElement() agit comme une fabrique et on peut lui passer
des options de configuration. Par exemple, des validateurs ou des filtres. Essayons ceci :

$form->addElement('text', 'username', array(


'validators' => array(
'alnum',
array('regex', false, '/^[a-z]/i')
),
'required' => true,
'filters' => array('StringToLower'),
));

Si vous vous apercevez que vous créez des éléments basés sur les mêmes
options, étendre Zend_Form_Element peut devenir une bonne option. Votre
nouvelle classe configurera directement vos objets.

2.3. Rendre (visuellement) un formulaire


Rendre un formulaire est très simple. La plupart des éléments nécessitent les aides de vue
Zend_View pour être rendus. Ils ont donc besoin d'un objet de vue. Pour rendre un formulaire,
appelez sa méthode render() ou faites un echo devant l'objet.

678
Zend_Form

// Appel explicite de render() :


echo $form->render($view);

// Supposant que setView() avec passage d'un objet Zend_View a été appelée avant :
echo $form;

Par défaut, Zend_Form et les Zend_Form_Element vont essayer de récupérer l'objet de vue
depuis l'aide d'action ViewRenderer, ce qui signifie que vous n'aurez pas besoin de spécifier
un objet de vue manuellement si vous utilisez le système MVC de Zend Framework. Pour rendre
un formulaire dans une vue MVC, un simple echo suffit :

<?php echo $this->form ?>

Techniquement, Zend_Form utilise des "décorateurs" pour effectuer le rendu visuel. Ces
décorateurs peuvent remplacer le contenu, ou le placer avant ou après. Ils peuvent aussi
introspecter l'élément qui leur est passé. Ainsi, vous pouvez chaîner plusieurs décorateurs pour
utiliser des effets visuels. Par défaut, Zend_Form_Element combine quatre décorateurs pour
s'afficher :

$element->addDecorators(array(
'ViewHelper',
'Errors',
array('HtmlTag', array('tag' => 'dd')),
array('Label', array('tag' => 'dt')),
));

(Où <HELPERNAME> est le nom de l'aide de vue à utiliser, qui varie selon l'élément à rendre.)

Les décorateurs par défaut (rappelés ci-dessus), produisent le rendu suivant :

<dt><label for="username" class="required">Username</dt>


<dd>
<input type="text" name="username" value="123-abc" />
<ul class="errors">
<li>'123-abc' has not only alphabetic and digit characters</li>
<li>'123-abc' does not match against pattern '/^[a-z]/i'</li>
</ul>
</dd>

(Le formatage peut un peu changer.)

Vous pouvez changer les décorateurs utilisés par un élément si vous voulez avoir un visuel
différent ; voyez la section sur les décorateurs pour plus d'informations.

Le formulaire boucle sur ses éléments et entoure leur rendu d'une balise HTML <form>.
Cette balise prend en compte la méthode, l'action, et les éventuels attributs passés via
setAttribs().

Les éléments sont bouclés dans l'ordre dans lequel ils sont ajoutés, ou, si votre élément possède
un attribut "order", celui-ci sera alors utilisé pour gérer sa place dans la pile des éléments :

$element->setOrder(10);

Ou encore, à la création de l'élément via addElement() :

679
Zend_Form

$form->addElement('text', 'username', array('order' => 10));

2.4. Vérifier qu'un formulaire est valide


Après l'envoi du formulaire, il faut vérifier les valeurs que contiennent ses éléments. Tous les
validateurs de chaque élément sont donc interrogés. Si l'élément était marqué comme requis et
que l'élément ne reçoit aucune donnée, les validateurs suivants agiront sur une valeur NULL.

D'où proviennent les données ? Vous pouvez utiliser $_POST ou $_GET, ou n'importe quelle
source de données (service Web par exemple) :

if ($form->isValid($_POST)) {
// succès!
} else {
// echec!
}

Avec des requêtes AJAX, il arrive que l'on ait besoin de ne valider qu'un élément, ou un groupe
d'élément. isValidPartial() validera un formulaire partiel. Contrairement à isValid(), si
une valeur est absente, les autres validateurs ne seront pas interrogés :

if ($form->isValidPartial($_POST)) {
// Tous les éléments présents dans $_POST ont passé la validation
} else {
// un ou plusieurs éléments présent dans $_POST ont échoué
}

La méthode processAjax() peut aussi être utilisée pour valider partiellement un formulaire.
Contrairement à isValidPartial(), cette méthode retournera les messages d'erreur de
validation au format JSON.

En supposant que les validateurs aient passé, vous pouvez dès lors récupérer les valeurs filtrées
depuis les éléments :

$values = $form->getValues();

Si vous désirez les valeurs non filtrées, utilisez :

$unfiltered = $form->getUnfilteredValues();

Si d'un autre côté, vous ne souhaitez que les valeurs filtrées valides d'un formulaire partiellement
valide, vous pouvez appeler :

$values = $form->getValidValues($_POST);

2.5. Les statuts d'erreur


Votre formulaire a échoué à l'envoi ? Dans la plupart des cas, vous voudrez rendre à nouveau
le formulaire, mais avec les messages d'erreur affichés :

if (!$form->isValid($_POST)) {
echo $form;

680
Zend_Form

// ou en assignant un objet de vue (cas non-MVC typiquement)


$this->view->form = $form;
return $this->render('form');
}

Si vous voulez inspecter les erreurs, 2 méthodes s'offrent à vous. getErrors() retourne un
tableau associatif avec en clé le nom de l'élément et en valeur un tableau de codes d'erreurs.
getMessages() retourne un tableau associatif avec en clé le nom de l'élément, et en valeur
un tableau de messages d'erreurs (code=>message). Tout élément ne comportant pas d'erreur
ne sera pas inclus dans le tableau.

2.6. Assembler le tout ensemble


Créons un formulaire de d'authentification. Il aura besoin d'élément représentant :

• un nom

• un mot de passe

• un bouton d'envoi

Pour notre exemple, imaginons un nom composé de caractères alphanumériques uniquement.


Le nom commencera par une lettre, et devra faire entre 6 et 20 caractères de long, qui seront
normalisés en lettres minuscules. Les mots de passe feront 6 caractères minimum.

Nous allons utiliser la puissance de Zend_Form pour configurer le formulaire et effectuer le


rendu :

$form = new Zend_Form();


$form->setAction('/user/login')
->setMethod('post');

// élément nom :
$username = $form->createElement('text', 'username');
$username->addValidator('alnum')
->addValidator('regex', false, array('/^[a-z]+/'))
->addValidator('stringLength', false, array(6, 20))
->setRequired(true)
->addFilter('StringToLower');

// élément mot de passe :


$password = $form->createElement('password', 'password');
$password->addValidator('StringLength', false, array(6))
->setRequired(true);

// Ajout des éléments au formulaire


$form->addElement($username)
->addElement($password)
// addElement() agit comme une fabrique qui crée un bouton 'Login'
->addElement('submit', 'login', array('label' => 'Login'));

Il nous faut à présent un contrôleur pour gérer tout cela :

class UserController extends Zend_Controller_Action


{
public function getForm()

681
Zend_Form

{
// Créer le formulaire comme décrit ci-dessus
return $form;
}

public function indexAction()


{
// rend user/form.phtml
$this->view->form = $this->getForm();
$this->render('form');
}

public function loginAction()


{
if (!$this->getRequest()->isPost()) {
return $this->_forward('index');
}
$form = $this->getForm();
if (!$form->isValid($_POST)) {
// Validation en echec
$this->view->form = $form;
return $this->render('form');
}

$values = $form->getValues();
// les valeurs sont récupérées
}
}

Le script de vue pour afficher le formulaire :

<h2>Identifiez vous:</h2>
<?php echo $this->form ?>

Comme vous le voyez sur le code du contrôleur, il reste du travail à faire une fois le formulaire
validé. Par exemple, utiliser Zend_Auth pour déclencher un processus d'identification.

2.7. Utiliser un objet Zend_Config


Toutes les classes du composant Zend_Form sont configurables au moyen d'un objet
Zend_Config ; vous pouvez passer un objet Zend_Config au constructeur ou via la méthode
setConfig(). Voyons comment créer le formulaire ci-dessus, au moyen d'un fichier INI. Tout
d'abord, nous nous baserons sur une section "developement", et nos instructions devront être
imbriquées afin de refléter la configuration. Ensuite nous utiliserons un espace de nom "user"
correspondant au contrôleur, puis un "login" concernant le formulaire (ceci permet de ranger les
données correctement dans le fichier INI) :

[development]
; informations générales du formulaire
user.login.action = "/user/login"
user.login.method = "post"

; element username
user.login.elements.username.type = "text"
user.login.elements.username.options.validators.alnum.validator = "alnum"
user.login.elements.username.options.validators.regex.validator = "regex"
user.login.elements.username.options.validators.regex.options.pattern = "/^[a-z]/i"

682
Zend_Form

user.login.elements.username.options.validators.strlen.validator = "StringLength"
user.login.elements.username.options.validators.strlen.options.min = "6"
user.login.elements.username.options.validators.strlen.options.max = "20"
user.login.elements.username.options.required = true
user.login.elements.username.options.filters.lower.filter = "StringToLower"

; element password
user.login.elements.password.type = "password"
user.login.elements.password.options.validators.strlen.validator = "StringLength"
user.login.elements.password.options.validators.strlen.options.min = "6"
user.login.elements.password.options.required = true

; element submit
user.login.elements.submit.type = "submit"

Le constructeur du formulaire ressemblera alors à ceci :

$config = new Zend_Config_Ini($configFile, 'development');


$form = new Zend_Form($config->user->login);

et tout le formulaire sera défini.

2.8. Conclusion
Vous êtes maintenant capable de libérer la puissance de Zend_Form. Continuez de lire les
chapitres suivants pour utiliser ce composant en profondeur !

3. Creating Form Elements Using Zend_Form_Element


A form is made of elements that typically correspond to HTML form input. Zend_Form_Element
encapsulates single form elements, with the following areas of responsibility:

• validation (is submitted data valid?)

• capturing of validation error codes and messages

• filtering (how is the element escaped or normalized prior to validation and/or for output?)

• rendering (how is the element displayed?)

• metadata and attributes (what information further qualifies the element?)

The base class, Zend_Form_Element, has reasonable defaults for many cases, but it is best
to extend the class for commonly used special purpose elements. Additionally, Zend Framework
ships with a number of standard XHTML elements; you can read about them in the Standard
Elements chapter.

3.1. Plugin Loaders


Zend_Form_Element makes use of Zend_Loader_PluginLoader to allow developers to specify
locations of alternate validators, filters, and decorators. Each has its own plugin loader associated
with it, and general accessors are used to retrieve and modify each.

The following loader types are used with the various plugin loader methods: 'validate', 'filter', and
'decorator'. The type names are case insensitive.

683
Zend_Form

The methods used to interact with plugin loaders are as follows:

• setPluginLoader($loader, $type): $loader is the plugin loader object itself, while


$type is one of the types specified above. This sets the plugin loader for the given type to
the newly specified loader object.

• getPluginLoader($type): retrieves the plugin loader associated with $type.

• addPrefixPath($prefix, $path, $type = null): adds a prefix/path association to


the loader specified by $type. If $type is NULL, it will attempt to add the path to all loaders, by
appending the prefix with each of "_Validate", "_Filter", and "_Decorator"; and appending the
path with "Validate/", "Filter/", and "Decorator/". If you have all your extra form element classes
under a common hierarchy, this is a convenience method for setting the base prefix for them.

• addPrefixPaths(array $spec): allows you to add many paths at once to one or more
plugin loaders. It expects each array item to be an array with the keys 'path', 'prefix', and 'type'.

Custom validators, filters, and decorators are an easy way to share functionality between forms
and to encapsulate custom functionality.

684
Zend_Form

Exemple 381. Custom Label


One common use case for plugins is to provide replacements for standard classes. For
instance, if you want to provide a different implementation of the 'Label' decorator -- for
instance, to always append a colon -- you could create your own 'Label' decorator with your
own class prefix, and then add it to your prefix path.
Let's start with a custom Label decorator. We'll give it the class prefix "My_Decorator", and
the class itself will be in the file "My/Decorator/Label.php".

class My_Decorator_Label extends Zend_Form_Decorator_Abstract


{
protected $_placement = 'PREPEND';

public function render($content)


{
if (null === ($element = $this->getElement())) {
return $content;
}
if (!method_exists($element, 'getLabel')) {
return $content;
}

$label = $element->getLabel() . ':';

if (null === ($view = $element->getView())) {


return $this->renderLabel($content, $label);
}

$label = $view->formLabel($element->getName(), $label);

return $this->renderLabel($content, $label);


}

public function renderLabel($content, $label)


{
$placement = $this->getPlacement();
$separator = $this->getSeparator();

switch ($placement) {
case 'APPEND':
return $content . $separator . $label;
case 'PREPEND':
default:
return $label . $separator . $content;
}
}
}

Now we can tell the element to use this plugin path when looking for decorators:

$element->addPrefixPath('My_Decorator', 'My/Decorator/', 'decorator');

Alternately, we can do that at the form level to ensure all decorators use this path:

$form->addElementPrefixPath('My_Decorator', 'My/Decorator/', 'decorator');

After it added as in the example above, the 'My/Decorator/' path will be searched first to see
if the decorator exists there when you add a decorator. As a result, 'My_Decorator_Label'
will now be used when the 'Label' decorator is requested.

685
Zend_Form

3.2. Filters
It's often useful and/or necessary to perform some normalization on input prior to validation.
For example, you may want to strip out all HTML, but run your validations on what remains
to ensure the submission is valid. Or you may want to trim empty space surrounding input so
that a StringLength validator will use the correct length of the input without counting leading
or trailing whitespace characters. These operations may be performed using Zend_Filter.
Zend_Form_Element has support for filter chains, allowing you to specify multiple, sequential
filters. Filtering happens both during validation and when you retrieve the element value via
getValue():

$filtered = $element->getValue();

Filters may be added to the chain in two ways:

• passing in a concrete filter instance

• providing a filter name – either a short name or fully qualified class name

Let's see some examples:

// Concrete filter instance:


$element->addFilter(new Zend_Filter_Alnum());

// Fully qualified class name:


$element->addFilter('Zend_Filter_Alnum');

// Short filter name:


$element->addFilter('Alnum');
$element->addFilter('alnum');

Short names are typically the filter name minus the prefix. In the default case, this will mean
minus the 'Zend_Filter_' prefix. The first letter can be upper-cased or lower-cased.

Using Custom Filter Classes


If you have your own set of filter classes, you can tell Zend_Form_Element
about these using addPrefixPath(). For instance, if you have filters under the
'My_Filter' prefix, you can tell Zend_Form_Element about this as follows:

$element->addPrefixPath('My_Filter', 'My/Filter/', 'filter');

(Recall that the third argument indicates which plugin loader on which to perform
the action.)

If at any time you need the unfiltered value, use the getUnfilteredValue() method:

$unfiltered = $element->getUnfilteredValue();

For more information on filters, see the Zend_Filter documentation.

Methods associated with filters include:

• addFilter($nameOfFilter, array $options = null)

• addFilters(array $filters)

686
Zend_Form

• setFilters(array $filters) (overwrites all filters)

• getFilter($name) (retrieve a filter object by name)

• getFilters() (retrieve all filters)

• removeFilter($name) (remove filter by name)

• clearFilters() (remove all filters)

3.3. Validators
If you subscribe to the security mantra of "filter input, escape output," you'll should use validator
to filter input submitted with your form. In Zend_Form, each element includes its own validator
chain, consisting of Zend_Validate_* validators.

Validators may be added to the chain in two ways:

• passing in a concrete validator instance

• providing a validator name – either a short name or fully qualified class name

Let's see some examples:

// Concrete validator instance:


$element->addValidator(new Zend_Validate_Alnum());

// Fully qualified class name:


$element->addValidator('Zend_Validate_Alnum');

// Short validator name:


$element->addValidator('Alnum');
$element->addValidator('alnum');

Short names are typically the validator name minus the prefix. In the default case, this will mean
minus the 'Zend_Validate_' prefix. As is the case with filters, the first letter can be upper-cased
or lower-cased.

Using Custom Validator Classes


If you have your own set of validator classes, you can tell Zend_Form_Element
about these using addPrefixPath(). For instance, if you have validators
under the 'My_Validator' prefix, you can tell Zend_Form_Element about this as
follows:

$element->addPrefixPath('My_Validator', 'My/Validator/', 'validate');

(Recall that the third argument indicates which plugin loader on which to perform
the action.)

If failing a particular validation should prevent later validators from firing, pass boolean TRUE as
the second parameter:

$element->addValidator('alnum', true);

If you are using a string name to add a validator, and the validator class accepts arguments to
the constructor, you may pass these to the third parameter of addValidator() as an array:

687
Zend_Form

$element->addValidator('StringLength', false, array(6, 20));

Arguments passed in this way should be in the order in which they are defined in the constructor.
The above example will instantiate the Zend_Validate_StringLenth class with its $min and
$max parameters:

$validator = new Zend_Validate_StringLength(6, 20);

Providing Custom Validator Error Messages


Some developers may wish to provide custom error messages for a validator.
The $options argument of the Zend_Form_Element::addValidator()
method allows you to do so by providing the key 'messages' and mapping it to an
array of key/value pairs for setting the message templates. You will need to know
the error codes of the various validation error types for the particular validator.

A better option is to use a Zend_Translate_Adapter with your form. Error


codes are automatically passed to the adapter by the default Errors decorator;
you can then specify your own error message strings by setting up translations
for the various error codes of your validators.

You can also set many validators at once, using addValidators(). The basic usage is to
pass an array of arrays, with each array containing 1 to 3 values, matching the constructor of
addValidator():

$element->addValidators(array(
array('NotEmpty', true),
array('alnum'),
array('stringLength', false, array(6, 20)),
));

If you want to be more verbose or explicit, you can use the array keys 'validator',
'breakChainOnFailure', and 'options':

$element->addValidators(array(
array(
'validator' => 'NotEmpty',
'breakChainOnFailure' => true),
array('validator' => 'alnum'),
array(
'validator' => 'stringLength',
'options' => array(6, 20)),
));

This usage is good for illustrating how you could then configure validators in a config file:

element.validators.notempty.validator = "NotEmpty"
element.validators.notempty.breakChainOnFailure = true
element.validators.alnum.validator = "Alnum"
element.validators.strlen.validator = "StringLength"
element.validators.strlen.options.min = 6
element.validators.strlen.options.max = 20

Notice that every item has a key, whether or not it needs one; this is a limitation of using
configuration files -- but it also helps make explicit what the arguments are for. Just remember
that any validator options must be specified in order.

688
Zend_Form

To validate an element, pass the value to isValid():

if ($element->isValid($value)) {
// valid
} else {
// invalid
}

Validation Operates On Filtered Values

Zend_Form_Element::isValid() filters values through the provided filter


chain prior to validation. See the Filters section for more information.

Validation Context

Zend_Form_Element::isValid() supports an additional argument,


$context. Zend_Form::isValid() passes the entire array of
data being processed to $context when validating a form, and
Zend_Form_Element::isValid(), in turn, passes it to each validator. This
means you can write validators that are aware of data passed to other form
elements. As an example, consider a standard registration form that has fields
for both password and a password confirmation; one validation would be that the
two fields match. Such a validator might look like the following:

class My_Validate_PasswordConfirmation extends Zend_Validate_Abstract


{
const NOT_MATCH = 'notMatch';

protected $_messageTemplates = array(


self::NOT_MATCH => 'Password confirmation does not match'
);

public function isValid($value, $context = null)


{
$value = (string) $value;
$this->_setValue($value);

if (is_array($context)) {
if (isset($context['password_confirm'])
&& ($value == $context['password_confirm']))
{
return true;
}
} elseif (is_string($context) && ($value == $context)) {
return true;
}

$this->_error(self::NOT_MATCH);
return false;
}
}

Validators are processed in order. Each validator is processed, unless a validator created with
a TRUE breakChainOnFailure value fails its validation. Be sure to specify your validators in
a reasonable order.

689
Zend_Form

After a failed validation, you can retrieve the error codes and messages from the validator chain:

$errors = $element->getErrors();
$messages = $element->getMessages();

(Note: error messages returned are an associative array of error code / error message pairs.)

In addition to validators, you can specify that an element is required, using


setRequired(true). By default, this flag is FALSE, meaning that your validator chain will be
skipped if no value is passed to isValid(). You can modify this behavior in a number of ways:

• By default, when an element is required, a flag, 'allowEmpty', is also TRUE. This means that if
a value evaluating to empty is passed to isValid(), the validators will be skipped. You can
toggle this flag using the accessor setAllowEmpty($flag); when the flag is FALSE and a
value is passed, the validators will still run.

• By default, if an element is required but does not contain a 'NotEmpty' validator, isValid()
will add one to the top of the stack, with the breakChainOnFailure flag set. This behavior
lends required flag semantic meaning: if no value is passed, we immediately invalidate the
submission and notify the user, and prevent other validators from running on what we already
know is invalid data.

If you do not want this behavior, you can turn it off by passing a FALSE value to
setAutoInsertNotEmptyValidator($flag); this will prevent isValid() from placing
the 'NotEmpty' validator in the validator chain.

For more information on validators, see the Zend_Validate documentation.

Using Zend_Form_Elements as general-purpose validators

Zend_Form_Element implements Zend_Validate_Interface, meaning an


element may also be used as a validator in other, non-form related validation
chains.

When is an element detected as empty?

As mentioned the 'NotEmpty' validator is used to detect if an element is empty


or not. But Zend_Validate_NotEmpty does, per default, not work like PHP's
method empty().

This means when an element contains an integer 0 or an string '0' then the
element will be seen as not empty. If you want to have a different behaviour you
must create your own instance of Zend_Validate_NotEmpty. There you can
define the behaviour of this validator. See Zend_Validate_NotEmpty for details.

Methods associated with validation include:

• setRequired($flag) and isRequired() allow you to set and retrieve the status of the
'required' flag. When set to boolean TRUE, this flag requires that the element be in the data
processed by Zend_Form.

• setAllowEmpty($flag) and getAllowEmpty() allow you to modify the behaviour of


optional elements (i.e., elements where the required flag is FALSE). When the 'allow empty'
flag is TRUE, empty values will not be passed to the validator chain.

690
Zend_Form

• setAutoInsertNotEmptyValidator($flag) allows you to specify whether or not a


'NotEmpty' validator will be prepended to the validator chain when the element is required. By
default, this flag is TRUE.

• addValidator($nameOrValidator, $breakChainOnFailure = false, array


$options = null)

• addValidators(array $validators)

• setValidators(array $validators) (overwrites all validators)

• getValidator($name) (retrieve a validator object by name)

• getValidators() (retrieve all validators)

• removeValidator($name) (remove validator by name)

• clearValidators() (remove all validators)

3.3.1. Custom Error Messages


At times, you may want to specify one or more specific error messages to use instead of the
error messages generated by the validators attached to your element. Additionally, at times you
may want to mark the element invalid yourself. As of 1.6.0, this functionality is possible via the
following methods.

• addErrorMessage($message): add an error message to display on form validation errors.


You may call this more than once, and new messages are appended to the stack.

• addErrorMessages(array $messages): add multiple error messages to display on form


validation errors.

• setErrorMessages(array $messages): add multiple error messages to display on form


validation errors, overwriting all previously set error messages.

• getErrorMessages(): retrieve the list of custom error messages that have been defined.

• clearErrorMessages(): remove all custom error messages that have been defined.

• markAsError(): mark the element as having failed validation.

• hasErrors(): determine whether the element has either failed validation or been marked
as invalid.

• addError($message): add a message to the custom error messages stack and flag the
element as invalid.

• addErrors(array $messages): add several messages to the custom error messages


stack and flag the element as invalid.

• setErrors(array $messages): overwrite the custom error messages stack with the
provided messages and flag the element as invalid.

All errors set in this fashion may be translated. Additionally, you may insert the placeholder
"%value%" to represent the element value; this current element value will be substituted when
the error messages are retrieved.

691
Zend_Form

3.4. Decorators
One particular pain point for many web developers is the creation of the XHTML forms
themselves. For each element, the developer needs to create markup for the element itself
(typically a label) and special markup for displaying validation error messages. The more
elements on the page, the less trivial this task becomes.

Zend_Form_Element tries to solve this issue through the use of "decorators". Decorators are
simply classes that have access to the element and a method for rendering content. For more
information on how decorators work, please see the section on Zend_Form_Decorator.

The default decorators used by Zend_Form_Element are:

• ViewHelper: specifies a view helper to use to render the element. The 'helper' element attribute
can be used to specify which view helper to use. By default, Zend_Form_Element specifies
the 'formText' view helper, but individual subclasses specify different helpers.

• Errors: appends error messages to the element using Zend_View_Helper_FormErrors. If


none are present, nothing is appended.

• Description: appends the element description. If none is present, nothing is appended. By


default, the description is rendered in a <p> tag with a class of 'description'.

• HtmlTag: wraps the element and errors in an HTML <dd> tag.

• Label: prepends a label to the element using Zend_View_Helper_FormLabel, and wraps


it in a <dt> tag. If no label is provided, just the definition term tag is rendered.

Default Decorators Do Not Need to Be Loaded


By default, the default decorators are loaded during object initialization. You
can disable this by passing the 'disableLoadDefaultDecorators' option to the
constructor:

$element = new Zend_Form_Element('foo',


array('disableLoadDefaultDecorators' =>
true)
);

This option may be mixed with any other options you pass, both as array options
or in a Zend_Config object.

Since the order in which decorators are registered matters- the first decorator registered is
executed first- you will need to make sure you register your decorators in an appropriate order,
or ensure that you set the placement options in a sane fashion. To give an example, here is the
code that registers the default decorators:

$this->addDecorators(array(
array('ViewHelper'),
array('Errors'),
array('Description', array('tag' => 'p', 'class' => 'description')),
array('HtmlTag', array('tag' => 'dd')),
array('Label', array('tag' => 'dt')),
));

The initial content is created by the 'ViewHelper' decorator, which creates the form element itself.
Next, the 'Errors' decorator fetches error messages from the element, and, if any are present,

692
Zend_Form

passes them to the 'FormErrors' view helper to render. If a description is present, the 'Description'
decorator will append a paragraph of class 'description' containing the descriptive text to the
aggregated content. The next decorator, 'HtmlTag', wraps the element, errors, and description
in an HTML <dd> tag. Finally, the last decorator, 'label', retrieves the element's label and passes
it to the 'FormLabel' view helper, wrapping it in an HTML <dt> tag; the value is prepended to the
content by default. The resulting output looks basically like this:

<dt><label for="foo" class="optional">Foo</label></dt>


<dd>
<input type="text" name="foo" id="foo" value="123" />
<ul class="errors">
<li>"123" is not an alphanumeric value</li>
</ul>
<p class="description">
This is some descriptive text regarding the element.
</p>
</dd>

For more information on decorators, read the Zend_Form_Decorator section.

Using Multiple Decorators of the Same Type

Internally, Zend_Form_Element uses a decorator's class as the lookup


mechanism when retrieving decorators. As a result, you cannot register multiple
decorators of the same type; subsequent decorators will simply overwrite those
that existed before.

To get around this, you can use aliases. Instead of passing a decorator or
decorator name as the first argument to addDecorator(), pass an array with
a single element, with the alias pointing to the decorator object or name:

// Alias to 'FooBar':
$element->addDecorator(array('FooBar' => 'HtmlTag'),
array('tag' => 'div'));

// And retrieve later:


$decorator = $element->getDecorator('FooBar');

In the addDecorators() and setDecorators() methods, you will need to


pass the 'decorator' option in the array representing the decorator:

// Add two 'HtmlTag' decorators, aliasing one to 'FooBar':


$element->addDecorators(
array('HtmlTag', array('tag' => 'div')),
array(
'decorator' => array('FooBar' => 'HtmlTag'),
'options' => array('tag' => 'dd')
),
);

// And retrieve later:


$htmlTag = $element->getDecorator('HtmlTag');
$fooBar = $element->getDecorator('FooBar');

Methods associated with decorators include:

693
Zend_Form

• addDecorator($nameOrDecorator, array $options = null)

• addDecorators(array $decorators)

• setDecorators(array $decorators) (overwrites all decorators)

• getDecorator($name) (retrieve a decorator object by name)

• getDecorators() (retrieve all decorators)

• removeDecorator($name) (remove decorator by name)

• clearDecorators() (remove all decorators)

Zend_Form_Element also uses overloading to allow rendering specific decorators. __call()


will intercept methods that lead with the text 'render' and use the remainder of the method name
to lookup a decorator; if found, it will then render that single decorator. Any arguments passed
to the method call will be used as content to pass to the decorator's render() method. As an
example:

// Render only the ViewHelper decorator:


echo $element->renderViewHelper();

// Render only the HtmlTag decorator, passing in content:


echo $element->renderHtmlTag("This is the html tag content");

If the decorator does not exist, an exception is raised.

3.5. Metadata and Attributes


Zend_Form_Element handles a variety of attributes and element metadata. Basic attributes
include:

• name: the element name. Uses the setName() and getName() accessors.

• label: the element label. Uses the setLabel() and getLabel() accessors.

• order: the index at which an element should appear in the form. Uses the setOrder() and
getOrder() accessors.

• value: the current element value. Uses the setValue() and getValue() accessors.

• description: a description of the element; often used to provide tooltip or javascript


contextual hinting describing the purpose of the element. Uses the setDescription() and
getDescription() accessors.

• required: flag indicating whether or not the element is required when performing form
validation. Uses the setRequired() and getRequired() accessors. This flag is FALSE
by default.

• allowEmpty: flag indicating whether or not a non-required (optional) element should attempt
to validate empty values. If it is set to TRUE and the required flag is FALSE, empty values are
not passed to the validator chain and are presumed TRUE. Uses the setAllowEmpty() and
getAllowEmpty() accessors. This flag is TRUE by default.

• autoInsertNotEmptyValidator: flag indicating whether or not to insert a 'NotEmpty'


validator when the element is required. By default, this flag is TRUE. Set the
flag with setAutoInsertNotEmptyValidator($flag) and determine the value with
autoInsertNotEmptyValidator().

694
Zend_Form

Form elements may require additional metadata. For XHTML form elements, for instance, you
may want to specify attributes such as the class or id. To facilitate this are a set of accessors:

• setAttrib($name, $value): add an attribute

• setAttribs(array $attribs): like addAttribs(), but overwrites

• getAttrib($name): retrieve a single attribute value

• getAttribs(): retrieve all attributes as key/value pairs

Most of the time, however, you can simply access them as object properties, as
Zend_Form_Element utilizes overloading to facilitate access to them:

// Equivalent to $element->setAttrib('class', 'text'):


$element->class = 'text;

By default, all attributes are passed to the view helper used by the element during rendering,
and rendered as HTML attributes of the element tag.

3.6. Standard Elements


Zend_Form ships with a number of standard elements; please read the Standard Elements
chapter for full details.

3.7. Zend_Form_Element Methods


Zend_Form_Element has many, many methods. What follows is a quick summary of their
signatures, grouped by type:

• Configuration:

• setOptions(array $options)

• setConfig(Zend_Config $config)

• I18n:

• setTranslator(Zend_Translate_Adapter $translator = null)

• getTranslator()

• setDisableTranslator($flag)

• translatorIsDisabled()

• Properties:

• setName($name)

• getName()

• setValue($value)

• getValue()

• getUnfilteredValue()

695
Zend_Form

• setLabel($label)

• getLabel()

• setDescription($description)

• getDescription()

• setOrder($order)

• getOrder()

• setRequired($flag)

• getRequired()

• setAllowEmpty($flag)

• getAllowEmpty()

• setAutoInsertNotEmptyValidator($flag)

• autoInsertNotEmptyValidator()

• setIgnore($flag)

• getIgnore()

• getType()

• setAttrib($name, $value)

• setAttribs(array $attribs)

• getAttrib($name)

• getAttribs()

• Plugin loaders and paths:

• setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type)

• getPluginLoader($type)

• addPrefixPath($prefix, $path, $type = null)

• addPrefixPaths(array $spec)

• Validation:

• addValidator($validator, $breakChainOnFailure = false, $options =


array())

• addValidators(array $validators)

• setValidators(array $validators)

• getValidator($name)

696
Zend_Form

• getValidators()

• removeValidator($name)

• clearValidators()

• isValid($value, $context = null)

• getErrors()

• getMessages()

• Filters:

• addFilter($filter, $options = array())

• addFilters(array $filters)

• setFilters(array $filters)

• getFilter($name)

• getFilters()

• removeFilter($name)

• clearFilters()

• Rendering:

• setView(Zend_View_Interface $view = null)

• getView()

• addDecorator($decorator, $options = null)

• addDecorators(array $decorators)

• setDecorators(array $decorators)

• getDecorator($name)

• getDecorators()

• removeDecorator($name)

• clearDecorators()

• render(Zend_View_Interface $view = null)

3.8. Configuration
Zend_Form_Element's constructor accepts either an array of options or a Zend_Config object
containing options, and it can also be configured using either setOptions() or setConfig().
Generally speaking, keys are named as follows:

• If 'set' + key refers to a Zend_Form_Element method, then the value provided will be passed
to that method.

697
Zend_Form

• Otherwise, the value will be used to set an attribute.

Exceptions to the rule include the following:

• prefixPath will be passed to addPrefixPaths()

• The following setters cannot be set in this way:

• setAttrib (though setAttribs will work)

• setConfig

• setOptions

• setPluginLoader

• setTranslator

• setView

As an example, here is a config file that passes configuration for every type of configurable data:

[element]
name = "foo"
value = "foobar"
label = "Foo:"
order = 10
required = true
allowEmpty = false
autoInsertNotEmptyValidator = true
description = "Foo elements are for examples"
ignore = false
attribs.id = "foo"
attribs.class = "element"
; sets 'onclick' attribute
onclick = "autoComplete(this, '/form/autocomplete/element')"
prefixPaths.decorator.prefix = "My_Decorator"
prefixPaths.decorator.path = "My/Decorator/"
disableTranslator = 0
validators.required.validator = "NotEmpty"
validators.required.breakChainOnFailure = true
validators.alpha.validator = "alpha"
validators.regex.validator = "regex"
validators.regex.options.pattern = "/^[A-F].*/$"
filters.ucase.filter = "StringToUpper"
decorators.element.decorator = "ViewHelper"
decorators.element.options.helper = "FormText"
decorators.label.decorator = "Label"

3.9. Custom Elements


You can create your own custom elements by simply extending the Zend_Form_Element class.
Common reasons to do so include:

• Elements that share common validators and/or filters

• Elements that have custom decorator functionality

698
Zend_Form

There are two methods typically used to extend an element: init(), which can be used to add
custom initialization logic to your element, and loadDefaultDecorators(), which can be
used to set a list of default decorators used by your element.

As an example, let's say that all text elements in a form you are creating need to be filtered with
StringTrim, validated with a common regular expression, and that you want to use a custom
decorator you've created for displaying them, 'My_Decorator_TextItem'. In addition, you have a
number of standard attributes, including 'size', 'maxLength', and 'class' you wish to specify. You
could define an element to accomplish this as follows:

class My_Element_Text extends Zend_Form_Element


{
public function init()
{
$this->addPrefixPath('My_Decorator', 'My/Decorator/', 'decorator')
->addFilters('StringTrim')
->addValidator('Regex', false, array('/^[a-z0-9]{6,}$/i'))
->addDecorator('TextItem')
->setAttrib('size', 30)
->setAttrib('maxLength', 45)
->setAttrib('class', 'text');
}
}

You could then inform your form object about the prefix path for such elements, and start creating
elements:

$form->addPrefixPath('My_Element', 'My/Element/', 'element')


->addElement('text', 'foo');

The 'foo' element will now be of type My_Element_Text, and exhibit the behaviour you've
outlined.

Another method you may want to override when extending Zend_Form_Element is the
loadDefaultDecorators() method. This method conditionally loads a set of default
decorators for your element; you may wish to substitute your own decorators in your extending
class:

class My_Element_Text extends Zend_Form_Element


{
public function loadDefaultDecorators()
{
$this->addDecorator('ViewHelper')
->addDecorator('DisplayError')
->addDecorator('Label')
->addDecorator('HtmlTag',
array('tag' => 'div', 'class' => 'element'));
}
}

There are many ways to customize elements. Read the API documentation of
Zend_Form_Element to learn about all of the available methods.

4. Creating Forms Using Zend_Form


The Zend_Form class is used to aggregate form elements, display groups, and subforms. It can
then perform the following actions on those items:

699
Zend_Form

• Validation, including retrieving error codes and messages

• Value aggregation, including populating items and retrieving both filtered and unfiltered values
from all items

• Iteration over all items, in the order in which they are entered or based on the order hints
retrieved from each item

• Rendering of the entire form, either via a single decorator that performs custom rendering or
by iterating over each item in the form

While forms created with Zend_Form may be complex, probably the best use case is for simple
forms; its best use is for Rapid Application Development (RAD) and prototyping.

At its most basic, you simply instantiate a form object:

// Generic form object:


$form = new Zend_Form();

// Custom form object:


$form = new My_Form()

You can optionally pass in a instance of Zend_Config or an array, which will be used to set
object state and potentially create new elements:

// Passing in configuration options:


$form = new Zend_Form($config);

Zend_Form is iterable, and will iterate over elements, display groups, and subforms, using the
order they were registered and any order index each may have. This is useful in cases where
you wish to render the elements manually in the appropriate order.

Zend_Form's magic lies in its ability to serve as a factory for elements and display groups, as
well as the ability to render itself through decorators.

4.1. Plugin Loaders


Zend_Form makes use of Zend_Loader_PluginLoader to allow developers to specify the
locations of alternate elements and decorators. Each has its own plugin loader associated with
it, and general accessors are used to retrieve and modify each.

The following loader types are used with the various plugin loader methods: 'element' and
'decorator'. The type names are case insensitive.

The methods used to interact with plugin loaders are as follows:

• setPluginLoader($loader, $type): $loader is the plugin loader object itself, while type
is one of the types specified above. This sets the plugin loader for the given type to the newly
specified loader object.

• getPluginLoader($type): retrieves the plugin loader associated with $type.

• addPrefixPath($prefix, $path, $type = null): adds a prefix/path association to


the loader specified by $type. If $type is NULL, it will attempt to add the path to all loaders, by
appending the prefix with each of "_Element" and "_Decorator"; and appending the path with

700
Zend_Form

"Element/" and "Decorator/". If you have all your extra form element classes under a common
hierarchy, this is a convenience method for setting the base prefix for them.

• addPrefixPaths(array $spec): allows you to add many paths at once to one or more
plugin loaders. It expects each array item to be an array with the keys 'path', 'prefix', and 'type'.

Additionally, you can specify prefix paths for all elements and display groups created through a
Zend_Form instance using the following methods:

• addElementPrefixPath($prefix, $path, $type = null): Just like


addPrefixPath(), you must specify a class prefix and a path. $type, when specified, must
be one of the plugin loader types specified by Zend_Form_Element; see the element plugins
section for more information on valid $type values. If no $type is specified, the method will
assume it is a general prefix for all types.

• addDisplayGroupPrefixPath($prefix, $path): Just like addPrefixPath(), you


must specify a class prefix and a path; however, since display groups only support decorators
as plugins, no $type is necessary.

Custom elements and decorators are an easy way to share functionality between forms and
encapsulate custom functionality. See the Custom Label example in the elements documentation
for an example of how custom elements can be used as replacements for standard classes.

4.2. Elements
Zend_Form provides several accessors for adding and removing form elements from a form.
These can take element object instances or serve as factories for instantiating the element
objects themselves.

The most basic method for adding an element is addElement(). This method can take either
an object of type Zend_Form_Element (or of a class extending Zend_Form_Element), or
arguments for building a new element -- including the element type, name, and any configuration
options.

Some examples:

// Using an element instance:


$element = new Zend_Form_Element_Text('foo');
$form->addElement($element);

// Using a factory
//
// Creates an element of type Zend_Form_Element_Text with the
// name of 'foo':
$form->addElement('text', 'foo');

// Pass label option to the element:


$form->addElement('text', 'foo', array('label' => 'Foo:'));

addElement() Implements Fluent Interface

addElement() implements a fluent interface; that is to say, it returns the


Zend_Form object, and not the element. This is done to allow you to chain
together multiple addElement() methods or other form methods that implement
the fluent interface (all setters in Zend_Form implement the pattern).

701
Zend_Form

If you wish to return the element instead, use createElement(), which is


outlined below. Be aware, however, that createElement() does not attach the
element to the form.

Internally, addElement() actually uses createElement() to create the


element before attaching it to the form.

Once an element has been added to the form, you can retrieve it by name. This can be done
either by using the getElement() method or by using overloading to access the element as
an object property:

// getElement():
$foo = $form->getElement('foo');

// As object property:
$foo = $form->foo;

Occasionally, you may want to create an element without attaching it to the form (for instance, if
you wish to make use of the various plugin paths registered with the form, but wish to later attach
the object to a sub form). The createElement() method allows you to do so:

// $username becomes a Zend_Form_Element_Text object:


$username = $form->createElement('text', 'username');

4.2.1. Populating and Retrieving Values


After validating a form, you will typically need to retrieve the values so you can perform other
operations, such as updating a database or notifying a web service. You can retrieve all values for
all elements using getValues(); getValue($name) allows you to retrieve a single element's
value by element name:

// Get all values:


$values = $form->getValues();

// Get only 'foo' element's value:


$value = $form->getValue('foo');

Sometimes you'll want to populate the form with specified values prior to rendering. This can be
done with either the setDefaults() or populate() methods:

$form->setDefaults($data);
$form->populate($data);

On the flip side, you may want to clear a form after populating or validating it; this can be done
using the reset() method:

$form->reset();

4.2.2. Global Operations


Occasionally you will want certain operations to affect all elements. Common scenarios include
needing to set plugin prefix paths for all elements, setting decorators for all elements, and setting
filters for all elements. As examples:

702
Zend_Form

Exemple 382. Setting Prefix Paths for All Elements

You can set prefix paths for all elements by type, or using a global prefix. Some examples:

// Set global prefix path:


// Creates paths for prefixes My_Foo_Filter, My_Foo_Validate,
// and My_Foo_Decorator
$form->addElementPrefixPath('My_Foo', 'My/Foo/');

// Just filter paths:


$form->addElementPrefixPath('My_Foo_Filter',
'My/Foo/Filter',
'filter');

// Just validator paths:


$form->addElementPrefixPath('My_Foo_Validate',
'My/Foo/Validate',
'validate');

// Just decorator paths:


$form->addElementPrefixPath('My_Foo_Decorator',
'My/Foo/Decorator',
'decorator');

Exemple 383. Setting Decorators for All Elements

You can set decorators for all elements. setElementDecorators() accepts an array of
decorators, just like setDecorators(), and will overwrite any previously set decorators in
each element. In this example, we set the decorators to simply a ViewHelper and a Label:

$form->setElementDecorators(array(
'ViewHelper',
'Label'
));

703
Zend_Form

Exemple 384. Setting Decorators for Some Elements

You can also set decorators for a subset of elements, either by inclusion or exclusion. The
second argument to setElementDecorators() may be an array of element names; by
default, specifying such an array will set the specified decorators on those elements only.
You may also pass a third argument, a flag indicating whether this list of elements is for
inclusion or exclusion purposes. If the flag is FALSE, it will decorate all elements except
those in the passed list. As with standard usage of the method, any decorators passed will
overwrite any previously set decorators in each element.

In the following snippet, we indicate that we want only the ViewHelper and Label decorators
for the 'foo' and 'bar' elements:

$form->setElementDecorators(
array(
'ViewHelper',
'Label'
),
array(
'foo',
'bar'
)
);

On the flip side, with this snippet, we'll now indicate that we want to use only the ViewHelper
and Label decorators for every element except the 'foo' and 'bar' elements:

$form->setElementDecorators(
array(
'ViewHelper',
'Label'
),
array(
'foo',
'bar'
),
false
);

Some Decorators are Inappropriate for Some Elements

While setElementDecorators() may seem like a good solution, there are


some cases where it may actually end up with unexpected results. For example,
the various button elements (Submit, Button, Reset) currently use the label as
the value of the button, and only use ViewHelper and DtDdWrapper decorators
-- preventing an additional labels, errors, and hints from being rendered. The
example above would duplicate some content (the label) for button elements.

You can use the inclusion/exclusion array to overcome this issue as noted in the
previous example.

So, use this method wisely, and realize that you may need to exclude some
elements or manually change some elements' decorators to prevent unwanted
output.

704
Zend_Form

Exemple 385. Setting Filters for All Elements

In some cases, you may want to apply the same filter to all elements; a common case is
to trim() all values:

$form->setElementFilters(array('StringTrim'));

4.2.3. Methods For Interacting With Elements


The following methods may be used to interact with elements:

• createElement($element, $name = null, $options = null)

• addElement($element, $name = null, $options = null)

• addElements(array $elements)

• setElements(array $elements)

• getElement($name)

• getElements()

• removeElement($name)

• clearElements()

• setDefaults(array $defaults)

• setDefault($name, $value)

• getValue($name)

• getValues()

• getUnfilteredValue($name)

• getUnfilteredValues()

• setElementFilters(array $filters)

• setElementDecorators(array $decorators)

• addElementPrefixPath($prefix, $path, $type = null)

• addElementPrefixPaths(array $spec)

4.3. Display Groups


Display groups are a way to create virtual groupings of elements for display purposes. All
elements remain accessible by name in the form, but when iterating over the form or rendering,
any elements in a display group are rendered together. The most common use case for this is
for grouping elements in fieldsets.

The base class for display groups is Zend_Form_DisplayGroup. While it can be instantiated
directly, it is usually best to use Zend_Form's addDisplayGroup() method to do so. This
method takes an array of elements as its first argument, and a name for the display group as

705
Zend_Form

its second argument. You may optionally pass in an array of options or a Zend_Config object
as the third argument.

Assuming that the elements 'username' and 'password' are already set in the form, the following
code would group these elements in a 'login' display group:

$form->addDisplayGroup(array('username', 'password'), 'login');

You can access display groups using the getDisplayGroup() method, or via overloading
using the display group's name:

// Using getDisplayGroup():
$login = $form->getDisplayGroup('login');

// Using overloading:
$login = $form->login;

Default Decorators Do Not Need to Be Loaded


By default, the default decorators are loaded during object initialization. You can
disable this by passing the 'disableLoadDefaultDecorators' option when creating
a display group:

$form->addDisplayGroup(
array('foo', 'bar'),
'foobar',
array('disableLoadDefaultDecorators' => true)
);

This option may be mixed with any other options you pass, both as array options
or in a Zend_Config object.

4.3.1. Global Operations


Just as with elements, there are some operations which might affect all display groups; these
include setting decorators and setting the plugin path in which to look for decorators.

Exemple 386. Setting Decorator Prefix Path for All Display Groups

By default, display groups inherit whichever decorator paths the form uses; however, if they
should look in alternate locations, you can use the addDisplayGroupPrefixPath()
method.

$form->addDisplayGroupPrefixPath('My_Foo_Decorator', 'My/Foo/Decorator');

Exemple 387. Setting Decorators for All Display Groups

You can set decorators for all display groups. setDisplayGroupDecorators() accepts
an array of decorators, just like setDecorators(), and will overwrite any previously set
decorators in each display group. In this example, we set the decorators to simply a fieldset
(the FormElements decorator is necessary to ensure that the elements are iterated):

$form->setDisplayGroupDecorators(array(
'FormElements',
'Fieldset'
));

706
Zend_Form

4.3.2. Using Custom Display Group Classes


By default, Zend_Form uses the Zend_Form_DisplayGroup class for display groups.
You may find you need to extend this class in order to provided custom functionality.
addDisplayGroup() does not allow passing in a concrete instance, but does allow specifying
the class to use as one of its options, using the 'displayGroupClass' key:

// Use the 'My_DisplayGroup' class


$form->addDisplayGroup(
array('username', 'password'),
'user',
array('displayGroupClass' => 'My_DisplayGroup')
);

If the class has not yet been loaded, Zend_Form will attempt to do so using Zend_Loader.

You can also specify a default display group class to use with the form such that all display
groups created with the form object will use that class:

// Use the 'My_DisplayGroup' class for all display groups:


$form->setDefaultDisplayGroupClass('My_DisplayGroup');

This setting may be specified in configurations as 'defaultDisplayGroupClass', and will be loaded


early to ensure all display groups use that class.

4.3.3. Methods for Interacting With Display Groups


The following methods may be used to interact with display groups:

• addDisplayGroup(array $elements, $name, $options = null)

• addDisplayGroups(array $groups)

• setDisplayGroups(array $groups)

• getDisplayGroup($name)

• getDisplayGroups()

• removeDisplayGroup($name)

• clearDisplayGroups()

• setDisplayGroupDecorators(array $decorators)

• addDisplayGroupPrefixPath($prefix, $path)

• setDefaultDisplayGroupClass($class)

• getDefaultDisplayGroupClass($class)

4.3.4. Zend_Form_DisplayGroup Methods


Zend_Form_DisplayGroup has the following methods, grouped by type:

• Configuration:

• setOptions(array $options)

• setConfig(Zend_Config $config)

707
Zend_Form

• Metadata:

• setAttrib($key, $value)

• addAttribs(array $attribs)

• setAttribs(array $attribs)

• getAttrib($key)

• getAttribs()

• removeAttrib($key)

• clearAttribs()

• setName($name)

• getName()

• setDescription($value)

• getDescription()

• setLegend($legend)

• getLegend()

• setOrder($order)

• getOrder()

• Elements:

• createElement($type, $name, array $options = array())

• addElement($typeOrElement, $name, array $options = array())

• addElements(array $elements)

• setElements(array $elements)

• getElement($name)

• getElements()

• removeElement($name)

• clearElements()

• Plugin loaders:

• setPluginLoader(Zend_Loader_PluginLoader $loader)

• getPluginLoader()

• addPrefixPath($prefix, $path)

• addPrefixPaths(array $spec)

708
Zend_Form

• Decorators:

• addDecorator($decorator, $options = null)

• addDecorators(array $decorators)

• setDecorators(array $decorators)

• getDecorator($name)

• getDecorators()

• removeDecorator($name)

• clearDecorators()

• Rendering:

• setView(Zend_View_Interface $view = null)

• getView()

• render(Zend_View_Interface $view = null)

• I18n:

• setTranslator(Zend_Translate_Adapter $translator = null)

• getTranslator()

• setDisableTranslator($flag)

• translatorIsDisabled()

4.4. Sub Forms


Sub forms serve several purposes:

• Creating logical element groups. Since sub forms are simply forms, you can validate subforms
as individual entities.

• Creating multi-page forms. Since sub forms are simply forms, you can display a separate sub
form per page, building up multi-page forms where each form has its own validation logic. Only
once all sub forms validate would the form be considered complete.

• Display groupings. Like display groups, sub forms, when rendered as part of a larger form,
can be used to group elements. Be aware, however, that the master form object will have no
awareness of the elements in sub forms.

A sub form may be a Zend_Form object, or, more typically, a Zend_Form_SubForm object. The
latter contains decorators suitable for inclusion in a larger form (i.e., it does not render additional
HTML form tags, but does group elements). To attach a sub form, simply add it to the form and
give it a name:

$form->addSubForm($subForm, 'subform');

You can retrieve a sub form using either getSubForm($name) or overloading using the sub
form name:

709
Zend_Form

// Using getSubForm():
$subForm = $form->getSubForm('subform');

// Using overloading:
$subForm = $form->subform;

Sub forms are included in form iteration, although the elements they contain are not.

4.4.1. Global Operations


Like elements and display groups, there are some operations that might need to affect all sub
forms. Unlike display groups and elements, however, sub forms inherit most functionality from
the master form object, and the only real operation that may need to be performed globally is
setting decorators for sub forms. For this purpose, there is the setSubFormDecorators()
method. In the next example, we'll set the decorator for all subforms to be simply a fieldset (the
FormElements decorator is needed to ensure its elements are iterated):

$form->setSubFormDecorators(array(
'FormElements',
'Fieldset'
));

4.4.2. Methods for Interacting With Sub Forms


The following methods may be used to interact with sub forms:

• addSubForm(Zend_Form $form, $name, $order = null)

• addSubForms(array $subForms)

• setSubForms(array $subForms)

• getSubForm($name)

• getSubForms()

• removeSubForm($name)

• clearSubForms()

• setSubFormDecorators(array $decorators)

4.5. Metadata and Attributes


While a form's usefulness primarily derives from the elements it contains, it can also contain other
metadata, such as a name (often used as a unique ID in the HTML markup); the form action
and method; the number of elements, groups, and sub forms it contains; and arbitrary metadata
(usually used to set HTML attributes for the form tag itself).

You can set and retrieve a form's name using the name accessors:

// Set the name:


$form->setName('registration');

// Retrieve the name:


$name = $form->getName();

710
Zend_Form

To set the action (url to which the form submits) and method (method by which it should submit,
e.g., 'POST' or 'GET'), use the action and method accessors:

// Set the action and method:


$form->setAction('/user/login')
->setMethod('post');

You may also specify the form encoding type specifically using the enctype
accessors. Zend_Form defines two constants, Zend_Form::ENCTYPE_URLENCODED and
Zend_Form::ENCTYPE_MULTIPART, corresponding to the values 'application/x-www-form-
urlencoded' and 'multipart/form-data', respectively; however, you can set this to any arbitrary
encoding type.

// Set the action, method, and enctype:


$form->setAction('/user/login')
->setMethod('post')
->setEnctype(Zend_Form::ENCTYPE_MULTIPART);

The method, action, and enctype are only used internally for rendering, and not
for any sort of validation.

Zend_Form implements the Countable interface, allowing you to pass it as an argument to


count:

$numItems = count($form);

Setting arbitrary metadata is done through the attribs accessors. Since overloading in
Zend_Form is used to access elements, display groups, and sub forms, this is the only method
for accessing metadata.

// Setting attributes:
$form->setAttrib('class', 'zend-form')
->addAttribs(array(
'id' => 'registration',
'onSubmit' => 'validate(this)',
));

// Retrieving attributes:
$class = $form->getAttrib('class');
$attribs = $form->getAttribs();

// Remove an attribute:
$form->removeAttrib('onSubmit');

// Clear all attributes:


$form->clearAttribs();

4.6. Decorators
Creating the markup for a form is often a time-consuming task, particularly if you plan on re-using
the same markup to show things such as validation errors, submitted values, etc. Zend_Form's
answer to this issue is decorators.

Decorators for Zend_Form objects can be used to render a form. The FormElements decorator
will iterate through all items in a form -- elements, display groups, and sub forms -- and render

711
Zend_Form

them, returning the result. Additional decorators may then be used to wrap this content, or append
or prepend it.

The default decorators for Zend_Form are FormElements, HtmlTag (wraps in a definition list),
and Form; the equivalent code for creating them is as follows:

$form->setDecorators(array(
'FormElements',
array('HtmlTag', array('tag' => 'dl')),
'Form'
));

This creates output like the following:

<form action="/form/action" method="post">


<dl>
...
</dl>
</form>

Any attributes set on the form object will be used as HTML attributes of the <form> tag.

Default Decorators Do Not Need to Be Loaded


By default, the default decorators are loaded during object initialization. You
can disable this by passing the 'disableLoadDefaultDecorators' option to the
constructor:

$form = new Zend_Form(array('disableLoadDefaultDecorators' => true));

This option may be mixed with any other options you pass, both as array options
or in a Zend_Config object.

Using Multiple Decorators of the Same Type


Internally, Zend_Form uses a decorator's class as the lookup mechanism when
retrieving decorators. As a result, you cannot register multiple decorators of the
same type; subsequent decorators will simply overwrite those that existed before.

To get around this, you can use aliases. Instead of passing a decorator or
decorator name as the first argument to addDecorator(), pass an array with
a single element, with the alias pointing to the decorator object or name:

// Alias to 'FooBar':
$form->addDecorator(array('FooBar' => 'HtmlTag'), array('tag' => 'div'));

// And retrieve later:


$form = $element->getDecorator('FooBar');

In the addDecorators() and setDecorators() methods, you will need to


pass the 'decorator' option in the array representing the decorator:

// Add two 'HtmlTag' decorators, aliasing one to 'FooBar':


$form->addDecorators(
array('HtmlTag', array('tag' => 'div')),
array(

712
Zend_Form

'decorator' => array('FooBar' => 'HtmlTag'),


'options' => array('tag' => 'dd')
),
);

// And retrieve later:


$htmlTag = $form->getDecorator('HtmlTag');
$fooBar = $form->getDecorator('FooBar');

You may create your own decorators for generating the form. One common use case is if you
know the exact HTML you wish to use; your decorator could create the exact HTML and simply
return it, potentially using the decorators from individual elements or display groups.

The following methods may be used to interact with decorators:

• addDecorator($decorator, $options = null)

• addDecorators(array $decorators)

• setDecorators(array $decorators)

• getDecorator($name)

• getDecorators()

• removeDecorator($name)

• clearDecorators()

Zend_Form also uses overloading to allow rendering specific decorators. __call() will
intercept methods that lead with the text 'render' and use the remainder of the method name to
lookup a decorator; if found, it will then render that single decorator. Any arguments passed to the
method call will be used as content to pass to the decorator's render() method. As an example:

// Render only the FormElements decorator:


echo $form->renderFormElements();

// Render only the fieldset decorator, passing in content:


echo $form->renderFieldset("<p>This is fieldset content</p>");

If the decorator does not exist, an exception is raised.

4.7. Validation
A primary use case for forms is validating submitted data. Zend_Form allows you to validate
an entire form, a partial form, or responses for XmlHttpRequests (AJAX). If the submitted data
is not valid, it has methods for retrieving the various error codes and messages for elements
and sub forms.

To validate a full form, use the isValid() method:

if (!$form->isValid($_POST)) {
// failed validation
}

isValid() will validate every required element, and any unrequired element contained in the
submitted data.

713
Zend_Form

Sometimes you may need to validate only a subset of the data; for this, use
isValidPartial($data):

if (!$form->isValidPartial($data)) {
// failed validation
}

isValidPartial() only attempts to validate those items in the data for which there are
matching elements; if an element is not represented in the data, it is skipped.

When validating elements or groups of elements for an AJAX request, you will typically be
validating a subset of the form, and want the response back in JSON. processAjax() does
precisely that:

$json = $form->processAjax($data);

You can then simply send the JSON response to the client. If the form is valid, this will be a
boolean TRUE response. If not, it will be a javascript object containing key/message pairs, where
each 'message' is an array of validation error messages.

For forms that fail validation, you can retrieve both error codes and error messages, using
getErrors() and getMessages(), respectively:

$codes = $form->getErrors();
$messages = $form->getMessages();

Since the messages returned by getMessages() are an array of error code/


message pairs, getErrors() is typically not needed.

You can retrieve codes and error messages for individual elements by simply passing the element
name to each:

$codes = $form->getErrors('username');
$messages = $form->getMessages('username');

Note: When validating elements, Zend_Form sends a second argument to each


element's isValid() method: the array of data being validated. This can then
be used by individual validators to allow them to utilize other submitted values
when determining the validity of the data. An example would be a registration
form that requires both a password and password confirmation; the password
element could use the password confirmation as part of its validation.

4.7.1. Custom Error Messages


At times, you may want to specify one or more specific error messages to use instead of the error
messages generated by the validators attached to your elements. Additionally, at times you may
want to mark the form invalid yourself. This functionality is possible via the following methods.

• addErrorMessage($message): add an error message to display on form validation errors.


You may call this more than once, and new messages are appended to the stack.

• addErrorMessages(array $messages): add multiple error messages to display on form


validation errors.

714
Zend_Form

• setErrorMessages(array $messages): add multiple error messages to display on form


validation errors, overwriting all previously set error messages.

• getErrorMessages(): retrieve the list of custom error messages that have been defined.

• clearErrorMessages(): remove all custom error messages that have been defined.

• markAsError(): mark the form as having failed validation.

• addError($message): add a message to the custom error messages stack and flag the
form as invalid.

• addErrors(array $messages): add several messages to the custom error messages


stack and flag the form as invalid.

• setErrors(array $messages): overwrite the custom error messages stack with the
provided messages and flag the form as invalid.

All errors set in this fashion may be translated.

4.7.2. Retrieving Valid Values Only


There are scenarios when you want to allow your user to work on a valid form in several steps.
Meanwhile you allow the user to save the form with any set of values inbetween. Then if all the
data is specified you can transfer the model from the building or prototying stage to a valid stage.

You can retrieve all the valid values that match the submitted data by calling:

$validValues = $form->getValidValues($_POST);

4.8. Methods
The following is a full list of methods available to Zend_Form, grouped by type:

• Configuration and Options:

• setOptions(array $options)

• setConfig(Zend_Config $config)

• Plugin Loaders and paths:

• setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type =


null)

• getPluginLoader($type = null)

• addPrefixPath($prefix, $path, $type = null)

• addPrefixPaths(array $spec)

• addElementPrefixPath($prefix, $path, $type = null)

• addElementPrefixPaths(array $spec)

• addDisplayGroupPrefixPath($prefix, $path)

715
Zend_Form

• Metadata:

• setAttrib($key, $value)

• addAttribs(array $attribs)

• setAttribs(array $attribs)

• getAttrib($key)

• getAttribs()
• removeAttrib($key)

• clearAttribs()

• setAction($action)
• getAction()

• setMethod($method)

• getMethod()

• setName($name)

• getName()

• Elements:

• addElement($element, $name = null, $options = null)

• addElements(array $elements)

• setElements(array $elements)

• getElement($name)

• getElements()

• removeElement($name)

• clearElements()
• setDefaults(array $defaults)

• setDefault($name, $value)

• getValue($name)

• getValues()

• getUnfilteredValue($name)

• getUnfilteredValues()

• setElementFilters(array $filters)

• setElementDecorators(array $decorators)

716
Zend_Form

• Sub forms:

• addSubForm(Zend_Form $form, $name, $order = null)

• addSubForms(array $subForms)

• setSubForms(array $subForms)

• getSubForm($name)

• getSubForms()

• removeSubForm($name)

• clearSubForms()

• setSubFormDecorators(array $decorators)

• Display groups:

• addDisplayGroup(array $elements, $name, $options = null)

• addDisplayGroups(array $groups)

• setDisplayGroups(array $groups)

• getDisplayGroup($name)

• getDisplayGroups()

• removeDisplayGroup($name)

• clearDisplayGroups()

• setDisplayGroupDecorators(array $decorators)

• Validation

• populate(array $values)

• isValid(array $data)

• isValidPartial(array $data)

• processAjax(array $data)

• persistData()

• getErrors($name = null)

• getMessages($name = null)

• Rendering:

• setView(Zend_View_Interface $view = null)

• getView()

• addDecorator($decorator, $options = null)

717
Zend_Form

• addDecorators(array $decorators)

• setDecorators(array $decorators)

• getDecorator($name)

• getDecorators()

• removeDecorator($name)

• clearDecorators()

• render(Zend_View_Interface $view = null)

• I18n:

• setTranslator(Zend_Translate_Adapter $translator = null)

• getTranslator()

• setDisableTranslator($flag)

• translatorIsDisabled()

4.9. Configuration
Zend_Form is fully configurable via setOptions() and setConfig() (or by passing options
or a Zend_Config object to the constructor). Using these methods, you can specify form
elements, display groups, decorators, and metadata.

As a general rule, if 'set' + the option key refers to a Zend_Form method, then the value provided
will be passed to that method. If the accessor does not exist, the key is assumed to reference
an attribute, and will be passed to setAttrib().

Exceptions to the rule include the following:

• prefixPaths will be passed to addPrefixPaths()

• elementPrefixPaths will be passed to addElementPrefixPaths()

• displayGroupPrefixPaths will be passed to addDisplayGroupPrefixPaths()

• the following setters cannot be set in this way:

• setAttrib (though setAttribs *will* work)

• setConfig

• setDefault

• setOptions

• setPluginLoader

• setSubForms

• setTranslator

718
Zend_Form

• setView

As an example, here is a config file that passes configuration for every type of configurable data:

[element]
name = "registration"
action = "/user/register"
method = "post"
attribs.class = "zend_form"
attribs.onclick = "validate(this)"

disableTranslator = 0

prefixPath.element.prefix = "My_Element"
prefixPath.element.path = "My/Element/"
elementPrefixPath.validate.prefix = "My_Validate"
elementPrefixPath.validate.path = "My/Validate/"
displayGroupPrefixPath.prefix = "My_Group"
displayGroupPrefixPath.path = "My/Group/"

elements.username.type = "text"
elements.username.options.label = "Username"
elements.username.options.validators.alpha.validator = "Alpha"
elements.username.options.filters.lcase = "StringToLower"
; more elements, of course...

elementFilters.trim = "StringTrim"
;elementDecorators.trim = "StringTrim"

displayGroups.login.elements.username = "username"
displayGroups.login.elements.password = "password"
displayGroupDecorators.elements.decorator = "FormElements"
displayGroupDecorators.fieldset.decorator = "Fieldset"

decorators.elements.decorator = "FormElements"
decorators.fieldset.decorator = "FieldSet"
decorators.fieldset.decorator.options.class = "zend_form"
decorators.form.decorator = "Form"

The above could easily be abstracted to an XML or PHP array-based configuration file.

4.10. Custom forms


An alternative to using configuration-based forms is to subclass Zend_Form. This has several
benefits:

• You can unit test your form easily to ensure validations and rendering perform as expected.

• Fine-grained control over individual elements.

• Re-use of form objects, and greater portability (no need to track config files).

• Implementing custom functionality.

The most typical use case would be to use the init() method to setup specific form elements
and configuration:

class My_Form_Login extends Zend_Form


{

719
Zend_Form

public function init()


{
$username = new Zend_Form_Element_Text('username');
$username->class = 'formtext';
$username->setLabel('Username:')
->setDecorators(array(
array('ViewHelper',
array('helper' => 'formText')),
array('Label',
array('class' => 'label'))
));

$password = new Zend_Form_Element_Password('password');


$password->class = 'formtext';
$password->setLabel('Username:')
->setDecorators(array(
array('ViewHelper',
array('helper' => 'formPassword')),
array('Label',
array('class' => 'label'))
));

$submit = new Zend_Form_Element_Submit('login');


$submit->class = 'formsubmit';
$submit->setValue('Login')
->setDecorators(array(
array('ViewHelper',
array('helper' => 'formSubmit'))
));

$this->addElements(array(
$username,
$password,
$submit
));

$this->setDecorators(array(
'FormElements',
'Fieldset',
'Form'
));
}
}

This form can then be instantiated with simply:

$form = new My_Form_Login();

and all functionality is already setup and ready; no config files needed. (Note that this example
is greatly simplified, as it contains no validators or filters for the elements.)

Another common reason for extension is to define a set of default decorators. You can do this
by overriding the loadDefaultDecorators() method:

class My_Form_Login extends Zend_Form


{
public function loadDefaultDecorators()
{
$this->setDecorators(array(

720
Zend_Form

'FormElements',
'Fieldset',
'Form'
));
}
}

5. Créer un visuel personnalisé en utilisant


Zend_Form_Decorator
Rendre visuellement un objet de formulaire est complètement optionnel -- il n'est pas obligatoire
d'utiliser la méthode render() de Zend_Form. Cependant, si vous l'utilisez, alors des
décorateurs sont utilisés pour rendre les différents objets du formulaire.

Un nombre arbitraire de décorateurs peut être attaché à chaque objet du formulaire (élément,
groupe d'affichage, sous-formulaires ou encore l'objet formulaire lui-même) ; cependant seul un
décorateur par type peut être attaché. Les décorateurs sont appelés dans l'ordre dans lequel ils
ont été enregistrés. En fonction du décorateur en question, celui-ci peut remplacer le contenu
qui lui est passé, ou alors le faire précédé ou suivre.

La configuration du décorateur est effectuée via son constructeur ou sa méthode


setOptions(). Lorsque vous créez des décorateurs au travers de méthodes comme
addDecorator(), alors sa configuration doit être passée en tant que tableau à ladite méthode.
Ces options de configuration peuvent être utilisées pour indiquer le placement du décorateur, le
séparateur inter-éléments ou toute autre option acceptable.

Avant le rendu d'un décorateur, au travers de sa méthode render(), l'objet sur lequel il agit lui
est passé en argument, grâce à setElement(), et ainsi le décorateur peut piloter l'élément sur
lequel il agit. Ceci permet de créer des décorateurs qui n'agissent que sur un petit paramètre de
l'élément auquel ils sont rattachés, comme le label, les messages d'erreur, etc... En chaînant des
décorateurs qui rendent chacun individuellement un petit morceau d'un élément, vous pouvez
créer une mise en forme complexe représentant l'objet (élément) dans son intégralité.

5.1. Configuration
Pour configurer un décorateur, passez un tableau d'options ou un objet Zend_Config à son
constructeur. Aussi, un tableau peut être passé à setOptions(), ou un objet Zend_Config
à setConfig().

Options de base:

• placement : le placement peut être 'append' ou 'prepend' (insensible à la casse), et indique


sur le contenu passé à render() doit être ajouté après ou avant, respectivement. Dans le cas
où le décorateur remplace le contenu, cette directive de placement est ignorée. La directive
par défaut est 'append'.

• separator : le séparateur est utilisé entre le contenu passé à render() et le nouveau


contenu généré par le décorateur, ou encore entre les éléments rendus (par exemple
FormElements utilise le séparateur entre chaque objet rendu). Dans le cas où le décorateur
remplace son contenu, cette option est ignorée. Par défaut, elle vaut PHP_EOL.

L'interface des décorateurs spécifie les méthodes pour agir sur les options. Les voici :

• setOption($key, $value) : affecte une option.

• getOption($key) : récupère une option.

721
Zend_Form

• getOptions() : récupère toutes les options.

• removeOption($key) : supprime une option.

• clearOptions() : supprime toutes les options.

Les décorateurs sont destinés à agir avec tous les objets du formulaire, Zend_Form,
Zend_Form_Element, Zend_Form_DisplayGroup, et toute classe en dérivant. La méthode
setElement() vous permet de passer l'objet au décorateur sur lequel il travaille.
getElement() vous permet de récupérer cet objet depuis le décorateur.

Chaque méthode render() des décorateurs accepte en paramètre une chaîne $content.
Lorsque le premier décorateur est appelé, cette chaîne est en toute logique vide, alors que tous
les appels successifs travailleront sur le contenu précédent. Selon le type de décorateur et ses
options, la chaîne sera alors remplacée, précédée ou suivie du nouveau contenu décoré. Dans
ces deux derniers cas, un séparateur optionnel peut être utilisé.

5.2. Décorateurs standards


Zend_Form est fourni avec quelques décorateurs de base, voyez le chapitre sur les décorateurs
standards pour plus de détails.

5.3. Décorateurs personnalisés


Si vos rendus HTML sont complexes, ou si vous avez besoin de beaucoup de personnalisation,
vous pouvez alors créer vos propres décorateurs.

Les décorateurs ont juste besoin d'implémenter l'interface


Zend_Form_Decorator_Interface. Celle-ci spécifie les méthodes suivantes :

interface Zend_Form_Decorator_Interface
{
public function __construct($options = null);
public function setElement($element);
public function getElement();
public function setOptions(array $options);
public function setConfig(Zend_Config $config);
public function setOption($key, $value);
public function getOption($key);
public function getOptions();
public function removeOption($key);
public function clearOptions();
public function render($content);
}

Pour vous simplifier la tâche, vous pourriez considérer le fait d'étendre


Zend_Form_Decorator_Abstract, qui implémente toutes les méthodes de l'interface sauf
render().

Par exemple, imaginons que vous ne souhaitiez pas vous encombrer avec un nombre important
de décorateurs, et que vous vouliez afficher les principale caractéristiques d'un élément grâce
à un seul décorateur (label, élément, messages d'erreur et description), le tout dans une div.
Voici comment vous pourriez procéder :

class My_Decorator_Composite extends Zend_Form_Decorator_Abstract


{

722
Zend_Form

public function buildLabel()


{
$element = $this->getElement();
$label = $element->getLabel();
if ($translator = $element->getTranslator()) {
$label = $translator->translate($label);
}
if ($element->isRequired()) {
$label .= '*';
}
$label .= ':';
return $element->getView()
->formLabel($element->getName(), $label);
}

public function buildInput()


{
$element = $this->getElement();
$helper = $element->helper;
return $element->getView()->$helper(
$element->getName(),
$element->getValue(),
$element->getAttribs(),
$element->options
);
}

public function buildErrors()


{
$element = $this->getElement();
$messages = $element->getMessages();
if (empty($messages)) {
return '';
}
return '<div class="errors">' .
$element->getView()->formErrors($messages) . '</div>';
}

public function buildDescription()


{
$element = $this->getElement();
$desc = $element->getDescription();
if (empty($desc)) {
return '';
}
return '<div class="description">' . $desc . '</div>';
}

public function render($content)


{
$element = $this->getElement();
if (!$element instanceof Zend_Form_Element) {
return $content;
}
if (null === $element->getView()) {
return $content;
}

$separator = $this->getSeparator();
$placement = $this->getPlacement();

723
Zend_Form

$label = $this->buildLabel();
$input = $this->buildInput();
$errors = $this->buildErrors();
$desc = $this->buildDescription();

$output = '<div class="form element">'


. $label
. $input
. $errors
. $desc
. '</div>'

switch ($placement) {
case (self::PREPEND):
return $output . $separator . $content;
case (self::APPEND):
default:
return $content . $separator . $output;
}
}
}

Vous pouvez maintenant placer ce décorateur dans les chemins des décorateurs :

// pour un élément:
$element->addPrefixPath('My_Decorator',
'My/Decorator/',
'decorator');

// pour tous les éléments:


$form->addElementPrefixPath('My_Decorator',
'My/Decorator/',
'decorator');

Dès à présent, vous pouvez indiquer que vous voulez utiliser le décorateur 'Composite', (c'est
son nom de classe sans le préfixe) et l'attacher à un élément :

// Ecrase les éventuels décorateurs de cet élément avec le notre:


$element->setDecorators(array('Composite'));

Cet exemple vous montre comment rendre un contenu HTML complexe à partir de propriétés
d'un élément, en une seule passe. Il existe des décorateurs qui ne s'occupent que d'une propriété
de l'élément auquel ils sont rattachés, 'Errors' et 'Label' en sont d'excellents exemples qui
permettent un placement fin.

Par exemple, si vous souhaitez simplement informer l'utilisateur d'une erreur, mais sans lui
montrer les messages d'erreurs, vous pouvez créer votre propre décorateur 'Errors' :

class My_Decorator_Errors
{
public function render($content = '')
{
$output = '<div class="errors">La valeur est invalide, rééssayez</div>';

$placement = $this->getPlacement();
$separator = $this->getSeparator();

switch ($placement) {

724
Zend_Form

case 'PREPEND':
return $output . $separator . $content;
case 'APPEND':
default:
return $content . $separator . $output;
}
}
}

Dans cet exemple particulier, comme le segment final du nom de la classe, 'Errors', respecte
la syntaxe de Zend_Form_Decorator_Errors, il sera alors utilisé à la place du décorateur
par défaut -- ceci signifie que vous n'avez pas besoin de l'injecter dans un élément particulier.
En nommant vos fins de classes de décorateurs comme celles des décorateurs standards, vous
pouvez changer la décoration sans agir sur les éléments en question.

5.4. Rendre des décorateurs individuellement


Comme les décorateurs agissent souvent sur une propriété d'un élément, et en fonction de la
décoration précédente, il peut être utile d'afficher juste le rendu d'un décorateur particulier, sur
un élément. Ceci est possible par la surcharge des méthodes dans les classes principales de
Zend_Form (formulaires, sous-formulaires, groupes d'affichage, éléments).

Pour effectuer ceci, appelez simplement render[nom-du-décorateur](), où "[nom-du-


décorateur]" est le nom court de votre décorateur (sans son préfixe de classe). Il est aussi
possible de lui passer optionnellement du contenu, par exemple :

// rend juste le décorateur Label de cet élément:


echo $element->renderLabel();

// Rend juste le décorateur Fieldset, en lui passant du contenu:


echo $group->renderFieldset('fieldset content');

// rend juste le tag HTML du formulaire, avec du contenu:


echo $form->renderHtmlTag('wrap this content');

Si le décorateur n'existe pas, une exception sera levée.

Ceci peut être particulièrement utile lors du rendu d'un formulaire avec le décorateur ViewScript ;
là où chaque élément utilise ses décorateurs pour rendre du contenu, mais de manière très fine.

6. Standard Form Elements Shipped With Zend Framework


Zend Framework ships with concrete element classes covering most HTML form elements. Most
simply specify a particular view helper for use when decorating the element, but several offer
additional functionality. The following is a list of all such classes, as well as descriptions of the
functionality they offer.

6.1. Zend_Form_Element_Button
Used for creating HTML button elements, Zend_Form_Element_Button extends
Zend_Form_Element_Submit, specifying some custom functionality. It specifies the 'formButton'
view helper for decoration.

Like the submit element, it uses the element's label as the element value for display purposes; in
other words, to set the text of the button, set the value of the element. The label will be translated
if a translation adapter is present.

725
Zend_Form

Because the label is used as part of the element, the button element uses only the ViewHelper
and DtDdWrapper decorators.

After populating or validating a form, you can check if the given button was clicked using the
isChecked() method.

6.2. Zend_Form_Element_Captcha
CAPTCHAs are used to prevent automated submission of forms by bots and other automated
processes.

The Captcha form element allows you to specify which Zend_Captcha adapter you wish to utilize
as a form CAPTCHA. It then sets this adapter as a validator to the object, and uses a Captcha
decorator for rendering (which proxies to the CAPTCHA adapter).

Adapters may be any adapters in Zend_Captcha, as well as any custom adapters you may have
defined elsewhere. To allow this, you may pass an additional plugin loader type key, 'CAPTCHA'
or 'captcha', when specifying a plugin loader prefix path:

$element->addPrefixPath('My_Captcha', 'My/Captcha/', 'captcha');

Captcha's may then be registered using the setCaptcha() method, which can take either a
concrete CAPTCHA instance, or the short name of a CAPTCHA adapter:

// Concrete instance:
$element->setCaptcha(new Zend_Captcha_Figlet());

// Using shortnames:
$element->setCaptcha('Dumb');

If you wish to load your element via configuration, specify either the key 'captcha' with an array
containing the key 'captcha', or both the keys 'captcha' and 'captchaOptions':

// Using single captcha key:


$element = new Zend_Form_Element_Captcha('foo', array(
'label' => "Please verify you're a human",
'captcha' => array(
'captcha' => 'Figlet',
'wordLen' => 6,
'timeout' => 300,
),
));

// Using both captcha and captchaOptions:


$element = new Zend_Form_Element_Captcha('foo', array(
'label' => "Please verify you're a human",
'captcha' => 'Figlet',
'captchaOptions' => array(
'captcha' => 'Figlet',
'wordLen' => 6,
'timeout' => 300,
),
));

The decorator used is determined by querying the captcha adapter. By default, the Captcha
decorator is used, but an adapter may specify a different one via its getDecorator() method.

726
Zend_Form

As noted, the captcha adapter itself acts as a validator for the element. Additionally, the NotEmpty
validator is not used, and the element is marked as required. In most cases, you should need to
do nothing else to have a captcha present in your form.

6.3. Zend_Form_Element_Checkbox
HTML checkboxes allow you return a specific value, but basically operate as booleans. When
checked, the checkbox's value is submitted. When the checkbox is not checked, nothing is
submitted. Internally, Zend_Form_Element_Checkbox enforces this state.

By default, the checked value is '1', and the unchecked value '0'. You can specify the values
to use using the setCheckedValue() and setUncheckedValue() accessors, respectively.
Internally, any time you set the value, if the provided value matches the checked value, then it
is set, but any other value causes the unchecked value to be set.

Additionally, setting the value sets the checked property of the checkbox. You can query this
using isChecked() or simply accessing the property. Using the setChecked($flag) method
will both set the state of the flag as well as set the appropriate checked or unchecked value in
the element. Please use this method when setting the checked state of a checkbox element to
ensure the value is set properly.

Zend_Form_Element_Checkbox uses the 'formCheckbox' view helper. The checked value is


always used to populate it.

6.4. Zend_Form_Element_File
The File form element provides a mechanism for supplying file upload fields to your form. It
utilizes Zend_File_Transfer internally to provide this functionality, and the FormFile view helper
as also the File decorator to display the form element.

By default, it uses the Http transfer adapter, which introspects the $_FILES array and allows
you to attach validators and filters. Validators and filters attached to the form element are in turn
attached to the transfer adapter.

727
Zend_Form

Exemple 388. File form element usage

The above explanation of using the File form element may seem arcane, but actual usage
is relatively trivial:

$element = new Zend_Form_Element_File('foo');


$element->setLabel('Upload an image:')
->setDestination('/var/www/upload');
// ensure only 1 file
$element->addValidator('Count', false, 1);
// limit to 100K
$element->addValidator('Size', false, 102400);
// only JPEG, PNG, and GIFs
$element->addValidator('Extension', false, 'jpg,png,gif');
$form->addElement($element, 'foo');

You also need to ensure that the correct encoding type is provided to the form; you should
use 'multipart/form-data'. You can do this by setting the 'enctype' attribute on the form:

$form->setAttrib('enctype', 'multipart/form-data');

After the form is validated successfully, you must receive the file to store it in the final
destination using receive(). Additionally you can determinate the final location using
getFileName():

if (!$form->isValid()) {
print "Uh oh... validation error";
}

if (!$form->foo->receive()) {
print "Error receiving the file";
}

$location = $form->foo->getFileName();

Default Upload Location


By default, files are uploaded to the system temp directory.

File values
Within HTTP a file element has no value. For this reason and because of security
concerns getValue() returns only the uploaded filename and not the complete
path. If you need the file path, call getFileName(), which returns both the path
and the name of the file.

Per default the file will automatically be received when you call getValues() on the form. The
reason behind this behaviour is, that the file itself is the value of the file element.

$form->getValues();

Therefor another call of receive() after calling getValues() will not have an
effect. Also creating a instance of Zend_File_Transfer will not have an effect
as there no file anymore to receive.

728
Zend_Form

Still, sometimes you may want to call getValues() without receiving the file. You can archive
this by calling setValueDisabled(true). To get the actual value of this flag you can call
isValueDisabled().

Exemple 389. Explicit file retrievement

First call setValueDisabled(true).

$element = new Zend_Form_Element_File('foo');


$element->setLabel('Upload an image:')
->setDestination('/var/www/upload')
->setValueDisabled(true);

Now the file will not be received when you call getValues(). So you must call receive()
on the file element, or an instance of Zend_File_Transfer yourself.

$values = $form->getValues();

if ($form->isValid($form->getPost())) {
if (!$form->foo->receive()) {
print "Upload error";
}
}

There are several states of the uploaded file which can be checked with the following methods:

• isUploaded(): Checks if the file element has been uploaded or not.

• isReceived(): Checks if the file element has already been received.

• isFiltered(): Checks if the filters have already been applied to the file element or not.

Exemple 390. Checking if an optional file has been uploaded

$element = new Zend_Form_Element_File('foo');


$element->setLabel('Upload an image:')
->setDestination('/var/www/upload')
->setRequired(false);
$element->addValidator('Size', false, 102400);
$form->addElement($element, 'foo');

// The foo file element is optional but when it's given go into here
if ($form->foo->isUploaded()) {
// foo file given... do something
}

Zend_Form_Element_File also supports multiple files. By calling the


setMultiFile($count) method you can set the number of file elements you want to create.
This keeps you from setting the same settings multiple times.

729
Zend_Form

Exemple 391. Setting multiple files

Creating a multifile element is the same as setting a single element. Just call
setMultiFile() after the element is created:

$element = new Zend_Form_Element_File('foo');


$element->setLabel('Upload an image:')
->setDestination('/var/www/upload');
// ensure minimum 1, maximum 3 files
$element->addValidator('Count', false, array('min' => 1, 'max' => 3));
// limit to 100K
$element->addValidator('Size', false, 102400);
// only JPEG, PNG, and GIFs
$element->addValidator('Extension', false, 'jpg,png,gif');
// defines 3 identical file elements
$element->setMultiFile(3);
$form->addElement($element, 'foo');

You now have 3 identical file upload elements with the same settings. To get the set multifile
number simply call getMultiFile().

File elements in Subforms


When you use file elements in subforms you must set unique names. For
example, if you name a file element in subform1 "file", you must give any file
element in subform2 a different name.

If there are 2 file elements with the same name, the second element is not be
displayed or submitted.

Additionally, file elements are not rendered within the sub-form. So when you
add a file element into a subform, then the element will be rendered within the
main form.

To limit the size of the file uploaded, you can specify the maximum file size by
setting the MAX_FILE_SIZE option on the form. When you set this value by using the
setMaxFileSize($size) method, it will be rendered with the file element.

$element = new Zend_Form_Element_File('foo');


$element->setLabel('Upload an image:')
->setDestination('/var/www/upload')
->addValidator('Size', false, 102400) // limit to 100K
->setMaxFileSize(102400); // limits the filesize on the client side
$form->addElement($element, 'foo');

MaxFileSize with Multiple File Elements


When you use multiple file elements in your form you should set the
MAX_FILE_SIZE only once. Setting it again will overwrite the previous value.

Note, that this is also the case when you use multiple forms.

6.5. Zend_Form_Element_Hidden
Hidden elements inject data that should be submitted, but that should not manipulated by the
user . Zend_Form_Element_Hidden accomplishes this with the 'formHidden' view helper.

730
Zend_Form

6.6. Zend_Form_Element_Hash
This element provides protection from CSRF attacks on forms, ensuring the data is submitted
by the user session that generated the form and not by a rogue script. Protection is achieved by
adding a hash element to a form and verifying it when the form is submitted.

The name of the hash element should be unique. We recommend using the salt option for the
element- two hashes with same names and different salts would not collide:

$form->addElement('hash', 'no_csrf_foo', array('salt' => 'unique'));

You can set the salt later using the setSalt($salt) method.

Internally, the element stores a unique identifier using Zend_Session_Namespace, and checks
for it at submission (checking that the TTL has not expired). The 'Identical' validator is then used
to ensure the submitted hash matches the stored hash.

The 'formHidden' view helper is used to render the element in the form.

6.7. Zend_Form_Element_Image
Images can be used as form elements, and you can use these images as graphical elements
on form buttons.

Images need an image source. Zend_Form_Element_Image allows you to specify this by


using the setImage() accessor (or 'image' configuration key). You can also optionally specify a
value to use when submitting the image using the setImageValue() accessor (or 'imageValue'
configuration key). When the value set for the element matches the imageValue, then the
accessor isChecked() will return TRUE.

Image elements use the Image Decorator for rendering, in addition to the standard Errors,
HtmlTag, and Label decorators. You can optionally specify a tag to the Image decorator that will
then wrap the image element.

6.8. Zend_Form_Element_MultiCheckbox
Often you have a set of related checkboxes, and you wish to group the results. This is much like a
Multiselect, but instead of them being in a dropdown list, you need to show checkbox/value pairs.

Zend_Form_Element_MultiCheckbox makes this a snap. Like all other elements extending


the base Multi element, you can specify a list of options, and easily validate against that same
list. The 'formMultiCheckbox' view helper ensures that these are returned as an array in the form
submission.

By default, this element registers an InArray validator which validates against the
array keys of registered options. You can disable this behavior by either calling
setRegisterInArrayValidator(false), or by passing a FALSE value to the
registerInArrayValidator configuration key.

You may manipulate the various checkbox options using the following methods:

• addMultiOption($option, $value)

• addMultiOptions(array $options)

• setMultiOptions(array $options) (overwrites existing options)

731
Zend_Form

• getMultiOption($option)

• getMultiOptions()

• removeMultiOption($option)

• clearMultiOptions()

To mark checked items, you need to pass an array of values to setValue(). The following will
check the values "bar" and "bat":

$element = new Zend_Form_Element_MultiCheckbox('foo', array(


'multiOptions' => array(
'foo' => 'Foo Option',
'bar' => 'Bar Option',
'baz' => 'Baz Option',
'bat' => 'Bat Option',
);
));

$element->setValue(array('bar', 'bat'));

Note that even when setting a single value, you must pass an array.

6.9. Zend_Form_Element_Multiselect
XHTML select elements allow a 'multiple' attribute, indicating multiple options may be selected
for submission, instead of the usual one. Zend_Form_Element_Multiselect extends
Zend_Form_Element_Select, and sets the multiple attribute to 'multiple'. Like other classes
that inherit from the base Zend_Form_Element_Multi class, you can manipulate the options
for the select using:

• addMultiOption($option, $value)

• addMultiOptions(array $options)

• setMultiOptions(array $options) (overwrites existing options)

• getMultiOption($option)

• getMultiOptions()

• removeMultiOption($option)

• clearMultiOptions()

If a translation adapter is registered with the form and/or element, option values will be translated
for display purposes.

By default, this element registers an InArray validator which validates against the
array keys of registered options. You can disable this behavior by either calling
setRegisterInArrayValidator(false), or by passing a FALSE value to the
registerInArrayValidator configuration key.

6.10. Zend_Form_Element_Password
Password elements are basically normal text elements -- except that you typically do not want
the submitted password displayed in error messages or the element itself when the form is re-
displayed.

732
Zend_Form

Zend_Form_Element_Password achieves this by calling setObscureValue(true) on


each validator (ensuring that the password is obscured in validation error messages), and using
the 'formPassword' view helper (which does not display the value passed to it).

6.11. Zend_Form_Element_Radio
Radio elements allow you to specify several options, of which you need a single value returned.
Zend_Form_Element_Radio extends the base Zend_Form_Element_Multi class, allowing
you to specify a number of options, and then uses the formRadio view helper to display these.

By default, this element registers an InArray validator which validates against the
array keys of registered options. You can disable this behavior by either calling
setRegisterInArrayValidator(false), or by passing a FALSE value to the
registerInArrayValidator configuration key.

Like all elements extending the Multi element base class, the following methods may be used
to manipulate the radio options displayed:

• addMultiOption($option, $value)

• addMultiOptions(array $options)

• setMultiOptions(array $options) (overwrites existing options)

• getMultiOption($option)

• getMultiOptions()

• removeMultiOption($option)

• clearMultiOptions()

6.12. Zend_Form_Element_Reset
Reset buttons are typically used to clear a form, and are not part of submitted data. However, as
they serve a purpose in the display, they are included in the standard elements.

Zend_Form_Element_Reset extends Zend_Form_Element_Submit. As such, the label is


used for the button display, and will be translated if a translation adapter is present. It utilizes
only the 'ViewHelper' and 'DtDdWrapper' decorators, as there should never be error messages
for such elements, nor will a label be necessary.

6.13. Zend_Form_Element_Select
Select boxes are a common way of limiting to specific choices for a given form datum.
Zend_Form_Element_Select allows you to generate these quickly and easily.

By default, this element registers an InArray validator which validates against the
array keys of registered options. You can disable this behavior by either calling
setRegisterInArrayValidator(false), or by passing a FALSE value to the
registerInArrayValidator configuration key.

As it extends the base Multi element, the following methods may be used to manipulate the
select options:

• addMultiOption($option, $value)

733
Zend_Form

• addMultiOptions(array $options)

• setMultiOptions(array $options) (overwrites existing options)

• getMultiOption($option)

• getMultiOptions()

• removeMultiOption($option)

• clearMultiOptions()

Zend_Form_Element_Select uses the 'formSelect' view helper for decoration.

6.14. Zend_Form_Element_Submit
Submit buttons are used to submit a form. You may use multiple submit buttons; you can
use the button used to submit the form to decide what action to take with the data submitted.
Zend_Form_Element_Submit makes this decisioning easy, by adding a isChecked()
method; as only one button element will be submitted by the form, after populating or validating
the form, you can call this method on each submit button to determine which one was used.

Zend_Form_Element_Submit uses the label as the "value" of the submit button, translating it
if a translation adapter is present. isChecked() checks the submitted value against the label
in order to determine if the button was used.

The ViewHelper and DtDdWrapper decorators to render the element. No label decorator is used,
as the button label is used when rendering the element; also, typically, you will not associate
errors with a submit element.

6.15. Zend_Form_Element_Text
By far the most prevalent type of form element is the text element, allowing for limited text entry;
it's an ideal element for most data entry. Zend_Form_Element_Text simply uses the 'formText'
view helper to display the element.

6.16. Zend_Form_Element_Textarea
Textareas are used when large quantities of text are expected, and place no limits on the
amount of text submitted (other than maximum size limits as dictated by your server or PHP).
Zend_Form_Element_Textarea uses the 'textArea' view helper to display such elements,
placing the value as the content of the element.

7. Décorateurs standards fournis avec Zend Framework


Zend_Form est livré avec plusieurs décorateurs standards. Pour plus d'informations sur
l'utilisation des décorateurs en général, voyez la section sur les décorateurs.

7.1. Zend_Form_Decorator_Callback
Le décorateur Callback peut exécuter une fonction de rappel pour rendre du contenu. Les
fonctions doivent être spécifiées grâce à l'option 'callback' passée à la configuration du
décorateur, et peut être n'importe quelle fonction PHP valide. Les fonctions peuvent accepter
3 arguments , $content ( le contenu original passé au décorateur), $element (l'objet étant
décoré), et un tableau d'options $options. Voici un exemple :

734
Zend_Form

class Util
{
public static function label($content, $element, array $options)
{
return '<span class="label">' . $element->getLabel() . "</span>";
}
}

Cette fonction de rappel devrait être spécifiée avec array('Util', 'label'), et générera du
(mauvais) code HTML pour le label. Le décorateur Callback remplacera, fera suivre ou précéder
le contenu original avec la valeur qu'il retourne.

Le décorateur Callback accepte qu'on lui passe une valeur nulle pour l'option de placement, ce
qui remplacera le contenu original par le contenu décoré. 'prepend' et 'append' restent cependant
acceptés.

7.2. Zend_Form_Decorator_Captcha
Le décorateur Captcha est à utiliser avec l'élément de formulaire CAPTCHA. Il utilise la méthode
render() de l'adaptateur de CAPTCHA pour générer son contenu.

Une variante du décorateur Captcha, 'Captcha_Word', est aussi utilisée quelques fois et créer 2
éléments, un id et un input. L'id indique l'identifiant de session à comparer et l'input est pour la
saisie du CAPTCHA. Ces 2 éléments sont validés comme un seul.

7.3. Zend_Form_Decorator_Description
Le décorateur Description peut être utilisé pour afficher la description affectée à un Zend_Form,
Zend_Form_Element, ou Zend_Form_DisplayGroup; il cherche cette description en
utilisant getDescription() sur l'objet en question.

Par défaut, si aucune description n'est présente, rien ne sera généré. Dans le cas contraire ,
la description est entourée d'un tag HTML p par défaut, même si vous pouvez passer le tag
que vous voulez en utilisant l'option tag à la création du décorateur, ou en utilisant sa méthode
setTag(). Vous pouvez aussi spécifier une classe pour le tag en renseignant l'option class
ou en appelant setClass().

La description est échappée en utilisant le mécanisme de l'objet de vue par défaut. Vous pouvez
désactiver cette fonctionnalité en passant FALSE à l'option 'escape' du décorateur ou via sa
méthode setEscape().

7.4. Zend_Form_Decorator_DtDdWrapper
Les décorateurs par défaut utilisent des listes de définition (<dl>) pour rendre les éléments de
formulaire. Comme les éléments d'un formulaire peuvent apparaître dans n'importe quel ordre,
les groupe d'affichage et les sous-formulaires peuvent être encapsulés dedans. Afin de garder
ces types d'éléments dans la liste de définition, DtDdWrapper crée une nouvelle définition vide
(<dt>) et encapsule don contenu dans une nouvelle donnée de définition (<dd>). L'affichage
ressemble alors à ceci :

<dt></dt>
<dd><fieldset id="subform">
<legend>User Information</legend>
...
</fieldset></dd>

735
Zend_Form

Ce décorateur remplace le contenu qu'on lui fournit par ce même contenu entouré de <dd>.

7.5. Zend_Form_Decorator_Errors
Les erreurs des éléments possèdent leur propre décorateur : 'Errors'. Celui-ci utilise l'aide de
vue FormErrors, qui rend les messages d'erreur dans une liste non ordonnée (<ul>) qui reçoit
la classe d'affichage "errors".

Le décorateur 'Errors' peut faire suivre ou précéder son contenu.

7.6. Zend_Form_Decorator_Fieldset
Les groupes d'affichage et les sous-formulaires rendent leur contenu dans des balises
HTML fieldsets par défaut. Le décorateur Fieldset vérifie une option 'legend' ou la méthode
getLegend() dans l'élément, et l'utilise comme élément de légende si non vide. Tout contenu
qu'on lui passe est entouré d'une balise HTML "fieldset", et remplace donc le contenu précédent.
Tout attribut passé à l'élément décoré sera rendu comme attribut de la balise HTML fieldset.

7.7. Zend_Form_Decorator_File
Les éléments de type "File" (upload de fichiers) ont une notation spéciale lorsque vous
utilisez de multiples éléments file ou des sous-formulaires. Le décorateur File est utilisé par
Zend_Form_Element_File et autorise plusieurs éléments avec un seul appel de méthode. Il
est utilisé automatiquement et gère alors le nom de chaque élément.

7.8. Zend_Form_Decorator_Form
Les objets Zend_Form ont en général besoin de rendre une balise HTML "form". Le décorateur
Form utilise l'aide de vue du même nom dans ce but. Il encapsule le contenu qu'on lui passe
dans une balise HTML 'form' et remplace donc ce contenu par le nouveau entouré. Les action,
méthode et attributs de l'objet Zend_Form sont bien entendus utilisés dans la balise.

7.9. Zend_Form_Decorator_FormElements
Les formulaires, groupes d'affichage et sous-formulaires sont des collections d'éléments. Afin
de rendre ces éléments, ils utilisent le décorateur FormElements, qui itère sur tous les éléments
et appelle leur méthode render() en les joignant avec le séparateur. Il peut faire suivre ou
précéder son contenu.

7.10. Zend_Form_Decorator_FormErrors
Certains développeurs ou designers préfèrent regrouper tous les messages d'erreur en haut du
formulaire. Le décorateur FormErrors a été conçu dans ce but.

Par défaut, la liste d'erreurs générée ressemble à ceci :

<ul class="form-errors>
<li><b>[element label or name]</b><ul>
<li>[error message]</li>
<li>[error message]</li>
</ul>
</li>
<li><ul>
<li><b>[subform element label or name</b><ul>
<li>[error message]</li>

736
Zend_Form

<li>[error message]</li>
</ul>
</li>
</ul></li>
</ul>

Vous pouvez lui passer un tas d'options afin de la configurer plus finement :

• ignoreSubForms : ignore ou pas la récursion dans les sous-formulaires. Par défaut : FALSE
(autorise la récursion).

• markupElementLabelEnd : balise à ajouter après le label des éléments. Par défaut: '</b>'

• markupElementLabelStart : balise à ajouter avant le label des éléments. Par défaut: '<b>'

• markupListEnd : balise à ajouter après la liste des messages d'erreur. Par défaut: '</ul>'.

• markupListItemEnd : balise à ajouter après chaque message d'erreur. Par défaut: '</li>'

• markupListItemStart : balise à ajouter avant chaque message d'erreur. Par défaut: '<li>'

• markupListStart : balise à ajouter autour de la liste des messages d'erreur. Par défaut:
'<ul class="form-errors">'

Le décorateur FormErrors peut faire suivre ou précéder son contenu.

7.11. Zend_Form_Decorator_HtmlTag
Le décorateur HtmlTag vous permet d'utiliser une balise HTML pour décorer votre contenu. La
balise utilisée est passée comme option 'tag' et toute autre option sera utilisée comme attribut
HTML à cette balise. Par défaut, le contenu généré remplace le contenu reçu par le décorateur.
Vous pouvez tout de même préciser un placement 'append' ou 'prepend'.

7.12. Zend_Form_Decorator_Image
Le décorateur Image vous permet de créer un tag HTML d'image (<input
type="image" ... />), et optionnellement le rendre à l'intérieur d'une autre balise HTML.

Par défaut, le décorateur utilise la propriété 'src' , qui peut être renseignée grâce à la méthode
setImage() (avec la source de l'image). Aussi, le label de l'élément va être utilisé comme
propriété 'alt' de la balise et le propriété imageValue (manipulée grâce à setImageValue()
et getImageValue()) sera utilisée comme valeur.

Pour spécifier une balise HTML à utiliser avec l'élément, passez l'option 'tag' au décorateur, ou
utilisez sa méthode setTag().

7.13. Zend_Form_Decorator_Label
Les éléments de formulaire possèdent en général un label, et le décorateur du même nom
permet de le rendre. Il utilise l'aide de vue FormLabel en récupérant le label de l'élément avec
getLabel(). Si aucun label n'est présent, rien n'est rendu. Par défaut, les label sont traduits
lorsqu'un objet de traduction existe.

Vous pouvez aussi spécifier optionnellement une option 'tag'. Si celle-ci est précisée, alors le
label sera encapsulé dans la balise HTML en question. Si la balise est présente mais qu'il n'y a
pas de label, alors la balise est rendu seule. Vous pouvez utiliser aussi une classe CSS grâce
à l'option 'class' ou la méthode setClass().

737
Zend_Form

Aussi, vous pouvez utiliser les préfixes ou des suffixes à afficher pour l'élément, selon si celui-ci
est requis ou pas. Par exemple on peut imaginer que tout label est suivi du caractère ":". Aussi,
tout élément requis à la saisie pourrait comporter une étoile "*". Des méthodes existent pour
effectuer cela :

• optionalPrefix: affecte le texte à préfixer au label si l'élément est optionnel.


setOptionalPrefix() et getOptionalPrefix() existent aussi.

• optionalSuffix: affecte le texte à suffixer au label si l'élément est optionnel.


setOptionalSuffix() et getOptionalSuffix() existent aussi.

• requiredPrefix: affecte le texte à préfixer au label si l'élément est marqué comme


requis.setRequiredPrefix() et getRequiredPrefix() existent aussi.

• requiredSuffix: affecte le texte à suffixer au label si l'élément est marqué comme


requis.setRequiredSuffix() et getRequiredSuffix() existent aussi.

Par défaut, le décorateur Label préfixe son rendu vis à vis du contenu qu'on lui passe à décorer.
L'option 'placement' reste disponible avec comme autre valeur possible 'append'

7.14. Zend_Form_Decorator_PrepareElements
Les formulaires, les groupes d'affichage et les sous-formulaires sont des collections d'éléments.
Lors de l'utilisation du décorateur ViewScript dans vos formulaires, il peut être utile de
récursivement passer l'objet de vue, le traducteur et tous les noms réels (notation tableau
des sous-formulaires) aux éléments. Cette tache peut être effectuée grâce au décorateur
'PrepareElements'. En général, vous le marquerez en tant que premier décorateur de la pile.

$form->setDecorators(array(
'PrepareElements',
array('ViewScript', array('viewScript' => 'form.phtml')),
));

7.15. Zend_Form_Decorator_ViewHelper
Beaucoup d'éléments utilisent les aides de Zend_View pour leur propre rendu, et ceci est
effectué grâce au décorateur ViewHelper. Avec lui, vous pouvez spécifier une option 'helper'
pour lui indiquer explicitement l'aide de vue à utiliser. Si aucune ne lui est fournie, il utilise le
nom de la classe de l'élément (moins le chemin : la dernière partie du nom de la classe) afin de
déterminer l'aide de vue à utiliser. Par exemple, 'Zend_Form_Element_Text' cherchera l'aide de
vue 'form' + 'Text' soit 'formText'.

Tout attributs ajoutés à l'élément sera passé à l'aide vue comme attribut de l'élément HTML
résultant.

Par défaut, ce décorateur fait suivre son contenu au contenu qu'on lui passe.

7.16. Zend_Form_Decorator_ViewScript
Quelques fois, vous pouvez avoir besoin d'un script de vue pour afficher vos éléments. Ceci
vous permettra un placement très fin et détaillé, ou alors de changer la vue utilisée en fonction
du module MVC dans lequel vous vous situez, par exemple.

Le décorateur ViewScript nécessite une option 'viewScript'. Celle-ci peut aussi être passée à
l'élément lui-même, via sa propriété 'viewScript'. Le décorateur rend alors ce script de vue comme

738
Zend_Form

un script partiel (ce qui signifie que chaque appel à lui possède son propre espace de variables).
Plusieurs variables sont alors peuplées dans le script de vue :

• element : l'élément décoré

• content : le contenu passé au décorateur

• decorator : l'objet décorateur lui-même

• Aussi, toute variable passée au décorateur via setOptions() et qui n'est pas utilisée en
interne (qui n'est pas 'placement', 'separator', etc.) est alors passée comme variable de vue.

Voici un exemple :

// Affectation d'un décorateur ViewScript à un seul élément


// en spécifiant comme option le script de vue (obligatoire) et d'autres options :
$element->setDecorators(array(array('ViewScript', array(
'viewScript' => '_element.phtml',
'class' => 'form element'
))));

// OU spécifier le script de vue comme attribut de l'élément


$element->viewScript = '_element.phtml';
$element->setDecorators(array(array('ViewScript',
array('class' => 'form element'))));

Le script de vue pourrait alors ressembler à cela :

<div class="<?php echo $this->class ?>">


<?php echo $this->formLabel($this->element->getName(),
$this->element->getLabel()) ?>
<?php echo $this->{$this->element->helper}(
$this->element->getName(),
$this->element->getValue(),
$this->element->getAttribs()
) ?>
<?php echo $this->formErrors($this->element->getMessages()) ?>
<div class="hint"><?php echo $this->element->getDescription() ?></div>
</div>

Remplacer le contenu avec un script de vue

Le contenu n'est pas remplacé par défaut, vous pouvez le demander en spécifiant
l'option 'placement' du décorateur. Il existe plusieurs manières de faire :

// A la création du décorateur:
$element->addDecorator('ViewScript', array('placement' => false));

// Application au décorateur déja existant:


$decorator->setOption('placement', false);

// Application au décorateur déja ajouté à un élément:


$element->getDecorator('ViewScript')->setOption('placement', false);

// Depuis un script de vue:


$this->decorator->setOption('placement', false);

739
Zend_Form

L'utilisation du décorateur ViewScript est recommandée dans les cas où vous souhaitez avoir
un placement HTML très détaillé et très fin de vos éléments.

8. Internationaliser un formulaire Zend_Form


De plus en plus de développeurs ont besoin de fournir des applications multilingues. Zend_Form
propose des moyens simples dans ce but, et gère cette responsabilité en tandem avec
Zend_Translate et Zend_Validate.

Par défaut, aucune internationalisation (i18n) n'est effectuée. Pour l'activer dans Zend_Form,
vous devrez instancier un objet Zend_Translate avec un adaptateur et l'attacher à
Zend_Form et/ou Zend_Validate. Voyez la documentation de Zend_Translate pour plus
d'informations sur la création de son objet et de ses adaptateurs.

L'i18n peut être désactivée par objet


Vous pouvez désactiver la traduction pour tout formulaire, élément,
groupe d'affichage ou sous-formulaire en appelant sa méthode
setDisableTranslator($flag) ou en lui passant un paramètre
disableTranslator. Ceci peut être utile pour désactiver l'i18n pour des
éléments de formulaires individuels, ou des groupes d'éléments par exemple.

8.1. Initialiser l'i18n dans les formulaires


Pour activer les traductions dans vos formulaires, vous avez besoin soit d'un objet
Zend_Translate complet, ou alors d'un objet Zend_Translate_Adapter , comme ceci
est détaillé dans la documentation de Zend_Translate. Une fois un objet d'i18n en votre
possession, plusieurs choix s'offrent à vous :

• Le plus simple : ajoutez l'objet d'i18n dans le registre. Tout composant utilisant l'i18n dans
Zend Framework a la capacité de découvrir de lui-même un objet de traduction si celui-ci est
enregistré dans le registre à la clé "Zend_Translate" :

// utilisez la clé registre 'Zend_Translate' ;


// $translate est un objet Zend_Translate :
Zend_Registry::set('Zend_Translate', $translate);

Cet objet sera cherché par Zend_Form, Zend_Validate, et


Zend_View_Helper_Translate.

• Si tout ce qui vous importe est la traduction des messages d'erreurs, vous pouvez ajouter
l'objet de traduction à Zend_Validate_Abstract :

// Indique aux classes de validation d'utiliser


// un objet de traduction spécifique :
Zend_Validate_Abstract::setDefaultTranslator($translate);

• Autre manière de procéder; attacher un objet de traduction à Zend_Form de manière générale.


Ceci aura pour effet, entres-autres, de gérer la traduction des messages d'erreur de la
validation :

// Indique à toutes les classes de formulaire d'utiliser un objet de traduction


// Indique aussi aux validateurs d'utiliser ce même objet pour traduire
// les messages d'erreur :
Zend_Form::setDefaultTranslator($translate);

740
Zend_Form

• Enfin, il est possible d'attacher un objet de traduction à une instance du formulaire, ou à un


ou plusieurs de ses éléments, grâce à setTranslator() :

// Indique à *cette* instance de formulaire, d'utiliser un objet de


// traduction. L'objet de traduction sera aussi utilisé par tous les
// validateurs pour traduire les messages d'erreur :
$form->setTranslator($translate);

// Indique à *cette* instance d'élément de formulaire, d'utiliser


// un objet de traduction. L'objet de traduction sera aussi utilisé
// par tous les validateurs de *cet* élément spécifique :
$element->setTranslator($translate);

8.2. Cibles gérées par l'I18n


Maintenant que vous avez attaché un objet de traduction, que pouvez vous faire avec ?

• Messages d'erreur des validateurs : les messages d'erreurs des validateurs peuvent être
traduits. Pour cela, utilisez les identifiants des messages des validateurs (constantes de vos
validateurs Zend_Validate. Pour plus d'informations sur ces clés, voyez la documentation
de Zend_Validate.

Aussi, depuis la version 1.6.0, vous pouvez fournir des chaînes de traduction en utilisant les
messages d'erreur actuels comme identifiants. C'est le comportement recommandé pour 1.6.0
ou supérieures, nous allons déprécier l'utilisation des clés (constantes de classe) dans les
prochaines versions.

• Labels : les labels des éléments seront traduits si un objet de traduction et une chaîne de
traduction existent.

• Légende des Fieldset : les groupes d'éléments et les sous-formulaires sont rendus dans des
"fieldsets" par défaut. Le décorateur FieldSet essaye de traduire la légende via l'objet de
traduction.

• Description des formulaires et éléments de formulaire : tous les types relatifs au formulaire
(éléments, formulaires, groupes d'éléments ou sous-formulaires) permettent de spécifier une
description optionnelle. Le décorateur Description essaye de traduire la description.

• Valeurs de Multi-option : les éléments héritant de


Zend_Form_Element_Multi(MultiCheckbox, Multiselect, et Radio) peuvent aussi traduire
les valeurs (et non les clés) de leurs options.

• Labels de Submit et Button : les boutons (éléments Submit, Button et Reset) vont traduire le
label affiché à l'utilisateur.

9. Advanced Zend_Form Usage


Zend_Form has a wealth of functionality, much of it aimed at experienced developers. This
chapter aims to document some of this functionality with examples and use cases.

9.1. Array Notation


Many experienced web developers like to group related form elements using array notation in
the element names. For example, if you have two addresses you wish to capture, a shipping
and a billing address, you may have identical elements; by grouping them in an array, you can
ensure they are captured separately. Take the following form, for example:

741
Zend_Form

<form>
<fieldset>
<legend>Shipping Address</legend>
<dl>
<dt><label for="recipient">Ship to:</label></dt>
<dd><input name="recipient" type="text" value="" /></dd>

<dt><label for="address">Address:</label></dt>
<dd><input name="address" type="text" value="" /></dd>

<dt><label for="municipality">City:</label></dt>
<dd><input name="municipality" type="text" value="" /></dd>

<dt><label for="province">State:</label></dt>
<dd><input name="province" type="text" value="" /></dd>

<dt><label for="postal">Postal Code:</label></dt>


<dd><input name="postal" type="text" value="" /></dd>
</dl>
</fieldset>

<fieldset>
<legend>Billing Address</legend>
<dl>
<dt><label for="payer">Bill To:</label></dt>
<dd><input name="payer" type="text" value="" /></dd>

<dt><label for="address">Address:</label></dt>
<dd><input name="address" type="text" value="" /></dd>

<dt><label for="municipality">City:</label></dt>
<dd><input name="municipality" type="text" value="" /></dd>

<dt><label for="province">State:</label></dt>
<dd><input name="province" type="text" value="" /></dd>

<dt><label for="postal">Postal Code:</label></dt>


<dd><input name="postal" type="text" value="" /></dd>
</dl>
</fieldset>

<dl>
<dt><label for="terms">I agree to the Terms of Service</label></dt>
<dd><input name="terms" type="checkbox" value="" /></dd>

<dt></dt>
<dd><input name="save" type="submit" value="Save" /></dd>
</dl>
</form>

In this example, the billing and shipping address contain some identical fields, which means one
would overwrite the other. We can solve this solution using array notation:

<form>
<fieldset>
<legend>Shipping Address</legend>
<dl>
<dt><label for="shipping-recipient">Ship to:</label></dt>
<dd><input name="shipping[recipient]" id="shipping-recipient"

742
Zend_Form

type="text" value="" /></dd>

<dt><label for="shipping-address">Address:</label></dt>
<dd><input name="shipping[address]" id="shipping-address"
type="text" value="" /></dd>

<dt><label for="shipping-municipality">City:</label></dt>
<dd><input name="shipping[municipality]" id="shipping-municipality"
type="text" value="" /></dd>

<dt><label for="shipping-province">State:</label></dt>
<dd><input name="shipping[province]" id="shipping-province"
type="text" value="" /></dd>

<dt><label for="shipping-postal">Postal Code:</label></dt>


<dd><input name="shipping[postal]" id="shipping-postal"
type="text" value="" /></dd>
</dl>
</fieldset>

<fieldset>
<legend>Billing Address</legend>
<dl>
<dt><label for="billing-payer">Bill To:</label></dt>
<dd><input name="billing[payer]" id="billing-payer"
type="text" value="" /></dd>

<dt><label for="billing-address">Address:</label></dt>
<dd><input name="billing[address]" id="billing-address"
type="text" value="" /></dd>

<dt><label for="billing-municipality">City:</label></dt>
<dd><input name="billing[municipality]" id="billing-municipality"
type="text" value="" /></dd>

<dt><label for="billing-province">State:</label></dt>
<dd><input name="billing[province]" id="billing-province"
type="text" value="" /></dd>

<dt><label for="billing-postal">Postal Code:</label></dt>


<dd><input name="billing[postal]" id="billing-postal"
type="text" value="" /></dd>
</dl>
</fieldset>

<dl>
<dt><label for="terms">I agree to the Terms of Service</label></dt>
<dd><input name="terms" type="checkbox" value="" /></dd>

<dt></dt>
<dd><input name="save" type="submit" value="Save" /></dd>
</dl>
</form>

In the above sample, we now get separate addresses. In the submitted form, we'll now have
three elements, the 'save' element for the submit, and then two arrays, 'shipping' and 'billing',
each with keys for their various elements.

743
Zend_Form

Zend_Form attempts to automate this process with its sub forms. By default, sub forms render
using the array notation as shown in the previous HTML form listing, complete with ids. The array
name is based on the sub form name, with the keys based on the elements contained in the sub
form. Sub forms may be nested arbitrarily deep, and this will create nested arrays to reflect the
structure. Additionally, the various validation routines in Zend_Form honor the array structure,
ensuring that your form validates correctly, no matter how arbitrarily deep you nest your sub
forms. You need do nothing to benefit from this; this behaviour is enabled by default.

Additionally, there are facilities that allow you to turn on array notation conditionally, as well as
specify the specific array to which an element or collection belongs:

• Zend_Form::setIsArray($flag): By setting the flag TRUE, you can indicate that an entire
form should be treated as an array. By default, the form's name will be used as the name of
the array, unless setElementsBelongTo() has been called. If the form has no specified
name, or if setElementsBelongTo() has not been set, this flag will be ignored (as there is
no array name to which the elements may belong).

You may determine if a form is being treated as an array using the isArray() accessor.

• Zend_Form::setElementsBelongTo($array): Using this method, you can specify the


name of an array to which all elements of the form belong. You can determine the name using
the getElementsBelongTo() accessor.

Additionally, on the element level, you can specify individual elements may belong to particular
arrays using Zend_Form_Element::setBelongsTo() method. To discover what this value is
-- whether set explicitly or implicitly via the form -- you may use the getBelongsTo() accessor.

9.2. Multi-Page Forms


Currently, Multi-Page forms are not officially supported in Zend_Form; however, most support
for implementing them is available and can be utilized with a little extra tooling.

The key to creating a multi-page form is to utilize sub forms, but to display only one such sub form
per page. This allows you to submit a single sub form at a time and validate it, but not process
the form until all sub forms are complete.

744
)),

new Zend_Form_Element_Text('familyName', array(


'required' Zend_Form
=> true,
'label' => 'Family (Last) Name:',
'filters' => array('StringTrim'),
'validators' => array(
Exemple 392. Registration Form Example
array('Regex',
false,
array('/^[a-z][a-z0-9., \'-]{2,}$/i'))
)
)),

new Zend_Form_Element_Text('location', array(


'required' => true,
'label' => 'Your Location:',
'filters' => array('StringTrim'),
'validators' => array(
array('StringLength', false, array(2))
)
)),
));

// Create mailing lists sub form


$listOptions = array(
class My_Form_Registration extends Zend_Form
{ 'none' => 'No lists, please',
// ... 'fw-general' => 'Zend Framework General List',
'fw-mvc' => 'Zend Framework MVC List',
/** 'fw-auth' => 'Zend Framwork Authentication and ACL List',
* Prepare 'fw-services'
a sub form => for'Zend
displayFramework Web Services List',
* );
$lists =
* @param new Zend_Form_SubForm();
string|Zend_Form_SubForm $spec
* $lists->addElements(array(
@return Zend_Form_SubForm
class RegistrationController extends Zend_Controller_Action
*/ new Zend_Form_Element_MultiCheckbox('subscriptions', array(
{
public 'label'
function =>
prepareSubForm($spec)
// ...
{ 'Which lists would you like to subscribe to?',
Note that ifthere are 'multiOptions'
no submit buttons,
(is_string($spec)) {=>and that we have done nothing with the sub form
$listOptions,
protected $_namespace = 'RegistrationController';
decorators -- which means
'required'
$subForm
protected $_session; = that by default
=> they
$this->{$spec}; true, will be displayed as fieldsets. We will need to
be able to}override 'filters'
elseifthese as we
($spec display=>each
instanceof array('StringTrim'),
individual sub form, and
Zend_Form_SubForm) { add in submit buttons
so we can actually 'validators'
process
$subForm => array(
them -- which
= $spec; will also require action and method properties.
/**
Let's add } else
some {
scaffoldingarray('InArray',
tonamespace
our class towe're
provide that information:
* Get the session using
throw new false,
Exception('Invalid argument passed to ' .
*
array(array_keys($listOptions)))
__FUNCTION__ . '()');
* @return Zend_Session_Namespace
)
*/ }
Now,public )),
let's$this->setSubFormDecorators($subForm)
addfunction
some functionality for determining which form to display. Basically, until the
getSessionNamespace()
entire{ form));
is considered valid, we need to continue displaying form segments. Additionally,
->addSubmitButton($subForm)
we likely want to->addSubFormActions($subForm);
if (null make sure
=== they're in a particular
$this->_session) { order: user, demog, and then lists. We can
// Attach sub forms to main form
determinereturn $subForm;
what$this->_session
data has been submitted= by checking our session namespace for particular
$this->addSubForms(array(
keys }representing new subform.
each
'user'
Zend_Session_Namespace($this->_namespace);
=> $user,
}
/** 'demog' => $demog,
Add 'lists'
class*RegistrationController
form => $lists
decorators toextends Zend_Controller_Action
an individual sub form
return $this->_session;
{ * ));
}
<?php }
protected
*//@param $_form;
Zend_Form_SubForm $subForm
registration/index.phtml ?>
} * @return My_Form_Registration
<h2>Registration</h2>
/**
<?php public
*/ Get function
*echo list ofgetForm()
$this->form
a forms?> already stored in the session
<?php {*// registration/verification.phtml
public function setSubFormDecorators(Zend_Form_SubForm ?> $subForm)
ifyou
{* @return
<h2>Thank (null
for ===
array $this->_form) {
registering!</h2>
$this->_form = new My_Form_Registration();
<p> */ $subForm->setDecorators(array(
Here}isfunction
public 'FormElements',
the information you provided:
getStoredForms()
</p>
class return $this->_form; array('tag'
array('HtmlTag',
{ RegistrationController => 'dl',
extends Zend_Controller_Action
{ } $stored = array(); 'class' => 'zend_form')),
}
<? // ...foreach'Form',
($this->getSessionNamespace() as $key => $value) {
Upcoming
// Have to releases
)); do thisof Zend
$stored[] = Framework
construct
$key;due to will how
include components
items to make
are stored multi page forms
in session
simpler
// byreturn
}abstracting
namespaces
class /** $this; the session and
RegistrationController ordering
extends logic. In the meantime, the above example
Zend_Controller_Action
should
{ }*serve
foreach ($this->info
Is as asub
the asvalid?
reasonable
form $info):
guideline on how to accomplish this task for your site.
foreach
//* ...
return ($info
$stored;as $form => $data): ?>
Let's /**
}create
<h4><?php our controller,
echo
* @param and add a?>:</h4>
ucfirst($form)
Zend_Form_SubForm method for retrieving a form instance:
$subForm
*
* Add
<dl>public @parama submit
function button
$data to an individual sub form
arrayindexAction()
{*
<?php
The view
/** foreach
scripts
* @return are ($data
very
bool simple: as $key => $value): ?>
* Get
*
*/ @param
<dt><?php
// Either
list Zend_Form_SubForm
echo ucfirst($key)
ofre-display
all subforms 745available
the $subFormpage, or grab the "next"
?></dt>
current
*
<?php@return
if
* // function
public My_Form_Registration
(is_array($value)):
(first) sub form
subFormIsValid(Zend_Form_SubForm $subForm,
*/ if
foreach
(!$form ($value as $label => $val): ?>
= $this->getCurrentSubForm()) {
Zend_Gdata
1. Introduction
Google Data APIs provide programmatic interface to some of Google's online services. The
Google data Protocol is based upon the Atom Publishing Protocol and allows client applications
to retrieve data matching queries, post data, update data and delete data using standard HTTP
and the Atom syndication formation. The Zend_Gdata component is a PHP 5 interface for
accessing Google Data from PHP. The Zend_Gdata component also supports accessing other
services implementing the Atom Publishing Protocol.

See http://code.google.com/apis/gdata/ for more information about Google Data API.

The services that are accessible by Zend_Gdata include the following:

• Google Calendar is a popular online calendar application.

• Google Spreadsheets provides an online collaborative spreadsheets tool which can be used
as a simple data store for your applications.

• Google Documents List provides an online list of all spreadsheets, word processing
documents, and presentations stored in a Google account.

• Google Provisioning provides the ability to create, retrieve, update, and delete user accounts,
nicknames, and email lists on a Google Apps hosted domain.

• Google Base provides the ability to retrieve, post, update, and delete items in Google Base.

• YouTube provides the ability to search and retrieve videos, comments, favorites, subscriptions,
user profiles and more.

• Picasa Web Albums provides an online photo sharing application.

• Google Blogger is a popular Internet provider of "push-button publishing" and syndication.

• Google CodeSearch allows you to search public source code from many projects.

• Google Notebook allows you to view public Notebook content.

Unsupported services
Zend_Gdata does not provide an interface to any other Google service, such
as Search, Gmail, Translation, or Maps. Only services that support the Google
Data API are supported.

1.1. Structure of Zend_Gdata


Zend_Gata is composed of several types of classes:

• Service classes - inheriting from Zend_Gdata_App. These also include other classes such
as Zend_Gdata, Zend_Gdata_Spreadsheets, etc. These classes enable interacting with
APP or GData services and provide the ability to retrieve feeds, retrieve entries, post entries,
update entries and delete entries.

• Query classes - inheriting from Zend_Gdata_Query. These also include other


classes for specific services, such as Zend_Gdata_Spreadsheets_ListQuery and

746
Zend_Gdata

Zend_Gdata_Spreadsheets_CellQuery. Query classes provide methods used to


construct a query for data to be retrieved from GData services. Methods include getters
and setters like setUpdatedMin(), setStartIndex(), and getPublishedMin(). The
query classes also have a method to generate a URL representing the constructed query --
getQueryUrl. Alternatively, the query string component of the URL can be retrieved used
the getQueryString() method.

• Feed classes - inheriting from Zend_Gdata_App_Feed. These also include other


classes such as Zend_Gdata_Feed, Zend_Gdata_Spreadsheets_SpreadsheetFeed,
and Zend_Gdata_Spreadsheets_ListFeed. These classes represent feeds of entries
retrieved from services. They are primarily used to retrieve data returned from services.

• Entry classes - inheriting from Zend_Gdata_App_Entry. These also include other classes
such as Zend_Gdata_Entry, and Zend_Gdata_Spreadsheets_ListEntry. These
classes represent entries retrieved from services or used for constructing data to send to
services. In addition to being able to set the properties of an entry (such as the spreadsheet
cell value), you can use an entry object to send update or delete requests to a service. For
example, you can call $entry->save() to save changes made to an entry back to service
from which the entry initiated, or $entry->delete() to delete an entry from the server.

• Other Data model classes - inheriting from Zend_Gdata_App_Extension. These include


classes such as Zend_Gdata_App_Extension_Title (representing the atom:title XML
element), Zend_Gdata_Extension_When (representing the gd:when XML element used by
the GData Event "Kind"), and Zend_Gdata_Extension_Cell (representing the gs:cell XML
element used by Google Spreadsheets). These classes are used purely to store the data
retrieved back from services and for constructing data to be sent to services. These include
getters and setters such as setText() to set the child text node of an element, getText()
to retrieve the text node of an element, getStartTime() to retrieve the start time attribute
of a When element, and other similiar methods. The data model classes also include methods
such as getDOM() to retrieve a DOM representation of the element and all children and
transferFromDOM() to construct a data model representation of a DOM tree.

1.2. Interacting with Google Services


Google data services are based upon the Atom Publishing Protocol (APP) and the Atom
syndication format. To interact with APP or Google services using the Zend_Gdata
component, you need to use the service classes such as Zend_Gdata_App, Zend_Gdata,
Zend_Gdata_Spreadsheets, etc. These service classes provide methods to retrieve data
from services as feeds, insert new entries into feeds, update entries, and delete entries.

Note: A full example of working with Zend_Gdata is available in the demos/Zend/Gdata


directory. This example is runnable from the command-line, but the methods contained within
are easily portable to a web application.

1.3. Obtaining instances of Zend_Gdata classes


The Zend Framework naming standards require that all classes be named based upon the
directory structure in which they are located. For instance, extensions related to Spreadsheets
are stored in: Zend/Gdata/Spreadsheets/Extension/... and, as a result of this, are
named Zend_Gdata_Spreadsheets_Extension_.... This causes a lot of typing if you're
trying to construct a new instance of a spreadsheet cell element!

We've implemented a magic factory method in all service classes (such as Zend_Gdata_App,
Zend_Gdata, Zend_Gdata_Spreadsheets) that should make constructing new instances
of data model, query and other classes much easier. This magic factory is implemented by

747
Zend_Gdata

using the magic __call method to intercept all attempts to call $service->newXXX(arg1,
arg2, ...). Based off the value of XXX, a search is performed in all registered 'packages' for
the desired class. Here's some examples:

$ss = new Zend_Gdata_Spreadsheets();

// creates a Zend_Gdata_App_Spreadsheets_CellEntry
$entry = $ss->newCellEntry();

// creates a Zend_Gdata_App_Spreadsheets_Extension_Cell
$cell = $ss->newCell();
$cell->setText('My cell value');
$cell->setRow('1');
$cell->setColumn('3');
$entry->cell = $cell;

// ... $entry can then be used to send an update to a Google Spreadsheet

Each service class in the inheritance tree is responsible for registering the appropriate
'packages' (directories) which are to be searched when calling the magic factory method.

1.4. Google Data Client Authentication


Most Google Data services require client applications to authenticate against the Google server
before accessing private data, or saving or deleting data. There are two implementations of
authentication for Google Data: AuthSub and ClientLogin. Zend_Gdata offers class interfaces
for both of these methods.

Most other types of queries against Google Data services do not require authentication.

1.5. Dependencies
Zend_Gdata makes use of Zend_Http_Client to send requests to google.com and fetch
results. The response to most Google Data requests is returned as a subclass of the
Zend_Gdata_App_Feed or Zend_Gdata_App_Entry classes.

Zend_Gdata assumes your PHP application is running on a host that has a direct connection
to the Internet. The Zend_Gdata client operates by contacting Google Data servers.

1.6. Creating a new Gdata client


Create a new object of class Zend_Gdata_App, Zend_Gdata, or one of the subclasses
available that offer helper methods for service-specific behavior.

The single optional parameter to the Zend_Gdata_App constructor is an instance of


Zend_Http_Client. If you don't pass this parameter, Zend_Gdata creates a default
Zend_Http_Client object, which will not have associated credentials to access private feeds.
Specifying the Zend_Http_Client object also allows you to pass configuration options to that
client object.

$client = new Zend_Http_Client();


$client->setConfig( ...options... );

$gdata = new Zend_Gdata($client);

Beginning with Zend Framework 1.7, support has been added for protocol versioning. This allows
the client and server to support new features while maintaining backwards compatibility. While

748
Zend_Gdata

most services will manage this for you, if you create a Zend_Gdata instance directly (as opposed
to one of its subclasses), you may need to specify the desired protocol version to access certain
server functionality.

$client = new Zend_Http_Client();


$client->setConfig( ...options... );

$gdata = new Zend_Gdata($client);


$gdata->setMajorProtocolVersion(2);
$gdata->setMinorProtocolVersion(null);

Also see the sections on authentication for methods to create an authenticated


Zend_Http_Client object.

1.7. Common Query Parameters


You can specify parameters to customize queries with Zend_Gdata. Query parameters are
specified using subclasses of Zend_Gdata_Query. The Zend_Gdata_Query class includes
methods to set all query parameters used throughout GData services. Individual services, such
as Spreadsheets, also provide query classes to defined parameters which are custom to the
particular service and feeds. Spreadsheets includes a CellQuery class to query the Cell Feed
and a ListQuery class to query the List Feed, as different query parameters are applicable to
each of those feed types. The GData-wide parameters are described below.

• The q parameter specifies a full-text query. The value of the parameter is a string.

Set this parameter with the setQuery() function.

• The alt parameter specifies the feed type. The value of the parameter can be atom, rss,
json, or json-in-script. If you don't specify this parameter, the default feed type is atom.
NOTE: Only the output of the atom feed format can be processed using Zend_Gdata. The
Zend_Http_Client could be used to retrieve feeds in other formats, using query URLs
generated by the Zend_Gdata_Query class and its subclasses.

Set this parameter with the setAlt() function.

• The maxResults parameter limits the number of entries in the feed. The value of the
parameter is an integer. The number of entries returned in the feed will not exceed this value.

Set this parameter with the setMaxResults() function.

• The startIndex parameter specifies the ordinal number of the first entry returned in the feed.
Entries before this number are skipped.

Set this parameter with the setStartIndex() function.

• The updatedMin and updatedMax parameters specify bounds on the entry date. If you
specify a value for updatedMin, no entries that were updated earlier than the date you specify
are included in the feed. Likewise no entries updated after the date specified by updatedMax
are included.

You can use numeric timestamps, or a variety of date/time string representations as the value
for these parameters.

Set this parameter with the setUpdatedMin() and setUpdatedMax() functions.

There is a get function for each set function.

749
Zend_Gdata

$query = new Zend_Gdata_Query();


$query->setMaxResults(10);
echo $query->getMaxResults(); // returns 10

The Zend_Gdata class also implements "magic" getter and setter methods, so you can use the
name of the parameter as a virtual member of the class.

$query = new Zend_Gdata_Query();


$query->maxResults = 10;
echo $query->maxResults; // returns 10

You can clear all parameters with the resetParameters() function. This is useful to do if you
reuse a Zend_Gdata object for multiple queries.

$query = new Zend_Gdata_Query();


$query->maxResults = 10;
// ...get feed...

$query->resetParameters(); // clears all parameters


// ...get a different feed...

1.8. Fetching a Feed


Use the getFeed() function to retrieve a feed from a specified URI. This function returns
an instance of class specified as the second argument to getFeed, which defaults to
Zend_Gdata_Feed.

$gdata = new Zend_Gdata();


$query = new Zend_Gdata_Query(
'http://www.blogger.com/feeds/blogID/posts/default');
$query->setMaxResults(10);
$feed = $gdata->getFeed($query);

See later sections for special functions in each helper class for Google Data services. These
functions help you to get feeds from the URI that is appropriate for the respective service.

1.9. Working with Multi-page Feeds


When retrieving a feed that contains a large number of entries, the feed may be broken up into
many smaller "pages" of feeds. When this occurs, each page will contain a link to the next page
in the series. This link can be accessed by calling getLink('next'). The following example
shows how to retrieve the next page of a feed:

function getNextPage($feed) {
$nextURL = $feed->getLink('next');
if ($nextURL !== null) {
return $gdata->getFeed($nextURL);
} else {
return null;
}
}

If you would prefer not to work with pages in your application, pass the first page of the feed
into Zend_Gdata_App::retrieveAllEntriesForFeed(), which will consolidate all entries
from each page into a single feed. This example shows how to use this function:

750
Zend_Gdata

$gdata = new Zend_Gdata();


$query = new Zend_Gdata_Query(
'http://www.blogger.com/feeds/blogID/posts/default');
$feed = $gdata->retrieveAllEntriesForFeed($gdata->getFeed($query));

Keep in mind when calling this function that it may take a long time to complete on large feeds.
You may need to increase PHP's execution time limit by calling set_time_limit().

1.10. Working with Data in Feeds and Entries


After retrieving a feed, you can read the data from the feed or the entries contained in the feed
using either the accessors defined in each of the data model classes or the magic accessors.
Here's an example:

$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);


$gdata = new Zend_Gdata($client);
$query = new Zend_Gdata_Query(
'http://www.blogger.com/feeds/blogID/posts/default');
$query->setMaxResults(10);
$feed = $gdata->getFeed($query);
foreach ($feed as $entry) {
// using the magic accessor
echo 'Title: ' . $entry->title->text;
// using the defined accessors
echo 'Content: ' . $entry->getContent()->getText();
}

1.11. Updating Entries


After retrieving an entry, you can update that entry and save changes back to the server. Here's
an example:

$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);


$gdata = new Zend_Gdata($client);
$query = new Zend_Gdata_Query(
'http://www.blogger.com/feeds/blogID/posts/default');
$query->setMaxResults(10);
$feed = $gdata->getFeed($query);
foreach ($feed as $entry) {
// update the title to append 'NEW'
echo 'Old Title: ' . $entry->title->text;
$entry->title->text = $entry->title->text . ' NEW';

// update the entry on the server


$newEntry = $entry->save();
echo 'New Title: ' . $newEntry->title->text;
}

1.12. Posting Entries to Google Servers


The Zend_Gdata object has a function insertEntry() with which you can upload data to
save new entries to Google Data services.

You can use the data model classes for each service to construct the appropriate
entry to post to Google's services. The insertEntry() function will accept a child of
Zend_Gdata_App_Entry as data to post to the service. The method returns a child of

751
Zend_Gdata

Zend_Gdata_App_Entry which represents the state of the entry as it was returned from the
server.

Alternatively, you could construct the XML structure for an entry as a string and pass the string
to the insertEntry() function.

$gdata = new Zend_Gdata($authenticatedHttpClient);

$entry = $gdata->newEntry();
$entry->title = $gdata->newTitle('Playing football at the park');
$content =
$gdata->newContent('We will visit the park and play football');
$content->setType('text');
$entry->content = $content;

$entryResult = $gdata->insertEntry($entry,
'http://www.blogger.com/feeds/blogID/posts/default');

echo 'The <id> of the resulting entry is: ' . $entryResult->id->text;

To post entries, you must be using an authenticated Zend_Http_Client that you created using
the Zend_Gdata_AuthSub or Zend_Gdata_ClientLogin classes.

1.13. Deleting Entries on Google Servers


Option 1: The Zend_Gdata object has a function delete() with which you can delete entries
from Google Data services. Pass the edit URL value from a feed entry to the delete() method.

Option 2: Alternatively, you can call $entry->delete() on an entry retrieved from a Google
service.

$gdata = new Zend_Gdata($authenticatedHttpClient);


// a Google Data feed
$feedUri = ...;
$feed = $gdata->getFeed($feedUri);
foreach ($feed as $feedEntry) {
// Option 1 - delete the entry directly
$feedEntry->delete();
// Option 2 - delete the entry by passing the edit URL to
// $gdata->delete()
// $gdata->delete($feedEntry->getEditLink()->href);
}

To delete entries, you must be using an authenticated Zend_Http_Client that you created
using the Zend_Gdata_AuthSub or Zend_Gdata_ClientLogin classes.

2. Authentification par procédé AuthSub


Le mécanisme d'authentification AuthSub permet d'écrire des applications dans lesquelles il
n'est pas nécessaire de coder "en dur" des identifiants. L'application demande ces informations
à l'utilisateur, pour ouvrir un session de travail.

Voyez http://code.google.com/apis/accounts/AuthForWebApps.html pour plus d'informations sur


l'authentification AuthSub de Google Data.

La documentation Google indique que le mécanisme ClientLogin est approprié dans le cas
d'applications embarquées, à la différence du mécanisme AuthSub, utilisé pour les applications
Web ayant recours à une authentification extérieure. AuthSub récupère des identifiant d'un

752
Zend_Gdata

utilisateur de l'application Web, et un navigateur réagissant aux redirections est requis. Le


processus ClientLogin, lui, utilise du code PHP tel qu'écrit dans l'application elle-même.
L'utilisateur de l'application n'entre pas en jeu pour fournir des identifiants de manière interactive.

Les identifiants utilisés par le processus AuthSub sont fournis par l'utilisateur de l'application, et
non par l'application elle-même.

Jetons sécurisés et certificats


Zend_Gdata ne supporte pas actuellement l'utilisation de jetons sécurisés, car
l'authentification AuthSub ne supporte pas les certificats permettant l'obtention
de jetons sécurisés.

2.1. Création d'un client HTTP authentifié avec AuthSub


Votre application PHP devrait fournir un lien URL vers le service d'authentification de Google. La
méthode statique Zend_Gdata_AuthSub::getAuthSubTokenUri() permet ceci. Elle prend
un argument représentant l'URL de votre application. De cette manière, le serveur Google pourra
générer une réponse menant à une redirection vers cette URL, une fois l'authentification passée.

Après que le serveur d'authentification de Google ait redirigé le navigateur de l'utilisateur vers
votre application, un paramètre GET est ajouté, il s'agit du jeton d'authentification. Ce jeton
servira à éviter de demander une authentification à chaque requête future.

Ensuite, utilisez le jeton avec un appel à la méthode


Zend_Gdata_AuthSub::getHttpClient(). Cette méthode retournera alors un objet de
type Zend_Http_Client, qui sera peuplé des bons en-têtes permettant ainsi une utilisation
future sans nécessité de ré-authentification.

Ci-dessous un exemple d'une application PHP qui effectue une authentification afin d'utiliser
le service Google Calendar. Elle crée un objet client Zend_Gdata utilisant le client HTTP
fraîchement authentifié.

$my_calendar =
'http://www.google.com/calendar/feeds/default/private/full';

if (!isset($_SESSION['cal_token'])) {
if (isset($_GET['token'])) {
// Vous pouvez convertir le jeton unique en jeton de session.
$session_token =
Zend_Gdata_AuthSub::getAuthSubSessionToken($_GET['token']);
// Enregistre le jeton de session, dans la session PHP.
$_SESSION['cal_token'] = $session_token;
} else {
// Affiche le lien permettant la génération du jeton unique.
$googleUri = Zend_Gdata_AuthSub::getAuthSubTokenUri(
'http://'. $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'],
$my_calendar, 0, 1);
echo "Cliquez <a href='$googleUri'>ici</a>"
. " pour autoriser votre application.";
exit();
}
}

// Création d'un client HTTP authentifié


// pour les échanges avec les serveurs Google.
$client = Zend_Gdata_AuthSub::getHttpClient($_SESSION['cal_token']);

753
Zend_Gdata

// Création d'un objet Gdata utilisant le client HTTP authentifié :


$cal = new Zend_Gdata_Calendar($client);

2.2. Destruction de l'authentification AuthSub


Pour détruire la validité d'un jeton d'authentification, utilisez la méthode statique
Zend_Gdata_AuthSub::AuthSubRevokeToken(). Autrement, le jeton reste valide un
certain temps.

// construction sécurisée de la valeur.


$php_self = htmlentities(substr($_SERVER['PHP_SELF'],
0,
strcspn($_SERVER['PHP_SELF'], "\n\r")),
ENT_QUOTES);

if (isset($_GET['logout'])) {
Zend_Gdata_AuthSub::AuthSubRevokeToken($_SESSION['cal_token']);
unset($_SESSION['cal_token']);
header('Location: ' . $php_self);
exit();
}

Notes de sécurité
Le traitement effectué pour la variable $php_self dans l'exemple ci-dessus
est une règle de sécurité générale, elle n'est pas spécifique à l'utilisation
de Zend_Gdata. Vous devriez systématiquement filtrer le contenu que vous
envoyez en tant qu'en-tête HTTP.

Au sujet de la destruction du jeton, elle est recommandée lorsque l'utilisateur en


a terminé avec sa session Google. Même si la possibilité d'interception de ce
jeton reste très faible, il s'agit d'une précaution faisant partie du bon sens et des
bonnes pratiques.

3. Using the Book Search Data API


The Google Book Search Data API allows client applications to view and update Book Search
content in the form of Google Data API feeds.

Your client application can use the Book Search Data API to issue full-text searches for books
and to retrieve standard book information, ratings, and reviews. You can also access individual
users' library collections and public reviews. Finally, your application can submit authenticated
requests to enable users to create and modify library collections, ratings, labels, reviews, and
other account-specific entities.

For more information on the Book Search Data API, please refer to the official PHP Developer's
Guide on code.google.com.

3.1. Authenticating to the Book Search service


You can access both public and private feeds using the Book Search Data API. Public feeds
don't require any authentication, but they are read-only. If you want to modify user libraries,
submit reviews or ratings, or add labels, then your client needs to authenticate before requesting
private feeds. It can authenticate using either of two approaches: AuthSub proxy authentication
or ClientLogin username/password authentication. Please refer to the Authentication section in
the PHP Developer's Guide for more detail.

754
Zend_Gdata

3.2. Searching for books


The Book Search Data API provides a number of feeds that list collections of books.

The most common action is to retrieve a list of books that match a search query. To do so you
create a VolumeQuery object and pass it to the Books::getVolumeFeed method.

For example, to perform a keyword query, with a filter on viewability to restrict the results to partial
or full view books, use the setMinViewability and setQuery methods of the VolumeQuery
object. The following code snippet prints the title and viewability of all volumes whose metadata
or text matches the query term "domino":

$books = new Zend_Gdata_Books();


$query = $books->newVolumeQuery();

$query->setQuery('domino');
$query->setMinViewability('partial_view');

$feed = $books->getVolumeFeed($query);

foreach ($feed as $entry) {


echo $entry->getVolumeId();
echo $entry->getTitle();
echo $entry->getViewability();
}

The Query class, and subclasses like VolumeQuery, are responsible for constructing feed
URLs. The VolumeQuery shown above constructs a URL equivalent to the following:

http://www.google.com/books/feeds/volumes?q=keyword&min-viewability=partial

Note: Since Book Search results are public, you can issue a Book Search query without
authentication.

Here are some of the most common VolumeQuery methods for setting search parameters:

setQuery: Specifies a search query term. Book Search searches all book metadata and full
text for books matching the term. Book metadata includes titles, keywords, descriptions, author
names, and subjects. Note that any spaces, quotes or other punctuation in the parameter value
must be URL-escaped. (Use a plus (+) for a space.) To search for an exact phrase, enclose the
phrase in quotation marks. For example, to search for books matching the phrase "spy plane", set
the q parameter to %22spy+plane%22. You can also use any of the advanced search operators
supported by Book Search. For example, jane+austen+-inauthor:austen returns matches
that mention (but are not authored by) Jane Austen.

setStartIndex: Specifies the index of the first matching result that should be included
in the result set. This parameter uses a one-based index, meaning the first result is 1, the
second result is 2 and so forth. This parameter works in conjunction with the max-results
parameter to determine which results to return. For example, to request the third set of 10
results—results 21-30—set the start-index parameter to 21 and the max-results parameter
to 10. Note: This isn't a general cursoring mechanism. If you first send a query with ?start-
index=1&max-results=10 and then send another query with ?start-index=11&max-
results=10, the service cannot guarantee that the results are equivalent to ?start-
index=1&max-results=20, because insertions and deletions could have taken place in
between the two queries.

755
Zend_Gdata

setMaxResults: Specifies the maximum number of results that should be included in the
result set. This parameter works in conjunction with the start-index parameter to determine which
results to return. The default value of this parameter is 10 and the maximum value is 20.

setMinViewability: Allows you to filter the results according to the books' viewability status.
This parameter accepts one of three values: 'none' (the default, returning all matching books
regardless of viewability), 'partial_view' (returning only books that the user can preview
or view in their entirety), or 'full_view' (returning only books that the user can view in their
entirety).

3.2.1. Partner Co-Branded Search


Google Book Search provides Co-Branded Search, which lets content partners provide full-text
search of their books from their own websites.

If you are a partner who wants to do Co-Branded Search using the Book Search Data API, you
may do so by modifying the feed URL above to point to your Co-Branded Search implementation.
If, for example, a Co-Branded Search is available at the following URL:

http://www.google.com/books/p/PARTNER_COBRAND_ID?q=ball

then you can obtain the same results using the Book Search Data API at the following URL:

http://www.google.com/books/feeds/p/PARTNER_COBRAND_ID/volumes?q=ball+-soccer

To specify an alternate URL when querying a volume feed, you can provide an extra parameter
to newVolumeQuery

$query =
$books->newVolumeQuery('http://www.google.com/books/p/PARTNER_COBRAND_ID');

For additional information or support, visit our Partner help center.

3.3. Using community features


3.3.1. Adding a rating
A user can add a rating to a book. Book Search uses a 1-5 rating system in which 1 is the lowest
rating. Users cannot update or delete ratings.

To add a rating, add a Rating object to a VolumeEntry and post it to the annotation feed. In
the example below, we start from an empty VolumeEntry object.

$entry = new Zend_Gdata_Books_VolumeEntry();


$entry->setId(new Zend_Gdata_App_Extension_Id(VOLUME_ID));
$entry->setRating(new Zend_Gdata_Extension_Rating(3, 1, 5, 1));
$books->insertVolume($entry, Zend_Gdata_Books::MY_ANNOTATION_FEED_URI);

3.3.2. Reviews
In addition to ratings, authenticated users can submit reviews or edit their reviews. For information
on how to request previously submitted reviews, see Retrieving annotations.

3.3.2.1. Adding a review

To add a review, add a Review object to a VolumeEntry and post it to the annotation feed. In
the example below, we start from an existing VolumeEntry object.

756
Zend_Gdata

$annotationUrl = $entry->getAnnotationLink()->href;
$review = new Zend_Gdata_Books_Extension_Review();

$review->setText("This book is amazing!");


$entry->setReview($review);
$books->insertVolume($entry, $annotationUrl);

3.3.2.2. Editing a review

To update an existing review, first you retrieve the review you want to update, then you modify
it, and then you submit it to the annotation feed.

$entryUrl = $entry->getId()->getText();
$review = new Zend_Gdata_Books_Extension_Review();

$review->setText("This book is actually not that good!");


$entry->setReview($review);
$books->updateVolume($entry, $entryUrl);

3.3.3. Labels
You can use the Book Search Data API to label volumes with keywords. A user can submit,
retrieve and modify labels. See Retrieving annotations for how to read previously submitted
labels.

3.3.3.1. Submitting a set of labels

To submit labels, add a Category object with the scheme LABELS_SCHEME to a VolumeEntry
and post it to the annotation feed.

$annotationUrl = $entry->getAnnotationLink()->href;
$category = new Zend_Gdata_App_Extension_Category(
'rated',
'http://schemas.google.com/books/2008/labels');
$entry->setCategory(array($category));
$books->insertVolume($entry, Zend_Gdata_Books::MY_ANNOTATION_FEED_URI);

3.3.4. Retrieving annotations: reviews, ratings, and labels


You can use the Book Search Data API to retrieve annotations submitted by a given user.
Annotations include reviews, ratings, and labels. To retrieve any user's annotations, you can
send an unauthenticated request that includes the user's user ID. To retrieve the authenticated
user's annotations, use the value me as the user ID.

$feed = $books->getVolumeFeed(
'http://www.google.com/books/feeds/users/USER_ID/volumes');
<i>(or)</i>
$feed = $books->getUserAnnotationFeed();

// print title(s) and rating value


foreach ($feed as $entry) {
foreach ($feed->getTitles() as $title) {
echo $title;
}
if ($entry->getRating()) {
echo 'Rating: ' . $entry->getRating()->getAverage();
}

757
Zend_Gdata

For a list of the supported query parameters, see the query parameters section.

3.3.5. Deleting Annotations


If you retrieved an annotation entry containing ratings, reviews, and/or labels, you can remove
all annotations by calling deleteVolume on that entry.

$books->deleteVolume($entry);

3.4. Book collections and My Library


Google Book Search provides a number of user-specific book collections, each of which has its
own feed.

The most important collection is the user's My Library, which represents the books the user would
like to remember, organize, and share with others. This is the collection the user sees when
accessing his or her My Library page.

3.4.1. Retrieving books in a user's library


The following sections describe how to retrieve a list of books from a user's library, with or without
query parameters.

You can query a Book Search public feed without authentication.

3.4.1.1. Retrieving all books in a user's library

To retrieve the user's books, send a query to the My Library feed. To get the library of the
authenticated user, use me in place of USER_ID.

$feed = $books->getUserLibraryFeed();

Note: The feed may not contain all of the user's books, because there's a default limit on the
number of results returned. For more information, see the max-results query parameter in
Searching for books.

3.4.1.2. Searching for books in a user's library

Just as you can search across all books, you can do a full-text search over just the books in a
user's library. To do this, just set the appropriate paramters on the VolumeQuery object.

For example, the following query returns all the books in your library that contain the word "bear":

$query = $books->newVolumeQuery(
'http://www.google.com/books/feeds/users' .
'/USER_ID/collections/library/volumes');
$query->setQuery('bear');
$feed = $books->getVolumeFeed($query);

For a list of the supported query parameters, see the query parameters section. In addition, you
can search for books that have been labeled by the user:

$query = $books->newVolumeQuery(
'http://www.google.com/books/feeds/users/' .
'USER_ID/collections/library/volumes');
$query->setCategory(

758
Zend_Gdata

$query->setCategory('favorites');
$feed = $books->getVolumeFeed($query);

3.4.2. Updating books in a user's library


You can use the Book Search Data API to add a book to, or remove a book from, a user's library.
Ratings, reviews, and labels are valid across all the collections of a user, and are thus edited
using the annotation feed (see Using community features).

3.4.2.1. Adding a book to a library

After authenticating, you can add books to the current user's library.

You can either create an entry from scratch if you know the volume ID, or insert an entry read
from any feed.

The following example creates a new entry and adds it to the library:

$entry = new Zend_Gdata_Books_VolumeEntry();


$entry->setId(new Zend_Gdata_App_Extension_Id(VOLUME_ID));
$books->insertVolume(
$entry,
Zend_Gdata_Books::MY_LIBRARY_FEED_URI
);

The following example adds an existing VolumeEntry object to the library:

$books->insertVolume(
$entry,
Zend_Gdata_Books::MY_LIBRARY_FEED_URI
);

3.4.2.2. Removing a book from a library

To remove a book from a user's library, call deleteVolume on the VolumeEntry object.

$books->deleteVolume($entry);

4. Authentification avec ClientLogin


Le mécanisme dit "ClientLogin" vous permet d'écrire des applications PHP qui récupèrent une
authentification vis à vis des services Google, en spécifiant des identifiants dans le client HTTP.

Voyez http://code.google.com/apis/accounts/AuthForInstalledApps.html pour plus


d'informations sur l'authentification ClientLogin de Google Data.

La documentation Google indique que le mécanisme ClientLogin est approprié dans le cas
d'applications embarquées, à la différence du mécanisme AuthSub, utilisé pour les applications
Web ayant recours à une authentification extérieure. AuthSub récupère des identifiant d'un
utilisateur de l'application Web, et un navigateur réagissant aux redirections est requis. Le
processus ClientLogin, lui, utilise du code PHP tel qu'écrit dans l'application elle-même.
L'utilisateur de l'application n'entre pas en jeu pour fournir des identifiants de manière interactive.

Les identifiants fournis au mécanisme ClientLogin doivent correspondre à des identifiants valides
pour les services Google, mais il n'est pas nécessaire qu'ils correspondent à ceux de l'utilisateur
de l'application.

759
Zend_Gdata

4.1. Création d'un client HTTP "ClientLogin" authentifié


La création d'un client HTTP "ClientLogin" authentifié est un processus servi par la méthode
statique Zend_Gdata_ClientLogin::getHttpClient(). Passez lui les identifiants Google
services sous forme de texte (plain text). La valeur de retour de cette méthode est un objet
Zend_Http_Client.

Le troisième paramètre optionnel est le nom du service Google Data. Par exemple, il peut être
"cl" pour Google Calendar. Par défaut il s'agit de "xapi", ce qui correspond au service générique
de Google Data.

La quatrième paramètre optionnel est une instance de Zend_Http_Client. Vous pouvez alors
configurer votre client à part (par exemple lui ajouter des options pour la gestion d'un Proxy). Si
vous passez NULL à ce paramètre, alors un client Zend_Http_Client générique est crée.

Le cinquième paramètre optionnel est le nom du client que les serveurs Google Data identifieront
en interne. Par défaut il s'agit de "Zend-ZendFramework".

Le sixième paramètre, toujours optionnel, est l'ID pour le challenge CAPTCHA™ retourné par le
serveur. Ce paramètre n'est nécessaire que si vous avez reçu un challenge lors d'un processus
d'authentification passé, et que vous le renvoyez pour résolution..

Le septième paramètre optionnel représente la réponse de l'utilisateur au challenge CAPTCHA™


précédemment reçu. Il n'est donc nécessaire que si vous avez reçu un challenge CAPTCHA™
à résoudre.

Ci dessous, un exemple d'une application PHP qui s'authentifie auprès du service Google
Calendar et crée un objet client Zend_Gdata utilisant l'objet Zend_Http_Client fraîchement
authentifié :

// identifiants de compte Google


$email = 'johndoe@gmail.com';
$passwd = 'xxxxxxxx';
try {
$client = Zend_Gdata_ClientLogin::getHttpClient($email, $passwd, 'cl');
} catch (Zend_Gdata_App_CaptchaRequiredException $cre) {
echo 'l'URL de l\'image CAPTCHA est: ' . $cre->getCaptchaUrl() . "\n";
echo 'Token ID: ' . $cre->getCaptchaToken() . "\n";
} catch (Zend_Gdata_App_AuthException $ae) {
echo 'Problème d'authentification : ' . $ae->exception() . "\n";
}

$cal = new Zend_Gdata_Calendar($client);

4.2. Fermer un client HTTP authentifié par ClientLogin


Il n'y a pas de méthode pour supprimer l'authentification effectuée via un ClientLogin, comme
c'est le cas avec le système de jeton du procédé AuthSub. Les identifiants dans le ClientLogin
étant un identifiant et un mot de passe de compte Google, ils ne peuvent être invalidés et sont
utilisables de manière continue.

5. Using Google Calendar


You can use the Zend_Gdata_Calendar class to view, create, update, and delete events in
the online Google Calendar service.

760
Zend_Gdata

See http://code.google.com/apis/calendar/overview.html for more information about the Google


Calendar API.

5.1. Connecting To The Calendar Service


The Google Calendar API, like all GData APIs, is based off of the Atom Publishing Protocol
(APP), an XML based format for managing web-based resources. Traffic between a client
and the Google Calendar servers occurs over HTTP and allows for both authenticated and
unauthenticated connections.

Before any transactions can occur, this connection needs to be made. Creating a connection
to the calendar servers involves two steps: creating an HTTP client and binding a
Zend_Gdata_Calendar service instance to that client.

5.1.1. Authentication
The Google Calendar API allows access to both public and private calendar feeds. Public feeds
do not require authentication, but are read-only and offer reduced functionality. Private feeds
offers the most complete functionality but requires an authenticated connection to the calendar
servers. There are three authentication schemes that are supported by Google Calendar:

• ClientAuth provides direct username/password authentication to the calendar servers.


Since this scheme requires that users provide your application with their password, this
authentication is only recommended when other authentication schemes are insufficient.

• AuthSub allows authentication to the calendar servers via a Google proxy server. This provides
the same level of convenience as ClientAuth but without the security risk, making this an ideal
choice for web-based applications.

• MagicCookie allows authentication based on a semi-random URL available from within the
Google Calendar interface. This is the simplest authentication scheme to implement, but
requires that users manually retrieve their secure URL before they can authenticate, doesn't
provide access to calendar lists, and is limited to read-only access.

The Zend_Gdata library provides support for all three authentication schemes. The rest of
this chapter will assume that you are familiar the authentication schemes available and how to
create an appropriate authenticated connection. For more information, please see section the
Authentication section of this manual or the Authentication Overview in the Google Data API
Developer's Guide.

5.1.2. Creating A Service Instance


In order to interact with Google Calendar, this library provides the Zend_Gdata_Calendar
service class. This class provides a common interface to the Google Data and Atom Publishing
Protocol models and assists in marshaling requests to and from the calendar servers.

Once deciding on an authentication scheme, the next step is to create an instance of


Zend_Gdata_Calendar. The class constructor takes an instance of Zend_Http_Client as
a single argument. This provides an interface for AuthSub and ClientAuth authentication, as both
of these require creation of a special authenticated HTTP client. If no arguments are provided,
an unauthenticated instance of Zend_Http_Client will be automatically created.

The example below shows how to create a Calendar service class using ClientAuth
authentication:

761
Zend_Gdata

// Parameters for ClientAuth authentication


$service = Zend_Gdata_Calendar::AUTH_SERVICE_NAME;
$user = "sample.user@gmail.com";
$pass = "pa$$w0rd";

// Create an authenticated HTTP client


$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);

// Create an instance of the Calendar service


$service = new Zend_Gdata_Calendar($client);

A Calendar service using AuthSub can be created in a similar, though slightly more lengthy
fashion:

/*
* Retrieve the current URL so that the AuthSub server knows where to
* redirect the user after authentication is complete.
*/
function getCurrentUrl()
{
global $_SERVER;

// Filter php_self to avoid a security vulnerability.


$php_request_uri =
htmlentities(substr($_SERVER['REQUEST_URI'],
0,
strcspn($_SERVER['REQUEST_URI'], "\n\r")),
ENT_QUOTES);

if (isset($_SERVER['HTTPS']) &&
strtolower($_SERVER['HTTPS']) == 'on') {
$protocol = 'https://';
} else {
$protocol = 'http://';
}
$host = $_SERVER['HTTP_HOST'];
if ($_SERVER['HTTP_PORT'] != '' &&
(($protocol == 'http://' && $_SERVER['HTTP_PORT'] != '80') ||
($protocol == 'https://' && $_SERVER['HTTP_PORT'] != '443'))) {
$port = ':' . $_SERVER['HTTP_PORT'];
} else {
$port = '';
}
return $protocol . $host . $port . $php_request_uri;
}

/**
* Obtain an AuthSub authenticated HTTP client, redirecting the user
* to the AuthSub server to login if necessary.
*/
function getAuthSubHttpClient()
{
global $_SESSION, $_GET;

// if there is no AuthSub session or one-time token waiting for us,


// redirect the user to the AuthSub server to get one.
if (!isset($_SESSION['sessionToken']) && !isset($_GET['token'])) {
// Parameters to give to AuthSub server
$next = getCurrentUrl();

762
Zend_Gdata

$scope = "http://www.google.com/calendar/feeds/";
$secure = false;
$session = true;

// Redirect the user to the AuthSub server to sign in

$authSubUrl = Zend_Gdata_AuthSub::getAuthSubTokenUri($next,
$scope,
$secure,
$session);
header("HTTP/1.0 307 Temporary redirect");

header("Location: " . $authSubUrl);

exit();
}

// Convert an AuthSub one-time token into a session token if needed


if (!isset($_SESSION['sessionToken']) && isset($_GET['token'])) {
$_SESSION['sessionToken'] =
Zend_Gdata_AuthSub::getAuthSubSessionToken($_GET['token']);
}

// At this point we are authenticated via AuthSub and can obtain an


// authenticated HTTP client instance

// Create an authenticated HTTP client


$client = Zend_Gdata_AuthSub::getHttpClient($_SESSION['sessionToken']);
return $client;
}

// -> Script execution begins here <-

// Make sure that the user has a valid session, so we can record the
// AuthSub session token once it is available.
session_start();

// Create an instance of the Calendar service, redirecting the user


// to the AuthSub server if necessary.
$service = new Zend_Gdata_Calendar(getAuthSubHttpClient());

Finally, an unauthenticated server can be created for use with either public feeds or MagicCookie
authentication:

// Create an instance of the Calendar service using an unauthenticated


// HTTP client

$service = new Zend_Gdata_Calendar();

Note that MagicCookie authentication is not supplied with the HTTP connection, but is instead
specified along with the desired visibility when submitting queries. See the section on retrieving
events below for an example.

5.2. Retrieving A Calendar List


The calendar service supports retrieving a list of calendars for the authenticated user. This is
the same list of calendars which are displayed in the Google Calendar UI, except those marked
as "hidden" are also available.

763
Zend_Gdata

The calendar list is always private and must be accessed over an authenticated connection. It is
not possible to retrieve another user's calendar list and it cannot be accessed using MagicCookie
authentication. Attempting to access a calendar list without holding appropriate credentials will
fail and result in a 401 (Authentication Required) status code.

$service = Zend_Gdata_Calendar::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Calendar($client);

try {
$listFeed= $service->getCalendarListFeed();
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}

Calling getCalendarListFeed() creates a new instance of


Zend_Gdata_Calendar_ListFeed containing each available calendar as an instance of
Zend_Gdata_Calendar_ListEntry. After retrieving the feed, you can use the iterator and
accessors contained within the feed to inspect the enclosed calendars.

echo "<h1>Calendar List Feed</h1>";


echo "<ul>";
foreach ($listFeed as $calendar) {
echo "<li>" . $calendar->title .
" (Event Feed: " . $calendar->id . ")</li>";
}
echo "</ul>";

5.3. Retrieving Events


Like the list of calendars, events are also retrieved using the Zend_Gdata_Calendar service
class. The event list returned is of type Zend_Gdata_Calendar_EventFeed and contains
each event as an instance of Zend_Gdata_Calendar_EventEntry. As before, the iterator
and accessors contained within the event feed instance allow inspection of individual events.

5.3.1. Queries
When retrieving events using the Calendar API, specially constructed query URLs are used to
describe what events should be returned. The Zend_Gdata_Calendar_EventQuery class
simplifies this task by automatically constructing a query URL based on provided parameters. A
full list of these parameters is available at the Queries section of the Google Data APIs Protocol
Reference. However, there are three parameters that are worth special attention:

• User is used to specify the user whose calendar is being searched for, and is specified as an
email address. If no user is provided, "default" will be used instead to indicate the currently
authenticated user (if authenticated).

• Visibility specifies whether a users public or private calendar should be searched. If using an
unauthenticated session and no MagicCookie is available, only the public feed will be available.

• Projection specifies how much data should be returned by the server and in what format. In
most cases you will want to use the "full" projection. Also available is the "basic" projection,
which places most meta-data into each event's content field as human readable text, and the
"composite" projection which includes complete text for any comments alongside each event.
The "composite" view is often much larger than the "full" view.

764
Zend_Gdata

5.3.2. Retrieving Events In Order Of Start Time

The example below illustrates the use of the Zend_Gdata_Query class and specifies the
private visibility feed, which requires that an authenticated connection is available to the calendar
servers. If a MagicCookie is being used for authentication, the visibility should be instead set
to "private-magicCookieValue", where magicCookieValue is the random string obtained
when viewing the private XML address in the Google Calendar UI. Events are requested
chronologically by start time and only events occurring in the future are returned.

$query = $service->newEventQuery();
$query->setUser('default');
// Set to $query->setVisibility('private-magicCookieValue') if using
// MagicCookie auth
$query->setVisibility('private');
$query->setProjection('full');
$query->setOrderby('starttime');
$query->setFutureevents('true');

// Retrieve the event list from the calendar server


try {
$eventFeed = $service->getCalendarEventFeed($query);
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}

// Iterate through the list of events, outputting them as an HTML list


echo "<ul>";
foreach ($eventFeed as $event) {
echo "<li>" . $event->title . " (Event ID: " . $event->id . ")</li>";
}
echo "</ul>";

Additional properties such as ID, author, when, event status, visibility, web content, and content,
among others are available within Zend_Gdata_Calendar_EventEntry. Refer to the Zend
Framework API Documentation and the Calendar Protocol Reference for a complete list.

5.3.3. Retrieving Events In A Specified Date Range

To print out all events within a certain range, for example from December 1, 2006 through
December 15, 2007, add the following two lines to the previous sample. Take care to remove
"$query->setFutureevents('true')", since futureevents will override startMin and
startMax.

$query->setStartMin('2006-12-01');
$query->setStartMax('2006-12-16');

Note that startMin is inclusive whereas startMax is exclusive. As a result, only events
through 2006-12-15 23:59:59 will be returned.

5.3.4. Retrieving Events By Fulltext Query

To print out all events which contain a specific word, for example "dogfood", use the setQuery()
method when creating the query.

$query->setQuery("dogfood");

765
Zend_Gdata

5.3.5. Retrieving Individual Events


Individual events can be retrieved by specifying their event ID as part of the query. Instead of
calling getCalendarEventFeed(), getCalendarEventEntry() should be called instead.

$query = $service->newEventQuery();
$query->setUser('default');
$query->setVisibility('private');
$query->setProjection('full');
$query->setEvent($eventId);

try {
$event = $service->getCalendarEventEntry($query);
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}

In a similar fashion, if the event URL is known, it can be passed directly into
getCalendarEntry() to retrieve a specific event. In this case, no query object is required
since the event URL contains all the necessary information to retrieve the event.

$eventURL = "http://www.google.com/calendar/feeds/default/private"
. "/full/g829on5sq4ag12se91d10uumko";

try {
$event = $service->getCalendarEventEntry($eventURL);
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}

5.4. Creating Events


5.4.1. Creating Single-Occurrence Events
Events are added to a calendar by creating an instance of Zend_Gdata_EventEntry and
populating it with the appropriate data. The calendar service instance (Zend_Gdata_Calendar)
is then used to used to transparently covert the event into XML and POST it to the calendar
server. Creating events requires either an AuthSub or ClientAuth authenticated connection to
the calendar server.

At a minimum, the following attributes should be set:

• Title provides the headline that will appear above the event within the Google Calendar UI.

• When indicates the duration of the event and, optionally, any reminders that are associated
with it. See the next section for more information on this attribute.

Other useful attributes that may optionally set include:

• Author provides information about the user who created the event.

• Content provides additional information about the event which appears when the event details
are requested from within Google Calendar.

• EventStatus indicates whether the event is confirmed, tentative, or canceled.

• Hidden removes the event from the Google Calendar UI.

766
Zend_Gdata

• Transparency indicates whether the event should be consume time on the user's free/busy list.

• WebContent allows links to external content to be provided within an event.

• Where indicates the location of the event.

• Visibility allows the event to be hidden from the public event lists.

For a complete list of event attributes, refer to the Zend Framework API Documentation and the
Calendar Protocol Reference. Attributes that can contain multiple values, such as where, are
implemented as arrays and need to be created accordingly. Be aware that all of these attributes
require objects as parameters. Trying instead to populate them using strings or primitives will
result in errors during conversion to XML.

Once the event has been populated, it can be uploaded to the calendar server by passing it as
an argument to the calendar service's insertEvent() function.

// Create a new entry using the calendar service's magic factory method
$event= $service->newEventEntry();

// Populate the event with the desired information


// Note that each attribute is crated as an instance of a matching class
$event->title = $service->newTitle("My Event");
$event->where = array($service->newWhere("Mountain View, California"));
$event->content =
$service->newContent(" This is my awesome event. RSVP required.");

// Set the date using RFC 3339 format.


$startDate = "2008-01-20";
$startTime = "14:00";
$endDate = "2008-01-20";
$endTime = "16:00";
$tzOffset = "-08";

$when = $service->newWhen();
$when->startTime = "{$startDate}T{$startTime}:00.000{$tzOffset}:00";
$when->endTime = "{$endDate}T{$endTime}:00.000{$tzOffset}:00";
$event->when = array($when);

// Upload the event to the calendar server


// A copy of the event as it is recorded on the server is returned
$newEvent = $service->insertEvent($event);

5.4.2. Event Schedules and Reminders


An event's starting time and duration are determined by the value of its when property, which
contains the properties startTime, endTime, and valueString. StartTime and EndTime
control the duration of the event, while the valueString property is currently unused.

All-day events can be scheduled by specifying only the date omitting the time when setting
startTime and endTime. Likewise, zero-duration events can be specified by omitting the
endTime. In all cases, date/time values should be provided in RFC3339 format.

// Schedule the event to occur on December 05, 2007 at 2 PM PST (UTC-8)


// with a duration of one hour.
$when = $service->newWhen();
$when->startTime = "2007-12-05T14:00:00-08:00";
$when->endTime="2007-12-05T15:00:00:00-08:00";

767
Zend_Gdata

// Apply the when property to an event


$event->when = array($when);

The when attribute also controls when reminders are sent to a user. Reminders are stored in an
array and each event may have up to find reminders associated with it.

For a reminder to be valid, it needs to have two attributes set: method and a time. Method
can accept one of the following strings: "alert", "email", or "sms". The time should be entered as
an integer and can be set with either the property minutes, hours, days, or absoluteTime.
However, a valid request may only have one of these attributes set. If a mixed time is desired,
convert to the most precise unit available. For example, 1 hour and 30 minutes should be entered
as 90 minutes.

// Create a new reminder object. It should be set to send an email


// to the user 10 minutes beforehand.
$reminder = $service->newReminder();
$reminder->method = "email";
$reminder->minutes = "10";

// Apply the reminder to an existing event's when property


$when = $event->when[0];
$when->reminders = array($reminder);

5.4.3. Creating Recurring Events


Recurring events are created the same way as single-occurrence events, except a recurrence
attribute should be provided instead of a where attribute. The recurrence attribute should hold
a string describing the event's recurrence pattern using properties defined in the iCalendar
standard (RFC 2445).

Exceptions to the recurrence pattern will usually be specified by a distinct


recurrenceException attribute. However, the iCalendar standard provides a secondary
format for defining recurrences, and the possibility that either may be used must be accounted for.

Due to the complexity of parsing recurrence patterns, further information on this them is outside
the scope of this document. However, more information can be found in the Common Elements
section of the Google Data APIs Developer Guide, as well as in RFC 2445.

// Create a new entry using the calendar service's magic factory method
$event= $service->newEventEntry();

// Populate the event with the desired information


// Note that each attribute is crated as an instance of a matching class
$event->title = $service->newTitle("My Recurring Event");
$event->where = array($service->newWhere("Palo Alto, California"));
$event->content =
$service->newContent(' This is my other awesome event, ' .
' occurring all-day every Tuesday from .
'2007-05-01 until 207-09-04. No RSVP required.');

// Set the duration and frequency by specifying a recurrence pattern.

$recurrence = "DTSTART;VALUE=DATE:20070501\r\n" .
"DTEND;VALUE=DATE:20070502\r\n" .
"RRULE:FREQ=WEEKLY;BYDAY=Tu;UNTIL=20070904\r\n";

768
Zend_Gdata

$event->recurrence = $service->newRecurrence($recurrence);

// Upload the event to the calendar server


// A copy of the event as it is recorded on the server is returned
$newEvent = $service->insertEvent($event);

5.4.4. Using QuickAdd


QuickAdd is a feature which allows events to be created using free-form text entry. For example,
the string "Dinner at Joe's Diner on Thursday" would create an event with the title "Dinner",
location "Joe's Diner", and date "Thursday". To take advantage of QuickAdd, create a new
QuickAdd property set to TRUE and store the freeform text as a content property.

// Create a new entry using the calendar service's magic factory method
$event= $service->newEventEntry();

// Populate the event with the desired information


$event->content= $service->newContent("Dinner at Joe's Diner on Thursday");
$event->quickAdd = $service->newQuickAdd("true");

// Upload the event to the calendar server


// A copy of the event as it is recorded on the server is returned
$newEvent = $service->insertEvent($event);

5.5. Modifying Events


Once an instance of an event has been obtained, the event's attributes can be locally modified
in the same way as when creating an event. Once all modifications are complete, calling the
event's save() method will upload the changes to the calendar server and return a copy of the
event as it was created on the server.

In the event another user has modified the event since the local copy was retrieved, save()
will fail and the server will return a 409 (Conflict) status code. To resolve this a fresh copy of the
event must be retrieved from the server before attempting to resubmit any modifications.

// Get the first event in the user's event list


$event = $eventFeed[0];

// Change the title to a new value


$event->title = $service->newTitle("Woof!");

// Upload the changes to the server


try {
$event->save();
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}

5.6. Deleting Events


Calendar events can be deleted either by calling the calendar service's delete() method and
providing the edit URL of an event or by calling an existing event's own delete() method.

In either case, the deleted event will still show up on a user's private event feed if an
updateMin query parameter is provided. Deleted events can be distinguished from regular
events because they will have their eventStatus property set to "http://schemas.google.com/
g/2005#event.canceled".

769
Zend_Gdata

// Option 1: Events can be deleted directly


$event->delete();

// Option 2: Events can be deleted supplying the edit URL of the event
// to the calendar service, if known
$service->delete($event->getEditLink()->href);

5.7. Accessing Event Comments


When using the full event view, comments are not directly stored within an entry. Instead, each
event contains a URL to its associated comment feed which must be manually requested.

Working with comments is fundamentally similar to working with events, with the only significant
difference being that a different feed and event class should be used and that the additional meta-
data for events such as where and when does not exist for comments. Specifically, the comment's
author is stored in the author property, and the comment text is stored in the content property.

// Extract the comment URL from the first event in a user's feed list
$event = $eventFeed[0];
$commentUrl = $event->comments->feedLink->url;

// Retrieve the comment list for the event


try {
$commentFeed = $service->getFeed($commentUrl);
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}

// Output each comment as an HTML list


echo "<ul>";
foreach ($commentFeed as $comment) {
echo "<li><em>Comment By: " . $comment->author->name "</em><br/>" .
$comment->content . "</li>";
}
echo "</ul>";

6. Using Google Documents List Data API


The Google Documents List Data API allows client applications to upload documents to Google
Documents and list them in the form of Google Data API ("GData") feeds. Your client application
can request a list of a user's documents, and query the content in an existing document.

See http://code.google.com/apis/documents/overview.html for more information about the


Google Documents List API.

6.1. Get a List of Documents


You can get a list of the Google Documents for a particular user by using the
getDocumentListFeed() method of the docs service. The service will return a
Zend_Gdata_Docs_DocumentListFeed object containing a list of documents associated with
the authenticated user.

$service = Zend_Gdata_Docs::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);

770
Zend_Gdata

$docs = new Zend_Gdata_Docs($client);


$feed = $docs->getDocumentListFeed();

The resulting Zend_Gdata_Docs_DocumentListFeed object represents the response from


the server. This feed contains a list of Zend_Gdata_Docs_DocumentListEntry objects
($feed->entries), each of which represents a single Google Document.

6.2. Upload a Document


You can create a new Google Document by uploading a word processing document,
spreadsheet, or presentation. This example is from the interactive Docs.php sample which comes
with the library. It demonstrates uploading a file and printing information about the result from
the server.

/**
* Upload the specified document
*
* @param Zend_Gdata_Docs $docs The service object to use for communicating
* with the Google Documents server.
* @param boolean $html True if output should be formatted for display in a
* web browser.
* @param string $originalFileName The name of the file to be uploaded. The
* MIME type of the file is determined from the extension on this file
* name. For example, test.csv is uploaded as a comma separated volume
* and converted into a spreadsheet.
* @param string $temporaryFileLocation (optional) The file in which the
* data for the document is stored. This is used when the file has been
* uploaded from the client's machine to the server and is stored in
* a temporary file which does not have an extension. If this parameter
* is null, the file is read from the originalFileName.
*/
function uploadDocument($docs, $html, $originalFileName,
$temporaryFileLocation) {
$fileToUpload = $originalFileName;
if ($temporaryFileLocation) {
$fileToUpload = $temporaryFileLocation;
}

// Upload the file and convert it into a Google Document. The original
// file name is used as the title of the document and the MIME type
// is determined based on the extension on the original file name.
$newDocumentEntry = $docs->uploadFile($fileToUpload, $originalFileName,
null, Zend_Gdata_Docs::DOCUMENTS_LIST_FEED_URI);

echo "New Document Title: ";

if ($html) {
// Find the URL of the HTML view of this document.
$alternateLink = '';
foreach ($newDocumentEntry->link as $link) {
if ($link->getRel() === 'alternate') {
$alternateLink = $link->getHref();
}
}
// Make the title link to the document on docs.google.com.
echo "<a href=\"$alternateLink\">\n";
}
echo $newDocumentEntry->title."\n";
if ($html) {echo "</a>\n";}

771
Zend_Gdata

6.3. Searching the documents feed


You can search the Document List using some of the standard Google Data API query
parameters. Categories are used to restrict the type of document (word processor document,
spreadsheet) returned. The full-text query string is used to search the content of all the
documents. More detailed information on parameters specific to the Documents List can be found
in the Documents List Data API Reference Guide.

6.3.1. Get a List of Word Processing Documents


You can also request a feed containing all of your documents of a specific type. For example, to
see a list of your work processing documents, you would perform a category query as follows.

$feed = $docs->getDocumentListFeed(
'http://docs.google.com/feeds/documents/private/full/-/document');

6.3.2. Get a List of Spreadsheets


To request a list of your Google Spreadsheets, use the following category query:

$feed = $docs->getDocumentListFeed(
'http://docs.google.com/feeds/documents/private/full/-/spreadsheet');

6.3.3. Performing a text query


You can search the content of documents by using a Zend_Gdata_Docs_Query in your
request. A Query object can be used to construct the query URI, with the search term being
passed in as a parameter. Here is an example method which queries the documents list for
documents which contain the search string:

$docsQuery = new Zend_Gdata_Docs_Query();


$docsQuery->setQuery($query);
$feed = $client->getDocumentListFeed($docsQuery);

7. Using Google Health


The Google Health Data API is designed to enable developers to do two things:

• Read a user's Google Health profile or query for medical records that match particular criteria
and then use the results to provide personalized functionality based on the data.

• Add new medical records to a user's profile by including CCR data when sending a notice
to a user's profile. Note: The CCR data is stored as an XML blob within the <atom> entry.
The library does not provide direct accessors to the object model but it does have helpers for
extracting specific fields.

There are three main feeds, each of which requires authentication. Unlike other Google
Data APIs, each Google Health feed has a limited set of HTTP operations you can
perform on it, depending on which authentication method you are using (ClientLogin or
AuthSub/OAuth). For a list of permitted operations, see http://code.google.com/apis/health/
reference.html#Authentication.

• Profile Feed use the profile feed to query a user's health profile for specific information.

• Register Feed use the register feed to reconcile new CCR data into a profile.

772
Zend_Gdata

• Profile List Feed the profile list feed should be used to determine which of the user's Health
profiles to interact with. This feed is only available when using ClientLogin.

See http://code.google.com/apis/health for more information about the Google Health API.

7.1. Connect To The Health Service


The Google Health API, like all Google Data APIs, is based off of the Atom Publishing Protocol
(APP), an XML based format for managing web-based resources. Traffic between a client and
the Google Health servers occurs over HTTP and allows for authenticated connections.

Before any transactions can occur, a connection needs to be made. Creating a connection to the
Health servers involves two steps: creating an HTTP client and binding a Zend_Gdata_Health
service instance to that client.

7.1.1. Authentication
The Google Health API allows programmatic access to a user's Health profile. There are three
authentication schemes that are supported by Google Health:

• ClientLogin provides direct username/password authentication to the Health servers. Since


this method requires that users provide your application with their password, this authentication
scheme is only recommended for installed/desktop applications.

• AuthSub allows a user to authorize the sharing of their private data. This provides the same
level of convenience as ClientLogin but without the security risk, making it an ideal choice for
web-based applications. For Google Health, AuthSub must be used in registered and secure
mode--meaning that all requests to the API must be digitally signed.

• OAuth is an alternative to AuthSub. Although this authentication scheme is not discussed in


this document, more information can be found in the Health Data API Developer's Guide.

See Authentication Overview in the Google Data API documentation for more information on
each authentication method.

7.1.2. Create A Health Service Instance


In order to interact with Google Health, the client library provides the Zend_Gdata_Health
service class. This class provides a common interface to the Google Data and Atom Publishing
Protocol models and assists in marshaling requests to and from the Health API.

Once you've decided on an authentication scheme, the next step is to create an


instance of Zend_Gdata_Health . This class should be passed an instance of
Zend_Gdata_HttpClient. This provides an interface for AuthSub/OAuth and ClientLogin to
create a special authenticated HTTP client.

To test against the H9 Developer's (/h9) instead of Google Health (/health), the
Zend_Gdata_Health constructor takes an optional third argument for you to specify the H9
service name 'weaver'.

The example below shows how to create a Health service class using ClientLogin authentication:

// Parameters for ClientLogin authentication


$healthServiceName = Zend_Gdata_Health::HEALTH_SERVICE_NAME;
//$h9ServiceName = Zend_Gdata_Health::H9_SANDBOX_SERVICE_NAME;
$user = "user@gmail.com";
$pass = "pa$$w0rd";

773
Zend_Gdata

// Create an authenticated HTTP client


$client = Zend_Gdata_ClientLogin::getHttpClient($user,
$pass,
$healthServiceName);

// Create an instance of the Health service


$service = new Zend_Gdata_Health($client);

A Health service using AuthSub can be created in a similar, though slightly more lengthy fashion.
AuthSub is the recommend interface to communicate with Google Health because each token
is directly linked to a specific profile in the user's account. Unlike other Google Data APIs, it is
required that all requests from your application be digitally signed.

/*
* Retrieve the current URL so that the AuthSub server knows where to
* redirect the user after authentication is complete.
*/
function getCurrentUrl() {
$phpRequestUri = htmlentities(substr($_SERVER['REQUEST_URI'],
0,
strcspn($_SERVER['REQUEST_URI'],
"\n\r")),
ENT_QUOTES);

if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') {


$protocol = 'https://';
} else {
$protocol = 'http://';
}
$host = $_SERVER['HTTP_HOST'];
if ($_SERVER['SERVER_PORT'] != '' &&
(($protocol == 'http://' && $_SERVER['SERVER_PORT'] != '80') ||
($protocol == 'https://' && $_SERVER['SERVER_PORT'] != '443'))) {
$port = ':' . $_SERVER['SERVER_PORT'];
} else {
$port = '';
}
return $protocol . $host . $port . $phpRequestUri;
}

/*
* Redirect a user to AuthSub if they do not have a valid session token.
* If they're coming back from AuthSub with a single-use token, instantiate
* a new HTTP client and exchange the token for a long-lived session token
* instead.
*/
function setupClient($singleUseToken = null) {
$client = null;

// Fetch a new AuthSub token?


if (!$singleUseToken) {
$next = getCurrentUrl();
$scope = 'https://www.google.com/health/feeds';
$authSubHandler = 'https://www.google.com/health/authsub';
$secure = 1;
$session = 1;
$authSubURL = Zend_Gdata_AuthSub::getAuthSubTokenUri($next,
$scope,

774
Zend_Gdata

$secure,
$session,
$authSubHandler);

// 1 - allows posting notices && allows reading profile data


$permission = 1;
$authSubURL .= '&permission=' . $permission;

echo '<a href="' . $authSubURL . '">Your Google Health Account</a>';


} else {
$client = new Zend_Gdata_HttpClient();

// This sets your private key to be used to sign subsequent requests


$client->setAuthSubPrivateKeyFile('/path/to/your/rsa_private_key.pem',
null,
true);

$sessionToken =
Zend_Gdata_AuthSub::getAuthSubSessionToken(trim($singleUseToken),
$client);

// Set the long-lived session token for subsequent requests


$client->setAuthSubToken($sessionToken);
}
return $client;
}

// -> Script execution begins here <-

session_start();

$client = setupClient(@$_GET['token']);

// Create an instance of the Health service


$userH9Sandbox = false;
$healthService = new Zend_Gdata_Health($client,
'googleInc-MyTestAppName-v1.0',
$userH9Sandbox);

NOTE: the remainder of this document will assume you are using AuthSub for authentication.

7.2. Profile Feed


To query the user's profile feed, make sure your initial AuthSub token was requested with the
permission=1 parameter set. The process of extracting data from the profile requires two
steps, sending a query and iterating through the resulting feed.

7.2.1. Send a Structured Query


You can send structured queries to retrieve specific records from a user's profile.

When retrieving the profile using the Health API, specifically constructed query URLs are used to
describe what (CCR) data should be returned. The Zend_Gdata_Health_Query class helps
simplify this task by automatically constructing a query URL based on the parameters you set.

7.2.1.1. Query The Feed

To execute a query against the profile feed, invoke a new instance of an


Zend_Gdata_Health_Query and call the service's getHealthProfileFeed() method:

775
Zend_Gdata

$healthService = new Zend_Gdata_Health($client);

// example query for the top 10 medications with 2 items each


$query = new Zend_Gdata_Health_Query();
$query->setDigest("true");
$query->setGrouped("true");
$query->setMaxResultsGroup(10);
$query->setMaxResultsInGroup(2);
$query->setCategory("medication");

$profileFeed = $healthService->getHealthProfileFeed($query);

Using setDigest("true") returns all of user's CCR data in a single Atom <entry>.

The setCategory() helper can be passed an additional parameter to return more


specific CCR information. For example, to return just the medication Lipitor, use
setCategory("medication", "Lipitor"). The same methodology can be applied to
other categories such as conditions, allergies, lab results, etc.

A full list of supported query parameters is available in the query parameters section of the Health
API Reference Guide.

7.2.2. Iterate Through The Profile Entries


Each Google Health entry contains CCR data, however, using the digest=true query
parameter will consolidate all of the CCR elements (that match your query) into a single Atom
<entry>.

To retrieve the full CCR information from an entry, make a call to the
Zend_Gdata_Health_ProfileEntry class's getCcr() method. That returns a
Zend_Gdata_Health_Extension_CCR:

$entries = $profileFeed->getEntries();
foreach ($entries as $entry) {
$medications = $entry->getCcr()->getMedications();
//$conditions = $entry->getCcr()->getConditions();
//$immunizations = $entry->getCcr()->getImmunizations();

// print the CCR xml (this will just be the entry's medications)
foreach ($medications as $med) {
$xmlStr = $med->ownerDocument->saveXML($med);
echo "<pre>" . $xmlStr . "</pre>";
}
}

Here, the getCcr() method is used in conjunction with a magic helper to drill down and extract
just the medication data from the entry's CCR. The formentioned magic helper takes the form
getCATEGORYNAME(), where CATEGORYNAME is a supported Google Health category. See the
Google Health reference Guide for the possible categories.

To be more efficient, you can also use category queries to only return the necessary CCR from
the Google Health servers. Then, iterate through those results:

$query = new Zend_Gdata_Health_Query();


$query->setDigest("true");
$query->setCategory("condition");
$profileFeed = $healthService->getHealthProfileFeed($query);

776
Zend_Gdata

// Since the query contained digest=true, only one Atom entry is returned
$entry = $profileFeed->entry[0];
$conditions = $entry->getCcr()->getConditions();

// print the CCR xml (this will just be the profile's conditions)
foreach ($conditions as $cond) {
$xmlStr = $cond->ownerDocument->saveXML($cond);
echo "<pre>" . $xmlStr . "</pre>";
}

7.3. Profile List Feed


NOTE: This feed is only available when using ClientLogin

Since ClientLogin requires a profile ID with each of its feeds, applications will likely want to query
this feed first in order to select the appropriate profile. The profile list feed returns Atom entries
corresponding each profile in the user's Google Health account. The profile ID is returned in the
Atom <content> and the profile name in the <title> element.

7.3.1. Query The Feed


To execute a query against the profile list feed, call the service's
getHealthProfileListFeed() method:

$client = Zend_Gdata_ClientLogin::getHttpClient('user@gmail.com',
'pa$$word',
'health');
$healthService = new Zend_Gdata_Health($client);
$feed = $healthService->getHealthProfileListFeed();

// print each profile's name and id


$entries = $feed->getEntries();
foreach ($entries as $entry) {
echo '<p>Profile name: ' . $entry->getProfileName() . '<br>';
echo 'profile ID: ' . $entry->getProfileID() . '</p>';
}

Once you've determined which profile to use, call setProfileID() with the profileID as an
argument. This will restrict subsequent API requests to be against that particular profile:

// use the first profile


$profileID = $feed->entry[0]->getProfileID();
$healthService->setProfileID($profileID);

$profileFeed = $healthService->getHealthProfileFeed();

$profileID = $healthService->getProfileID();
echo '<p><b>Queried profileID</b>: ' . $profileID . '</p>';

7.4. Sending Notices to the Register Feed


Individual posts to the register feed are known as notices. Notice are sent from third-party
applications to inform the user of a new event. With AuthSub/OAuth, notices are the single means
by which your application can add new CCR information into a user's profile. Notices can contain
plain text (including certain XHTML elements), a CCR document, or both. As an example, notices

777
Zend_Gdata

might be sent to remind users to pick up a prescription, or they might contain lab results in the
CCR format.

7.4.1. Sending a notice


Notices can be sent by using the sendHealthNotice() method for the Health service:

$healthService = new Zend_Gdata_Health($client);

$subject = "Title of your notice goes here";


$body = "Notice body can contain <b>html</b> entities";
$ccr = '<ContinuityOfCareRecord xmlns="urn:astm-org:CCR">
<Body>
<Problems>
<Problem>
<DateTime>
<Type><Text>Start date</Text></Type>
<ExactDateTime>2007-04-04T07:00:00Z</ExactDateTime>
</DateTime>
<Description>
<Text>Aortic valve disorders</Text>
<Code>
<Value>410.10</Value>
<CodingSystem>ICD9</CodingSystem>
<Version>2004</Version>
</Code>
</Description>
<Status><Text>Active</Text></Status>
</Problem>
</Problems>
</Body>
</ContinuityOfCareRecord>';

$responseEntry = $healthService->sendHealthNotice($subject,
$body,
"html",
$ccr);

8. Using Google Spreadsheets


The Google Spreadsheets data API allows client applications to view and update Spreadsheets
content in the form of Google data API feeds. Your client application can request a list of a
user's spreadsheets, edit or delete content in an existing Spreadsheets worksheet, and query
the content in an existing Spreadsheets worksheet.

See http://code.google.com/apis/spreadsheets/overview.html for more information about the


Google Spreadsheets API.

8.1. Create a Spreadsheet


The Spreadsheets data API does not currently provide a way to programmatically create or delete
a spreadsheet.

8.2. Get a List of Spreadsheets


You can get a list of spreadsheets for a particular user by using the
getSpreadsheetFeed method of the Spreadsheets service. The service will return a

778
Zend_Gdata

Zend_Gdata_Spreadsheets_SpreadsheetFeed object containing a list of spreadsheets


associated with the authenticated user.

$service = Zend_Gdata_Spreadsheets::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$spreadsheetService = new Zend_Gdata_Spreadsheets($client);
$feed = $spreadsheetService->getSpreadsheetFeed();

8.3. Get a List of Worksheets


A given spreadsheet may contain multiple worksheets. For each spreadsheet, there's a
worksheets metafeed listing all the worksheets in that spreadsheet.

Given the spreadsheet key from the <id> of a


Zend_Gdata_Spreadsheets_SpreadsheetEntry object you've already retrieved, you can
fetch a feed containing a list of worksheets associated with that spreadsheet.

$query = new Zend_Gdata_Spreadsheets_DocumentQuery();


$query->setSpreadsheetKey($spreadsheetKey);
$feed = $spreadsheetService->getWorksheetFeed($query);

The resulting Zend_Gdata_Spreadsheets_WorksheetFeed object feed represents


the response from the server. Among other things, this feed contains a list of
Zend_Gdata_Spreadsheets_WorksheetEntry objects ($feed->entries), each of
which represents a single worksheet.

8.4. Interacting With List-based Feeds


A given worksheet generally contains multiple rows, each containing multiple cells. You can
request data from the worksheet either as a list-based feed, in which each entry represents a
row, or as a cell-based feed, in which each entry represents a single cell. For information on cell-
based feeds, see Interacting with cell-based feeds.

The following sections describe how to get a list-based feed, add a row to a worksheet, and send
queries with various query parameters.

The list feed makes some assumptions about how the data is laid out in the spreadsheet.

In particular, the list feed treats the first row of the worksheet as a header row; Spreadsheets
dynamically creates XML elements named after the contents of header-row cells. Users who
want to provide Gdata feeds should not put any data other than column headers in the first row
of a worksheet.

The list feed contains all rows after the first row up to the first blank row. The first blank row
terminates the data set. If expected data isn't appearing in a feed, check the worksheet manually
to see whether there's an unexpected blank row in the middle of the data. In particular, if the
second row of the spreadsheet is blank, then the list feed will contain no data.

A row in a list feed is as many columns wide as the worksheet itself.

8.4.1. Get a List-based Feed


To retrieve a worksheet's list feed, use the getListFeed method of the Spreadsheets service.

$query = new Zend_Gdata_Spreadsheets_ListQuery();


$query->setSpreadsheetKey($spreadsheetKey);

779
Zend_Gdata

$query->setWorksheetId($worksheetId);
$listFeed = $spreadsheetService->getListFeed($query);

The resulting Zend_Gdata_Spreadsheets_ListFeed object $listfeed represents


a response from the server. Among other things, this feed contains an array of
Zend_Gdata_Spreadsheets_ListEntry objects ($listFeed->entries), each of which
represents a single row in a worksheet.

Each Zend_Gdata_Spreadsheets_ListEntry contains an array, custom, which contains


the data for that row. You can extract and display this array:

$rowData = $listFeed->entries[1]->getCustom();
foreach($rowData as $customEntry) {
echo $customEntry->getColumnName() . " = " . $customEntry->getText();
}

An alternate version of this array, customByName, allows direct access to an entry's cells by
name. This is convenient when trying to access a specific header:

$customEntry = $listFeed->entries[1]->getCustomByName('my_heading');
echo $customEntry->getColumnName() . " = " . $customEntry->getText();

8.4.2. Reverse-sort Rows


By default, rows in the feed appear in the same order as the corresponding rows in the GUI; that
is, they're in order by row number. To get rows in reverse order, set the reverse properties of the
Zend_Gdata_Spreadsheets_ListQuery object to TRUE:

$query = new Zend_Gdata_Spreadsheets_ListQuery();


$query->setSpreadsheetKey($spreadsheetKey);
$query->setWorksheetId($worksheetId);
$query->setReverse('true');
$listFeed = $spreadsheetService->getListFeed($query);

Note that if you want to order (or reverse sort) by a particular column, rather than by position in the
worksheet, you can set the orderby value of the Zend_Gdata_Spreadsheets_ListQuery
object to column:<the header of that column>.

8.4.3. Send a Structured Query


You can set a Zend_Gdata_Spreadsheets_ListQuery's sq value to produce a feed with
entries that meet the specified criteria. For example, suppose you have a worksheet containing
personnel data, in which each row represents information about a single person. You wish to
retrieve all rows in which the person's name is "John" and the person's age is over 25. To do
so, you would set sq as follows:

$query = new Zend_Gdata_Spreadsheets_ListQuery();


$query->setSpreadsheetKey($spreadsheetKey);
$query->setWorksheetId($worksheetId);
$query->setSpreadsheetQuery('name=John and age>25');
$listFeed = $spreadsheetService->getListFeed($query);

8.4.4. Add a Row


Rows can be added to a spreadsheet by using the insertRow method of the Spreadsheet
service.

780
Zend_Gdata

$insertedListEntry = $spreadsheetService->insertRow($rowData,
$spreadsheetKey,
$worksheetId);

The $rowData parameter contains an array of column keys to data values. The method returns
a Zend_Gdata_Spreadsheets_SpreadsheetsEntry object which represents the inserted
row.

Spreadsheets inserts the new row immediately after the last row that appears in the list-based
feed, which is to say immediately before the first entirely blank row.

8.4.5. Edit a Row


Once a Zend_Gdata_Spreadsheets_ListEntry object is fetched, its rows can be updated
by using the updateRow method of the Spreadsheet service.

$updatedListEntry = $spreadsheetService->updateRow($oldListEntry,
$newRowData);

The $oldListEntry parameter contains the list entry to be updated. $newRowData contains
an array of column keys to data values, to be used as the new row data. The method returns
a Zend_Gdata_Spreadsheets_SpreadsheetsEntry object which represents the updated
row.

8.4.6. Delete a Row


To delete a row, simply invoke deleteRow on the Zend_Gdata_Spreadsheets object with
the existing entry to be deleted:

$spreadsheetService->deleteRow($listEntry);

Alternatively, you can call the delete method of the entry itself:

$listEntry->delete();

8.5. Interacting With Cell-based Feeds


In a cell-based feed, each entry represents a single cell.

Note that we don't recommend interacting with both a cell-based feed and a list-based feed for
the same worksheet at the same time.

8.5.1. Get a Cell-based Feed


To retrieve a worksheet's cell feed, use the getCellFeed method of the Spreadsheets service.

$query = new Zend_Gdata_Spreadsheets_CellQuery();


$query->setSpreadsheetKey($spreadsheetKey);
$query->setWorksheetId($worksheetId);
$cellFeed = $spreadsheetService->getCellFeed($query);

The resulting Zend_Gdata_Spreadsheets_CellFeed object $cellFeed represents


a response from the server. Among other things, this feed contains an array of
Zend_Gdata_Spreadsheets_CellEntry objects ($cellFeed>entries), each of which
represents a single cell in a worksheet. You can display this information:

781
Zend_Gdata

foreach($cellFeed as $cellEntry) {
$row = $cellEntry->cell->getRow();
$col = $cellEntry->cell->getColumn();
$val = $cellEntry->cell->getText();
echo "$row, $col = $val\n";
}

8.5.2. Send a Cell Range Query


Suppose you wanted to retrieve the cells in the first column of a worksheet. You can request a
cell feed containing only this column as follows:

$query = new Zend_Gdata_Spreadsheets_CellQuery();


$query->setMinCol(1);
$query->setMaxCol(1);
$query->setMinRow(2);
$feed = $spreadsheetService->getCellsFeed($query);

This requests all the data in column 1, starting with row 2.

8.5.3. Change Contents of a Cell


To modify the contents of a cell, call updateCell with the row, column, and new value of the cell.

$updatedCell = $spreadsheetService->updateCell($row,
$col,
$inputValue,
$spreadsheetKey,
$worksheetId);

The new data is placed in the specified cell in the worksheet. If the specified cell contains data
already, it will be overwritten. Note: Use updateCell to change the data in a cell, even if the
cell is empty.

9. Using Google Apps Provisioning


Google Apps is a service which allows domain administrators to offer their users managed
access to Google services such as Mail, Calendar, and Docs & Spreadsheets. The Provisioning
API offers a programmatic interface to configure this service. Specifically, this API allows
administrators the ability to create, retrieve, update, and delete user accounts, nicknames, and
email lists.

This library implements version 2.0 of the Provisioning API. Access to your account via the
Provisioning API must be manually enabled for each domain using the Google Apps control
panel. Only certain account types are able to enable this feature.

For more information on the Google Apps Provisioning API, including instructions for enabling
API access, refer to the Provisioning API V2.0 Reference.

Authentication

The Provisioning API does not support authentication via AuthSub and
anonymous access is not permitted. All HTTP connections must be authenticated
using ClientAuth authentication.

782
Zend_Gdata

9.1. Setting the current domain


In order to use the Provisioning API, the domain being administered needs to be specified in
all request URIs. In order to ease development, this information is stored within both the Gapps
service and query classes to use when constructing requests.

9.1.1. Setting the domain for the service class


To set the domain for requests made by the service class, either call setDomain() or specify
the domain when instantiating the service class. For example:

$domain = "example.com";
$gdata = new Zend_Gdata_Gapps($client, $domain);

9.1.2. Setting the domain for query classes


Setting the domain for requests made by query classes is similar to setting it for the service class-
either call setDomain() or specify the domain when creating the query. For example:

$domain = "example.com";
$query = new Zend_Gdata_Gapps_UserQuery($domain, $arg);

When using a service class factory method to create a query, the service class will automatically
set the query's domain to match its own domain. As a result, it is not necessary to specify the
domain as part of the constructor arguments.

$domain = "example.com";
$gdata = new Zend_Gdata_Gapps($client, $domain);
$query = $gdata->newUserQuery($arg);

9.2. Interacting with users


Each user account on a Google Apps hosted domain is represented as an instance of
Zend_Gdata_Gapps_UserEntry. This class provides access to all account properties
including name, username, password, access rights, and current quota.

9.2.1. Creating a user account


User accounts can be created by calling the createUser() convenience method:

$gdata->createUser('foo', 'Random', 'User', '••••••••');

Users can also be created by instantiating UserEntry, providing a username, given name, family
name, and password, then calling insertUser() on a service object to upload the entry to
the server.

$user = $gdata->newUserEntry();
$user->login = $gdata->newLogin();
$user->login->username = 'foo';
$user->login->password = '••••••••';
$user->name = $gdata->newName();
$user->name->givenName = 'Random';
$user->name->familyName = 'User';
$user = $gdata->insertUser($user);

783
Zend_Gdata

The user's password should normally be provided as cleartext. Optionally, the password can be
provided as an SHA-1 digest if login->passwordHashFunction is set to 'SHA-1'.

9.2.2. Retrieving a user account


Individual user accounts can be retrieved by calling the retrieveUser() convenience method.
If the user is not found, NULL will be returned.

$user = $gdata->retrieveUser('foo');

echo 'Username: ' . $user->login->userName . "\n";


echo 'Given Name: ' . $user->name->givenName . "\n";
echo 'Family Name: ' . $user->name->familyName . "\n";
echo 'Suspended: ' . ($user->login->suspended ? 'Yes' : 'No') . "\n";
echo 'Admin: ' . ($user->login->admin ? 'Yes' : 'No') . "\n"
echo 'Must Change Password: ' .
($user->login->changePasswordAtNextLogin ? 'Yes' : 'No') . "\n";
echo 'Has Agreed To Terms: ' .
($user->login->agreedToTerms ? 'Yes' : 'No') . "\n";

Users can also be retrieved by creating an instance of Zend_Gdata_Gapps_UserQuery,


setting its username property to equal the username of the user that is to be retrieved, and calling
getUserEntry() on a service object with that query.

$query = $gdata->newUserQuery('foo');
$user = $gdata->getUserEntry($query);

echo 'Username: ' . $user->login->userName . "\n";


echo 'Given Name: ' . $user->login->givenName . "\n";
echo 'Family Name: ' . $user->login->familyName . "\n";
echo 'Suspended: ' . ($user->login->suspended ? 'Yes' : 'No') . "\n";
echo 'Admin: ' . ($user->login->admin ? 'Yes' : 'No') . "\n"
echo 'Must Change Password: ' .
($user->login->changePasswordAtNextLogin ? 'Yes' : 'No') . "\n";
echo 'Has Agreed To Terms: ' .
($user->login->agreedToTerms ? 'Yes' : 'No') . "\n";

If the specified user cannot be located a ServiceException will be thrown with an error
code of Zend_Gdata_Gapps_Error::ENTITY_DOES_NOT_EXIST. ServiceExceptions will be
covered in Section 9.6, « Handling errors ».

9.2.3. Retrieving all users in a domain


To retrieve all users in a domain, call the retrieveAllUsers() convenience method.

$feed = $gdata->retrieveAllUsers();

foreach ($feed as $user) {


echo " * " . $user->login->username . ' (' . $user->name->givenName .
' ' . $user->name->familyName . ")\n";
}

This will create a Zend_Gdata_Gapps_UserFeed object which holds each user on the domain.

Alternatively, call getUserFeed() with no options. Keep in mind that on larger domains this
feed may be paged by the server. For more information on paging, see Section 1.9, « Working
with Multi-page Feeds ».

784
Zend_Gdata

$feed = $gdata->getUserFeed();

foreach ($feed as $user) {


echo " * " . $user->login->username . ' (' . $user->name->givenName .
' ' . $user->name->familyName . ")\n";
}

9.2.4. Updating a user account


The easiest way to update a user account is to retrieve the user as described in the previous
sections, make any desired changes, then call save() on that user. Any changes made will be
propagated to the server.

$user = $gdata->retrieveUser('foo');
$user->name->givenName = 'Foo';
$user->name->familyName = 'Bar';
$user = $user->save();

9.2.4.1. Resetting a user's password

A user's password can be reset to a new value by updating the login->password property.

$user = $gdata->retrieveUser('foo');
$user->login->password = '••••••••';
$user = $user->save();

Note that it is not possible to recover a password in this manner as stored passwords are not
made available via the Provisioning API for security reasons.

9.2.4.2. Forcing a user to change their password

A user can be forced to change their password at their next login by setting the login-
>changePasswordAtNextLogin property to TRUE.

$user = $gdata->retrieveUser('foo');
$user->login->changePasswordAtNextLogin = true;
$user = $user->save();

Similarly, this can be undone by setting the login->changePasswordAtNextLogin property


to FALSE.

9.2.4.3. Suspending a user account

Users can be restricted from logging in without deleting their user account by instead suspending
their user account. Accounts can be suspended or restored by using the suspendUser() and
restoreUser() convenience methods:

$gdata->suspendUser('foo');
$gdata->restoreUser('foo');

Alternatively, you can set the UserEntry's login->suspended property to TRUE.

$user = $gdata->retrieveUser('foo');
$user->login->suspended = true;
$user = $user->save();

785
Zend_Gdata

To restore the user's access, set the login->suspended property to FALSE.

9.2.4.4. Granting administrative rights

Users can be granted the ability to administer your domain by setting their login->admin
property to TRUE.

$user = $gdata->retrieveUser('foo');
$user->login->admin = true;
$user = $user->save();

And as expected, setting a user's login->admin property to FALSE revokes their administrative
rights.

9.2.5. Deleting user accounts


Deleting a user account to which you already hold a UserEntry is a simple as calling delete()
on that entry.

$user = $gdata->retrieveUser('foo');
$user->delete();

If you do not have access to a UserEntry object for an account, use the deleteUser()
convenience method.

$gdata->deleteUser('foo');

9.3. Interacting with nicknames


Nicknames serve as email aliases for existing users. Each nickname contains precisely two key
properties: its name and its owner. Any email addressed to a nickname is forwarded to the user
who owns that nickname.

Nicknames are represented as an instances of Zend_Gdata_Gapps_NicknameEntry.

9.3.1. Creating a nickname


Nicknames can be created by calling the createNickname() convenience method:

$gdata->createNickname('foo', 'bar');

Nicknames can also be created by instantiating NicknameEntry, providing the nickname with a
name and an owner, then calling insertNickname() on a service object to upload the entry
to the server.

$nickname = $gdata->newNicknameEntry();
$nickname->login = $gdata->newLogin('foo');
$nickname->nickname = $gdata->newNickname('bar');
$nickname = $gdata->insertNickname($nickname);

9.3.2. Retrieving a nickname


Nicknames can be retrieved by calling the retrieveNickname() convenience method. This
will return NULL if a user is not found.

786
Zend_Gdata

$nickname = $gdata->retrieveNickname('bar');

echo 'Nickname: ' . $nickname->nickname->name . "\n";


echo 'Owner: ' . $nickname->login->username . "\n";

Individual nicknames can also be retrieved by creating an instance of


Zend_Gdata_Gapps_NicknameQuery, setting its nickname property to equal the nickname
that is to be retrieved, and calling getNicknameEntry() on a service object with that query.

$query = $gdata->newNicknameQuery('bar');
$nickname = $gdata->getNicknameEntry($query);

echo 'Nickname: ' . $nickname->nickname->name . "\n";


echo 'Owner: ' . $nickname->login->username . "\n";

As with users, if no corresponding nickname is found a ServiceException will be thrown with an


error code of Zend_Gdata_Gapps_Error::ENTITY_DOES_NOT_EXIST. Again, these will be
discussed in Section 9.6, « Handling errors ».

9.3.3. Retrieving all nicknames for a user


To retrieve all nicknames associated with a given user, call the convenience method
retrieveNicknames().

$feed = $gdata->retrieveNicknames('foo');

foreach ($feed as $nickname) {


echo ' * ' . $nickname->nickname->name . "\n";
}

This will create a Zend_Gdata_Gapps_NicknameFeed object which holds each nickname


associated with the specified user.

Alternatively, create a new Zend_Gdata_Gapps_NicknameQuery, set its username property


to the desired user, and submit the query by calling getNicknameFeed() on a service object.

$query = $gdata->newNicknameQuery();
$query->setUsername('foo');
$feed = $gdata->getNicknameFeed($query);

foreach ($feed as $nickname) {


echo ' * ' . $nickname->nickname->name . "\n";
}

9.3.4. Retrieving all nicknames in a domain


To retrieve all nicknames in a feed, simply call the convenience method
retrieveAllNicknames()

$feed = $gdata->retrieveAllNicknames();

foreach ($feed as $nickname) {


echo ' * ' . $nickname->nickname->name . ' => ' .
$nickname->login->username . "\n";
}

787
Zend_Gdata

This will create a Zend_Gdata_Gapps_NicknameFeed object which holds each nickname on


the domain.

Alternatively, call getNicknameFeed() on a service object with no arguments.

$feed = $gdata->getNicknameFeed();

foreach ($feed as $nickname) {


echo ' * ' . $nickname->nickname->name . ' => ' .
$nickname->login->username . "\n";
}

9.3.5. Deleting a nickname


Deleting a nickname to which you already hold a NicknameEntry for is a simple as calling
delete() on that entry.

$nickname = $gdata->retrieveNickname('bar');
$nickname->delete();

For nicknames which you do not hold a NicknameEntry for, use the deleteNickname()
convenience method.

$gdata->deleteNickname('bar');

9.4. Interacting with email lists


Email lists allow several users to retrieve email addressed to a single email address. Users do
not need to be a member of this domain in order to subscribe to an email list provided their
complete email address (including domain) is used.

Each email list on a domain is represented as an instance of


Zend_Gdata_Gapps_EmailListEntry.

9.4.1. Creating an email list


Email lists can be created by calling the createEmailList() convenience method:

$gdata->createEmailList('friends');

Email lists can also be created by instantiating EmailListEntry, providing a name for the list, then
calling insertEmailList() on a service object to upload the entry to the server.

$list = $gdata->newEmailListEntry();
$list->emailList = $gdata->newEmailList('friends');
$list = $gdata->insertEmailList($list);

9.4.2. Retrieving all email lists to which a recipient is subscribed


To retrieve all email lists to which a particular recipient is subscribed, call the
retrieveEmailLists() convenience method:

$feed = $gdata->retrieveEmailLists('baz@somewhere.com');

foreach ($feed as $list) {

788
Zend_Gdata

echo ' * ' . $list->emailList->name . "\n";


}

This will create a Zend_Gdata_Gapps_EmailListFeed object which holds each email list
associated with the specified recipient.

Alternatively, create a new Zend_Gdata_Gapps_EmailListQuery, set its recipient property


to the desired email address, and submit the query by calling getEmailListFeed() on a
service object.

$query = $gdata->newEmailListQuery();
$query->setRecipient('baz@somewhere.com');
$feed = $gdata->getEmailListFeed($query);

foreach ($feed as $list) {


echo ' * ' . $list->emailList->name . "\n";
}

9.4.3. Retrieving all email lists in a domain


To retrieve all email lists in a domain, call the convenience method
retrieveAllEmailLists().

$feed = $gdata->retrieveAllEmailLists();

foreach ($feed as $list) {


echo ' * ' . $list->emailList->name . "\n";
}

This will create a Zend_Gdata_Gapps_EmailListFeed object which holds each email list on
the domain.

Alternatively, call getEmailListFeed() on a service object with no arguments.

$feed = $gdata->getEmailListFeed();

foreach ($feed as $list) {


echo ' * ' . $list->emailList->name . "\n";
}

9.4.4. Deleting an email list


To delete an email list, call the deleteEmailList() convenience method:

$gdata->deleteEmailList('friends');

9.5. Interacting with email list recipients


Each recipient subscribed to an email list is represented by an instance of
Zend_Gdata_Gapps_EmailListRecipient. Through this class, individual recipients can be
added and removed from email lists.

9.5.1. Adding a recipient to an email list


To add a recipient to an email list, simply call the addRecipientToEmailList() convenience
method:

789
Zend_Gdata

$gdata->addRecipientToEmailList('bar@somewhere.com', 'friends');

9.5.2. Retrieving the list of subscribers to an email list


The convenience method retrieveAllRecipients() can be used to retrieve the list of
subscribers to an email list:

$feed = $gdata->retrieveAllRecipients('friends');

foreach ($feed as $recipient) {


echo ' * ' . $recipient->who->email . "\n";
}

Alternatively, construct a new EmailListRecipientQuery, set its emailListName property to match


the desired email list, and call getEmailListRecipientFeed() on a service object.

$query = $gdata->newEmailListRecipientQuery();
$query->setEmailListName('friends');
$feed = $gdata->getEmailListRecipientFeed($query);

foreach ($feed as $recipient) {


echo ' * ' . $recipient->who->email . "\n";
}

This will create a Zend_Gdata_Gapps_EmailListRecipientFeed object which holds each


recipient for the selected email list.

9.5.3. Removing a recipient from an email list


To remove a recipient from an email list, call the removeRecipientFromEmailList()
convenience method:

$gdata->removeRecipientFromEmailList('baz@somewhere.com', 'friends');

9.6. Handling errors


In addition to the standard suite of exceptions thrown by Zend_Gdata, requests using
the Provisioning API may also throw a Zend_Gdata_Gapps_ServiceException. These
exceptions indicate that a API specific error occurred which prevents the request from
completing.

Each ServiceException instance may hold one or more Error objects. Each of these objects
contains an error code, reason, and (optionally) the input which triggered the exception. A
complete list of known error codes is provided in the Zend Framework API documentation
under Zend_Gdata_Gapps_Error. Additionally, the authoritative error list is available online
at Google Apps Provisioning API V2.0 Reference: Appendix D.

While the complete list of errors received is available within ServiceException as an array by
calling getErrors(), often it is convenient to know if one specific error occurred. For these
cases the presence of an error can be determined by calling hasError().

The following example demonstrates how to detect if a requested resource doesn't exist and
handle the fault gracefully:

function retrieveUser ($username) {

790
Zend_Gdata

$query = $gdata->newUserQuery($username);
try {
$user = $gdata->getUserEntry($query);
} catch (Zend_Gdata_Gapps_ServiceException $e) {
// Set the user to null if not found
if ($e->hasError(Zend_Gdata_Gapps_Error::ENTITY_DOES_NOT_EXIST)) {
$user = null;
} else {
throw $e;
}
}
return $user;
}

10. Using Google Base


The Google Base data API is designed to enable developers to do two things:

• Query Google Base data to create applications and mashups.

• Input and manage Google Base items programmatically.

There are two item feeds: snippets feed and customer items feeds. The snippets feed contains all
Google Base data and is available to anyone to query against without a need for authentication.
The customer items feed is a customer-specific subset of data and only a customer/owner can
access this feed to insert, update, or delete their own data. Queries are constructed the same
way against both types of feeds.

See http://code.google.com/apis/base for more information about the Google Base API.

10.1. Connect To The Base Service


The Google Base API, like all GData APIs, is based off of the Atom Publishing Protocol (APP),
an XML based format for managing web-based resources. Traffic between a client and the
Google Base servers occurs over HTTP and allows for both authenticated and unauthenticated
connections.

Before any transactions can occur, this connection needs to be made. Creating a connection to
the base servers involves two steps: creating an HTTP client and binding a Zend_Gdata_Gbase
service instance to that client.

10.1.1. Authentication
The Google Base API allows access to both public and private base feeds. Public feeds do not
require authentication, but are read-only and offer reduced functionality. Private feeds offers the
most complete functionality but requires an authenticated connection to the base servers. There
are three authentication schemes that are supported by Google Base:

• ClientAuth provides direct username/password authentication to the base servers. Since this
scheme requires that users provide your application with their password, this authentication is
only recommended when other authentication schemes are insufficient.

• AuthSub allows authentication to the base servers via a Google proxy server. This provides
the same level of convenience as ClientAuth but without the security risk, making this an ideal
choice for web-based applications.

791
Zend_Gdata

The Zend_Gdata library provides support for all three authentication schemes. The rest of this
chapter will assume that you are familiar the authentication schemes available and how to create
an appropriate authenticated connection. For more information, please see section Section 1.4,
« Google Data Client Authentication ». or the Authentication Overview in the Google Data API
Developer's Guide.

10.1.2. Create A Service Instance


In order to interact with Google Base, this library provides the Zend_Gdata_Gbase service
class. This class provides a common interface to the Google Data and Atom Publishing Protocol
models and assists in marshaling requests to and from the base servers.

Once deciding on an authentication scheme, the next step is to create an instance of


Zend_Gdata_Gbase . This class takes in an instance of Zend_Http_Client as a single
argument. This provides an interface for AuthSub and ClientAuth authentication, as both of these
creation of a special authenticated HTTP client. If no arguments are provided, an unauthenticated
instance of Zend_Http_Client will be automatically created.

The example below shows how to create a Base service class using ClientAuth authentication:

// Parameters for ClientAuth authentication


$service = Zend_Gdata_Gbase::AUTH_SERVICE_NAME;
$user = "sample.user@gmail.com";
$pass = "pa$$w0rd";

// Create an authenticated HTTP client


$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);

// Create an instance of the Base service


$service = new Zend_Gdata_Gbase($client);

A Base service using AuthSub can be created in a similar, though slightly more lengthy fashion:

/*
* Retrieve the current URL so that the AuthSub server knows where to
* redirect the user after authentication is complete.
*/
function getCurrentUrl()
{
global $_SERVER;

// Filter php_self to avoid a security vulnerability.


$php_request_uri =
htmlentities(substr($_SERVER['REQUEST_URI'],
0,
strcspn($_SERVER['REQUEST_URI'], "\n\r")),
ENT_QUOTES);

if (isset($_SERVER['HTTPS']) &&
strtolower($_SERVER['HTTPS']) == 'on') {
$protocol = 'https://';
} else {
$protocol = 'http://';
}
$host = $_SERVER['HTTP_HOST'];
if ($_SERVER['HTTP_PORT'] != '' &&
(($protocol == 'http://' && $_SERVER['HTTP_PORT'] != '80') ||

792
Zend_Gdata

($protocol == 'https://' && $_SERVER['HTTP_PORT'] != '443'))) {


$port = ':' . $_SERVER['HTTP_PORT'];
} else {
$port = '';
}
return $protocol . $host . $port . $php_request_uri;
}

/**
* Obtain an AuthSub authenticated HTTP client, redirecting the user
* to the AuthSub server to login if necessary.
*/
function getAuthSubHttpClient()
{
global $_SESSION, $_GET;

// If there is no AuthSub session or one-time token waiting for us,


// redirect the user to the AuthSub server to get one.
if (!isset($_SESSION['sessionToken']) && !isset($_GET['token'])) {
// Parameters to give to AuthSub server
$next = getCurrentUrl();
$scope = "http://www.google.com/base/feeds/items/";
$secure = false;
$session = true;

// Redirect the user to the AuthSub server to sign in

$authSubUrl = Zend_Gdata_AuthSub::getAuthSubTokenUri($next,
$scope,
$secure,
$session);
header("HTTP/1.0 307 Temporary redirect");

header("Location: " . $authSubUrl);

exit();
}

// Convert an AuthSub one-time token into a session token if needed


if (!isset($_SESSION['sessionToken']) && isset($_GET['token'])) {
$_SESSION['sessionToken'] =
Zend_Gdata_AuthSub::getAuthSubSessionToken($_GET['token']);
}

// At this point we are authenticated via AuthSub and can obtain an


// authenticated HTTP client instance

// Create an authenticated HTTP client


$client = Zend_Gdata_AuthSub::getHttpClient($_SESSION['sessionToken']);
return $client;
}

// -> Script execution begins here <-

// Make sure http://code.google.com/apis/gdata/reference.html#Queriesthat


// the user has a valid session, so we can record the
// AuthSub session token once it is available.
session_start();

// Create an instance of the Base service, redirecting the user

793
Zend_Gdata

// to the AuthSub server if necessary.


$service = new Zend_Gdata_Gbase(getAuthSubHttpClient());

Finally, an unauthenticated server can be created for use with snippets feeds:

// Create an instance of the Base service using an unauthenticated HTTP client


$service = new Zend_Gdata_Gbase();

10.2. Retrieve Items


You can query customer items feed or snippets feed to retrieve items. It involves two steps,
sending a query and iterating through the returned feed.

10.2.1. Send a Structured Query

You can send a structured query to retrieve items from your own customer items feed or from
the public snippets feed.

When retrieving items using the Base API, specially constructed query URLs are used
to describe what events should be returned. The Zend_Gdata_Gbase_ItemQuery and
Zend_Gdata_Gbase_SnippetQuery classes simplify this task by automatically constructing
a query URL based on provided parameters.

10.2.1.1. Query Customer Items Feed

To execute a query against the customer items feed, invoke newItemQuery() and
getGbaseItemFeed() methods:

$service = new Zend_Gdata_Gbase($client);


$query = $service->newItemQuery();
$query->setBq('[title:Programming]');
$query->setOrderBy('modification_time');
$query->setSortOrder('descending');
$query->setMaxResults('5');
$feed = $service->getGbaseItemFeed($query);

A full list of these parameters is available at the Query parameters section of the Customer Items
Feed documentation.

10.2.1.2. Query Snippets Feed

To execute a query against the public snippets feed, invoke newSnippetQuery() and
getGbaseSnippetFeed() methods:

$service = new Zend_Gdata_Gbase();


$query = $service->newSnippetQuery();
$query->setBq('[title:Programming]');
$query->setOrderBy('modification_time');
$query->setSortOrder('descending');
$query->setMaxResults('5');
$feed = $service->getGbaseSnippetFeed($query);

A full list of these parameters is available at the Query parameters section of the Snippets Feed
documentation.

794
Zend_Gdata

10.2.2. Iterate through the Items


Google Base items can contain item-specific attributes such as <g:main_ingredient> and
<g:weight>.

To iterate through all attributes of a given item, invoke getGbaseAttributes() and iterate
through the results:

foreach ($feed->entries as $entry) {


// Get all attributes and print out the name and text value of each
// attribute
$baseAttributes = $entry->getGbaseAttributes();
foreach ($baseAttributes as $attr) {
echo "Attribute " . $attr->name . " : " . $attr->text . "<br>";
}
}

Or, you can look for specific attribute name and iterate through the results that match:

foreach ($feed->entries as $entry) {


// Print all main ingredients <g:main_ingredient>
$baseAttributes = $entry->getGbaseAttribute("main_ingredient");
foreach ($baseAttributes as $attr) {
echo "Main ingredient: " . $attr->text . "<br>";
}
}

10.3. Insert, Update, and Delete Customer Items


A customer/owner can access his own Customer Items feed to insert, update, or delete their
items. These operations do not apply to the public snippets feed.

You can test a feed operation before it is actually executed by setting the dry-run flag ($dryRun)
to TRUE. Once you are sure that you want to submit the data, set it to FALSE to execute the
operation.

10.3.1. Insert an Item


Items can be added by using the insertGbaseItem() method for the Base service:

$service = new Zend_Gdata_Gbase($client);


$newEntry = $service->newItemEntry();

// Add title
$title = "PHP Developer Handbook";
$newEntry->title = $service->newTitle(trim($title));

// Add some content


$content = "Essential handbook for PHP developers.";
$newEntry->content = $service->newContent($content);
$newEntry->content->type = 'text';

// Define product type


$itemType = "Products";
$newEntry->itemType = $itemType;

// Add item specific attributes

795
Zend_Gdata

$newEntry->addGbaseAttribute("product_type", "book", "text");


$newEntry->addGbaseAttribute("price", "12.99 USD", "floatUnit");
$newEntry->addGbaseAttribute("quantity", "10", "int");
$newEntry->addGbaseAttribute("weight", "2.2 lbs", "numberUnit");
$newEntry->addGbaseAttribute("condition", "New", "text");
$newEntry->addGbaseAttribute("author", "John Doe", "text");
$newEntry->addGbaseAttribute("edition", "First Edition", "text");
$newEntry->addGbaseAttribute("pages", "253", "number");
$newEntry->addGbaseAttribute("publisher", "My Press", "text");
$newEntry->addGbaseAttribute("year", "2007", "number");
$newEntry->addGbaseAttribute("payment_accepted", "Google Checkout", "text");

$dryRun = true;
$createdEntry = $service->insertGbaseItem($newEntry, $dryRun);

10.3.2. Modify an Item


You can update each attribute element of an item as you iterate through them:

// Update the title


$newTitle = "PHP Developer Handbook Second Edition";
$entry->title = $service->newTitle($newTitle);

// Find <g:price> attribute and update the price


$baseAttributes = $entry->getGbaseAttribute("price");
if (is_object($baseAttributes[0])) {
$newPrice = "16.99 USD";
$baseAttributes[0]->text = $newPrice;
}

// Find <g:pages> attribute and update the number of pages


$baseAttributes = $entry->getGbaseAttribute("pages");
if (is_object($baseAttributes[0])) {
$newPages = "278";
$baseAttributes[0]->text = $newPages;

// Update the attribute type from "number" to "int"


if ($baseAttributes[0]->type == "number") {
$newType = "int";
$baseAttributes[0]->type = $newType;
}
}

// Remove <g:label> attributes


$baseAttributes = $entry->getGbaseAttribute("label");
foreach ($baseAttributes as $note) {
$entry->removeGbaseAttribute($note);
}

// Add new attributes


$entry->addGbaseAttribute("note", "PHP 5", "text");
$entry->addGbaseAttribute("note", "Web Programming", "text");

// Save the changes by invoking save() on the entry object itself


$dryRun = true;
$entry->save($dryRun);

// Or, save the changes by calling updateGbaseItem() on the service object


// $dryRun = true;

796
Zend_Gdata

// $service->updateGbaseItem($entry, $dryRun);

After making the changes, either invoke save($dryRun) method on the


Zend_Gdata_Gbase_ItemEntry object or call updateGbaseItem($entry, $dryRun)
method on the Zend_Gdata_Gbase object to save the changes.

10.3.3. Delete an Item


You can remove an item by calling deleteGbaseItem() method:

$dryRun = false;
$service->deleteGbaseItem($entry, $dryRun);

Alternatively, you can invoke delete() on the Zend_Gdata_Gbase_ItemEntry object:

$dryRun = false;
$entry->delete($dryRun);

11. Utilisation des albums Web Picasa


Les albums Web Picasa représentent un service Google permettant de maintenir à jour des
albums photos, tout en pouvant récupérer des photos de l'album d'un membre. L'API propose
des services pour ajouter, mettre à jour ou supprimer des photos d'un album, de même que gérer
des mots-clés ou des commentaires sur des images(photos).

L'accès public à un album, en lecture donc, n'est pas sujet à demande d'authentification. En
revanche, toute autre manipulation telle que la mise à jour ou la suppression, nécessitera que
vous vous authentifiez.

Pour plus d'informations sur l'API, voyez l'API Picasa Web Albums.

Authentification
L'API propose les deux modes d'authentification, AuthSub (recommandé) et
ClientAuth. Pour toute opération d'écriture vers le service, une authentification
sera demandée, la lecture est elle, libre, au regard de l'API.

11.1. Se connecter au service


L'API Picasa, comme tous les autres services Web Google Gdata, est basée sur le protocole
Atom Publishing Protocol (APP), et le XML. Le trafic entre le client et le serveur se fait sur HTTP,
et autorise des connexions authentifiées, ou non.

Avant tout, il faut donc se connecter. Ceci se fait en deux étapes : créer un client HTTP, et insérer
un Zend_Gdata_Photos dans celui-ci.

11.1.1. Authentification
L'API propose un accès à la fois aux données publiques, et aux données privées. Les données
publiques ne requièrent pas d'authentification, mais ne sont accessibles qu'en lecture seule.
L'écriture et l'accès aux données privées requièrent une authentification, qui peut s'effectuer de
trois manières différentes :

• ClientAuth permet une authentification directe en donnant un couple login/password. Les


utilisateurs devront donc renseigner ces 2 paramètres sur votre site directement.

797
Zend_Gdata

• AuthSub permet l'authentification en passant par un serveur proxy de Google. Les risques liés
à la sécurité sont donc moindre avec cette méthode.

La librairie Zend_Gdata permet ces 2 types d'authentification. Le reste de ce chapitre supposera


que vous soyez habitué à l'authentification avec les service Web Google GData. Si ce n'est pas
le cas, nous vous conseillons de consulter la section authentification de ce manuel, ou encore
le guide d'authentification Google GData webservices API.

11.1.2. Créer une instance du service


Pour interagir avec les serveurs, la classe Zend_Gdata_Photos sera nécessaire. Elle abstrait
toute la logique de communication avec le Protocol Atom Publishing vers les serveurs de Google.

Une fois que vous avez choisi une méthode d'authentification, vous devez créer une
instance de Zend_Gdata_Photos. Le constructeur prend en paramètre une instance de
Zend_Http_Client. Cette classe est l'interface AuthSub ou ClientAuth authentification. Si
vous ne passez pas cette instance en argument, alors une instance de Zend_Http_Client
sera crée automatiquement, mais en mode non authentifié.

Voici un exemple qui démontre comment créer une classe vers le service avec le procédé
d'authentification ClientAuth :

// Paramètres pour ClientAuth authentification


$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$user = "sample.user@gmail.com";
$pass = "pa$$w0rd";

// Création d'une client HTTP authentifié


$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);

// Création de l'instance du service


$service = new Zend_Gdata_Photos($client);

Au sujet du procédé AuthSub, voici la démarche :

session_start();

/**
* Retourne l'URL complet de la page actuelle,
* en fonction des variables d'environnement
*
* Env variables utilisées:
* $_SERVER['HTTPS'] = (on|off|)
* $_SERVER['HTTP_HOST'] = value of the Host: header
* $_SERVER['SERVER_PORT'] = port number (only used if not http/80,https/443)
* $_SERVER['REQUEST_URI'] = the URI after the method of the HTTP request
*
* @return string Current URL
*/
function getCurrentUrl()
{
global $_SERVER;

/**
* Filtre php_self pour éviter des problèmes de sécurité
*/
$php_request_uri = htmlentities(substr($_SERVER['REQUEST_URI'], 0,
strcspn($_SERVER['REQUEST_URI'], "\n\r")), ENT_QUOTES);

798
Zend_Gdata

if (isset($_SERVER['HTTPS'])
&& strtolower($_SERVER['HTTPS']) == 'on') {
$protocol = 'https://';
} else {
$protocol = 'http://';
}
$host = $_SERVER['HTTP_HOST'];
if ($_SERVER['SERVER_PORT'] != '' &&
(($protocol == 'http://' && $_SERVER['SERVER_PORT'] != '80') ||
($protocol == 'https://' && $_SERVER['SERVER_PORT'] != '443'))) {
$port = ':' . $_SERVER['SERVER_PORT'];
} else {
$port = '';
}
return $protocol . $host . $port . $php_request_uri;
}

/**
* Retourne l'URL AuthSub que l'utilisateur doit visiter
* pour authentifier ses requêtes
*
* Utilise getCurrentUrl() pour récupérer le prochain URL
* vers lequel l'utilisateur sera redirigé après
* s'être authentifié.
*
* @return string AuthSub URL
*/
function getAuthSubUrl()
{
$next = getCurrentUrl();
$scope = 'http://picasaweb.google.com/data';
$secure = false;
$session = true;
return Zend_Gdata_AuthSub::getAuthSubTokenUri($next,
$scope,
$secure,
$session);
}

/**
* Retourne un objet servant de client HTTP avec les bons en-têtes,
* permettant de communiquer avec les services Google, et utilisant
* l'authentification AuthSub.
*
* Utilise $_SESSION['sessionToken'] pour stocker le jeton de session
* AuthSub après l'avoir obtenu. $_GET['token'] récupère ce jeton
* après la redirection d'authentification
*
* @return Zend_Http_Client
*/
function getAuthSubHttpClient()
{
global $_SESSION, $_GET;
if (!isset($_SESSION['sessionToken']) && isset($_GET['token'])) {
$_SESSION['sessionToken'] =
Zend_Gdata_AuthSub::getAuthSubSessionToken($_GET['token']);
}
$client =
Zend_Gdata_AuthSub::getHttpClient($_SESSION['sessionToken']);

799
Zend_Gdata

return $client;
}

/**
* Créer une instance du service, redirigeant l'utilisateur
* vers le serveur AuthSub si nécéssaire.
*/
$service = new Zend_Gdata_Photos(getAuthSubHttpClient());

Enfin, un client non authentifié peut aussi être crée :

// Création d'une instance du service en mode non authentifié


$service = new Zend_Gdata_Photos();

11.2. Comprendre et construire des requêtes


Pour créer des requêtes vers le service Web, vous devrez utiliser une de ces classes :

• User Cette classe requêtera tout ce qui concerne un utilisateur du service. Sans spécifier
d'utilisateur, "default" sera utilisé.

• Album Cette classe va servir de base pour toutes les requêtes concernant les albums Picasa.

• Photo Cette classe va servir de base pour toutes les requêtes concernant les photos Picasa.

Une UserQuery peut être construite comme suit :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

$query = new Zend_Gdata_Photos_UserQuery();


$query->setUser("sample.user");

Pour chaque requête, des paramètres de limitations de la recherche peuvent être passés grâce
aux méthodes get(Paramètre) and set(Paramètre) :

• Projection spécifie le format de retour des données dans le flux. Peut être "api" ou "base". En
temps normal, "api" est conseillé, c'est la valeur par défaut d'ailleurs.

• Type détermine le type des éléments retournés, "feed"(défaut) ou "entry".

• Access détermine la visibilité des éléments retournés, "all"(défaut), "public", ou "private". Les
éléments non publics ne seront retournés que si le client est authentifié.

• Tag fournit un filtre par mots-clés sur les éléments retournés.

• Kind détermine un filtre sur la sorte (le type) d'éléments retournés.

• ImgMax spécifie un filtre par dimension maximale sur les éléments retournés.

• Thumbsize spécifie un filtre par dimension maximale des miniatures retournées.

• User spécifie l'utilisateur dont les éléments sont recherchés. Par défaut, "default".

• AlbumId spécifie l'identifiant de l'album recherché. Ceci ne s'applique qu'aux requêtes album
et photo. Dans le cas d'une recherche de photo, ceci indique l'album dans lequel effectuer la
requête de recherche. Ce paramètre annule et remplace AlbumName, si spécifié.

800
Zend_Gdata

• AlbumName spécifie le nom de l'album recherché. Ceci ne s'applique qu'aux requêtes album
et photo. Dans le cas d'une recherche de photo, ceci indique l'album dans lequel effectuer la
requête de recherche. Ce paramètre annule et remplace AlbumId, si spécifié.

• PhotoId spécifie l'identifiant de la photo recherchée. Ceci ne s'applique qu'aux requêtes photo.

11.3. Récupérer des flux et des éléments


Le service propose des méthodes de récupération de flux, ou d'éléments simples, concernant
les utilisateurs, albums, ou photos.

11.3.1. Récupérer un utilisateur


Le service propose de récupérer un utilisateur, et toutes les infos de son flux, comme ses photos,
ses albums.... Si le client est authentifié et demande des informations sur son propre compte,
alors les éléments marqués comme "hidden" seront aussi retournés.

Le flux de l'utilisateur est accessible en passant son nom à la méthode getUserFeed :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

try {
$userFeed = $service->getUserFeed("sample.user");
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}

Ou alors, le flux peut être requêté directement :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

$query = new Zend_Gdata_Photos_UserQuery();


$query->setUser("sample.user");

try {
$userFeed = $service->getUserFeed(null, $query);
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}

Construire une requête donne aussi accès aux éléments d'un utilisateur :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

$query = new Zend_Gdata_Photos_UserQuery();


$query->setUser("sample.user");
$query->setType("entry");

try {
$userEntry = $service->getUserEntry($query);

801
Zend_Gdata

} catch (Zend_Gdata_App_Exception $e) {


echo "Error: " . $e->getMessage();
}

11.3.2. Récupérer un album


Le service donne accès aux flux d'albums et à leurs contenus.

Le flux d'albums est disponible en construisant un objet de requête et en le passant à


getAlbumFeed :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

$query = new Zend_Gdata_Photos_AlbumQuery();


$query->setUser("sample.user");
$query->setAlbumId("1");

try {
$albumFeed = $service->getAlbumFeed($query);
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}

L'objet de requête accepte aussi un nom d'album avec setAlbumName. Attention, ceci annule
un identifiant d'album éventuellement précédemment spécifié.

Construire une requête donne aussi accès au requêtage d'un album :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

$query = new Zend_Gdata_Photos_AlbumQuery();


$query->setUser("sample.user");
$query->setAlbumId("1");
$query->setType("entry");

try {
$albumEntry = $service->getAlbumEntry($query);
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}

11.3.3. Récupérer une Photo


Le service permet la récupération de flux de photos, et des commentaires et/ou mots-clés
associés

Le flux de photos est accessible en construisant un objet de requête et en le passant à la méthode


getPhotoFeed :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

802
Zend_Gdata

$query = new Zend_Gdata_Photos_PhotoQuery();


$query->setUser("sample.user");
$query->setAlbumId("1");
$query->setPhotoId("100");

try {
$photoFeed = $service->getPhotoFeed($query);
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}

Construire une requête donne aussi accès au requêtage d'une photo :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

$query = new Zend_Gdata_Photos_PhotoQuery();


$query->setUser("sample.user");
$query->setAlbumId("1");
$query->setPhotoId("100");
$query->setType("entry");

try {
$photoEntry = $service->getPhotoEntry($query);
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}

11.3.4. Récupérer des commentaires


Vous pouvez récupérer des commentaires depuis des éléments divers de flux. En spécifiant
à votre requête un paramètre de "comment", celle-ci retournera les mots-clés associés à la
ressource demandée (user, album ou photo)

Voici comment effectuer des actions sur les commentaires récupérés d'une photo :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

$query = new Zend_Gdata_Photos_PhotoQuery();


$query->setUser("sample.user");
$query->setAlbumId("1");
$query->setPhotoId("100");
$query->setKind("comment");

try {
$photoFeed = $service->getPhotoFeed($query);

foreach ($photoFeed as $entry) {


if ($entry instanceof Zend_Gdata_Photos_CommentEntry) {
// Faites quelque chose avec le commentaire
}
}
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}

803
Zend_Gdata

11.3.5. Récupérer des mots-clés


Vous pouvez récupérer des mots-clés depuis des éléments divers de flux. En spécifiant à
votre requête un paramètre de "tag", celle-ci retournera les mots-clés associés à la ressource
demandée.

Voici comment effectuer des actions sur les mots-clés récupérés d'une photo :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

$query = new Zend_Gdata_Photos_PhotoQuery();


$query->setUser("sample.user");
$query->setAlbumId("1");
$query->setPhotoId("100");
$query->setKind("tag");

try {
$photoFeed = $service->getPhotoFeed($query);

foreach ($photoFeed as $entry) {


if ($entry instanceof Zend_Gdata_Photos_TagEntry) {
// Faites quelque chose avec le mot-clé
}
}
} catch (Zend_Gdata_App_Exception $e) {
echo "Error: " . $e->getMessage();
}

11.4. Créer des ressources


Des opérations de création sont possible, qu'il s'agisse d'albums, photos, commentaires, ou
mots-clés.

11.4.1. Créer un album


Il est possible de créer un album, pour les clients authentifiés :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

$entry = new Zend_Gdata_Photos_AlbumEntry();


$entry->setTitle($service->newTitle("test album"));

$service->insertAlbumEntry($entry);

11.4.2. Créer une photo


Créer une photo est possible pour les clients authentifiés, procédez comme suit :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

// $photo est le nom d'un fichier issu d'un formulaire d'uplaod

804
Zend_Gdata

$fd = $service->newMediaFileSource($photo["tmp_name"]);
$fd->setContentType($photo["type"]);

$entry = new Zend_Gdata_Photos_PhotoEntry();


$entry->setMediaSource($fd);
$entry->setTitle($service->newTitle($photo["name"]));

$albumQuery = new Zend_Gdata_Photos_AlbumQuery;


$albumQuery->setUser("sample.user");
$albumQuery->setAlbumId("1");

$albumEntry = $service->getAlbumEntry($albumQuery);

$service->insertPhotoEntry($entry, $albumEntry);

11.4.3. Créer un commentaire pour une photo


Il est possible de créer un commentaire pour une photo, voici un exemple :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

$entry = new Zend_Gdata_Photos_CommentEntry();


$entry->setTitle($service->newTitle("comment"));
$entry->setContent($service->newContent("comment"));

$photoQuery = new Zend_Gdata_Photos_PhotoQuery;


$photoQuery->setUser("sample.user");
$photoQuery->setAlbumId("1");
$photoQuery->setPhotoId("100");
$photoQuery->setType('entry');

$photoEntry = $service->getPhotoEntry($photoQuery);

$service->insertCommentEntry($entry, $photoEntry);

11.4.4. Créer un mot-clé pour une photo


Il est possible de créer un mot-clé pour une photo, voici un exemple :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

$entry = new Zend_Gdata_Photos_TagEntry();


$entry->setTitle($service->newTitle("tag"));

$photoQuery = new Zend_Gdata_Photos_PhotoQuery;


$photoQuery->setUser("sample.user");
$photoQuery->setAlbumId("1");
$photoQuery->setPhotoId("100");
$photoQuery->setType('entry');

$photoEntry = $service->getPhotoEntry($photoQuery);

$service->insertTagEntry($entry, $photoEntry);

805
Zend_Gdata

11.5. Supprimer des éléments


Il est possible de supprimer albums, photos, commentaires, et mots-clés.

11.5.1. Supprimer un album


Supprimer un album est possible si le client est authentifié :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

$albumQuery = new Zend_Gdata_Photos_AlbumQuery;


$albumQuery->setUser("sample.user");
$albumQuery->setAlbumId("1");
$albumQuery->setType('entry');

$entry = $service->getAlbumEntry($albumQuery);

$service->deleteAlbumEntry($entry, true);

11.5.2. Supprimer une photo


Supprimer une photo est possible si le client est authentifié :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

$photoQuery = new Zend_Gdata_Photos_PhotoQuery;


$photoQuery->setUser("sample.user");
$photoQuery->setAlbumId("1");
$photoQuery->setPhotoId("100");
$photoQuery->setType('entry');

$entry = $service->getPhotoEntry($photoQuery);

$service->deletePhotoEntry($entry, true);

11.5.3. Supprimer un commentaire


Supprimer un commentaire est possible si le client est authentifié :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

$photoQuery = new Zend_Gdata_Photos_PhotoQuery;


$photoQuery->setUser("sample.user");
$photoQuery->setAlbumId("1");
$photoQuery->setPhotoId("100");
$photoQuery->setType('entry');

$path = $photoQuery->getQueryUrl() . '/commentid/' . "1000";

$entry = $service->getCommentEntry($path);

$service->deleteCommentEntry($entry, true);

806
Zend_Gdata

11.5.4. Supprimer un mot-clé


Supprimer un mot-clé est possible, si le client est authentifié :

$service = Zend_Gdata_Photos::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Photos($client);

$photoQuery = new Zend_Gdata_Photos_PhotoQuery;


$photoQuery->setUser("sample.user");
$photoQuery->setAlbumId("1");
$photoQuery->setPhotoId("100");
$photoQuery->setKind("tag");
$query = $photoQuery->getQueryUrl();

$photoFeed = $service->getPhotoFeed($query);

foreach ($photoFeed as $entry) {


if ($entry instanceof Zend_Gdata_Photos_TagEntry) {
if ($entry->getContent() == $tagContent) {
$tagEntry = $entry;
}
}
}

$service->deleteTagEntry($tagEntry, true);

11.5.5. Gestion des accès concurrents


Les flux GData, dont ceux de Picasa Web Albums, implémentent un système d'accès concurrent
qui empêche les changements avec écrasements par inadvertance. Si vous demandez
l'effacement d'une ressource qui a été modifiée depuis votre dernière requête, alors une
exception sera levée, sauf si vous demandez le contraire explicitement (dans un tel cas, la
procédure d'effacement sera réessayée sur l'élément mis à jour).

Voici un exemple de gestion des versions et accès concurrent sur un effacement avec
deleteAlbumEntry:

// $album est l'albumEntry à effacer


try {
$this->delete($album);
} catch (Zend_Gdata_App_HttpException $e) {
if ($e->getMessage()->getStatus() === 409) {
$entry =
new Zend_Gdata_Photos_AlbumEntry($e->getMessage()
->getBody());
$this->delete($entry->getLink('edit')->href);
} else {
throw $e;
}
}

12. Using the YouTube Data API


The YouTube Data API offers read and write access to YouTube's content. Users can perform
unauthenticated requests to Google Data feeds to retrieve feeds of popular videos, comments,
public information about YouTube user profiles, user playlists, favorites, subscriptions and so on.

807
Zend_Gdata

For more information on the YouTube Data API, please refer to the official PHP Developer's
Guide on code.google.com.

12.1. Authentication
The YouTube Data API allows read-only access to public data, which does not require
authentication. For any write requests, a user needs to authenticate either using ClientLogin or
AuthSub authentication. Please refer to the Authentication section in the PHP Developer's Guide
for more detail.

12.2. Developer Keys and Client ID


A developer key identifies the YouTube developer that is submitting an API request. A
client ID identifies your application for logging and debugging purposes. Please visit http://
code.google.com/apis/youtube/dashboard/ to obtain a developer key and client ID. The example
below demonstrates how to pass the developer key and client ID to the Zend_Gdata_YouTube
service object.

Exemple 393. Passing a Developer Key and ClientID to Zend_Gdata_YouTube

$yt = new Zend_Gdata_YouTube($httpClient,


$applicationId,
$clientId,
$developerKey);

12.3. Retrieving public video feeds


The YouTube Data API provides numerous feeds that return a list of videos, such as standard
feeds, related videos, video responses, user's uploads, and user's favorites. For example, the
user's uploads feed returns all videos uploaded by a specific user. See the YouTube API
reference guide for a detailed list of available feeds.

12.3.1. Searching for videos by metadata


You can retrieve a list of videos that match specified search criteria, using the YouTubeQuery
class. The following query looks for videos which contain the word "cat" in their metadata, starting
with the 10th video and displaying 20 videos per page, ordered by the view count.

Exemple 394. Searching for videos

$yt = new Zend_Gdata_YouTube();


$query = $yt->newVideoQuery();
$query->videoQuery = 'cat';
$query->startIndex = 10;
$query->maxResults = 20;
$query->orderBy = 'viewCount';

echo $query->queryUrl . "\n";


$videoFeed = $yt->getVideoFeed($query);

foreach ($videoFeed as $videoEntry) {


echo "---------VIDEO----------\n";
echo "Title: " . $videoEntry->getVideoTitle() . "\n";
echo "\nDescription:\n";
echo $videoEntry->getVideoDescription();
echo "\n\n\n";
}

808
Zend_Gdata

For more details on the different query parameters, please refer to the Reference Guide.
The available helper functions in Zend_Gdata_YouTube_VideoQuery for each of these
parameters are described in more detail in the PHP Developer's Guide.

12.3.2. Searching for videos by categories and tags/keywords


Searching for videos in specific categories is done by generating a specially formatted URL. For
example, to search for comedy videos which contain the keyword dog:

Exemple 395. Searching for videos in specific categories

$yt = new Zend_Gdata_YouTube();


$query = $yt->newVideoQuery();
$query->category = 'Comedy/dog';

echo $query->queryUrl . "\n";


$videoFeed = $yt->getVideoFeed($query);

12.3.3. Retrieving standard feeds


The YouTube Data API has a number of standard feeds. These standard
feeds can be retrieved as Zend_Gdata_YouTube_VideoFeed objects using the
specified URLs, using the predefined constants within the Zend_Gdata_YouTube class
(Zend_Gdata_YouTube::STANDARD_TOP_RATED_URI for example) or using the predefined
helper methods (see code listing below).

To retrieve the top rated videos using the helper method:

Exemple 396. Retrieving a standard video feed

$yt = new Zend_Gdata_YouTube();


$videoFeed = $yt->getTopRatedVideoFeed();

There are also query parameters to specify the time period over which the standard feed is
computed.

For example, to retrieve the top rated videos for today:

Exemple 397. Using a Zend_Gdata_YouTube_VideoQuery to Retrieve Videos

$yt = new Zend_Gdata_YouTube();


$query = $yt->newVideoQuery();
$query->setTime('today');
$videoFeed = $yt->getTopRatedVideoFeed($query);

Alternatively, you could just retrieve the feed using the URL:

Exemple 398. Retrieving a video feed by URL

$yt = new Zend_Gdata_YouTube();


$url = 'http://gdata.youtube.com/feeds/standardfeeds/top_rated?time=today'
$videoFeed = $yt->getVideoFeed($url);

12.3.4. Retrieving videos uploaded by a user


You can retrieve a list of videos uploaded by a particular user using a simple helper method. This
example retrieves videos uploaded by the user 'liz'.

809
Zend_Gdata

Exemple 399. Retrieving videos uploaded by a specific user

$yt = new Zend_Gdata_YouTube();


$videoFeed = $yt->getUserUploads('liz');

12.3.5. Retrieving videos favorited by a user


You can retrieve a list of a user's favorite videos using a simple helper method. This example
retrieves videos favorited by the user 'liz'.

Exemple 400. Retrieving a user's favorite videos

$yt = new Zend_Gdata_YouTube();


$videoFeed = $yt->getUserFavorites('liz');

12.3.6. Retrieving video responses for a video


You can retrieve a list of a video's video responses using a simple helper method. This example
retrieves video response for a video with the ID 'abc123813abc'.

Exemple 401. Retrieving a feed of video responses

$yt = new Zend_Gdata_YouTube();


$videoFeed = $yt->getVideoResponseFeed('abc123813abc');

12.4. Retrieving video comments


The comments for each YouTube video can be retrieved in several ways. To retrieve the
comments for the video with the ID 'abc123813abc', use the following code:

Exemple 402. Retrieving a feed of video comments from a video ID

$yt = new Zend_Gdata_YouTube();


$commentFeed = $yt->getVideoCommentFeed('abc123813abc');

foreach ($commentFeed as $commentEntry) {


echo $commentEntry->title->text . "\n";
echo $commentEntry->content->text . "\n\n\n";
}

Comments can also be retrieved for a video if you have a copy of the
Zend_Gdata_YouTube_VideoEntry object:

Exemple 403. Retrieving a Feed of Video Comments from a


Zend_Gdata_YouTube_VideoEntry

$yt = new Zend_Gdata_YouTube();


$videoEntry = $yt->getVideoEntry('abc123813abc');
// we don't know the video ID in this example, but we do have the URL
$commentFeed = $yt->getVideoCommentFeed(null,
$videoEntry->comments->href);

12.5. Retrieving playlist feeds


The YouTube Data API provides information about users, including profiles, playlists,
subscriptions, and more.

810
Zend_Gdata

12.5.1. Retrieving the playlists of a user


The library provides a helper method to retrieve the playlists associated with a given user. To
retrieve the playlists for the user 'liz':

Exemple 404. Retrieving the playlists of a user

$yt = new Zend_Gdata_YouTube();


$playlistListFeed = $yt->getPlaylistListFeed('liz');

foreach ($playlistListFeed as $playlistEntry) {


echo $playlistEntry->title->text . "\n";
echo $playlistEntry->description->text . "\n";
echo $playlistEntry->getPlaylistVideoFeedUrl() . "\n\n\n";
}

12.5.2. Retrieving a specific playlist


The library provides a helper method to retrieve the videos associated with a given playlist. To
retrieve the playlists for a specific playlist entry:

Exemple 405. Retrieving a specific playlist

$feedUrl = $playlistEntry->getPlaylistVideoFeedUrl();
$playlistVideoFeed = $yt->getPlaylistVideoFeed($feedUrl);

12.6. Retrieving a list of a user's subscriptions


A user can have several types of subscriptions: channel subscription, tag subscription,
or favorites subscription. A Zend_Gdata_YouTube_SubscriptionEntry is used to represent
individual subscriptions.

To retrieve all subscriptions for the user 'liz':

Exemple 406. Retrieving all subscriptions for a user

$yt = new Zend_Gdata_YouTube();


$subscriptionFeed = $yt->getSubscriptionFeed('liz');

foreach ($subscriptionFeed as $subscriptionEntry) {


echo $subscriptionEntry->title->text . "\n";
}

12.7. Retrieving a user's profile


You can retrieve the public profile information for any YouTube user. To retrieve the profile for
the user 'liz':

Exemple 407. Retrieving a user's profile

$yt = new Zend_Gdata_YouTube();


$userProfile = $yt->getUserProfile('liz');
echo "username: " . $userProfile->username->text . "\n";
echo "age: " . $userProfile->age->text . "\n";
echo "hometown: " . $userProfile->hometown->text . "\n";

811
Zend_Gdata

12.8. Uploading Videos to YouTube


Please make sure to review the diagrams in the protocol guide on code.google.com for a high-
level overview of the upload process. Uploading videos can be done in one of two ways: either
by uploading the video directly or by sending just the video meta-data and having a user upload
the video through an HTML form.

In order to upload a video directly, you must first construct a new


Zend_Gdata_YouTube_VideoEntry object and specify some required meta-data The following
example shows uploading the Quicktime video "mytestmovie.mov" to YouTube with the following
properties:

Tableau 64. Metadata used in the code-sample below

Property Value
Title My Test Movie
Category Autos
Keywords cars, funny
Description My description
Filename mytestmovie.mov
File MIME type video/quicktime
Video private? FALSE
Video location 37, -122 (lat, long)
Developer Tags mydevelopertag, anotherdevelopertag

The code below creates a blank Zend_Gdata_YouTube_VideoEntry to be uploaded. A


Zend_Gdata_App_MediaFileSource object is then used to hold the actual video file. Under the
hood, the Zend_Gdata_YouTube_Extension_MediaGroup object is used to hold all of the video's
meta-data. Our helper methods detailed below allow you to just set the video meta-data without
having to worry about the media group object. The $uploadUrl is the location where the new entry
gets posted to. This can be specified either with the $userName of the currently authenticated
user, or, alternatively, you can simply use the string 'default' to refer to the currently authenticated
user.

812
Zend_Gdata

Exemple 408. Uploading a video

$yt = new Zend_Gdata_YouTube($httpClient);


$myVideoEntry = new Zend_Gdata_YouTube_VideoEntry();

$filesource = $yt->newMediaFileSource('mytestmovie.mov');
$filesource->setContentType('video/quicktime');
$filesource->setSlug('mytestmovie.mov');

$myVideoEntry->setMediaSource($filesource);

$myVideoEntry->setVideoTitle('My Test Movie');


$myVideoEntry->setVideoDescription('My Test Movie');
// Note that category must be a valid YouTube category !
$myVideoEntry->setVideoCategory('Comedy');

// Set keywords, note that this must be a comma separated string


// and that each keyword cannot contain whitespace
$myVideoEntry->SetVideoTags('cars, funny');

// Optionally set some developer tags


$myVideoEntry->setVideoDeveloperTags(array('mydevelopertag',
'anotherdevelopertag'));

// Optionally set the video's location


$yt->registerPackage('Zend_Gdata_Geo');
$yt->registerPackage('Zend_Gdata_Geo_Extension');
$where = $yt->newGeoRssWhere();
$position = $yt->newGmlPos('37.0 -122.0');
$where->point = $yt->newGmlPoint($position);
$myVideoEntry->setWhere($where);

// Upload URI for the currently authenticated user


$uploadUrl =
'http://uploads.gdata.youtube.com/feeds/users/default/uploads';

// Try to upload the video, catching a Zend_Gdata_App_HttpException


// if availableor just a regular Zend_Gdata_App_Exception

try {
$newEntry = $yt->insertEntry($myVideoEntry,
$uploadUrl,
'Zend_Gdata_YouTube_VideoEntry');
} catch (Zend_Gdata_App_HttpException $httpException) {
echo $httpException->getRawResponseBody();
} catch (Zend_Gdata_App_Exception $e) {
echo $e->getMessage();
}

To upload a video as private, simply use: $myVideoEntry->setVideoPrivate(); prior to performing


the upload. $videoEntry->isVideoPrivate() can be used to check whether a video entry is private
or not.

12.9. Browser-based upload


Browser-based uploading is performed almost identically to direct uploading,
except that you do not attach a Zend_Gdata_App_MediaFileSource object to the
Zend_Gdata_YouTube_VideoEntry you are constructing. Instead you simply submit all of your

813
Zend_Gdata

video's meta-data to receive back a token element which can be used to construct an HTML
upload form.

Exemple 409. Browser-based upload

$yt = new Zend_Gdata_YouTube($httpClient);

$myVideoEntry= new Zend_Gdata_YouTube_VideoEntry();


$myVideoEntry->setVideoTitle('My Test Movie');
$myVideoEntry->setVideoDescription('My Test Movie');

// Note that category must be a valid YouTube category


$myVideoEntry->setVideoCategory('Comedy');
$myVideoEntry->SetVideoTags('cars, funny');

$tokenHandlerUrl = 'http://gdata.youtube.com/action/GetUploadToken';
$tokenArray = $yt->getFormUploadToken($myVideoEntry, $tokenHandlerUrl);
$tokenValue = $tokenArray['token'];
$postUrl = $tokenArray['url'];

The above code prints out a link and a token that is used to construct an HTML form to display
in the user's browser. A simple example form is shown below with $tokenValue representing the
content of the returned token element, as shown being retrieved from $myVideoEntry above.
In order for the user to be redirected to your website after submitting the form, make sure to
append a $nextUrl parameter to the $postUrl above, which functions in the same way as the
$next parameter of an AuthSub link. The only difference is that here, instead of a single-use
token, a status and an id variable are returned in the URL.

Exemple 410. Browser-based upload: Creating the HTML form

// place to redirect user after upload


$nextUrl = 'http://mysite.com/youtube_uploads';

$form = '<form action="'. $postUrl .'?nexturl='. $nextUrl .


'" method="post" enctype="multipart/form-data">'.
'<input name="file" type="file"/>'.
'<input name="token" type="hidden" value="'. $tokenValue .'"/>'.
'<input value="Upload Video File" type="submit" />'.
'</form>';

12.10. Checking upload status


After uploading a video, it will immediately be visible in an authenticated user's uploads feed.
However, it will not be public on the site until it has been processed. Videos that have been
rejected or failed to upload successfully will also only be in the authenticated user's uploads feed.
The following code checks the status of a Zend_Gdata_YouTube_VideoEntry to see if it is not
live yet or if it has been rejected.

814
Zend_Gdata

Exemple 411. Checking video upload status

try {
$control = $videoEntry->getControl();
} catch (Zend_Gdata_App_Exception $e) {
echo $e->getMessage();
}

if ($control instanceof Zend_Gdata_App_Extension_Control) {


if ($control->getDraft() != null &&
$control->getDraft()->getText() == 'yes') {
$state = $videoEntry->getVideoState();

if ($state instanceof Zend_Gdata_YouTube_Extension_State) {


print 'Upload status: '
. $state->getName()
.' '. $state->getText();
} else {
print 'Not able to retrieve the video status information'
.' yet. ' . "Please try again shortly.\n";
}
}
}

12.11. Other Functions


In addition to the functionality described above, the YouTube API contains many other functions
that allow you to modify video meta-data, delete video entries and use the full range of community
features on the site. Some of the community features that can be modified through the API
include: ratings, comments, playlists, subscriptions, user profiles, contacts and messages.

Please refer to the full documentation available in the PHP Developer's Guide on
code.google.com.

13. Attraper les exceptions Gdata


La classe Zend_Gdata_App_Exception est la classe de base de toutes les exceptions
envoyées par les composants Gdata.

try {
$client =
Zend_Gdata_ClientLogin::getHttpClient($username, $password);
} catch(Zend_Gdata_App_Exception $ex) {
// Affiche l'exception à l'utilisateur
die($ex->getMessage());
}

Voici les sous classes exception utilisées dans Zend_Gdata :

• Zend_Gdata_App_AuthException indique que les identifiants du compte utilisateur sont


erronés.

• Zend_Gdata_App_BadMethodCallException est levée lorsque vous tentez d'utiliser une


méthode sur un service qui ne l'implémente pas. Par exemple, le service CodeSearch ne
supporte pas la méthode post().

• Zend_Gdata_App_HttpException indique un échec de requête HTTP. Cette exception


vous donne le moyen de récupérer la réponse Zend_Http_Response entière pour

815
Zend_Gdata

déterminer la cause exacte de l'erreur, alors que $e->getMessage() ne montre pas autant
de détails.

• Zend_Gdata_App_InvalidArgumentException est envoyée lorsque l'application envoie


une valeur non attendue. Par exemple spécifier la visibilité d'un calendrier à "banane", ou
récupérer le flux d'un blog Blogger sans spécifier le nom du blog en question.

• Zend_Gdata_App_CaptchaRequiredException est envoyée lorsqu'une tentative de


ClientLogin reçoit un challenge CAPTCHA™ depuis le service d'authentification. Cette
exception contient un jeton ID et une URL vers une image CAPTCHA™ . Cette image
est un puzzle visuel qui devrait être retournée à l'utilisateur du service. Après récupération
de la réponse de l'utilisateur, celle-ci peut être incluse lors du ClientLogin suivant.
L'utilisateur peut aussi alternativement être redirigé vers ce site : https://www.google.com/
accounts/DisplayUnlockCaptcha. De plus amples informations peuvent être trouvées dans la
documentation du ClientLogin.

Vous pouvez ainsi utiliser ces sous-classes d'exceptions pour les gérer chacune différemment.
Référez vous à l'API pour savoir quel composant Zend_Gdata envoie quel type d'exception.

try {
$client =
Zend_Gdata_ClientLogin::getHttpClient($username,
$password,
$service);
} catch(Zend_Gdata_App_AuthException $authEx) {
// identifiants fournis incorrects
// Vous pourriez par exemple offrir une
// seconde chance à l'utilisateur ici
...
} catch(Zend_Gdata_App_HttpException $httpEx) {
// les serveurs Google Data sont injoignables
die($httpEx->getMessage);
}

816
Zend_Http
1. Introduction
Zend_Http_Client fournit une interface qui permet d'utiliser le protocole HTTP (Hyper-Text
Transfer Protocol). Zend_Http_Client supporte les fonctionnalités de base d'un client HTTP,
ainsi que des fonctionnalités plus avancées, comme l'authentification ou l'upload de fichiers.
Toutes les requêtes retournent un objet Zend_Http_Response, avec lequel on pourra accéder
au corps ou aux en-têtes de la réponse HTTP (voyez Section 5, « Zend_Http_Response »).

1.1. Utilisation de Zend_Http_Client


Le constructeur de classe accepte deux paramètres : l'URI (ou un objet Zend_Uri_Http), et un
tableau ou un objet Zend_Config d'options de configuration. Ils peuvent aussi être définis avec
des méthodes plus tard : setUri() et setConfig().

Exemple 412. Instanciation d'un objet Zend_Http_Client

$client = new Zend_Http_Client('http://example.org', array(


'maxredirects' => 0,
'timeout' => 30));

// OU
$client = new Zend_Http_Client();
$client->setUri('http://example.org');
$client->setConfig(array(
'maxredirects' => 0,
'timeout' => 30));

// You can also use a Zend_Config object to set the client's configuration
$config = new Zend_Config_Ini('httpclient.ini, 'secure');
$client->setConfig($config);

Zend_Http_Client utilise Zend_Uri_Http pour valider les URLs. Ce qui veut


dire que certains caractères comme les pipes ("|") ou le symbole "^" ne seront
pas acceptés par défaut dans les URLs. Ceci peut être modifié par le réglage de
l'option "allow_unwise" de Zend_Uri à TRUE. Voir Section 1.4.1, « Autoriser les
caractères "imprudents" dans les URIs » pour de plus amples informations.

1.2. Les paramètres de configuration


Le constructeur et setConfig() acceptent un tableau associatif de paramètre de configuration,
ou un objet Zend_Config. Fixer ces paramètres est optionnel, ils ont tous une valeur par défaut.

Tableau 65. Zend_Http_Client : paramètres de configuration


Paramètre Description Valeur attendue Valeur par défaut
maxredirects Nombre maximum de entier 5
redirections à suivre (0
= aucune)
strict Validation faite ou non booléen TRUE
sur les noms d'en-

817
Zend_Http

Paramètre Description Valeur attendue Valeur par défaut


têtes. Si à FALSE, des
fonctions de validation
n'interviendront pas.
Habituellement ceci
ne devrait pas être
changé
strictredirects Est ce que le client booléen FALSE
doit suivre strictement
les redirections selon
la RFC2616 ?
(voyez Section 2.1,
« Redirections
HTTP »)
useragent La chaîne User Agent chaîne 'Zend_Http_Client'
du client (envoyée en
en-tête de requête)
timeout Connexion timeout entier 10
(secondes)
httpversion Version du protocole chaîne '1.1'
HTTP à utiliser ('1.1',
'1.0' ou '0.9')
adapter Classe adaptateur mixed 'Zend_Http_Client_Adapter_Socket'
à utiliser (voyez
Section 3,
« Zend_Http_Client
- Adaptateurs de
connexion »)
keepalive Utilisation du pipelining booléen FALSE
HTTP (connexion
ouverte après
déconnexion du client)
storeresponse Stockage ou non booléen TRUE
de la dernière
réponse pour une
récupération ultérieure
avec
getLastResponse().
Si réglez à FALSE,
getLastResponse()
retournera NULL.

1.3. Utilisation basique


Exécuter des requêtes HTTP basiques est très simple grâce à la méthode request(), et ceci
nécessite rarement plus d'une ligne de code :

Exemple 413. Requête GET simple

$client = new Zend_Http_Client('http://example.org');


$response = $client->request();

818
Zend_Http

La méthode request() accepte un paramètre optionnel définissant la méthode HTTP, - GET,


POST, PUT, HEAD, DELETE, TRACE, OPTIONS ou CONNECT - comme définies dans la RFC
1
2616 concernant le protocole HTTP . Ces méthodes HTTP sont aussi définies en tant que
constantes de classe, Zend_Http_Request::GET, Zend_Http_Request::POST, etc...

Si aucune méthode de requêtage HTTP n'est définie, alors la dernière utilisée via setMethod()
sera utilisée. Si setMethod() n'a jamais été appelée, GET est alors utilisée par défaut.

Exemple 414. Requêtes d'autres types que GET

// requête POST
$response = $client->request('POST');

// autre manière de faire :


$client->setMethod(Zend_Http_Client::POST);
$response = $client->request();

1.4. Ajouts de paramètres GET et POST


Ajouter des paramètres GET à la requête HTTP est très simple. Vous pouvez les ajouter en tant
que partie de l'URL désirée, ou en utilisant la méthode setParameterGet(). Celle-ci prend
en premier paramètre le nom du paramètre GET, et en second sa valeur. Un tableau associatif
peut aussi être utilisé.

Exemple 415. Ajouts de paramètres GET

// Avec la méthode setParameterGet


$client->setParameterGet('knight', 'lancelot');

// Ce qui est équivalent à :


$client->setUri('http://example.com/index.php?knight=lancelot');

// Ajout de plusieurs paramètres en un appel


$client->setParameterGet(array(
'first_name' => 'Bender',
'middle_name' => 'Bending'
'made_in' => 'Mexico',
));

Coté POST, c'est très similaire à GET, sauf que les paramètres POST doivent faire partie du
corps de la requête. Il n'est donc pas possible de les ajouter dans l'URL. Utilisez simplement
setParameterPost() de la même manière que sa soeur setParameterGet().

Exemple 416. Ajout de paramètres POST

// passage de paramètre POST simple


$client->setParameterPost('language', 'fr');

// Plusieurs paramètres, dont un avec plusieurs valeurs


$client->setParameterPost(array(
'language' => 'es',
'country' => 'ar',
'selection' => array(45, 32, 80)
));

1
Voyez la RFC 2616 - http://www.w3.org/Protocols/rfc2616/rfc2616.html.

819
Zend_Http

Notez qu'en plus de paramètres POST, vous pouvez ajouter des paramètres GET à une requête
POST. Le contraire n'est pas possible, ainsi les paramètres POST ajoutés à une requête GET
seront acceptés certes, mais ignorés.

1.5. Accéder à la dernière requête, ou réponse


Zend_Http_Client fournit un moyen d'accéder à la dernière requête qu'il a effectuée, ainsi
qu'à la dernière réponse qu'il a reçue. Zend_Http_Client->getLastRequest() ne prends
pas de paramètres et retourne la dernière requête sous forme de chaîne de caractères.
Zend_Http_Client->getLastResponse() retourne elle la dernière réponse, mais sous
forme d'objet Zend_Http_Response.

2. Zend_Http_Client - Utilisation avancée


2.1. Redirections HTTP
Par défaut, Zend_Http_Client gère automatiquement les redirections HTTP, et suivra jusqu'à
5 redirections. Ce comportement peut être modifié en changeant le paramètre de configuration
"maxredirects".

Conformément à la RFC HTTP/1.1, les codes réponse HTTP 301 et 302 doivent être traités par
le client en envoyant à nouveau la même requête à l'adresse spécifiée - en utilisant la même
méthode de requête. Cependant, la plupart des clients ne réagissent pas correctement et redirige
toujours via une requête GET. Par défaut, Zend_Http_Client agit de même - Lors d'une
redirection basée sur la réception d'un code 301 ou 302, tous les paramètres GET et POST sont
remis à zéro, et une requête GET est envoyée à la nouvelle adresse. Ce comportement peut
être modifié en positionnant le paramètre de configuration "strictredirects" à TRUE :

Exemple 417. Forcer des redirections conformes au RFC 2616 lors de la réception
d'un code statut 301 and 302

// Redirections strictes
$client->setConfig(array('strictredirects' => true)

// Redirections non strictes


$client->setConfig(array('strictredirects' => false)

Il est toujours possible d'obtenir le nombre de redirections effectuées après l'envoi d'une requête
en invoquant la méthode getRedirectionsCount().

2.2. Ajout de cookies et gestion de leur persistance


Zend_Http_Client fournit une interface simple afin d'ajouter des cookies à une requête de
manière à ce qu'aucune modification directe de l'en-tête ne soit nécessaire. Ceci est réalisé via
la méthode setCookie(). Cette méthode peut être utilisée de plusieurs manières :

820
Zend_Http

Exemple 418. Définition de cookies via setCookie()

// Simple et facile : en fournissant un nom de cookie et une valeur


$client->setCookie('parfum', 'pépites de chocolat');

// en fournissant directement une chaîne de cookie encodée (nom=valeur)


// Notez que la valeur doit être déjà encodée au format URL
$client->setCookie('parfum=p%C3%A9pites%20de%20chocolat');

// En fournissant un objet Zend_Http_Cookie


$cookie =
Zend_Http_Cookie::fromString('parfum=p%C3%A9pites%20de%20chocolat');
$client->setCookie($cookie);

Pour plus d'information sur les objets Zend_Http_Cookie, voir Section 4, « Zend_Http_Cookie
and Zend_Http_CookieJar ».

Zend_Http_Client permet également la persistance des cookies - ce qui permet au client de


stocker tous les cookies reçus et transmis, et de les retransmettre automatiquement lors des
requêtes suivantes. Cela se révèle très utile lorsqu'il est nécessaire de s'identifier sur un site
donné (et de recevoir ainsi un cookie de session) avant de pouvoir envoyer d'autres requêtes.

Exemple 419. Activer la persistance des cookies

// Pour activer la persistance des cookies,


// définissez un Magasin de cookie "Cookie Jar"
$client->setCookieJar();

// Première requête : s'identifier et démarrer une session


$client->setUri('http://exemple.com/login.php');
$client->setParameterPost('user', 'h4x0r');
$client->setParameterPost('password', '1337');
$client->request('POST');

// Le magasin de cookies stocke automatiquement les


// cookies transmis dans la réponse, un cookie de session par exemple

// Maintenant nous pouvons envoyer notre requête suivante


// les cookies stockés seront transmis automatiquement.
$client->setUri('http://exemple.com/lire_actualite_membres.php');
$client->request('GET');

Pour plus d'information sur la classe Zend_Http_CookieJar, voir Section 4.5, « Classe
Zend_Http_CookieJar : Instanciation ».

2.3. Définir des en-têtes personnalisés


Il est possible de définir des en-têtes personnalisés en utilisant la méthode setHeaders().
Cette méthode est très versatile et peut être utilisée de diverses manières comme le montre
l'exemple suivant :

821
Zend_Http

Exemple 420. Définir un en-tête personnalisé unique

// Définition d'un en-tête unique,


// écrasant toute valeur précédemment définie
$client->setHeaders('Host', 'www.exemple.com');

// La même chose d'une autre manière


$client->setHeaders('Host: www.example.com');

// Définition de plusieurs valeurs pour le même en-tête


// (surtout utile pour les en-têtes de cookies)
$client->setHeaders('Cookie', array(
'PHPSESSID=1234567890abcdef1234567890abcdef',
'language=fr'
));

setHeader() peut aussi être facilement utilisé pour définir des en-têtes multiples en un seul
appel, en fournissant un tableau d'en-têtes comme paramètre unique :

Exemple 421. Définition de plusieurs en-têtes personnalisés

// Définition de plusieurs en-têtes,


// écrasant toute valeur précédemment définie
$client->setHeaders(array(
'Host' => 'www.exemple.com',
'Accept-encoding' => 'gzip,deflate',
'X-Powered-By' => 'Zend Framework'));

// Le tableau peut contenir uniquement des valeurs


$client->setHeaders(array(
'Host: www.exemple.com',
'Accept-encoding: gzip,deflate',
'X-Powered-By: Zend Framework'));

2.4. Envoi de fichiers


Il est possible d'envoyer des fichiers au travers d'HTTP en utilisant la méthode setFileUpload.
Cette méthode attend un nom de fichier comme premier paramètre, un nom de formulaire comme
second paramètre, et, en option, des données comme troisième paramètre. Si le troisième
paramètre est NULL, la valeur du premier paramètre est supposée être un fichier sur le disque
dur et Zend_Http_Client essaiera de lire ce fichier et de l'envoyer. Sinon la valeur du premier
paramètre sera envoyée comme nom du fichier mais il n'est pas nécessaire que le fichier existe
sur le disque dur. Le deuxième paramètre est toujours requis, et est équivalent à l'attribut "name"
d'une balise <input>, si le fichier devait être envoyé à partir d'un formulaire HTML. Un quatrième
paramètre optionnel fournit le type du fichier. S'il n'est pas spécifié et que Zend_Http_Client
lit le fichier à partir du disque dur, la fonction mime_content_type sera utilisée pour tenter de
définir, si possible, le type du fichier. Dans tous les cas, le type MIME par défaut sera 'application/
octet-stream'.

822
Zend_Http

Exemple 422. Utilisation de setFileUpload pour envoyer des fichiers

// Envoi de données arbitraires comme fichier


$texte = 'ceci est un texte ordinaire';
$client->setFileUpload('du_texte.txt', 'upload', $texte, 'text/plain');

// envoi d'un fichier existant


$client->setFileUpload('/tmp/Backup.tar.gz', 'bufile');

// envoi des fichiers


$client->request('POST');

Dans le premier exemple, la variable $texte est envoyée et sera disponible dans
$_FILES['upload'] côté serveur. Dans le second exemple, le fichier existant "/tmp/
Backup.tar.gz" est envoyé au serveur et sera disponible dans $_FILES['bufile']. Son
type sera défini automatiquement si possible. Sinon, le type sera défini comme "application/
octet-stream".

Envoi de fichiers

Lors de l'envoi de fichiers, le type de la requête HTTP est automatiquement


défini comme "multipart/form-data". Gardez à l'esprit que vous devez utiliser la
méthode POST ou la méthode PUT pour envoyer des fichiers. La plupart des
serveurs ignoreront le corps de la requête si vous utilisez une autre méthode.

2.5. Envoyer des données brutes via POST


Vous pouvez utiliser Zend_Http_Client pour envoyer des données brutes via POST en
utilisant la méthode setRawData(). Cette méthode accepte deux paramètres : le premier
contient les données à transmettre dans le corps de la requête. Le deuxième paramètre,
optionnel, contient le type des données. Bien que ce paramètre soit optionnel, vous devriez
normalement le définir avant l'envoi de la requête, soit via setRawData() ou via la méthode
setEncType().

Exemple 423. Envoi de données brutes via POST

$xml = '<book>' .
' <title>Islands in the Stream</title>' .
' <author>Ernest Hemingway</author>' .
' <year>1970</year>' .
'</book>';

$client->setRawData($xml, 'text/xml')->request('POST');

// Une autre manière de faire la même chose :


$client->setRawData($xml)->setEncType('text/xml')->request('POST');

Les données seront disponible côté serveur via la variable PHP $HTTP_RAW_POST_DATA ou
via le flux php://input.

Utiliser des données brutes POST

Définir des données brutes POST pour une requête écrasera tout autre
paramètre POST ou envoi de fichiers. Il est recommandé de ne pas utiliser les

823
Zend_Http

deux conjointement. Gardez à l'esprit que la plupart des serveurs ignoreront le


corps de la requête si celle-ci n'utilise pas la méthode POST.

2.6. Authentification HTTP


Actuellement, Zend_Http_Client propose uniquement l'authentification HTTP "basic". Cette
fonctionnalité est utilisée via la méthode setAuth(), ou en spécifiant le nom d'utilisateur
et le mot de passe dans l'URI. La méthode setAuth() accepte trois paramètres : le nom
d'utilisateur, le mot de passe et un type d'authentification optionnel. Comme mentionné, seule
l'authentification "basic" est actuellement implémentée (l'ajout de l'authentification "digest" est
planifié).

Exemple 424. Définir nom d'utilisateur et mot de passe pour l'authentification


HTTP

// Utilisation de l'authentification 'basic'


$client->setAuth('shahar',
'monMotdePasse!',
Zend_Http_Client::AUTH_BASIC);

// L'authentification 'basic' étant le comportement par défaut,


// on peut aussi écrire ceci :
$client->setAuth('shahar', 'monMotdePasse!');

// Vous pouvez aussi spécifier le nom d'utilisateur


// et le mot de passe dans l'URI
$client->setUri('http://christer:secret@example.com');

2.7. Envoyer plusieurs requêtes avec le même client


Zend_Http_Client a été également conçu spécifiquement pour gérer plusieurs requêtes
consécutives avec la même instance. Ceci est utile dans les cas ou le script nécessite d'accéder
à des données en provenance de divers emplacements ou, par exemple, lors de l'accès à des
ressources HTTP nécessitant une authentification préalable.

Lorsqu'on génère plusieurs requêtes vers le même hôte, il est chaudement recommandé
d'activer la variable de configuration "keepalive". De cette manière, si le serveur supporte le mode
de connexion "keep-alive", la connexion au serveur sera fermée après l'exécution de toutes les
requêtes et la destruction de l'instance. Ceci permet d'éviter au serveur d'ouvrir et de fermer de
multiples connexions TCP.

Lorsqu'on génère plusieurs requêtes avec le même client, mais qu'on souhaite s'assurer que tous
les paramètres spécifiques de chacune des requêtes sont effacés, on peut utiliser la méthode
resetParameters(). Ceci permet de supprimer tous les paramètres GET et POST, le contenu
des requêtes et les en-têtes spécifiques de manière à ce qu'ils ne soient pas réutilisés lors de
la requête suivante.

Réinitialiser les paramètres

Notez que les en-têtes spécifiques non liés à la requête ne sont pas réinitialisés
par défaut quand la méthode resetParameters est invoquée. En fait, seuls
les en-têtes "Content-length" et "Content-type" sont supprimés. Ceci permet
de définir une seule fois les en-têtes comme "Accept-language" ou "Accept-
encoding".

824
Zend_Http

Pour effacer tous les entêtes et toutes les données excepté l'URI et la méthode,
utilisez resetParameters(true).

Une autre fonctionnalité spécifique aux requêtes consécutives est l'objet Magasin de Cookies
("Cookie Jar"). Il permet de sauver automatiquement les cookies définis par le serveur lors de
la première requête et de les renvoyer de manière transparente lors de chacune des requêtes
suivantes. Ceci permet, par exemple, de passer une étape d'authentification avant d'envoyer
d'autres requêtes.

Si votre application nécessite une requête d'authentification par utilisateur, et que d'autres
requêtes peuvent être effectuées via plusieurs scripts différents, il peut se révéler pratique de
stocker le Magasin de cookies dans la session utilisateur. De cette manière, il sera possible de
ne s'identifier qu'une seule fois par session.

Exemple 425. Exécuter plusieurs requêtes avec un seul client

// D'abord, instancier le client


$client =
new Zend_Http_Client('http://www.exemple.com/obtientdonnees.php',
array('keepalive' => true));

// Disposons-nous du cookie de session ?


if (isset($_SESSION['cookiejar']) &&
$_SESSION['cookiejar'] instanceof Zend_Http_CookieJar)) {

$client->setCookieJar($_SESSION['cookiejar']);
} else {
// Sinon, Identifions-nous et stockons le cookie
$client->setCookieJar();
$client->setUri('http://www.exemple.com/connexion.php');
$client->setParameterPost(array(
'user' => 'shahar',
'pass' => 'secret'
));
$client->request(Zend_Http_Client::POST);

// Maintenant, effaçons les paramètres et définissons l'URI


// à sa valeur originale (notez que les cookies envoyés par le
// serveur sont stockés dans le magasin de cookies)
$client->resetParameters();
$client->setUri('http://www.exemple.com/obtientdonnees.php');
}

$reponse = $client->request(Zend_Http_Client::GET);

// Stockons les cookies dans la session pour la page suivante


$_SESSION['cookiejar'] = $client->getCookieJar();

2.8. Data Streaming


By default, Zend_Http_Client accepts and returns data as PHP strings. However, in many
cases there are big files to be sent or received, thus keeping them in memory might be
unnecessary or too expensive. For these cases, Zend_Http_Client supports reading data
from files (and in general, PHP streams) and writing data to files (streams).

In order to use stream to pass data to Zend_Http_Client, use setRawData() method with
data argument being stream resource (e.g., result of fopen()).

825
Zend_Http

Exemple 426. Sending file to HTTP server with streaming

$fp = fopen("mybigfile.zip", "r");


$client->setRawData($fp, 'application/zip')->request('PUT');

Only PUT requests currently support sending streams to HTTP server.

In order to receive data from the server as stream, use setStream(). Optional argument
specifies the filename where the data will be stored. If the argument is just TRUE (default),
temporary file will be used and will be deleted once response object is destroyed. Setting
argument to FALSE disables the streaming functionality.

When using streaming, request() method will return object of


class Zend_Http_Client_Response_Stream, which has two useful methods:
getStreamName() will return the name of the file where the response is stored, and
getStream() will return stream from which the response could be read.

You can either write the response to pre-defined file, or use temporary file for storing it and send
it out or write it to another file using regular stream functions.

Exemple 427. Receiving file from HTTP server with streaming

$client->setStreaming(); // will use temp file


$response = $client->request('GET');
// copy file
copy($response->getStreamName(), "my/downloads/file");
// use stream
$fp = fopen("my/downloads/file2", "w");
stream_copy_to_stream($response->getStream(), $fp);
// Also can write to known file
$client->setStreaming("my/downloads/myfile)->request('GET');

3. Zend_Http_Client - Adaptateurs de connexion


3.1. Présentation globale
Zend_Http_Client accepte des objets adaptateurs. Ces objets ont la responsabilité de
soutenir la connexion vers un serveur, à savoir écrire des requêtes et lire des réponses
L'adaptateur peut donc être changé, et même écrit ou réécrit pour correspondre à vos besoins,
sans avoir l'obligation de toucher à toute la classe dite "client". Vous vous connectez et manipulez
votre connexion toujours de la même manière quelque soit l'adaptateur situé dessous.

Actuellement, la classe cliente Zend_Http_Client est fournie avec quatre adaptateurs :

• Zend_Http_Client_Adapter_Socket (défaut)

• Zend_Http_Client_Adapter_Proxy

• Zend_Http_Client_Adapter_Curl

• Zend_Http_Client_Adapter_Test

L'objet Zend_Http_Client se voit spécifié un adaptateur via son constructeur avec le tableau
d'options, à l'index 'adapter'. Fournissez alors une chaîne représentant la classe d'adaptateur à
utiliser (par exemple 'Zend_Http_Client_Adapter_Socket'), ou un objet directement (par exemple
new Zend_Http_Client_Adapter_Test). Vous pouvez de même passer un adaptateur plus
tard, avec la méthode Zend_Http_Client->setConfig().

826
Zend_Http

3.2. Adaptateur Socket


L'adaptateur par défaut est Zend_Http_Client_Adapter_Socket. Il est basé sur les fonctions
PHP fsockopen() et soeurs. Il ne nécessite donc aucune extension particulière ni option de
compilation de PHP.

L'adaptateur Socket peut être configuré avec des options, passées par Zend_Http_Client-
>setConfig() ou au constructeur du client.

Tableau 66. Zend_Http_Client_Adapter_Socket configuration

Paramètre Description Types attendus Valeur par défaut


persistent Utilise ou non booléen false
les connexions TCP
persistantes
ssltransport Couche de transport chaîne ssl
SSL ('sslv2', 'tls')
sslcert Chemin vers le chaîne null
certificat SSL encodé
PEM
sslpassphrase Phrase de passe pour chaîne null
le fichier de certificat
SSL

Connexions TCP persistantes

L'utilisation de connexions TCP persistantes peut potentiellement accélérer vos


requêtes HTTP mais n'a, dans la plupart des cas, qu'un petit effet positif et peut
surcharger le serveur HTTP auquel vous êtes connecté.

Il est recommandé d'utiliser les connexions TCP persistantes seulement si


vous vous connectez au même serveur très fréquemment, et que vous êtes
sûr que le serveur est capable de gérer un nombre élevé de connections
concurrentes. Dans tous les cas vous êtes encouragés à tester l'effet des
connections persistantes à la fois sur l'accélération du client et sur la charge du
serveur avant d'activer cette option.

De plus, quand vous utilisez des connexions persistantes, il est recommandé


d'activer l'option "Keep-Alive" décrite dans Section 1.2, « Les paramètres de
configuration », sinon les connexions persistantes n'auront que peu ou pas
d'effet.

HTTPS SSL Paramètres de flux

ssltransport, sslcert and sslpassphrase sont seulement appropriées


lors de l'utilisation d'HTTPS.

Bien que les réglages par défaut du mode SSL fonctionneront pour la plupart
des applications, vous pourrez avoir besoin de les changer si le serveur, auquel
vous vous connectez, requière un paramétrage particulier du client. Dans ce cas,
vous devriez lire les sections sur la couche de transport SSL et ses options à
cette adresse.

827
Zend_Http

Exemple 428. Changer la couche de transport HTTPS

// Définit des paramètres de configuration


$config = array(
'adapter' => 'Zend_Http_Client_Adapter_Socket',
'ssltransport' => 'tls'
);

// Instantie un objet client


$client = new Zend_Http_Client('https://www.example.com', $config);

// Cette requête sera envoyée vers une connexion sécurisée TLS


$response = $client->request();

Le résultat ci-dessus sera similaire à l'ouverture d'une connexion TCP avec la commande PHP
suivante :

fsockopen('tls://www.example.com', 443)

3.2.1. Customizing and accessing the Socket adapter stream context

Starting from Zend Framework 1.9, Zend_Http_Client_Adapter_Socket provides direct


access to the underlying stream context used to connect to the remote server. This allows the
user to pass specific options and parameters to the TCP stream, and to the SSL wrapper in case
of HTTPS connections.

You can access the stream context using the following methods of
Zend_Http_Client_Adapter_Socket:

• setStreamContext($context) Sets the stream context to be used by the adapter. Can


accept either a stream context resource created using the stream_context_create() PHP
function, or an array of stream context options, in the same format provided to this function.
Providing an array will create a new stream context using these options, and set it.

• getStreamContext() Get the stream context of the adapter. If no stream context was set,
will create a default stream context and return it. You can then set or get the value of different
context options using regular PHP stream context functions.

828
Zend_Http

Exemple 429. Setting stream context options for the Socket adapter

// Array of options
$options = array(
'socket' => array(
// Bind local socket side to a specific interface
'bindto' => '10.1.2.3:50505'
),
'ssl' => array(
// Verify server side certificate,
// do not accept invalid or self-signed SSL certificates
'verify_peer' => true,
'allow_self_signed' => false,

// Capture the peer's certificate


'capture_peer_cert' => true
)
);

// Create an adapter object and attach it to the HTTP client


$adapter = new Zend_Http_Client_Adapter_Socket();
$client = new Zend_Http_Client();
$client->setAdapter($adapter);

// Method 1: pass the options array to setStreamContext()


$adapter->setStreamContext($options);

// Method 2: create a stream context and pass it to setStreamContext()


$context = stream_context_create($options);
$adapter->setStreamContext($context);

// Method 3: get the default stream context and set the options on it
$context = $adapter->getStreamContext();
stream_context_set_option($context, $options);

// Now, preform the request


$response = $client->request();

// If everything went well, you can now access the context again
$opts = stream_context_get_options($adapter->getStreamContext());
echo $opts['ssl']['peer_certificate'];

Note that you must set any stream context options before using the adapter
to preform actual requests. If no context is set before preforming HTTP
requests with the Socket adapter, a default stream context will be created. This
context resource could be accessed after preforming any requests using the
getStreamContext() method.

3.3. Adaptateur Proxy


L'adaptateur Zend_Http_Client_Adapter_Proxy est identique à celui par défaut, Socket, sauf que
Proxy se connectera au serveur via un serveur Proxy (mandataire). Cette utilisation peut être
rencontrée pour des raisons de performances ou de sécurité.

En utilisant l'adaptateur Proxy, quelques paramètres de configuration seront nécessaires en plus


du paramètre 'adapter' :

829
Zend_Http

Tableau 67. Zend_Http_Client paramètres de configuration

Paramètre Description Valeurs attendues Valeur par défaut


proxy_host Adresse du serveur chaîne 'proxy.myhost.com' ou
Proxy '10.1.2.3'
proxy_port Port du serveur Proxy entier 8080 (défaut) ou 81
proxy_user nom d'utilisateur pour chaîne 'shahar' ou '' pour
le Proxy, si requis aucun (défaut)
proxy_pass Mot de passe du chaîne 'secret' ou '' pour
Proxy, si requis aucun (défaut)
proxy_auth Type d'authentification chaîne Zend_Http_Client::AUTH_BASIC
HTTP du Proxy (défaut)

proxy_host devrait toujours être fourni. Si ça n'est pas le cas, alors le client retournera sur une
connexion Socket par défaut. proxy_port est par défaut à "8080".

proxy_user et proxy_pass ne sont requis que si le serveur Proxy demande une


authentification. Si vous remplissez ces options, alors un champ d'en-tête HTTP "Proxy-
Authentication" sera ajouté à vos requêtes, via votre client.

proxy_auth définit le type d'authentification à utiliser, si le serveur Proxy demande une


authentification. Actuellement, seule la méthode "basic" (Zend_Http_Client::AUTH_BASIC)
est supportée.

Exemple 430. Utiliser Zend_Http_Client derrière un serveur Proxy

// Paramètres de configuration
$config = array(
'adapter' => 'Zend_Http_Client_Adapter_Proxy',
'proxy_host' => 'proxy.int.zend.com',
'proxy_port' => 8000,
'proxy_user' => 'shahar.e',
'proxy_pass' => 'bananashaped'
);

// Crée l'objet client


$client = new Zend_Http_Client('http://www.example.com', $config);

// utilisez l'objet client ici ...

Comme déjà dit, si proxy_host n'est pas rempli ou défini en tant que chaîne vide, alors le client
utilisera l'adaptateur Socket par défaut. Ceci est utile si le proxy est utilisé optionnellement, ou
par intermittence.

Since the proxy adapter inherits from Zend_Http_Client_Adapter_Socket,


you can use the stream context access method (see Section 3.2.1, « Customizing
and accessing the Socket adapter stream context ») to set stream context options
on Proxy connections as demonstrated above.

3.4. The cURL Adapter


cURL is a standard HTTP client library that is distributed with many operating systems and can
be used in PHP via the cURL extension. It offers functionality for many special cases which can

830
Zend_Http

occur for a HTTP client and make it a perfect choice for a HTTP adapter. It supports secure
connections, proxy, all sorts of authentication mechanisms and shines in applications that move
large files around between servers.

Exemple 431. Setting cURL options

$config = array(
'adapter' => 'Zend_Http_Client_Adapter_Curl',
'curloptions' => array(CURLOPT_FOLLOWLOCATION => true),
);
$client = new Zend_Http_Client($uri, $config);

By default the cURL adapter is configured to behave exactly like the Socket Adapter and it
also accepts the same configuration parameters as the Socket and Proxy adapters. You can
also change the cURL options by either specifying the 'curloptions' key in the constructor of the
adapter or by calling setCurlOption($name, $value). The $name key corresponds to the
CURL_* constants of the cURL extension. You can get access to the Curl handle by calling
$adapter->getHandle();

Exemple 432. Transfering Files by Handle

You can use cURL to transfer very large files over HTTP by filehandle.

$putFileSize = filesize("filepath");
$putFileHandle = fopen("filepath", "r");

$adapter = new Zend_Http_Client_Adapter_Curl();


$client = new Zend_Http_Client();
$client->setAdapter($adapter);
$adapter->setConfig(array(
'curloptions' => array(
CURLOPT_INFILE => $putFileHandle,
CURLOPT_INFILESIZE => $putFileSize
)
));
$client->request("PUT");

3.5. Adaptateur Test


Il est quelque fois difficile de tester une application qui a besoin d'une connexion HTTP. Par
exemple, une application qui est en charge de lire un flux RSS aura besoin d'une connexion, qui
n'est pas tout le temps disponible.

C'est pour cette raison que l'adaptateur Zend_Http_Client_Adapter_Test est présent.


Vous pouvez de cette manière écrire vos applications, et lors de la phase de tests, passer votre
connexion sur l'adaptateur Test (objet mock).

La classe Zend_Http_Client_Adapter_Test possède une méthode supplémentaire,


setResponse(). Elle prend en paramètre un objet Zend_Http_Response ou une chaîne.
Une fois cet objet de réponse déterminé, l'adaptateur de Test retournera toujours cette réponse,
sans effectuer de réelle requête HTTP.

831
Zend_Http

Exemple 433. Tester avec un objet de réponse HTTP unique

// Création de l'adatateur et de l'objet client :


$adapter = new Zend_Http_Client_Adapter_Test();
$client = new Zend_Http_Client('http://www.example.com', array(
'adapter' => $adapter
));

// Passage de l'objet de réponse


$adapter->setResponse(
"HTTP/1.1 200 OK" . "\r\n" .
"Content-type: text/xml" . "\r\n" .
"\r\n" .
'<?xml version="1.0" encoding="UTF-8"?>' .
'<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"' .
' xmlns:wfw="http://wellformedweb.org/CommentAPI/"' .
' xmlns:dc="http://purl.org/dc/elements/1.1/">' .
' <channel>' .
' <title>Premature Optimization</title>' .
// etc....
'</rss>');

$response = $client->request('GET');
// ... continuez à parser $response...

L'exemple ci dessus montre comment préconfigurer la réponse qui sera retournée lors d'une
requête de votre objet client. Ainsi lors des tests, votre application continuera de se comporter
normalement, elle aura tout simplement été trompée (mock). Aucune connexion HTTP n'est dans
ce cas là nécessaire.

Quelques fois, plusieurs transactions HTTP peuvent être nécessaires. Une réponse peut
demander une redirection, vers une autre. Dans ce cas, utiliser setResponse() toute seule
n'est pas possible car il ne sera pas possible de spécifier les réponses suivantes, nécessaires
alors à l'application.

832
Zend_Http

Exemple 434. Tester avec plusieurs réponses HTTP

// Création des objets adaptateur, et client


$adapter = new Zend_Http_Client_Adapter_Test();
$client = new Zend_Http_Client('http://www.example.com', array(
'adapter' => $adapter
));

// Configuration de la première réponse attendue


$adapter->setResponse(
"HTTP/1.1 302 Found" . "\r\n" .
"Location: /" . "\r\n" .
"Content-Type: text/html" . "\r\n" .
"\r\n" .
'<html>' .
' <head><title>Moved</title></head>' .
' <body><p>This page has moved.</p></body>' .
'</html>');

// Configuration des réponses successives


$adapter->addResponse(
"HTTP/1.1 200 OK" . "\r\n" .
"Content-Type: text/html" . "\r\n" .
"\r\n" .
'<html>' .
' <head><title>My Pet Store Home Page</title></head>' .
' <body><p>...</p></body>' .
'</html>');

// l'objet $client est prêt à être testé


// son comportement est déja configuré

La méthode setResponse() détruit toutes les réponses dans le buffer de


Zend_Http_Client_Adapter_Test et définit la première réponse qui sera retournée. La
méthode addResponse() définit les réponses suivantes.

Les réponses seront rejouées dans leur ordre d'ajout.

Dans l'exemple ci-dessus, l'adaptateur est configuré pour un scénario de test de redirections
302. En fonction de votre application, le suivi d'une redirection peut être ou non désiré. Dans
notre exemple, nous nous attendons à ce que la redirection soit suivie et nous configurons
notre adaptateur de tests pour ceci. La réponse de redirection originelle (302) est définie avec
la méthode setResponse(), quant à la réponse non redirigeante (200) suivante, elles est
définie avec la méthode addResponse(). Lorsque votre objet client est configuré, vous pouvez
l'injecter dans votre application à tester, et voir le résultat et les comportements.

If you need the adapter to fail on demand you can use setNextRequestWillFail($flag).
The method will cause the next call to connect() to throw an
Zend_Http_Client_Adapter_Exception exception. This can be useful when your
application caches content from an external site (in case the site goes down) and you want to
test this feature.

833
Zend_Http

Exemple 435. Forcing the adapter to fail

// Instantiate a new adapter and client


$adapter = new Zend_Http_Client_Adapter_Test();
$client = new Zend_Http_Client('http://www.example.com', array(
'adapter' => $adapter
));

// Force the next request to fail with an exception


$adapter->nextRequestWillFail(true);

try {
// This call will result in a Zend_Http_Client_Adapter_Exception
$client->request();
} catch (Zend_Http_Client_Adapter_Exception $e) {
// ...
}

// Further requests will work as expected until


// you call setNextRequestWillFail(true) again

3.6. Créer vos propres adaptateurs de connexion


Vous pouvez créer vos propres adaptateurs, si vous avez un besoin spécial à utiliser. Par
exemple, des possibilités de cache, ou des sockets persistantes.

Pour ceci, votre classe d'adaptateur doit implémenter l'interface


Zend_Http_Client_Adapter_Interface. L'exemple suivant montre un squelette de
classe. Toutes les méthodes publiques, ici, sont indispensables à la classe, elles sont issues
de l'interface :

834
* Définit le tableau de configuration pour cet adaptateur
*
* @param array $config
*/
Zend_Http
public function setConfig($config = array())
{
// Ceci change rarement, vous devriez copier l'implémentation
// présente dans Zend_Http_Client_Adapter_Socket.
Exemple 436. Création de votre propre adaptateur de connexion
}

/**
* Connecte à une serveur distant
*
* @param string $host
* @param int $port
* @param boolean $secure
*/
public function connect($host, $port = 80, $secure = false)
{
// Etablit la connexion au serveur
}

/**
* Envoie une requête au serveur
*
* @param string $method
* @param Zend_Uri_Http $url
* @param string $http_ver
* @param array $headers
* @param string $body
* @return string Request as text
*/
public function write($method,
$url,
$http_ver = '1.1',
$headers = array(),
$body = '')
{
// Envoie la requête au serveur distant. Cette fonction devrait
// retourner la requête complète (en-tête et corps) as a string
}

/**
* Lit la réponse du serveur
*
* @return string
*/
public function read()
{
// Lit la réponse du serveur distant, et la retourne sous forme
// de chaine de caractères
}

/**
* Ferme la connexion avec le serveur
*
*/
public function close()
{
// Ferme la connexion, appelée en dernière.
}
}

// Maintenant, vous pouvez utiliser cet adaptateur :


$client = new Zend_Http_Client(array(
'adapter' => 'MyApp_Http_Client_Adapter_BananaProtocol'
));

835
Zend_Http

4. Zend_Http_Cookie and Zend_Http_CookieJar


4.1. Introduction
Zend_Http_Cookie, comme son nom l'indique, est une classe qui représente un cookie HTTP.
Elle propose des méthodes d'analyse de la chaîne de réponse HTTP, de collection des cookies,
et d'accès à leurs propriétés. Il est aussi possible avec cette classe de vérifier si les paramètres
d'un cookie correspondent à un scénario précis, par exemple une URL spécifique, un certain
temps d'expiration, la présence ou non de HTTPS, etc...

Zend_Http_CookieJar est un objet utilisé en général avec Zend_Http_Client pour


fournir une collection d'objets Zend_Http_Cookie. L'idée principale est d'attacher un objet
Zend_Http_CookieJar à un objet Zend_Http_Client, de manière à ce que toutes les
requêtes de celui-ci utilisent les cookies présents dans l'objet CookieJar. Ainsi, lorsque le
client enverra une autre requête, il demandera à l'objet CookieJar tous les cookies concernant
cette requête. Ceci est très pratique dans des cas comme envoyer un cookie de session
entre plusieurs requêtes HTTP successives. De plus, l'objet Zend_Http_CookieJar peut être
sérialisé et mis en session.

4.2. Instancier des objets Zend_Http_Cookie


L'instanciation se fait de deux manières différentes :

• Via son constructeur, de cette façon : new Zend_Http_Cookie(string $name, string


$value, string $domain, [int $expires, [string $path, [boolean
$secure]]]);

• $name: Nom du cookie (par ex. "PHPSESSID") (requis)

• $value: La valeur du cookie (requis)

• $domain: Le domaine de validité du cookie (par ex. ".example.com") (requis)

• $expires: Temps d'expiration du cookie, un timestamp UNIX (optionnel, défaut à NULL).


Si non fourni, le cookie sera considéré comme "cookie de session", avec pas de temps
d'expiration.

• $path: Chemin de validité du cookie, par ex. "/foo/bar/" (optionnel, défaut : "/")

• $secure: Booléen, Si le cookie doit être transmis via connexion sécurisée (HTTPS)
uniquement (optionnel, défaut à FALSE)

• En appelant la méthode statique fromString(), avec une chaîne de caractères représentant


un cookie tel que défini dans les en-têtes HTTP "Set-Cookie" (réponse) ou "Cookie" (requête).
Dans ce cas la valeur du cookie doit être encodée. Lorsque la chaîne de caractères
représentant un cookie ne comporte pas de partie "domain", vous devez fournir alors un URI
selon lequel le cookie cherchera son domaine et son chemin.

836
Zend_Http

Exemple 437. Créer un objet Zend_Http_Cookie

// D'abord, en utilisant son constructeur.


// ce cookie expirera dans 2 heures
$cookie = new Zend_Http_Cookie('foo',
'bar',
'.example.com',
time() + 7200,
'/path');

// En prenant l'en-tête de réponse HTTP 'Set-Cookie'


// Ce cookie n'expirera pas et ne sera envoyé que
// sur des connexions sécurisées
$cookie = Zend_Http_Cookie::fromString(
'foo=bar; domain=.example.com; path=/path; secure');

// Si le domaine n'est pas présent, spécifiez le manuellement :


$cookie = Zend_Http_Cookie::fromString(
'foo=bar; secure;', 'http://www.example.com/path');

Lorsque vous utilisez la méthode statique


Zend_Http_Cookie::fromString(), veillez à fournir un cookie URL encodé
(tel que c'est le cas dans les en-têtes HTTP). Avec le constructeur en revanche,
il est nécessaire d'utiliser une valeur non encodée.

La manipulation inverse est possible. Grâce à la méthode __toString(), vous pouvez


récupérer une chaîne représentant le cookie, à partir de l'objet Zend_Http_Cookie. La chaîne
alors retournée est la même que celle utilisée dans l'en-tête HTTP "Cookie", à savoir une chaîne
encodée, terminée par un point-virgule (;) :

Exemple 438. Passer de l'objet Zend_Http_Cookie à la chaîne

// Création d'un nouveau cookie


$cookie = new Zend_Http_Cookie('foo',
'two words',
'.example.com',
time() + 7200,
'/path');

// Va afficher 'foo=two+words;' :
echo $cookie->__toString();

// Ceci est la même chose


echo (string) $cookie;

// En PHP 5.2 et plus, ceci fonctionne aussi :


echo $cookie;

4.3. Zend_Http_Cookie méthodes getter


Une fois l'objet Zend_Http_Cookie crée, il existe des méthodes 'getter' pour accéder aux
différentes propriétés du cookie :

• string getName(): Retourne le nom du cookie

• string getValue(): Retourne la valeur réelle (décodée), du cookie

837
Zend_Http

• string getDomain(): Retourne le domaine du cookie

• string getPath(): Retourne le chemin du cookie, par défaut '/'

• int getExpiryTime(): Retourne la date d'expiration, comme timestamp UNIX. Si pas de


date, NULL sera retourné.

Voici encore quelques méthodes de vérifications booléennes :

• boolean isSecure(): Regarde si le cookie est un cookie sécurisé. Si c'est le cas,


les navigateurs ont pour instruction de ne les envoyer que sur des connexions sécurisées
(HTTPS).

• boolean isExpired(int $time = null): Vérifie si le cookie est expirés. Si il n'y a pas
de date d'expiration, cette méthode retournera toujours TRUE. Si $time est fourni, alors la
date du cookie sera comparée à ce $time, et non plus au temps actuel.

• boolean isSessionCookie(): Vérifie si le cookie est un cookie dit 'de session'. C'est un
cookie sans date d'expiration, sensé être détruit à la fin de la session de travail actuelle (à la
fermeture du navigateur).

Exemple 439. Utilisation des méthodes getter de Zend_Http_Cookie

// Création d'un cookie


$cookie =
Zend_Http_Cookie::fromString('foo=two+words;'
. ' domain=.example.com;'
. ' path=/somedir;'
. 'secure;'
. 'expires=Wednesday, 28-Feb-05 20:41:22 UTC');

echo $cookie->getName(); // Affiche 'foo'


echo $cookie->getValue(); // Affiche 'two words'
echo $cookie->getDomain(); // Affiche '.example.com'
echo $cookie->getPath(); // Affiche '/'

echo date('Y-m-d', $cookie->getExpiryTime());


// Affiche '2005-02-28'

echo ($cookie->isExpired() ? 'Yes' : 'No');


// Affiche 'Yes'

echo ($cookie->isExpired(strtotime('2005-01-01') ? 'Yes' : 'No');


// Affiche 'No'

echo ($cookie->isSessionCookie() ? 'Yes' : 'No');


// Affiche 'No'

4.4. Zend_Http_Cookie: Correspondance de scénario


La vraie valeur ajoutée d'un objet Zend_Http_Cookie est sa méthode match(). Celle-ci teste
le cookie en rapport avec un scénario HTTP, pour savoir ci celui-ci doit être attaché à la requête
ou pas. La syntaxe est la suivante : boolean Zend_Http_Cookie->match(mixed $uri,
[boolean $matchSessionCookies, [int $now]]);

• mixed $uri : un objet Zend_Uri_Http avec un domaine et un chemin à vérifier. Une chaîne
représentant une URL peut aussi être utilisée. Le cookie sera déclaré bon si le schéma de
l'URL (HTTP ou HTTPS) correspond, ainsi que le chemin (path).

838
Zend_Http

• boolean $matchSessionCookies : établit ou non une correspondance pour les cookies


dits de session. Par défaut : TRUE. Si mis à FALSE, alors les cookies sans date d'expiration
seront ignorés du processus.

• int $now : timestamp UNIX passé pour vérifier l'expiration du cookie. Si non spécifié, alors
le temps actuel sera pris en considération.

Exemple 440. Correspondance de cookies

// Création de l'objet cookie - d'abord un cookie sécurisé


$cookie = Zend_Http_Cookie::fromString(
'foo=two+words; domain=.example.com; path=/somedir; secure;');

$cookie->match('https://www.example.com/somedir/foo.php');
// Retournera true

$cookie->match('http://www.example.com/somedir/foo.php');
// Retournera false, car la connexion n'est pas sécurisée

$cookie->match('https://otherexample.com/somedir/foo.php');
// Retournera false, le domaine est incorrect

$cookie->match('https://example.com/foo.php');
// Retournera false, le chemin est incorrect

$cookie->match('https://www.example.com/somedir/foo.php', false);
// Retournera false, car les cookies de session ne sont pas pris en compte

$cookie->match('https://sub.domain.example.com/somedir/otherdir/foo.php');
// Retournera true

// Création d'un autre objet cookie - cette fois non sécurisé,


// expire dans 2 heures
$cookie = Zend_Http_Cookie::fromString(
'foo=two+words; domain=www.example.com; expires='
. date(DATE_COOKIE, time() + 7200));

$cookie->match('http://www.example.com/');
// Retournera true

$cookie->match('https://www.example.com/');
// Will return true - non secure cookies can go
// over secure connexions as well!

$cookie->match('http://subdomain.example.com/');
// Retournera false, domaine incorrect

$cookie->match('http://www.example.com/', true, time() + (3 * 3600));


// Retournera false, car nous avons rajouter 3 heures au temps actuel

4.5. Classe Zend_Http_CookieJar : Instanciation


Dans la plupart des cas, il ne sera pas nécessaire d'instancier soi-même un objet
Zend_Http_CookieJar. Si vous voulez un conteneur de cookie (CookieJar) attaché à votre
objet Zend_Http_Client, appelez simplement Zend_Http_Client->setCookieJar(),
et un nouveau conteneur, vide, y sera attaché. Plus tard, vous pourrez utiliser la méthode
Zend_Http_Client->getCookieJar(), pour récupérer ce conteneur.

839
Zend_Http

Si vous voulez tout de même instancier manuellement un objet CookieJar, appelez son
constructeur avec "new Zend_Http_CookieJar()", sans paramètres. Sinon il est possible
aussi de passer par la méthode statique Zend_Http_CookieJar::fromResponse() qui
prend, elle, deux paramètres : un objet Zend_Http_Response et un URI de référence
(un objet Zend_Uri_Http ou une chaîne). Cette méthode retourne alors un objet
Zend_Http_CookieJar qui contiendra les cookies de la réponse HTTP passée. L'URI de
référence servira à remplir les paramètres "domain" et "path" des cookies, si jamais ils n'ont pas
été définis dans les en-têtes "Set-Cookie".

4.6. Ajouter des cookies à un objet Zend_Http_CookieJar


En temps normal, c'est l'objet Zend_Http_Client qui ajoutera des cookies dans l'objet
CookieJar que vous lui aurez attaché. Vous pouvez en ajouter manuellement aussi :

• Zend_Http_CookieJar->addCookie($cookie[, $ref_uri]): Ajoute un cookie au


conteneur (Jar). $cookie peut être soit un objet Zend_Http_Cookie, soit une chaîne qui sera
alors convertie de manière automatique en objet cookie. Si vous passez une chaîne, alors vous
devriez aussi passer le paramètre $ref_uri qui représente l'URI de référence pour déterminer
les paramètres "domain" et "path" du cookie.

• Zend_Http_CookieJar->addCookiesFromResponse($response, $ref_uri):
Ajoute tous les cookies présents dans une réponse HTTP au conteneur. La réponse HTTP doit
être un objet Zend_Http_Response contenant au moins un en-tête "Set-Cookie". $ref_uri
est un URI (un objet Zend_Uri_Http ou une chaîne), servant de référence pour remplir les
paramètres du cookie "domain" et "path", si ceux-ci ne sont pas trouvés dans la réponse.

4.7. Récupérer les cookies présents dans un objet


Zend_Http_CookieJar
Comme pour l'ajout de cookies, en théorie, vous n'aurez pas besoin de récupérer des cookies du
conteneur, car l'objet Zend_Http_Client se chargera de les gérer lui-même et de les envoyer
dans les bonnes requêtes. Cependant, il existe des méthodes pour récupérer des cookies depuis
un conteneur (Jar) : getCookie(), getAllCookies(), et getMatchingCookies(). De
plus, itérer sur le CookieJar vous permettra d'en extraire tous les objets Zend_Http_Cookie.

Il est important de noter que chacune de ces trois méthodes, prend un paramètre spécial destiné
à déterminer le type que chaque méthode retournera. Ce paramètre peut avoir 3 valeurs:

• Zend_Http_CookieJar::COOKIE_OBJECT: Retourne un objet Zend_Http_Cookie. Si


plus d'un cookie devait être retourné, il s'agira alors d'un tableau d'objets cookie.

• Zend_Http_CookieJar::COOKIE_STRING_ARRAY: Retourne les cookies comme des


chaînes de caractères dans un format "foo=bar", correspondant au format de l'en-tête de
requête HTTP "Cookie". Si plus d'un cookie devait être retourné, il s'agira alors d'un tableau
de chaînes.

• Zend_Http_CookieJar::COOKIE_STRING_CONCAT: Similaire à
COOKIE_STRING_ARRAY, mais si plusieurs cookies devaient être retournés, alors il ne
s'agira plus d'un tableau, mais d'une chaîne concaténant tous les cookies, séparés par des
point-virgule (;). Ceci est très utile pour passer tous les cookies d'un coup, dans l'en-tête HTTP
"Cookie".

Voici la structure des méthodes de récupération des cookies :

• Zend_Http_CookieJar->getCookie($uri, $cookie_name[, $ret_as]): Retourne


un cookie depuis le conteneur, selon son URI (domain et path), et son nom. $uri est

840
Zend_Http

un objet Zend_Uri_Http ou une chaîne. $cookie_name est une chaîne identifiant le


cookie en question. $ret_as spécifie le type de retour, comme vu plus haut (par défaut
COOKIE_OBJECT).

• Zend_Http_CookieJar->getAllCookies($ret_as): Retourne tous les cookies du


conteneur. $ret_as spécifie le type de retour, comme vu plus haut (par défaut
COOKIE_OBJECT).

• Zend_Http_CookieJar->getMatchingCookies($uri[,
$matchSessionCookies[, $ret_as[, $now]]]): Retourne tous les cookies ayant une
correspondance pour un scénario donné, à savoir un URI et une date d'expiration.

• $uri est soit un objet Zend_Uri_Http soit une chaîne.

• $matchSessionCookies est un booléen désignant si les cookies de session, c'est à dire


sans date d'expiration, doivent être analysés aussi pour établir une correspondance. Par
défaut : TRUE.

• $ret_as spécifie le type de retour, comme vu plus haut (par défaut COOKIE_OBJECT).

• $now est un entier représentant un timestamp UNIX à considérer comme 'maintenant'. Ainsi
tous les cookies expirant avant ce temps là, ne seront pas pris en compte. Si vous ne
spécifiez pas ce paramètre, alors c'est le temps actuel qui sera pris comme référence.
Vous pouvez en apprendre plus sur la correspondance des cookies ici : Section 4.4,
« Zend_Http_Cookie: Correspondance de scénario ».

5. Zend_Http_Response
5.1. Introduction
Zend_Http_Response fournit un accès simplifié aux réponses HTTP d'un message,
ainsi qu'un ensemble de méthodes statiques pour analyser ces réponses HTTP.
Habituellement Zend_Http_Response est utilisé en tant qu'objet retourné par une requête
Zend_Http_Client.

Dans la plupart des cas, un objet Zend_Http_Response sera instancié en utilisant la méthode
fromString(), qui lit une chaîne contenant une réponse HTTP, et retourne un nouvel objet
Zend_Http_Response :

Exemple 441. Instancier un objet Zend_Http_Response en utilisant la méthode


factory

$str = '';
$sock = fsockopen('www.exemple.com', 80);
$req = "GET / HTTP/1.1\r\n" .
"Host: www.exemple.com\r\n" .
"Connection: close\r\n" .
"\r\n";

fwrite($sock, $req);
while ($buff = fread($sock, 1024))
$str .= $sock;

$response = Zend_Http_Response::fromString($str);

Vous pouvez aussi utiliser le constructeur pour créer un nouvel objet de réponse HTTP, en
spécifiant tous les paramètres de la réponse :

841
Zend_Http

public function __construct($code, $headers, $body = null, $version =


'1.1', $message = null)

• $code : le code de la réponse HTTP (par ex. 200, 404, etc.)

• $headers : un tableau associatif d'en-têtes de réponse HTTP (par ex. "Host" =>
"exemple.com")

• $body : le corps de la réponse sous la forme d'une chaîne

• $version : la version de la réponse HTTP (habituellement 1.0 ou 1.1)

• $message : le message de la réponse HTTP (par ex. "OK", "Internal Server Error"). Si non
spécifié, le message sera paramétré suivant le code de la réponse.

5.2. Méthodes de tests booléennes


Une fois qu'un objet Zend_Http_Response est instancié, il fournit plusieurs méthodes qui
peuvent être utilisées pour tester le type de la réponse. Elles retournent toutes un booléen TRUE
ou FALSE :

• isSuccessful() : la requête est réussie ou non. Retourne true pour les codes de
réponses HTTP 1xx et 2xx.

• isError() : la requête implique une erreur ou non. Retourne true pour les codes de
réponses HTTP 4xx (erreurs du client) et 5xx (erreurs du serveur).

• isRedirect() : la requête est une redirection ou non. Retourne true pour les codes de
réponses HTTP 3xx.

Exemple 442. Utiliser la méthode isError() pour valider une réponse

if ($response->isError()) {
echo "Erreur de transmission des données.\n"
echo "Les infos Serveur sont : "
. $response->getStatus()
. " " . $response->getMessage()
. "\n";
}
// ... traiter la réponse ici ...

5.3. Méthodes accesseurs


Le but principal de l'objet réponse est de fournir un accès facile à divers paramètres de la
réponse.

• int getStatus() : récupère le code de la réponse HTTP (par ex. 200, 504, etc.)

• string getMessage() : récupère le message de la réponse HTTP (par ex. "Not Found",
"Authorization Required")

• string getBody() : récupère le corps complet décodé de la réponse HTTP

• string getRawBody() : récupère le corps brut, possiblement encodé, de la réponse HTTP.


Si le corps est encodé en utilisant l'encodage GZIP par exemple, il ne sera pas décodé.

• array getHeaders() : récupère les en-têtes de la réponse HTTP sous la forme d'un tableau
associatif (par ex. 'Content-type' => 'text/html')

842
Zend_Http

• string|array getHeader($header) : récupère un en-tête spécifique de la réponse


HTTP, spécifié par $header

• string getHeadersAsString($status_line = true, $br = "\n") : récupère


l'ensemble des en-têtes sous la forme d'une chaîne. Si $status_line est à TRUE (défaut),
la première ligne de statut (par ex. "HTTP/1.1 200 OK") sera aussi retournée. Les lignes sont
coupées avec le paramètre $br (par ex. "<br />")

• string asString($br = "\n") : récupère la réponse complète sous la forme d'une


chaîne. Les lignes sont coupées avec le paramètre $br (par ex. "<br />"). Vous pouvez aussi
utiliser la méthode magique __toString() lors du cast de l'objet en chaîne de caractère.
Ce sera alors proxié vers asString().

Exemple 443. Utiliser les méthodes accesseurs de Zend_Http_Response

if ($response->getStatus() == 200) {
echo "La requête retourne les informations suivantes :<br />";
echo $response->getBody();
} else {
echo "Une erreur est apparue lors de la recherche des données :<br />";
echo $response->getStatus() . ": " . $response->getMessage();
}

Vérifier toujours la valeur retournée


Puisqu'une réponse peut contenir plusieurs exemplaires du même en-tête, la
méthode getHeader() et la méthode getHeaders() peuvent renvoyer l'un
comme l'autre soit une chaîne seule, soit un tableau de chaînes pour chaque
en-tête. Vous devez donc toujours vérifier si la valeur retournée est une chaîne
ou un tableau.

Exemple 444. Accéder aux en-têtes de réponse

$ctype = $response->getHeader('Content-type');
if (is_array($ctype)) $ctype = $ctype[0];

$body = $response->getBody();
if ($ctype == 'text/html' || $ctype == 'text/xml') {
$body = htmlentities($body);
}

echo $body;

5.4. Analyseurs statiques de réponse HTTP


La classe Zend_Http_Response inclut également plusieurs méthodes utilisées en interne pour
traiter et analyser des messages de réponse HTTP. Ces méthodes sont toutes exposées en tant
que méthodes statiques, ce qui permet de les utiliser extérieurement, ainsi il n'est pas nécessaire
d'instancier un objet réponse si vous souhaitez extraire une partie spécifique de la réponse.

• int Zend_Http_Response::extractCode($response_str) : extrait et retourne le


code de la réponse HTTP (par ex. 200 ou 404) issu de$response_str

• string Zend_Http_Response::extractMessage($response_str) : extrait et


retourne le message de la réponse HTTP (par ex. "OK" ou "File Not Found") issu de
$response_str

843
Zend_Http

• string Zend_Http_Response::extractVersion($response_str) : extrait et


retourne la version HTTP (par ex. 1.1 or 1.0) issue de $response_str

• array Zend_Http_Response::extractHeaders($response_str) : extrait et


retourne les en-têtes de la réponse HTTP issus de $response_str sous la forme d'un
tableau

• string Zend_Http_Response::extractBody($response_str) : extrait et retourne


le corps de la réponse HTTP issu de $response_str

• string Zend_Http_Response::responseCodeAsText($code = null, $http11


= true) : récupère le message standard de la réponse HTTP pour le code $code. Par
exemple, la méthode retournera "Internal Server Error" si $code vaut 500. Si $http11 vaut
TRUE (valeur par défaut), la méthode retournera les messages standards HTTP/1.1 - sinon les
messages HTTP/1.0 seront retournés. Si $code n'est pas spécifié, cette méthode retournera
tous les codes de réponse HTTP connus sous la forme d'un tableau associatif (code =>
message).

Indépendamment des méthodes d'analyse, la classe inclut également un ensemble de


décodeurs pour les encodages de transfert de réponse HTTP communs :

• string Zend_Http_Response::decodeChunkedBody($body): décode un corps


complet de type "Content-Transfer-Encoding: Chunked"

• string Zend_Http_Response::decodeGzip($body) : décode un corps de type


"Content-Encoding: gzip"

• string Zend_Http_Response::decodeDeflate($body) : décode un corps de type


"Content-Encoding: deflate"

844
Zend_InfoCard
1. Introduction
The Zend_InfoCard component implements relying-party support for Information Cards.
Information Cards are used for identity management on the internet and authentication of users
to web sites. The web sites that the user ultimately authenticates to are called relying-parties.

Detailed information about information cards and their importance to the internet identity
metasystem can be found on the IdentityBlog.

1.1. Basic Theory of Usage


Usage of Zend_InfoCard can be done one of two ways: either as part of the larger Zend_Auth
component via the Zend_InfoCard authentication adapter or as a stand-alone component. In
both cases an information card can be requested from a user by using the following HTML block
in your HTML login form:

<form action="http://example.com/server" method="POST">


<input type='image' src='/images/ic.png' align='center'
width='120px' style='cursor:pointer' />
<object type="application/x-informationCard"
name="xmlToken">
<param name="tokenType"
value="urn:oasis:names:tc:SAML:1.0:assertion" />
<param name="requiredClaims"
value="http://.../claims/privatepersonalidentifier
http://.../claims/givenname
http://.../claims/surname" />
</object>
</form>

In the example above, the requiredClaims <param> tag is used to identify pieces of
information known as claims (i.e. person's first name, last name) which the web site (a.k.a "relying
party") needs in order a user to authenticate using an information card. For your reference, the
full URI (for instance the givenname claim) is as follows: http://schemas.xmlsoap.org/
ws/2005/05/identity/claims/givenname

When the above HTML is activated by a user (clicks on it), the browser will bring up a card
selection program which not only shows them which information cards meet the requirements of
the site, but also allows them to select which information card to use if multiple meet the criteria.
This information card is transmitted as an XML document to the specified POST URL and is
ready to be processed by the Zend_InfoCard component.

Note, Information cards can only be HTTP POSTed to SSL-encrypted URLs. Please consult your
web server's documentation on how to set up SSL encryption.

1.2. Using as part of Zend_Auth


In order to use the component as part of the Zend_Auth authentication system, you must
use the provided Zend_Auth_Adapter_InfoCard to do so (not available in the standalone
Zend_InfoCard distribution). An example of its usage is shown below:

845
Zend_InfoCard

<?php
if (isset($_POST['xmlToken'])) {

$adapter = new Zend_Auth_Adapter_InfoCard($_POST['xmlToken']);

$adapter->addCertificatePair('/usr/local/Zend/apache2/conf/server.key',
'/usr/local/Zend/apache2/conf/server.crt');

$auth = Zend_Auth::getInstance();

$result = $auth->authenticate($adapter);

switch ($result->getCode()) {
case Zend_Auth_Result::SUCCESS:
$claims = $result->getIdentity();
print "Given Name: {$claims->givenname}<br />";
print "Surname: {$claims->surname}<br />";
print "Email Address: {$claims->emailaddress}<br />";
print "PPI: {$claims->getCardID()}<br />";
break;
case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
print "The Credential you provided did not pass validation";
break;
default:
case Zend_Auth_Result::FAILURE:
print "There was an error processing your credentials.";
break;
}

if (count($result->getMessages()) > 0) {
print "<pre>";
var_dump($result->getMessages());
print "</pre>";
}

}
?>
<hr />
<div id="login" style="font-family: arial; font-size: 2em;">
<p>Simple Login Demo</p>
<form method="post">
<input type="submit" value="Login" />
<object type="application/x-informationCard" name="xmlToken">
<param name="tokenType"
value="urn:oasis:names:tc:SAML:1.0:assertion" />
<param name="requiredClaims"
value="http://.../claims/givenname
http://.../claims/surname
http://.../claims/emailaddress
http://.../claims/privatepersonalidentifier" />
</object>
</form>
</div>

In the example above, we first create an instance of the Zend_Auth_Adapter_InfoCard and


pass the XML data posted by the card selector into it. Once an instance has been created you
must then provide at least one SSL certificate public/private key pair used by the web server
that received the HTTP POST. These files are used to validate the destination of the information
posted to the server and are a requirement when using Information Cards.

846
Zend_InfoCard

Once the adapter has been configured, you can then use the standard Zend_Auth facilities to
validate the provided information card token and authenticate the user by examining the identity
provided by the getIdentity() method.

1.3. Using the Zend_InfoCard component standalone


It is also possible to use the Zend_InfoCard component as a standalone component by
interacting with the Zend_InfoCard class directly. Using the Zend_InfoCard class is very
similar to its use with the Zend_Auth component. An example of its use is shown below:

<?php
if (isset($_POST['xmlToken'])) {
$infocard = new Zend_InfoCard();
$infocard->addCertificatePair('/usr/local/Zend/apache2/conf/server.key',
'/usr/local/Zend/apache2/conf/server.crt');

$claims = $infocard->process($_POST['xmlToken']);

if($claims->isValid()) {
print "Given Name: {$claims->givenname}<br />";
print "Surname: {$claims->surname}<br />";
print "Email Address: {$claims->emailaddress}<br />";
print "PPI: {$claims->getCardID()}<br />";
} else {
print "Error Validating identity: {$claims->getErrorMsg()}";
}
}
?>
<hr />
<div id="login" style="font-family: arial; font-size: 2em;">
<p>Simple Login Demo</p>
<form method="post">
<input type="submit" value="Login" />
<object type="application/x-informationCard" name="xmlToken">
<param name="tokenType"
value="urn:oasis:names:tc:SAML:1.0:assertion" />
<param name="requiredClaims"
value="http://.../claims/givenname
http://.../claims/surname
http://.../claims/emailaddress
http://.../claims/privatepersonalidentifier" />
</object>
</form>
</div>

In the example above, we use the Zend_InfoCard component independently to validate the
token provided by the user. As was the case with the Zend_Auth_Adapter_InfoCard, we
create an instance of Zend_InfoCard and then set one or more SSL certificate public/private
key pairs used by the web server. Once configured, we can use the process() method to
process the information card and return the results.

1.4. Working with a Claims object


Regardless of whether the Zend_InfoCard component is used as a standalone component
or as part of Zend_Auth via Zend_Auth_Adapter_InfoCard, the ultimate result of the
processing of an information card is a Zend_InfoCard_Claims object. This object contains
the assertions (a.k.a. claims) made by the submitting user based on the data requested by

847
Zend_InfoCard

your web site when the user authenticated. As shown in the examples above, the validity of
the information card can be ascertained by calling the Zend_InfoCard_Claims::isValid()
method. Claims themselves can either be retrieved by simply accessing the identifier desired
(i.e. givenname) as a property of the object or through the getClaim() method.

In most cases you will never need to use the getClaim() method. However, if your
requiredClaims mandate that you request claims from multiple different sources/namespaces
then you will need to extract them explicitly using this method (simply pass it the full URI of the
claim to retrieve its value from within the information card). Generally speaking however, the
Zend_InfoCard component will set the default URI for claims to be the one used the most
frequently within the information card itself and the simplified property-access method can be
used.

As part of the validation process, it is the developer's responsibility to examine the issuing
source of the claims contained within the information card and to decide if that source is
a trusted source of information. To do so, the getIssuer() method is provided within the
Zend_InfoCard_Claims object which returns the URI of the issuer of the information card
claims.

1.5. Attaching Information Cards to existing accounts


It is possible to add support for information cards to an existing authentication system by
storing the private personal identifier (PPI) to a previously traditionally-authenticated account and
including at least the http://schemas.xmlsoap.org/ws/2005/05/identity/claims/
privatepersonalidentifier claim as part of the requiredClaims of the request. If this
claim is requested then the Zend_InfoCard_Claims object will provide a unique identifier for
the specific card that was submitted by calling the getCardID() method.

An example of how to attach an information card to an existing traditional-authentication account


is shown below:

// ...
public function submitinfocardAction()
{
if (!isset($_REQUEST['xmlToken'])) {
throw new ZBlog_Exception('Expected an encrypted token ' .
'but was not provided');
}

$infoCard = new Zend_InfoCard();


$infoCard->addCertificatePair(SSL_CERTIFICATE_PRIVATE,
SSL_CERTIFICATE_PUB);

try {
$claims = $infoCard->process($request['xmlToken']);
} catch(Zend_InfoCard_Exception $e) {
// TODO Error processing your request
throw $e;
}

if ($claims->isValid()) {
$db = ZBlog_Data::getAdapter();

$ppi = $db->quote($claims->getCardID());
$fullname = $db->quote("{$claims->givenname} {$claims->surname}");

$query = "UPDATE blogusers

848
Zend_InfoCard

SET ppi = $ppi,


real_name = $fullname
WHERE username='administrator'";

try {
$db->query($query);
} catch(Exception $e) {
// TODO Failed to store in DB
}

$this->view->render();
return;
} else {
throw new
ZBlog_Exception("Infomation card failed security checks");
}
}

1.6. Creating Zend_InfoCard Adapters


The Zend_InfoCard component was designed to allow for growth in the information card
standard through the use of a modular architecture. At this time, many of these hooks are unused
and can be ignored, but there is one class that should be written for any serious information card
implementation: the Zend_InfoCard adapter.

The Zend_InfoCard adapter is used as a callback mechanism within the component to perform
various tasks, such as storing and retrieving Assertion IDs for information cards when they are
processed by the component. While storing the assertion IDs of submitted information cards
is not necessary, failing to do so opens up the possibility of the authentication scheme being
compromised through a replay attack.

To prevent this, one must implement the Zend_InfoCard_Adapter_Interface and set an


instance of this interface prior to calling either the process() (standalone) or authenticate()
method as a Zend_Auth adapter. To set this interface, the setAdapter() method should be
used. In the example below, we set a Zend_InfoCard adapter and use it in our application:

class myAdapter implements Zend_InfoCard_Adapter_Interface


{
public function storeAssertion($assertionURI,
$assertionID,
$conditions)
{
/* Store the assertion and its conditions by ID and URI */
}

public function retrieveAssertion($assertionURI, $assertionID)


{
/* Retrieve the assertion by URI and ID */
}

public function removeAssertion($assertionURI, $assertionID)


{
/* Delete a given assertion by URI/ID */
}
}

$adapter = new myAdapter();

849
Zend_InfoCard

$infoCard = new Zend_InfoCard();


$infoCard->addCertificatePair(SSL_PRIVATE, SSL_PUB);
$infoCard->setAdapter($adapter);

$claims = $infoCard->process($_POST['xmlToken']);

850
Zend_Json
1. Introduction
Zend_Json fournit des méthodes pratiques permettant de convertir du code PHP natif en
notation JSON, et vice versa. Pour plus d'informations concernant JSON, visitez le site du projet
JSON.

La notation JSON (JavaScript Object Notation [Ndt : Notation-Objet JavaScript]) peut être utilisée
comme un système d'échange de données entre JavaScript et d'autres langages. Comme la
notation JSON peut être évaluée directement par JavaScript, c'est une alternative plus simple
que XML pour les interfaces AJAX.

De plus, Zend_Json fournit une manière utile pour convertir n'importe quel chaîne arbitraire
formatée en XML en une chaîne formatée en JSON. Cette caractéristique permettra aux
développeurs PHP de transformer les données encodées en format XML en un format JSON
avant de l'envoyer aux navigateurs basés sur des applications client Ajax. Zend_Json fournit
une fonction facilitant la conversion de données dynamiques du code côté serveur évitant ainsi
l'analyse syntaxique inutile réalisée dans les applications côté client. Il offre une fonction utilitaire
agréable qui aboutit aux techniques plus simples de traitement de données d'applications
spécifiques.

2. Utilisation de base
L'utilisation de Zend_Json implique l'emploi des deux méthodes statiques publiques
disponibles : Zend_Json::encode() et Zend_Json::decode().

// Obtention d'une valeur


$phpNatif = Zend_Json::decode($valeurCodee);

// Codage pour renvoi au client :


$json = Zend_Json::encode($phpNatif);

2.1. Pretty-printing JSON


Sometimes, it may be hard to explore JSON data generated by Zend_Json::encode(), since
it has no spacing or indentation. In order to make it easier, Zend_Json allows you to pretty-print
JSON data in the human-readable format with Zend_Json::prettyPrint().

// Encode it to return to the client:


$json = Zend_Json::encode($phpNative);
if($debug) {
echo Zend_Json::prettyPrint($json, array("indent" => " "));
}

Second optional argument of Zend_Json::prettyPrint() is an option array. Option indent


allows to set indentation string - by default it's a single tab character.

851
Zend_Json

3. Utilisation avancée de Zend_Json


3.1. Objets JSON
Lorsque vous encodez des objets PHP en tant que JSON, toutes les propriétés publiques de cet
objet sont encodées dans un objet JSON.

JSON ne vous permet pas de référencer des objets, donc le soin devra être pris pour
ne pas coder des objets avec des références récursives. Si vous avez des problèmes
de récursivité, Zend_Json::encode() et Zend_Json_Encoder::encode() autorisent un
deuxième paramètre facultatif afin de vérifier la récursivité ; si un objet est sérialisé deux fois,
une exception sera levée.

Bien que les objets Javascript correspondent de très près aux tableau associatifs de PHP,
décoder des objets JSON pose une légère difficulté. Certains suggèrent qu'un identifiant de
classe soit passé, et qu'une instance de cette classe soit créée et définie avec les paires clé/
valeur des objets JSON ; d'autres pensent que cela pourrait poser un risque de sécurité potentiel.

Par défaut, Zend_Json décodera des objets JSON comme en tableaux associatifs. Cependant,
si vous désirez avoir un objet en retour, vous pouvez le spécifier :

// Décode des objets JSON en tant qu'objets PHP


$phpNatif = Zend_Json::decode($valeurEncodee, Zend_Json::TYPE_OBJECT);

Tous les objets sont ainsi décodés et retournés comme des objets de type StdClass, avec
leurs propriétés correspondantes aux paires clé/valeur de la notation JSON.

La recommandation de Zend Framework est que le développeur doit décider comment décoder
les objets JSON. Si un objet d'un type spécifié doit être créé, il peut être créé dans le code du
développeur et définit avec les valeurs décodées en utilisant Zend_Json.

3.2. Encoding PHP objects


If you are encoding PHP objects by default the encoding mechanism can only access public
properties of these objects. When a method toJson() is implemented on an object to encode,
Zend_Json calls this method and expects the object to return a JSON representation of its
internal state.

3.3. Internal Encoder/Decoder


Zend_Json has two different modes depending if ext/json is enabled in your PHP installation or
not. If ext/json is installed by default json_encode() and json_decode() functions are used
for encoding and decoding JSON. If ext/json is not installed a Zend Framework implementation
in PHP code is used for en-/decoding. This is considerably slower than using the php extension,
but behaves exactly the same.

Still sometimes you might want to use the internal encoder/decoder even if you have ext/json
installed. You can achieve this by calling:

Zend_Json::$useBuiltinEncoderDecoder = true:

3.4. JSON Expressions


Javascript makes heavy use of anonymnous function callbacks, which can be saved within JSON
object variables. Still they only work if not returned inside double qoutes, which Zend_Json

852
Zend_Json

naturally does. With the Expression support for Zend_Json support you can encode JSON
objects with valid javascript callbacks. This works for both json_encode() or the internal
encoder.

A javascript callback is represented using the Zend_Json_Expr object. It implements the value
object pattern and is immutable. You can set the javascript expression as the first constructor
argument. By default Zend_Json::encode does not encode javascript callbacks, you have to
pass the option 'enableJsonExprFinder' = true into the encode function. If enabled the
expression support works for all nested expressions in large object structures. A usage example
would look like:

$data = array(
'onClick' => new Zend_Json_Expr('function() {'
. 'alert("I am a valid javascript callback '
. 'created by Zend_Json"); }'),
'other' => 'no expression',
);
$jsonObjectWithExpression = Zend_Json::encode(
$data,
false,
array('enableJsonExprFinder' => true)
);

4. XML to JSON conversion


Zend_Json fournit une méthode de convenance pour transformer des données au format XML
en un format JSON. Ce dispositif est inspiré d'un article de developerWorks d'IBM.

Zend_Json inclut une fonction statique appelée Zend_Json::fromXml(). Cette fonction


produira du JSON à partir d'une entrée au format XML. Cette fonction prend n'importe quelle
chaîne arbitraire XML comme paramètre d'entrée. Elle prend également un paramètre booléen
facultatif d'entrée pour informer la logique de conversion d'ignorer ou non les attributs XML
pendant le processus de conversion. Si ce paramètre facultatif d'entrée n'est pas donné, alors
le comportement par défaut est d'ignorer les attributs XML. Cet appel de fonction est réalisé
comme ceci :

// la fonction fromXml prend simplement une chaîne


// contenant le XML comme entrée
$jsonContents = Zend_Json::fromXml($xmlStringContents, true);

La fonction Zend_Json::fromXml() fait la conversion du paramètre d'entrée (chaîne au


format XML) et renvoie le rendu équivalent sous forme de chaîne au format JSON. En cas
d'erreur, de format XML ou de logique de conversion, cette fonction lèvera une exception. La
logique de conversion emploie également des techniques récursives à travers l'arbre XML. Il
supporte la récursivité jusqu'à 25 niveaux de profondeur. Au delà de cette profondeur, elle
lèvera une Zend_Json_Exception. Il y a plusieurs fichiers XML, avec différents niveaux de
complexité, fournis dans le répertoire tests de Zend Framework. Ils peuvent être utilisés pour
tester la fonctionnalité du dispositif xml2json.

Ce qui suit est un exemple simple qui montre à la fois la chaîne XML fournie et la chaîne JSON
retournée en résultat de la fonction Zend_Json::fromXml(). Cet exemple utilise le paramètre
facultatif pour ne pas ignorer les attributs XML pendant la conversion. Par conséquent, vous
pouvez noter que la chaîne résultante JSON inclut une représentation des attributs XML actuels
de la chaîne XML fournie.

853
Zend_Json

Chaîne XML fournie à la fonction Zend_Json::fromXml() :

<?xml version="1.0" encoding="UTF-8"?>


<books>
<book id="1">
<title>Code Generation in Action</title>
<author><first>Jack</first><last>Herrington</last></author>
<publisher>Manning</publisher>
</book>

<book id="2">
<title>PHP Hacks</title>
<author><first>Jack</first><last>Herrington</last></author>
<publisher>O'Reilly</publisher>
</book>

<book id="3">
<title>Podcasting Hacks</title>
<author><first>Jack</first><last>Herrington</last></author>
<publisher>O'Reilly</publisher>
</book>
</books>

Chaîne JSON retournée par la fonction Zend_Json::fromXml() :

{
"books" : {
"book" : [ {
"@attributes" : {
"id" : "1"
},
"title" : "Code Generation in Action",
"author" : {
"first" : "Jack", "last" : "Herrington"
},
"publisher" : "Manning"
}, {
"@attributes" : {
"id" : "2"
},
"title" : "PHP Hacks", "author" : {
"first" : "Jack", "last" : "Herrington"
},
"publisher" : "O'Reilly"
}, {
"@attributes" : {
"id" : "3"
},
"title" : "Podcasting Hacks", "author" : {
"first" : "Jack", "last" : "Herrington"
},
"publisher" : "O'Reilly"
}
]}
}

Plus de détails au sujet de ce dispositif xml2json peuvent être trouvés dans la proposition
originale elle-même. Jetez un oeil à la proposition Zend_xml2json.

854
Zend_Json

5. Zend_Json_Server - JSON-RPC server


Zend_Json_Server is a JSON-RPC server implementation. It supports both the JSON-RPC
version 1 specification as well as the version 2 specification; additionally, it provides a PHP
implementation of the Service Mapping Description (SMD) specification for providing service
metadata to service consumers.

JSON-RPC is a lightweight Remote Procedure Call protocol that utilizes JSON for its messaging
envelopes. This JSON-RPC implementation follows PHP's SoapServer API. This means, in a
typical situation, you will simply:

• Instantiate the server object

• Attach one or more functions and/or classes/objects to the server object

• handle() the request

Zend_Json_Server utilizes Section 2, « Zend_Server_Reflection » to perform reflection on


any attached classes or functions, and uses that information to build both the SMD and enforce
method call signatures. As such, it is imperative that any attached functions and/or class methods
have full PHP docblocks documenting, minimally:

• All parameters and their expected variable types

• The return value variable type

Zend_Json_Server listens for POST requests only at this time; fortunately, most JSON-RPC
client implementations in the wild at the time of this writing will only POST requests as it is. This
makes it simple to utilize the same server end point to both handle requests as well as to deliver
the service SMD, as is shown in the next example.

855
* Calculator - sample class to expose via JSON-RPC
*/
First,
classlet's define a class we wish to expose via the JSON-RPC server. We'll call the class
Calculator
'Calculator',
{ and define methodsZend_Json
for 'add', 'subtract', 'multiply', and 'divide':
/**
* Return sum of two variables
*
Exemple
* @param 445.int
Zend_Json_Server
$x Usage
* @param int $y
* @return int
*/
public function add($x, $y)
{
return $x + $y;
}

/**
* Return difference of two variables
*
* @param int $x
* @param int $y
* @return int
*/
public function subtract($x, $y)
{
return $x - $y;
}

/**
* Return product of two variables
*
* @param int $x
* @param int $y
* @return int
*/
public function multiply($x, $y)
{
return $x * $y;
}
$server
/** =
$server = new
new Zend_Json_Server();
Zend_Json_Server();
$server->setClass('Calculator');
* Return the division of two variables
However, this will not address the issue of returning an SMD so that the JSON-RPC client
// Indicate
* what functionality is available:
can
if autodiscover
('GET' methods. That can be accomplished
== $_SERVER['REQUEST_METHOD'])
$server->setClass('Calculator'); { by determining the HTTP request
* @param int $x
method,
//
Now we'll and then
Indicate specifying
create aint
* @param the URL some server
endpoint, metadata:
and
script$yto handle the requests:the JSON-RPC version used:
$server->setTarget('/json-rpc.php')
// Handle the request:
* @return float
->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
$server->handle();
*/
Note that each method has a docblock with entries indicating each parameter and its
public function divide($x, $y)
type,//
{as Grab
well as
theanSMDentry for the return value. This is absolutely critical when utilizing
$smdreturn $x /or $y;
any other server component in Zend Framework, for that matter.
= $server->getServiceMap();
Zend_Json_Server
$server = new Zend_Json_Server();
}
$server->setClass('Calculator');
} // Return the SMD to the client
header('Content-Type: application/json');
If
ifutilizing
('GET' the
== JSON-RPC server with Dojo toolkit,
$_SERVER['REQUEST_METHOD']) { you will also need to set a special
echo $smd;
compatibility flag to ensure that the
$server->setTarget('/json-rpc.php')
return; two interoperate properly:
} ->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
$smd = $server->getServiceMap();
$server->handle();
// Set Dojo compatibility:
$smd->setDojoCompatible(true);

header('Content-Type: application/json');
echo $smd;
return;
}

$server->handle();

856
Zend_Json

5.1. Advanced Details


While most functionality for Zend_Json_Server is spelled out in Exemple 445,
« Zend_Json_Server Usage », more advanced functionality is available.

5.1.1. Zend_Json_Server
Zend_Json_Server is the core class in the JSON-RPC offering; it handles all requests and
returns the response payload. It has the following methods:

• addFunction($function): Specify a userland function to attach to the server.

• setClass($class): Specify a class or object to attach to the server; all public methods of
that item will be exposed as JSON-RPC methods.

• fault($fault = null, $code = 404, $data = null): Create and return a


Zend_Json_Server_Error object.

• handle($request = false): Handle a JSON-RPC request; optionally, pass a


Zend_Json_Server_Request object to utilize (creates one by default).

• getFunctions(): Return a list of all attached methods.

• setRequest(Zend_Json_Server_Request $request): Specify a request object for the


server to utilize.

• getRequest(): Retrieve the request object used by the server.

• setResponse(Zend_Json_Server_Response $response): Set the response object for


the server to utilize.

• getResponse(): Retrieve the response object used by the server.

• setAutoEmitResponse($flag): Indicate whether the server should automatically emit the


response and all headers; by default, this is TRUE.

• autoEmitResponse(): Determine if auto-emission of the response is enabled.

• getServiceMap(): Retrieve the service map description in the form of a


Zend_Json_Server_Smd object

5.1.2. Zend_Json_Server_Request
The JSON-RPC request environment is encapsulated in the Zend_Json_Server_Request
object. This object allows you to set necessary portions of the JSON-RPC request, including the
request ID, parameters, and JSON-RPC specification version. It has the ability to load itself via
JSON or a set of options, and can render itself as JSON via the toJson() method.

The request object has the following methods available:

• setOptions(array $options): Specify object configuration. $options may contain keys


matching any 'set' method: setParams(), setMethod(), setId(), and setVersion().

• addParam($value, $key = null): Add a parameter to use with the method call.
Parameters can be just the values, or can optionally include the parameter name.

• addParams(array $params): Add multiple parameters at once; proxies to addParam()

857
Zend_Json

• setParams(array $params): Set all parameters at once; overwrites any existing


parameters.

• getParam($index): Retrieve a parameter by position or name.

• getParams(): Retrieve all parameters at once.

• setMethod($name): Set the method to call.

• getMethod(): Retrieve the method that will be called.

• isMethodError(): Determine whether or not the request is malformed and would result in
an error.

• setId($name): Set the request identifier (used by the client to match requests to responses).

• getId(): Retrieve the request identifier.

• setVersion($version): Set the JSON-RPC specification version the request conforms to.
May be either '1.0' or '2.0'.

• getVersion(): Retrieve the JSON-RPC specification version used by the request.

• loadJson($json): Load the request object from a JSON string.

• toJson(): Render the request as a JSON string.

An HTTP specific version is available via Zend_Json_Server_Request_Http. This class


will retrieve the request via php://input, and allows access to the raw JSON via the
getRawJson() method.

5.1.3. Zend_Json_Server_Response
The JSON-RPC response payload is encapsulated in the Zend_Json_Server_Response
object. This object allows you to set the return value of the request, whether or not the response
is an error, the request identifier, the JSON-RPC specification version the response conforms
to, and optionally the service map.

The response object has the following methods available:

• setResult($value): Set the response result.

• getResult(): Retrieve the response result.

• setError(Zend_Json_Server_Error $error): Set an error object. If set, this will be


used as the response when serializing to JSON.

• getError(): Retrieve the error object, if any.

• isError(): Whether or not the response is an error response.

• setId($name): Set the request identifier (so the client may match the response with the
original request).

• getId(): Retrieve the request identifier.

• setVersion($version): Set the JSON-RPC version the response conforms to.

• getVersion(): Retrieve the JSON-RPC version the response conforms to.

858
Zend_Json

• toJson(): Serialize the response to JSON. If the response is an error response, serializes
the error object.

• setServiceMap($serviceMap): Set the service map object for the response.

• getServiceMap(): Retrieve the service map object, if any.

An HTTP specific version is available via Zend_Json_Server_Response_Http. This class


will send the appropriate HTTP headers as well as serialize the response as JSON.

5.1.4. Zend_Json_Server_Error
JSON-RPC has a special format for reporting error conditions. All errors need to provide,
minimally, an error message and error code; optionally, they can provide additional data, such
as a backtrace.

Error codes are derived from those recommended by the XML-RPC EPI project.
Zend_Json_Server appropriately assigns the code based on the error condition. For
application exceptions, the code '-32000' is used.

Zend_Json_Server_Error exposes the following methods:

• setCode($code): Set the error code; if the code is not in the accepted XML-RPC error code
range, -32000 will be assigned.

• getCode(): Retrieve the current error code.

• setMessage($message): Set the error message.

• getMessage(): Retrieve the current error message.

• setData($data): Set auxiliary data further qualifying the error, such as a backtrace.

• getData(): Retrieve any current auxiliary error data.

• toArray(): Cast the error to an array. The array will contain the keys 'code', 'message', and
'data'.

• toJson(): Cast the error to a JSON-RPC error representation.

5.1.5. Zend_Json_Server_Smd
SMD stands for Service Mapping Description, a JSON schema that defines how a client can
interact with a particular web service. At the time of this writing, the specification has not yet been
formally ratified, but it is in use already within Dojo toolkit as well as other JSON-RPC consumer
clients.

At its most basic, a Service Mapping Description indicates the method of transport (POST,
GET, TCP/IP, etc), the request envelope type (usually based on the protocol of the server), the
target URL of the service provider, and a map of services available. In the case of JSON-RPC,
the service map is a list of available methods, which each method documenting the available
parameters and their types, as well as the expected return value type.

Zend_Json_Server_Smd provides an object oriented way to build service maps. At its most
basic, you pass it metadata describing the service using mutators, and specify services (methods
and functions).

859
Zend_Json

The service descriptions themselves are typically instances of


Zend_Json_Server_Smd_Service; you can also pass all information as an array to the
various service mutators in Zend_Json_Server_Smd, and it will instantiate a service object
for you. The service objects contain information such as the name of the service (typically the
function or method name), the parameters (names, types, and position), and the return value
type. Optionally, each service can have its own target and envelope, though this functionality
is rarely used.

Zend_Json_Server actually does all of this behind the scenes for you, by using reflection on
the attached classes and functions; you should create your own service maps only if you need
to provide custom functionality that class and function introspection cannot offer.

Methods available in Zend_Json_Server_Smd include:

• setOptions(array $options): Setup an SMD object from an array of options. All


mutators (methods beginning with 'set') can be used as keys.

• setTransport($transport): Set the transport used to access the service; only POST is
currently supported.

• getTransport(): Get the current service transport.

• setEnvelope($envelopeType): Set the request envelope that should be used to access


the service. Currently, supports the constants Zend_Json_Server_Smd::ENV_JSONRPC_1
and Zend_Json_Server_Smd::ENV_JSONRPC_2.

• getEnvelope(): Get the current request envelope.

• setContentType($type): Set the content type requests should use (by default, this is
'application/json').

• getContentType(): Get the current content type for requests to the service.

• setTarget($target): Set the URL endpoint for the service.

• getTarget(): Get the URL endpoint for the service.

• setId($id): Typically, this is the URL endpoint of the service (same as the target).

• getId(): Retrieve the service ID (typically the URL endpoint of the service).

• setDescription($description): Set a service description (typically narrative


information describing the purpose of the service).

• getDescription(): Get the service description.

• setDojoCompatible($flag): Set a flag indicating whether or not the SMD is compatible


with Dojo toolkit. When TRUE, the generated JSON SMD will be formatted to comply with the
format that Dojo's JSON-RPC client expects.

• isDojoCompatible(): Returns the value of the Dojo compatibility flag (FALSE, by default).

• addService($service): Add a service to the map. May be an array of information to pass


to the constructor of Zend_Json_Server_Smd_Service, or an instance of that class.

• addServices(array $services): Add multiple services at once.

860
Zend_Json

• setServices(array $services): Add multiple services at once, overwriting any


previously set services.

• getService($name): Get a service by its name.

• getServices(): Get all attached services.

• removeService($name): Remove a service from the map.

• toArray(): Cast the service map to an array.

• toDojoArray(): Cast the service map to an array compatible with Dojo Toolkit.

• toJson(): Cast the service map to a JSON representation.

Zend_Json_Server_Smd_Service has the following methods:

• setOptions(array $options): Set object state from an array. Any mutator (methods
beginning with 'set') may be used as a key and set via this method.

• setName($name): Set the service name (typically, the function or method name).

• getName(): Retrieve the service name.

• setTransport($transport): Set the service transport (currently, only transports


supported by Zend_Json_Server_Smd are allowed).

• getTransport(): Retrieve the current transport.

• setTarget($target): Set the URL endpoint of the service (typically, this will be the same
as the overall SMD to which the service is attached).

• getTarget(): Get the URL endpoint of the service.

• setEnvelope($envelopeType): Set the service envelope (currently, only envelopes


supported by Zend_Json_Server_Smd are allowed).

• getEnvelope(): Retrieve the service envelope type.

• addParam($type, array $options = array(), $order = null): Add a parameter


to the service. By default, only the parameter type is necessary. However, you may also specify
the order, as well as options such as:

• name: the parameter name

• optional: whether or not the parameter is optional

• default: a default value for the parameter

• description: text describing the parameter

• addParams(array $params): Add several parameters at once; each param should be an


assoc array containing minimally the key 'type' describing the parameter type, and optionally
the key 'order'; any other keys will be passed as $options to addOption().

• setParams(array $params): Set many parameters at once, overwriting any existing


parameters.

861
Zend_Json

• getParams(): Retrieve all currently set parameters.

• setReturn($type): Set the return value type of the service.

• getReturn(): Get the return value type of the service.

• toArray(): Cast the service to an array.

• toJson(): Cast the service to a JSON representation.

862
Zend_Layout
1. Introduction
Zend_Layout utilise le design pattern Two Step View, ce qui permet d'encapsuler le contenu
d'une vue dans une autre, généralement appelée template. D'autres projets les appellent aussi
layouts, ainsi Zend Framework utilise ce terme.

Les principales caractéristiques de Zend_Layout sont :

• Automatiser le rendu des layouts lorsqu'ils sont utilisés avec les composants MVC de Zend
Framework.

• Fournir un cadre à part entière pour les variables du layout, au même titre que les variables
de vue.

• Permettre la configuration du nom des layouts, la recherche des scripts leurs correspondant
(inflexion), ainsi que leurs chemins d'accès.

• Permettre de désactiver les layouts temporairement, changer leur configuration ; tout ceci
depuis les contrôleurs ou les scripts de vue.

• Utiliser les mêmes règles de résolution (inflexion) que le ViewRenderer, mais sans empêcher
de les personnaliser à part.

• Une intégration sous forme d'aides/plugin dans le modèle MVC de Zend Framework.

2. Zend_Layout - Démarrage rapide


Il y a deux modes d'utilisation de Zend_Layout : avec Zend Framework MVC, et sans.

2.1. Scripts de layout


Dans tous les cas, un script de layout est nécessaire. Les scripts de layout utilisent simplement
Zend_View (ou une implémentation particulière personnalisée). Les variables de layout sont
enregistrées dans le placeholder Layout, et peuvent être accédées via l'aide de vue placeholder
ou directement en tant que propriétés de l'objet layout.

Par exemple :

<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Mon Site</title>
</head>
<body>
<?php
// récupère la clé "content" via l'aide de vue layout :
echo $this->layout()->content;

// récupère la clé "foo" via l'aide de vue placeholder :


echo $this->placeholder('Zend_Layout')->foo;

863
Zend_Layout

// récupère l'objet layout, et accède à diverses clés :


$layout = $this->layout();
echo $layout->bar;
echo $layout->baz;
?>
</body>
</html>

Toutes les aides de vue enregistrées sont accessibles dans Zend_Layout car il utilise
Zend_View pour son propre rendu. Vous pouvez aussi accéder aux variables de la vue. Les
aides placeholder sont très pratiques pour l'accès aux éléments tels que <head>, les scripts,
les méta, etc. :

<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php echo $this->headTitle() ?>
<?php echo $this->headScript() ?>
<?php echo $this->headStyle() ?>
</head>
<body>
<?php echo $this->render('header.phtml') ?>
<div id="nav"><?php echo $this->placeholder('nav') ?></div>

<div id="content"><?php echo $this->layout()->content ?></div>

<?php echo $this->render('footer.phtml') ?>


</body>
</html>

2.2. Utilisation de Zend_Layout avec le système MVC de Zend


Framework
Zend_Controller propose une manière d'étendre ses fonctionnalités au travers de plugins
de contrôleur frontal et d'aides d'action. Zend_View propose aussi des aides. Zend_Layout
utilise toutes ces possibilités lorsqu'employé avec les composants MVC.

Zend_Layout::startMvc() crée une instance de Zend_Layout avec des paramètres de


configuration optionnels. Cette méthode enregistre aussi un plugin de contrôleur frontal qui
s'occupe du rendu du layout rempli, lorsque la boucle de distribution est terminée. Elle enregistre
également une aide d'action qui permet aux actions d'accéder à l'objet layout. Enfin, l'aide de
vue layout, elle, donne accès à l'objet layout depuis la vue.

Regardons d'abord comment initialiser Zend_Layout afin de l'utiliser dans un contexte MVC

// Dans le fichier de démarrage (bootstrap)


Zend_Layout::startMvc();

startMvc() peut prendre en paramètre un tableau d'options ou un objet Zend_Config pour


personnaliser l'instance. Ces options sont détaillées dans Section 3, « Zend_Layout options de
configuration ».

Dans le contrôleur d'action, vous pouvez donc accéder à l'instance de layout via l'aide d'action :

864
Zend_Layout

class FooController extends Zend_Controller_Action


{
public function barAction()
{
// désactive les layouts pour cette action
$this->_helper->layout->disableLayout();
}

public function bazAction()


{
// utilise un script de layout différent pour
// cette action
$this->_helper->layout->setLayout('foobaz');
};
}

Dans vos scripts de vue, utiliser l'aide layout pour accéder à l'instance de Zend_Layout.
Notez que cette aide est différente des autres car elle ne retourne pas une chaîne, mais bien un
objet. Vous pouvez donc enchaîner une méthode immédiatement :

$this->layout()->setLayout('foo'); // utilise un script de layout spécifique

Autrement, vous pouvez n'importe où accéder à votre instance de Zend_Layout via la méthode
statique getMvcInstance() :

// Retourne null si startMvc() n'a pas été appelée auparavant


$layout = Zend_Layout::getMvcInstance();

Enfin, le plugin de contrôleur frontal Zend_Layout dispose d'une caractéristique annexe au


rendu automatique du layout : il analyse les segments de l'objet de réponse et les assigne en
tant que variables de layout dans vos scripts de layout. Le segment "default" est assigné à la
variable "content". Ceci permet de mettre la main sur le contenu rendu dans l'action principale.

Par exemple, supposons que votre code rencontre d'abord


FooController::indexAction(), qui va rendre du contenu dans le segment par
défaut de la réponse. Ensuite il forward vers NavController::menuAction(),
qui rend son contenu dans un segment nommé 'nav'. Enfin, vous forwardez vers
CommentController::fetchAction() pour récupérer des commentaires, mais vous les
rendez aussi dans le segment par défaut de la réponse (ce qui va rajouter du contenu). Votre
script de layout peut alors rendre chaque segment de manière séparée :

<body>
<!-- rend /nav/menu -->
<div id="nav"><?php echo $this->layout()->nav ?></div>

<!-- rend /foo/index + /comment/fetch -->


<div id="content"><?php echo $this->layout()->content ?></div>
</body>

Cette approche est particulièrement utile avec l'aide d'action ActionStack et son plugin du même
nom. Vous pouvez les utiliser pour gérer une pile d'actions et ainsi décomposer vos processus.

2.3. Utilisation de Zend_Layout en composant indépendant


Pris indépendamment des composants MVC, Zend_Layout n'offre pas tout à fait les mêmes
possibilités et la même flexibilité. Cependant, vous bénéficiez de deux avantages :

865
Zend_Layout

• Des variables propres aux layouts.

• Isolation du script de layout, de son contenu issu des scripts de vue.

En tant que composant indépendant, instanciez un objet Zend_Layout, configurez le au moyen


d'accesseurs, passez vos variables comme des propriétés de l'objet, et rendez le layout :

$layout = new Zend_Layout();

// Spécification du chemin des scripts layout:


$layout->setLayoutPath('/chemin/vers/layouts');

// passage de quelques variables :


$layout->content = $content;
$layout->nav = $nav;

// Utilisation d'un script de layout "foo" :


$layout->setLayout('foo');

// rendu du layout :
echo $layout->render();

2.4. Layout d'exemple


Une image valant mieux qu'un paragraphe, voyez donc celle-ci qui décrit l'utilisation :

866
Zend_Layout

867
Zend_Layout

Avec cette approche, vous pouvez régler vos mises en forme CSS. En positionnement absolu,
par exemple, vous pourriez rendre la barre de navigation plus tard, en fin. Le mécanisme
d'obtention du contenu reste le même cependant.

3. Zend_Layout options de configuration


Zend_Layout possède quelques options. Vous pouvez les spécifier grâce à des accesseurs.
Autrement, en passant un tableau ou un objet Zend_Config au constructeur, ou à
startMvc(). Un tableau d'options peut aussi être passé à setOptions(), un objet
Zend_Config peut être passé à setConfig(). Les options de configuration sont les
suivantes :

• layout : le nom du script de layout. L'inflecteur traduit alors ceci en nom de fichier. Par
défaut, il s'agit de "layout" traduit vers "layout.phtml". Les accesseurs sont setLayout() et
getLayout().

• layoutPath : l'url de base vers les scripts de layout. Les accesseurs sont setLayoutPath()
et getLayoutPath().

• contentKey : la variable de layout utilisée pour accéder au contenu par défaut


(lorsqu'utilisée couplée avec MVC). La valeur par défaut est "content". Pour les accesseurs :
setContentKey() et getContentKey().

• mvcSuccessfulActionOnly : si une action envoie une exception et que cette option vaut
TRUE, alors le layout ne sera pas rendu. (Ceci évite un double rendu alors que le
plugin ErrorHandler est activé). Par défaut cette option est à TRUE. Ses accesseurs :
setMvcSuccessfulActionOnly() et getMvcSuccessfulActionOnly().

• view : l'objet de vue (Zend_View) utilisée par le layout pour rendre son script. Utilisé avec
MVC, Zend_Layout cherchera à récupérer la vue via l'aide ViewRenderer, si aucun objet de
vue ne lui est passé explicitement. Les accesseurs sont setView() et getView().

• helperClass : la classe représentant l'aide d'action lorsque Zend_Layout


est utilisé avec les composants MVC. Par défaut il s'agit
de Zend_Layout_Controller_Action_Helper_Layout. Les accesseurs sont
setHelperClass() et getHelperClass().

• pluginClass : la classe représentant le plugin de contrôleur frontal lorsque


Zend_Layout est utilisé avec les composants MVC. Par défaut, il s'agit de
Zend_Layout_Controller_Plugin_Layout. Les accesseurs sont setPluginClass()
et getPluginClass().

• inflector : l'inflecteur utilisé pour la résolution des noms de layout vers les scripts de
layout. Voyez la documentation spécifique pour plus de détails. Les accesseurs sont
setInflector() et getInflector().

Vous devez passer les helperClass et pluginClass à startMvc()


Pour que les paramètres helperClass et pluginClass agissent, vous devez
les passer en options à startMvc(). Si vous les spécifiez après, ils seront
ignorés.

3.1. Exemples
Les exemples sont basés sur les paramètres $options et $config suivants :

868
Zend_Layout

$options = array(
'layout' => 'foo',
'layoutPath' => '/chemin/vers/layouts',
'contentKey' => 'CONTENT'
// ignorés si MVC n'est pas utilisé
);

/**
[layout]
layout = "foo"
layoutPath = "/chemin/vers/layouts"
contentKey = "CONTENT"
*/
$config = new Zend_Config_Ini('/chemin/vers/layout.ini', 'layout');

Exemple 446. Passer des options au constructeur ou à startMvc()

Le constructeur et la méthode statique startMvc() acceptent soit un tableau d'options,


soit un objet Zend_Config.

Voyons le cas du tableau :

// Avec le constructeur :
$layout = new Zend_Layout($options);

// Avec startMvc():
$layout = Zend_Layout::startMvc($options);

Et maintenant avec l'objet de configuration :

$config = new Zend_Config_Ini('/chemin/vers/layout.ini', 'layout');

// Cas du constructeur:
$layout = new Zend_Layout($config);

// Via startMvc():
$layout = Zend_Layout::startMvc($config);

C'est la manière la plus simple de configurer votre objet Zend_Layout.

Exemple 447. Utilisation de setOptions() et setConfig()

Pour configurer Zend_Layout après l'avoir instanciée, utilisez les méthodes


setOptions() et setConfig() sur l'objet :

// Utilisation d'un tableau d'options:


$layout->setOptions($options);

// Utilisation d'un objet Zend_Config:


$layout->setConfig($options);

Notez cependant que certaines options comme pluginClass et helperClass n'auront


aucun effet avec ses méthodes. Elles doivent être passées au constructeur ou à la méthode
startMvc().

869
Zend_Layout

Exemple 448. Utilisation des accesseurs

Enfin, vous pouvez aussi configurer votre objet de Zend_Layout grâce à ses accesseurs.
Ils peuvent s'utiliser chaînés (interface fluide):

$layout->setLayout('foo')
->setLayoutPath('/chemin/vers/layouts')
->setContentKey('CONTENT');

4. Zend_Layout, utilisation avancée


Zend_Layout permet d'être utilisé de manière plus pointu.

Vous pouvez agir sur ces éléments :

• Objet de vue personnalisé. Zend_Layout accepte tout objet de vue implémentant l'interface
Zend_View_Interface.

• Plugin contrôleur frontal personnalisé. Zend_Layout est livré avec un plugin qui rend le layout
automatiquement avant de renvoyer la réponse (utilisation MVC). Vous pouvez injecter votre
propre plugin.

• Aide d'action personnalisée. Zend_Layout est livrée avec une aide d'action qui devrait en
théorie suffire dans la majorité des cas. C'est un proxy vers l'objet Zend_Layout. Vous pouvez
cependant utiliser votre propre classe d'aide.

• Résolveur de chemin de script personnalisé. Zend_Layout vous permet d'utiliser votre


inflecteur pour la résolution des scripts de layout ou de modifier l'inflecteur par défaut.

4.1. Objets de vue personnalisés


Zend_Layout accepte des objets de vue implémentant Zend_View_Interface ou étendant
Zend_View_Abstract pour le rendu du script de layout. Passez le en paramètre au
constructeur ou à startMvc(), ou utilisez l'accesseur setView() :

$view = new My_Custom_View();


$layout->setView($view);

Attention à vos implémentations de Zend_View


Même si Zend_Layout vous permet d'utiliser votre propre objet de
vue (implémentant Zend_View_Interface), vous pouvez rencontrer des
problèmes si votre vue n'a pas accès à certaines aides de vue, en particulier
les aides "layout" et "placeholder". Zend_Layout effectue des affectations de
variables sur la vue via ces aides.

Si vous avez besoin d'un objet Zend_View personnalisé qui ne supporte pas
ces aides de vue, vous devrez alors trouver un moyen de passer les variables
du layout à la vue. Par exemple, en étendant l'objet Zend_Layout et en
rédéfinissant la méthode render() en passant des variables à la vue. Aussi,
vous pouvez créer votre propre plugin qui s'occupe de passer ces variables avant
le rendu du layout.

De même, si votre implémentation de la vue permet l'extension via des plugins,


vous pouvez à tout moment accéder aux variables du layout grâce à l'aide
placeholder en utilisant la clé "Zend_Layout" :

870
Zend_Layout

$placeholders = new Zend_View_Helper_Placeholder();


$layoutVars = $placeholders->placeholder('Zend_Layout')
->getArrayCopy();

4.2. Plugin de contrôleur frontal personnalisé


Lorsqu'utilisé avec les composants MVC, Zend_Layout enregistre un plugin de contrôleur
frontal qui se charge du rendu du layout juste avant la fin de la boucle de distribution. Ceci
convient à la majorité des cas, si cependant vous avez besoin de construire votre propre plugin,
passez son nom dans l'option pluginClass de la méthode startMvc().

Votre plugin doit alors étendre Zend_Controller_Plugin_Abstract, et devrait accepter un


objet Zend_Layout lors de sa construction.

La classe par défaut du plugin est Zend_Layout_Controller_Plugin_Layout.

4.3. Aide d'action personnalisée


Si les composants MVC sont utilisés, alors Zend_Layout enregistre une classe
d'aide d'action dans le gestionnaire d'aides (helper broker). Par défaut, il s'agit de
Zend_Layout_Controller_Action_Helper_Layout. Cette aide agit comme un proxy vers
l'instance de Zend_Layout et permet d'y accéder dans vos actions.

Si vous voulez utiliser votre propre classe, celle-ci devra alors étendre
Zend_Controller_Action_Helper_Abstract. Passez le nom de la classe dans l'option
helperClass de la méthode startMvc().

4.4. Résolution de chemin de script personnalisé (inflecteur)


Zend_Layout utilise Zend_Filter_Inflector pour établir une chaine de filtre permettant
la résolution du nom du layout, vers le fichier y correspondant. Par défaut, les règles
"Word_CamelCaseToDash" suivie de "StringToLower" sont utilisées. Le suffixe "phtml" est
ensuite ajouté :

• "foo" sera transformé en "foo.phtml".

• "FooBarBaz" sera transformé vers "foo-bar-baz.phtml".

Vous pouvez personnaliser l'inflecteur de 3 manières différentes : Modifier la cible et/


ou le suffixe grâce à des accesseurs dans Zend_Layout ; Modifier les règles de
l'inflecteur associé à Zend_Layout ; Ou encore créer votre propre inflecteur et le passer à
Zend_Layout::setInflector().

Exemple 449. Utilisation des accesseurs pour modifier l'inflecteur

L'inflecteur par défaut de Zend_Layout utilise des marqueurs statiques pour la cible et le
suffixe. 2 accesseurs vous sont donc proposés :

// Affecte une cible à l'inflecteur:


$layout->setInflectorTarget('layouts/:script.:suffix');

// Affecte le suffixe:
$layout->setViewSuffix('php');

871
Zend_Layout

Exemple 450. Modification directe de l'inflecteur de Zend_Layout

Les inflecteurs fonctionnent avec un cible et plusieurs règles. La cible par défaut utilisée
pour Zend_Layout est ":script.:suffix" ; ":script" représente le nom du script de layout, et
":suffix" est une règle statique.

Imaginons que vous vouliez que le suffixe du script de layout soit "html", et que vous vouliez
séparer les mots en CasseMélangée ou en notationCamel avec des tirets-bats au lieu des
tirets. De plus, vous voulez chercher vos scripts dans un sous-dossier "layouts" :

$layout->getInflector()->setTarget('layouts/:script.:suffix')
->setStaticRule('suffix', 'html')
->setFilterRule(array('Word_CamelCaseToUnderscore'));

Exemple 451. Inflecteur personnalisé

Dans la plupart des cas, modifier l'inflecteur sera suffisant. Vous pouvez cependant créer
votre propre inflecteur, pour l'utiliser à différents endroits par exemple, et le passer à
Zend_Layout:

$inflector = new Zend_Filter_Inflector('layouts/:script.:suffix');


$inflector->addRules(array(
':script' => array('Word_CamelCaseToUnderscore'),
'suffix' => 'html'
));
$layout->setInflector($inflector);

L'inflecteur peut être désactivé


L'inflecteur peut être désactivé si vous spécifiez, par exemple, un chemin absolu
pour un script utilisé par Zend_Layout. Les méthodes enableInflection()
et disableInflection() vous y aideront.

872
Zend_Ldap
1. Introduction
Zend_Ldap is a class for performing LDAP operations including but not limited to binding,
searching and modifying entries in an LDAP directory.

1.1. Theory of operation


This component currently consists of the main Zend_Ldap class, that conceptually represents a
binding to a single LDAP server and allows for executing operations against a LDAP server such
as OpenLDAP or ActiveDirectory (AD) servers. The parameters for binding may be provided
explicitly or in the form of an options array. Zend_Ldap_Node provides an object-oriented
interface for single LDAP nodes and can be used to form a basis for an active-record-like interface
for a LDAP-based domain model.

The component provides several helper classes to perform operations on LDAP entries
(Zend_Ldap_Attribute) such as setting and retrieving attributes (date values, passwords,
boolean values, ...), to create and modify LDAP filter strings (Zend_Ldap_Filter) and to
manipulate LDAP distinguished names (DN) (Zend_Ldap_Dn).

Additionally the component abstracts LDAP schema browsing for OpenLDAP and ActiveDirectoy
servers Zend_Ldap_Node_Schema and server information retrieval for OpenLDAP-,
ActiveDirectory- and Novell eDirectory servers (Zend_Ldap_Node_RootDse).

Using the Zend_Ldap class depends on the type of LDAP server and is best summarized with
some simple examples.

If you are using OpenLDAP, a simple example looks like the following (note that the
bindRequiresDn option is important if you are not using AD):

$options = array(
'host' => 's0.foo.net',
'username' => 'CN=user1,DC=foo,DC=net',
'password' => 'pass1',
'bindRequiresDn' => true,
'accountDomainName' => 'foo.net',
'baseDn' => 'OU=Sales,DC=foo,DC=net',
);
$ldap = new Zend_Ldap($options);
$acctname = $ldap->getCanonicalAccountName('abaker',
Zend_Ldap::ACCTNAME_FORM_DN);
echo "$acctname\n";

If you are using Microsoft AD a simple example is:

$options = array(
'host' => 'dc1.w.net',
'useStartTls' => true,
'username' => 'user1@w.net',
'password' => 'pass1',
'accountDomainName' => 'w.net',
'accountDomainNameShort' => 'W',
'baseDn' => 'CN=Users,DC=w,DC=net',

873
Zend_Ldap

);
$ldap = new Zend_Ldap($options);
$acctname = $ldap->getCanonicalAccountName('bcarter',
Zend_Ldap::ACCTNAME_FORM_DN);
echo "$acctname\n";

Note that we use the getCanonicalAccountName() method to retrieve the account DN here
only because that is what exercises the most of what little code is currently present in this class.

1.1.1. Automatic Username Canonicalization When Binding


If bind() is called with a non-DN username but bindRequiresDN is TRUE and no username
in DN form was supplied as an option, the bind will fail. However, if a username in DN form is
supplied in the options array, Zend_Ldap will first bind with that username, retrieve the account
DN for the username supplied to bind() and then re-bind with that DN.

This behavior is critical to Zend_Auth_Adapter_Ldap, which passes the username supplied


by the user directly to bind().

The following example illustrates how the non-DN username 'abaker' can be used with bind():

$options = array(
'host' => 's0.foo.net',
'username' => 'CN=user1,DC=foo,DC=net',
'password' => 'pass1',
'bindRequiresDn' => true,
'accountDomainName' => 'foo.net',
'baseDn' => 'OU=Sales,DC=foo,DC=net',
);
$ldap = new Zend_Ldap($options);
$ldap->bind('abaker', 'moonbike55');
$acctname = $ldap->getCanonicalAccountName('abaker',
Zend_Ldap::ACCTNAME_FORM_DN);
echo "$acctname\n";

The bind() call in this example sees that the username 'abaker' is not in DN form, finds
bindRequiresDn is TRUE, uses 'CN=user1,DC=foo,DC=net' and 'pass1' to bind, retrieves
the DN for 'abaker', unbinds and then rebinds with the newly discovered 'CN=Alice
Baker,OU=Sales,DC=foo,DC=net'.

1.1.2. Account Name Canonicalization


The accountDomainName and accountDomainNameShort options are used for two purposes:
(1) they facilitate multi-domain authentication and failover capability, and (2) they are also used
to canonicalize usernames. Specifically, names are canonicalized to the form specified by the
accountCanonicalForm option. This option may one of the following values:

Tableau 68. Options for accountCanonicalForm

Name Value Example


ACCTNAME_FORM_DN 1 CN=Alice
Baker,CN=Users,DC=example,DC=com
ACCTNAME_FORM_USERNAME 2 abaker
ACCTNAME_FORM_BACKSLASH 3 EXAMPLE\abaker
ACCTNAME_FORM_PRINCIPAL 4 abaker@example.com

874
Zend_Ldap

The default canonicalization depends on what account domain name options were supplied.
If accountDomainNameShort was supplied, the default accountCanonicalForm value is
ACCTNAME_FORM_BACKSLASH. Otherwise, if accountDomainName was supplied, the default is
ACCTNAME_FORM_PRINCIPAL.

Account name canonicalization ensures that the string used to identify an account is consistent
regardless of what was supplied to bind(). For example, if the user supplies an account name
of abaker@example.com or just abaker and the accountCanonicalForm is set to 3, the resulting
canonicalized name would be EXAMPLE\abaker.

1.1.3. Multi-domain Authentication and Failover


The Zend_Ldap component by itself makes no attempt to authenticate with multiple servers.
However, Zend_Ldap is specifically designed to handle this scenario gracefully. The required
technique is to simply iterate over an array of arrays of serve options and attempt to bind with
each server. As described above bind() will automatically canonicalize each name, so it does
not matter if the user passes abaker@foo.net or W\bcarter or cdavis - the bind() method
will only succeed if the credentials were successfully used in the bind.

Consider the following example that illustrates the technique required to implement multi-domain
authentication and failover:

$acctname = 'W\\user2';
$password = 'pass2';

$multiOptions = array(
'server1' => array(
'host' => 's0.foo.net',
'username' => 'CN=user1,DC=foo,DC=net',
'password' => 'pass1',
'bindRequiresDn' => true,
'accountDomainName' => 'foo.net',
'accountDomainNameShort' => 'FOO',
'accountCanonicalForm' => 4, // ACCT_FORM_PRINCIPAL
'baseDn' => 'OU=Sales,DC=foo,DC=net',
),
'server2' => array(
'host' => 'dc1.w.net',
'useSsl' => true,
'username' => 'user1@w.net',
'password' => 'pass1',
'accountDomainName' => 'w.net',
'accountDomainNameShort' => 'W',
'accountCanonicalForm' => 4, // ACCT_FORM_PRINCIPAL
'baseDn' => 'CN=Users,DC=w,DC=net',
),
);

$ldap = new Zend_Ldap();

foreach ($multiOptions as $name => $options) {

echo "Trying to bind using server options for '$name'\n";

$ldap->setOptions($options);
try {
$ldap->bind($acctname, $password);
$acctname = $ldap->getCanonicalAccountName($acctname);

875
Zend_Ldap

echo "SUCCESS: authenticated $acctname\n";


return;
} catch (Zend_Ldap_Exception $zle) {
echo ' ' . $zle->getMessage() . "\n";
if ($zle->getCode() === Zend_Ldap_Exception::LDAP_X_DOMAIN_MISMATCH) {
continue;
}
}
}

If the bind fails for any reason, the next set of server options is tried.

The getCanonicalAccountName() call gets the canonical account name that the application
would presumably use to associate data with such as preferences. The accountCanonicalForm
= 4 in all server options ensures that the canonical form is consistent regardless of which server
was ultimately used.

The special LDAP_X_DOMAIN_MISMATCH exception occurs when an account name with a


domain component was supplied (e.g., abaker@foo.net or FOO\abaker and not just abaker)
but the domain component did not match either domain in the currently selected server options.
This exception indicates that the server is not an authority for the account. In this case, the bind
will not be performed, thereby eliminating unnecessary communication with the server. Note
that the continue instruction has no effect in this example, but in practice for error handling and
debugging purposes, you will probably want to check for LDAP_X_DOMAIN_MISMATCH as well
as LDAP_NO_SUCH_OBJECT and LDAP_INVALID_CREDENTIALS.

The above code is very similar to code used within Zend_Auth_Adapter_Ldap. In fact, we
recommend that you simply use that authentication adapter for multi-domain + failover LDAP
based authentication (or copy the code).

2. API overview
2.1. Configuration / options
The Zend_Ldap component accepts an array of options either supplied to the constructor or
through the setOptions() method. The permitted options are as follows:

Tableau 69. Zend_Ldap Options


Name Description
host The default hostname of LDAP server if not
supplied to connect() (also may be used
when trying to canonicalize usernames in
bind()).
port Default port of LDAP server if not supplied to
connect().
useStartTls Whether or not the LDAP client should
use TLS (aka SSLv2) encrypted transport.
A value of TRUE is strongly favored in
production environments to prevent passwords
from be transmitted in clear text. The default
value is FALSE, as servers frequently require
that a certificate be installed separately
after installation. The useSsl and useStartTls
options are mutually exclusive. The useStartTls

876
Zend_Ldap

Name Description
option should be favored over useSsl but not all
servers support this newer mechanism.
useSsl Whether or not the LDAP client should use
SSL encrypted transport. The useSsl and
useStartTls options are mutually exclusive.
username The default credentials username. Some
servers require that this be in DN form. This
must be given in DN form if the LDAP server
requires a DN to bind and binding should be
possible with simple usernames.
password The default credentials password (used only
with username above).
bindRequiresDn If TRUE, this instructs Zend_Ldap to retrieve
the DN for the account used to bind if the
username is not already in DN form. The default
value is FALSE.
baseDn The default base DN used for searching (e.g.,
for accounts). This option is required for most
account related operations and should indicate
the DN under which accounts are located.
accountCanonicalForm A small integer indicating the form to which
account names should be canonicalized. See
the Account Name Canonicalization section
below.
accountDomainName The FQDN domain for which the target LDAP
server is an authority (e.g., example.com).
accountDomainNameShort The 'short' domain for which the target LDAP
server is an authority. This is usually used
to specify the NetBIOS domain name for
Windows networks but may also be used by
non-AD servers.
accountFilterFormat The LDAP search filter used to search for
accounts. This string is a sprintf() style
expression that must contain one '%s' to
accommodate the username. The default value
is '(&(objectClass=user)(sAMAccountName=
%s))' unless bindRequiresDn is set
to TRUE, in which case the default
is '(&(objectClass=posixAccount)(uid=%s))'.
Users of custom schemas may need to change
this option.
allowEmptyPassword Some LDAP servers can be configured to
accept an empty string password as an
anonymous bind. This behavior is almost
always undesirable. For this reason, empty
passwords are explicitly disallowed. Set this
value to TRUE to allow an empty string
password to be submitted during the bind.

877
Zend_Ldap

Name Description
optReferrals If set to TRUE, this option indicates to the LDAP
client that referrals should be followed. The
default value is FALSE.
tryUsernameSplit If set to FALSE, this option indicates that the
given username should not be split at the first
@ or \ character to separate the username
from the domain during the binding-procedure.
This allows the user to use usernames that
contain an @ or \ character that do not inherit
some domain-information, e.g. using email-
addresses for binding. The default value is
TRUE.

2.2. API Reference

Method names in italics are static methods.

2.2.1. Zend_Ldap

Zend_Ldap is the base interface into a LDAP server. It provides connection and binding methods
as well as methods to operate on the LDAP tree.

Tableau 70. Zend_Ldap API

Method Description
string filterEscape(string $str) Escapes a value to be used in a
LDAP filter according to RFC 2254.
This method is deprecated, please use
Zend_Ldap_Filter_Abstract::escapeValue()
instead.
boolean explodeDn($dn, array &$keys Checks if a given DN $dn is malformed. If
= null, array &$vals = null) $keys or $keys and $vals are given, these
arrays will be filled with the appropriate DN keys
and values. This method is deprecated, please
use Zend_Ldap_Dn::checkDn() instead.
__construct($options) Constructor. The $options parameter is
optional and can be set to an array or
a Zend_Config instance. If no options
are provided at instantiation, the connection
parameters must be passed to the instance
using Zend_Ldap::setOptions(). The
allowed options are specified in Zend_Ldap
Options
resource getResource() Returns the raw LDAP extension (ext/ldap)
resource.
integer getLastErrorCode() Returns the LDAP error number of the last
LDAP command.

878
Zend_Ldap

Method Description
string getLastError(integer & Returns the LDAP error message of the last
$errorCode, array &$errorMessages) LDAP command. The optional $errorCode
parameter is set to the LDAP error number
when given. The optional $errorMessages
array will be filled with the raw error messages
when given. The various LDAP error retrieval
functions can return different things, so they are
all collected if $errorMessages is given.
Zend_Ldap setOptions($options) Sets the LDAP connection and binding
parameters. $options can be an array or
an instance of Zend_Config. The allowed
options are specified in Zend_Ldap Options
array getOptions() Returns the current connection and binding
parameters.
string getBaseDn() Returns the base DN this LDAP connection is
bound to.
string Returns the canonical account name of the
getCanonicalAccountName(string given account name $acctname. $form
$acctname, integer $form) specifies the format into which the account
name is canonicalized. See Account Name
Canonicalization for more details.
Zend_Ldap disconnect() Disconnects the Zend_Ldap instance from the
LDAP server.
Zend_Ldap connect(string $host, Connects the Zend_Ldap instance to the
integer $port, boolean $useSsl, given LDAP server. All parameters are
boolean $useStartTls) optional and will be taken from the LDAP
connection and binding parameters passed
to the instance via the construtor or via
Zend_Ldap::setOptions() when set to
NULL.
Zend_Ldap bind(string $username, Authenticates $username with $password
string $password) at the LDAP server. If both paramaters are
omitted the binding will be carried out with
the credentials given in the connection and
binding parameters. If no credentials are given
in the connection and binding parameters
an anonymous bind will be performed. Note
that this requires anonymous binds to be
allowed on the LDAP server. An empty
string '' can be passed as $password
together with a username if, and only if,
allowEmptyPassword is set to TRUE in the
connection and binding parameters.
Zend_Ldap_Collection Searches the LDAP tree with the given
search(string| $filter and the given search parameters.
Zend_Ldap_Filter_Abstract $filter,
string|Zend_Ldap_Dn $basedn, string| The filter
integer $scope, array Zend_Ldap_Filter_Abstract string to
$filter be used in

879
Zend_Ldap

Method Description
$attributes, string $sort, string the search,
$collectionClass) e.g.
(objectClass=posixAcc

string|Zend_Ldap_Dn The search


$basedn base for the
search. If
omitted or
NULL, the
baseDn
from the
connection
and binding
parameters
is used.

integer $scope The search


scope.
Zend_Ldap::SEARCH_SCO
searches
the
complete
subtree
including
the
$baseDn
node.
Zend_Ldap::SEARCH_SCO
restricts
search to
one level
below
$baseDn.
Zend_Ldap::SEARCH_SCO
restricts
search to
the
$baseDn
itself; this
can be
used to
efficiently
retrieve a
single entry
by its DN.
The default
value is
Zend_Ldap::SEARCH_SCO

array $attributes Specifies


the
attributes
contained

880
Zend_Ldap

Method Description
in the
returned
entries. To
include all
possible
attributes
(ACL
restrictions
can
disallow
certain
attribute to
be
retrieved by
a given
user) pass
either an
empty
array
array()
or
array('*')
to the
method. On
some
LDAP
servers you
can retrieve
special
internal
attributes
by passing
array('*',
'+') to the
method.

string $sort If given


the result
collection
will be
sorted after
the
attribute
$sort.
Results can
only be
sorted after
one single
attribute as
this
parameter
uses the

881
Zend_Ldap

Method Description
ext/ldap
function
ldap_sort().

string $collectionClass If given the


result will
be wrapped
in an object
of type
$collectionClass.
By default
an object
of type
Zend_Ldap_Collection
will be
returned.
The custom
class must
extend
Zend_Ldap_Collection
and will be
passed a
Zend_Ldap_Collection_
on
instantiation.
integer count(string| Counts the elements returned by
Zend_Ldap_Filter_Abstract $filter, the given search parameters. See
string|Zend_Ldap_Dn $basedn, Zend_Ldap::search() for a detailed
integer $scope) description of the method parameters.
integer countChildren(string| Counts the direct descendants (children) of the
Zend_Ldap_Dn $dn) entry identified by the given $dn.
boolean exists(string|Zend_Ldap_Dn Checks whether the entry identified by the
$dn) given $dn exists.
array searchEntries(string| Performs a search operation and returns
Zend_Ldap_Filter_Abstract $filter, the result as an PHP array. This
string|Zend_Ldap_Dn $basedn, is essentially the same method as
integer $scope, array $attributes, Zend_Ldap::search() except for the return
string $sort) type. See Zend_Ldap::search() for a
detailed description of the method parameters.
array getEntry(string|Zend_Ldap_Dn Retrieves the LDAP entry identified by $dn
$dn, array $attributes, boolean with the attributes specified in $attributes.
$throwOnNotFound) If $attributes is ommitted, all attributes
(array()) are included in the result.
$throwOnNotFound is FALSE by default, so
the method will return NULL if the specified
entry cannot be found. If set to TRUE,
a Zend_Ldap_Exception will be thrown
instead.
void prepareLdapEntryArray(array & Prepare an array for the use in LDAP
$entry) modification operations. This method does not

882
Zend_Ldap

Method Description
need to be called by the end-user as it's
implicitly called on every data modification
method.
Zend_Ldap add(string|Zend_Ldap_Dn Adds the entry identified by $dn with its
$dn, array $entry) attributes $entry to the LDAP tree. Throws a
Zend_Ldap_Exception if the entry could not
be added.
Zend_Ldap update(string| Updates the entry identified by $dn with its
Zend_Ldap_Dn $dn, array $entry) attributes $entry to the LDAP tree. Throws a
Zend_Ldap_Exception if the entry could not
be modified.
Zend_Ldap save(string|Zend_Ldap_Dn Saves the entry identified by $dn with its
$dn, array $entry) attributes $entry to the LDAP tree. Throws a
Zend_Ldap_Exception if the entry could not
be saved. This method decides by querying the
LDAP tree if the entry will be added or updated.
Zend_Ldap delete(string| Deletes the entry identified by $dn
Zend_Ldap_Dn $dn, boolean from the LDAP tree. Throws a
$recursively) Zend_Ldap_Exception if the entry could
not be deleted. $recursively is FALSE
by default. If set to TRUE the deletion will
be carried out recursively and will effectively
delete a complete subtree. Deletion will fail if
$recursively is FALSE and the entry $dn is
not a leaf entry.
Zend_Ldap moveToSubtree(string| Moves the entry identified by $from to
Zend_Ldap_Dn $from, string| a location below $to keeping its RDN
Zend_Ldap_Dn $to, boolean unchanged. $recursively specifies if the
$recursively, boolean operation will be carried out recursively (FALSE
$alwaysEmulate) by default) so that the entry $from and all its
descendants will be moved. Moving will fail if
$recursively is FALSE and the entry $from
is not a leaf entry. $alwaysEmulate controls
whether the ext/ldap function ldap_rename()
should be used if available. This can only work
for leaf entries and for servers and for ext/ldap
supporting this function. Set to TRUE to always
use an emulated rename operation.

All move-operations are carried


out by copying and then
deleting the corresponding
entries in the LDAP tree. These
operations are not atomic
so that failures during the
operation will result in an
inconsistent state on the LDAP
server. The same is true for
all recursive operations. They

883
Zend_Ldap

Method Description
also are by no means atomic.
Please keep this in mind.
Zend_Ldap move(string|Zend_Ldap_Dn This is an alias for Zend_Ldap::rename().
$from, string|Zend_Ldap_Dn $to,
boolean $recursively, boolean
$alwaysEmulate)
Zend_Ldap rename(string| Renames the entry identified by $from to $to.
Zend_Ldap_Dn $from, string| $recursively specifies if the operation will
Zend_Ldap_Dn $to, boolean be carried out recursively (FALSE by default) so
$recursively, boolean that the entry $from and all its descendants will
$alwaysEmulate) be moved. Moving will fail if $recursively is
FALSE and the entry $from is not a leaf entry.
$alwaysEmulate controls whether the ext/
ldap function ldap_rename() should be used
if available. This can only work for leaf entries
and for servers and for ext/ldap supporting
this function. Set to TRUE to always use an
emulated rename operation.
Zend_Ldap copyToSubtree(string| Copies the entry identified by $from to
Zend_Ldap_Dn $from, string| a location below $to keeping its RDN
Zend_Ldap_Dn $to, boolean unchanged. $recursively specifies if the
$recursively) operation will be carried out recursively (FALSE
by default) so that the entry $from and all its
descendants will be copied. Copying will fail if
$recursively is FALSE and the entry $from
is not a leaf entry.
Zend_Ldap copy(string|Zend_Ldap_Dn Copies the entry identified by $from to $to.
$from, string|Zend_Ldap_Dn $to, $recursively specifies if the operation will
boolean $recursively) be carried out recursively (FALSE by default) so
that the entry $from and all its descendants will
be copied. Copying will fail if $recursively is
FALSE and the entry $from is not a leaf entry.
Zend_Ldap_Node getNode(string| Returns the entry $dn wrapped in a
Zend_Ldap_Dn $dn) Zend_Ldap_Node.
Zend_Ldap_Node getBaseNode() Returns the entry for the base DN $baseDn
wrapped in a Zend_Ldap_Node.
Zend_Ldap_Node_RootDse Returns the RootDSE for the current server.
getRootDse()
Zend_Ldap_Node_Schema getSchema() Returns the LDAP schema for the current
server.

2.2.1.1. Zend_Ldap_Collection

Zend_Ldap_Collection implements Iterator to allow for item traversal using foreach()


and Countable to be able to respond to count(). With its protected _createEntry() method
it provides a simple extension point for developers needing custom result objects.

884
Zend_Ldap

Tableau 71. Zend_Ldap_Collection API


Method Description
Constructor.
__construct(Zend_Ldap_Collection_Iterator_Interface The constrcutor must
$iterator) be provided by a
Zend_Ldap_Collection_Iterator_Interface
which does the real result iteration.
Zend_Ldap_Collection_Iterator_Default
is the default implementation for iterating ext/
ldap results.
boolean close() Closes the internal iterator. This is also called
in the destructor.
array toArray() Returns all entries as an array.
array getFirst() Returns the first entry in the collection or NULL
if the collection is empty.

2.2.2. Zend_Ldap_Attribute
Zend_Ldap_Attribute is a helper class providing only static methods to manipulate arrays
suitable to the structure used in Zend_Ldap data modification methods and to the data format
required by the LDAP server. PHP data types are converted the following way:

string No conversion will be done.

integer and float The value will be converted to a string.

boolean TRUE will be converted to 'TRUE' and FALSE to 'FALSE'

object and array The value will be converted to a string by using serialize().

resource If a stream resource is given, the data will be fetched by calling


stream_get_contents().

others All other data types (namely non-stream resources) will be ommitted.

On reading attribute values the following conversion will take place:

'TRUE' Converted to TRUE.

'FALSE' Converted to FALSE.

others All other strings won't be automatically converted and are passed as they are.

Tableau 72. Zend_Ldap_Attribute API


Method Description
void setAttribute(array &$data, Sets the attribute $attribName in $data to
string $attribName, mixed $value, the value $value. If $append is TRUE (FALSE
boolean $append) by default) $value will be appended to the
attribute. $value can be a scalar value or an
array of scalar values. Conversion will take
place.
array|mixed getAttribute(array Returns the attribute $attribName from
$data, string $attribName, integer| $data. If $index is NULL (default) an array
null $index) will be returned containing all the values for
the given attribute. An empty array will be

885
Zend_Ldap

Method Description
returned if the attribute does not exist in the
given array. If an integer index is specified the
corresponding value at the given index will be
returned. If the index is out of bounds, NULL will
be returned. Conversion will take place.
boolean attributeHasValue(array & Checks if the attribute $attribName in $data
$data, string $attribName, mixed| has the value(s) given in $value. The method
array $value) returns TRUE only if all values in $value are
present in the attribute. Comparison is done
strictly (respecting the data type).
void Removes all duplicates from the attribute
removeDuplicatesFromAttribute(array$attribName in $data.
&$data, string $attribName)
void removeFromAttribute(array & Removes the value(s) given in $value from
$data, string $attribName, mixed| the attribute $attribName in $data.
array $value)
string|null Converts a PHP data type into its LDAP
convertToLdapValue(mixed $value) representation. See introduction for details.
mixed convertFromLdapValue(string Converts an LDAP value into its PHP data type.
$value) See introduction for details.
string|null Converts a timestamp into its LDAP date/time
convertToLdapDateTimeValue(integer representation. If $utc is TRUE (FALSE by
$value, boolean $utc) default) the resulting LDAP date/time string will
be in UTC, otherwise a local date/time string
will be returned.
integer|null Converts LDAP date/time representation into
convertFromLdapDateTimeValue(stringa timestamp. The method returns NULL if
$value) $value can not be converted back into a PHP
timestamp.
void setPassword(array &$data, Sets a LDAP password for the attribute
string $password, string $hashType, $attribName in $data. $attribName
string $attribName) defaults to 'userPassword' which is
the standard password attribute. The
password hash can be specified with
$hashType. The default value here is
Zend_Ldap_Attribute::PASSWORD_HASH_MD5
with
Zend_Ldap_Attribute::PASSWORD_HASH_SHA
as the other possibilty.
string createPassword(string Creates a LDAP password. The
$password, string $hashType) password hash can be specified with
$hashType. The default value here is
Zend_Ldap_Attribute::PASSWORD_HASH_MD5
with
Zend_Ldap_Attribute::PASSWORD_HASH_SHA
as the other possibilty.
void setDateTimeAttribute(array & Sets the attribute $attribName in $data
$data, string $attribName, integer| to the date/time value $value. If $append

886
Zend_Ldap

Method Description
array $value, boolean $utc, boolean is TRUE (FALSE by default) $value will
$append) be appended to the attribute. $value
can be an integer value or an array of
integers. Date-time-conversion according to
Zend_Ldap_Attribute::convertToLdapDateTimeValue
will take place.
array|integer Returns the date/time attribute $attribName
getDateTimeAttribute(array $data, from $data. If $index is NULL (default) an
string $attribName, integer|null array will be returned containing all the date/
$index) time values for the given attribute. An empty
array will be returned if the attribute does
not exist in the given array. If an integer
index is specified the corresponding date/time
value at the given index will be returned.
If the index is out of bounds, NULL will be
returned. Date-time-conversion according to
Zend_Ldap_Attribute::convertFromLdapDateTimeVal
will take place.

2.2.3. Zend_Ldap_Dn
Zend_Ldap_Dn provides an object-oriented interface to manipulating LDAP distinguished
names (DN). The parameter $caseFold that is used in several methods determines the way
DN attributes are handled regarding their case. Allowed values for this paraneter are:

No case-folding will be done.


Zend_Ldap_Dn::ATTR_CASEFOLD_NONE

All attributes will be converted to upper-case.


Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER

All attributes will be converted to lower-case.


Zend_Ldap_Dn::ATTR_CASEFOLD_LOWER

The default case-folding is Zend_Ldap_Dn::ATTR_CASEFOLD_NONE and can be set with


Zend_Ldap_Dn::setDefaultCaseFold(). Each instance of Zend_Ldap_Dn can have its
own case-folding-setting. If the $caseFold parameter is ommitted in method-calls it defaults to
the instance's case-folding setting.

The class implements ArrayAccess to allow indexer-access to the different parts of the
DN. The ArrayAccess-methods proxy to Zend_Ldap_Dn::get($offset, 1, null)
for offsetGet(integer $offset), to Zend_Ldap_Dn::set($offset, $value)
for offsetSet() and to Zend_Ldap_Dn::remove($offset, 1) for offsetUnset().
offsetExists() simply checks if the index is within the bounds.

Tableau 73. Zend_Ldap_Dn API


Method Description
Zend_Ldap_Dn factory(string|array Creates a Zend_Ldap_Dn instance from
$dn, string|null $caseFold) an array or a string. The array must
conform to the array structure detailed under
Zend_Ldap_Dn::implodeDn().
Zend_Ldap_Dn fromString(string Creates a Zend_Ldap_Dn instance from a
$dn, string|null $caseFold) string.
Zend_Ldap_Dn fromArray(array $dn, Creates a Zend_Ldap_Dn instance from
string|null $caseFold) an array. The array must conform

887
Zend_Ldap

Method Description
to the array structure detailed under
Zend_Ldap_Dn::implodeDn().
array getRdn(string|null Gets the RDN of the current DN. The return
$caseFold) value is an array with the RDN attribute names
its keys and the RDN attribute values.
string getRdnString(string|null Gets the RDN of the current DN. The return
$caseFold) value is a string.
Zend_Ldap_Dn getParentDn(integer Gets the DN of the current DN's ancestor
$levelUp) $levelUp levels up the tree. $levelUp
defaults to 1.
array get(integer $index, integer Returns a slice of the current DN determined
$length, string|null $caseFold) by $index and $length. $index starts with
0 on the DN part from the left.
Zend_Ldap_Dn set(integer $index, Replaces a DN part in the current DN. This
array $value) operation manipulates the current instance.
Zend_Ldap_Dn remove(integer Removes a DN part from the current DN. This
$index, integer $length) operation manipulates the current instance.
$length defaults to 1
Zend_Ldap_Dn append(array $value) Appends a DN part to the current DN. This
operation manipulates the current instance.
Zend_Ldap_Dn prepend(array $value) Prepends a DN part to the current DN. This
operation manipulates the current instance.
Zend_Ldap_Dn insert(integer Inserts a DN part after the index $index to
$index, array $value) the current DN. This operation manipulates the
current instance.
void setCaseFold(string|null Sets the case-folding option to the
$caseFold) current DN instance. If $caseFold is
NULL the default case-folding setting
(Zend_Ldap_Dn::ATTR_CASEFOLD_NONE
by default or set via
Zend_Ldap_Dn::setDefaultCaseFold()
will be set for the current instance.
string toString(string|null Returns DN as a string.
$caseFold)
array toArray(string|null Returns DN as an array.
$caseFold)
string __toString() Returns DN as a string - proxies to
Zend_Ldap_Dn::toString(null).
void setDefaultCaseFold(string Sets the default case-folding option used by
$caseFold) all instances on creation by default. Already
existing instances are not affected by this
setting.
array escapeValue(string|array Escapes a DN value according to RFC 2253.
$values)
array unescapeValue(string|array Undoes the conversion done by
$values) Zend_Ldap_Dn::escapeValue().

888
Zend_Ldap

Method Description
array explodeDn(string $dn, array Explodes the DN $dn into an array containing
&$keys, array &$vals, string|null all parts of the given DN. $keys optinally
$caseFold) receive DN keys (e.g. CN, OU, DC, ...). $vals
optionally receive DN values. The resulting
array will be of type

array(
array("cn" => "name1", "uid" => "user"),
array("cn" => "name2"),
array("dc" => "example"),
array("dc" => "org")
)

for a DN of
cn=name1+uid=user,cn=name2,dc=example,dc=org.
boolean checkDn(string $dn, array Checks if a given DN $dn is malformed. If
&$keys, array &$vals, string|null $keys or $keys and $vals are given, these
$caseFold) arrays will be filled with the appropriate DN keys
and values.
string implodeRdn(array $part, Returns a DN part in the form $attribute=
string|null $caseFold) $value
string implodeDn(array $dnArray, Implodes an array in the form delivered
string|null $caseFold, string by Zend_Ldap_Dn::explodeDn() to a DN
$separator) string. $separator defaults to ',' but some
LDAP servers also understand ';'. $dnArray
must of type

array(
array("cn" => "name1", "uid" => "user"),
array("cn" => "name2"),
array("dc" => "example"),
array("dc" => "org")
)

boolean isChildOf(string| Checks if given $childDn is beneath


Zend_Ldap_Dn $childDn, string| $parentDn subtree.
Zend_Ldap_Dn $parentDn)

2.2.4. Zend_Ldap_Filter
Tableau 74. Zend_Ldap_Filter API

Method Description
Zend_Ldap_Filter equals(string Creates an 'equals' filter: (attr=value).
$attr, string $value)
Zend_Ldap_Filter begins(string Creates an 'begins with' filter:
$attr, string $value) (attr=value*).
Zend_Ldap_Filter ends(string Creates an 'ends with' filter: (attr=*value).
$attr, string $value)
Zend_Ldap_Filter contains(string Creates an 'contains' filter: (attr=*value*).
$attr, string $value)

889
Zend_Ldap

Method Description
Zend_Ldap_Filter greater(string Creates an 'greater' filter: (attr>value).
$attr, string $value)
Zend_Ldap_Filter Creates an 'greater or equal' filter:
greaterOrEqual(string $attr, (attr>=value).
string $value)
Zend_Ldap_Filter less(string Creates an 'less' filter: (attr<value).
$attr, string $value)
Zend_Ldap_Filter Creates an 'less or equal' filter:
lessOrEqual(string $attr, string (attr<=value).
$value)
Zend_Ldap_Filter approx(string Creates an 'approx' filter: (attr~=value).
$attr, string $value)
Zend_Ldap_Filter any(string $attr) Creates an 'any' filter: (attr=*).
Zend_Ldap_Filter string(string Creates a simple custom string filter. The user
$filter) is responsible for all value-escaping as the filter
is used as is.
Zend_Ldap_Filter mask(string Creates a filter from a string mask. All $value
$mask, string $value,...) parameters will be escaped and substituted
into $mask by using sprintf()
Zend_Ldap_Filter Creates an 'and' filter from all arguments given.
andFilter(Zend_Ldap_Filter_Abstract
$filter,...)
Zend_Ldap_Filter Creates an 'or' filter from all arguments given.
orFilter(Zend_Ldap_Filter_Abstract
$filter,...)
__construct(string $attr, string Constructor. Creates an arbitrary filter
$value, string $filtertype, string| according to the parameters supplied. The
null $prepend, string|null $append) resulting filter will be a concatenation $attr .
$filtertype . $prepend . $value .
$append. Normally this constructor is not
needed as all filters can be created by using the
appropriate factory methods.
string toString() Returns a string representation of the filter.
string __toString() Returns a string representation
of the filter. Proxies to
Zend_Ldap_Filter::toString().
Zend_Ldap_Filter_Abstract negate() Negates the current filter.
Zend_Ldap_Filter_Abstract Creates an 'and' filter from the current filter and
addAnd(Zend_Ldap_Filter_Abstract all filters passed in as the arguments.
$filter,...)
Zend_Ldap_Filter_Abstract Creates an 'or' filter from the current filter and
addOr(Zend_Ldap_Filter_Abstract all filters passed in as the arguments.
$filter,...)
string|array escapeValue(string| Escapes the given $values according to
array $values) RFC 2254 so that they can be safely used
in LDAP filters. If a single string is given,

890
Zend_Ldap

Method Description
a string is returned - otherwise an array is
returned. Any control characters with an ASCII
code < 32 as well as the characters with
special meaning in LDAP filters "*", "(", ")",
and "\" (the backslash) are converted into the
representation of a backslash followed by two
hex digits representing the hexadecimal value
of the character.
string|array unescapeValue(string| Undoes the conversion done
array $values) by Zend_Ldap_Filter::escapeValue().
Converts any sequences of a backslash
followed by two hex digits into the
corresponding character.

2.2.5. Zend_Ldap_Node
Zend_Ldap_Node includes the magic property accessors __set(), __get(),
__unset() and __isset() to access the attributes by their name. They
proxy to Zend_Ldap_Node::setAttribute(), Zend_Ldap_Node::getAttribute(),
Zend_Ldap_Node::deleteAttribute() and Zend_Ldap_Node::existsAttribute()
respectively. Furthermore the class implements ArrayAccess for array-style-access to the
attributes. Zend_Ldap_Node also implements Iterator and RecursiveIterato to allow for
recursive tree-traversal.

Tableau 75. Zend_Ldap_Node API

Method Description
Zend_Ldap getLdap() Returns the current LDAP connection. Throws
Zend_Ldap_Exception if current node is
in detached mode (not connected to a
Zend_Ldap instance).
Zend_Ldap_Node Attach the current node to the
attachLdap(Zend_Ldap $ldap) $ldap Zend_Ldap instance. Throws
Zend_Ldap_Exception if $ldap is not
responsible for the current node (node is not a
child of the $ldap base DN).
Zend_Ldap_Node detachLdap() Detach node from LDAP connection.
boolean isAttached() Checks if the current node is attached to a
LDAP connection.
Zend_Ldap_Node create(string| Factory method to create a new detached
array|Zend_Ldap_Dn $dn, array Zend_Ldap_Node for a given DN. Creates a
$objectClass) new Zend_Ldap_Node with the DN $dn and
the object-classes $objectClass.
Zend_Ldap_Node fromLdap(string| Factory method to create an attached
array|Zend_Ldap_Dn $dn, Zend_Ldap Zend_Ldap_Node for a given DN. Loads an
$ldap) existing Zend_Ldap_Node with the DN $dn
from the LDAP connection $ldap.
Zend_Ldap_Node fromArray((array Factory method to create a detached
$data, boolean $fromDataSource) Zend_Ldap_Node from array data $data.
If $fromDataSource is TRUE (FALSE by

891
Zend_Ldap

Method Description
default), the data is treated as beeing present
in a LDAP tree.
boolean isNew() Tells if the node is consiedered as new (not
present on the server). Please note, that this
doesn't tell if the node is really present on the
server. Use Zend_Ldap_Node::exists()
to see if a node is already there.
boolean willBeDeleted() Tells if this node is going to be deleted once
Zend_Ldap_Node::update() is called.
Zend_Ldap_Node delete() Marks this node as to be
deleted. Node will be deleted on
calling Zend_Ldap_Node::update() if
Zend_Ldap_Node::willBeDeleted() is
TRUE.
boolean willBeMoved() Tells if this node is going to be moved once
Zend_Ldap_Node::update() is called.
Zend_Ldap_Node update(Zend_Ldap Sends all pending changes to the LDAP
$ldap) server. If $ldap is omitted the current
LDAP connection is used. If the current
node is detached from a LDAP connection
a Zend_Ldap_Exception will be thrown. If
$ldap is provided the current node will be
attached to the given LDAP connection.
Zend_Ldap_Dn getCurrentDn() Gets the current DN of the current node as a
Zend_Ldap_Dn. This does not reflect possible
rename-operations.
Zend_Ldap_Dn getDn() Gets the original DN of the current node as a
Zend_Ldap_Dn. This reflects possible rename-
operations.
string getDnString(string Gets the original DN of the current node
$caseFold) as a string. This reflects possible rename-
operations.
array getDnArray(string $caseFold) Gets the original DN of the current node
as an array. This reflects possible rename-
operations.
string getRdnString(string Gets the RDN of the current node as a string.
$caseFold) This reflects possible rename-operations.
array getRdnArray(string Gets the RDN of the current node as an array.
$caseFold) This reflects possible rename-operations.
Zend_Ldap_Node setDn(Zend_Ldap_Dn| Sets the new DN for this node
string|array $newDn) effectively moving the node once
Zend_Ldap_Node::update() is called.
Zend_Ldap_Node move(Zend_Ldap_Dn| This is an alias for
string|array $newDn) Zend_Ldap_Node::setDn().
Zend_Ldap_Node This is an alias for
rename(Zend_Ldap_Dn|string|array Zend_Ldap_Node::setDn().
$newDn)

892
Zend_Ldap

Method Description
array getObjectClass() Returns the objectClass of the node.
Zend_Ldap_Node Sets the objectClass attribute.
setObjectClass(array|string
$value)
Zend_Ldap_Node Appends to the objectClass attribute.
appendObjectClass(array|string
$value)
string toLdif(array $options) Returns a LDIF representation of the current
node. $options will be passed to the
Zend_Ldap_Ldif_Encoder.
array getChangedData() Gets changed node data. The array
contains all changed attributes. This format
can be used in Zend_Ldap::add() and
Zend_Ldap::update().
array getChanges() Returns all changes made.
string toString() Returns the DN of the current node - proxies to
Zend_Ldap_Dn::getDnString().
string __toString() Casts to string representation - proxies to
Zend_Ldap_Dn::toString().
array toArray(boolean Returns an array representation of the current
$includeSystemAttributes) node. If $includeSystemAttributes is
FALSE (defaults to TRUE) the system specific
attributes are stripped from the array. Unlike
Zend_Ldap_Node::getAttributes() the
resulting array contains the DN with key 'dn'.
string toJson(boolean Returns a JSON representation of the current
$includeSystemAttributes) node using Zend_Ldap_Node::toArray().
array getData(boolean Returns the node's attributes. The array
$includeSystemAttributes) contains all attributes in its internal format (no
conversion).
boolean existsAttribute(string Checks whether a given attribute exists. If
$name, boolean $emptyExists) $emptyExists is FALSE empty attributes
(containing only array()) are treated as non-
existent returning FALSE. If $emptyExists is
TRUE empty attributes are treated as existent
returning TRUE. In this case the method returns
FALSE only if the attribute name is missing in
the key-collection.
boolean attributeHasValue(string Checks if the given value(s) exist in the
$name, mixed|array $value) attribute. The method returns TRUE only if all
values in $value are present in the attribute.
Comparison is done strictly (respecting the
data type).
integer count() Returns the number of attributes in the node.
Implements Countable.

893
Zend_Ldap

Method Description
mixed getAttribute(string $name, Gets a LDAP attribute. Data conversion is
integer|null $index) applied using
Zend_Ldap_Attribute::getAttribute().
array getAttributes(boolean Gets all attributes of node. If
$includeSystemAttributes) $includeSystemAttributes is FALSE
(defaults to TRUE) the system specific attributes
are stripped from the array.
Zend_Ldap_Node setAttribute(string Sets a LDAP attribute. Data conversion is
$name, mixed $value) applied using
Zend_Ldap_Attribute::setAttribute().
Zend_Ldap_Node Appends to a LDAP attribute.
appendToAttribute(string $name, Data conversion is applied using
mixed $value) Zend_Ldap_Attribute::setAttribute().
array|integer Gets a LDAP date/time attribute.
getDateTimeAttribute(string $name, Data conversion is applied using
integer|null $index) Zend_Ldap_Attribute::getDateTimeAttribute().
Zend_Ldap_Node Sets a LDAP date/time attribute.
setDateTimeAttribute(string $name, Data conversion is applied using
integer|array $value, boolean $utc) Zend_Ldap_Attribute::setDateTimeAttribute().
Zend_Ldap_Node Appends to a LDAP date/time attribute.
appendToDateTimeAttribute(string Data conversion is applied using
$name, integer|array $value, Zend_Ldap_Attribute::setDateTimeAttribute().
boolean $utc)
Zend_Ldap_Node Sets a LDAP password on $attribName
setPasswordAttribute(string (defaults to 'userPassword') to $password
$password, string $hashType, string with the hash type $hashType (defaults to
$attribName) Zend_Ldap_Attribute::PASSWORD_HASH_MD5).
Zend_Ldap_Node Deletes a LDAP attribute.
deleteAttribute(string $name)
void Removes duplicate values from a LDAP
attribute.
removeDuplicatesFromAttribute(string
$name)
void removeFromAttribute(string Removes the given values from a LDAP
$attribName, mixed|array $value) attribute.
boolean exists(Zend_Ldap $ldap) Checks if the current node exists on the given
LDAP server (current server is used if NULL is
passed).
Zend_Ldap_Node reload(Zend_Ldap Reloads the current node's attributes from the
$ldap) given LDAP server (current server is used if
NULL is passed).
Zend_Ldap_Node_Collection Searches the nodes's subtree with the given
searchSubtree(string| $filter and the given search parameters.
Zend_Ldap_Filter_Abstract $filter, See Zend_Ldap::search() for details on
integer $scope, string $sort) the parameters $scope and $sort.
integer countSubtree(string| Count the nodes's subtree items matching the
Zend_Ldap_Filter_Abstract $filter, given $filter and the given search scope.
integer $scope)

894
Zend_Ldap

Method Description
See Zend_Ldap::search() for details on
the $scope parameter.
integer countChildren() Count the nodes's children.
Zend_Ldap_Node_Collection Searches the nodes's children
searchChildren(string| matching the given $filter. See
Zend_Ldap_Filter_Abstract $filter, Zend_Ldap::search() for details on the
string $sort) $sort parameter.
boolean hasChildren() Returns whether the current node has children.
Zend_Ldap_Node_ChildrenIterator Returns all children of the current node.
getChildren()
Zend_Ldap_Node getParent(Zend_Ldap Returns the parent of the current node using
$ldap) the LDAP connection $ldap (uses the current
LDAP connection if omitted).

2.2.6. Zend_Ldap_Node_RootDse
The following methods are available on all vendor-specific subclasses.

Zend_Ldap_Node_RootDse includes the magic property accessors


__get() and __isset() to access the attributes by their
name. They proxy to Zend_Ldap_Node_RootDse::getAttribute() and
Zend_Ldap_Node_RootDse::existsAttribute() respectively. __set() and
__unset() are also implemented but they throw a BadMethodCallException as
modifications are not allowed on RootDSE nodes. Furthermore the class implements
ArrayAccess for array-style-access to the attributes. offsetSet() and offsetUnset()
also throw a BadMethodCallException due ro obvious reasons.

Tableau 76. Zend_Ldap_Node_RootDse API

Method Description
Zend_Ldap_Dn getDn() Gets the DN of the current node as a
Zend_Ldap_Dn.
string getDnString(string Gets the DN of the current node as a string.
$caseFold)
array getDnArray(string $caseFold) Gets the DN of the current node as an array.
string getRdnString(string Gets the RDN of the current node as a string.
$caseFold)
array getRdnArray(string Gets the RDN of the current node as an array.
$caseFold)
array getObjectClass() Returns the objectClass of the node.
string toString() Returns the DN of the current node - proxies to
Zend_Ldap_Dn::getDnString().
string __toString() Casts to string representation - proxies to
Zend_Ldap_Dn::toString().
array toArray(boolean Returns an array representation of the current
$includeSystemAttributes) node. If $includeSystemAttributes is
FALSE (defaults to TRUE) the system specific
attributes are stripped from the array. Unlike

895
Zend_Ldap

Method Description
Zend_Ldap_Node_RootDse::getAttributes()
the resulting array contains the DN with key
'dn'.
string toJson(boolean Returns a JSON representation
$includeSystemAttributes) of the current node using
Zend_Ldap_Node_RootDse::toArray().
array getData(boolean Returns the node's attributes. The array
$includeSystemAttributes) contains all attributes in its internal format (no
conversion).
boolean existsAttribute(string Checks whether a given attribute exists. If
$name, boolean $emptyExists) $emptyExists is FALSE, empty attributes
(containing only array()) are treated as non-
existent returning FALSE. If $emptyExists is
TRUE, empty attributes are treated as existent
returning TRUE. In this case the method returns
FALSE only if the attribute name is missing in
the key-collection.
boolean attributeHasValue(string Checks if the given value(s) exist in the
$name, mixed|array $value) attribute. The method returns TRUE only if all
values in $value are present in the attribute.
Comparison is done strictly (respecting the
data type).
integer count() Returns the number of attributes in the node.
Implements Countable.
mixed getAttribute(string $name, Gets a LDAP attribute. Data conversion is
integer|null $index) applied using
Zend_Ldap_Attribute::getAttribute().
array getAttributes(boolean Gets all attributes of node. If
$includeSystemAttributes) $includeSystemAttributes is FALSE
(defaults to TRUE) the system specific attributes
are stripped from the array.
array|integer Gets a LDAP date/time attribute.
getDateTimeAttribute(string $name, Data conversion is applied using
integer|null $index) Zend_Ldap_Attribute::getDateTimeAttribute().
Zend_Ldap_Node_RootDse Reloads the current node's attributes from the
reload(Zend_Ldap $ldap) given LDAP server.
Zend_Ldap_Node_RootDse Factory method to create the RootDSE.
create(Zend_Ldap $ldap)
array getNamingContexts() Gets the namingContexts.
string|null getSubschemaSubentry() Gets the subschemaSubentry.
boolean supportsVersion(string| Determines if the LDAP version is supported.
int|array $versions)
boolean Determines if the sasl mechanism is supported.
supportsSaslMechanism(string|array
$mechlist)
integer getServerType() Gets the server type. Returns

896
Zend_Ldap

Method Description
for
Zend_Ldap_Node_RootDse::SERVER_TYPE_GENERIC
unknown
LDAP
servers

for
Zend_Ldap_Node_RootDse::SERVER_TYPE_OPENLDAP
OpenLDAP
servers

for
Zend_Ldap_Node_RootDse::SERVER_TYPE_ACTIVEDIREC
Microsoft
ActiveDirectory
servers

For Novell
Zend_Ldap_Node_RootDse::SERVER_TYPE_EDIRECTORY
eDirectory
servers
Zend_Ldap_Dn getSchemaDn() Returns the schema DN.

2.2.6.1. OpenLDAP

Additionally the common methods above apply to instances of


Zend_Ldap_Node_RootDse_OpenLdap.

Refer to LDAP Operational Attributes and Objectsfor information on the attributes


of OpenLDAP RootDSE.

Tableau 77. Zend_Ldap_Node_RootDse_OpenLdap API

Method Description
integer getServerType() Gets the server type. Returns
Zend_Ldap_Node_RootDse::SERVER_TYPE_OPENLDAP
string|null getConfigContext() Gets the configContext.
string|null getMonitorContext() Gets the monitorContext.
boolean supportsControl(string| Determines if the control is supported.
array $oids)
boolean supportsExtension(string| Determines if the extension is supported.
array $oids)
boolean supportsFeature(string| Determines if the feature is supported.
array $oids)

2.2.6.2. ActiveDirectory

Additionally the common methods above apply to instances of


Zend_Ldap_Node_RootDse_ActiveDirectory.

Refer to RootDSEfor information on the attributes of Microsoft ActiveDirectory


RootDSE.

897
Zend_Ldap

Tableau 78. Zend_Ldap_Node_RootDse_ActiveDirectory API

Method Description
integer getServerType() Gets the server type. Returns
Zend_Ldap_Node_RootDse::SERVER_TYPE_ACTIVEDIREC
string|null Gets the configurationNamingContext.
getConfigurationNamingContext()
string|null getCurrentTime() Gets the currentTime.
string|null Gets the defaultNamingContext.
getDefaultNamingContext()
string|null getDnsHostName() Gets the dnsHostName.
string|null Gets the domainControllerFunctionality.
getDomainControllerFunctionality()
string|null Gets the domainFunctionality.
getDomainFunctionality()
string|null getDsServiceName() Gets the dsServiceName.
string|null Gets the forestFunctionality.
getForestFunctionality()
string|null Gets the highestCommittedUSN.
getHighestCommittedUSN()
string|null Gets the isGlobalCatalogReady.
getIsGlobalCatalogReady()
string|null getIsSynchronized() Gets the isSynchronized.
string|null getLdapServiceName() Gets the ldapServiceName.
string|null Gets the rootDomainNamingContext.
getRootDomainNamingContext()
string|null Gets the schemaNamingContext.
getSchemaNamingContext()
string|null getServerName() Gets the serverName.
boolean supportsCapability(string| Determines if the capability is supported.
array $oids)
boolean supportsControl(string| Determines if the control is supported.
array $oids)
boolean supportsPolicy(string| Determines if the version is supported.
array $policies)

2.2.6.3. eDirectory

Additionally the common methods above apply to instances of


Zend_Ldap_Node_RootDse_eDirectory.

Refer to Getting Information about the LDAP Serverfor information on the


attributes of Novell eDirectory RootDSE.

898
Zend_Ldap

Tableau 79. Zend_Ldap_Node_RootDse_eDirectory API


Method Description
integer getServerType() Gets the server type. Returns
Zend_Ldap_Node_RootDse::SERVER_TYPE_EDIRECTORY
boolean supportsExtension(string| Determines if the extension is supported.
array $oids)
string|null getVendorName() Gets the vendorName.
string|null getVendorVersion() Gets the vendorVersion.
string|null getDsaName() Gets the dsaName.
string|null getStatisticsErrors() Gets the server statistics "errors".
string|null Gets the server statistics "securityErrors".
getStatisticsSecurityErrors()
string|null Gets the server statistics "chainings".
getStatisticsChainings()
string|null Gets the server statistics "referralsReturned".
getStatisticsReferralsReturned()
string|null Gets the server statistics "extendedOps".
getStatisticsExtendedOps()
string|null Gets the server statistics "abandonOps".
getStatisticsAbandonOps()
string|null Gets the server statistics
"wholeSubtreeSearchOps".
getStatisticsWholeSubtreeSearchOps()

2.2.7. Zend_Ldap_Node_Schema
The following methods are available on all vendor-specific subclasses.

Zend_Ldap_Node_Schema includes the magic property accessors


__get() and __isset() to access the attributes by their
name. They proxy to Zend_Ldap_Node_Schema::getAttribute() and
Zend_Ldap_Node_Schema::existsAttribute() respectively. __set() and __unset()
are also implemented, but they throw a BadMethodCallException as modifications
are not allowed on RootDSE nodes. Furthermore the class implements ArrayAccess
for array-style-access to the attributes. offsetSet() and offsetUnset() also throw a
BadMethodCallException due to obvious reasons.

Tableau 80. Zend_Ldap_Node_Schema API


Method Description
Zend_Ldap_Dn getDn() Gets the DN of the current node as a
Zend_Ldap_Dn.
string getDnString(string Gets the DN of the current node as a string.
$caseFold)
array getDnArray(string $caseFold) Gets the DN of the current node as an array.
string getRdnString(string Gets the RDN of the current node as a string.
$caseFold)
array getRdnArray(string Gets the RDN of the current node as an array.
$caseFold)

899
Zend_Ldap

Method Description
array getObjectClass() Returns the objectClass of the node.
string toString() Returns the DN of the current node - proxies to
Zend_Ldap_Dn::getDnString().
string __toString() Casts to string representation - proxies to
Zend_Ldap_Dn::toString().
array toArray(boolean Returns an array representation of the current
$includeSystemAttributes) node. If $includeSystemAttributes is
FALSE (defaults to TRUE), the system specific
attributes are stripped from the array. Unlike
Zend_Ldap_Node_Schema::getAttributes(),
the resulting array contains the DN with key
'dn'.
string toJson(boolean Returns a JSON representation
$includeSystemAttributes) of the current node using
Zend_Ldap_Node_Schema::toArray().
array getData(boolean Returns the node's attributes. The array
$includeSystemAttributes) contains all attributes in its internal format (no
conversion).
boolean existsAttribute(string Checks whether a given attribute exists. If
$name, boolean $emptyExists) $emptyExists is FALSE, empty attributes
(containing only array()) are treated as non-
existent returning FALSE. If $emptyExists is
TRUE, empty attributes are treated as existent
returning TRUE. In this case the method returns
FALSE only if the attribute name is missing in
the key-collection.
boolean attributeHasValue(string Checks if the given value(s) exist in the
$name, mixed|array $value) attribute. The method returns TRUE only if all
values in $value are present in the attribute.
Comparison is done strictly (respecting the
data type).
integer count() Returns the number of attributes in the node.
Implements Countable.
mixed getAttribute(string $name, Gets a LDAP attribute. Data conversion is
integer|null $index) applied using
Zend_Ldap_Attribute::getAttribute().
array getAttributes(boolean Gets all attributes of node. If
$includeSystemAttributes) $includeSystemAttributes is FALSE
(defaults to TRUE) the system specific attributes
are stripped from the array.
array|integer Gets a LDAP date/time attribute.
getDateTimeAttribute(string $name, Data conversion is applied using
integer|null $index) Zend_Ldap_Attribute::getDateTimeAttribute().
Zend_Ldap_Node_Schema Reloads the current node's attributes from the
reload(Zend_Ldap $ldap) given LDAP server.
Zend_Ldap_Node_Schema Factory method to create the Schema node.
create(Zend_Ldap $ldap)

900
Zend_Ldap

Method Description
array getAttributeTypes() Gets the attribute types as an array of .
array getObjectClasses() Gets the object classes as an array of
Zend_Ldap_Node_Schema_ObjectClass_Interface.

Tableau 81. Zend_Ldap_Node_Schema_AttributeType_Interface API

Method Description
string getName() Gets the attribute name.
string getOid() Gets the attribute OID.
string getSyntax() Gets the attribute syntax.
int|null getMaxLength() Gets the attribute maximum length.
boolean isSingleValued() Returns if the attribute is single-valued.
string getDescription() Gets the attribute description

Tableau 82. Zend_Ldap_Node_Schema_ObjectClass_Interface API

Method Description
string getName() Returns the objectClass name.
string getOid() Returns the objectClass OID.
array getMustContain() Returns the attributes that this objectClass
must contain.
array getMayContain() Returns the attributes that this objectClass may
contain.
string getDescription() Returns the attribute description
integer getType() Returns the objectClass type. The method
returns one of the following values:

for
Zend_Ldap_Node_Schema::OBJECTCLASS_TYPE_UNKNOWN
unknown
class types

for
Zend_Ldap_Node_Schema::OBJECTCLASS_TYPE_STRUCTU
structural
classes

for abstract
Zend_Ldap_Node_Schema::OBJECTCLASS_TYPE_ABSTRAC
classes

for auxiliary
Zend_Ldap_Node_Schema::OBJECTCLASS_TYPE_AUXILIA
classes
array getParentClasses() Returns the parent objectClasses of this class.
This includes structural, abstract and auxiliary
objectClasses.

Classes representing attribute types and object classes extend


Zend_Ldap_Node_Schema_Item which provides some core methods to access arbitrary
attributes on the underlying LDAP node. Zend_Ldap_Node_Schema_Item includes the
magic property accessors __get() and __isset() to access the attributes by their name.

901
Zend_Ldap

Furthermore the class implements ArrayAccess for array-style-access to the attributes.


offsetSet() and offsetUnset() throw a BadMethodCallException as modifications
are not allowed on schema information nodes.

Tableau 83. Zend_Ldap_Node_Schema_Item API

Method Description
array getData() Gets all the underlying data from the schema
information node.
integer count() Returns the number of attributes in this schema
information node. Implements Countable.

2.2.7.1. OpenLDAP

Additionally the common methods above apply to instances of


Zend_Ldap_Node_Schema_OpenLDAP.

Tableau 84. Zend_Ldap_Node_Schema_OpenLDAP API

Method Description
array getLdapSyntaxes() Gets the LDAP syntaxes.
array getMatchingRules() Gets the matching rules.
array getMatchingRuleUse() Gets the matching rule use.

Tableau 85. Zend_Ldap_Node_Schema_AttributeType_OpenLDAP API

Method Description
Returns the parent attribute type in the
Zend_Ldap_Node_Schema_AttributeType_OpenLdap|
null getParent() inheritance tree if one exists.

Tableau 86. Zend_Ldap_Node_Schema_ObjectClass_OpenLDAP API

Method Description
array getParents() Returns the parent object classes in
the inheritance tree if one exists.
The returned array is an array of
Zend_Ldap_Node_Schema_ObjectClass_OpenLdap.

2.2.7.2. ActiveDirectory

Schema browsing on ActiveDirectory servers


Due to restrictions on Microsoft ActiveDirectory servers regarding the number
of entries returned by generic search routines and due to the structure of the
ActiveDirectory schema repository, schema browsing is currently not available
for Microsoft ActiveDirectory servers.

Zend_Ldap_Node_Schema_ActiveDirectory does not provide any additional methods.

Tableau 87. Zend_Ldap_Node_Schema_AttributeType_ActiveDirectory API

Zend_Ldap_Node_Schema_AttributeType_ActiveDirectory does not provide any


additional methods.

902
Zend_Ldap

Tableau 88. Zend_Ldap_Node_Schema_ObjectClass_ActiveDirectory API

Zend_Ldap_Node_Schema_ObjectClass_ActiveDirectory does not provide any


additional methods.

2.2.8. Zend_Ldif_Encoder

Tableau 89. Zend_Ldif_Encoder API

Method Description
array decode(string $string) Decodes the string $string into an array of
LDIF items.
string encode(scalar|array| Encode $value into a LDIF representation.
Zend_Ldap_Node $value, array $options is an array that may contain the
$options) following keys:

'sort' Sort the given attributes with


dn following objectClass and
following all other attributes
sorted alphabetically. TRUE by
default.

'version' The LDIF format version. 1 by


default.

'wrap' The line-length. 78 by default


to conform to the LDIF
specification.

3. Usage Scenarios
3.1. Authentication scenarios
3.1.1. OpenLDAP

3.1.2. ActiveDirectory

903
Zend_Ldap

3.2. Basic CRUD operations


3.2.1. Retrieving data from the LDAP

Exemple 452. Getting an entry by its DN

$options = array(/* ... */);


$ldap = new Zend_Ldap($options);
$ldap->bind();
$hm = $ldap->getEntry('cn=Hugo Müller,ou=People,dc=my,dc=local');
/*
$hm is an array of the following structure
array(
'dn' => 'cn=Hugo Müller,ou=People,dc=my,dc=local',
'cn' => array('Hugo Müller'),
'sn' => array('Müller'),
'objectclass' => array('inetOrgPerson', 'top'),
...
)
*/

Exemple 453. Check for the existence of a given DN

$options = array(/* ... */);


$ldap = new Zend_Ldap($options);
$ldap->bind();
$isThere = $ldap->exists('cn=Hugo Müller,ou=People,dc=my,dc=local');

Exemple 454. Count children of a given DN

$options = array(/* ... */);


$ldap = new Zend_Ldap($options);
$ldap->bind();
$childrenCount = $ldap->countChildren(
'cn=Hugo Müller,ou=People,dc=my,dc=local');

Exemple 455. Searching the LDAP tree

$options = array(/* ... */);


$ldap = new Zend_Ldap($options);
$ldap->bind();
$result = $ldap->search('(objectclass=*)',
'ou=People,dc=my,dc=local',
Zend_Ldap_Ext::SEARCH_SCOPE_ONE);
foreach ($result as $item) {
echo $item["dn"] . ': ' . $item['cn'][0] . PHP_EOL;
}

904
Zend_Ldap

3.2.2. Adding data to the LDAP


Exemple 456. Add a new entry to the LDAP

$options = array(/* ... */);


$ldap = new Zend_Ldap($options);
$ldap->bind();
$entry = array();
Zend_Ldap_Attribute::setAttribute($entry, 'cn', 'Hans Meier');
Zend_Ldap_Attribute::setAttribute($entry, 'sn', 'Meier');
Zend_Ldap_Attribute::setAttribute($entry, 'objectClass', 'inetOrgPerson');
$ldap->add('cn=Hans Meier,ou=People,dc=my,dc=local', $entry);

3.2.3. Deleting from the LDAP


Exemple 457. Delete an existing entry from the LDAP

$options = array(/* ... */);


$ldap = new Zend_Ldap($options);
$ldap->bind();
$ldap->delete('cn=Hans Meier,ou=People,dc=my,dc=local');

3.2.4. Updating the LDAP


Exemple 458. Update an existing entry on the LDAP

$options = array(/* ... */);


$ldap = new Zend_Ldap($options);
$ldap->bind();
$hm = $ldap->getEntry('cn=Hugo Müller,ou=People,dc=my,dc=local');
Zend_Ldap_Attribute::setAttribute($hm, 'mail', 'mueller@my.local');
Zend_Ldap_Attribute::setPassword($hm,
'newPa$$w0rd',
Zend_Ldap_Attribute::PASSWORD_HASH_SHA1);
$ldap->update('cn=Hugo Müller,ou=People,dc=my,dc=local', $hm);

3.3. Extended operations


3.3.1. Copy and move entries in the LDAP
Exemple 459. Copy a LDAP entry recursively with all its descendants

$options = array(/* ... */);


$ldap = new Zend_Ldap($options);
$ldap->bind();
$ldap->copy('cn=Hugo Müller,ou=People,dc=my,dc=local',
'cn=Hans Meier,ou=People,dc=my,dc=local',
true);

Exemple 460. Move a LDAP entry recursively with all its descendants to a
different subtree

$options = array(/* ... */);


$ldap = new Zend_Ldap($options);
$ldap->bind();
$ldap->moveToSubtree('cn=Hugo Müller,ou=People,dc=my,dc=local',
'ou=Dismissed,dc=my,dc=local',
true);

905
Zend_Ldap

4. Tools
4.1. Creation and modification of DN strings

4.2. Using the filter API to create search filters


Exemple 461. Create simple LDAP filters

$f1 = Zend_Ldap_Filter::equals('name', 'value'); // (name=value)


$f2 = Zend_Ldap_Filter::begins('name', 'value'); // (name=value*)
$f3 = Zend_Ldap_Filter::ends('name', 'value'); // (name=*value)
$f4 = Zend_Ldap_Filter::contains('name', 'value'); // (name=*value*)
$f5 = Zend_Ldap_Filter::greater('name', 'value'); // (name>value)
$f6 = Zend_Ldap_Filter::greaterOrEqual('name', 'value'); // (name>=value)
$f7 = Zend_Ldap_Filter::less('name', 'value'); // (name<value)
$f8 = Zend_Ldap_Filter::lessOrEqual('name', 'value'); // (name<=value)
$f9 = Zend_Ldap_Filter::approx('name', 'value'); // (name~=value)
$f10 = Zend_Ldap_Filter::any('name'); // (name=*)

Exemple 462. Create more complex LDAP filters

$f1 = Zend_Ldap_Filter::ends('name', 'value')->negate(); // (!(name=*value))

$f2 = Zend_Ldap_Filter::equals('name', 'value');


$f3 = Zend_Ldap_Filter::begins('name', 'value');
$f4 = Zend_Ldap_Filter::ends('name', 'value');

// (&(name=value)(name=value*)(name=*value))
$f5 = Zend_Ldap_Filter::andFilter($f2, $f3, $f4);

// (|(name=value)(name=value*)(name=*value))
$f6 = Zend_Ldap_Filter::orFilter($f2, $f3, $f4);

4.3. Modify LDAP entries using the Attribute API

5. Object oriented access to the LDAP tree using


Zend_Ldap_Node
5.1. Basic CRUD operations
5.1.1. Retrieving data from the LDAP

5.1.1.1. Getting a node by its DN

5.1.1.2. Searching a node's subtree

5.1.2. Adding a new node to the LDAP

906
Zend_Ldap

5.1.3. Deleting a node from the LDAP

5.1.4. Updating a node on the LDAP

5.2. Extended operations


5.2.1. Copy and move nodes in the LDAP

5.3. Tree traversal


Exemple 463. Traverse LDAP tree recursively

$options = array(/* ... */);


$ldap = new Zend_Ldap($options);
$ldap->bind();
$ri = new RecursiveIteratorIterator($ldap->getBaseNode(),
RecursiveIteratorIterator::SELF_FIRST);
foreach ($ri as $rdn => $n) {
var_dump($n);
}

6. Getting information from the LDAP server


6.1. RootDSE
See the following documents for more information on the attributes contained within the RootDSE
for a given LDAP server.

• OpenLDAP

• Microsoft ActiveDirectory

• Novell eDirectory

Exemple 464. Getting hands on the RootDSE

$options = array(/* ... */);


$ldap = new Zend_Ldap($options);
$rootdse = $ldap->getRootDse();
$serverType = $rootdse->getServerType();

6.2. Schema Browsing


Exemple 465. Getting hands on the server schema

$options = array(/* ... */);


$ldap = new Zend_Ldap($options);
$schema = $ldap->getSchema();
$classes = $schema->getObjectClasses();

6.2.1. OpenLDAP

907
Zend_Ldap

6.2.2. ActiveDirectory

Schema browsing on ActiveDirectory servers

Due to restrictions on Microsoft ActiveDirectory servers regarding the number


of entries returned by generic search routines and due to the structure of the
ActiveDirectory schema repository, schema browsing is currently not available
for Microsoft ActiveDirectory servers.

7. Serializing LDAP data to and from LDIF


7.1. Serialize a LDAP entry to LDIF
$data = array(
'dn' => 'uid=rogasawara,ou=###,o=Airius',
'objectclass' => array('top',
'person',
'organizationalPerson',
'inetOrgPerson'),
'uid' => array('rogasawara'),
'mail' => array('rogasawara@airius.co.jp'),
'givenname;lang-ja' => array('####'),
'sn;lang-ja' => array('###'),
'cn;lang-ja' => array('### ####'),
'title;lang-ja' => array('### ##'),
'preferredlanguage' => array('ja'),
'givenname' => array('####'),
'sn' => array('###'),
'cn' => array('### ####'),
'title' => array('### ##'),
'givenname;lang-ja;phonetic' => array('####'),
'sn;lang-ja;phonetic' => array('#####'),
'cn;lang-ja;phonetic' => array('##### ####'),
'title;lang-ja;phonetic' => array('###### ####'),
'givenname;lang-en' => array('Rodney'),
'sn;lang-en' => array('Ogasawara'),
'cn;lang-en' => array('Rodney Ogasawara'),
'title;lang-en' => array('Sales, Director'),
);
$ldif = Zend_Ldap_Ldif_Encoder::encode($data, array('sort' => false,
'version' => null));
/*
$ldif contains:
dn:: dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVz
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: rogasawara
mail: rogasawara@airius.co.jp
givenname;lang-ja:: 44Ot44OJ44OL44O8
sn;lang-ja:: 5bCP56yg5Y6f
cn;lang-ja:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
title;lang-ja:: 5Za25qWt6YOoIOmDqOmVtw==
preferredlanguage: ja
givenname:: 44Ot44OJ44OL44O8
sn:: 5bCP56yg5Y6f

908
Zend_Ldap

cn:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
title:: 5Za25qWt6YOoIOmDqOmVtw==
givenname;lang-ja;phonetic:: 44KN44Gp44Gr44O8
sn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJ
cn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJIOOCjeOBqeOBq+ODvA==
title;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2IOOBtuOBoeOCh+OBhg==
givenname;lang-en: Rodney
sn;lang-en: Ogasawara
cn;lang-en: Rodney Ogasawara
title;lang-en: Sales, Director
*/

7.2. Deserialize a LDIF string into a LDAP entry


$ldif = "dn:: dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVz
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: rogasawara
mail: rogasawara@airius.co.jp
givenname;lang-ja:: 44Ot44OJ44OL44O8
sn;lang-ja:: 5bCP56yg5Y6f
cn;lang-ja:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
title;lang-ja:: 5Za25qWt6YOoIOmDqOmVtw==
preferredlanguage: ja
givenname:: 44Ot44OJ44OL44O8
sn:: 5bCP56yg5Y6f
cn:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
title:: 5Za25qWt6YOoIOmDqOmVtw==
givenname;lang-ja;phonetic:: 44KN44Gp44Gr44O8
sn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJ
cn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJIOOCjeOBqeOBq+ODvA==
title;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2IOOBtuOBoeOCh+OBhg==
givenname;lang-en: Rodney
sn;lang-en: Ogasawara
cn;lang-en: Rodney Ogasawara
title;lang-en: Sales, Director";
$data = Zend_Ldap_Ldif_Encoder::decode($ldif);
/*
$data = array(
'dn' => 'uid=rogasawara,ou=###,o=Airius',
'objectclass' => array('top',
'person',
'organizationalPerson',
'inetOrgPerson'),
'uid' => array('rogasawara'),
'mail' => array('rogasawara@airius.co.jp'),
'givenname;lang-ja' => array('####'),
'sn;lang-ja' => array('###'),
'cn;lang-ja' => array('### ####'),
'title;lang-ja' => array('### ##'),
'preferredlanguage' => array('ja'),
'givenname' => array('####'),
'sn' => array('###'),
'cn' => array('### ####'),
'title' => array('### ##'),
'givenname;lang-ja;phonetic' => array('####'),
'sn;lang-ja;phonetic' => array('#####'),

909
Zend_Ldap

'cn;lang-ja;phonetic' => array('##### ####'),


'title;lang-ja;phonetic' => array('###### ####'),
'givenname;lang-en' => array('Rodney'),
'sn;lang-en' => array('Ogasawara'),
'cn;lang-en' => array('Rodney Ogasawara'),
'title;lang-en' => array('Sales, Director'),
);
*/

910
Zend_Loader
1. Charger les fichiers et les classes dynamiquement
La classe Zend_Loader inclut des méthodes afin de vous aider à charger des fichiers
dynamiquement.

Zend_Loader contre require_once()


Les méthodes Zend_Loader sont les meilleures à utiliser si le nom de fichier
que vous devez charger est variable. Par exemple, s'il est basé sur un paramètre
de la saisie de l'utilisateur ou un argument de méthode. Si vous chargez un fichier
ou une classe dont le nom est constant, il n'y a aucun avantage à l'utilisation
de Zend_Loader sur l'utilisation de fonctions de PHP traditionnelles comme
require_once().

1.1. Charger des fichiers


La méthode statique Zend_Loader::loadFile() charge un fichier PHP, qui peut contenir
du code PHP arbitraire. Cette méthode enveloppe la fonction PHP include(), et retournera le
booléen FALSE si le fichier n'existe pas.

Exemple 466. Exemple d'utilisation de la méthode loadFile()

Zend_Loader::loadFile($filename, $dirs=null, $once=false);

L'argument $filename définit le nom du fichier à charger, et il ne doit contenir aucune


information concernant son chemin d'accès. Une vérification de sécurité est effectuée sur
$filename. Le fichier $filename ne peut contenir que des caractères alphanumérique, des
tirets ("-"), des tirets-bas ("_") ou des points ("."). Aucune de ces restrictions ne s'applique à
l'argument $dirs.

L'argument $dirs définit les dossiers où rechercher le fichier. Si NULL, la recherche s'effectuera
uniquement dans les dossiers définis par la variable include_path. Si c'est une chaîne ou
un tableau, le ou les répertoires spécifiés seront scannés, ainsi que les dossiers définis par la
variable include_path.

L'argument $once est un booléen. Si TRUE, Zend_Loader::loadFile() utilise la fonction


PHP include_once() pour charger le fichier sinon la fonction PHP include() est utilisée.

1.2. Charger des classes


La méthode statique Zend_Loader::loadClass($class, $dirs) charge un fichier PHP
et vérifie l'existence de la classe.

Exemple 467. Exemple d'utilisation de la méthode loadClass()

Zend_Loader::loadClass('Container_Tree',
array(
'/home/production/mylib',
'/home/production/myapp'
)
);

911
Zend_Loader

La chaîne spécifiant la classe est convertie en chemin relatif en remplaçant les tirets bas
("_") par le séparateur de dossier puis en ajoutant le bloc ".php". Dans l'exemple ci-dessus,
"Container_Tree" devient "Container\\Tree.php".

Si $dirs est une chaîne ou un tableau, Zend_Loader::loadClass() va chercher dans les


dossiers suivant l'ordre donné. Le premier fichier trouvé est chargé. Si le fichier n'existe pas dans
les dossiers spécifiés $dirs, alors la recherche est effectuée dans include_path du PHP.

Si le fichier n'est pas trouvé ou que la classe n'existe pas après le chargement,
Zend_Loader::loadClass() lèvera une exception Zend_Exception

Zend_Loader::loadFile() est utilisé pour le chargement, donc le nom de la classe ne peut


contenir que des caractères alphanumériques et les caractères tiret ("-"), tiret bas ("_"), et point
(".").

Loading Classes from PHP Namespaces


Starting in version 1.10.0, Zend Framework now allows loading classes from
PHP namespaces. This support follows the same guidelines and implementation
as that found in the PHP Framework Interop Group PSR-0 reference
implementation.

Under this guideline, the following rules apply:

• Each namespace separator is converted to a DIRECTORY_SEPARATOR when


loading from the file system.

• Each "_" character in the CLASS NAME is converted to a


DIRECTORY_SEPARATOR. The "_" character has no special meaning in the
namespace.

• The fully-qualified namespace and class is suffixed with ".php" when loading
from the file system.

As examples:

• \Doctrine\Common\IsolatedClassLoader => /path/to/project/


lib/vendor/Doctrine/Common/IsolatedClassLoader.php

• \namespace\package\Class_Name => /path/to/project/lib/


vendor/namespace/package/Class/Name.php

• \namespace\package_name\Class_Name => /path/to/project/


lib/vendor/namespace/package_name/Class/Name.php

1.3. Tester si un fichier est lisible


La méthode statique Zend_Loader::isReadable($pathname) retourne TRUE si le fichier
existe dans le dossier spécifié et qu'il est lisible, sinon FALSE.

Exemple 468. Exemple d'utilisation de la méthode isReadable()

if (Zend_Loader::isReadable($filename)) {
// puis manipulation avec $filename
}

912
Zend_Loader

L'argument $filename spécifie le nom du fichier à vérifier. Il peut contenir des informations
concernant le chemin d'accès. Cette méthode enveloppe la fonction PHP is_readable().
La fonction PHP ne recherche pas le fichier spécifié dans les répertoires de l'include_path,
contrairement à Zend_Loader::isReadable().

1.4. Utiliser l'autoloader


La classe Zend_Loader contient une méthode Zend_Loader::autoload() que vous
pouvez inscrire dans le PHP SPL autoloader. Par commodité, Zend_Loader fournit la
fonction registerAutoload() qui enregistre automatiquement sa méthode autoload(). Si
l'extension spl_autoload n'est pas présente dans l'environnement PHP, alors la méthode
registerAutoload() lèvera une Zend_Exception.

Exemple 469. Exemple d'inscription de la méthode de callback autoloader

Zend_Loader::registerAutoload();

Après avoir inscrit le callback vers l'autoload de Zend Framework, vous pouvez appeler une
classe de Zend Framework sans l'avoir explicitement chargé auparavant. La méthode autoload
utilise automatiquement Zend_Loader::loadClass() quand vous appelez une classe.

Si vous avez étendu la classe Zend_Loader, vous pouvez passer un argument optionnel
à registerAutoload(), pour spécifier la classe de laquelle vous souhaitez enregistrer la
méthode autoload().

Exemple 470. Exemple d'inscription de la méthode de callback autoloader d'une


classe étendue

A cause de la sémantique de référencement des fonctions statiques en PHP, vous devez


implémenter le code pour les méthodes loadClass() et autoload(), et la méthode
autoload() doit appeler self::loadClass(). Si votre méthode autoload() délégue
à son parent l'appel self::loadClass(), alors cela appellerait la méthode de même nom
dans la classe parente et non dans la sous-classe.

class Mon_Chargeur extends Zend_Loader


{
public static function loadClass($class, $dirs = null)
{
parent::loadClass($class, $dirs);
}

public static function autoload($class)


{
try {
self::loadClass($class);
return $class;
} catch (Exception $e) {
return false;
}
}}

Zend_Loader::registerAutoload('Mon_Chargeur');

Vous pouvez effacer un callback d'autoload. registerAutoload() a un paramètre optionnel,


qui est réglé à TRUE par défaut. S'il vaut FALSE, le callback de l'autoload est alors effacé de la
pile des autoload SPL.

913
Zend_Loader

2. L'autoloader
Zend_Loader_Autoloader propose une solution intelligente et souple d'auto-chargement
(autoload) pour Zend Framework. Il a été conçu pour remplir plusieurs objectifs :

• Proposer un autoloader à base d'espaces de noms (auparavant, les espaces de noms étaient
interceptés).

• Proposer d'enregistrer des autoloads personnalisés, et les gérer comme une pile. (A l'heure
actuelle, ceci permet de s'affranchir de certaines contraintes avec spl_autoload, qui ne
permet pas le ré-enregistrement d'une fonction à base d'objet).

• Proposer un autoload optimisé pour les espaces de noms, qui permet une meilleure résolution
des noms de classes.

Zend_Loader_Autoloader est un singleton, il est donc universellement accessible. Ceci


permet d'enregistrer des autoload depuis n'importe où dans votre code.

2.1. Utiliser le chargeur automatique (autoloader)


La première fois qu'une instance de l'autoloader est créée, il s'enregistre lui-même sur la fonction
spl_autoload. Vous récupérez son instance via la méthode getInstance() :

$autoloader = Zend_Loader_Autoloader::getInstance();

Par défaut, l'autoloader est configuré pour capturer les espaces de noms "Zend_" et "ZendX_".
Si votre propre librairie de code utilise un espace de noms différent, vous devez alors enregistrer
celui-ci avec la méthode registerNamespace(). Par exemple, si votre librairie possède
l'espace de noms "My_", vous devriez agir comme cela :

$autoloader->registerNamespace('My_');

Préfixes des espaces de noms


Notez que l'exemple précédent enregistre "My_" et non "My". Ceci car
Zend_Loader_Autoloader est un autoloader global, et n'a aucune idée qu'un
préfixe de classe possède un underscore. Si c'est votre cas, alors faites le
apparaître lors de son enregistrement dans l'autoloader.

Il est aussi possible que vous enregistriez vos propres fonctions d'autoload, optionnellement
avec un espace de noms spécifique, Zend_Loader_Autoloader va alors tenter de l'utiliser
lorsque nécessaire (lors de l'auto-chargement).

Par exemple, vous pourriez avoir besoin d'un ou plusieurs composants eZcomponents avec
votre application Zend Framework. Pour utiliser ses capacités d'autoload, ajoutez son autoloader
à votre pile grâce à pushAutoloader() :

$autoloader->pushAutoloader(array('ezcBase', 'autoload'), 'ezc');

Ceci indique que les classes dont le nom commence par "ezc" devra utiliser cette fonction
d'autoload.

unshiftAutoloader(), elle, rajoute la méthode d'autoload au début de la pile.

Par défaut, Zend_Loader_Autoloader ne supprime aucune erreur lorsqu'il utilise son


autoloader interne, s'appuyant sur Zend_Loader::loadClass(). La plupart du temps, c'est

914
Zend_Loader

le comportement recherché. Cependant, si vous voulez faire apparaître les éventuelles erreurs
de chargement, appelez alors suppressNotFoundWarnings() :

$autoloader->suppressNotFoundWarnings(true);

Enfin, il se peut que vous vouliez que l'autoloader par défaut charge toutes les classes de tous
les espaces de noms. Par exemple, les librairies PEAR ne partagent pas un espace de noms
commun, ce qui rend la tâche difficile si on veut associer chacun des espaces de noms internes.
Utilisez alors setFallbackAutoloader() pour rendre l'autoloader "global" et charger tous
les espaces de noms :

$autoloader->setFallbackAutoloader(true);

Loading Classes from PHP Namespaces

Starting in version 1.10.0, Zend Framework now allows loading classes from
PHP namespaces. This support follows the same guidelines and implementation
as that found in the PHP Framework Interop Group PSR-0 reference
implementation.

Under this guideline, the following rules apply:

• Each namespace separator is converted to a DIRECTORY_SEPARATOR when


loading from the file system.

• Each "_" character in the CLASS NAME is converted to a


DIRECTORY_SEPARATOR. The "_" character has no special meaning in the
namespace.

• The fully-qualified namespace and class is suffixed with ".php" when loading
from the file system.

As examples:

• \Doctrine\Common\IsolatedClassLoader => /path/to/project/


lib/vendor/Doctrine/Common/IsolatedClassLoader.php

• \namespace\package\Class_Name => /path/to/project/lib/


vendor/namespace/package/Class/Name.php

• \namespace\package_name\Class_Name => /path/to/project/


lib/vendor/namespace/package_name/Class/Name.php

2.2. Selecting a Zend Framework version


Typically, you will use the version of Zend Framework that the autoloader you instantiate came
with. However, when developing a project, it's often useful to track specific versions, major or
minor branches, or just the latest version. Zend_Loader_Autoloader, as of version 1.10,
offers some features to help manage this task.

Imagine the following scenario:

• During development, you want to track the latest version of Zend Framework you have
installed, so that you can ensure the application works when you upgrade between versions.

915
Zend_Loader

When pushing to Quality Assurance, however, you need to have slightly more stability, so you
want to use the latest installed revision of a specific minor version.

Finally, when you push to production, you want to pin to a specific installed version, to ensure
no breakage occurs if or when you add new versions of Zend Framework to you server.

The autoloader allows you to do this with the method setZfPath(). This method takes two
arguments, a path to a set of Zend Framework installations, and a version to use. Once invoked,
it prepends a path to the include_path pointing to the appropriate Zend Framework installation
library.

The directory you specify as your path should have a tree such as the following:

ZendFramework/
|-- 1.9.2/
| |-- library/
|-- ZendFramework-1.9.1-minimal/
| |-- library/
|-- 1.8.4PL1/
| |-- library/
|-- 1.8.4/
| |-- library/
|-- ZendFramework-1.8.3/
| |-- library/
|-- 1.7.8/
| |-- library/
|-- 1.7.7/
| |-- library/
|-- 1.7.6/
| |-- library/

(where path points to the directory "ZendFramework" in the above example)

Note that each subdirectory should contain the directory library, which contains the actual
Zend Framework library code. The individual subdirectory names may be version numbers, or
simply be the untarred contents of a standard Zend Framework distribution tarball/zipfile.

Now, let's address the use cases. In the first use case, in development, we want to track the
latest source install. We can do that by passing "latest" as the version:

$autoloader->setZfPath($path, 'latest');

In the example from above, this will map to the directory ZendFramework/1.9.2/library/;
you can verify this by checking the return value of getZfPath().

In the second situation, for quality assurance, let's say we want to pin to the 1.8 minor release,
using the latest install you have for that release. You can do so as follows:

$autoloader->setZfPath($path, '1.8');

In this case, it will find the directory ZendFramework/1.8.4PL1/library/.

In the final case, for production, we'll pin to a specific version -- 1.7.7, since that was what was
available when Quality Assurance tested prior to our release.

$autoloader->setZfPath($path, '1.7.7');

916
Zend_Loader

Predictably, it finds the directory ZendFramework/1.7.7/library/.

You can also specify these values in the configuration file you use with Zend_Application.
To do so, you'd specify the following information:

[production]
autoloaderZfPath = "path/to/ZendFramework"
autoloaderZfVersion = "1.7.7"

[qa]
autoloaderZfVersion = "1.8"

[development]
autoloaderZfVersion = "latest"

Note the different environment sections, and the different version specified in each environment;
these factors will allow Zend_Application to configure the autoloader appropriately.

Performance implications
For best performance, either do not use this feature, or specify a specific Zend
Framework version (i.e., not "latest", a major revision such as "1", or a minor
revision such as "1.8"). Otherwise, the autoloader will need to scan the provided
path for directories matching the criteria -- a somewhat expensive operation to
perform on each request.

2.3. L'interface de l'autoloader


Vous pouvez donc ajouter des fonctions de chargement par espace de
noms, mais Zend Framework définit aussi une interface pour l'autoload,
Zend_Loader_Autoloader_Interface :

interface Zend_Loader_Autoloader_Interface
{
public function autoload($class);
}

L'utilisation de l'interface vous permet de passer un objet aux méthodes pushAutoloader()


et unshiftAutoloader() de Zend_Loader_Autoloader :

// Foo_Autoloader implémente Zend_Loader_Autoloader_Interface:


$foo = new Foo_Autoloader();

$autoloader->pushAutoloader($foo, 'Foo_');

2.4. Référence de l'autoloader


Voici un guide des méthodes de Zend_Loader_Autoloader.

Tableau 90. Méthodes de Zend_Loader_Autoloader


Méthode Valeur de retour Paramètres Description
getInstance() N/A
Zend_Loader_Autoloader Retourne l'instance
singleton de
Zend_Loader_Autoloader
Au premier appel,
enregistre l'autoloader

917
Zend_Loader

Méthode Valeur de retour Paramètres Description


avec spl_autoload.
Cette méthode est
statique.
resetInstance() void N/A Remet à zéro
l'état interne de
Zend_Loader_Autoloader
en désenregistrant les
fonctions d'autoload
éventuellement
présentes, ainsi que
tous les espaces de
noms.
autoload($class) string|false • $class, requis. Essaye de résoudre
Une classe à un nom de classe en
charger. fichier, et tente de la
charger.
setDefaultAutoloader($callback) • $callback, requis. Spécifie une fonction
Zend_Loader_Autoloader
PHP à utiliser comme
autoloader par défaut.
getDefaultAutoloader()
callback N/A Retourne la fonction
d'autoload par défaut,
il s'agit par défaut de
Zend_Loader::loadClass().
setAutoloaders(array • $autoloaders,
Zend_Loader_Autoloader Passe une liste
$autoloaders) requis. d'autoloaders (sous
forme de noms de
fonctions PHP) Ã
ajouter à la pile de
ceux déjà présents.
getAutoloaders() Array N/A Récupère la pile
d'autoloaders interne.
Array
getNamespaceAutoloaders($namespace) • $namespace, Récupère tous les
requis autoloaders qui sont
associés à un certain
espace de noms.
registerNamespace($namespace) • $namespace,
Zend_Loader_Autoloader Enregistre un ou
requis. plusieurs espaces
de noms, avec
l'autoloader par défaut.
Si $namespace est
une chaîne, c'est cet
espace de noms qui
sera enregistré, si c'est
un tableau de chaînes,
ils le seront tous.
unregisterNamespace($namespace) • $namespace,
Zend_Loader_Autoloader Désenregistre
requis. (supprime) un espace
de noms depuis
l'autoloader par défaut.

918
Zend_Loader

Méthode Valeur de retour Paramètres Description


Si $namespace est
une chaîne, c'est cet
espace de noms qui
sera désenregistré, si
c'est un tableau de
chaînes, ils le seront
tous.
Array
getRegisteredNamespaces() N/A Retourne un tableau
comportant tous les
espaces de noms
enregistrés avec
l'autoloader par défaut.
suppressNotFoundWarnings($flag
boolean| • $flag, optionnel. Affecte ou récupère
= null) Zend_Loader_Autoloader la valeur du
paramètre indiquant
si l'autoloader par
défaut doit supprimer
les warnings "file
not found". Si aucun
argument (ou null) lui
est passé, il retourne
sa valeur actuelle,
dans le cas contraire,
il retournera l'instance
de l'autoloader
permettant le chainage
des méthodes.
setFallbackAutoloader($flag) • $flag, requis.
Zend_Loader_Autoloader Affecte la valeur
du drapeau utilisé
pour déterminer si
l'autoloader par défaut
doit être utilisé
comme "catch-all"
pour charger tous les
espaces de noms.
Boolean
isFallbackAutoloader() N/A Retourne la valeur
du drapeau utilisé
pour déterminer si
l'autoloader par défaut
doit être utilisé
comme "catch-all"
pour charger tous les
espaces de noms.
Array
getClassAutoloaders($class) • $class, requis. Retourne une liste
d'autoloaders
d'espaces de noms
qui pourraient
correspondre à la
classe indiquée. Si
aucun ne correspond,

919
Zend_Loader

Méthode Valeur de retour Paramètres Description


la liste de tous les
autoloaders globaux
(non associés à des
espaces de noms)
sera retournée.
unshiftAutoloader($callback, • $callback, requis. Ajoute un autoloader
Zend_Loader_Autoloader
$namespace = '') Une fonction PHP au début de la pile des
valide. autoloaders internes.
Si un espace de noms
• $namespace, est fourni, il sera utilisé
optionnel. Une pour cet autoloader,
chaîne représentant sinon l'autoloader sera
un préfixe de classe. global.
pushAutoloader($callback, • $callback, requis. Ajoute un autoloader à
Zend_Loader_Autoloader
$namespace = '') Une fonction PHP la fin de la pile des
valide. autoloaders internes.
Si un espace de noms
• $namespace, est fourni, il sera utilisé
optionnel. Une pour cet autoloader,
chaîne représentant sinon l'autoloader sera
un préfixe de classe. global.
removeAutoloader($callback, • $callback, requis. Supprime
Zend_Loader_Autoloader un
$namespace = '') Une fonction PHP autoloader de la pile
valide. interne. Si un espace
de noms est indiqué,
• $namespace, supprime l'autoloader
optionnel. Une pour cet espace de
chaîne représentant noms uniquement.
un préfixe de classe,
ou un tableau de
chaînes.

3. Autoloaders de ressources
Les autoloaders de ressources servent à manipuler du code de librairies dans des espaces
de noms, respectant les conventions de codage du Zend Framework, mais n'ayant pas une
correspondance 1:1 entre le nom de la classe et la structure du dossier. Leur but est de faciliter
le chargement du code des ressources de l'application, comme les modèles, les ACLs, les
formulaires...

Les autoloaders de ressources s'enregistrent dans l'autoloader à leur instanciation, avec l'espace
de noms auxquels ils sont rattachés. Ceci permet de facilement isoler du code dans des dossiers,
sous l'espace de noms, tout en gardant les bénéfices de l'autoload.

3.1. Utilisation de l'autoloader de ressources


Soit la structure de répertoires suivante :

path/to/some/directory/
acls/
Site.php
forms/

920
Zend_Loader

Login.php
models/
User.php

Au sein de ce répertoire, toutes les classes sont préfixées par l'espace de noms "My_". Dans le
dossier "acls", le préfixe de composant "Acl_" est ajouté, ce qui donne un nom de classe final
"My_Acl_Site". Aussi, le dossier "forms" correspond à "Form_", ce qui donne "My_Form_Login".
Le dossier "models" n'a pas d'espace de noms particulier, donnant donc "My_User".

Pour instancier un autoloader de ressoucres, il faut au minimum lui passer son dossier de travail
(base path), et le nom de l'espace de noms correspondant :

$resourceLoader = new Zend_Loader_Autoloader_Resource(array(


'basePath' => 'path/to/some/directory',
'namespace' => 'My',
));

Espace de noms de base


Dans Zend_Loader_Autoloader, vous devez spécifier le underscore final
("_") dans votre espace de noms. Zend_Loader_Autoloader_Resource
suppose par contre que tout le code à auto-charger utilisera le séparateur
d'espaces de noms underscore. Ainsi, vous n'avez pas besoin de le préciser avec
l'autoloader de ressources.

Maintenant que notre autoloader est configuré, nous pouvons ajouter des composants à auto-
charger. Ceci se fait via la méthode addResourceType(), qui accepte 3 arguments : un "type"
de ressource, utiliser en interne comme nom de référence ; le sous dossier dans lequel la
ressource en question est logé, et l'espace de noms du composant à rajouter à l'espace de noms
général. Voici un exemple :

$resourceLoader->addResourceType('acl', 'acls/', 'Acl')


->addResourceType('form', 'forms/', 'Form')
->addResourceType('model', 'models/');

Aussi, vous auriez pu effectuer la même action avec un tableau PHP. addResourceTypes()
est alors appropriée :

$resourceLoader->addResourceTypes(array(
'acl' => array(
'path' => 'acls/',
'namespace' => 'Acl',
),
'form' => array(
'path' => 'forms/',
'namespace' => 'Form',
),
'model' => array(
'path' => 'models/',
),
));

Enfin, vous pouvez spécifier tout cela d'un seul coup avec des tableaux nichés. La clé doit alors
être "resourceTypes" :

$resourceLoader = new Zend_Loader_Autoloader_Resource(array(


'basePath' => 'path/to/some/directory',

921
Zend_Loader

'namespace' => 'My',


'resourceTypes' => array(
'acl' => array(
'path' => 'acls/',
'namespace' => 'Acl',
),
'form' => array(
'path' => 'forms/',
'namespace' => 'Form',
),
'model' => array(
'path' => 'models/',
),
),
));

3.2. L'autoloader de ressource Module


Zend Framework fournit une implémentation concrète de
Zend_Loader_Autoloader_Resource qui contient des correspondances de ressources
pour mettre en avant la structure modulaire par défaut que propose le Zend Framework dans
ses applications MVC. Ce chargeur, Zend_Application_Module_Autoloader, propose le
mapping suivant :

forms/ => Form


models/ => Model
DbTable/ => Model_DbTable
mappers/ => Model_Mapper
plugins/ => Plugin
services/ => Service
views/
helpers => View_Helper
filters => View_Filter

Par exemple, avec un module dont le préfixe est "Blog_", le chargement de la classe
"Blog_Form_Entry" mènerait au chargement du fichier "forms/Entry.php".

En utilisant les bootstraps de modules avec Zend_Application, une instance de


Zend_Application_Module_Autoloader sera crée pour chaque module utilisé.

3.3. Utiliser les autoloaders de ressources comme fabriques


d'objets

3.4. Référence de l'autoloader de ressources

4. Chargeur de Plugins
Zend Framework vous propose l'utilisation de composants "pluggables", que vous créez
vous même. Ceux-ci ne sont pas forcément dans l'include_path. De même, ils ne
suivent pas forcément les mêmes règles de nommage que les composants de Zend
Framework.Zend_Loader_PluginLoader propose une solution à ce problème.

PluginLoader suit la convention "une classe par fichier" et les tirets bas sont utilisés comme
séparateurs de dossiers. Il accepte aussi qu'un préfixe optionnel lui soit passé, afin de charger

922
Zend_Loader

une classe. Tous les chemins sont analysés en ordre LIFO. Grâce à ces deux spécificités, vous
pouvez "namespacer" vos plugins, et écraser les plugins enregistrés plus tôt.

4.1. Utilisation basique


Même si nous parlons de "plugins", ce n'est pas réservé aux plugins de contrôleur frontal, mais
bien à toute classe étant utilisée avec Zend Framework. Imaginons une structure de répertoires
comme suit, dans laquelle les dossiers "application" et "library" sont dans l'include_path :

application/
modules/
foo/
views/
helpers/
FormLabel.php
FormSubmit.php
bar/
views/
helpers/
FormSubmit.php
library/
Zend/
View/
Helper/
FormLabel.php
FormSubmit.php
FormText.php

Maintenant créons un chargeur de plugins pour utiliser les différentes classes d'aides de vue :

$loader = new Zend_Loader_PluginLoader();


$loader->addPrefixPath('Zend_View_Helper',
'Zend/View/Helper/')
->addPrefixPath('Foo_View_Helper',
'application/modules/foo/views/helpers')
->addPrefixPath('Bar_View_Helper',
'application/modules/bar/views/helpers');

Il devient alors possible de charger une aide de vue en spécifiant juste le nom de sa classe :

// charge l'aide 'FormText' :


$formTextClass = $loader->load('FormText');
// 'Zend_View_Helper_FormText'

// charge l'aide 'FormLabel' :


$formLabelClass = $loader->load('FormLabel');
// 'Foo_View_Helper_FormLabel'

// charge l'aide 'FormSubmit' :


$formSubmitClass = $loader->load('FormSubmit');
// 'Bar_View_Helper_FormSubmit'

Une fois chargée, la classe devient instanciable.

Plusieurs dossiers peuvent être assignés à un même préfixe


Vous pouvez "namespacer" vos composants en enregistrant plusieurs chemins
pour un même préfixe.Zend_Loader_PluginLoader cherchera alors en ordre

923
Zend_Loader

LIFO (dernier arrivé, premier sorti). Ceci est pratique pour court-circuiter ses
composants et utiliser ceux en incubateur, par exemple.

Paramétrage des chemins dans le constructeur


En constructeur, passez un tableau de paires prefix / path ou prefix / paths --
plusieurs dossiers par préfixe :

$loader = new Zend_Loader_PluginLoader(array(


'Zend_View_Helper' => 'Zend/View/Helper/',
'Foo_View_Helper' => 'application/modules/foo/views/helpers',
'Bar_View_Helper' => 'application/modules/bar/views/helpers'
));

Zend_Loader_PluginLoader peut aussi permettre de partager des plugins grâce au registre.


Indiquez le nom du registre de cette manière :

// Stocke les plugins dans le registre à l'index 'foobar':


$loader = new Zend_Loader_PluginLoader(array(), 'foobar');

Si un autre composant instancie le PluginLoader en utilisant le même nom de registre, alors


tous les chemins et plugins déjà chargés seront disponibles.

4.2. Manipulation des chemins des Plugins


Pour afficher ou supprimer des chemins déjà enregistrés, utilisez l'une des méthodes suivantes :

• getPaths($prefix = null) retourne les chemin sous la forme prefix / path si $prefix
n'est pas renseigné. Sinon, ce sont les chemins enregistrés pour le préfixe en question qui
sont renvoyés.

• clearPaths($prefix = null) va effacer tous les chemins. Si $prefix est passé, ce


sont les chemins correspondants à ce préfixe qui seront supprimés.

• removePrefixPath($prefix, $path = null) permet de supprimer un chemin précis,


d'un préfixe spécifié. Si $path n'est pas renseigné, tous les chemins du préfixe seront effacés.

4.3. Test des Plugins et récupération des noms de classe


Lorsque vous voulez savoir si une classe de plugin a été chargée, isLoaded() prend en
paramètre le nom du plugin, et retourne sont statut.

Une autre utilisation de PluginLoader peut être de récupérer le nom des classes des plugins
chargés.getClassName() vous le permet. Utilisée en conjonction avec isLoaded(), vous
pouvez écrire par exemple ceci :

if ($loader->isLoaded('Adapter')) {
$class = $loader->getClassName('Adapter');
$adapter = call_user_func(array($class, 'getInstance'));
}

4.4. Obtenir de meilleures performances avec les Plugins


Le chargement des plugins peut être une opération consommatrice en ressources. En interne,
il doit parcourir chaque préfixe, ainsi que chaque chemin dans ce préfixe jusqu'à ce qu'il trouve

924
Zend_Loader

un fichier qui correspond - et qui définit de plus la classe voulue. Dans le cas où le fichier existe
mais ne défini pas la classe, une erreur sera ajouté à la pile d'erreur PHP, opération qui est elle
aussi consommatrice. La question qui vient à l'esprit est : comment maintenir la flexibilité des
plugins et la performance ?

Zend_Loader_PluginLoader offre une fonctionnalité intégrée pour ce cas, un fichier de


cache des inclusions de classe. Quand il est activé, ceci crée un fichier qui contient toutes
les inclusions qui ont fonctionnées et qui peuvent donc être appelées dans votre fichier
d'initialisation. En utilisant ceci, vous pouvez considérablement accroître les performances de
vos serveurs de production.

Exemple 471. Utilisation du fichier de cache des inclusions de classe de


PluginLoader

Pour utiliser le fichier de cache des inclusions de classe, collez simplement le code suivant
dans votre fichier d'initialisation :

$classFileIncCache = APPLICATION_PATH . '/../data/pluginLoaderCache.php';


if (file_exists($classFileIncCache)) {
include_once $classFileIncCache;
}
Zend_Loader_PluginLoader::setIncludeFileCache($classFileIncCache);

Évidemment, le chemin et le fichier varieront en fonction de vos besoins. Ce code doit


intervenir aussi vite que possible, pour s'assurer que tous les composants à base de plugins
pourront l'utiliser.

En cours du développement, vous pouvez souhaiter désactiver le cache. Une méthode


permettant ceci est d'utiliser une clé de configuration pour déterminer ou non si le chargeur
de plugins doit mettre les informations en cache.

$classFileIncCache = APPLICATION_PATH . '/../data/pluginLoaderCache.php';


if (file_exists($classFileIncCache)) {
include_once $classFileIncCache;
}
if ($config->enablePluginLoaderCache) {
Zend_Loader_PluginLoader::setIncludeFileCache($classFileIncCache);
}

Cette technique vous permet de restreindre les modifications au seul fichier de configuration
plutôt que dans votre code.

925
Zend_Locale
1. Introduction
Zend_Locale is the Frameworks answer to the question, "How can the same application be
used around the whole world?" Most people will say, "That's easy. Let's translate all our output to
several languages." However, using simple translation tables to map phrases from one language
to another is not sufficient. Different regions will have different conventions for first names,
surnames, salutory titles, formatting of numbers, dates, times, currencies, etc.

We need Localization and complementary Internationalization . Both are often abbreviated to


L10n and I18n. Internationalization refers more to support for use of systems, regardless
of special needs unique to groups of users related by language, region, number format
conventions, financial conventions, time and date conventions, etc. Localization involves adding
explicit support to systems for special needs of these unique groups, such as language
translation, and support for local customs or conventions for communicating plurals, dates,
times, currencies, names, symbols, sorting and ordering, etc. L10n and I18n compliment
each other. Zend Framework provides support for these through a combination of components,
including Zend_Locale, Zend_Date, Zend_Measure, Zend_Translate, Zend_Currency,
and Zend_TimeSync.

Zend_Locale and setLocale()


PHP's documentation states that setlocale() is not threadsave because it is
maintained per process and not per thread. This means that, in multithreaded
environments, you can have the problem that the locale changes while the script
never has changed the locale itself. This can lead to unexpected behaviour when
you use setlocale() in your scripts.

When you are using Zend_Locale you will not have this limitations, because
Zend_Locale is not related to or coupled with PHP's setlocale().

1.1. What is Localization


Localization means that an application (or homepage) can be used from different users which
speak different languages. But as you already have expected Localization means more than only
translating strings. It includes

• Zend_Locale - Backend support of locales available for localization support within other Zend
Framework components.

• Zend_Translate - Translating of strings.

• Zend_Date - Localization of dates, times.

• Zend_Calendar - Localization of calendars (support for non-Gregorian calendar systems)

• Zend_Currency - Localization of currencies.

• Zend_Locale_Format - Parsing and generating localized numbers.

• Zend_Locale_Data - Retrieve localized standard strings as country names, language names


and more from the CLDR .

926
Zend_Locale

• TODO - Localization of collations

1.2. What is a Locale?


Each computer user makes use of Locales, even when they don't know it. Applications lacking
localization support, normally have implicit support for one particular locale (the locale of the
author). When a class or function makes use of localization, we say it is locale-aware. How
does the code know which localization the user is expecting?

A locale string or object identifying a supported locale gives Zend_Locale and its subclasses
access to information about the language and region expected by the user. Correct formatting,
normalization, and conversions are made based on this information.

1.3. How are Locales Represented?


Locale identifiers consist of information about the user's language and preferred/primary
geographic region (e.g. state or province of home or workplace). The locale identifier strings
used in Zend Framework are internationally defined standard abbreviations of language and
region, written as language_REGION. Both the language and region parts are abbreviated to
alphabetic, ASCII characters.

Be aware that there exist not only locales with 2 characters as most people
think. Also there are languages and regions which are not only abbreviated with
2 characters. Therefor you should NOT strip the region and language yourself,
but use Zend_Locale when you want to strip language or region from a locale
string. Otherwise you could have unexpected behaviour within your code when
you do this yourself.

A user from USA would expect the language English and the region USA, yielding the locale
identifier "en_US". A user in Germany would expect the language German and the region
Germany, yielding the locale identifier "de_DE". See the list of pre-defined locale and region
combinations, if you need to select a specific locale within Zend Framework.

Exemple 472. Choosing a specific locale

$locale = new Zend_Locale('de_DE'); // German language _ Germany

A German user in America might expect the language German and the region USA, but these
non-standard mixes are not supported directly as recognized "locales". Instead, if an invalid
combination is used, then it will automatically be truncated by dropping the region code. For
example, "de_IS" would be truncated to "de", and "xh_RU" would be truncated to "xh", because
neither of these combinations are valid. Additionally, if the base language code is not supported
(e.g. "zz_US") or does not exist, then a default "root" locale will be used. The "root" locale
has default definitions for internationally recognized representations of dates, times, numbers,
currencies, etc. The truncation process depends on the requested information, since some
combinations of language and region might be valid for one type of data (e.g. dates), but not for
another (e.g. currency format).

Beware of historical changes, as Zend Framework components do not know about or attempt to
track the numerous timezone changes made over many years by many regions. For example,
we can see a historical list showing dozens of changes made by governments to when and
if a particular region observes Daylight Savings Time, and even which timezone a particular

927
Zend_Locale

geographic area belongs. Thus, when performing date math, the math performed by Zend
Framework components will not adjust for these changes, but instead will give the correct time
for the timezone using current, modern rules for DST and timezone assignment for geographic
regions.

1.4. Selecting the Right Locale


For most situations, new Zend_Locale() will automatically select the correct locale,
with preference given to information provided by the user's web browser. However, if new
Zend_Locale(Zend_Locale::ENVIRONMENT) is used, then preference will be given to using
the host server's environment configuration, as described below.

Exemple 473. Automatically selecting a locale

$locale = new Zend_Locale();

// default behavior, same as above


$locale1 = new Zend_Locale(Zend_Locale::BROWSER);

// prefer settings on host server


$locale2 = new Zend_Locale(Zend_Locale::ENVIRONMENT);

// perfer framework app default settings


$locale3 = new Zend_Locale(Zend_Locale::FRAMEWORK);

The search algorithm used by Zend_Locale for automatic selection of a locale uses three
sources of information:

1. const Zend_Locale::BROWSER - The user's Web browser provides information with each
request, which is published by PHP in the global variable HTTP_ACCEPT_LANGUAGE. If
no matching locale can be found, then preference is given to ENVIRONMENT and lastly
FRAMEWORK.

2. const Zend_Locale::ENVIRONMENT - PHP publishes the host server's locale via the PHP
internal function setlocale(). If no matching locale can be found, then preference is given
to FRAMEWORK and lastly BROWSER.

3. const Zend_Locale::FRAMEWORK - When Zend Framework has a standardized way of


specifying component defaults (planned, but not yet available), then using this constant during
instantiation will give preference to choosing a locale based on these defaults. If no matching
locale can be found, then preference is given to ENVIRONMENT and lastly BROWSER.

1.5. Usage of automatic Locales


Zend_Locale provides three additionally locales. These locales do not belong to any language
or region. They are "automatic" locales which means that they have the same effect as the
method getDefault() but without the negative effects like creating an instance. These
"automatic" locales can be used anywhere, where also a standard locale and also the definition
of a locale, its string representation, can be used. This offers simplicity for situations like working
with locales which are provided by a browser.

There are three locales which have a slightly different behaviour:

1. 'browser' - Zend_Locale should work with the information which is provided by the user's
Web browser. It is published by PHP in the global variable HTTP_ACCEPT_LANGUAGE.

928
Zend_Locale

If a user provides more than one locale within his browser, Zend_Locale will use the first
found locale. If the user does not provide a locale or the script is being called from the
command line the automatic locale 'environment' will automatically be used and returned.

2. 'environment' - Zend_Locale should work with the information which is provided by the
host server. It is published by PHP via the internal function setlocale().

If a environment provides more than one locale, Zend_Locale will use the first found locale.
If the host does not provide a locale the automatic locale 'browser' will automatically be
used and returned.

3. 'auto' - Zend_Locale should automatically detect any locale which can be worked with. It
will first search for a users locale and then, if not successful, search for the host locale.

If no locale can be detected, it will throw an exception and tell you that the automatic detection
has been failed.

Exemple 474. Using automatic locales

// without automatic detection


//$locale = new Zend_Locale(Zend_Locale::BROWSER);
//$date = new Zend_Date($locale);

// with automatic detection


$date = new Zend_Date('auto');

1.6. Using a default Locale


In some environments it is not possible to detect a locale automatically. You can expect this
behaviour when you get an request from command line or the requesting browser has no
language tag set and additionally your server has the default locale 'C' set or another proprietary
locale.

In such cases Zend_Locale will normally throw an exception with a message that the automatic
detection of any locale was not successful. You have two options to handle such a situation.
Either through setting a new locale per hand, or defining a default locale.

Exemple 475. Handling locale exceptions

// within the bootstrap file


try {
$locale = new Zend_Locale('auto');
} catch (Zend_Locale_Exception $e) {
$locale = new Zend_Locale('de');
}

// within your model/controller


$date = new Zend_Date($locale);

But this has one big negative effect. You will have to set your locale object within every class
using Zend_Locale. This could become very unhandy if you are using multiple classes.

Since Zend Framework Release 1.5 there is a much better way to handle this. You can set a
default locale which the static setDefault() method. Of course, every unknown or not full

929
Zend_Locale

qualified locale will also throw an exception. setDefault() should be the first call before you
initiate any class using Zend_Locale. See the following example for details:

Exemple 476. Setting a default locale

// within the bootstrap file


Zend_Locale::setDefault('de');

// within your model/controller


$date = new Zend_Date();

In the case that no locale can be detected, automatically the locale de will be used. Otherwise,
the detected locale will be used.

1.7. ZF Locale-Aware Classes


In the Zend Framework, locale-aware classes rely on Zend_Locale to automatically select a
locale, as explained above. For example, in a Zend Framework web application, constructing a
date using Zend_Date without specifying a locale results in an object with a locale based on
information provided by the current user's web browser.

Exemple 477. Dates default to correct locale of web users

$date = new Zend_Date('2006',Zend_Date::YEAR);

To override this default behavior, and force locale-aware Zend Framework components to use
specific locales, regardless of the origin of your website visitors, explicitly specify a locale as the
third argument to the constructor.

Exemple 478. Overriding default locale selection

$usLocale = new Zend_Locale('en_US');


$date = new Zend_Date('2006', Zend_Date::YEAR, $usLocale);
$temp = new Zend_Measure_Temperature('100,10',
Zend_Measure::TEMPERATURE,
$usLocale);

If you know many objects should all use the same default locale, explicitly specify the default
locale to avoid the overhead of each object determining the default locale.

Exemple 479. Performance optimization when using a default locale

$locale = new Zend_Locale();


$date = new Zend_Date('2006', Zend_Date::YEAR, $locale);
$temp = new Zend_Measure_Temperature('100,10',
Zend_Measure::TEMPERATURE,
$locale);

1.8. Application wide locale


Zend Framework allows the usage of an application wide locale. You simply set an instance of
Zend_Locale to the registry with the key 'Zend_Locale'. Then this instance will be used within
all locale aware classes of Zend Framework. This way you set one locale within your registry
and then you can forget about setting it again. It will automatically be used in all other classes.
See the below example for the right usage:

930
Zend_Locale

Exemple 480. Usage of an application wide locale

// within your bootstrap


$locale = new Zend_Locale('de_AT');
Zend_Registry::set('Zend_Locale', $locale);

// within your model or controller


$date = new Zend_Date();
// print $date->getLocale();
echo $date->getDate();

1.9. Zend_Locale_Format::setOptions(array $options)


The 'precision' option of a value is used to truncate or stretch extra digits. A value of '-1'
disables modification of the number of digits in the fractional part of the value. The 'locale' option
helps when parsing numbers and dates using separators and month names. The date format
'format_type' option selects between CLDR/ISO date format specifier tokens and PHP's date()
tokens. The 'fix_date' option enables or disables heuristics that attempt to correct invalid dates.
The 'number_format' option specifies a default number format for use with toNumber() (see
Section 3.2, « Number localization » ).

The 'date_format' option can be used to specify a default date format string, but beware of using
getDate(), checkdateFormat() and getTime() after using setOptions() with a 'date_format'. To
use these four methods with the default date format for a locale, use array('date_format' => null,
'locale' => $locale) for their options.

Exemple 481. Dates default to correct locale of web users

Zend_Locale_Format::setOptions(array('locale' => 'en_US',


'fix_date' => true,
'format_type' => 'php'));

For working with the standard definitions of a locale the option


Zend_Locale_Format::STANDARD can be used. Setting the option
Zend_Locale_Format::STANDARD for date_format uses the standard definitions from the
actual set locale. Setting it for number_format uses the standard number format for this locale.
And setting it for locale uses the standard locale for this environment or browser.

Exemple 482. Using STANDARD definitions for setOptions()

Zend_Locale_Format::setOptions(array('locale' => 'en_US',


'date_format' => 'dd.MMMM.YYYY'));
// overriding the global set date format
$date = Zend_Locale_Format::getDate('2007-04-20',
array('date_format' =>
Zend_Locale_Format::STANDARD);

// global setting of the standard locale


Zend_Locale_Format::setOptions(array('locale' => Zend_Locale_Format::STANDARD,
'date_format' => 'dd.MMMM.YYYY'));

1.10. Speed up Zend_Locale and its subclasses


Zend_Locale and its subclasses can be speed up by the usage of Zend_Cache. Use
the static method Zend_Locale::setCache($cache) if you are using Zend_Locale.

931
Zend_Locale

Zend_Locale_Format can be speed up the using the option cache within


Zend_Locale_Format::setOptions(array('cache' => $adapter));. If you are
using both classes you should only set the cache for Zend_Locale, otherwise the last set
cache will overwrite the previous set cache. For convenience there are also the static methods
getCache(), hasCache(), clearCache() and removeCache().

When no cache is set, then Zend_Locale will automatically set a cache itself. Sometimes it is
wished to prevent that a cache is set, even if this degrades performance. In this case the static
disableCache(true) method should be used. It does not only disable the actual set cache,
without erasing it, but also prevents that a cache is automatically generated when no cache is set.

2. Using Zend_Locale
Zend_Locale also provides localized information about locales for each locale, including
localized names for other locales, days of the week, month names, etc.

2.1. Copying, Cloning, and Serializing Locale Objects


Use object cloning to duplicate a locale object exactly and efficiently. Most locale-aware methods
also accept string representations of locales, such as the result of $locale->toString().

Exemple 483. clone

$locale = new Zend_Locale('ar');

// Save the $locale object as a serialization


$serializedLocale = $locale->serialize();
// re-create the original object
$localeObject = unserialize($serializedLocale);

// Obtain a string identification of the locale


$stringLocale = $locale->toString();

// Make a cloned copy of the $local object


$copiedLocale = clone $locale;

print "copied: ", $copiedLocale->toString();

// PHP automatically calls toString() via __toString()


print "copied: ", $copiedLocale;

2.2. Equality
Zend_Locale also provides a convenience function to compare two locales. All locale-aware
classes should provide a similar equality check.

Exemple 484. Check for equal locales

$locale = new Zend_Locale();


$mylocale = new Zend_Locale('en_US');

// Check if locales are equal


if ($locale->equals($mylocale)) {
print "Locales are equal";
}

932
Zend_Locale

2.3. Default locales


The method getDefault() returns an array of relevant locales using information from the
user's web browser (if available), information from the environment of the host server, and Zend
Framework settings. As with the constructor for Zend_Locale, the first parameter selects a
preference of which information to consider (BROWSER, ENVIRONMENT, or FRAMEWORK) first. The
second parameter toggles between returning all matching locales or only the first/best match.
Locale-aware components normally use only the first locale. A quality rating is included, when
available.

Exemple 485. Get default locales

$locale = new Zend_Locale();

// Return all default locales


$found = $locale->getDefault();
print_r($found);

// Return only browser locales


$found2 = $locale->getDefault(Zend_Locale::BROWSER,TRUE);
print_r($found2);

To obtain only the default locales relevant to the BROWSER, ENVIRONMENT, or FRAMEWORK ,
use the corresponding method:

• getEnvironment()

• getBrowser()

• getLocale()

2.4. Set a new locale


A new locale can be set with the function setLocale(). This function takes a locale string as
parameter. If no locale is given, a locale is automatically selected. Since Zend_Locale objects
are "light", this method exists primarily to cause side-effects for code that have references to the
existing instance object.

Exemple 486. setLocale

$locale = new Zend_Locale();

// Actual locale
print $locale->toString();

// new locale
$locale->setLocale('aa_DJ');
print $locale->toString();

2.5. Getting the language and region


Use getLanguage() to obtain a string containing the two character language code from the
string locale identifier. Use getRegion() to obtain a string containing the two character region
code from the string locale identifier.

933
Zend_Locale

Exemple 487. getLanguage and getRegion

$locale = new Zend_Locale();

// if locale is 'de_AT' then 'de' will be returned as language


print $locale->getLanguage();

// if locale is 'de_AT' then 'AT' will be returned as region


print $locale->getRegion();

2.6. Obtaining localized strings


getTranslationList() gives you access to localized informations of several types. These
information are useful if you want to display localized data to a customer without the need of
translating it. They are already available for your usage.

The requested list of information is always returned as named array. If you want to give more
than one value to a explicit type where you wish to receive values from, you have to give an
array instead of multiple values.

Exemple 488. getTranslationList

$list = Zend_Locale::getTranslationList('language', 'de_AT');

print_r ($list);
// example key -> value pairs...
// [de] -> Deutsch
// [en] -> Englisch

// use one of the returned key as value for the getTranslation() method
// of another language
print Zend_Locale::getTranslation('de', 'language', 'zh');
// returns the translation for the language 'de' in chinese

You can receive this informations for all languages. But not all of the informations are completely
available for all languages. Some of these types are also available through an own function for
simplicity. See this list for detailed informations.

Tableau 91. Details for getTranslationList($type = null, $locale = null, $value = null)
Type Description
Language Returns a localized list of all languages. The
language part of the locale is returned as key
and the translation as value
Script Returns a localized list of all scripts. The script
is returned as key and the translation as value
Territory Returns a localized list of all territories. This
contains countries, continents and territories.
To get only territories and continents use '1'
as value. To get only countries use '2' as
value. The country part of the locale is used
as key where applicable. In the other case the
official ISO code for this territory is used. The
translated territory is returned as value. When
you omit the value you will get a list with both.

934
Zend_Locale

Type Description
Variant Returns a localized list of known variants of
scripts. The variant is returned as key and the
translation as value
Key Returns a localized list of known keys. This
keys are generic values used in translation.
These are normally calendar, collation and
currency. The key is returned as array key and
the translation as value
Type Returns a localized list of known types of
keys. These are variants of types of calendar
representations and types of collations. When
you use 'collation' as value you will get all types
of collations returned. When you use 'calendar'
as value you will get all types of calendars
returned. When you omit the value you will get
a list all both returned. The type is used as key
and the translation as value
Layout Returns a list of rules which describes how to
format special text parts
Characters Returns a list of allowed characters within this
locale
Delimiters Returns a list of allowed quoting characters for
this locale
Measurement Returns a list of known measurement values.
This list is depreciated
Months Returns a list of all month representations
within this locale. There are several different
representations which are all returned as sub
array. If you omit the value you will get a
list of all months from the 'gregorian' calendar
returned. You can give any known calendar as
value to get a list of months from this calendar
returned. Use Zend_Date for simplicity
Month Returns a localized list of all month names for
this locale. If you omit the value you will get
the normally used gregorian full name of the
months where each month number is used as
key and the translated month is returned as
value. You can get the months for different
calendars and formats if you give an array
as value. The first array entry has to be the
calendar, the second the used context and the
third the width to return. Use Zend_Date for
simplicity
Days Returns a list of all day representations
within this locale. There are several different
representations which are all returned as sub
array. If you omit the value you will get a list of
all days from the 'gregorian' calendar returned.

935
Zend_Locale

Type Description
You can give any known calendar as value to
get a list of days from this calendar returned.
Use Zend_Date for simplicity
Day Returns a localized list of all day names for this
locale. If you omit the value you will get the
normally used gregorian full name of the days
where the english day abbreviation is used as
key and the translated day is returned as value.
You can get the days for different calendars
and formats if you give an array as value. The
first array entry has to be the calendar, the
second the used context and the third the width
to return. Use Zend_Date for simplicity
Week Returns a list of values used for proper week
calculations within a locale. Use Zend_Date for
simplicity
Quarters Returns a list of all quarter representations
within this locale. There are several different
representations which are all returned as sub
array. If you omit the value you will get a list
of all quarters from the 'gregorian' calendar
returned. You can give any known calendar as
value to get a list of quarters from this calendar
returned
Quarter Returns a localized list of all quarter names for
this locale. If you omit the value you will get
the normally used gregorian full name of the
quarters where each quarter number is used
as key and the translated quarter is returned
as value. You can get the quarters for different
calendars and formats if you give an array
as value. The first array entry has to be the
calendar, the second the used context and the
third the width to return
Eras Returns a list of all era representations within
this locale. If you omit the value you will get
a list of all eras from the 'gregorian' calendar
returned. You can give any known calendar as
value to get a list of eras from this calendar
returned
Era Returns a localized list of all era names for this
locale. If you omit the value you will get the
normally used gregorian full name of the eras
where each era number is used as key and the
translated era is returned as value. You can get
the eras for different calendars and formats if
you give an array as value. The first array entry
has to be the calendar and the second the width
to return

936
Zend_Locale

Type Description
Date Returns a localized list of all date formats for
this locale. The name of the dateformat is used
as key and the format itself as value.If you omit
the value you will get the date formats for the
gregorian calendar returned. You can get the
date formats for different calendars if you give
the wished calendar as string. Use Zend_Date
for simplicity
Time Returns a localized list of all time formats for
this locale. The name of the timeformat is used
as key and the format itself as value. If you omit
the value you will get the time formats for the
gregorian calendar returned. You can get the
time formats for different calendars if you give
the wished calendar as string. Use Zend_Date
for simplicity
DateTime Returns a localized list of all known date-time
formats for this locale. The name of the date-
time format is used as key and the format
itself as value. If you omit the value you will
get the date-time formats for the gregorian
calendar returned. You can get the date-time
formats for different calendars if you give the
wished calendar as string. Use Zend_Date for
simplicity
DateItem Returns a list of default formats for given date
or time items
DateInterval Returns a list of date or time formats which
are used when you want to display intervals.
The list is a multidimentional array where the
first dimension is the interval format, and the
second dimension is the token with the greatest
difference.
Field Returns a localized list of date fields which can
be used to display calendars or date strings
like 'month' or 'year' in a wished language. If
you omit the value you will get this list for the
gregorian calendar returned. You can get the
list for different calendars if you give the wished
calendar as string
Relative Returns a localized list of relative dates which
can be used to display textual relative dates like
'yesterday' or 'tomorrow' in a wished language.
If you omit the value you will get this list for the
gregorian calendar returned. You can get the
list for different calendars if you give the wished
calendar as string
Symbols Returns a localized list of characters used for
number representations

937
Zend_Locale

Type Description
NameToCurrency Returns a localized list of names for currencies.
The currency is used as key and the translated
name as value. Use Zend_Currency for
simplicity
CurrencyToName Returns a list of currencies for localized names.
The translated name is used as key and the
currency as value. Use Zend_Currency for
simplicity
CurrencySymbol Returns a list of known localized currency
symbols for currencies. The currency is used
as key and the symbol as value. Use
Zend_Currency for simplicity
Question Returns a list of localized strings for
acceptance ('yes') and negotation ('no').
Use Zend_Locale's getQuestion method for
simplicity
CurrencyFraction Returns a list of fractions for currency values.
The currency is used as key and the fraction as
integer value. Use Zend_Currency for simplicity
CurrencyRounding Returns a list of how to round which currency.
The currency is used as key and the rounding
as integer value. Use Zend_Currency for
simplicity
CurrencyToRegion Returns a list of currencies which are known
to be used within a region. The ISO3166
value ('region') is used as array key and the
ISO4217 value ('currency') as array value. Use
Zend_Currency for simplicity
RegionToCurrency Returns a list of regions where a currency is
used . The ISO4217 value ('currency') is used
as array key and the ISO3166 value ('region')
as array value. When a currency is used in
several regions these regions are separated
with a whitespace. Use Zend_Currency for
simplicity
RegionToTerritory Returns a list of territories with the countries
or sub territories which are included within that
territory. The ISO territory code ('territory') is
used as array key and the ISO3166 value
('region') as array value. When a territory
contains several regions these regions are
separated with a whitespace
TerritoryToRegion Returns a list of regions and the territories
where these regions are located. The ISO3166
code ('region') is used as array key and the ISO
territory code ('territory') as array value. When
a region is located in several territories these
territories are separated with a whitespace

938
Zend_Locale

Type Description
ScriptToLanguage Returns a list of scripts which are used within a
language. The language code is used as array
key and the script code as array value. When a
language contains several scripts these scripts
are separated with a whitespace
LanguageToScript Returns a list of languages which are using a
script. The script code is used as array key
and the language code as array value. When
a script is used in several languages these
languages are separated with a whitespace
TerritoryToLanguage Returns a list of countries which are using
a language. The country code is used as
array key and the language code as array
value. When a language is used in several
countries these countries are separated with a
whitespace
LanguageToTerritory Returns a list of countries and the languages
spoken within these countries. The country
code is used as array key and the language
code as array value. When a territory is
using several languages these languages are
separated with a whitespace
TimezoneToWindows Returns a list of windows timezones and the
related ISO timezone. The windows timezone
is used as array key and the ISO timezone as
array value
WindowsToTimezone Returns a list of ISO timezones and the related
windows timezone. The ISO timezone is used
as array key and the windows timezone as
array value
TerritoryToTimezone Returns a list of regions or territories and the
related ISO timezone. The ISO timezone is
used as array key and the territory code as
array value
TimezoneToTerritory Returns a list of timezones and the related
region or territory code. The region or territory
code is used as array key and the ISO timezone
as array value
CityToTimezone Returns a localized list of cities which can
be used as translation for a related timezone.
Not for all timezones is a translation available,
but for a user is the real city written in his
languages more accurate than the ISO name
of this timezone. The ISO timezone is used as
array key and the translated city as array value
TimezoneToCity Returns a list of timezones for localized city
names. The localized city is used as array key
and the ISO timezone name as array value

939
Zend_Locale

Type Description
PhoneToTerritory Returns a list of phone codes which are known
to be used within a territory. The territory
(region) is used as array key and the telephone
code as array value
TerritoryToPhone Returns a list of territories where a phone is
used . The phone code is used as array key
and the territory (region) as array value. When
a phone code is used in several territories these
territories are separated with a whitespace
NumericToTerritory Returns a list of 3 digit number codes for
territories. The territory (region) is used as array
key and the 3 digit number code as array value
TerritoryToNumeric Returns a list of territories with their 3 digit
number code. The 3 digit number code is used
as array key and the territory (region) as array
value
Alpha3ToTerritory Returns a list of 3 sign character codes for
territories. The territory (region) is used as array
key and the 3 sign character code as array
value
TerritoryToAlpha3 Returns a list of territories with their 3 sign
character code. The 3 sign character code is
used as array key and the territory (region) as
array value
PostalToTerritory Returns a list of territories with a regex for
postal codes which are included within that
territory. The ISO territory code ('territory') is
used as array key and the regex as array value.
NumberingSystem Returns a list of scripts with the notation for
digits used within the script
FallbackToChar Returns a list of replacement characters for
often used unicode characters. This can be
used to replace "©" with "(C)" for example
CharToFallback Returns a list of unicode characters for often
used replacement characters. This can be used
to replace "(C)" with "©" for example
LocaleUpgrade Returns a list of locale dependencies which can
be used to upgrade a language to a full qualified
locale
Unit Returns a list of localized calendar units. This
can be used to translate the strings "day",
"month" and so on automatically

If you are in need of a single translated value, you can use the getTranslation() method. It
returns always a string but it accepts some different types than the getTranslationList()
method. Also value is the same as before with one difference. You have to give the detail you
want to get returned as additional value.

940
Zend_Locale

Because you have almost always give a value as detail this parameter has to be
given as first parameter. This differs from the getTranslationList() method.

See the following table for detailed information:

Tableau 92. Details for getTranslation($value = null, $type = null, $locale = null)

Type Description
Language Returns a translation for a language. To select
the wished translation you must give the
language code as value
Script Returns a translation for a script. To select
the wished translation you must give the script
code as value
Territory or Country Returns a translation for a territory. This can be
countries, continents and territories. To select
the wished variant you must give the territory
code as value
Variant Returns a translation for a script variant. To
select the wished variant you must give the
variant code as value
Key Returns translation for a known keys. This keys
are generic values used in translation. These
are normally calendar, collation and currency.
To select the wished key you must give the key
code as value
DefaultCalendar Returns the default calendar for the given
locale. For most locales this will be 'gregorian'.
Use Zend_Date for simplicity
MonthContext Returns the default context for months which is
used within the given calendar. If you omit the
value the 'gregorian' calendar will be used. Use
Zend_Date for simplicity
DefaultMonth Returns the default format for months which is
used within the given calendar. If you omit the
value the 'gregorian' calendar will be used. Use
Zend_Date for simplicity
Month Returns a translation for a month. You have
to give the number of the month as integer
value. It has to be between 1 and 12. If
you want to receive data for other calendars,
contexts or formats, then you must give
an array instead of an integer with the
expected values. The array has to look like
this: array( 'calendar', 'context',
'format', 'month number'). If you give
only an integer then the default values are the
'gregorian' calendar, the context 'format' and
the format 'wide'. Use Zend_Date for simplicity

941
Zend_Locale

Type Description
DayContext Returns the default context for ´days which is
used within the given calendar. If you omit the
value the 'gregorian' calendar will be used. Use
Zend_Date for simplicity
DefaultDay Returns the default format for days which is
used within the given calendar. If you omit the
value the 'gregorian' calendar will be used. Use
Zend_Date for simplicity
Day Returns a translation for a day. You have
to give the english abbreviation of the day
as string value ('sun', 'mon', etc.). If you
want to receive data for other calendars,
contexts or format, then you must give
an array instead of an integer with the
expected values. The array has to look like
this: array('calendar', 'context',
'format', 'day abbreviation'). If you
give only an string then the default values are
the 'gregorian' calendar, the context 'format'
and the format 'wide'. Use Zend_Date for
simplicity
Quarter Returns a translation for a quarter. You
have to give the number of the quarter as
integer and it has to be between 1 and
4. If you want to receive data for other
calendars, contexts or formats, then you must
give an array instead of an integer with
the expected values. The array has to look
like this: array('calendar', 'context',
'format', 'quarter number'). If you
give only an string then the default values are
the 'gregorian' calendar, the context 'format'
and the format 'wide'
Am Returns a translation for 'AM' in a expected
locale. If you want to receive data for other
calendars an string with the expected calendar.
If you omit the value then the 'gregorian'
calendar will be used. Use Zend_Date for
simplicity
Pm Returns a translation for 'PM' in a expected
locale. If you want to receive data for other
calendars an string with the expected calendar.
If you omit the value then the 'gregorian'
calendar will be used. Use Zend_Date for
simplicity
Era Returns a translation for an era within a locale.
You have to give the era number as string
or integer. If you want to receive data for
other calendars or formats, then you must give
an array instead of the era number with the

942
Zend_Locale

Type Description
expected values. The array has to look like this:
array('calendar', 'format', 'era
number'). If you give only an string then the
default values are the 'gregorian' calendar and
the 'abbr' format
DefaultDate Returns the default date format which is used
within the given calendar. If you omit the
value the 'gregorian' calendar will be used. Use
Zend_Date for simplicity
Date Returns the date format for an given calendar
or format within a locale. If you omit the value
then the 'gregorian' calendar will be used with
the 'medium' format. If you give a string then the
'gregorian' calendar will be used with the given
format. Or you can also give an array which will
have to look like this: array('calendar',
'format'). Use Zend_Date for simplicity
DefaultTime Returns the default time format which is used
within the given calendar. If you omit the
value the 'gregorian' calendar will be used. Use
Zend_Date for simplicity
Time Returns the time format for an given calendar
or format within a locale. If you omit the value
then the 'gregorian' calendar will be used with
the 'medium' format. If you give a string then the
'gregorian' calendar will be used with the given
format. Or you can also give an array which will
have to look like this: array('calendar',
'format'). Use Zend_Date for simplicity
DateTime Returns the datetime format for the given locale
which indicates how to display date with times
in the same string within the given calendar. If
you omit the value the 'gregorian' calendar will
be used. Use Zend_Date for simplicity
DateItem Returns the default format for a given date or
time item
DateInterval Returns the interval format for a given
date or time format. The first value is the
calendar format, normally 'gregorian'. The
second value is the interval format and the third
value the token with the greatest difference.
For example: array('gregorian', 'yMMMM', 'y')
returns the interval format for the date format
'yMMMM' where 'y' has the greatest difference.
Field Returns a translated date field which can be
used to display calendars or date strings like
'month' or 'year' in a wished language. You
must give the field which has to be returned
as string. In this case the 'gregorian' calendar

943
Zend_Locale

Type Description
will be used. You can get the field for other
calendar formats if you give an array which has
to look like this: array('calendar', 'date
field')
Relative Returns a translated date which is relative
to today which can include date strings like
'yesterday' or 'tomorrow' in a wished language.
You have to give the number of days relative
to tomorrow to receive the expected string.
Yesterday would be '-1', tomorrow '1' and so
on. This will use the 'gregorian' calendar. If you
want to get relative dates for other calendars
you will have to give an array which has to look
like this: array('calendar', 'relative
days'). Use Zend_Date for simplicity
DecimalNumber Returns the format for decimal numbers within
a given locale. Use Zend_Locale_Format for
simplicity
ScientificNumber Returns the format for scientific numbers within
a given locale
PercentNumber Returns the format for percentage numbers
within a given locale
CurrencyNumber Returns the format for displaying currency
numbers within a given locale. Use
Zend_Currency for simplicity
NameToCurrency Returns the translated name for a given
currency. The currency has to be given in
ISO format which is for example 'EUR' for
the currency 'euro'. Use Zend_Currency for
simplicity
CurrencyToName Returns a currency for a given localized name.
Use Zend_Currency for simplicity
CurrencySymbol Returns the used symbol for a currency within
a given locale. Not for all currencies exists a
symbol. Use Zend_Currency for simplicity
Question Returns a localized string for acceptance ('yes')
and negotation ('no'). You have to give either
'yes' or 'no' as value to receive the expected
string. Use Zend_Locale's getQuestion method
for simplicity
CurrencyFraction Returns the fraction to use for a given currency.
You must give the currency as ISO value. Use
Zend_Currency for simplicity
CurrencyRounding Returns how to round a given currency. You
must give the currency as ISO value. If you omit
the currency then the 'DEFAULT' rounding will
be returned. Use Zend_Currency for simplicity

944
Zend_Locale

Type Description
CurrencyToRegion Returns the currency for a given region. The
region code has to be given as ISO3166
string for example 'AT' for austria. Use
Zend_Currency for simplicity
RegionToCurrency Returns the regions where a currency is used.
The currency has to be given as ISO4217 code
for example 'EUR' for euro. When a currency
is used in multiple regions, these regions are
separated with a whitespace character. Use
Zend_Currency for simplicity
RegionToTerritory Returns the regions for a given territory. The
territory has to be given as ISO4217 string
for example '001' for world. The regions within
this territory are separated with a whitespace
character
TerritoryToRegion Returns the territories where a given region
is located. The region has to be given in
ISO3166 string for example 'AT' for austria.
When a region is located in multiple territories
then these territories are separated with a
whitespace character
ScriptToLanguage Returns the scripts which are used within a
given language. The language has to be given
as ISO language code for example 'en' for
english. When multiple scripts are used within a
language then these scripts are separated with
a whitespace character
LanguageToScript Returns the languages which are used within a
given script. The script has to be given as ISO
script code for example 'Latn' for latin. When a
script is used in multiple languages then these
languages are separated with a whitespace
character
TerritoryToLanguage Returns the territories where a given language
is used. The language has to be given
as ISO language code for example 'en' for
english. When multiple territories exist where
this language is used then these territories are
separated with a whitespace character
LanguageToTerritory Returns the languages which are used within
a given territory. The territory has to be given
as ISO3166 code for example 'IT' for italia.
When a language is used in multiple territories
then these territories are separated with a
whitespace character
TimezoneToWindows Returns a ISO timezone for a given windows
timezone

945
Zend_Locale

Type Description
WindowsToTimezone Returns a windows timezone for a given ISO
timezone
TerritoryToTimezone Returns the territory for a given ISO timezone
TimezoneToTerritory Returns the ISO timezone for a given territory
CityToTimezone Returns the localized city for a given ISO
timezone. Not for all timezones does a city
translation exist
TimezoneToCity Returns the ISO timezone for a given localized
city name. Not for all cities does a timezone
exist
PhoneToTerritory Returns the telephone code for a given territory
(region). The territory code has to be given as
ISO3166 string for example 'AT' for austria
TerritoryToPhone Returns the territory (region) where a telephone
code is used. The telephone code has to be
given as plain integer code for example '43'
for +43. When a telephone code is used in
multiple territories (regions), these territories
are separated with a whitespace character
NumericToTerritory Returns the 3 digit number code for a given
territory (region). The territory code has to be
given as ISO3166 string for example 'AT' for
austria
TerritoryToNumeric Returns the territory (region) for a 3 digit
number code. The 3 digit number code has to
be given as plain integer code for example '43'
Alpha3ToTerritory Returns the 3 sign character code for a given
territory (region). The territory code has to be
given as ISO3166 string for example 'AT' for
austria
TerritoryToAlpha3 Returns the territory (region) for a 3 sign
character code
PostalToTerritory Returns the a regex for postal codes for a
given territory. The territory has to be given as
ISO4217 string for example '001' for world
NumberingSystem Returns a scripts with the notation for digits
used within this script
FallbackToChar Returns a replacement character for a often
used unicode character. This can be used to
replace "©" with "(C)" for example
CharToFallback Returns a unicode character for a often used
replacement character. This can be used to
replace "(C)" with "©" for example
LocaleUpgrade Returns a locale dependencies for a given
language which can be used to upgrade this
language to a full qualified locale

946
Zend_Locale

Type Description
Unit Returns a localized calendar unit. This can be
used to translate the strings "day", "month" and
so on automatically. The first parameter has to
be the type, and the second parameter has to
be the count

With Zend Framework 1.5 several old types have been renamed. This has to
be done because of several new types, some misspelling and to increase the
usability. See this table for a list of old to new types:

Tableau 93. Differences between Zend Framework 1.0 and 1.5

Old type New type


Country Territory (with value '2')
Calendar Type (with value 'calendar')
Month_Short Month (with array('gregorian', 'format',
'abbreviated')
Month_Narrow Month (with array('gregorian', 'stand-alone',
'narrow')
Month_Complete Months
Day_Short Day (with array('gregorian', 'format',
'abbreviated')
Day_Narrow Day (with array('gregorian', 'stand-alone',
'narrow')
DateFormat Date
TimeFormat Time
Timezones CityToTimezone
Currency NameToCurrency
Currency_Sign CurrencySymbol
Currency_Detail CurrencyToRegion
Territory_Detail TerritoryToRegion
Language_Detail LanguageToTerritory

The example below demonstrates how to obtain the names of things in different languages.

Exemple 489. getTranslationList

// prints the names of all countries in German language


print_r(Zend_Locale::getTranslationList('country', 'de'));

The next example shows how to find the name of a language in another language, when the two
letter iso country code is not known.

947
Zend_Locale

Exemple 490. Converting country name in one language to another

$code2name = Zend_Locale::getLanguageTranslationList('en_US');
$name2code = array_flip($code2name);
$frenchCode = $name2code['French'];
echo Zend_Locale::getLanguageTranslation($frenchCode, 'de_AT');
// output is the German name of the French language

To generate a list of all languages known by Zend_Locale, with each language


name shown in its own language, try the example below in a web page. Similarly,
getCountryTranslationList() and getCountryTranslation() could be used to
create a table mapping your native language names for regions to the names of the regions
shown in another language. Use a try .. catch block to handle exceptions that occur when
using a locale that does not exist. Not all languages are also locales. In the example, below
exceptions are ignored to prevent early termination.

Exemple 491. All Languages written in their native language

$list = Zend_Locale::getLanguageTranslationList('auto');

foreach($list as $language => $content) {


try {
$output = Zend_Locale::getLanguageTranslation($language, $language);
if (is_string($output)) {
print "\n<br>[".$language."] ".$output;
}
} catch (Exception $e) {
continue;
}
}

2.7. Obtaining translations for "yes" and "no"


Frequently, programs need to solicit a "yes" or "no" response from the user. Use
getQuestion() to obtain an array containing the correct word(s) or regex strings to use for
prompting the user in a particular $locale (defaults to the current object's locale). The returned
array will contain the following informations :

• yes and no: A generic string representation for yes and no responses. This will contain the first
and most generic response from yesarray and noarray.

yesarray and noarray: An array with all known yes and no responses. Several languages have
more than just two responses. In general this is the full string and its abbreviation.

yesexpr and noexpr: An generated regex which allows you to handle user response, and
search for yes or no.

All of this informations are of course localized and depend on the set locale. See the following
example for the informations you can receive:

948
Zend_Locale

Exemple 492. getQuestion()

$locale = new Zend_Locale();


// Question strings
print_r($locale->getQuestion('de'));

- - - Output - - -

Array
(
[yes] => ja
[no] => nein
[yesarray] => Array
(
[0] => ja
[1] => j
)

[noarray] => Array


(
[0] => nein
[1] => n
)

[yesexpr] => ^([jJ][aA]?)|([jJ]?)


[noexpr] => ^([nN]([eE][iI][nN])?)|([nN]?)
)

Until 1.0.3 yesabbr from the underlaying locale data was also available. Since 1.5
this information is no longer standalone available, but you will find the information
from it within yesarray.

2.8. Get a list of all known locales


Sometimes you will want to get a list of all known locales. This can be used for several tasks like
the creation of a selectbox. For this purpose you can use the static getLocaleList() method
which will return a list of all known locales.

Exemple 493. getLocaleList()

$localelist = Zend_Locale::getLocaleList();

Note that the locales are returned as key of the array you will receive. The value
is always a boolean TRUE.

2.9. Detecting locales


When you want to detect if a given input, regardless of its source, is a locale you should use
the static isLocale() method. The first parameter of this method is the string which you want
to check.

949
Zend_Locale

Exemple 494. Simple locale detection

$input = 'to_RU';
if (Zend_Locale::isLocale($input)) {
print "'{$input}' is a locale";
} else {
print "Sorry... the given input is no locale";
}

As you can see, the output of this method is always a boolean. There is only one reason you
could get an exception when calling this method. When your system does not provide any locale
and Zend Framework is not able to detect it automatically. Normally this shows that there is a
problem with your OS in combination with PHP's setlocale().

You should also note that any given locale string will automatically be degraded if the region part
does not exist for this locale. In our previous example the language 'to' does not exist in the
region 'RU', but you will still get TRUE returned as Zend_Locale can work with the given input.

Still it's sometimes useful to prevent this automatic degrading, and this is where the second
parameter of isLocale() comes in place. The strict parameter defaults to FALSE and can
be used to prevent degrading when set to TRUE.

Exemple 495. Strict locale detection

$input = 'to_RU';
if (Zend_Locale::isLocale($input, true)) {
print "'{$input}' is a locale";
} else {
print "Sorry... the given input is no locale";
}

Now that you are able to detect if a given string is a locale you could add locale aware behaviour
to your own classes. But you will soon detect that this will always leads to the same 15 lines of
code. Something like the following example:

Exemple 496. Implement locale aware behaviour

if ($locale === null) {


$locale = new Zend_Locale();
}

if (!Zend_Locale::isLocale($locale, true, false)) {


if (!Zend_Locale::isLocale($locale, false, false)) {
throw new Zend_Locale_Exception(
"The locale '$locale' is no known locale");
}

$locale = new Zend_Locale($locale);


}

if ($locale instanceof Zend_Locale) {


$locale = $locale->toString();
}

With Zend Framework 1.8 we added a static findLocale() method which returns you a locale
string which you can work with. It processes the following tasks:

• Detects if a given string is a locale

950
Zend_Locale

• Degrades the locale if it does not exist in the given region

• Returns a previous set application wide locale if no input is given

• Detects the locale from browser when the previous detections failed

• Detects the locale from environment when the previous detections failed

• Detects the locale from framework when the previous detections failed

• Returns always a string which represents the found locale.

The following example shows how these checks and the above code can be simplified with one
single call:

Exemple 497. Locale aware behaviour as with Zend Framework 1.8

$locale = Zend_Locale::findLocale($inputstring);

3. Normalization and Localization


Zend_Locale_Format is a internal component used by Zend_Locale. All locale aware
classes use Zend_Locale_Format for normalization and localization of numbers and dates.
Normalization involves parsing input from a variety of data representations, like dates, into
a standardized, structured representation, such as a PHP array with year, month, and day
elements.

The exact same string containing a number or a date might mean different things to people with
different customs and conventions. Disambiguation of numbers and dates requires rules about
how to interpret these strings and normalize the values into a standardized data structure. Thus,
all methods in Zend_Locale_Format require a locale in order to parse the input data.

Default "root" Locale


If no locale is specified, then normalization and localization will use the standard
"root" locale, which might yield unexpected behavior, if the input originated in a
different locale, or output for a specific locale was expected.

3.1. Number normalization: getNumber($input, Array $options)


There are many number systems different from the common decimal system (e.g. "3.14").
Numbers can be normalized with the getNumber() function to obtain the standard decimal
representation. for all number-related discussions in this manual, Arabic/European numerals
(0,1,2,3,4,5,6,7,8,9) are implied, unless explicitly stated otherwise. The options array may contain
a 'locale' to define grouping and decimal characters. The array may also have a 'precision' to
truncate excess digits from the result.

Exemple 498. Number normalization

$locale = new Zend_Locale('de_AT');


$number = Zend_Locale_Format::getNumber('13.524,678',
array('locale' => $locale,
'precision' => 3)
);

print $number; // will return 13524.678

951
Zend_Locale

3.1.1. Precision and Calculations


Since getNumber($value, array $options = array()) can normalize extremely large
numbers, check the result carefully before using finite precision calculations, such as ordinary
PHP math operations. For example, if ((string)int_val($number) != $number)
{ use BCMath or GMP . Most PHP installations support the BCMath extension.

Also, the precision of the resulting decimal representation can be rounded to a desired length
with getNumber() with the option 'precision'. If no precision is given, no rounding occurs.
Use only PHP integers to specify the precision.

If the resulting decimal representation should be truncated to a desired length instead of


rounded the option 'number_format' can be used instead. Define the length of the decimal
representation with the desired length of zeros. The result will then not be rounded. So if the
defined precision within number_format is zero the value "1.6" will return "1", not "2. See the
example nearby:

Exemple 499. Number normalization with precision

$locale = new Zend_Locale('de_AT');


$number = Zend_Locale_Format::getNumber('13.524,678',
array('precision' => 1,
'locale' => $locale)
);
print $number; // will return 13524.7

$number = Zend_Locale_Format::getNumber('13.524,678',
array('number_format' => '#.00',
'locale' => $locale)
);
print $number; // will return 13524.67

3.2. Number localization


toNumber($value, array $options = array()) can localize numbers to the following
supported locales . This function will return a localized string of the given number in a
conventional format for a specific locale. The 'number_format' option explicitly specifies a non-
default number format for use with toNumber().

Exemple 500. Number localization

$locale = new Zend_Locale('de_AT');


$number = Zend_Locale_Format::toNumber(13547.36,
array('locale' => $locale));

// will return 13.547,36


print $number;

Unlimited length

toNumber() can localize numbers with unlimited length. It is not related to


integer or float limitations.

The same way as within getNumber(), toNumber() handles precision. If no precision is given,
the complete localized number will be returned.

952
Zend_Locale

Exemple 501. Number localization with precision

$locale = new Zend_Locale('de_AT');


$number = Zend_Locale_Format::toNumber(13547.3678,
array('precision' => 2,
'locale' => $locale));

// will return 13.547,37


print $number;

Using the option 'number_format' a self defined format for generating a number can be defined.
The format itself has to be given in CLDR format as described below. The locale is used to get
separation, precision and other number formatting signs from it. German for example defines ','
as precision separation and in English the '.' sign is used.

Tableau 94. Format tokens for self generated number formats

Token Description Example format Generated output


#0 Generates a number #0 1234567
without precision and
separation
, Generates a #,##0 1,234,567
separation with the
length from separation
to next separation or to
0
#,##,##0 Generates a standard #,##,##0 12,34,567
separation of 3 and all
following separations
with 2
. Generates a precision #0.# 1234567.1234
0 Generates a precision #0.00 1234567.12
with a defined length

Exemple 502. Using a self defined number format

$locale = new Zend_Locale('de_AT');


$number = Zend_Locale_Format::toNumber(13547.3678,
array('number_format' => '#,#0.00',
'locale' => 'de')
);

// will return 1.35.47,36


print $number;

$number = Zend_Locale_Format::toNumber(13547.3,
array('number_format' => '#,##0.00',
'locale' => 'de')
);

// will return 13.547,30


print $number;

953
Zend_Locale

3.3. Number testing


isNumber($value, array $options = array()) checks if a given string is a number
and returns TRUE or FALSE.

Exemple 503. Number testing

$locale = new Zend_Locale();


if (Zend_Locale_Format::isNumber('13.445,36', array('locale' => 'de_AT')) {
print "Number";
} else {
print "not a Number";
}

3.4. Float value normalization


Floating point values can be parsed with the getFloat($value, array $options =
array()) function. A floating point value will be returned.

Exemple 504. Floating point value normalization

$locale = new Zend_Locale('de_AT');


$number = Zend_Locale_Format::getFloat('13.524,678',
array('precision' => 2,
'locale' => $locale)
);

// will return 13524.68


print $number;

3.5. Floating point value localization


toFloat() can localize floating point values. This function will return a localized string of the
given number.

Exemple 505. Floating point value localization

$locale = new Zend_Locale('de_AT');


$number = Zend_Locale_Format::toFloat(13547.3655,
array('precision' => 1,
'locale' => $locale)
);

// will return 13.547,4


print $number;

3.6. Floating point value testing


isFloat($value, array $options = array()) checks if a given string is a floating point
value and returns TRUE or FALSE.

954
Zend_Locale

Exemple 506. Floating point value testing

$locale = new Zend_Locale('de_AT');


if (Zend_Locale_Format::isFloat('13.445,36', array('locale' => $locale)) {
print "float";
} else {
print "not a float";
}

3.7. Integer value normalization


Integer values can be parsed with the getInteger() function. A integer value will be returned.

Exemple 507. Integer value normalization

$locale = new Zend_Locale('de_AT');


$number = Zend_Locale_Format::getInteger('13.524,678',
array('locale' => $locale));

// will return 13524


print $number;

3.8. Integer point value localization


toInteger($value, array $options = array()) can localize integer values. This
function will return a localized string of the given number.

Exemple 508. Integer value localization

$locale = new Zend_Locale('de_AT');


$number = Zend_Locale_Format::toInteger(13547.3655,
array('locale' => $locale));

// will return 13.547


print $number;

3.9. Integer value testing


isInteger($value, array $options = array()) checks if a given string is a integer
value and returns TRUE or FALSE.

Exemple 509. Integer value testing

$locale = new Zend_Locale('de_AT');


if (Zend_Locale_Format::isInteger('13.445', array('locale' => $locale)) {
print "integer";
} else {
print "not a integer";
}

3.10. Numeral System Conversion


Zend_Locale_Format::convertNumerals() converts digits between different numeral
systems , including the standard Arabic/European/Latin numeral system (0,1,2,3,4,5,6,7,8,9),

955
Zend_Locale

not to be confused with Eastern Arabic numerals sometimes used with the Arabic language to
express numerals. Attempts to use an unsupported numeral system will result in an exception,
to avoid accidentally performing an incorrect conversion due to a spelling error. All characters
in the input, which are not numerals for the selected numeral system, are copied to the output
with no conversion provided for unit separator characters. Zend_Locale* components rely on
the data provided by CLDR (see their list of scripts grouped by language).

In CLDR and hereafter, the Europena/Latin numerals will be referred to as "Latin" or by the
assigned 4-letter code "Latn". Also, the CLDR refers to this numeral systems as "scripts".

Suppose a web form collected a numeric input expressed using Eastern Arabic
digits "####". Most software and PHP functions expect input using Arabic numerals.
Fortunately, converting this input to its equivalent Latin numerals "100" requires little
effort using convertNumerals($inputNumeralString, $sourceNumeralSystem,
$destNumeralSystem) , which returns the $input with numerals in the script
$sourceNumeralSystem converted to the script $destNumeralSystem.

Exemple 510. Converting numerals from Eastern Arabic scripts to European/Latin


scripts

$arabicScript = "####"; // Arabic for "100" (one hundred)


$latinScript = Zend_Locale_Format::convertNumerals($arabicScript,
'Arab',
'Latn');

print "\nOriginal: " . $arabicScript;


print "\nNormalized: " . $latinScript;

Similarly, any of the supported numeral systems may be converted to any other supported
numeral system.

Exemple 511. Converting numerals from Latin script to Eastern Arabic script

$latinScript = '123';
$arabicScript = Zend_Locale_Format::convertNumerals($latinScript,
'Latn',
'Arab');

print "\nOriginal: " . $latinScript;


print "\nLocalized: " . $arabicScript;

Exemple 512. Getting 4 letter CLDR script code using a native-language name of
the script

function getScriptCode($scriptName, $locale)


{
$scripts2names = Zend_Locale_Data::getList($locale, 'script');
$names2scripts = array_flip($scripts2names);
return $names2scripts[$scriptName];
}
echo getScriptCode('Latin', 'en'); // outputs "Latn"
echo getScriptCode('Tamil', 'en'); // outputs "Taml"
echo getScriptCode('tamoul', 'fr'); // outputs "Taml"

For a list of supported numeral systems call


Zend_Locale::getTranslationList('numberingsystem', 'en').

956
Zend_Locale

4. Working with Dates and Times


Zend_Locale_Format provides several methods for working with dates and times to help
convert and normalize between different formats for different locales. Use Zend_Date for
manipulating dates, and working with date strings that already conform to one of the many
internationally recognized standard formats, or one of the localized date formats supported by
Zend_Date . Using an existing, pre-defined format offers advantages, including the use of well-
tested code, and the assurance of some degree of portability and interoperability (depending on
the standard used). The examples below do not follow these recommendations, since using non-
standard date formats would needlessly increase the difficulty of understanding these examples.

4.1. Normalizing Dates and Times


The getDate() method parses strings containing dates in localized formats. The results are
returned in a structured array, with well-defined keys for each part of the date. In addition, the
array will contain a key 'date_format' showing the format string used to parse the input date
string. Since a localized date string may not contain all parts of a date/time, the key-value pairs
are optional. For example, if only the year, month, and day is given, then all time values are
suppressed from the returned array, and vice-versa if only hour, minute, and second were given
as input. If no date or time can be found within the given input, an exception will be thrown.

If setOption(array('fix_date' => true)) is set the getDate() method adds a key


'fixed' with a whole number value indicating if the input date string required "fixing" by rearranging
the day, month, or year in the input to fit the format used.

Tableau 95. Key values for getDate() with option 'fix_date'

value meaning
0 nothing to fix
1 fixed false month
2 swapped day and year
3 swapped month and year
4 swapped month and day

For those needing to specify explicitly the format of the date string, the following format token
specifiers are supported. If an invalid format specifier is used, such as the PHP 'i' specifier when
in ISO format mode, then an error will be thrown by the methods in Zend_Locale_Format that
support user-defined formats.

These specifiers (below) are a small subset of the full "ISO" set supported by Zend_Date's
toString(). If you need to use PHP date() compatible format specifiers, then first
call setOptions(array('format_type' => 'php')). And if you want to convert
only one special format string from PHP date() compatible format to "ISO" format use
convertPhpToIsoFormat(). Currently, the only practical difference relates to the specifier
for minutes ('m' using the ISO default, and 'i' using the PHP date format).

Tableau 96. Return values

getDate() format Array key Returned value Minimum Maximum


character
d day integer 1 31

957
Zend_Locale

getDate() format Array key Returned value Minimum Maximum


character
M month integer 1 12
y year integer no limit PHP integer's
maximum
h hour integer 0 PHP integer's
maximum
m minute integer 0 PHP integer's
maximum
s second integer 0 PHP integer's
maximum

Exemple 513. Normalizing a date

$dateString = Zend_Locale_Format::getDate('13.04.2006',
array('date_format' =>
'dd.MM.yyyy')
);

// creates a Zend_Date object for this date


$dateObject = Zend_Date('13.04.2006',
array('date_format' => 'dd.MM.yyyy'));

print_r($dateString); // outputs:

Array
(
[format] => dd.MM.yyyy
[day] => 13
[month] => 4
[year] => 2006
)

// alternatively, some types of problems with input data can be


// automatically corrected
$date = Zend_Locale_Format::getDate('04.13.2006',
array('date_format' => 'dd.MM.yyyy',
'fix_date' => true)
);

print_r($date); // outputs:

Array
(
[format] => dd.MM.yyyy
[day] => 13
[month] => 4
[year] => 2006
[fixed] => 4
)

Since getDate() is "locale-aware", specifying the $locale is sufficient for date strings
adhering to that locale's format. The option 'fix_date' uses simple tests to determine if the day
or month is not valid, and then applies heuristics to try and correct any detected problems. Note
the use of 'Zend_Locale_Format::STANDARD' as the value for 'date_format' to prevent the

958
Zend_Locale

use of a class-wide default date format set using setOptions(). This forces getDate to use
the default date format for $locale.

Exemple 514. Normalizing a date by locale

$locale = new Zend_Locale('de_AT');


$date = Zend_Locale_Format::getDate('13.04.2006',
array('date_format' =>
Zend_Locale_Format::STANDARD,
'locale' => $locale)
);

print_r ($date);

A complete date and time is returned when the input contains both a date and time in the expected
format.

Exemple 515. Normalizing a date with time

$locale = new Zend_Locale('de_AT');


$date = Zend_Locale_Format::getDate('13.04.2005 22:14:55',
array('date_format' =>
Zend_Locale_Format::STANDARD,
'locale' => $locale)
);

print_r ($date);

If a specific format is desired, specify the $format argument, without giving a $locale. Only
single-letter codes (H, m, s, y, M, d), and MMMM and EEEE are supported in the $format.

Exemple 516. Normalizing a userdefined date

$date = Zend_Locale_Format::getDate('13200504T551422',
array('date_format' =>
'ddyyyyMM ssmmHH')
);

print_r ($date);

The format can include the following signs :

Tableau 97. Format definition

Format Letter Description


d or dd 1 or 2 digit day
M or MM 1 or 2 digit month
y or yy 1 or 2 digit year
yyyy 4 digit year
h 1 or 2 digit hour
m 1 or 2 digit minute
s 1 or 2 digit second

Examples for proper formats are

959
Zend_Locale

Tableau 98. Example formats

Formats Input Output


dd.MM.yy 1.4.6 ['day'] => 1, ['month'] => 4,
['year'] => 6
dd.MM.yy 01.04.2006 ['day'] => 1, ['month'] => 4,
['year'] => 2006
yyyyMMdd 1.4.6 ['day'] => 6, ['month'] => 4,
['year'] => 1

Database date format

To parse a database date value (f.e. MySql or MsSql), use Zend_Date's


ISO_8601 format instead of getDate().

The option 'fix_date' uses simple tests to determine if the day or month is not valid, and then
applies heuristics to try and correct any detected problems. getDate() automatically detects
and corrects some kinds of problems with input, such as misplacing the year:

Exemple 517. Automatic correction of input dates

$date = Zend_Locale_Format::getDate('41.10.20',
array('date_format' => 'ddMMyy',
'fix_date' => true)
);

// instead of 41 for the day, the 41 will be returned as year value


print_r ($date);

4.2. Testing Dates


Use checkDateFormat($inputString, array('date_format' => $format,
$locale)) to check if a given string contains all expected date parts. The
checkDateFormat() method uses getDate(), but without the option 'fixdate' to avoid
returning TRUE when the input fails to conform to the date format. If errors are detected in the
input, such as swapped values for months and days, the option 'fixdate' method will apply
heuristics to "correct" dates before determining their validity.

Exemple 518. Date testing

$locale = new Zend_Locale('de_AT');


// using the default date format for 'de_AT', is this a valid date?
if (Zend_Locale_Format::checkDateFormat('13.Apr.2006',
array('date_format' =>
Zend_Locale_Format::STANDARD,
$locale)
) {
print "date";
} else {
print "not a date";
}

960
Zend_Locale

4.3. Normalizing a Time


Normally, a time will be returned with a date, if the input contains both. If the proper format is
not known, but the locale relevant to the user input is known, then getTime() should be used,
because it uses the default time format for the selected locale.

Exemple 519. Normalize an unknown time

$locale = new Zend_Locale('de_AT');


if (Zend_Locale_Format::getTime('13:44:42',
array('date_format' =>
Zend_Locale_Format::STANDARD,
'locale' => $locale)) {
print "time";
} else {
print "not a time";
}

4.4. Testing Times


Use checkDateFormat() to check if a given string contains a proper time. The usage is exact
the same as with checking Dates, only date_format should contain the parts which you expect
to have.

Exemple 520. Testing a time

$locale = new Zend_Locale('de_AT');


if (Zend_Locale_Format::checkDateFormat('13:44:42',
array('date_format' => 'HH:mm:ss',
'locale' => $locale)) {
print "time";
} else {
print "not a time";
}

5. Supported locales
Zend_Locale provides information on several locales. The following table shows all languages
and their related locales, sorted by language:

Tableau 99. List of all supported languages


Language Locale Region
aa ---
aa_DJ Djibouti
Afar
aa_ER Eritrea
aa_ET Ethiopia
af ---
Afrikaans af_NA Namibia
af_ZA South Africa
ak ---
Akan
ak_GH Ghana
Amharic am ---

961
Zend_Locale

Language Locale Region


am_ET Ethiopia
ar ---
ar_AE United Arab Emirates
ar_BH Bahrain
ar_DZ Algeria
ar_EG Egypt
ar_IQ Iraq
ar_JO Jordan
ar_KW Kuwait
ar_LB Lebanon
Arabic
ar_LY Libya
ar_MA Morocco
ar_OM Oman
ar_QA Qatar
ar_SA Saudi Arabia
ar_SD Sudan
ar_SY Syria
ar_TN Tunisia
ar_YE Yemen
as ---
Assamese
as_IN India
az ---
Azerbaijani
az_AZ Azerbaijan
be ---
Belarusian
be_BY Belarus
bg ---
Bulgarian
bg_BG Bulgaria
bn ---
Bengali bn_BD Bangladesh
bn_IN India
bo ---
Tibetan bo_CN China
bn_IN India
bs ---
Bosnian
bs_BA Bosnia and Herzegovina
byn ---
Blin
byn_ER Eritrea
Catalan ca ---

962
Zend_Locale

Language Locale Region


ca_ES Spain
cch ---
Atsam
cch_NG Nigeria
Coptic cop ---
cs ---
Czech
cs_CZ Czech Republic
cy ---
Welsh
cy_GB United Kingdom
da ---
Danish
da_DK Denmark
de ---
de_AT Austria
de_BE Belgium
German de_CH Switzerland
de_DE Germany
de_LI Liechtenstein
de_LU Luxembourg
dv ---
Divehi
dv_MV Maldives
dz ---
Dzongkha
dz_BT Bhutan
ee ---
Ewe ee_GH Ghana
ee_TG Togo
el ---
Greek el_CY Cyprus
el_GR Greece
en ---
en_AS American Samoa
en_AU Australia
en_BE Belgium
en_BW Botswana
English en_BZ Belize
en_CA Canada
en_GB United Kingdom
en_GU Guam
en_HK Hong Kong
en_IE Ireland

963
Zend_Locale

Language Locale Region


en_IN India
en_JM Jamaica
en_MH Marshall Islands
en_MP Northern Mariana Islands
en_MT Malta
en_NA Namibia
en_NZ New Zealand
en_PH Philippines
en_PK Pakistan
en_SG Singapore
en_TT Trinidad and Tobago
en_UM United States Minor Outlying
Islands
en_US United States
en_VI U.S. Virgin Islands
en_ZA South Africa
en_ZW Zimbabwe
Esperanto eo ---
es ---
es_AR Argentina
es_BO Bolivia
es_CL Chile
es_CO Colombia
es_CR Costa Rica
es_DO Dominican Republic
es_EC Ecuador
es_ES Spain
es_GT Guatemala
Spanish
es_HN Honduras
es_MX Mexico
es_NI Nicaragua
es_PA Panama
es_PE Peru
es_PR Puerto Rico
es_PY Paraguay
es_SV El Salvador
es_US United States
es_UY Uruguay

964
Zend_Locale

Language Locale Region


es_VE Venezuela
et ---
Estonian
et_EE Estonia
eu ---
Basque
eu_ES Spain
fa ---
Persian fa_AF Afghanistan
fa_IR Iran
fi ---
Finnish
fi_FI Finland
fil ---
Filipino
fil_PH Philippines
fo ---
Faroese
fo_FO Faroe Islands
fr ---
fr_BE Belgium
fr_CA Canada
fr_CH Switzerland
French
fr_FR France
fr_LU Luxembourg
fr_MC Monaco
fr_SN Senegal
fur ---
Friulian
fur_IT Italy
ga ---
Irish
ga_IE Ireland
gaa ---
Ga
gaa_GH Ghana
gez ---
Geez gez_ER Eritrea
gez_ET Ethiopia
gl ---
Gallegan
gl_ES Spain
gsw ---
Swiss German
gsw_CH Swiss
gu ---
Gujarati
gu_IN India
Manx gv ---

965
Zend_Locale

Language Locale Region


gv_GB United Kingdom
ha ---
ha_GH Ghana
Hausa ha_NE Niger
ha_NG Nigeria
ha_SD Sudan
haw ---
Hawaiian
haw_US United States
he ---
Hebrew
he_IL Israel
hi ---
Hindi
hi_IN India
hr ---
Croatian
hr_HR Croatia
hu ---
Hungarian
hu_HU Hungary
Armenian hy ---
Interlingua ia ---
id ---
Indonesian
id_ID Indonesia
ig ---
Igbo
ig_NG Nigeria
ii ---
Sichuan Yi
ii_CN China
Indonesian in ---
is ---
Icelandic
is_IS Iceland
it ---
Italian it_CH Switzerland
it_IT Italy
Inuktitut iu ---
Hebrew iw ---
ja ---
Japanese
ja_JP Japan
ka ---
Georgian
ka_GE Georgia
kaj ---
Jju
kaj_NG Nigeria

966
Zend_Locale

Language Locale Region


kam ---
Kamba
kam_KE Kenya
kcg ---
Tyap
kcg_NG Nigeria
kfo ---
Koro
kfo_CI Ivory Coast
kk ---
Kazakh
kk_KZ Kazakhstan
kl ---
Kalaallisut
kl_GL Greenland
km ---
Khmer
km_KH Cambodia
kn ---
Kannada
kn_IN India
ko ---
Korean
ko_KR South Korea
kok ---
Konkani
kok_IN India
kpe ---
Kpelle kpe_GN Guinea
kpe_LR Liberia
ku ---
Kurdish
ku_IQ Iraq
ku_IR Iran
ku_SY Syria
ku_TR Turkey
kw ---
Cornish
kw_GB United Kingdom
ky ---
Kirghiz
ky_KG Kyrgyzstan
ln ---
Lingala ln_CD Congo - Kinshasa
ln_CG Congo - Brazzaville
lo ---
Lao
lo_LA Laos
lt ---
Lithuanian
lt_LT Lithuania
Latvian lv ---

967
Zend_Locale

Language Locale Region


lv_LV Latvia
mk ---
Macedonian
mk_MK Macedonia
ml ---
Malayalam
ml_IN India
mn ---
Mongolian mn_CN China
mn_MN Mongolia
Romanian mo ---
mr ---
Marathi
mr_IN India
ms ---
Malay ms_BN Brunei
ms_MY Malaysia
mt ---
Maltese
mt_MT Malta
my ---
Burmese
my_MM Myanmar
nb ---
Norwegian Bokmal
nb_NO Norway
nds ---
Low German
nds_DE Germany
ne ---
Nepali ne_IN India
ne_NP Nepal
nl ---
Dutch nl_BE Belgium
nl_NL Netherlands
nn ---
Norwegian Nynorsk
nn_NO Norway
Norwegian no ---
nr ---
South Ndebele
nr_ZA South Africa
nso ---
Northern Sotho
nso_ZA South Africa
ny ---
Nyanja
ny_MW Malawi
Occitan oc ---

968
Zend_Locale

Language Locale Region


oc_FR France
om ---
Oromo om_ET Ethiopia
om_KE Kenya
or ---
Oriya
or_IN India
pa ---
Punjabi pa_IN India
pa_PK Pakistan
pl ---
Polish
pl_PL Poland
ps ---
Pashto
ps_AF Afghanistan
pt ---
Portuguese pt_BR Brazil
pt_PT Portugal
ro ---
Romanian ro_MD Moldova
ro_RO Romania
ru ---
Russian ru_RU Russia
ru_UA Ukraine
rw ---
Kinyarwanda
rw_RW Rwanda
sa ---
Sanskrit
sa_IN India
se ---
Northern Sami se_FI Finland
se_NO Norway
sh ---
sh_BA Bosnia and Herzegovina
Serbo-Croatian
sh_CS Serbia and Montenegro
sh_YU Serbia
si ---
Sinhala
si_LK Sri Lanka
sid ---
Sidamo
sid_ET Ethiopia
Slovak sk ---

969
Zend_Locale

Language Locale Region


sk_SK Slovakia
sl ---
Slovenian
sl_SI Slovenia
so ---
so_DJ Djibouti
Somali so_ET Ethiopia
so_KE Kenya
so_SO Somalia
sq ---
Albanian
sq_AL Albania
sr ---
sr_BA Bosnia and Herzegovina
sr_CS Serbia and Montenegro
Serbian
sr_ME Montenegro
sr_RS Serbia
sr_YU Serbia
ss ---
Swati ss_SZ Swaziland
ss_ZA South Africa
st ---
Southern Sotho st_LS Lesotho
st_ZA South Africa
sv ---
Swedish sv_FI Finland
sv_SE Sweden
sw ---
Swahili sw_KE Kenya
sw_TZ Tanzania
syr ---
Syriac
syr_SY Syria
ta ---
Tamil
ta_IN India
te ---
Telugu
te_IN India
tg ---
Tajik
tg_TJ Tajikistan
th ---
Thai
th_TH Thailand

970
Zend_Locale

Language Locale Region


ti ---
Tigrinya ti_ER Eritrea
ti_ET Ethiopia
tig ---
Tigre
tig_ER Eritrea
Tagalog tl ---
tn ---
Tswana
tn_ZA South Africa
to ---
Tonga
to_TO Tonga
tr ---
Turkish
tr_TR Turkey
trv ---
Taroko
trv_TW Taiwan
ts ---
Tsonga
ts_ZA South Africa
tt ---
Tatar
tt_RU Russia
ug ---
Uighur
ug_CN China
uk ---
Ukrainian
uk_UA Ukraine
ur ---
Urdu ur_IN India
ur_PK Pakistan
uz ---
Uzbek uz_AF Afghanistan
uz_UZ Uzbekistan
ve ---
Venda
ve_ZA South Africa
vi ---
Vietnamese
vi_VN Vietnam
wal ---
Walamo
wal_ET Ethiopia
wo ---
Wolof
wo_SN Senegal
xh ---
Xhosa
xh_ZA South Africa

971
Zend_Locale

Language Locale Region


yo ---
Yoruba
yo_NG Nigeria
zh ---
zh_CN China
zh_HK Hong Kong
Chinese
zh_MO Macau
zh_SG Singapore
zh_TW Taiwan
zu ---
Zulu
zu_ZA South Africa

972
Zend_Log
1. Présentation
Zend_Log est un composant destiné à tous les usages du log. Il supporte l'écriture multiple
centralisée, formate les messages envoyés vers les logs, et les filtre. Ces fonctions sont divisées
en objets suivants :

• Un enregistreur (instance de Zend_Log) est l'objet que votre application emploie le plus. Vous
pouvez avoir autant d'objets d'enregistreur que vous voulez ; ils n'agissent pas l'un sur l'autre.
Un objet enregistreur doit contenir au moins un rédacteur (Writer), et peut facultativement
contenir un ou plusieurs filtres.

• Un rédacteur [ou Writer] (hérite de Zend_Log_Writer_Abstract) est responsable de la


sauvegarde des données dans le stockage.

• Un filtre (implémente Zend_Log_Filter_Interface) bloque des données de log ne devant


pas être écrites. Un filtre peut être appliqué à un rédacteur en particulier, ou à tous les
rédacteurs. Dans l'un ou l'autre cas, les filtres peuvent être enchaînés.

• Un formateur (implémente Zend_Log_Formatter_Interface) peut formater les données


de log avant qu'elles soient écrites par un rédacteur. Chaque rédacteur a exactement un
formateur.

1.1. Créer un log


Pour commencer à enregistrer, instanciez un rédacteur et passez le à une instance d'un
enregistreur :

$logger = new Zend_Log();


$redacteur = new Zend_Log_Writer_Stream('php://output');

$logger->addWriter($redacteur);

Il est important de noter que l'enregistreur doit avoir au moins un rédacteur. Vous pouvez ajouter
tout nombre de rédacteurs en utilisant la méthode addWriter().

Alternativement, vous pouvez passer un rédacteur directement au constructeur de l'enregistreur :

$logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output'));

L'enregistreur est maintenant prêt à être utilisé.

1.2. Messages de logs


Pour enregistrer un message, appelez la méthode log() de l'instance de l'enregistreur et
passez lui le message avec son niveau de priorité.

$logger->log("Message d'information", Zend_Log::INFO);

Le premier paramètre de la méthode log() est une chaîne message et le deuxième paramètre
est une priority fourni en nombre entier. La priorité doit être l'une des priorités identifiées par
l'instance de l'enregistreur. Ceci est expliqué dans la prochaine section.

973
Zend_Log

Un raccourci est également disponible. Au lieu d'appeler la méthode log(), vous pouvez
appeler une méthode par le même nom que la priorité :

$logger->log("Message d'information", Zend_Log::INFO);


$logger->info("Message d'information");

$logger->log("Message d'urgence", Zend_Log::EMERG);


$logger->emerg("Message d'urgence");

1.3. Détruire un log


Si l'objet enregistreur n'est plus nécessaire, vous devez affectez la valeur NULL à la variable le
contenant pour le détruire. Ceci appellera automatiquement la méthode shutdown() de chaque
rédacteur avant que l'objet enregistreur ne soit détruit :

$logger = null;

Explicitement détruire le log de cette façon est facultatif et est exécuté automatiquement à la
fermeture de PHP.

1.4. Utiliser les priorités intégrées


La classe de Zend_Log définit les priorités suivantes :

EMERG = 0; // Urgence : le système est inutilisable


ALERT = 1; // Alerte: une mesure corrective
// doit être prise immédiatement
CRIT = 2; // Critique : états critiques
ERR = 3; // Erreur: états d'erreur
WARN = 4; // Avertissement: états d'avertissement
NOTICE = 5; // Notice: normal mais état significatif
INFO = 6; // Information: messages d'informations
DEBUG = 7; // Debug: messages de déboguages

Ces priorités sont toujours disponibles, et une méthode de convenance de même nom est
disponible pour chacun.

Les priorités ne sont pas arbitraires. Elles viennent du protocole BSD syslog, qui est décrit dans
la RFC-3164. Les noms et les niveaux de priorité correspondants sont également compatibles
avec un autre système de log de PHP, PEAR Log, ce qui favorise l'interopérabilité entre lui et
Zend_Log.

Les numéros de priorité descendent par ordre d'importance. EMERG (0) est la priorité la plus
importante. DEBUG (7) est la priorité la moins importante des priorités intégrées. Vous pouvez
définir des priorités d'importance inférieure que DEBUG. En choisissant la priorité pour votre
message de log, faîtes attention à cette hiérarchie prioritaire et choisissez convenablement.

1.5. Ajouter ses propres priorités


Des priorités définies par l'utilisateur peuvent être ajoutées en cours d'exécution en utilisant la
méthode de addPriority() de l'enregistreur :

$logger->addPriority('ESSAI', 8);

974
Zend_Log

L'extrait ci-dessus crée une nouvelle priorité, ESSAI, dont la valeur est 8. La nouvelle priorité
est alors disponible pour l'enregistreur :

$logger->log("Message d'essai", 8);


$logger->essai("Message d'essai");

Les nouvelles priorités ne peuvent pas surcharger celles existantes.

1.6. Comprendre les événements de logs


Quand vous appelez la méthode log() ou l'un de ses raccourcis, un événement de log est
créé. C'est simplement un tableau associatif avec des données décrivant l'événement qui est
envoyé aux rédacteurs. Les clés suivantes sont toujours créées dans ce tableau : timestamp,
message, priority, et priorityName.

La création du tableau event est complètement transparente. Cependant, la connaissance du


tableau d'événement est exigée pour ajouter un élément qui n'existerait pas dans le réglage par
défaut ci-dessus.

Pour ajouter un nouvel élément à chaque futur événement, appeler la méthode


setEventItem() en donnant une clé et une valeur :

$logger->setEventItem('pid', getmypid());

L'exemple ci-dessus place un nouvel élément nommé pid et lui donne comme valeur le PID du
processus courant. Une fois qu'un nouvel élément a été placé, il est disponible automatiquement
pour tous les rédacteurs avec toutes les autres données d'événement pendant l'enregistrement.
Un élément peut être surchargé à tout moment en appelant une nouvelle fois la méthode
setEventItem().

Le réglage d'un nouvel élément d'événement avec setEventItem() entraîne que le nouvel
élément sera envoyé à tous les rédacteurs de l'enregistreur. Cependant, ceci ne garantit pas
que les rédacteurs utilisent réellement l'élément. C'est parce que les rédacteurs ne sauront pas
quoi faire avec lui à moins qu'un objet formateur soit informé du nouvel élément. Veuillez vous
reporter à la section sur des formateurs pour en apprendre davantage.

2. Rédacteurs (Writers)
Un rédacteur est un objet qui hérite de Zend_Log_Writer_Abstract. La responsabilité d'un
rédacteur est d'enregistrer des données de log dans un stockage particulier.

2.1. Écrire vers un flux (stream)


Zend_Log_Writer_Stream envoie des données de log à un flux de PHP.

Pour écrire des données de log dans le buffer d'affichage de PHP, il faut utiliser l'URL php://
output. Alternativement, vous pouvez préférer envoyer des données de log directement à un
flux comme STDERR (php://stderr).

$redacteur = new Zend_Log_Writer_Stream('php://output');


$logger = new Zend_Log($redacteur);

$logger->info("Message d'information");

975
Zend_Log

Pour écrire des données dans un fichier, employer un des Filesystem URLs:

$redacteur = new Zend_Log_Writer_Stream('/chemin/vers/fichierdelog');


$logger = new Zend_Log($redacteur);

$logger->info("Message d'information");

Par défaut, le flux s'ouvre en mode d'ajout ("a"). Pour l'ouvrir avec un mode différent, le
constructeur de Zend_Log_Writer_Stream accepte un deuxième paramètre facultatif pour
le mode.

Le constructeur de Zend_Log_Writer_Stream accepte également une ressource existante


de flux :

$flux = @fopen('/chemin/vers/fichierdelog', 'a', false);


if (! $flux) {
throw new Exception('Impossible d\'ouvrir le flux');
}

$redacteur = new Zend_Log_Writer_Stream($flux);


$logger = new Zend_Log($redacteur);

$logger->info("Message d'information");

Vous ne pouvez pas indiquer le mode pour des ressources existantes de flux. Le faire entraînera
une Zend_Log_Exception.

2.2. Écrire dans des bases de données


Zend_Log_Writer_Db écrit les informations de log dans une table de base de données
en utilisant Zend_Db. Le constructeur de Zend_Log_Writer_Db reçoit une instance de
Zend_Db_Adapter, un nom de table, et un plan de correspondance entre les colonnes de la
base de données et les données élémentaires d'événement :

$parametres = array ('host' => '127.0.0.1',


'username' => 'malory',
'password' => '******',
'dbname' => 'camelot');
$db = Zend_Db::factory('PDO_MYSQL', $parametres);

$planDeCorrespondance = array('niveau' => 'priority', 'msg' => 'message');


$redacteur = new Zend_Log_Writer_Db($db,
'nom_de_la_table_de_log',
$planDeCorrespondance);

$logger = new Zend_Log($redacteur);

$logger->info("Message d'information");

L'exemple ci-dessus écrit une ligne unique de données de log dans la table appelée
nom_de_la_table_de_log. La colonne de base de données appelée niveau reçoit le niveau
de priorité et la colonne appelée msg reçoit le message de log.

2.3. Écrire vers Firebug


Zend_Log_Writer_Firebug envoie des données d'historisation vers la console Firebug.

976
Zend_Log

Toutes les données sont envoyées via le composant


Zend_Wildfire_Channel_HttpHeaders qui utilise les en-têtes HTTP pour s'assurer que
le contenu de la page n'est pas perturbé. Déboguer les requêtes AJAX qui requière du JSON
"propre" ou un réponse XML est possible avec cette approche.

Éléments requis :

• Navigateur Firefox idéalement en version 3 mais la version 2 est aussi supportée.

• L'extension Firefox nommée Firebug qui peut être téléchargée à cette adresse https://
addons.mozilla.org/en-US/firefox/addon/1843.

• L'extension Firefox nommée FirePHP ui peut être téléchargée à cette adresse https://
addons.mozilla.org/en-US/firefox/addon/6149.

Exemple 521. Journaliser avec Zend_Controller_Front

// Placez ceci dans votre fichier d'amorçage


// avant de distribuer votre contrôleur frontal
$writer = new Zend_Log_Writer_Firebug();
$logger = new Zend_Log($writer);

// Utiliser ceci dans vos fichiers de modèles, vues et contrôleurs


$logger->log('Ceci est un message de log !', Zend_Log::INFO);

977
Zend_Log

Exemple 522. Journaliser sans Zend_Controller_Front

$writer = new Zend_Log_Writer_Firebug();


$logger = new Zend_Log($writer);

$request = new Zend_Controller_Request_Http();


$response = new Zend_Controller_Response_Http();
$channel = Zend_Wildfire_Channel_HttpHeaders::getInstance();
$channel->setRequest($request);
$channel->setResponse($response);

// Démarrer l'output buffering


ob_start();

// Maintenant vous pouvez appeler le logguer


$logger->log('Ceci est un message de log !', Zend_Log::INFO);

// Envoi des données d'historisation vers le navigateur


$channel->flush();
$response->sendHeaders();

2.3.1. Paramétrer les styles pour les priorités


Les priorités incorporées et celles définies par l'utilisateur peuvent être stylisées avec la méthode
setPriorityStyle().

$logger->addPriority('FOO', 8);
$writer->setPriorityStyle(8, 'TRACE');
$logger->foo('Foo Message');

Le style par défaut pour les priorités définies par l'utilisateur peut être paramétrer avec la méthode
setDefaultPriorityStyle().

$writer->setDefaultPriorityStyle('TRACE');

Les styles supportés sont les suivants :

Tableau 100. Styles d'historisation de Firebug


Style Description
LOG Affiche un message d'historisation basique
INFO Affiche un message d'historisation de type
information
WARN Affiche un message d'historisation de type
avertissement
ERROR Affiche un message d'historisation de type
erreur (celui-ci incrémente le compteur d'erreur
de Firebug)
TRACE Affiche un message d'historisation avec une
trace extensible
EXCEPTION Affiche un message d'historisation de type
erreur avec une trace extensible
TABLE Affiche un message d'historisation avec une
table extensible

978
Zend_Log

2.3.2. Préparer les données pour l'historisation

Toute variable PHP peut être journalisée avec les priorités incorporées, un formatage spécial
est requis si vous utilisez des styles d'historisation un peu plus spécialisé.

Les styles LOG, INFO, WARN, ERROR et TRACE ne requièrent pas de formatage spécial.

2.3.3. Historisation des exceptions

Pour journaliser une Zend_Exception, fournissez simplement l'objet exception au logguer. Il


n'y a pas d'importance sur la priorité ou le style que vous avez fourni puisque l'exception est
automatiquement reconnue.

$exception = new Zend_Exception('Test d\'exception');


$logger->err($exception);

2.3.4. Historisation sous forme de tableau

Vous pouvez aussi journaliser des données en les formatant comme un tableau. Les colonnes
sont automatiquement reconnues et la première ligne de données devient automatiquement la
ligne d'en-têtes.

$writer->setPriorityStyle(8, 'TABLE');
$logger->addPriority('TABLE', 8);

$table = array('Ligne de résumé pour la table',


array(
array('Colonne 1', 'Colonne 2'),
array('Ligne 1 c 1',' Ligne 1 c 2'),
array('Ligne 2 c 1',' Ligne 2 c 2')
)
);
$logger->table($table);

2.4. Écrire vers un émail


Zend_Log_Writer_Mail va écrire les entrées du log dans un message émail en utilisant
Zend_Mail. Le constructeur de Zend_Log_Writer_Mail requière un objet Zend_Mail et
optionnellement un objet Zend_Layout.

Le cas d'utilisation principal de Zend_Log_Writer_Mail est la notification les développeurs,


les administrateurs ou toute personne concernée, d'une erreur qui peut survenir dans des scripts.
Zend_Log_Writer_Mail a été crée avec l'idée que si quelque chose ne tourne pas rond, une
intervention humaine est nécessaire.

Voici un exemple d'utilisation basique :

$mail = new Zend_Mail();


$mail->setFrom('errors@example.org')
->addTo('project_developers@example.org');

$writer = new Zend_Log_Writer_Mail($mail);

// Ecrit le sujet. Un résumé des erreurs est ajouté à la suite

979
Zend_Log

$writer->setSubjectPrependText('Errors with script foo.php');

// Limite uniquement au niveau Warning ou supérieur


$writer->addFilter(Zend_Log::WARN);

$log = new Zend_Log();


$log->addWriter($writer);

// Essai
$log->error('unable to connect to database');

// A la fermeture, Zend_Mail::send() est inviqué et concernera


// tous les logs passés dans le filtre.

Zend_Log_Writer_Mail utilisera un corps de message en texte plein (plain text) par défaut.

Le filtre est géré. Par exemple si le filtre est réglé sur Warnings, et que 2 évènements warnings
et 5 évènements erreurs se produisent, alors 7 évènements seront envoyés.

2.4.1. Utilisation avec Zend_Layout


Une instance de Zend_Layout peut être utilisée pour générer du HTML qui fera partie de
l'émail multipart. Si Zend_Layout est utilisé, Zend_Log_Writer_Mail considérera que le
corps HTML du message sera la valeur du rendu de Zend_Layout.

En utilisant Zend_Log_Writer_Mail avec un objet Zend_Layout vous pouvez utiliser un


formateur personnalisé grâce à setLayoutFormatter(). Si aucun formateur spécifique
Zend_Layout n'est indiqué, le formateur en cours d'utilisation sera appelé. Voici un exemple :

$mail = new Zend_Mail();


$mail->setFrom('errors@example.org')
->addTo('project_developers@example.org');
// Nous ne spécifions pas le sujet du message dans l'objet Zend_Mail !

// Utilisons un simple objet Zend_Layout


$layout = new Zend_Layout();

// Créons un formateur à base de listes


$layoutFormatter = new Zend_Log_Formatter_Simple(
'<li>' . Zend_Log_Formatter_Simple::DEFAULT_FORMAT . '</li>'
);

$writer = new Zend_Log_Writer_Mail($mail, $layout);

// Appliquons le formateur sur le rendu de Zend_Layout.


$writer->setLayoutFormatter($layoutFormatter);
$writer->setSubjectPrependText('Errors with script foo.php');
$writer->addFilter(Zend_Log::WARN);

$log = new Zend_Log();


$log->addWriter($writer);

// essai
$log->error('unable to connect to database');

// A la fermeture, Zend_Mail::send() est inviqué et concernera


// tous les logs passés dans le filtre.
// l'email contiendra une partie "plain text", et une partie HTML

980
Zend_Log

2.4.2. Ligne du sujet dynamique


La méthode setSubjectPrependText() est utilisée à la place de
Zend_Mail::setSubject() pour que la ligne de sujet dans l'émail soit générée
dynamiquement avant l'envoi de l'émail. Par exemple, si le texte indiqué est "Erreurs depuis ce
script", le sujet de l'émail généré par Zend_Log_Writer_Mail avec 2 warnings et 5 errors
sera alors "Erreurs depuis ce script (warn = 2; error = 5)". Si le sujet n'est pas indiqué via
Zend_Log_Writer_Mail, la ligne de sujet de Zend_Mail, si il y en a une, sera utilisée.

2.4.3. Attention
Envoyer des rapports d'erreurs par emails peut être dangereux. Si votre système de surveillance
d'erreurs n'est pas correct ou a un problème, vous risquez de vous retrouver inondé de tonnes
d'emails en provenance de votre application.

A l'heure actuelle, il n'existe dans Zend_Log_Writer_Mail aucun système de limitation ou de


contrôle du nombre ou de la fréquence d'envoi des emails. Si vous nécessitez un tel système,
vous devrez l'implémenter vous-même.

Encore une fois, l'unique but de Zend_Log_Writer_Mail est la notification d'un humain au
sujet d'une erreur. Si ce système est clairement contrôlé, alors il peut devenir un avantage très
appréciable.

2.5. Ecrire dans lee journal du système


Zend_Log_Writer_Syslog écrit les rapports de log dans le journal système (syslog). En
interne, il utilise les fonctions PHP openlog(), closelog(), et syslog().

Un cas d'utilisation intéressant de Zend_Log_Writer_Syslog est le cluster de machines. La


fonctionnalité de journal système permet de faire en sorte que chaque machine enregistre dans
un fichier de journal centralisé, ce qui simplifie l'administration.

Par défaut, tous les messages gérés sont préfixés par "Zend_Log". Si vous souhaitez changer
ce nom, utilisez le constructeur ou l'accesseur:

// A l'instanciation
$writer = new Zend_Log_Writer_Syslog(array('application' => 'FooBar'));

// Plus tard:
$writer->setApplicationName('BarBaz');

Le journal système vous aidera aussi à identifier les messages par types d'application ("facility"),
les programmes de journalisation système vont générer des fichiers journaux différents en
fonction des types d'application, ce qui là encore, peut aider dans l'administration.

Pour spécifier le type d'application, utilisez le constructeur ou l'accesseur. Cette option peut être
l'une des constantes utilisées par openlog(), définies dans la page du manuel de openlog().

// A l'instanciation
$writer = new Zend_Log_Writer_Syslog(array('facility' => LOG_AUTH));

// Plus tard
$writer->setFacility(LOG_USER);

En utilisant l'objet de log, continuez d'utiliser les constantes de Zend_Log, elles vont être
converties en leurs valeurs par syslog().

981
Zend_Log

2.6. Ecrire vers le moniteur Zend Server


Zend_Log_Writer_ZendMonitor vous permet de journaliser des évènements via l'API de
Zend Server. Vous pouvez alors aggréger des messages de journal pour l'application et tout
son environnement, ceci vers un seul endroit. En interne, cet objet utilise simplement la fonction
monitor_custom_event() issue de Zend Monitor.

Une caractéristique particulière de l'API Monitor est que vous pouvez spécifier n'importe quelle
information dans le journal. Par exemple, journaliser une exception est possible en journalisant
tout l'objet Exception d'un coup et pas juste son message. L'objet sera alors visible et analysable
via le moniteur d'évènement de Zend Server.

Zend Monitor doit être installé et activé

Pour utiliser cet objet d'écriture, Zend Monitor doit petre installé et activé. Si ce
n'est pas le cas, alors l'objet d'écriture agira de manière transparente et ne fera
rien du tout.

Instancier l'objet d'écriture ZendMonitor est très simple:

$writer = new Zend_Log_Writer_ZendMonitor();


$log = new Zend_Log($writer);

Ensuite, journalisez vos évènements comme d'habitude:

$log->info('Voici un message');

Vous pouvez ajouter des informations à journaliser, passez les comme second paramètre:

$log->info('Exception rencontrée', $e);

Ce deuxième paramètre peut être de type scalaire, objet, ou tableau; si vous souhaitez passer
plusieurs informations d'un seul coup, utilisez un tableau.

$log->info('Exception rencontrée', array(


'request' => $request,
'exception' => $e,
));

Au sein de Zend Server, votre évènement est enregistré comme un "évènement


personnalisé" (custom event). Depuis l'onglet "Monitor", sélectionnez le sous menu
"Evènements"(Events), et utilisez ensuite le filtre "Personnalisé"(Custom).

982
Zend_Log

983
Zend_Log

Evènements dans le récapitulatif Zend Server Monitor

Sur cette image, les deux premiers évènements listés sont des évènements personnalisés
enregistré via l'objet d'écriture ZendMonitor. Cliquez alors sur un évènement pour voir toutes
ses informations.

984
Zend_Log

985
Zend_Log

Détails de l'évènement dans Zend Server Monitor

Cliquer sur le sous menu "Personnalisé"(Custom) montre les détails, c'est à dire ce que vous
avez passé comme deuxième argument à la méthode de journalisation. Cet information est
enregistrée sous la clé info; et vous pouvez voir que l'objet de requête a été enregistré dans
cet exemple.

Intégration avec Zend_Application

Par défaut, les commandes zf.sh et zf.bat ajoute une configuration pour la
ressource 'log' deZend_Application , elle inclut la configuration pour l'objet
d'écriture du journal ZendMonitor. Aussi, le ErrorController utilise ce
journal pour journaliser les exceptions de l'application.

Comme dit précedemment, si l'API de Zend Monitor API n'est pas détectée sur
votre installation de PHP, alors le journal ne fera rien du tout.

2.7. Déraciner les rédacteurs


Le Zend_Log_Writer_Null est une souche qui écrit des données de log nulle part. Il est utile
pour neutraliser le log ou déraciner le log pendant les essais :

$redacteur = new Zend_Log_Writer_Null;


$logger = new Zend_Log($redacteur);

// va nulle part
$logger->info("Message d'information");

2.8. Tester avec un simulacre


Le Zend_Log_Writer_Mock est un rédacteur très simple qui enregistre les données brutes
qu'il reçoit dans un tableau exposé comme propriété publique.

$simulacre = new Zend_Log_Writer_Mock;


$logger = new Zend_Log($simulacre);

$logger->info("Message d'information");

var_dump($mock->events[0]);

// Array
// (
// [timestamp] => 2007-04-06T07:16:37-07:00
// [message] => Message d'information
// [priority] => 6
// [priorityName] => INFO
// )

Pour effacer les événements notés dans le simulacre, il faut simplement réaliser $simulacre-
>events = array().

2.9. Additionner les rédacteurs


Il n'y a aucun objet composite de rédacteurs. Cependant, une instance d'enregistreur peut écrire
vers tout nombre de rédacteurs. Pour faire ceci, employer la méthode addWriter() :

986
Zend_Log

$redacteur1 =
new Zend_Log_Writer_Stream('/chemin/vers/premier/fichierdelog');
$redacteur2 =
new Zend_Log_Writer_Stream('/chemin/vers/second/fichierdelog');

$logger = new Zend_Log();


$logger->addWriter($redacteur1);
$logger->addWriter($redacteur2);

// va dans les 2 rédacteurs


$logger->info("Message d'information");

3. Formateurs (mise en forme)


Un formateur est un objet qui est responsable de prendre un tableau event décrivant un
événement de log et produisant une ligne de log formatée sous la forme d'un une chaîne.

Quelques rédacteurs ("Writers") ne fonctionnent pas en terme de ligne et ne peuvent pas utiliser
un formateur. Un exemple est le rédacteur de base de données, qui insère les items d'événement
directement en colonnes de base de données. Pour les rédacteurs qui ne peuvent pas supporter
un formateur, une exception est levée si vous essayez d'affecter un formateur.

3.1. Formatage simple


Zend_Log_Formatter_Simple est le formateur par défaut. Il est configuré automatiquement
quand vous n'indiquez aucun formateur. La configuration par défaut est équivalente à ce qui suit :

$format = '%timestamp% %priorityName% (%priority%): %message%' . PHP_EOL;


$formatter = new Zend_Log_Formatter_Simple($format);

Un formateur est affecté à un objet individuel de rédacteur en utilisant la méthode


setFormatter() du rédacteur :

$redacteur = new Zend_Log_Writer_Stream('php://output');


$formateur = new Zend_Log_Formatter_Simple('Bonjour %message%' . PHP_EOL);
$redacteur->setFormatter($formateur);

$logger = new Zend_Log();


$logger->addWriter($redacteur);

$logger->info('Monde');

// affiche "Bonjour Monde"

Le constructeur de Zend_Log_Formatter_Simple accepte un paramètre unique : la chaîne


de formatage. Cette chaîne contient des clés entourées par le signe pourcentage (par exemple
%message%). La chaîne de formatage peut contenir n'importe quelle clé du tableau de
données d'événement. Vous pouvez récupérer les clés par défaut en utilisant la constante
DEFAULT_FORMAT de Zend_Log_Formatter_Simple.

3.2. Formater vers le XML


Zend_Log_Formatter_Xml formate des données de log dans des chaînes de type XML. Par
défaut, il note automatiquement tout le tableau de données d'événements :

987
Zend_Log

$redacteur = new Zend_Log_Writer_Stream('php://output');


$formateur = new Zend_Log_Formatter_Xml();
$redacteur->setFormatter($formateur);

$logger = new Zend_Log();


$logger->addWriter($redacteur);

$logger->info("Message d'information");

Le code ci-dessus affiche le XML suivant (des espaces supplémentaires sont ajoutés pour la
clarté) :

<logEntry>
<timestamp>2007-04-06T07:24:37-07:00</timestamp>
<message>Message d'information</message>
<priority>6</priority>
<priorityName>INFO</priorityName>
</logEntry>

Il est possible d'adapter l'élément racine comme indiquent faire correspondre les éléments XML
au tableau de données d'évènements. Le constructeur de Zend_Log_Formatter_Xml accepte
une chaîne avec le nom de l'élément racine comme premier paramètre et un tableau associatif
avec les éléments de correspondance comme deuxième paramètre :

$redacteur = new Zend_Log_Writer_Stream('php://output');


$formateur = new Zend_Log_Formatter_Xml('log',
array('msg' => 'message',
'niveau' => 'priorityName'));
$redacteur->setFormatter($formateur);

$logger = new Zend_Log();


$logger->addWriter($redacteur);

$logger->info("Message d'information");

Le code ci-dessus change l'élément racine par défaut de logEntry en log. Il fait correspondre
également les éléments msg au message de l'item de donnée d'événement. Ceci a comme
conséquence l'affichage suivant :

<log>
<msg>Message d'information</msg>
<niveau>INFO</niveau>
</log>

4. Filtres
Un objet Filter bloque les messages avant l'écriture dans le log.

4.1. Filtrer pour tous les rédacteurs (Writers)


Pour filtrer avant tous les rédacteurs, vous pouvez ajouter autant de filtres que vous souhaitez
à l'objet enregistreur en utilisant la méthode addFilter() :

$logger = new Zend_Log();

988
Zend_Log

$redacteur = new Zend_Log_Writer_Stream('php://output');


$logger->addWriter($redacteur);

$filtre = new Zend_Log_Filter_Priority(Zend_Log::CRIT);


$logger->addFilter($filtre);

// bloqué
$logger->info("Message d'information");

// écrit dans le log


$logger->emerg("Message d'urgence");

Quand vous ajoutez un ou plusieurs filtres à l'objet enregistreur, le message doit passer par tous
les filtres avant que tous les rédacteurs le reçoive.

4.2. Filtrer pour une seule instance de rédacteur


Pour filtrer seulement sur un instance spécifique de rédacteur, employer la méthode addFilter
de ce rédacteur :

$logger = new Zend_Log();

$redacteur1 =
new Zend_Log_Writer_Stream('/chemin/vers/premier/fichierdelog');
$logger->addWriter($redacteur1);

$redacteur2 =
new Zend_Log_Writer_Stream('/chemin/vers/second/fichierdelog');
$logger->addWriter($redacteur2);

// ajoute le filter seulement pour le redacteur2


$filter = new Zend_Log_Filter_Priority(Zend_Log::CRIT);
$redacteur2->addFilter($filter);

// écrit par le redacteur1, bloqué par le redacteur2


$logger->info("Message d'information");

// écrit dans les 2 logs


$logger->emerg("Message d'urgence");

5. Utiliser la fabrique pour créer des logs


En plus de pouvoir instancier les objets directement, il est possible d'utiliser une fabrique, la
méthode factory() d'une instance Log, et il est possible de configurer les objets d'écriture
(writers) et leurs filtres. En utilisant la fabrique, vous pouvez attacher plusieurs objets d'écriture
dont la configuration peut être passée sous forme de tableau ou d'objet Zend_Config.

Un exemple:

$logger = Zend_Log::factory(array(
array(
'writerName' => 'Stream',
'writerParams' => array(
'stream' => '/tmp/zend.log',
),
'filterName' => 'Priority',
'filterParams' => array(

989
Zend_Log

'priority' => Zend_Log::WARN,


),
),
array(
'writerName' => 'Firebug',
'filterName' => 'Priority',
'filterParams' => array(
'priority' => Zend_Log::INFO,
),
),
));

Le code ci-dessus instancie un objet journal et 2 objets d'écriture dont un vers un fichier local,
puis un vers Firebug. Chacun possède un filtre.

Chaque objet d'écriture support les options suivantes:

writerName (requis) Le nom "court" de l'objet d'écriture; le nom sans le préfixe.


Voyez "writerNamespace" pour plus de détails, des exemples
sont : "Mock", "Stream", "Firebug".

writerParams (optionnel) Tableau associatif de paramètre à utiliser à l'instanciation de


l'objet d'écriture. Chaque méthode factory() fera suivre
ces paramètres.

writerNamespace (optionnel) Le préfixe de classe ou espace de nom(namespace) à utiliser


pour créer le nom de classe complet de l'objet d'écriture. Par
défault : "Zend_Log_Writer".

filterName (optionnel) Le nom "court" d'un filtre à utiliser sur l'objet d'écriture.
Voyez "filterNamespace" pour plus de détails. Exemples:
"Message", "Priority".

filterParams (optionnel) Tableau associatif de paramètre à utiliser à l'instanciation de


l'objet filtre. Chaque méthode factory() fera suivre ces
paramètres.

filterNamespace (optionnel) Le préfixe de classe ou espace de nom(namespace) à utiliser


pour créer le nom de classe complet de l'objet filtre. Par
défault : "Zend_Log_Filter".

Chaque objet d'écriture et chaque filtre possède des options.

5.1. Options pour les objets d'écriture


5.1.1. Zend_Log_Writer_Db Options
db Une instance de Zend_Db_Adapter

table Nom de la table à utiliser.

columnMap Tableau associatif de correspondance entre les noms des colonnes de la table et
les champs des évènements du journal.

5.1.2. Zend_Log_Writer_Firebug Options


Aucune option n'est acceptée par cet objet d'écriture.

990
Zend_Log

5.1.3. Zend_Log_Writer_Mail Options


Zend_Log_Writer_Mail actuellement (en 1.10) n'implémente pas la fabrique, et renverra une
exception si vous tentez de l'utiliser via Zend_Log::factory().

5.1.4. Zend_Log_Writer_Mock Options


Aucune option n'est acceptée par cet objet d'écriture.

5.1.5. Zend_Log_Writer_Null Options


Aucune option n'est acceptée par cet objet d'écriture.

5.1.6. Zend_Log_Writer_Stream Options


stream|url Un identifiant de flux PHP valide vers lequel journaliser.

mode Le mode I/O (Lecture/Ecriture) à utiliser; défaut : "a" pour "append".

5.1.7. Zend_Log_Writer_Syslog Options


application Nom de l'application utilisé par le journaliseur syslog.

facility Facility utilisée par le journal syslog.

5.1.8. Zend_Log_Writer_ZendMonitor Options


Aucune option n'est acceptée par cet objet d'écriture.

5.2. Options des filtres


5.2.1. Zend_Log_Filter_Message Options
regexp Expression régulière à faire correspondre par rapport au message du journal.

5.2.2. Zend_Log_Filter_Priority Options


priority La priorité maximale à journaliser.

operator L'opérateur de comparaison (supérieur ou inférieur) à utiliser pour la comparaison,


"<=" est utilisé par défaut.

5.2.3. Zend_Log_Writer_Suppress Options


Aucune option n'est acceptée par cet objet d'écriture.

5.3. Créer des objets d'écriture et des filtres configurés


SI vous souhaitez créer vos propres objets d'écriture du journal, ou vos propres filtres, il est
possible de les rendre compatibles avec Zend_Log::factory() facilement.

Vous devez au minimum implémenter Zend_Log_FactoryInterface, qui attend une


méthode statique factory() accéptant un seul argument, $config, de types tableau ou
instance de Zend_Config. Si vos objets étendent Zend_Log_Writer_Abstract, ou vos
filtres étendent Zend_Log_Filter_Abstract, alors ce sera tout.

991
Zend_Log

Après, définissez la correspondance entre les options de configuration et les arguments du


constructeur. Par exemple :

class My_Log_Writer_Foo extends Zend_Log_Writer_Abstract


{
public function __construct($bar, $baz)
{
// ...
}

public static function factory($config)


{
if ($config instanceof Zend_Config) {
$config = $config->toArray();
}
if (!is_array($config)) {
throw new Exception(
'factory attend un tableau ou un Zend_Config'
);
}

$default = array(
'bar' => null,
'baz' => null,
);
$config = array_merge($default, $config);

return new self(


$config['bar'],
$config['baz']
);
}
}

Aussi, il est possible d'appeler les setters après l'instanciation, mais avant de retourner l'instance:

class My_Log_Writer_Foo extends Zend_Log_Writer_Abstract


{
public function __construct($bar = null, $baz = null)
{
// ...
}

public function setBar($value)


{
// ...
}

public function setBaz($value)


{
// ...
}

public static function factory($config)


{
if ($config instanceof Zend_Config) {
$config = $config->toArray();
}
if (!is_array($config)) {

992
Zend_Log

throw new Exception(


'factory attend un tableau ou un Zend_Config'
);
}

$writer = new self();


if (isset($config['bar'])) {
$writer->setBar($config['bar']);
}
if (isset($config['baz'])) {
$writer->setBaz($config['baz']);
}
return $writer;
}
}

993
Zend_Mail
1. Introduction
1.1. Pour commencer
Zend_Mail fournit des fonctionnalités génériques pour écrire et envoyer des émail au format
texte et MIME. Un émail peut-être envoyé avec Zend_Mail via le transporteur par défaut
Zend_Mail_Transport_Sendmail ou via Zend_Mail_Transport_Smtp.

Exemple 523. Émail simple avec Zend_Mail

Un émail simple est composé d'un destinataire, d'un sujet, d'un message et d'un expéditeur.
Pour envoyer ce genre de messages en utilisant Zend_Mail_Transport_Sendmail,
vous pouvez faire comme ceci :

$mail = new Zend_Mail();


$mail->setBodyText('Ceci est le texte du message.');
$mail->setFrom('somebody@example.com', 'un expéditeur');
$mail->addTo('somebody_else@example.com', 'un destinataire');
$mail->setSubject('Sujet de test');
$mail->send();

Définitions minimales
Pour envoyer un émail avec Zend_Mail, vous devez spécifier au moins un
destinataire, un expéditeur (avec setFrom()), et un message (texte et/ou
HTML).

Pour la plupart des attributs de l'émail, il y a des méthodes "get" pour lire les informations
stockées dans l'objet mail. Pour plus de détails, merci de vous référer à la documentation de
l'API. Une méthode spéciale est getRecipients(). Elle retourne un tableau avec toutes les
adresses émail des destinataires qui ont été ajoutés avant l'appel de cette méthode.

Pour des raisons de sécurité, Zend_Mail filtre tous les champs d'en-tête pour éviter tout
problème d'injection d'en-têtes avec des caractères de nouvelles lignes (\n). Les guillemets
doubles sont changés en guillemets simples et les crochets en parenthèses dans le nom des
émetteurs et des destinataires. Si ces caractères sont dans l'adresse émail, ils sont enlevés.

Vous pouvez aussi utiliser la plupart des méthodes de l'objet Zend_Mail via une interface fluide.

$mail = new Zend_Mail();


$mail->setBodyText('Ceci est le texte du message.')
->setFrom('somebody@example.com', 'un expéditeur')
->addTo('somebody_else@example.com', 'un destinataire')
->setSubject('Sujet de test')
->send();

1.2. Configurer le transport sendmail par défaut


Le transporteur par défaut pour une instance Zend_Mail est
Zend_Mail_Transport_Sendmail. C'est essentiellement un paquet pour la fonction PHP

994
Zend_Mail

mail(). Si vous souhaitez fournir des paramètres additionnels à la fonction mail(), créez
simplement une nouvelle instance du transporteur et fournissez vos paramètres au constructeur.
La nouvelle instance du transporteur peut ainsi devenir le transporteur par défaut Zend_Mail,
ou il peut être fourni à la méthode send() de Zend_Mail.

Exemple 524. Fournir des paramètres additionnels au transporteur


Zend_Mail_Transport_Sendmail

Cet exemple montre comment changer le Return-Path de la fonction mail().

$tr = new Zend_Mail_Transport_Sendmail('-freturn_to_me@example.com');


Zend_Mail::setDefaultTransport($tr);

$mail = new Zend_Mail();


$mail->setBodyText('Ceci est le texte du message.');
$mail->setFrom('somebody@example.com', 'un expéditeur');
$mail->addTo('somebody_else@example.com', 'un destinataire');
$mail->setSubject('TestSubject');
$mail->send();

Restrictions en mode Safe

Les paramètres additionnels optionnels peuvent entraînés un échec de la


fonction mail() si PHP fonctionne en mode safe.

Transport Sendmail et Windows

Comme le spécifie le manuel PHP, la fonction mail() a des comportements


différents sous Windows ou sur les systèmes de type *nix. Utiliser le transport
Sendmail sous Windows ne fonctionnera pas conjointement avec addBcc(). La
fonction mail() enverra vers le destinataire BCC de manière à ce que tous les
destinataires puissent voir qu'il est destinataire !

Ainsi si vous voulez utiliser BCC sur un serveur Windows, utilisez le transport
SMTP pour l'envoi !

2. Envoyer des émail en utilisant SMTP


Pour envoyer des émail via SMTP, Zend_Mail_Transport_Smtp a besoin d'être créé et
enregistré avant que la méthode soit appelée. Pour tout appel de Zend_Mail::send() dans
le script en cours, le transport SMTP sera utilisé :

Exemple 525. Envoyer un émail via SMTP

$tr = new Zend_Mail_Transport_Smtp('mail.example.com');


Zend_Mail::setDefaultTransport($tr);

La méthode setDefaultTransport() et le constructeur de Zend_Mail_Transport_Smtp


ne sont pas coûteux en terme de performances. Ces deux lignes peuvent être traitées lors
de l'initialisation du script (par exemple dans un fichier config.inc) pour configurer le
comportement de la classe Zend_Mail pour le reste du script. Cela garde les informations de
configuration en dehors de la logique applicative - si les émail doivent être envoyés via SMTP
ou via mail(), quel serveur est utilisé, etc.

995
Zend_Mail

3. Envoyer plusieurs émail par connexion SMTP


Par défaut un transport SMTP unique crée une connexion unique et la réutilise pour toute la
durée de la vie du script. Vous pouvez envoyer plusieurs émail à travers cette connexion SMTP.
Une commande RSET doit être envoyée avant chaque distribution pour garantir que le dialogue
SMTP correct est respecté.

Optionally, you can also define a default From email address and name, as well as a default
reply-to header. This can be done through the static methods setDefaultFrom() and
setDefaultReplyTo(). These defaults will be used when you don't specify a From/Reply-
to Address or -Name until the defaults are reset (cleared). Resetting the defaults can be done
through the use of the clearDefaultFrom() and clearDefaultReplyTo.

Exemple 526. Envoyer plusieurs émail par connexion SMTP

// Créer un transport
$config = array('name' => 'sender.example.com');
$transport = new Zend_Mail_Transport_Smtp('mail.example.com', $config);

// Ajouter les nom et adresses "From" & "Reply-To" pour tous les émails
// à envoyer
Zend_Mail::setDefaultFrom('sender@example.com', 'John Doe');
Zend_Mail::setDefaultReplyTo('replyto@example.com','Jane Doe');

// Boucle à travers les messages


for ($i = 0; $i < 5; $i++) {
$mail = new Zend_Mail();
$mail->addTo('studio@example.com', 'Test');
$mail->setSubject(
'Démonstration - Envoyer plusieurs emails par connexion SMTP'
);
$mail->setBodyText('...Votre message ici...');
$mail->send($transport);
}

// Effacer les valeurs par défaut


Zend_Mail::clearDefaultFrom();
Zend_Mail::clearDefaultReplyTo();

Si vous voulez avoir une connexion SMTP séparée pour chaque distribution d'émail, vous devez
créer et détruire votre transport avant et après chaque appel de la méthode send(). Ou sinon,
vous pouvez manipuler la connexion entre chaque distribution en accédant à l'objet de protocole
de transport.

996
Zend_Mail

Exemple 527. Contrôler manuellement la connexion de transport

// Créer un transport
$transport = new Zend_Mail_Transport_Smtp();

$protocol = new Zend_Mail_Protocol_Smtp('mail.example.com');


$protocol->connect();
$protocol->helo('sender.example.com');

$transport->setConnection($protocol);

// Boucle à travers les messages


for ($i = 0; $i < 5; $i++) {
$mail = new Zend_Mail();
$mail->addTo('studio@example.com', 'Test');
$mail->setFrom('studio@example.com', 'Test');
$mail->setSubject(
'Démonstration - Envoyer plusieurs emails par connexion SMTP'
);
$mail->setBodyText('...Votre message ici...');

// Contrôler manuellement la connexion


$protocol->rset();
$mail->send($transport);
}

$protocol->quit();
$protocol->disconnect();

4. Utiliser différents transports


Au cas où vous voudriez envoyer différent émail via des connexions différentes, vous
pouvez aussi passer l'objet de transport directement à send() sans être obligé d'appeler
setDefaultTransport() avant. L'objet passé va être prioritaire sur le transport par défaut
pour la requête send() courante.

Exemple 528. Utiliser différents transports

$mail = new Zend_Mail();


// construction du message
$tr1 = new Zend_Mail_Transport_Smtp('serveur@exemple.com');
$tr2 = new Zend_Mail_Transport_Smtp('autre_serveur@exemple.com');
$mail->send($tr1);
$mail->send($tr2);
$mail->send(); // utilisation du transport par défaut

Transports additionnels

Des transports additionnels peuvent-être écrit en implémentant


Zend_Mail_Transport_Interface.

5. Émail HTML
Pour envoyer un émail au format HTML, définissez le corps du message en utilisant la
méthode setBodyHTML() à la place de setBodyText(). Le type de contenu MIME sera

997
Zend_Mail

automatiquement définit à text/html. Si vous utilisez les formats textes et HTML, un message
MIME de type multipart/alternative sera automatiquement généré :

Exemple 529. Envoyer des émail HTML

$mail = new Zend_Mail();


$mail->setBodyText('Mon texte de test');
$mail->setBodyHtml('Mon texte de test');
$mail->setFrom('somebody@exemple.com', 'Un expéditeur');
$mail->addTo('somebody_else@exemple.com', 'Un destinataire');
$mail->setSubject('Sujet de test');
$mail->send();

6. Fichiers joints
Des fichiers peuvent-être attachés à un émail en utilisant la méthode createAttachment().
Le comportement par défaut de Zend_Mail est de définir que le fichier joint est un objet
binaire (application/octet-stream), qui devra être transféré avec un encodage de type base64,
et est définit comme une pièce jointe. Ce comportement peut être redéfinit en passant plus de
paramètres à createAttachment() :

Exemple 530. Émail avec fichiers joints

$mail = new Zend_Mail();


// construction du message
$mail->createAttachment($uneChaineBinaire);
$mail->createAttachment($monImage,
'image/gif',
Zend_Mime::DISPOSITION_INLINE,
Zend_Mime::ENCODING_8BIT);

Si vous voulez contrôler la partie MIME générée pour un fichier joint, vous pouvez utiliser
la valeur retournée de createAttachment() pour modifier ses attributs. La méthodes
createAttachment() retourne un objet de type Zend_Mime_Part :

$mail = new Zend_Mail();

$at = $mail->createAttachment($monImage);
$at->type = 'image/gif';
$at->disposition = Zend_Mime::DISPOSITION_INLINE;
$at->encoding = Zend_Mime::ENCODING_8BIT;
$at->filename = 'test.gif';

$mail->send();

Une façon alternative est de créer une instance de Zend_Mime_Part et de l'ajouter avec la
méthode addAttachment() :

$mail = new Zend_Mail();

$at = new Zend_Mime_Part($monImage);


$at->type = 'image/gif';
$at->disposition = Zend_Mime::DISPOSITION_INLINE;
$at->encoding = Zend_Mime::ENCODING_8BIT;
$at->filename = 'test.gif';

998
Zend_Mail

$mail->addAttachment($at);

$mail->send();

7. Ajouter des destinataires


Des destinataires peuvent être ajouter de trois façons :

• addTo(): Ajoute un destinataire à l'émail grâce à un en-tête "To"

• addCc(): Ajoute un destinataire à l'émail grâce à un en-tête "Cc"

• addBcc(): Ajoute un destinataire non-visible dans les en-têtes de l'émail

getRecipients() récupère la liste des destinataires. clearRecipients() efface la liste.

Paramètres additionnels
addTo() et addCc() acceptent un second paramètre optionnel, qui est utilisé
comme un nom de destinataire humainement lisible. Le guillemet double est
changé en simple guillemet et les crochets en parenthèses dans le paramètre.

Utilisation optionnelle
Ces trois méthodes peuvent aussi accepter un tableau d'adresses émails plutôt
que de les ajouter une par une. Dans le cas de addTo() et addCc(), il peut
s'agir de tableaux associatifs où la clé est un nom de destinataire humainement
lisible.

8. Contrôler les limites MIME


Dans un message en plusieurs parties, une limite MIME est normalement générée
aléatoirement pour séparer les différentes parties du message. Cependant dans le cas où
vous souhaiteriez spécifier vous-même la limite MIME utilisée, vous pouvez appeler la méthode
setMimeBoundary(), comme le montre l'exemple suivant :

Exemple 531. Changer la limite MIME

$mail = new Zend_Mail();


$mail->setMimeBoundary('=_' . md5(microtime(1) . $someId++));
// construction du message...

9. En-têtes additionnels
Zend_Mail provides several methods to set additional Mail Headers:

• setReplyTo($email, $name=null): sets the Reply-To: header.

• setDate($date = null): sets the Date: header. This method uses current time stamp by
default. Or You can pass time stamp, date string or Zend_Date instance to this method.

• setMessageId($id = true): sets the Message-Id: header. This method can generate
message ID automatically by default. Or You can pass your message ID string to this method.
This method call createMessageId() internally.

999
Zend_Mail

Return-Path
If you set Return-Path on your mail, see Configuring sendmail transport.
Unfortunately, setReturnPath($email) method does not perform this
purpose.

Des en-têtes arbitraires peuvent être définis en utilisant la méthode addHeader(). Elle a besoin
de deux paramètres contenant le nom et la valeur du champ d'en-tête. Un troisième paramètre
optionnel détermine si l'en-tête doit avoir une ou plusieurs valeurs :

Exemple 532. Ajouter des en-têtes à l'émail

$mail = new Zend_Mail();


$mail->addHeader('X-MailGenerator', 'MaSuperApplication');
$mail->addHeader('X-greetingsTo', 'Maman', true); // plusieurs valeurs
$mail->addHeader('X-greetingsTo', 'Papa', true);

10. Jeux de caractères


Zend_Mail ne recherche pas le jeu de caractères des parties de l'émail. Lorsque vous
instanciez Zend_Mail, un jeu de caractères pour l'émail peut être fournit. La valeur par défaut
est iso-8859-1. L'application doit vérifier que toutes les parties ajoutées à cet émail ont leurs
contenus encodés avec le bon jeu de caractères. Lors de la création d'une nouvelle partie de
l'émail, un jeu de caractères différent peut-être définit pour chaque partie.

Seulement au format texte


Les jeux de caractères ne s'appliquent que pour les parties du message au format
texte.

Exemple 533. Usage in CJK languages

The following example is how to use Zend_Mail in Japanese. This is one of CJK (aka
CJKV ) languages. If you use Chinese, you may use HZ-GB-2312 instead of ISO-2022-JP.

//We suppose that character encoding of strings is UTF-8 on PHP script.


function myConvert($string) {
return mb_convert_encoding($string, 'ISO-2022-JP', 'UTF-8');
}

$mail = new Zend_Mail('ISO-2022-JP');


//In this case, You can use ENCODING_7BIT because the ISO-2022-JP does not use MSB.
$mail->setBodyText(myConvert('This is the text of the mail.'), null, Zend_Mime::ENCODING
$mail->setHeaderEncoding(Zend_Mime::ENCODING_BASE64);
$mail->setFrom('somebody@example.com', myConvert('Some Sender'));
$mail->addTo('somebody_else@example.com', myConvert('Some Recipient'));
$mail->setSubject(myConvert('TestSubject'));
$mail->send();

11. Encodage
Par défaut, le corps des messages textes et HTML est encodé via le mécanisme "quoted-
printable". Les en-têtes du message sont aussi encodés avec le mécanisme "quoted-printable"
si vous ne spécifiez pas base64 avec setHeaderEncoding(). Si vous utilisez une langue
qui n'est pas sur des lettres de type romaines, la base64 sera plus convenable. Tous les
fichiers joints sont encodés via base64 si aucun autre encodage n'est spécifié lors de l'appel à

1000
Zend_Mail

addAttachment() ou assigné plus tard à la partie MIME de l'objet. Les encodages 7Bit et 8Bit
ne se font pour l'instant que sur les données binaires.

L'encodage des en-têtes, spécialement l'encodage du sujet, est toujours délicat. Zend_Mime
implémente actuellement son propre algorithme pour encoder les en-têtes "quoted-printable"
suivant la RFC-2045. Ceci est du à un problème des fonctions iconv_mime_encode et
mb_encode_mimeheader avec certaines tables de caractères. Cet algorithme ne coupe les en-
têtes qu'au niveau des espaces, ce qui peut entraîner des problèmes quand la longueur excède
la longueur de 76 caractères. Dans ce cas, il est suggéré de basculer en encodage BASE64
pour les en-têtes comme décrit dans les exemples suivants :

// Par défaut Zend_Mime::ENCODING_QUOTEDPRINTABLE


$mail = new Zend_Mail('KOI8-R');

// Bascule en encodage Base64 parce que le Russe exprimé en KOI8-R est


// considérablement différent des langues basées sur des lettres romaines
$mail->setHeaderEncoding(Zend_Mime::ENCODING_BASE64);

Zend_Mail_Transport_Smtp encode les lignes commençant par un ou deux points, ainsi


l'émail ne viole pas le protocole SMTP.

12. Authentification SMTP


Zend_Mail supporte l'utilisation de l'authentification SMTP, qui peut être activé
en passant le paramètre "auth" au tableau de configuration du constructeur de
Zend_Mail_Transport_Smtp. Les méthodes d'authentification intégrées disponibles sont
PLAIN, LOGIC et CRAM-MD5 qui ont tous besoins des valeurs "username" et "password" dans
le tableau de configuration.

Exemple 534. Activer l'authentification dans Zend_Mail_Transport_Smtp

$config = array('auth' => 'login',


'username' => 'myusername',
'password' => 'password');

$transport = new Zend_Mail_Transport_Smtp('mail.server.com', $config);

$mail = new Zend_Mail();


$mail->setBodyText('Ceci est le texte de l\'email.');
$mail->setFrom('emetteur@test.com', 'Un émetteur');
$mail->addTo('destinataire@test.com', 'Un destinataire');
$mail->setSubject('Sujet de test');
$mail->send($transport);

Type d'authentification
Le type d'authentification est sensible à la casse mais ne contient pas de
ponctuation. Par exemple, pour utiliser CRAM-MD5 vous devez passer 'auth'
=> 'crammd5' dans le constructeur de Zend_Mail_Transport_Smtp.

13. Sécuriser les transports SMTP


Zend_Mail supporte aussi l'utilisation des connexions SMTP sécurisées via TLSS ou SSL. Ceci
peut être activé en passant le paramètre "ssl" ou "tls" au tableau de configuration du constructeur
de Zend_Mail_Transport_Smtp. Un port peut optionnellement être fourni, sinon il vaut par
défaut 25 pour TLS et 465 pour SSL.

1001
Zend_Mail

Exemple 535. Activer une connexion sécurisée dans Zend_Mail_Transport_Smtp

$config = array('ssl' => 'tls',


'port' => 25); // Port optionel fourni

$transport = new Zend_Mail_Transport_Smtp('mail.server.com', $config);

$mail = new Zend_Mail();


$mail->setBodyText('Ceci est le texte de l\'email.');
$mail->setFrom('emetteur@test.com', 'Un émetteur');
$mail->addTo('destinataire@test.com', 'Un destinataire');
$mail->setSubject('Sujet de test');
$mail->send($transport);

14. Lire des émail


Zend_Mail peut lire des émail provenant de différents stockages locaux ou distants. Tous
bénéficient de la même API pour compter et extraire les messages, certains implémentent des
interfaces additionnelles pour des fonctionnalités moins communes. Pour une vue d'ensemble
des fonctionnalités des stockages implémentés voir la table suivante.

Tableau 101. Vue d'ensemble des fonctionnalités de lecture d'émail


Fonctionnalité Mbox Maildir Pop3 IMAP
Type de stockage local local distant distant
Extraction des Oui Oui Oui Oui
messages
Extraction des émulé émulé émulé émulé
parties mimes
Dossiers Oui Oui Non Oui
Créer des Non A faire Non A faire
messages/
dossiers
Flags Non Oui Non Oui
Quota Non Oui Non Non

14.1. Exemple simple avec Pop3


$mail = new Zend_Mail_Storage_Pop3(array('host' => 'localhost',
'user' => 'test',
'password' => 'test'));

echo $mail->countMessages() . " messages trouvés\n";


foreach ($mail as $message) {
echo "Mail from '{$message->from}': {$message->subject}\n";
}

14.2. Ouvrir un stockage local


Mbox et Maildir sont les deux formats supportés pour le stockage local des émail, tous les deux
dans leurs formats le plus simple.

Si vous voulez lire un fichier Mbox, vous devez juste donner le nom du fichier au constructeur
de Zend_Mail_Storage_Mbox:

1002
Zend_Mail

$mail =
new Zend_Mail_Storage_Mbox(array('filename' => '/home/test/mail/inbox'));

Maildir est très similaire mais nécessite un nom de dossier :

$mail =
new Zend_Mail_Storage_Maildir(array('dirname' => '/home/test/mail/'));

Ces deux constructeurs lèvent une exception Zend_Mail_Exception si le stockage ne peut


pas être lu.

14.3. Ouvrir un stockage distant


Pour les stockages distants les deux protocoles les plus populaires sont supportés : Pop3 et
Imap. Les deux nécessitent au moins un hôte et un utilisateur pour se connecter et s'identifier.
Le mot de passe par défaut est une chaîne vide et le port par défaut celui donné dans la RFC
du protocole.

// connexion à Pop3
$mail = new Zend_Mail_Storage_Pop3(array('host' => 'exemple.com'
'user' => 'test',
'password' => 'test'));

// connexion à Imap
$mail = new Zend_Mail_Storage_Imap(array('host' => 'exemple.com'
'user' => 'test',
'password' => 'test'));

// exemple à un port non standard


$mail = new Zend_Mail_Storage_Pop3(array('host' => 'exemple.com',
'port' => 1120
'user' => 'test',
'password' => 'test'));

Pour ces deux stockages SSL et TLS sont supportés. Si vous utilisez SSL le port par défaut
change comme indiqué dans la RFC.

// exemples pour Zend_Mail_Storage_Pop3,


// identique à Zend_Mail_Storage_Imap

// utiliser SSL avec un port différent


// (par défaut 995 pour Pop3 et 993 pour Imap)
$mail = new Zend_Mail_Storage_Pop3(array('host' => 'exemple.com'
'user' => 'test',
'password' => 'test',
'ssl' => 'SSL'));

// utiliser TLS
$mail = new Zend_Mail_Storage_Pop3(array('host' => 'exemple.com'
'user' => 'test',
'password' => 'test',
'ssl' => 'TLS'));

Les deux constructeurs peuvent lever une exception Zend_Mail_Exception ou


Zend_Mail_Protocol_Exception(étendant Zend_Mail_Exception), en fonction du type
de l'erreur.

1003
Zend_Mail

14.4. Extraire des messages et autres méthodes simples


Dès que vous avez ouvert l'accès, les messages peuvent être extraits. Vous devez fournir un
numéro de message, qui est un compteur qui démarre à 1 pour le premier message. Pour extraire
le message vous utilisez la méthode getMessage() :

$message = $mail->getMessage($numeroDeMessage);

L'accès sous forme de tableau est aussi supporté, mais cet méthode d'accès ne supporte pas les
paramètres additionnels qui aurait pu être ajouté à getMessage(). Tant que vous n'en n'avez
pas besoin et que vous pouvez vivre avec les valeurs par défaut, vous pouvez utiliser :

$message = $mail[$numeroDeMessage];

Pour itérer tous les messages, l'interface Iterator est implémentée :

foreach ($mail as $numeroDeMessage => $message) {


// faire qqch ...
}

Pour compter les messages dans le stockage, vous pouvez soit utiliser la méthode
countMessages() ou utiliser l'accès de type tableau :

// par méthode
$maxMessage = $mail->countMessages();

// type tableau
$maxMessage = count($mail);

Pour supprimer un mail vous pouvez utiliser la méthode removeMessage() ou l'accès de type
tableau :

// méthode
$mail->removeMessage($numeroDeMessage);

// type tableau
unset($mail[$messageNum]);

14.5. Travailler avec les messages


Après avoir extrait les messages avec getMessage() vous voulez extraire les en-têtes, le
contenu ou une partie d'un message multipart. Tous les en-têtes peuvent être accédés via les
propriétés ou la méthode getHeader() si vous voulez plus de contrôle ou avoir accès à des en-
têtes peu communs. Les noms des en-têtes gérés en interne avec une casse minuscule, ainsi la
casse du nom de l'en-tête importe peu. En outre les en-têtes avec un tiret-bas peuvent être écrit
avec la notation Camel. Si aucun en-tête n'est trouvé pour les deux notations, une exception est
levée. Pour éviter ceci, la méthode headerExists() peut être utilisée pour vérifier l'existence
d'un en-tête.

// récupérer l'objet message


$message = $mail->getMessage(1);

// afficher le sujet du message


echo $message->subject . "\n";

// récupérer l'en-tête content-type

1004
Zend_Mail

$type = $message->contentType;

// vérifier si CC est spécifié :


if( isset($message->cc) ) { // ou $message->headerExists('cc');
$cc = $message->cc;
}

Si vous avez plusieurs en-têtes avec le même nom, par exemple les en-têtes "Received", vous
pourriez les vouloir sous la forme d'un tableau plutôt qu'en tant que chaîne. Ceci est possible
avec la méthode getHeader().

// récupérer l'en-tête comme une propriété - le résultat est toujours


// une chaîne, avec de nouvelles lignes entre chaque occurence
// dans le message
$received = $message->received;

// la même chose avec la méthode getHeader()


$received = $message->getHeader('received', 'string');

// ou mieux un tableau avec une entrée pour chaque occurence


$received = $message->getHeader('received', 'array');
foreach ($received as $line) {
// faire qqch
}

// si vous ne définissez pas de format vous récupérerez la représentation


// interne (chaîne pour en-têtes uniques, tableau pour en-têtes multiples
$received = $message->getHeader('received');
if (is_string($received)) {
// seulement un en-tête received trouvé dans le message
}

La méthode getHeaders() retourne tous les headers sous forme de tableau avec des clés en
minuscules et des valeurs en tant que tableau pour des en-têtes multiples ou une chaîne pour
des en-têtes uniques.

// récupère tous les en-têtes


foreach ($message->getHeaders() as $name => $value) {
if (is_string($value)) {
echo "$name: $value\n";
continue;
}
foreach ($value as $entry) {
echo "$name: $entry\n";
}
}

Si vous n'avez pas de message de type multipart, extraire le contenu est facilité avec
getContent(). A la différence des en-têtes, le contenu est seulement extrait en cas de besoin
(alias late-fetch).

// affiche le contenu du message


echo '<pre>';
echo $message->getContent();
echo '</pre>';

Vérifier si un message est de type multipart est réalisé avec la méthode isMultipart().
Si vous avez un message de type multipart vous pouvez récupérer une instance de

1005
Zend_Mail

Zend_Mail_Part avec la méthode getPart(). Zend_Mail_Part est la classe de


base de Zend_Mail_Message, donc vous avez les mêmes méthodes : getHeader(),
getHeaders(), getContent(), getPart(), isMultipart et les propriétés pour les en-
têtes.

// récupérer la première partie non-multipart


$part = $message;
while ($part->isMultipart()) {
$part = $message->getPart(1);
}
echo 'Le type de cette partie est '
. strtok($part->contentType, ';')
. "\n";
echo "Contenu :\n";
echo $part->getContent();

Zend_Mail_Part implémente aussi RecursiveIterator, qui rend facile le scan de


toutes les parties. Et pour un affichage facile, il implémente de plus la méthode magique
__toString() qui retourne le contenu.

// affiche la première partie de type text/plain=


$foundPart = null;
foreach (new RecursiveIteratorIterator($mail->getMessage(1)) as $part) {
try {
if (strtok($part->contentType, ';') == 'text/plain') {
$foundPart = $part;
break;
}
} catch (Zend_Mail_Exception $e) {
// ignore
}
}
if (!$foundPart) {
echo 'Aucune partie "plain text" trouvés';
} else {
echo "Partie \"plain text\" : \n" . $foundPart;
}

14.6. Vérifier les drapeaux ("flags")


Maildir et IMAP supporte l'enregistrement de drapeaux. La classe Zend_Mail_Storage
possède des constantes pour tous les drapeaux maildir et IMAP connus,
nommés Zend_Mail_Storage::FLAG_<nomdudrapeau>. Pour vérifier les drapeaux
Zend_Mail_Message possède une méthode hasFlag(). Avec getFlags() vous récupérez
tous les drapeaux existants.

// trouvé les messages non lus


echo "Emails non lus :\n";
foreach ($mail as $message) {
if ($message->hasFlag(Zend_Mail_Storage::FLAG_SEEN)) {
continue;
}
// marque les emails récents/nouveaux
if ($message->hasFlag(Zend_Mail_Storage::FLAG_RECENT)) {
echo '! ';
} else {
echo ' ';
}

1006
Zend_Mail

echo $message->subject . "\n";


}

// vérifie les drapeaux connus


$flags = $message->getFlags();
echo "Le message est marqué comme : ";
foreach ($flags as $flag) {
switch ($flag) {
case Zend_Mail_Storage::FLAG_ANSWERED:
echo 'Réponse ';
break;
case Zend_Mail_Storage::FLAG_FLAGGED:
echo 'Marqués ';
break;

// ...
// vérifie d'autres drapeaux
// ...

default:
echo $flag . '(drapeau inconnu) ';
}
}

Comme IMAP autorise les drapeaux définis par client ou l'utilisateur, vous pouvez obtenir ces
drapeaux même s'ils n'ont pas de constante dans Zend_Mail_Storage. Au lieu de cela ils sont
retournés comme une chaîne et peuvent être vérifiés de la même manière avec hasFlag().

// Vérifie le message avec les drapeaux $EstUnSpam, $SpamTeste


if (!$message->hasFlag('$SpamTeste')) {
echo 'ce message n\'est pas considéré comme un spam';
} else if ($message->hasFlag('$EstUnSpam')) {
echo 'ce message est un spam';
} else {
echo 'ce message est sûr';
}

14.7. Utiliser les dossiers


Tous les stockages, excepté Pop3, supportent les dossiers, également appelés boîtes aux
lettres. L'interface implémentée par tous les stockages supportant les dossiers s'appelle
Zend_Mail_Storage_Folder_Interface. En outre toutes ces classes ont un paramètre
facultatif additionnel appelé folder, qui est le dossier choisi après ouverture, dans le
constructeur.

Pour les stockages locaux vous devez employer les classes séparées appelées
Zend_Mail_Storage_Folder_Mbox ou Zend_Mail_Storage_Folder_Maildir. Tous
les deux ont besoin d'un paramètre nommé dirname avec le nom du dossier de base. Le format
pour le maildir est comme définie dans maildir++ (avec un point comme délimiteur par défaut),
Mbox est une hiérarchie de dossiers avec des fichiers Mbox. Si vous n'avez pas un dossier de
Mbox appelé INBOX dans votre dossier de base Mbox vous devez placer un autre dossier dans
le constructeur.

Zend_Mail_Storage_Imap supporte déjà des dossiers par défaut. Exemples pour ouvrir ces
stockages :

// mbox avec dossiers

1007
Zend_Mail

$mail = new Zend_Mail_Storage_Folder_Mbox(


array('dirname' => '/home/test/mail/')
);

// mbox avec un dossier par défaut nommé INBOX, fontionne aussi


// avec Zend_Mail_Storage_Folder_Maildir et Zend_Mail_Storage_Imap
$mail = new Zend_Mail_Storage_Folder_Mbox(
array('dirname' => '/home/test/mail/', 'folder' => 'Archive')
);

// maildir avec dossiers


$mail = new Zend_Mail_Storage_Folder_Maildir(
array('dirname' => '/home/test/mail/')
);

// maildir avec deux-points comme délimiteur,


// comme suggéré dans Maildir++
$mail = new Zend_Mail_Storage_Folder_Maildir(
array('dirname' => '/home/test/mail/', 'delim' => ':')
);

// imap est le même avec ou sans dossier


$mail = new Zend_Mail_Storage_Imap(array('host' => 'example.com',
'user' => 'test',
'password' => 'test'));

Avec la méthode getFolders($root = null) vous pouvez obtenir la hiérarchie des


dossiers en commençant par le dossier racine ou le dossier fourni. Elle est retournée comme
instance de Zend_Mail_Storage_Folder, qui implémente RecursiveIterator et tous
ses enfants sont également des instances de Zend_Mail_Storage_Folder. Chacune de
ces instances à des noms locaux et globaux retournés par les méthodes getLocalName() et
getGlobalName(). Le nom global est le nom absolu du dossier racine (délimiteurs y compris),
le nom local est le nom dans le dossier parent.

Tableau 102. Noms de dossiers


Nom global Nom local
/INBOX INBOX
/Archive/2005 2005
List.ZF.General General

Si vous employez l'itérateur, la clé de l'élément courant est le nom local. Le nom global est
également retourné par la méthode magique __toString(). Quelques dossiers peuvent ne
pas être sélectionnables, ce qui veut dire qu'ils ne peuvent pas stocker des messages et les
choisir entraînerait une erreur. Ceci peut être vérifié avec la méthode isSelectable(). Ainsi
il est très facile de produire l'arbre entier dans une vue :

$folders = new RecursiveIteratorIterator(


$this->mail->getFolders(),
RecursiveIteratorIterator::SELF_FIRST
);
echo '<select name="folder">';
foreach ($folders as $localName => $folder) {
$localName = str_pad('', $folders->getDepth(), '-', STR_PAD_LEFT)
. $localName;
echo '<option';
if (!$folder->isSelectable()) {

1008
Zend_Mail

echo ' disabled="disabled"';


}
echo ' value="' . htmlspecialchars($folder) . '">'
. htmlspecialchars($localName) . '</option>';
}
echo '</select>';

Les dossiers choisis courants sont retournés par la méthode getSelectedFolder(). Changer
de dossier est fait avec la méthode selectFolder(), qui a besoin du nom global comme
paramètre. Si vous voulez éviter d'écrire des délimiteurs vous pouvez également employer les
propriétés d'une instance de Zend_Mail_Storage_Folder :

// selon votre stockage et ses réglages $rootFolder->Archive->2005


// est la même chose que :
// /Archive/2005
// Archive:2005
// INBOX.Archive.2005
// ...
$folder = $mail->getFolders()->Archive->2005;
echo 'Le précédent dossier était '
. $mail->getSelectedFolder()
. "Le nouveau dossier est $folder\n";
$mail->selectFolder($folder);

14.8. Utilisation avancée


14.8.1. Utiliser NOOP
Si vous employez un stockage distant et avez une longue tâche vous pourriez devoir maintenir
la connexion persistante par l'intermédiaire du noop :

foreach ($mail as $message) {

// faire qqch...

$mail->noop(); // maintient la connexion

// faire autre chose...

$mail->noop(); // maintient la connexion


}

14.8.2. Mettre en cache des instances


Zend_Mail_Storage_Mbox, Zend_Mail_Storage_Folder_Mbox,
Zend_Mail_Storage_Maildir et Zend_Mail_Storage_Folder_Maildir implémentant
les méthodes magiques __sleep() et __wakeup(), ce qui veut dire qu'ils sont sérialisable.
Ceci évite d'analyser les dossiers ou l'arbre des dossiers plus d'une fois. L'inconvénient est que
votre stockage de Mbox ou de Maildir ne doit pas changer. Quelques contrôles faciles sont
faits, comme ré-analyser le dossier courant de Mbox si le temps de modification change ou ré-
analysé la structure du dossier si un dossier a disparu (ce qui a toujours comme conséquence
une erreur, mais vous pouvez rechercher un autre dossier après). Il est meilleur si vous avez
quelque chose comme un fichier de signal pour des changements et la vérifiez avant d'employer
l'instance caché.

// il n'y a pas de gestionnaire spécifique de cache utilisé ici,


// changer le code pour utiliser votre gestionnaire de cache

1009
Zend_Mail

$signal_file = '/home/test/.mail.last_change';
$mbox_basedir = '/home/test/mail/';
$cache_id = 'exemple de mail en cache ' . $mbox_basedir . $signal_file;

$cache = new Your_Cache_Class();


if (!$cache->isCached($cache_id) ||
filemtime($signal_file) > $cache->getMTime($cache_id)) {
$mail = new Zend_Mail_Storage_Folder_Pop3(
array('dirname' => $mbox_basedir)
);
} else {
$mail = $cache->get($cache_id);
}

// faire qqch ...

$cache->set($cache_id, $mail);

14.8.3. Étendre les classes de protocoles


Les stockages distants utilisent deux classes : Zend_Mail_Storage_<NOM> et
Zend_Mail_Protocol_<NOM>. La classe de protocole traduit les commandes et les réponses
de protocole et issu de ou pour PHP, comme des méthodes pour les commandes ou les variables
avec différentes structures pour les données. L'autre/classe principale met en application
l'interface commune.

Si vous avez besoin de fonctionnalités additionnelles de protocole vous pouvez étendre la classe
de protocole et l'employer dans le constructeur de la classe principale. Supposer par exemple
que nous devons joindre différents ports avant que nous puissions nous relier à POP3.

Zend_Loader::loadClass('Zend_Mail_Storage_Pop3');

class Example_Mail_Exception extends Zend_Mail_Exception


{}

class Example_Mail_Protocol_Exception extends Zend_Mail_Protocol_Exception


{}

class Example_Mail_Protocol_Pop3_Knock extends Zend_Mail_Protocol_Pop3


{
private $host, $port;

public function __construct($host, $port = null)


{
// pas d'auto-connexion dans cette classe
$this->host = $host;
$this->port = $port;
}

public function knock($port)


{
$sock = @fsockopen($this->host, $port);
if ($sock) {
fclose($sock);
}
}

public function connect($host = null, $port = null, $ssl = false)


{

1010
Zend_Mail

if ($host === null) {


$host = $this->host;
}
if ($port === null) {
$port = $this->port;
}
parent::connect($host, $port);
}
}

class Example_Mail_Pop3_Knock extends Zend_Mail_Storage_Pop3


{
public function __construct(array $params)
{
// ... vérifier les $params ici ! ...
$protocol =
new Example_Mail_Protocol_Pop3_Knock($params['host']);

// faire votre fonction "spéciale"


foreach ((array)$params['knock_ports'] as $port) {
$protocol->knock($port);
}

// récupérer l'état coorect


$protocol->connect($params['host'], $params['port']);
$protocol->login($params['user'], $params['password']);

// initialise le parent
parent::__construct($protocol);
}
}

$mail = new Example_Mail_Pop3_Knock(


array('host' => 'localhost',
'user' => 'test',
'password' => 'test',
'knock_ports' => array(1101,
1105,
1111))
);

Comme vous voyez nous supposons toujours que nous sommes reliés, identifiés et, si supporté,
un dossier est choisi dans le constructeur de la classe principale. Ainsi si vous assignez votre
propre classe de protocole vous devez toujours vous assurer que c'est fait ou la prochaine
méthode échouera si le serveur ne la permet pas dans l'état actuel.

14.8.4. Utilisation des Quotas (avant 1.5)


Zend_Mail_Storage_Writable_Maildir supporte les quotas Maildir++. Ceci est désactivé
par défaut, mais il est possible de l'utiliser manuellement, si la vérification automatique n'est pas
souhaitée (ce qui veut dire que appendMessage(), removeMessage() et copyMessage()
ne vérifie pas et n'ajoute pas d'entrée dans le fichier de contrôle de la taille du dossier de mails).
Si vous l'activez une exception sera levée si vous tentez d'écrire dans le dossier de mails et qu'il
a déjà atteint son quota.

Il existe trois méthodes pour les quotas : getQuota(), setQuota() et checkQuota():

$mail = new Zend_Mail_Storage_Writable_Maildir(

1011
Zend_Mail

array('dirname' => '/home/test/mail/')


);
$mail->setQuota(true); // true pour activer, false pour désactiver
echo 'La vérification du quota est maintenant ',
$mail->getQuota() ? 'active' : 'inactive',
"\n";
// la vérification du quota peut être utilisée
// si celle-ci est désactivée
echo 'Vous êtes ',
$mail->checkQuota() ? 'hors quota' : 'dans le quota',
"\n";

checkQuota() peut aussi retournée une réponse plus détaillée :

$quota = $mail->checkQuota(true);
echo 'Vous êtes ',
$quota['over_quota'] ? 'hors quota' : 'dans le quota',
"\n";
echo 'Vous avez ',
$quota['count'],
' de ',
$quota['quota']['count'],
' messages et vous utilisez ';
echo $quota['size'], ' de ', $quota['quota']['size'], ' octets';

Si vous voulez spécifier votre propre quota plutôt que d'utiliser celui spécifié dans le fichier de
contrôle de la taille du dossier de mails, vous pouvez le faire avec setQuota() :

// le nombre de messages et la taille en octet sont supportés,


// l'ordre est important
$quota = $mail->setQuota(array('size' => 10000, 'count' => 100));

Pour ajouter vos propres vérifications de quota, utilisez des caractères uniques en tant que
clé et ils seront préservés (mais évidemment non vérifié). Il est aussi possible d'étendre
Zend_Mail_Storage_Writable_Maildir pour définir votre propre quota seulement si le
fichier de contrôle de la taille du dossier de mails est absent (qui peut se produire dans Maildir
++) :

class Exemple_Mail_Storage_Maildir extends Zend_Mail_Storage_Writable_Maildir {


// getQuota est appelé avec $fromStorage = true
// par la vérification de quota
public function getQuota($fromStorage = false) {
try {
return parent::getQuota($fromStorage);
} catch (Zend_Mail_Storage_Exception $e) {
if (!$fromStorage) {
// Erreur inconnue
throw $e;
}
// le fichier de contrôle de la taille du dossier de mails
// doit être absent

list($count, $size) = get_un_autre_quota();


return array('count' => $count, 'size' => $size);
}
}
}

1012
Zend_Markup
1. Introduction
The Zend_Markup component provides an extensible way for parsing text and rendering
lightweight markup languages like BBcode and Textile. It is available as of Zend Framework
version 1.10.

Zend_Markup uses a factory method to instantiate an instance of a renderer that extends


Zend_Markup_Renderer_Abstract. The factory method accepts three arguments. The first
one is the parser used to tokenize the text (e.g. BbCode). The second (optional) parameter is
the renderer to use, Html by default. Thirdly an array with options to use for the renderer can
be specified.

2. Guide de démarrage avec Zend_Markup


Ce guide pour vous aider à démarrer avec Zend_Markup utilisera le parseur BBCode et le
moteur de rendu HTML. Les principes utilisés s'adaptent à d'autres formats.

Exemple 536. Utilisation classique de Zend_Markup

Nous allons d'abord instancier un objet Zend_Markup_Renderer_Html en


utilisant la méthode Zend_Markup::factory(). Ceci créera aussi un objet a
Zend_Markup_Parser_Bbcode qui sera ajouté à l'objet de rendu.

Ensuite, nous utiliserons la méthode render() afin de convertir un bout de BBCode vers
du HTML.

// Créer une instance de Zend_Markup_Renderer_Html,


// avec Zend_Markup_Parser_BbCode comme parseur
$bbcode = Zend_Markup::factory('Bbcode');

echo $bbcode->render('[b]bold text[/b] and [i]cursive text[/i]');


// Affiche: '<strong>bold text</strong> and <em>cursive text</em>'

1013
Zend_Markup

Exemple 537. Un exemple plus complexe de Zend_Markup

Même chose ici, mais avec un bout de BBCode plus complexe.

$bbcode = Zend_Markup::factory('Bbcode');

$input = <<<EOT
[list]
[*]Zend Framework
[*]Foobar
[/list]
EOT;

echo $bbcode->render($input);
/*
Devrait afficher quelque chose comme:
<ul>
<li>Zend Framework</li>
<li>Foobar</li>
</ul>
*/

Exemple 538. Traitement des entrées incorrectes

En plus d'analyser et rendre des codes de type BBCode, Zend_Markup peut aussi traiter
les entrées non valides. La plupart des processeurs de BBCode ne sont pas capables de
rendre toute l'entrée sous forme de XHTML valide. Zend_Markup corrige les entrées non
valides et ajoute des tags de fermetures si nécessaire:

$bbcode = Zend_Markup::factory('Bbcode');

echo $bbcode->render('some [i]wrong [b]sample [/i] text');


// Remarquez que le tag '[b]' n'est pas fermé et est aussi mal niché
// dans l'arbre; mais Zend_Markup propose un rendu correct:
// some <em>wrong <strong>sample </strong></em><strong> text</strong>

3. Analyseurs Zend_Markup (parsers)


Zend_Markup est fourni avec deux analyseurs, BBCode et Textile.

3.1. Theorie de l'analyse


Les analyseurs syntaxiques de Zend_Markup sont des classes qui convertissent du texte
balisé en un arbre d'identifiants d'analyses, appelées 'tokens'. Même si nous utilisons par la
suite l'analyseur BBCode, le principe de l'arbre à tokens est le même pour tous les analyseurs
syntaxiques. Essayons avec un morceau de BBCode par exemple:

[b]foo[i]bar[/i][/b]baz

L'analyseur BBCode va analyser syntaxiquement ce code et en déduire l'arbre suivant:

• [b]

• foo

• [i]

• bar

1014
Zend_Markup

• baz

Notez que les tags de fermeture n'existent plus dans l'arbre généré. Ceci car ils n'ont pas de
valeur particulière pour la sémantique, ils ne sont pas perdus mais stockés grâce au seul tag
d'ouverture. Notez aussi que ceci n'est qu'une vue simplifiée de l'arbre réel qui contient en réalité
bien plus d'informations comme les attributs éventuels du tag et son nom.

3.2. L'analyseur BBCode


L'analyseur BBCode est un analyseur de Zend_Markup qui transforme un code BBCode en
arbres à tokens. La syntaxe des tags BBCode est:

[name(=(value|"value"))( attribute=(value|"value"))*]

Des exemples de tags BBCode valides:

[b]
[list=1]
[code file=Zend/Markup.php]
[url="http://framework.zend.com/" title="Zend Framework!"]

Par défaut, tous les tags sont fermés avec la syntaxe '[/tagname]'.

3.3. L'analyseur Textile


L'analyseur Textile de Zend_Markup convertit du texte au format Textile en un arbre à tokens.
Textile n'ayant pas de structure à base de tags, la liste suivante est un exemple de tags:

Tableau 103. Liste de tags Textile basiques

Entrée Sortie
*foo* <strong>foo</strong>
_foo_ <em>foo</em>
??foo?? <cite>foo</cite>
-foo- <del>foo</del>
+foo+ <ins>foo</ins>
^foo^ <sup>foo</sup>
~foo~ <sub>foo</sub>
%foo% <span>foo</span>
PHP(PHP Hypertext Preprocessor) <acronym title="PHP Hypertext
Preprocessor">PHP</acronym>
"Zend Framework":http:// <a href="http://framework.zend.com/">Zend
framework.zend.com/ Framework</a>
h1. foobar <h1>foobar</h1>
h6. foobar <h6>foobar</h6>
!http://framework.zend.com/images/logo.gif! <img src="http://framework.zend.com/images/
logo.gif" />

L'analyseur Textile encapsule tous les tags dans des paragraphes; un paragraphe se termine par
deux nouvelles lignes, et s'il y a des tags supplémentaires, un nouveau paragraphe sera ajouté.

1015
Zend_Markup

3.3.1. Listes
L'analyseur Textile supporte aussi deux types de listes. Le type numérique, utilisant le caractère
"#" et le type anonyme qui utilise lui l'étoile "*". Exemple des deux listes:

# Item 1
# Item 2

* Item 1
* Item 2

Le code ci-dessus génèrera deux listes, la première, numérique; et la seconde, anonyme.


Dans les éléments des listes, vous pouvez utiliser des tags classiques comme le gras (*), et
l'emphase(italique) (_). Les tags ayant besoin de créer une nouvelle ligne (comme 'h1' etc.) ne
peuvent être utilisés au sein des listes.

4. Moteurs de rendu Zend_Markup


Zend_Markup est fournie avec un moteur de rendu, le HTML.

4.1. Ajouter vos propres tags


En ajoutant vos tags, vous pouvez ajouter vos propres fonctionnalités aux moteurs de rendu
de Zend_Markup. Grâce à la structure en tags, vous pouvez ajouter presque toutes les
fonctionnalités que vous voulez, depuis des tags simples jusqu'à des structures de données
complexes. Voici un exemple pour un tag simple 'foo':

// Créer une instance de Zend_Markup_Renderer_Html,


// avec Zend_Markup_Parser_BbCode comme analyseur
$bbcode = Zend_Markup::factory('Bbcode');

// Ceci va créer un tag simple 'foo'


// Le premier paramètre définit le nom du tag
// Le second param prend un entier qui définit le type de tag.
// Le troisième param est un tableau qui définit d'autres caractéristiques
// du tag comme son groupe et (dans ce cas) les tags de début et de fin
$bbcode->addTag(
'foo',
Zend_Markup_Renderer_RendererAbstract::TYPE_REPLACE,
array(
'start' => '-bar-',
'end' => '-baz-',
'group' => 'inline'
)
);

// La sortie sera: 'my -bar-tag-baz-'


echo $bbcode->render('my [foo]tag[/foo]');

Notez que créer vos propres tags n'est utile que si l'analyseur syntaxique en tient compte.
Actuellement, seul BBCode supporte cela. Textile ne supporte pas les tags personnalisés.

Certains moteurs de rendu (comme le moteur HTML) supporte un paramètre nommé 'tag'. Cela
remplace les paramètres 'start' et 'end', et il rend le tag avec des attributs par défaut ainsi que
le tag de fin.

1016
Zend_Markup

4.1.1. Ajout d'un tag de rappel(callback)


Ajouter des tags de rappel permet de faire bien plus que de simples remplacements. Par
exemple, vous pouvez changer le contenu, utiliser des paramètres pour changer la sortie, etc.

Un rappel est une classe qui implémente Zend_Markup_Renderer_TokenInterface Voici


un exemple de classe de tag de rappel:

class My_Markup_Renderer_Html_Upper extends Zend_Markup_Renderer_TokenConverterInterface


{

public function convert(Zend_Markup_Token $token, $text)


{
return '!up!' . strtoupper($text) . '!up!';
}

Il est possible maintenant d'ajouter le tag 'upper', avec comme fonction de rappel, une instance
de My_Markup_Renderer_Html_Upper. Voici un exemple:

// Créer une instance de Zend_Markup_Renderer_Html,


// avec Zend_Markup_Parser_BbCode comme analyseur
$bbcode = Zend_Markup::factory('Bbcode');

// Ceci va créer un tag simple 'foo'


// Le premier paramètre définit le nom du tag
// Le second param prend un entier qui définit le type de tag.
// Le troisième param est un tableau qui définit d'autres caractéristiques
// du tag comme son groupe et (dans ce cas) les tags de début et de fin
$bbcode->addTag(
'upper',
Zend_Markup_Renderer_RendererAbstract::TYPE_REPLACE,
array(
'callback' => new My_Markup_Renderer_Html_Upper(),
'group' => 'inline'
)
);

// La sortie sera: 'my !up!TAG!up!'


echo $bbcode->render('my [upper]tag[/upper]');

4.2. Liste de tags


Tableau 104. Liste de tags

Entrée (bbcode) Sortie


[b]foo[/b] <strong>foo</strong>
[i]foo[/i] <em>foo</em>
[cite]foo[/cite] <cite>foo</cite>
[del]foo[/del] <del>foo</del>
[ins]foo[/ins] <ins>foo</ins>
[sup]foo[/sup] <sup>foo</sup>
[sub]foo[/sub] <sub>foo</sub>

1017
Zend_Markup

Entrée (bbcode) Sortie


[span]foo[/span] <span>foo</span>
[acronym title="PHP Hypertext <acronym title="PHP Hypertext
Preprocessor]PHP[/acronym] Preprocessor">PHP</acronym>
[url=http://framework.zend.com/]Zend <a href="http://framework.zend.com/">Zend
Framework[/url] Framework</a>
[h1]foobar[/h1] <h1>foobar</h1>
[img]http://framework.zend.com/images/ <img src="http://framework.zend.com/images/
logo.gif[/img] logo.gif" />

1018
Zend_Measure
1. Introduction
Les classes Zend_Measure_* fournissent un moyen générique et facile de travailler avec les
mesures. En utilisant des classes de Zend_Measure_*, vous pouvez convertir des mesures en
différentes unités du même type. Elles peuvent être ajoutées, soustraites et comparées les uns
contre les autres. À partir d'une entrée donnée faite dans la langue maternelle de l'utilisateur,
l'unité de la mesure peut être automatiquement extraite. Des unités de mesure supportées sont
nombreuses.

Exemple 539. Convertir des mesures

L'exemple d'introduction suivant montre la conversion automatique des unités de mesure.


Pour convertir une mesure, sa valeur et son type doivent être connus. La valeur peut être
un nombre entier, un nombre à virgule flottante ("float"), ou même une chaîne contenant
un nombre. Les conversions sont seulement possibles aux unités du même type (la masse,
secteur, température, vitesse, etc.), pas entre les types.

$locale = new Zend_Locale('en');


$unit = new Zend_Measure_Length(100,
Zend_Measure_Length::METER,
$locale);

// Converti les mètres en yards


echo $unit->convertTo(Zend_Measure_Length::YARD);

Zend_Measure_* inclut le support de beaucoup de différentes unités de mesure. Toutes les


unités de mesure ont une notation unifiée : Zend_Measure_<TYPE>::NAME_OF_UNIT, où
<TYPE> correspond à une propriété physique ou numérique bien connue. Chaque unité de
mesure se compose d'un facteur de conversion et d'une unité de visualisation. Une liste détaillée
peut être trouvée dans le chapitre des types de mesures.

Exemple 540. La mesure de la longueur

Le mètre est utilisé pour mesurer des longueurs, ainsi son type constante peut être trouvé
dans la classe des longueurs. Pour se rapporter à cette unité de mesure, la notation
Length::METER doit être utilisée. L'unité de visualisation est m.

echo Zend_Measure_Length::STANDARD;
// affiche 'Length::METER'
echo Zend_Measure_Length::KILOMETER;
// affiche 'Length::KILOMETER'

$unit = new Zend_Measure_Length(100,'METER');


echo $unit;
// affiche '100 m'

2. Création d'une mesure


En créant un objet de mesure, les méthodes Zend_Measure_* prévoient que l'entrée ou la
mesure originale soit le premier paramètre. Ceci peut être un argument numérique, une

1019
Zend_Measure

chaîne sans unités, ou une chaîne régionale avec une (des) unité(s) spécifiée(s). Le
deuxième paramètre définit le type de la mesure. Les deux paramètres sont obligatoires. La
langue peut être indiquée comme troisième paramètre optionnel.

2.1. Créer des mesures à partir de nombres entiers et décimaux


En plus des valeurs de données en nombre entier, des nombre décimaux peuvent être employés,
mais "il est fréquent que de simples fractions décimales telles que 0.1 ou 0.7 ne puissent être
converties au format interne binaire sans une légère perte de précision" parfois en donnant des
résultats étonnants. En outre, il ne faut pas comparer l'égalité de deux nombres décimaux.

Exemple 541. Création de mesure en utilisant des nombres entiers et décimaux

$mesure = 1234.7;
$unite = new Zend_Measure_Length((integer)$mesure,
Zend_Measure_Length::STANDARD);
echo $unite;
// affiche '1234 m' (mètres)

$unite = new Zend_Measure_Length($mesure, Zend_Measure_Length::STANDARD);


echo $unite;
// affiche '1234.7 m' (mètres)

2.2. Créer des mesures à partir de chaînes de caractères


Beaucoup de mesures reçues comme entrée des applications Zend Framework peuvent
seulement être passées aux classes Zend_Measure_* comme des chaînes, telles que des
nombres écrits en utilisant les chiffres romains ou les valeurs binaires extrêmement grandes qui
excèdent la précision native de PHP des nombres entiers ou décimaux. Puisque les nombres
entiers peuvent être indiqués en utilisant des chaînes, s'il y a un quelconque risque de perdre
la précision à cause des limitations des types natifs (nombre entier et décimaux), il faut utiliser
des chaînes à la place. Zend_Measure_Number emploie l'extension BCMath pour supporter
la précision arbitraire, afin d'éviter les limitations dans beaucoup de fonctions de PHP, telle que
bin2dec().

Exemple 542. Création de mesure en utilisant des chaînes

$machaine = "10010100111010111010100001011011101010001";
$unit = new Zend_Measure_Number($machaine, Zend_Measure_Number::BINARY);

echo $unit;

2.3. Mesures à partir de chaînes localisées


Quand une corde est présentée dans une notation régionalisée, l'interprétation correcte ne peut
pas être déterminée sans connaître la région attendue. La division des chiffres décimaux avec
"." et grouper des milliers avec "," est commun en l'anglais, mais pas dans d'autres langues.
Par exemple, le nombre anglais "1,234.50" serait interprété comme "1.2345" en allemand. Pour
traiter de tels problèmes, la famille des classes Zend_Measure_* offrent la possibilité d'indiquer
une langue ou une région pour lever l'ambiguïté les données d'entrée et pour interpréter
correctement la valeur sémantique prévue.

1020
Zend_Measure

Exemple 543. Chaînes localisées

$locale = new Zend_Locale('de');


$machaine = "1,234.50";
$unite = new Zend_Measure_Length($machaine,
Zend_Measure_Length::STANDARD, $locale);
echo $unite; // affiche "1.234 m"

$machaine = "1,234.50";
$unite = new Zend_Measure_Length($machaine,
Zend_Measure_Length::STANDARD, 'en_US');
echo $unite; // affiche "1234.50 m"

Depuis la version 1.7.0 de Zend Framework, Zend_Measure supporte aussi l'utilisation


d'une application pleinement localisée. Vous pouvez simplement paramétrer une instance
Zend_Locale dans le registre comme présenté ci-dessous. Avec cette notation vous pouvez ne
pas paramétrer cette valeur manuellement à chaque fois quand vous utilisez la même localisation
plusieurs fois.

// in your bootstrap file


$locale = new Zend_Locale('de_AT');
Zend_Registry::set('Zend_Locale', $locale);

// somewhere in your application


$length = new Zend_Measure_Length(Zend_Measure_Length::METER();

3. Récupérer des mesures


Les mesures peuvent être récupérer de différentes manières.

Récupération automatique

Récupération des valeurs

Récupération de l'unité de mesure

Récupération en tant que chaîne régionale

3.1. Récupération automatique


Zend_Measure supporte la récupération sous formes de chaînes de caractères
automatiquement.

Exemple 544. Récupération automatique

$locale = new Zend_Locale('de');


$machaine = "1.234.567,89";
$unite = new Zend_Measure_Length($machaine,
Zend_Measure_Length::STANDARD,
$locale);

echo $unite; // affiche "1234567.89 m"

Affichage de la mesure
L'affichage peut être réalisé simplement en utilisant echo ou print.

1021
Zend_Measure

3.2. Récupération des valeurs


La valeur d'une mesure peut être récupérée en utilisant getValue().

Exemple 545. Récupération d'une valeur

$locale = new Zend_Locale('de');


$machaine = "1.234.567,89";
$unite = new Zend_Measure_Length($machaine,
Zend_Measure_Length::STANDARD,
$locale);

echo $unite->getValue(); // affiche "1234567.89"

La méthode getValue() accepte un paramètre facultatif "round" qui permet de définir la


précision de la sortie générée. La précision par défaut est de 2.

3.3. Récupération de l'unité de mesure


La fonction getType() retourne l'unité de mesure courante.

Exemple 546. Récupérer l'unité de mesure

$locale = new Zend_Locale('de');


$machaine = "1.234.567,89";
$unit = new Zend_Measure_Weight($machaine,
Zend_Measure_Weight::POUND,
$locale);

echo $unit->getType(); // affiche "POUND"

3.4. Récupération en tant que chaîne régionale


Récupérer une chaîne dans un format habituel du pays de l'utilisateur est habituellement
souhaitable. Par exemple, la mesure "1234567.8" deviendrait "1.234.567,8" pour l'Allemagne.
Cette fonctionnalité sera supportée dans une future version.

4. Manipuler des mesures


L'analyse et la normalisation de l'entrée, combinées avec la récupération suivant les notations
régionalisées rend des données accessibles aux utilisateurs dans différentes régions. Beaucoup
de méthodes additionnelles existent dans les composants Zend_Measure_* pour manipuler et
travailler ces données, après qu'elles aient été normalisées.

• Convertir

• Ajouter et soustraire

• Comparer avec un booléen

• Comparer "plus/moins grand que"

• Changer manuellement des valeurs

1022
Zend_Measure

• Changer manuellement de type

4.1. Convertir
Le dispositif le plus important est probablement la conversion dans différentes unités de la
mesure. La conversion d'une unité peut être faite à tout moment en utilisant la méthode
convertTo(). Des unités de mesure peuvent seulement être converties en d'autres unités
du même type (classe). Par conséquent, il n'est pas possible de convertir (par exemple : une
longueur en poids), qui encouragerait des pratiques de programmation pauvres et entraînerait
la propagation d'erreurs sans lever d'exception.

La méthode convertTo accepte un paramètre facultatif. Avec ce paramètre vous pouvez définir
une précision pour l'élément retourné. La précision par défaut est "2".

Exemple 547. Convertir

$locale = new Zend_Locale('de');


$machaine = "1.234.567,89";
$unite = new Zend_Measure_Weight($machaine,'POND', $locale);

print "Kilo : ".$unite->convertTo('KILOGRAM');


// affiche "Kilo : 617283.945 kg"

// l'utilisation de constantes est considérée comme


// une meilleure pratique que les chaînes
print "Tonne : ".$unite->convertTo(Zend_Measure_Weight::TON);
// affiche "Tonne : 617.283945 t"

// définition de la précision pour l'affichage


print "Tonne :".$unit->convertTo(Zend_Measure_Weight::TON, 3);

4.2. Ajouter et soustraire


Les mesures peuvent être ajoutées en utilisant add() et soustraites en utilisant sub(). Chaque
addition créera un nouvel objet pour le résultat. L'objet courant ne sera jamais changé par
la classe. Le nouvel objet sera du même type que l'objet de début. Les objets dynamiques
supportent un modèle fluide de programmation, où des ordres complexes d'opération peuvent
être imbriqués sans risque d'effets secondaires changeant les objets d'entrée.

Exemple 548. Ajouter des mesures

// Définition des objets


$unite1 = new Zend_Measure_Length(200, Zend_Measure_Length::CENTIMETER);
$unite2 = new Zend_Measure_Length(1, Zend_Measure_Length::METER);

// ajouter l'$unite2 à l'$unite1


$somme = $unite1->add($unite2);

echo $somme; // affiche "300 cm"

Conversion automatique

Ajouter un objet à l'autre le convertira automatiquement dans l'unité correcte.


Il n'est pas nécessaire d'appeler convertTo() avant d'ajouter des unités
différentes.

1023
Zend_Measure

Exemple 549. Soustraire des mesures

La soustraction des mesures fonctionne comme l'addition.

// Définition des objets


$unite1 = new Zend_Measure_Length(200, Zend_Measure_Length::CENTIMETER);
$unite2 = new Zend_Measure_Length(1, Zend_Measure_Length::METER);

// soustriare l'$unite2 de l'$unite1


$somme = $unite1->sub($unite2);

echo $somme; // affiche "100 cm"

4.3. Vérifier l'égalité des mesures


Les mesures peuvent également être comparées, mais sans conversion automatique de l'unité.
De plus, equals() retourne TRUE, seulement si la valeur et l'unité de mesure sont identiques.

Exemple 550. Mesures différentes

// Définition des mesures


$unite1 = new Zend_Measure_Length(100, Zend_Measure_Length::CENTIMETER);
$unite2 = new Zend_Measure_Length(1, Zend_Measure_Length::METER);

if ($unite1->equals($unite2)) {
print "Les mesures sont identiques";
} else {
print "Les mesures sont différentes";
}
// affiche "Les mesures sont différentes"

Exemple 551. Mesures identiques

// Définition des mesures


$unite1 = new Zend_Measure_Length(100, Zend_Measure_Length::CENTIMETER);
$unite2 = new Zend_Measure_Length(1, Zend_Measure_Length::METER);

$unite2->setType(Zend_Measure_Length::CENTIMETER);

if ($unite1->equals($unite2)) {
print "Les mesures sont identiques";
} else {
print "Les mesures sont différentes";
} // affiche "Les mesures sont identiques"

4.4. Comparer les mesures


Pour déterminer si une mesure est plus ou moins grande qu'une autre, il faut utiliser compare(),
qui renvoie 0, -1 ou 1 selon la différence entre les deux objets. Les mesures identiques
retourneront 0. Plus petit retournera -1 et plus grand retournera +1.

1024
Zend_Measure

Exemple 552. Différence

$unite1 = new Zend_Measure_Length(100, Zend_Measure_Length::CENTIMETER);


$unite2 = new Zend_Measure_Length(1, Zend_Measure_Length::METER);
$unite3 = new Zend_Measure_Length(1.2, Zend_Measure_Length::METER);

print "Egalité : ".$unite2->compare($unite1);


// affiche "Egalité : 0"
print "Plus petit que : ".$unite2->compare($unite3);
// affiche "Plus petit que : -1"
print "Plus grand que : ".$unite3->compare($unite2);
// affiche "Plus grand que : 1"

4.5. Changer manuellement des valeurs


Pour changer explicitement la valeur d'une mesure, il faut utiliser setValue() pour surcharger
la valeur courante. Les paramètres sont identiques à ceux du constructeur.

Exemple 553. Changer une valeur

$locale = new Zend_Locale('de_AT');


$unite = new Zend_Measure_Length(1,Zend_Measure_Length::METER);

$unite->setValue(1.2);
echo $unite; // affiche "1.2 m"

$unite->setValue(1.2, Zend_Measure_Length::KILOMETER);
echo $unite; // affiche "1200 km"

$unite->setValue("1.234,56", Zend_Measure_Length::MILLIMETER,$locale);
echo $unite; // affiche "1234.56 mm"

4.6. Changer manuellement de type


Pour changer le type d'une mesure sans altérer sa valeur, il faut utiliser setType().

Exemple 554. Changer de type

$unite = new Zend_Measure_Length(1,Zend_Measure_Length::METER);


echo $unite; // affiche "1 m"

$unite->setType(Zend_Measure_Length::KILOMETER);
echo $unite; // affiche "1000 km"

5. Types de mesures
Tous les types de mesures supportées sont listées ci-dessous, chacun avec une exemple
d'utilisation standard pour ce type de mesure.

Tableau 105. Liste des types de mesure


Type Classe Unité standard Description
Accélération Zend_Measure_Acceleration
Mètres par seconde Zend_Measure_Acceleration
carré | m/s² couvre le facteur
physique
d'accélération.

1025
Zend_Measure

Type Classe Unité standard Description


Angle Zend_Measure_Angle Radiant | rad Zend_Measure_Angle
couvre les dimensions
angulaires.
Superficie Zend_Measure_Area Mètres carré | m² Zend_Measure_Area
couvre les superficies.
Binaire Zend_Measure_Binary Bit | b Zend_Measure_Binary
couvre les conversions
binaires.
Capacité électrique Zend_Measure_Capacitance
Farad | F Zend_Measure_Capacitance
couvre le facteur
physique de capacité
électrique.
Volume (de cuisine) Zend_Measure_Cooking_Volume
Mètre au cube | m³ Zend_Measure_Cooking_Volume
couvre les volumes
(principalement pour la
cuisine ou les livres de
cuisine).
Poids (de cuisine) Zend_Measure_Cooking_Weight
Gramme | g Zend_Measure_Cooking_Weight
couvre les poids
(principalement pour la
cuisine ou les livres de
cuisine).
Courant électrique Zend_Measure_CurrentAmpère | A Zend_Measure_Current
couvre le facteur
physique de courant
électrique.
Masse volumique Zend_Measure_DensityKilogramme par mètre Zend_Measure_Density
(densité) au cube | kg/m³ couvre le facteur
physique de la masse
volumique (densité).
Énergie Zend_Measure_EnergyJoule | J Zend_Measure_Energy
couvre le facteur
physique de l'énergie.
Force Zend_Measure_Force Newton | N Zend_Measure_Force
couvre le facteur
physique de la force.
Débit (massique) Zend_Measure_Flow_Mass
Kilogramme par Zend_Measure_Flow_Mass
seconde | kg/s couvre le facteur
physique de débit
massique. Le poids
de la masse en
écoulement est utilisé
comme point de
référence de la classe.
Débit (molaire) Zend_Measure_Flow_Mole
Mole par seconde | Zend_Measure_Flow_Mole
mol/s couvre le facteur
physique de débit
massique. La densité

1026
Zend_Measure

Type Classe Unité standard Description


de la masse en
écoulement est utilisée
comme point de
référence de la classe.
Débit (volumique) Zend_Measure_Flow_Volume
Mètres au cube par Zend_Measure_Flow_Volume
seconde | m³/s couvre le facteur
physique de débit
massique. Le volume
de la masse en
écoulement est utilisé
comme point de
référence de la classe.
Fréquence Zend_Measure_Frequency
Hertz | Hz Zend_Measure_Frequency
couvre le facteur
physique de
fréquence.
Éclairement lumineux Zend_Measure_Illumination
Lux | lx Zend_Measure_Illumination
couvre le facteur
physique de
l'éclairement lumineux.
Longueur Zend_Measure_Length Mètres | m Zend_Measure_Length
couvre le facteur
physique de longueur.
Luminosité Zend_Measure_Lightness
Candela par mètre Zend_Measure_Ligntness
carré | cd/m² couvre le facteur
physique de
luminosité.
Nombre Zend_Measure_NumberDécimal | (10) Zend_Measure_Number
permet la conversion
entre les formats
numériques.
Puissance Zend_Measure_Power Watt | W Zend_Measure_Power
couvre le facteur
physique de
puissance.
Pression Zend_Measure_Pressure
Newton par mètre Zend_Measure_Pressure
carré | N/m² couvre le facteur
physique de pression.
Vitesse Zend_Measure_Speed Mètre par seconde | m/ Zend_Measure_Speed
s couvre le facteur
physique de vitesse
Température Zend_Measure_Temperature
Kelvin | K Zend_Measure_Temperature
couvre le facteur
physique de
température
Durée Zend_Measure_Time Seconde | s Zend_Measure_Time
couvre le facteur
physique de la durée.

1027
Zend_Measure

Type Classe Unité standard Description


Couple Zend_Measure_TorqueNewton mètre | Nm Zend_Measure_Torque
couvre le facteur
physique du couple
Viscosité (dynamique) Zend_Measure_Viscosity_Dynamic
Kilogramme par mètre Zend_Measure_Viscosity_Dynamic
seconde | kg/ms couvre le facteur
physique de viscosité.
La masse du fluide
est utilisée comme le
point de référence de
la classe.
Viscosité Zend_Measure_Viscosity_Kinematic
Mètres carré par Zend_Measure_Viscosity_Kinemat
(cinématique) seconde | m²/s couvre le facteur
physique de viscosité.
La distance parcouru
par la masse en
écoulement est utilisée
comme le point de
référence de la classe.
Volume Zend_Measure_VolumeMètre au cube | m³ Zend_Measure_Volume
couvre le facteur
physique de volume
(contenu).
Masse Zend_Measure_Weight Kilogramme | kg Zend_Measure_Weight
couvre le facteur
physique de masse.

5.1. Conseils pour Zend_Measure_Binary


Quelques conventions binaires populaires, incluent des termes comme le kilo-, le mega-, le giga,
etc. dans les langues utilisant implicitement la base 10, tels que 1000 ou 10³. Cependant, dans
le format binaire des ordinateurs, ces limites doivent être vues comme un facteur de conversion
de 1024 au lieu de 1000. Pour exclure des confusions il y a quelques années, la notation BI a
été introduite. Au lieu du "kilobyte", le kibibyte pour le "kilo-binary-byte" devrait être employé.

Dans la classe BINARY les deux notations peuvent être trouvées, comme KILOBYTE =
1024 - binary computer conversion KIBIBYTE = 1024 - new notation
KILO_BINARY_BYTE = 1024 - new, ou la notation, en format long KILOBYTE_SI = 1000
- SI notation for kilo (1000). Les DVDs par exemple sont identifiés par la SI-notation,
mais presque tous les disques durs sont marqués dans la numérotation binaire des ordinateurs.

5.2. Conseils pour Zend_Measure_Number


Le format de nombre le plus connu est le système décimal. De manière additionnelle, cette
classe supporte le système octal, le système hexadécimal, le système binaire, le système des
chiffres romains et quelques autres systèmes moins populaires. Noter que seulement la partie
décimale des nombres est manipulée. Toute partie fractionnelle sera effacée.

1028
Zend_Measure

5.3. Chiffres romains


Les chiffres romains plus grands que 4000 sont supportés. Ces nombres sont écrits avec une
barre au dessus. Comme cette barre ne peut pas être représentée sur l'ordinateur, il faut utiliser
un tiret bas en début de chaîne.

$valeur_grande = '_X';
$locale = new Zend_Locale('en');
$unite = new Zend_Measure_Number($valeur_grande,
Zend_Measure_Number::ROMAN,
$locale);

// convertir en système décimal


echo $unite->convertTo(Zend_Measure_Number::DECIMAL);
// affiche 10000

1029
Zend_Memory
1. Présentation
1.1. Introduction
Le composant Zend_Memory est destiné à gérer des données dans un environnement où la
mémoire est limitée.

Les objets mémoire (conteneurs de mémoire) sont produits par le manager de mémoire sur
demande et mis en cache/chargés d'une manière transparente quand c'est nécessaire.

Par exemple, si la création ou le chargement d'un objet entraîne une utilisation de mémoire totale
excédant la limite que vous spécifiez, certains objets gérés sont copiés en cache à l'extérieur
de la mémoire. De cette façon, la mémoire totale utilisée par les objets gérés n'excède pas la
limite que vous devez mettre en application.

Le manager de mémoire utilise les backends Zend_Cache comme fournisseurs de stockage.

Exemple 555. Utiliser le composant Zend_Memory

Zend_Memory::factory() instancie l'objet de management de la mémoire avec les


options spécifiques du backend.

$backendOptions = array(
'cache_dir' => './tmp/'
// Dossier où les blocks de mémoire peuvent être stockés
);

$memoryManager = Zend_Memory::factory('File', $backendOptions);

$loadedFiles = array();

for ($count = 0; $count < 10000; $count++) {


$f = fopen($fileNames[$count], 'rb');
$data = fread($f, filesize($fileNames[$count]));
$fclose($f);

$loadedFiles[] = $memoryManager->create($data);
}

echo $loadedFiles[$index1]->value;

$loadedFiles[$index2]->value = $newValue;

$loadedFiles[$index3]->value[$charIndex] = '_';

1.2. Aspect théorique


Zend_Memory travaille avec les concepts suivants :

• Manager de mémoire

• Conteneur de mémoire

1030
Zend_Memory

• Objet de mémoire verrouillé

• Objet de mémoire mobile

1.2.1. Manager de mémoire


Le manager de mémoire produit des objets de mémoire (verrouillé ou mobile) sur demande de
l'utilisateur et les retourne encapsulé dans un objet conteneur de mémoire.

1.2.2. Conteneur de mémoire


Le conteneur de mémoire a un attribut value virtuel ou réel de type chaîne de caractères. Cet
attribut contient la valeur de donnée indiquée au moment de la création de l'objet mémoire.

Vous pouvez exploiter cet attribut value comme une propriété d'objet :

$memObject = $memoryManager->create($data);

echo $memObject->value;

$memObject->value = $newValue;

$memObject->value[$index] = '_';

echo ord($memObject->value[$index1]);

$memObject->value = substr($memObject->value, $start, $length);

Si vous utilisez une version de PHP inférieure à 5.2, utilisez la méthode getRef()
au lieu d'accéder directement à la valeur de la propriété.

1.2.3. Objet de mémoire verrouillé


Les objets de mémoire verrouillés sont toujours stockés dans la mémoire. Les données stockées
dans la mémoire verrouillée ne sont jamais mis en cache.

1.2.4. Objet de mémoire mobile


Les objets de mémoire mobiles sont mis en cache et chargés de manière transparente de/vers
le cache par Zend_Memory si c'est nécessaire.

Le manager de mémoire ne met pas en cache des objets ayant une taille plus petite que
le minimum spécifié dans un soucis de performances. Voir Section 2.3.2, « MinSize (taille
minimum) » pour plus de détails.

2. Manager de mémoire
2.1. Créer un manager de mémoire
Vous pouvez créer un nouveau manager de mémoire (objet Zend_Memory_Manager) en
utilisant la méthode Zend_Memory::factory($backendName [, $backendOprions]).

Le premier argument $backendName est le nom d'un type de backend supporté par
Zend_Cache

1031
Zend_Memory

Le second argument $backendOptions est un tableau optionnel indiquant les options du


backend.

$backendOptions = array(
'cache_dir' => './tmp/'
// Dossier où les blocks de mémoire peuvent être stockés
);

$memoryManager = Zend_Memory::factory('File', $backendOptions);

Zend_Memory utilise les backends Zend_Cache comme fournisseurs de stockage.

Vous pouvez de plus utiliser le nom spécial 'None' en tant que nom de backend supplémentaire
de Zend_Cache.

$memoryManager = Zend_Memory::factory('None');

Si vous utilisez "None", alors le manager de mémoire ne mettra pas en cache les blocks de
mémoire. Ceci est intéressant si vous savez que la mémoire n'est pas limitée ou la taille complète
des objets n'atteint jamais la limite de mémoire.

Le backend "None" ne nécessite aucune option.

2.2. Manager les objets mémoire


Cette section décrit la création et la destruction d'objet de mémoire, et les réglages du manager
de mémoire.

2.2.1. Créer des objets mobiles


Créer des objets mobiles (objets qui peuvent être mis en cache) en utilisant la méthode
Zend_Memory_Manager::create([$data]) :

$memObject = $memoryManager->create($data);

L'argument $data est optionnel et utilisé pour initialiser la valeur de l'objet. Si l'argument $data
est omis, la valeur est une chaîne vide.

2.2.2. Créer des objets verrouillés


Créer des objets verrouillés (objets qui ne doivent pas être mis en cache) en utilisant la méthode
Zend_Memory_Manager::createLocked([$data]) :

$memObject = $memoryManager->createLocked($data);

L'argument $data est optionnel et utilisé pour initialiser la valeur de l'objet. Si l'argument $data
est omis, la valeur est une chaîne vide.

2.2.3. Détruire des objets


Les objets mémoire sont automatiquement détruits et effacés de la mémoire quand ils sont hors
de portée :

function foo()
{

1032
Zend_Memory

global $memoryManager, $memList;

...

$memObject1 = $memoryManager->create($data1);
$memObject2 = $memoryManager->create($data2);
$memObject3 = $memoryManager->create($data3);

...

$memList[] = $memObject3;

...

unset($memObject2); // $memObject2 est détruit ici

...
// $memObject1 est détruit ici
// mais $memObject3 est toujours référencé par $memList
// et n'est pas détruit
}

Ceci s'applique aux objets mobiles et verrouillés.

2.3. Régler le manager de mémoire


2.3.1. Mémoire limite
La mémoire limite est le nombre d'octets autorisés à être utilisés par des objets mobiles chargés.

Si le chargement ou la création d'un objet entraîne l'utilisation de mémoire excédant cette limite,
alors le manager met en cache un certain nombre d'objet.

Vous pouvez récupérer et régler la mémoire limite en utilisant les méthodes


getMemoryLimit() et setMemoryLimit($newLimit) :

$oldLimit = $memoryManager->getMemoryLimit();
// Récupére la mémoire limite en octets
$memoryManager->setMemoryLimit($newLimit);
// Règle la mémoire limite en octets

Une valeur négative pour limite de mémoire équivaut à "pas de limite".

La valeur par défaut est deux-tiers de la valeur de "memory_limit" dans le php.ini ou "no
limit" (-1) si "memory_limit" n'est pas réglé dans le php.ini.

2.3.2. MinSize (taille minimum)


MinSize est la taille minimale des objets de mémoire, qui peuvent être mis en cache par le
manager de mémoire. Le manager ne met pas en cache des objets plus petits que cette valeur.
Ceci réduit le nombre d'opérations de mise de cache/chargement

Vous pouvez récupérer et régler la taille minimale en utilisant les méthodes getMinSize() et
setMinSize($newSize) :

$oldMinSize = $memoryManager->getMinSize();
// Récupère la taille minimale en octets

1033
Zend_Memory

$memoryManager->setMinSize($newSize);
// Règle la taille minimale en octets

La taille minimum par défaut est 16KB (16384 octets).

3. Objet mémoire
3.1. Mobile
Créer des objets mémoires mobiles en utilisant la méthode create([$data]) du manager de
mémoire :

$memObject = $memoryManager->create($data);

"Mobile" signifie que de tels objets peuvent être mis en cache et déchargés de la mémoire et
chargés ensuite quand le code de l'application accède à l'objet.

3.2. Verrouillé
Créer des objets mémoires verrouillés en utilisant la méthode createLocked([$data]) du
manager de mémoire :

$memObject = $memoryManager->createLocked($data);

"Verrouillé" signifie que de tels objets ne sont jamais mis en cache et déchargés de la mémoire.

Les objets verrouillés fournissent la même interface que des objets mobiles
(Zend_Memory_Container_Interface). Donc l'objet verrouillé peut être utilisé en n'importe
quel endroit à la place des objets mobiles.

Il est utile si une application ou un développeur peut décider, que quelques objets ne devraient
jamais être mis en cache, en se basant sur des considérations de performance.

L'accès aux objets verrouillés est plus rapide, parce que le manager de mémoire ne doit pas
suivre à la trace des changements pour ces objets.

La classe d'objets verrouillés (Zend_Memory_Container_Locked) garantit pratiquement la


même performance qu'en travaillant avec une variable de type chaîne de caractères. La couche
supérieure est un simple référence pour récupérer la propriété de classe.

3.3. Propriété "value" du manager de mémoire


Utilisez la propriété "value" du conteneur de mémoire (mobile ou verrouillé) pour travailler avec
les données des objets mémoire :

$memObject = $memoryManager->create($data);

echo $memObject->value;

$memObject->value = $newValue;

$memObject->value[$index] = '_';

echo ord($memObject->value[$index1]);

1034
Zend_Memory

$memObject->value = substr($memObject->value, $start, $length);

Une autre manière d'accéder aux données d'objet mémoire est d'utiliser la méthode getRef().
Cette méthode doit être utilisée pour les versions de PHP inférieure à 5.2. Il devrait aussi être
utilisé dans quelques autres cas pour des raisons de performance.

3.4. Interface du conteneur de mémoire


Le conteneur de mémoire fournit les méthodes suivantes :

3.4.1. La méthode getRef()

public function &getRef();

La méthode getRef() retourne la référence vers une valeur d'objet.

Des objets mobiles sont chargés du cache à ce moment si l'objet n'est pas déjà dans la mémoire.
Si l'objet est chargé du cache, cela pourrait entraîner la mise en cache d'autres objets si la limite
de mémoire était dépassée en ayant tous les objets en mémoire.

La méthode getRef() doit être utilisée pour accéder aux données d'objet mémoire si la version
de PHP est inférieure à 5.2

Suivre à la trace les changements de ces données nécessitent des ressources supplémentaires.
La méthode getRef() retourne une référence à une chaîne, qui est changé directement par
l'utilisateur de l'application. Ainsi, c'est une bonne idée d'utiliser la méthode getRef() pour le
traitement des données :

$memObject = $memoryManager->create($data);

$value = &$memObject->getRef();

for ($count = 0; $count < strlen($value); $count++) {


$char = $value[$count];
...
}

3.4.2. La méthode touch()

public function touch();

La méthode touch() devrait être employée en commun avec getRef(). Elle signale que la
valeur d'objet a été changé :

$memObject = $memoryManager->create($data);
...

$value = &$memObject->getRef();

for ($count = 0; $count < strlen($value); $count++) {


...
if ($condition) {
$value[$count] = $char;
}
...
}

1035
Zend_Memory

$memObject->touch();

3.4.3. La méthode lock()

public function lock();

La méthode lock() verrouille l'objet en mémoire. Elle devrait être utilisé pour empêcher la mise
en cache des objets que vous choisissez. Normalement, ce n'est pas nécessaire, parce que le
manager de mémoire utilise un algorithme intelligent pour choisir des candidats à la mise en
cache. Mais si vous savez exactement, qu'à cette endroit du code certains objets ne devraient
pas être mis en cache, vous pouvez les verrouiller.

Le verrouillage d'objets dans la mémoire garantit aussi que la référence retournée par la méthode
getRef() est valable jusqu'à ce que vous déverrouiller l'objet :

$memObject1 = $memoryManager->create($data1);
$memObject2 = $memoryManager->create($data2);
...

$memObject1->lock();
$memObject2->lock();

$value1 = &$memObject1->getRef();
$value2 = &$memObject2->getRef();

for ($count = 0; $count < strlen($value2); $count++) {


$value1 .= $value2[$count];
}

$memObject1->touch();
$memObject1->unlock();
$memObject2->unlock();

3.4.4. La méthode unlock()

public function unlock();

La méthode unlock() déverrouille l'objet quand il n'est plus nécessaire de maintenir verrouillé.
Voir l'exemple ci-dessus.

3.4.5. La méthode isLocked()

public function isLocked();

La méthode isLocked() peut être utilisée pour vérifier si l'objet est verrouillé. Il retourne TRUE
si l'objet est verrouillé, ou FALSE s'il n'est pas verrouillé. C'est toujours TRUE pour les objets
"verrouillés" et peut être TRUE ou FALSE pour des objets "mobiles".

1036
Zend_Mime
1. Zend_Mime
1.1. Introduction
Zend_Mime est une classe de support pour gérer les messages MIME en plusieurs parties. Elle
est utilisé par Zend_Mail et Zend_Mime_Message, est peut-être utilisée dans l'application qui
nécessite un support MIME.

1.2. Méthodes statiques et constantes


Zend_Mime fournit un jeu simple de méthodes statiques pour fonctionner avec MIME :

• Zend_Mime::isPrintable(): retourne TRUE si la chaine données contient des caractères


non imprimables. FALSE dans les autres cas.

• Zend_Mime::encode(): encode une chaîne en utilisant l'encodage spécifié.

• Zend_Mime::encodeBase64()encodeBase64(): encode une chaîne en utilisant base64.

• Zend_Mime::encodeQuotedPrintable(): encode une chaîne avec le mécanisme


quoted-printable.

• Zend_Mime::encodeBase64Header(): encode une chaîne en utilisant base64 pour les


entêtes émail.

• Zend_Mime::encodeQuotedPrintableHeader(): ncode une chaîne avec le mécanisme


quoted-printable pour les entêtes émail.

Zend_Mime définit un jeu de constantes communément utilisé avec des messages MIME :

• Zend_Mime::TYPE_OCTETSTREAM: "application/octet-stream"

• Zend_Mime::TYPE_TEXT: "text/plain"

• Zend_Mime::TYPE_HTML: "text/html"

• Zend_Mime::ENCODING_7BIT: "7bit"

• Zend_Mime::ENCODING_8BIT: "8bit"

• Zend_Mime::ENCODING_QUOTEDPRINTABLE: "quoted-printable"

• Zend_Mime::ENCODING_BASE64: "base64"

• Zend_Mime::DISPOSITION_ATTACHMENT: "attachment"

• Zend_Mime::DISPOSITION_INLINE: "inline"

• Zend_Mime::MULTIPART_ALTERNATIVE: 'multipart/alternative'

• Zend_Mime::MULTIPART_MIXED: 'multipart/mixed'

1037
Zend_Mime

• Zend_Mime::MULTIPART_RELATED: 'multipart/related'

1.3. Instancier Zend_Mime


Lors de l'instanciation d'un objet Zend_Mime, une frontière MIME est stockée pour qu'elle soit
utilisée pour tous les appels aux méthodes statiques suivant, sur cet objet. Si le constructeur est
appelé avec une chaîne en paramètre, cette valeur sera utilisée comme frontière MIME. Sinon,
une frontière MIME aléatoire sera générée lors de la construction.

Un objet Zend_Mime contient les méthodes suivantes :

• boundary(): retourne la frontière MIME.

• boundaryLine(): retourne la ligne complète de la frontière MIME.

• mimeEnd(): retourne la fin de la frontière MIME complète.

2. Zend_Mime_Message
2.1. Introduction
Zend_Mime_Message représente un message compatible MIME qui peut contenir une
ou plusieurs parties séparées (représentées par des objets Zend_Mime_Part) Avec
Zend_Mime_Message, les messages multiparts compatibles MIME peuvent être générés à
partir de Zend_Mime_Part. L'encodage et la gestion des frontières sont gérées de manière
transparente par la classe. Les objets Zend_Mime_Message peuvent aussi être reconstruits à
partir de chaînes de caractères données (expérimental). Utilisés par Zend_Mail.

2.2. Instancier Zend_Mime_Message


Il n'y a pas de constructeur explicite pour Zend_Mime_Message.

2.3. Ajouter des parties MIME


Les objets Zend_Mime_Part peuvent êtres ajoutés à un objet Zend_Mime_Message donné
en appelant ->addPart($part).

Un tableau avec toutes les objets Zend_Mime_Part du Zend_Mime_Message est retourné


dans un tableau grâce à ->getParts(). Les objets Zend_Mime_Part peuvent ainsi être
changés car ils sont stockés dans le tableau comme références. Si des parties sont ajoutées
au tableau, ou que la séquence est changée, le tableau à besoin d'être retourné à l'objet
Zend_Mime_Part en appelant ->setParts($partsArray).

La fonction ->isMultiPart() retournera TRUE si plus d'une partie est enregistrée avec l'objet
Zend_Mime_Message, l'objet pourra ainsi régénérer un objet Multipart-Mime-Message lors de
la génération de la sortie.

2.4. Gérer les frontières


Zend_Mime_Message crée et utilise généralement son propre objet Zend_Mime pour générer
une frontière. Si vous avez besoin de définir une frontière ou si vous voulez changer
le comportement de l'objet Zend_Mime utilisé par Zend_Mime_Message, vous pouvez
instancier l'objet Zend_Mime vous-même et l'enregistrer ensuite dans Zend_Mime_Message.

1038
Zend_Mime

Généralement, vous n'aurez pas besoin de faire cela. ->setMime(Zend_Mime $mime) définit
une instance spéciale de Zend_Mime pour qu'elle soit utilisée par ce Message.

->getMime() retourne l'instance de Zend_Mime qui sera utilisée pour générer le message
lorsque generateMessage() est appelée.

->generateMessage() génère le contenu ZZend_Mime_Message en une chaîne de


caractères.

2.5. Parser une chaîne de caractère pour créer un objet


Zend_Mime_Message (expérimental)
Un message compatible MIME donné sous forme de chaîne de caractère peut être utilisé pour
reconstruire un objet Zend_Mime_Message. Zend_Mime_Message a une méthode de fabrique
statique pour parser cette chaîne et retourner un objet Zend_Mime_Message.

Zend_Mime_Message::createFromMessage($str, $boundary) décode la chaîne de


caractères donnée et retourne un objet Zend_Mime_Message qui peut ensuite être examiné
en utilisant ->getParts().

3. Zend_Mime_Part
3.1. Introduction
Cette classe représente une seule partie d'un message MIME. Elle contient le contenu actuel
de la partie du message ainsi que des informations sur son encodage, le type de contenu
("content-type") et le nom de fichier original. Elle fournie une méthode pour générer une chaîne
de caractères à partir des données stockées. Les objets Zend_Mime_Part peuvent-être ajoutés
à Zend_Mime_Message pour assembler un message multipart complet.

3.2. Instanciation
Zend_Mime_Part est instanciée avec une chaîne de caractères qui représente le contenu de
cette nouvelle partie. Le type doit être OCTET-STREAM, et l'encodage 8 bits. Après instanciation
de Zend_Mime_Part, les métas-informations peuvent être définies en accédant directement
aux attributs :

public $type = Zend_Mime::TYPE_OCTETSTREAM;


public $encoding = Zend_Mime::ENCODING_8BIT;
public $id;
public $disposition;
public $filename;
public $description;
public $charset;
public $boundary;
public $location;
public $language;

3.3. Méthodes pour retourner la partie du message en une chaîne


de caractères
getContent() retourne le contenu encodé de MimePart en une chaîne de caractères
en utilisant l'encodage spécifié dans l'attribut $encoding. Les valeurs valides sont
Zend_Mime::ENCODING_*, les conversions de jeux de caractères ne sont pas effectuées.

1039
Zend_Mime

getHeaders() retourne les Mime-Headers d'un MimePart générés à partir des attributs
accessibles publiquement. Les attributs de l'objet doivent être paramétrés correctement avant
que cette méthode ne soit appelée.

• $charset doit définir l'encodage actuel du contenu, si c'est un type texte (Texte ou HTML).

• $id doit être défini pour identifier un content-id pour les images d'un mail HTML.

• $filename contient le nom que le fichier aura lors de son téléchargement.

• $disposition définit si le fichier doit être traité comme une pièce jointe ou s'il est inclus
dans le mail (HTML).

• $description sert uniquement pour information.

• $boundary définit une chaîne en tant que limite.

• $location peut être utilisé comme URI d'une ressource URI qui a une relation avec le
contenu.

• $language définit la langue du contenu.

1040
Zend_Navigation
1. Introduction
Zend_Navigation est un composant gérant arbres et menus pour les pages webs. Il permet
de créer des menus, des fils, des liens et des cartographies de sites (sitemaps), ou encore toute
autre représentation concernant la navigation.

1.1. Pages et Conteneurs


Deux concepts existent dans Zend_Navigation:

1.1.1. Pages
Une page (Zend_Navigation_Page) dans Zend_Navigation – dans sa forme la plus simple
– est un objet pointant vers une page web. En plus d'un pointeur vers une page web, l'objet page
contient d'autres informations utiles à la navigation comme un label, un titre title, etc.

Pour plus d'informations sur les pages, lisez leur section.

1.1.2. Conteneurs
Un conteneur de navigation (Zend_Navigation_Container) est une classe contenant
des pages. Elle possède des méthodes pour ajouter, supprimer, récupérer et itrérer au
travers de pages. Elle implémente les interfaces de la SPL RecursiveIterator et
Countable, et peuvent ainsi être parcourues avec les itérateurs de la SPL tels que
RecursiveIteratorIterator.

Pour plus d'informations sur les conteneurs, lisez leur section.

Zend_Navigation_Page étend Zend_Navigation_Container, ce qui


signifie qu'une page peut posséder des sous-pages.

1.2. Séparation des données (modèle) et du rendu (vue)


Les classes dans Zend_Navigation ne s'occupent pas du rendu visuel, celui-ci est effectué
par des aides de vue. Par contre, les pages peuvent contenir des informations utilisées par
les aides de vue comme un label (libellé), une classe CSS, un titre, des attributs lastmod et
priority pour les sitemaps, etc.

Pour plus d'informations sur le rendu des éléments, lisez leur section.

2. Pages
Zend_Navigation est fournie par défaut avec deux types de page:

• Pages MVC – utilisant la classe Zend_Navigation_Page_Mvc

• Pages URI – utilisant la classe Zend_Navigation_Page_Uri

Les pages MVC proposeront des liens pour l'application courante et utilisent les paramètres
MVC (action, controller, module, route, params). Les pages URI utilisent elles une seule
option,uri, ce qui vous offre la possibilité de créer des liens vers des sites externes ou encore
de créer des liens personnalisés comme par exemple <a href="#">foo<a>.

1041
Zend_Navigation

2.1. Caractéristiques communes aux pages


Toutes les classes pour des pages doivent étendre Zend_Navigation_Page, elles partageront
ainsi des caractéristiques communes. Ces options sont représentées dans le tableau ci-après.

Les noms des options (en clés) sont dirigées vers les setters appropriés set. Ceci signifie
qu'une option appelée order sera passée à la méthode setOrder(), et une option
nommée reset_params sera dirigée vers setResetParams(). Si aucune méthode setter ne
correspond, l'option sera alors évaluée comme un attribut personnalisé de la page.

Documentez vous au sujet de la création de pages Zend_Navigation_Page dans la


documentation appropriée.

Tableau 106. Options communes aux pages


Clé Type Valeur par défaut Description
label chaine NULL Un nom de page,
comme 'Home' ou
'Blog'.
id chaine | entier NULL Un tag id à utiliser
lors du rendu de
la page, typiquement
pour repérer un
élément.
class chaine NULL Une classe CSS à
utiliser lors du rendu de
la page.
title chaine NULL Un titre de page
utilisé lors du rendu,
utilisé typiquement
sous forme d'attribut
title.
target chaine NULL La cible à utiliser dans
la page.
rel tableau array() Attribue les relations
de la page. Chaque
élément dans le
tableau est une paire
clé-valeur où la clé
désigne le type de
relation et la valeur
un pointeur vers la
page. Par exemple
'alternate' =>
'format/
plain.html'. Pour
une fléxibilité
maximale, il n'y a pas
de restrictions quant
aux valeurs, elles
peuvent être autre
chose qu'une chaine.
Concernant rel et

1042
Zend_Navigation

Clé Type Valeur par défaut Description


rev, voyez la section
de documentation sur
l'aide de vue Links..
rev tableau array() Spécifie les relations
inverses de la
page. Fonctionne tout
comme rel.
order chaine | entier | NULL Fonctionne comme
NULL order pour les
éléments de
Zend_Form. Si
spécifiée, la page
sera parcourue dans
un ordre précis ce
qui signifie que vous
pouvez forcer la page
à apparaitre avant
les autres en utilisant
une valeur de order
basse, comme -100. Si
une chaine est passée,
elle doit pouvoir être
convertie en entier.
Si NULL est utilisé, le
paramètre sera remis
à zéro, donc l'ordre
dans lequel la page a
été ajoutée sera utilisé.
resource chaine | NULL Une ressource d'ACL
Zend_Acl_Resource_Interface à associer à la
| NULL page. Voyez la
documentation de la
section sur les ACL
concernant les aides
de vue..
privilege chaine | NULL NULL Un privilège d'ACL
à associer à la
page. Voyez la
documentation de la
section sur les ACL
concernant les aides
de vue..
active booléen FALSE Si oui ou non la page
doit être considérée
comme active. Si
à FALSE (ou non
fourni), les pages
MVC vont aller vérifier
l'objet requête suite

1043
Zend_Navigation

Clé Type Valeur par défaut Description


à l'appel à $page-
>isActive().
visible booléen TRUE Si oui ou non
la page doit être
visible à l'utilisateur
ou juste présente
dans la structure
mais non représentée
visuellement.
pages tableau | NULL Pages enfant de la
Zend_Config | NULL page en cours. Peut
être de type tableau
ou Zend_Config
contenant des options
à passer à la
méthode factory()
ou des instances de
Zend_Navigation_Page,
ou un mélange des
deux types.

Propriétés personnalisées
Toutes les pages supportent la gestion de propriétés personnalisées, ceci
via les méthodes magiques __set($name, $value), __get($name),
__isset($name) et __unset($name). Ces propriétés peuvent prendre
n'importe quelle valeur et seront incluses dans le tableau retourné par $page-
>toArray(), ce qui signifie que les pages peuvent être dé/sérialisées même si
elles comportent des propriétés non natives à leur classe.

Que les pages soient natives ou personnalisées par vos soins, les propriétés
peuvent être gérées au moyen des méthodes $page->set($name, $value)
et $page->get($name), ou encore via des méthodes magiques.

Exemple 556. Propriétés de pages personnalisées

Cet exemple montre comment les propriétés personnalisées des pages peuvent être
utilisées.

$page = new Zend_Navigation_Page_Mvc();


$page->foo = 'bar';
$page->meaning = 42;

echo $page->foo;

if ($page->meaning != 42) {
// quelque chose à faire ici
}

2.2. Zend_Navigation_Page_Mvc
Les pages de type MVC utilisent des paramètres MVC issus du composant Zend_Controller.
Une page MVC utilisera en interne Zend_Controller_Action_Helper_Url dans la

1044
Zend_Navigation

méthode getHref() pour générer des cibles (hrefs), et la méthode isActive() utilisera
les paramètres issus de Zend_Controller_Request_Abstract et les comparera aux
paramètres internes à la page.

Tableau 107. Options des pages de type MV

Clé Type Valeur par défaut Description


action chaine NULL Nom de l'action pour
générer des cibles
vers la page.
controller chaine NULL Nom du contrôleur
pour générer des
cibles vers la page.
module chaine NULL Nom du module pour
générer des cibles
vers la page.
params Array array() Paramètres
utilisateurs pour
générer des cibles
vers la page.
route chaine NULL Nom de la route à
utiliser pour générer
des cibles vers la
page.
reset_params bool TRUE Remettre à zéro les
paramètres de la route
ou non.

Les trois exemples qui suivent supposent une configuration MVC par défaut, avec
une route default.

L'URI retournée est relative au baseUrl de Zend_Controller_Front. Dans


nos exemples, le baseUrl vaut '/' pour simplifier.

1045
Zend_Navigation

Exemple 557. getHref() génères les URI de la page

Cet exemple montre que les pages de type MVC utilisent


Zend_Controller_Action_Helper_Url en interne pour générer les URIs suite à
l'appel à $page->getHref().

// getHref() retourne /
$page = new Zend_Navigation_Page_Mvc(array(
'action' => 'index',
'controller' => 'index'
));

// getHref() retourne /blog/post/view


$page = new Zend_Navigation_Page_Mvc(array(
'action' => 'view',
'controller' => 'post',
'module' => 'blog'
));

// getHref() retourne /blog/post/view/id/1337


$page = new Zend_Navigation_Page_Mvc(array(
'action' => 'view',
'controller' => 'post',
'module' => 'blog',
'params' => array('id' => 1337)
));

1046
Zend_Navigation

Exemple 558. isActive() détermine si la page est active

Cet exemple montre que les pages de type MVC utilisent l'objet de requête afin de
déterminer si elles sont actives ou non.

/*
* Requête dispatchée:
* - module: default
* - controller: index
* - action: index
*/
$page1 = new Zend_Navigation_Page_Mvc(array(
'action' => 'index',
'controller' => 'index'
));

$page2 = new Zend_Navigation_Page_Mvc(array(


'action' => 'bar',
'controller' => 'index'
));

$page1->isActive(); // retourne true


$page2->isActive(); // retourne false

/*
* Requête dispatchée:
* - module: blog
* - controller: post
* - action: view
* - id: 1337
*/
$page = new Zend_Navigation_Page_Mvc(array(
'action' => 'view',
'controller' => 'post',
'module' => 'blog'
));

// retourne true, car la requpete a le même trio module/controller/action


$page->isActive();

/*
* Requête dispatchée:
* - module: blog
* - controller: post
* - action: view
*/
$page = new Zend_Navigation_Page_Mvc(array(
'action' => 'view',
'controller' => 'post',
'module' => 'blog',
'params' => array('id' => null)
));

// retourne false, car page a besoin du paramètre id dans la requête


$page->isActive(); // retourne false

1047
Zend_Navigation

Exemple 559. Utiliser les routes

Les routes sont utilisables dans les pages de type MVC. Si une page a une route, elle sera
utilisée par getHref() pour générer l'URL de la page.

Notez que si vous utilisez le paramètre route, vous devrez


préciser les paramètres par défaut de la route (module, controller,
action, etc.), autremant isActive() ne pourra déterminer si la
page est active ou pas. La raison est qu'il n'existe actuellement
aucune méthode permettant de récupérer les paramètres par défaut
d'une route un objet Zend_Controller_Router_Route_Interface,
ni même de récupérer la route courante depuis un objet
Zend_Controller_Router_Interface.

// La route suivante est ajoutée au routeur de ZF


Zend_Controller_Front::getInstance()->getRouter()->addRoute(
'article_view', // nom de la route
new Zend_Controller_Router_Route(
'a/:id',
array(
'module' => 'news',
'controller' => 'article',
'action' => 'view',
'id' => null
)
)
);

// Une page est créee avec un paramètre 'route'


$page = new Zend_Navigation_Page_Mvc(array(
'label' => 'A news article',
'route' => 'article_view',
'module' => 'news', // requis pour isActive(), voyez les notes ci-dessus
'controller' => 'article', // requis pour isActive(), voyez les notes ci-dessus
'action' => 'view', // requis pour isActive(), voyez les notes ci-dessus
'params' => array('id' => 42)
));

// retourne: /a/42
$page->getHref();

2.3. Zend_Navigation_Page_Uri
Les pages de type Zend_Navigation_Page_Uri peuvent être utilisées pour pointer vers des
sites externes, ou des pages internes personnalisées. Les pages URI sont simples, en plus
des options classiques des pages, les pages URI utilisent une seule option : uri. L' uri sera
retourné à l'appel de $page->getHref() et retournera une chaine ou NULL.

Zend_Navigation_Page_Uri ne pourra pas calculer elle même si elle est


active ou pas suite à un appel à $page->isActive(). L'appel retournera la
valeur que vous aurez spécifier vous-mêmes grâce à $page->setActive()
ou via l'option de constructeur active.

1048
Zend_Navigation

Tableau 108. URI page options

Clé Type Valeur par défaut Description


uri chaine NULL URI vers la page. Une
chaine, ou NULL.

2.4. Créer des pages de type personnalisé


Etendre Zend_Navigation_Page ne nécessite pas forcément de réécrire le constructeur ou
les méthodes setOptions() ou setConfig(). Le constructeur prend un seul paramètre
de type Array ou Zend_Config et il est passé à setOptions() ou setConfig()
respectivement. Ces méthodes appellerons par la suite les setters set() qui distribueront leurs
options. Si l'option internal_id est présente, alors la méthode setInternalId() sera
évaluée si présente, et l'option en question lui sera passée. Si une telle méthode n'existe pas,
l'option sera alors vue comme une propriété de la page et sera accessible sous $internalId
= $page->internal_id; ou $internalId = $page->get('internal_id');.

Exemple 560. La page personnalisée la plus simple possible

La seule chose à définir dans une page personnalisée est la méthode getHref().

class My_Simple_Page extends Zend_Navigation_Page


{
public function getHref()
{
return 'Quelquechose-ici--ce-que-je-veux';
}
}

1049
Zend_Navigation

Exemple 561. Une page personnalisée avec des propriétés

Ajouter des propriétés à vos pages étendues ne nécessite pas de réécrire setOptions()
ou setConfig().

class My_Navigation_Page extends Zend_Navigation_Page


{
private $_foo;
private $_fooBar;

public function setFoo($foo)


{
$this->_foo = $foo;
}

public function getFoo()


{
return $this->_foo;
}

public function setFooBar($fooBar)


{
$this->_fooBar = $fooBar;
}

public function getFooBar()


{
return $this->_fooBar;
}

public function getHref()


{
return $this->foo . '/' . $this->fooBar;
}
}

// can now construct using


$page = new My_Navigation_Page(array(
'label' => 'Les noms des propriétés sont dirigés vers les setters',
'foo' => 'bar',
'foo_bar' => 'baz'
));

// ...or
$page = Zend_Navigation_Page::factory(array(
'type' => 'My_Navigation_Page',
'label' => 'Les noms des propriétés sont dirigés vers les setters',
'foo' => 'bar',
'foo_bar' => 'baz'
));

2.5. Créer des pages avec la fabrique


Toute les pages (même les personnalisées) peuvent petre créer via la fabrique
Zend_Navigation_Page::factory(). Celle-ci peut prendre un tableau d'options ou un
objet Zend_Config. Chaque clé correspondant à une option de l'obet page à créer comme
l'indique la section concernant les Pages. Si le paramètre uri est passé et qu'aucun paramètre
concernant MVC ne sont présents (action, controller, module, route), une page de

1050
Zend_Navigation

type URI sera créee. Si un ou plusieurs paramètres concernant MVC sont passés, une page de
type MVC sera retournée.

Si le paramètre type est passé, la fabrique l'utilisera pour déterminer le nom de la classe à
utiliser. Les valeurs mvc ou uri créeront des pages de types MVC/URI.

Exemple 562. Créer une page MVC avec la fabrique

$page = Zend_Navigation_Page::factory(array(
'label' => 'My MVC page',
'action' => 'index'
));

$page = Zend_Navigation_Page::factory(array(
'label' => 'Search blog',
'action' => 'index',
'controller' => 'search',
'module' => 'blog'
));

$page = Zend_Navigation_Page::factory(array(
'label' => 'Home',
'action' => 'index',
'controller' => 'index',
'module' => 'index',
'route' => 'home'
));

$page = Zend_Navigation_Page::factory(array(
'type' => 'mvc',
'label' => 'My MVC page'
));

Exemple 563. Créer une page URI avec la fabrique

$page = Zend_Navigation_Page::factory(array(
'label' => 'My URI page',
'uri' => 'http://www.example.com/'
));

$page = Zend_Navigation_Page::factory(array(
'label' => 'Search',
'uri' => 'http://www.example.com/search',
'active' => true
));

$page = Zend_Navigation_Page::factory(array(
'label' => 'My URI page',
'uri' => '#'
));

$page = Zend_Navigation_Page::factory(array(
'type' => 'uri',
'label' => 'My URI page'
));

1051
Zend_Navigation

Exemple 564. Créer une page personnalisée avec la fabrique

Utilisez l'option type afin de nommer la classe à utiliser.

class My_Navigation_Page extends Zend_Navigation_Page


{
protected $_fooBar = 'ok';

public function setFooBar($fooBar)


{
$this->_fooBar = $fooBar;
}
}

$page = Zend_Navigation_Page::factory(array(
'type' => 'My_Navigation_Page',
'label' => 'My custom page',
'foo_bar' => 'foo bar'
));

3. Containers
Containers have methods for adding, retrieving, deleting and iterating pages. Containers
implement the SPL interfaces RecursiveIterator and Countable, meaning that a container
can be iterated using the SPL RecursiveIteratorIterator class.

3.1. Creating containers


Zend_Navigation_Container is abstract, and can not be instantiated directly. Use
Zend_Navigation if you want to instantiate a container.

Zend_Navigation can be constructed entirely empty, or take an array or a Zend_Config


object with pages to put in the container. Each page in the given array/config will eventually be
passed to the addPage() method of the container class, which means that each element in the
array/config can be an array or a config object, or a Zend_Navigation_Page instance.

1052
'label' => 'Page 5.1',
'uri' => '#',
'pages' => array(
array(
Zend_Navigation
'label' => 'Page 5.1.1',
'uri' => '#',
'pages' => array(
array(
Exemple 565. Creating a container using an array
'label' => 'Page 5.1.2',
'uri' => '#',
// let's say this page is active
'active' => true
)
)
)
)
)
)
),
array(
'label' => 'ACL page 1 (guest)',
'uri' => '#acl-guest',
'resource' => 'nav-guest',
'pages' => array(
array(
'label' => 'ACL page 1.1 (foo)',
'uri' => '#acl-foo',
'resource' => 'nav-foo'
),
array(
'label' => 'ACL page 1.2 (bar)',
'uri' => '#acl-bar',
'resource' => 'nav-bar'
),
array(
'label' => 'ACL page 1.3 (baz)',
'uri' => '#acl-baz',
'resource' => 'nav-baz'
),
array(
'label' => 'ACL page 1.4 (bat)',
'uri' => '#acl-bat',
'resource' => 'nav-bat'
)
)
),
array(
'label' => 'ACL page 2 (member)',
'uri' => '#acl-member',
'resource' => 'nav-member'
),
array(
'label' => 'ACL page 3 (admin',
'uri' => '#acl-admin',
'resource' => 'nav-admin',
'pages' => array(
array(
'label' => 'ACL page 3.1 (nothing)',
'uri' => '#acl-nada'
)
)
),
array(
'label' => 'Zend Framework',
'route' => 'zf-route'
)
));

1053
<uri>page3</uri>
<pages>

<page3_1>
Zend_Navigation
<label>Page 3.1</label>
<uri>page3/page3_1</uri>
<resource>guest</resource>
</page3_1>
Exemple 566. Creating a container using a config object
<page3_2>
<label>Page 3.2</label>
<uri>page3/page3_2</uri>
<resource>member</resource>
<pages>

<page3_2_1>
<label>Page 3.2.1</label>
<uri>page3/page3_2/page3_2_1</uri>
</page3_2_1>

<page3_2_2>
<label>Page 3.2.2</label>
<uri>page3/page3_2/page3_2_2</uri>
<resource>admin</resource>
</page3_2_2>

</pages>
</page3_2>

<page3_3>
<label>Page 3.3</label>
<uri>page3/page3_3</uri>
<resource>special</resource>
<pages>

<page3_3_1>
<label>Page 3.3.1</label>
<uri>page3/page3_3/page3_3_1</uri>
<visible>0</visible>
</page3_3_1>

<page3_3_2>
<label>Page 3.3.2</label>
<uri>page3/page3_3/page3_3_2</uri>
<resource>admin</resource>
</page3_3_2>

</pages>
</page3_3>

</pages>
</page3>

<home>
<label>Home</label>
<order>-100</order>
<module>default</module>
<controller>index</controller>
<action>index</action>
</home>

</nav>
</config>
*/

$config = new Zend_Config_Xml('/path/to/navigation.xml', 'nav');


$container = new Zend_Navigation($config);

1054
Zend_Navigation

3.2. Adding pages


Adding pages to a container can be done with the methods addPage(), addPages(), or
setPages(). See examples below for explanation.

Exemple 567. Adding pages to a container

// create container
$container = new Zend_Navigation();

// add page by giving a page instance


$container->addPage(Zend_Navigation_Page::factory(array(
'uri' => 'http://www.example.com/'
)))

// add page by giving an array


$container->addPage(array(
'uri' => 'http://www.example.com/'
)))

// add page by giving a config object


$container->addPage(new Zend_Config(array(
'uri' => 'http://www.example.com/'
)))

$pages = array(
array(
'label' => 'Save'
'action' => 'save',
),
array(
'label' => 'Delete',
'action' => 'delete'
)
);

// add two pages


$container->addPages($pages);

// remove existing pages and add the given pages


$container->setPages($pages);

3.3. Removing pages


Removing pages can be done with removePage() or removePages(). The first method
accepts a an instance of a page, or an integer. The integer corresponds to the order a page
has. The latter method will remove all pages in the container.

1055
Zend_Navigation

Exemple 568. Removing pages from a container

$container = new Zend_Navigation(array(


array(
'label' => 'Page 1',
'action' => 'page1'
),
array(
'label' => 'Page 2',
'action' => 'page2',
'order' => 200
),
array(
'label' => 'Page 3',
'action' => 'page3'
)
));

// remove page by implicit page order


$container->removePage(0); // removes Page 1

// remove page by instance


$page3 = $container->findOneByAction('Page 3');
$container->removePage($page3); // removes Page 3

// remove page by explicit page order


$container->removePage(200); // removes Page 2

// remove all pages


$container->removePages(); // removes all pages

3.4. Finding pages


Containers have finder methods for retrieving pages. They are findOneBy($property,
$value), findAllBy($property, $value), and findBy($property, $value, $all
= false). Those methods will recursively search the container for pages matching the given
$page->$property == $value. The first method, findOneBy(), will return a single page
matching the property with the given value, or NULL if it cannot be found. The second method
will return all pages with a property matching the given value. The third method will call one of
the two former methods depending on the $all flag.

The finder methods can also be used magically by appending the property name to findBy,
findOneBy, or findAllBy, e.g. findOneByLabel('Home') to return the first matching
page with label Home. Other combinations are findByLabel(...), findOnyByTitle(...),
findAllByController(...), etc. Finder methods also work on custom properties, such as
findByFoo('bar').

1056
array(
'label' => 'Page 1.2',
'uri' => 'page-1.2',
'class' => 'my-class',
), Zend_Navigation
array(
'type' => 'uri',
'label' => 'Page 1.3',
Exemple 569. Finding pages in a container
'uri' => 'page-1.3',
'action' => 'about'
)
)
),
array(
'label' => 'Page 2',
'id' => 'page_2_and_3',
'class' => 'my-class',
'module' => 'page2',
'controller' => 'index',
'action' => 'page1'
),
array(
'label' => 'Page 3',
'id' => 'page_2_and_3',
'module' => 'page3',
'controller' => 'index'
)
));

// The 'id' is not required to be unique, but be aware that


// having two pages with the same id will render the same id attribute
// in menus and breadcrumbs.
$found = $container->findBy('id',
'page_2_and_3'); // returns Page 2
$found = $container->findOneBy('id',
'page_2_and_3'); // returns Page 2
$found = $container->findBy('id',
'page_2_and_3',
true); // returns Page 2 and Page 3
$found = $container->findById('page_2_and_3'); // returns Page 2
$found = $container->findOneById('page_2_and_3'); // returns Page 2
$found = $container->findAllById('page_2_and_3'); // returns Page 2 and Page 3

// Find all matching CSS class my-class


$found = $container->findAllBy('class',
'my-class'); // returns Page 1.2 and Page 2
$found = $container->findAllByClass('my-class'); // returns Page 1.2 and Page 2

// Find first matching CSS class my-class


$found = $container->findOneByClass('my-class'); // returns Page 1.2

// Find all matching CSS class non-existant


$found = $container->findAllByClass('non-existant'); // returns array()

// Find first matching CSS class non-existant


$found = $container->findOneByClass('non-existant'); // returns null

// Find all pages with custom property 'foo' = 'bar'


$found = $container->findAllBy('foo', 'bar'); // returns Page 1 and Page 1.1

// To achieve the same magically, 'foo' must be in lowercase.


// This is because 'foo' is a custom property, and thus the
// property name is not normalized to 'Foo'
$found = $container->findAllByfoo('bar');

// Find all with controller = 'index'


$found = $container->findAllByController('index'); // returns Page 2 and Page 3

1057
Zend_Navigation

3.5. Iterating containers


Zend_Navigation_Container implements RecursiveIteratorIterator, and can
be iterated using any Iterator class. To iterate a container recursively, use the
RecursiveIteratorIterator class.

Exemple 570. Iterating a container

/*
* Create a container from an array
*/
$container = new Zend_Navigation(array(
array(
'label' => 'Page 1',
'uri' => '#'
),
array(
'label' => 'Page 2',
'uri' => '#',
'pages' => array(
array(
'label' => 'Page 2.1',
'uri' => '#'
),
array(
'label' => 'Page 2.2',
'uri' => '#'
)
)
)
array(
'label' => 'Page 3',
'uri' => '#'
)
));

// Iterate flat using regular foreach:


// Output: Page 1, Page 2, Page 3
foreach ($container as $page) {
echo $page->label;
}

// Iterate recursively using RecursiveIteratorIterator


$it = new RecursiveIteratorIterator(
$container, RecursiveIteratorIterator::SELF_FIRST);

// Output: Page 1, Page 2, Page 2.1, Page 2.2, Page 3


foreach ($it as $page) {
echo $page->label;
}

3.6. Other operations


The method hasPage(Zend_Navigation_Page $page) checks if the container has the
given page. The method hasPages() checks if there are any pages in the container, and is
equivalent to count($container) > 1.

1058
Zend_Navigation

The toArray() method converts the container and the pages in it to an array. This can be
useful for serializing and debugging.

1059
["pages"]=> array(0) {
}
["uri"]=> string(1) "#"
}
[1]=> array(15) { Zend_Navigation
["label"]=> string(6) "Page 2"
["id"]=> NULL
["class"]=> NULL
Exemple 571. Converting a container to an array
["title"]=> NULL
["target"]=> NULL
["rel"]=> array(0) {
}
["rev"]=> array(0) {
}
["order"]=> NULL
["resource"]=> NULL
["privilege"]=> NULL
["active"]=> bool(false)
["visible"]=> bool(true)
["type"]=> string(23) "Zend_Navigation_Page_Uri"
["pages"]=> array(2) {
[0]=> array(15) {
["label"]=> string(8) "Page 2.1"
["id"]=> NULL
["class"]=> NULL
["title"]=> NULL
["target"]=> NULL
["rel"]=> array(0) {
}
["rev"]=> array(0) {
}
["order"]=> NULL
["resource"]=> NULL
["privilege"]=> NULL
["active"]=> bool(false)
["visible"]=> bool(true)
["type"]=> string(23) "Zend_Navigation_Page_Uri"
["pages"]=> array(0) {
}
["uri"]=> string(1) "#"
}
[1]=>
array(15) {
["label"]=> string(8) "Page 2.2"
["id"]=> NULL
["class"]=> NULL
["title"]=> NULL
["target"]=> NULL
["rel"]=> array(0) {
}
["rev"]=> array(0) {
}
["order"]=> NULL
["resource"]=> NULL
["privilege"]=> NULL
["active"]=> bool(false)
["visible"]=> bool(true)
["type"]=> string(23) "Zend_Navigation_Page_Uri"
["pages"]=> array(0) {
}
["uri"]=> string(1) "#"
}
}
["uri"]=> string(1) "#"
}
}
*/

1060
Zend_Oauth
1. Introduction to OAuth
OAuth allows you to approve access by any application to your private data stored a website
without being forced to disclose your username or password. If you think about it, the practice of
handing over your username and password for sites like Yahoo Mail or Twitter has been endemic
for quite a while. This has raised some serious concerns because there's nothing to prevent
other applications from misusing this data. Yes, some services may appear trustworthy but that
is never guaranteed. OAuth resolves this problem by eliminating the need for any username and
password sharing, replacing it with a user controlled authorization process.

This authorization process is token based. If you authorize an application (and by application we
can include any web based or desktop application) to access your data, it will be in receipt of
an Access Token associated with your account. Using this Access Token, the application can
access your private data without continually requiring your credentials. In all this authorization
delegation style of protocol is simply a more secure solution to the problem of accessing private
data via any web service API.

OAuth is not a completely new idea, rather it is a standardized protocol building on the existing
properties of protocols such as Google AuthSub, Yahoo BBAuth, Flickr API, etc. These all
to some extent operate on the basis of exchanging user credentials for an Access Token of
some description. The power of a standardized specification like OAuth is that it only requires
a single implementation as opposed to many disparate ones depending on the web service.
This standardization has not occurred independently of the major players, and indeed many now
support OAuth as an alternative and future replacement for their own solutions.

Zend Framework's Zend_Oauth currently implements a full OAuth Consumer conforming to the
OAuth Core 1.0 Revision A Specification (24 June 2009) via the Zend_Oauth_Consumer class.

1.1. Protocol Workflow


Before implementing OAuth it makes sense to understand how the protocol operates. To do so
we'll take the example of Twitter which currently implements OAuth based on the OAuth Core
1.0 Revision A Specification. This example looks at the protocol from the perspectives of the
User (who will approve access), the Consumer (who is seeking access) and the Provider (who
holds the User's private data). Access may be read-only or read and write.

By chance, our User has decided that they want to utilise a new service called TweetExpress
which claims to be capable of reposting your blog posts to Twitter in a manner of seconds.
TweetExpress is a registered application on Twitter meaning that it has access to a Consumer
Key and a Consumer Secret (all OAuth applications must have these from the Provider they will
be accessing) which identify its requests to Twitter and that ensure all requests can be signed
using the Consumer Secret to verify their origin.

To use TweetExpress you are asked to register for a new account, and after your registration is
confirmed you are informed that TweetExpress will seek to associate your Twitter account with
the service.

In the meantime TweetExpress has been busy. Before gaining your approval from Twitter, it has
sent a HTTP request to Twitter's service asking for a new unauthorized Request Token. This
token is not User specific from Twitter's perspective, but TweetExpress may use it specifically
for the current User and should associate it with their account and store it for future use.

1061
Zend_Oauth

TweetExpress now redirects the User to Twitter so they can approve TweetExpress' access. The
URL for this redirect will be signed using TweetExpress' Consumer Secret and it will contain the
unauthorized Request Token as a parameter.

At this point the User may be asked to log into Twitter and will now be faced with a Twitter screen
asking if they approve this request by TweetExpress to access Twitter's API on the User's behalf.
Twitter will record the response which we'll assume was positive. Based on the User's approval,
Twitter will record the current unauthorized Request Token as having been approved by the User
(thus making it User specific) and will generate a new value in the form of a verification code.
The User is now redirected back to a specific callback URL used by TweetExpress (this callback
URL may be registered with Twitter or dynamically set using an oauth_callback parameter in
requests). The redirect URL will contain the newly generated verification code.

TweetExpress' callback URL will trigger an examination of the response to determine whether the
User has granted their approval to Twitter. Assuming so, it may now exchange it's unauthorized
Request Token for a fully authorized Access Token by sending a request back to Twitter including
the Request Token and the received verification code. Twitter should now send back a response
containing this Access Token which must be used in all requests used to access Twitter's API
on behalf of the User. Twitter will only do this once they have confirmed the attached Request
Token has not already been used to retrieve another Access Token. At this point, TweetExpress
may confirm the receipt of the approval to the User and delete the original Request Token which
is no longer needed.

From this point forward, TweetExpress may use Twitter's API to post new tweets on the User's
behalf simply by accessing the API endpoints with a request that has been digitally signed (via
HMAC-SHA1) with a combination of TweetExpress' Consumer Secret and the Access Key being
used.

Although Twitter do not currently expire Access Tokens, the User is free to deauthorize
TweetExpress from their Twitter account settings. Once deauthorized, TweetExpress' access
will be cut off and their Access Token rendered invalid.

1.2. Security Architecture


OAuth was designed specifically to operate over an insecure HTTP connection and so the use
of HTTPS is not required though obviously it would be desireable if available. Should a HTTPS
connection be feasible, OAuth offers a signature method implementation called PLAINTEXT
which may be utilised. Over a typical unsecured HTTP connection, the use of PLAINTEXT must
be avoided and an alternate scheme using. The OAuth specification defines two such signature
methods: HMAC-SHA1 and RSA-SHA1. Both are fully supported by Zend_Oauth.

These signature methods are quite easy to understand. As you can imagine, a PLAINTEXT
signature method does nothing that bears mentioning since it relies on HTTPS. If you were to
use PLAINTEXT over HTTP, you are left with a significant problem: there's no way to be sure that
the content of any OAuth enabled request (which would include the OAuth Access Token) was
altered en route. This is because unsecured HTTP requests are always at risk of eavesdropping,
Man In The Middle (MITM) attacks, or other risks whereby a request can be retooled so to speak
to perform tasks on behalf of the attacker by masquerading as the origin application without being
noticed by the service provider.

HMAC-SHA1 and RSA-SHA1 alleviate this risk by digitally signing all OAuth requests with the
original application's registered Consumer Secret. Assuming only the Consumer and the Provider
know what this secret is, a middle-man can alter requests all they wish - but they will not be
able to validly sign them and unsigned or invalidly signed requests would be discarded by both
parties. Digital signatures therefore offer a guarantee that validly signed requests do come from

1062
Zend_Oauth

the expected party and have not been altered en route. This is the core of why OAuth can operate
over an unsecure connection.

How these digital signatures operate depends on the method used, i.e. HMAC-SHA1, RSA-SHA1
or perhaps another method defined by the service provider. HMAC-SHA1 is a simple mechanism
which generates a Message Authentication Code (MAC) using a cryptographic hash function (i.e.
SHA1) in combination with a secret key known only to the message sender and receiver (i.e. the
OAuth Consumer Secret and the authorized Access Key combined). This hashing mechanism
is applied to the parameters and content of any OAuth requests which are concatenated into a
"base signature string" as defined by the OAuth specification.

RSA-SHA1 operates on similar principles except that the shared secret is, as you would expect,
each parties' RSA private key. Both sides would have the other's public key with which to verify
digital signatures. This does pose a level of risk compared to HMAC-SHA1 since the RSA method
does not use the Access Key as part of the shared secret. This means that if the RSA private
key of any Consumer is compromised, then all Access Tokens assigned to that Consumer are
also. RSA imposes an all or nothing scheme. In general, the majority of service providers offering
OAuth authorization have therefore tended to use HMAC-SHA1 by default, and those who offer
RSA-SHA1 may offer fallback support to HMAC-SHA1.

While digital signatures add to OAuth's security they are still vulnerable to other forms of attack,
such as replay attacks which copy earlier requests which were intercepted and validly signed at
that time. An attacker can now resend the exact same request to a Provider at will at any time
and intercept its results. This poses a significant risk but it is quiet simple to defend against -
add a unique string (i.e. a nonce) to all requests which changes per request (thus continually
changing the signature string) but which can never be reused because Providers actively track
used nonces within the a certain window defined by the timestamp also attached to a request.
You might first suspect that once you stop tracking a particular nonce, the replay could work but
this ignore the timestamp which can be used to determine a request's age at the time it was
validly signed. One can assume that a week old request used in an attempted replay should be
summarily discarded!

As a final point, this is not an exhaustive look at the security architecture in OAuth. For example,
what if HTTP requests which contain both the Access Token and the Consumer Secret are
eavesdropped? The system relies on at one in the clear transmission of each unless HTTPS
is active, so the obvious conclusion is that where feasible HTTPS is to be preferred leaving
unsecured HTTP in place only where it is not possible or affordable to do so.

1.3. Getting Started


With the OAuth protocol explained, let's show a simple example of it with source code. Our new
Consumer will be handling Twitter Status submissions. To do so, it will need to be registered with
Twitter in order to receive an OAuth Consumer Key and Consumer Secret. This are utilised to
obtain an Access Token before we use the Twitter API to post a status message.

Assuming we have obtained a key and secret, we can start the OAuth workflow by setting up
a Zend_Oauth_Consumer instance as follows passing it a configuration (either an array or
Zend_Config object).

$config = array(
'callbackUrl' => 'http://example.com/callback.php',
'siteUrl' => 'http://twitter.com/oauth',
'consumerKey' => 'gg3DsFTW9OU9eWPnbuPzQ',
'consumerSecret' => 'tFB0fyWLSMf74lkEu9FTyoHXcazOWpbrAjTCCK48A'
);
$consumer = new Zend_Oauth_Consumer($config);

1063
Zend_Oauth

The callbackUrl is the URI we want Twitter to request from our server when sending information.
We'll look at this later. The siteUrl is the base URI of Twitter's OAuth API endpoints. The full list of
endpoints include http://twitter.com/oauth/request_token, http://twitter.com/oauth/access_token,
and http://twitter.com/oauth/authorize. The base siteUrl utilises a convention which maps to
these three OAuth endpoints (as standard) for requesting a request token, access token or
authorization. If the actual endpoints of any service differ from the standard set, these three URIs
can be separately set using the methods setRequestTokenUrl(), setAccessTokenUrl(),
and setAuthorizeUrl() or the configuration fields requestTokenUrl, accessTokenUrl and
authorizeUrl.

The consumerKey and consumerSecret are retrieved from Twitter when your application is
registered for OAuth access. These also apply to any OAuth enabled service, so each one will
provide a key and secret for your application.

All of these configuration options may be set using method calls simply by converting from, e.g.
callbackUrl to setCallbackUrl().

In addition, you should note several other configuration values not explicitly used:
requestMethod and requestScheme. By default, Zend_Oauth_Consumer sends
requests as POST (except for a redirect which uses GET). The customised client
(see later) also includes its authorization by way of a header. Some services may,
at their discretion, require alternatives. You can reset the requestMethod (which
defaults to Zend_Oauth::POST) to Zend_Oauth::GET, for example, and reset the
requestScheme from its default of Zend_Oauth::REQUEST_SCHEME_HEADER to one of
Zend_Oauth::REQUEST_SCHEME_POSTBODY or
Zend_Oauth::REQUEST_SCHEME_QUERYSTRING. Typically the defaults should work fine
apart from some exceptional cases. Please refer to the service provider's documentation for
more details.

The second area of customisation is how HMAC operates when calculating/comparing


them for all requests. This is configured using the signatureMethod configuration field or
setSignatureMethod() . By default this is HMAC-SHA1. You can set it also to a provider's
preferred method including RSA-SHA1. For RSA-SHA1, you should also configure RSA
private and public keys via the rsaPrivateKey and rsaPublicKey configuration fields or the
setRsaPrivateKey() and setRsaPublicKey() methods.

The first part of the OAuth workflow is obtaining a request token. This is accomplished using:

$config = array(
'callbackUrl' => 'http://example.com/callback.php',
'siteUrl' => 'http://twitter.com/oauth',
'consumerKey' => 'gg3DsFTW9OU9eWPnbuPzQ',
'consumerSecret' => 'tFB0fyWLSMf74lkEu9FTyoHXcazOWpbrAjTCCK48A'
);
$consumer = new Zend_Oauth_Consumer($config);

// fetch a request token


$token = $consumer->getRequestToken();

The new request token (an instance of Zend_Oauth_Token_Request ) is unauthorized. In


order to exchange it for an authorized token with which we can access the Twitter API, we need
the user to authorize it. We accomplish this by redirecting the user to Twitter's authorize endpoint
via:

$config = array(

1064
Zend_Oauth

'callbackUrl' => 'http://example.com/callback.php',


'siteUrl' => 'http://twitter.com/oauth',
'consumerKey' => 'gg3DsFTW9OU9eWPnbuPzQ',
'consumerSecret' => 'tFB0fyWLSMf74lkEu9FTyoHXcazOWpbrAjTCCK48A'
);
$consumer = new Zend_Oauth_Consumer($config);

// fetch a request token


$token = $consumer->getRequestToken();

// persist the token to storage


$_SESSION['TWITTER_REQUEST_TOKEN'] = serialize($token);

// redirect the user


$consumer->redirect();

The user will now be redirected to Twitter. They will be asked to authorize the request token
attached to the redirect URI's query string. Assuming they agree, and complete the authorization,
they will be again redirected, this time to our Callback URL as previously set (note that the
callback URL is also registered with Twitter when we registered our application).

Before redirecting the user, we should persist the request token to storage. For simplicity I'm just
using the user's session, but you can easily use a database for the same purpose, so long as you
tie the request token to the current user so it can be retrieved when they return to our application.

The redirect URI from Twitter will contain an authorized Access Token. We can include code to
parse out this access token as follows - this source code would exist within the executed code of
our callback URI. Once parsed we can discard the previous request token, and instead persist
the access token for future use with the Twitter API. Again, we're simply persisting to the user
session, but in reality an access token can have a long lifetime so it should really be stored to
a database.

$config = array(
'callbackUrl' => 'http://example.com/callback.php',
'siteUrl' => 'http://twitter.com/oauth',
'consumerKey' => 'gg3DsFTW9OU9eWPnbuPzQ',
'consumerSecret' => 'tFB0fyWLSMf74lkEu9FTyoHXcazOWpbrAjTCCK48A'
);
$consumer = new Zend_Oauth_Consumer($config);

if (!empty($_GET) && isset($_SESSION['TWITTER_REQUEST_TOKEN'])) {


$token = $consumer->getAccessToken($_GET, unserialize($_SESSION['TWITTER_REQUEST_TOKEN']
$_SESSION['TWITTER_ACCESS_TOKEN'] = serialize($token);

// Now that we have an Access Token, we can discard the Request Token
$_SESSION['TWITTER_REQUEST_TOKEN'] = null;
} else {
// Mistaken request? Some malfeasant trying something?
exit('Invalid callback request. Oops. Sorry.');
}

Success! We have an authorized access token - so it's time to actually use the Twitter API.
Since the access token must be included with every single API request, Zend_Oauth_Consumer
offers a ready-to-go HTTP client (a subclass of Zend_Http_Client) to use either by itself or
by passing it as a custom HTTP Client to another library or component. Here's an example of
using it standalone. This can be done from anywhere in your application, so long as you can
access the OAuth configuration and retrieve the final authorized access token.

1065
Zend_Oauth

$config = array(
'callbackUrl' => 'http://example.com/callback.php',
'siteUrl' => 'http://twitter.com/oauth',
'consumerKey' => 'gg3DsFTW9OU9eWPnbuPzQ',
'consumerSecret' => 'tFB0fyWLSMf74lkEu9FTyoHXcazOWpbrAjTCCK48A'
);

$statusMessage = 'I\'m posting to Twitter using Zend_Oauth!';

$token = unserialize($_SESSION['TWITTER_ACCESS_TOKEN']);
$client = $token->getHttpClient($configuration);
$client->setUri('http://twitter.com/statuses/update.json');
$client->setMethod(Zend_Http_Client::POST);
$client->setParameterPost('status', $statusMessage);
$response = $client->request();

$data = Zend_Json::decode($response->getBody());
$result = $response->getBody();
if (isset($data->text)) {
$result = 'true';
}
echo $result;

As a note on the customised client, this can be passed to most Zend Framework service or other
classes using Zend_Http_Client displacing the default client they would otherwise use.

1066
Zend_OpenId
1. Introduction
Zend_OpenId est le composant de Zend Framework qui propose une API simple pour
l'utilisation de la technologie OpenID dans son applicatif internet.

1.1. Qu'est ce qu'OpenID ?


OpenID est un ensemble de protocole permettant une gestion centralisée de l'identification
d'une personne. Ces protocoles permettent la création d'une identité en ligne, via un fournisseur
d'identité. Cette identité peut alors être utilisée n'importe où, où OpenID est supporté. Sur les
sites utilisant OpenID, il n'est plus nécessaire de se souvenir d'identifiants différents, la seule et
unique identité OpenID est la même partout. Une identité OpenID est en général matérialisée
par une URL et un utilisateur est libre de choisir son fournisseur OpenID, ou alors même de créer
son propre serveur d'identification OpenID, ceci ne nécessitant pas d'autorisation centrale.

Visitez donc le site officiel de OpenID pour plus d'information, voyez aussi le OpenID Book, par
Rafeeq Rehman ou OpenIDFrance.

1.2. Comment cela fonctionne-t-il ?


Le but de Zend_OpenId est d'implémenter le protocole d'identification OpenID, comme décrit
dans le diagramme suivant :

1. L'authentification est initialisée par l'utilisateur final, qui passe son identifiant OpenID, via son
navigateur.

2. Le service protégé par OpenID normalise l'identifiant de l'utilisateur. Il en résulte un identifiant


validé, une URL du serveur OpenID, et une version du protocole OpenID.

3. Le service protégé par OpenID établit optionnellement une connexion avec le serveur OpenID
en utilisant des clés Diffie-Hellman. Les deux parties partagent alors un "secret" utilisé pour
signer et vérifier les messages suivants.

4. Le service protégé par OpenID redirige le navigateur vers l'URL du serveur OpenID, en
effectuant une requête d'authentification.

5. Le serveur OpenID vérifie si le navigateur n'est pas déjà identifié.

6. L'utilisateur entre son mot de passe.

7. Le serveur OpenID effectue une vérification pour savoir si l'utilisateur a le droit d'accéder au
service protégé par OpenID.

1067
Zend_OpenId

8. L'utilisateur final accepte alors ou non de partager ses informations d'identité pour le service
protégé par OpenID.

9. Le serveur OpenID redirige le navigateur vers le service protégé par OpenID, avec un
message "authentification approuvée" ou "échouée".

10.Le service protégé par OpenID vérifie l'information du serveur OpenID en utilisant le "secret"
obtenu étape 3 ou en envoyant des informations supplémentaires.

1.3. Zend_OpenId Structure


Zend_OpenId contient deux sous-classes. Zend_OpenId_Consumer est un client, il sera
utilisé sur les sites nécessitant l'identification OpenID. Zend_OpenId_Provider, elle, permet
de créer son propre serveur OpenID. Ces deux classes sont totalement indépendantes l'une de
l'autre.

Les seuls points communs entre ces deux classes sont l'extension Simple Registration
Extension, implémentée par la classe Zend_OpenId_Extension_Sreg, ainsi que les
fonctions utilitaires présentes dans la classe Zend_OpenId.

Zend_OpenId utilise l'extension GMP, lorsqu'elle est disponible. Activez cette


extension si possible, ceci améliorera les performances avec Zend_OpenId.

1.4. Standards OpenID supportés


Le composant Zend_OpenId est conforme aux standards suivants :

• OpenID Authentication protocol version 1.1

• OpenID Authentication protocol version 2.0 draft 11

• OpenID Simple Registration Extension version 1.0

• OpenID Simple Registration Extension version 1.1 draft 1

2. Zend_OpenId_Consumer Basics
Zend_OpenId_Consumer can be used to implement OpenID authentication for web sites.

2.1. OpenID Authentication


From a web site developer's point of view, the OpenID authentication process consists of three
steps:

1. Show OpenID authentication form

2. Accept OpenID identity and pass it to the OpenID provider

3. Verify response from the OpenID provider

The OpenID authentication protocol actually requires more steps, but many of them are
encapsulated inside Zend_OpenId_Consumer and are therefore transparent to the developer.

The end user initiates the OpenID authentication process by submitting his or her identification
credentials with the appropriate form. The following example shows a simple form that accepts
an OpenID identifier. Note that the example only demonstrates a login.

1068
Zend_OpenId

Exemple 572. The Simple OpenID Login form

<html><body>
<form method="post" action="example-1_2.php"><fieldset>
<legend>OpenID Login</legend>
<input type="text" name="openid_identifier">
<input type="submit" name="openid_action" value="login">
</fieldset></form></body></html>

This form passes the OpenID identity on submission to the following PHP script
that performs the second step of authentication. The PHP script need only call the
Zend_OpenId_Consumer::login() method in this step. The first argument of this method is
an accepted OpenID identity, and the second is the URL of a script that handles the third and
last step of authentication.

Exemple 573. The Authentication Request Handler

$consumer = new Zend_OpenId_Consumer();


if (!$consumer->login($_POST['openid_identifier'], 'example-1_3.php')) {
die("OpenID login failed.");
}

The Zend_OpenId_Consumer::login() method performs discovery on a given identifier,


and, if successful, obtains the address of the identity provider and its local identifier. It then
creates an association to the given provider so that both the site and provider share a secret
that is used to sign the subsequent messages. Finally, it passes an authentication request to the
provider. This request redirects the end user's web browser to an OpenID server site, where the
user can continue the authentication process.

An OpenID provider usually asks users for their password (if they weren't previously logged-
in), whether the user trusts this site and what information may be returned to the site. These
interactions are not visible to the OpenID consumer, so it can not obtain the user's password or
other information that the user did not has not directed the OpenID provider to share with it.

On success, Zend_OpenId_Consumer::login() does not return, instead performing an


HTTP redirection. However, if there is an error it may return FALSE. Errors may occur due to an
invalid identity, unresponsive provider, communication error, etc.

The third step of authentication is initiated by the response from the OpenID provider, after it has
authenticated the user's password. This response is passed indirectly, as an HTTP redirection
using the end user's web browser. The consumer must now simply check that this response is
valid.

Exemple 574. The Authentication Response Verifier

$consumer = new Zend_OpenId_Consumer();


if ($consumer->verify($_GET, $id)) {
echo "VALID " . htmlspecialchars($id);
} else {
echo "INVALID " . htmlspecialchars($id);
}

This check is performed using the Zend_OpenId_Consumer::verify method, which takes


an array of the HTTP request's arguments and checks that this response is properly signed by
the OpenID provider. It may assign the claimed OpenID identity that was entered by end user in
the first step using a second, optional argument.

1069
Zend_OpenId

2.2. Combining all Steps in One Page


The following example combines all three steps in one script. It doesn't provide any new
functionality. The advantage of using just one script is that the developer need not specify URL's
for a script to handle the next step. By default, all steps use the same URL. However, the script
now includes some dispatch code to execute the appropriate code for each step of authentication.

Exemple 575. The Complete OpenID Login Script

<?php
$status = "";
if (isset($_POST['openid_action']) &&
$_POST['openid_action'] == "login" &&
!empty($_POST['openid_identifier'])) {

$consumer = new Zend_OpenId_Consumer();


if (!$consumer->login($_POST['openid_identifier'])) {
$status = "OpenID login failed.";
}
} else if (isset($_GET['openid_mode'])) {
if ($_GET['openid_mode'] == "id_res") {
$consumer = new Zend_OpenId_Consumer();
if ($consumer->verify($_GET, $id)) {
$status = "VALID " . htmlspecialchars($id);
} else {
$status = "INVALID " . htmlspecialchars($id);
}
} else if ($_GET['openid_mode'] == "cancel") {
$status = "CANCELLED";
}
}
?>
<html><body>
<?php echo "$status<br>" ?>
<form method="post">
<fieldset>
<legend>OpenID Login</legend>
<input type="text" name="openid_identifier" value=""/>
<input type="submit" name="openid_action" value="login"/>
</fieldset>
</form>
</body></html>

In addition, this code differentiates between cancelled and invalid authentication responses. The
provider returns a cancelled response if the identity provider is not aware of the supplied identity,
the user is not logged in, or the user doesn't trust the site. An invalid response indicates that the
response is not conformant to the OpenID protocol or is incorrectly signed.

2.3. Consumer Realm


When an OpenID-enabled site passes authentication requests to a provider, it identifies itself
with a realm URL. This URL may be considered a root of a trusted site. If the user trusts the
realm URL, he or she should also trust matched and subsequent URLs.

By default, the realm URL is automatically set to the URL of the directory in which the login script
resides. This default value is useful for most, but not all, cases. Sometimes an entire domain,
and not a directory should be trusted. Or even a combination of several servers in one domain.

1070
Zend_OpenId

To override the default value, developers may pass the realm URL as a third argument to the
Zend_OpenId_Consumer::login method. In the following example, a single interaction asks
for trusted access to all php.net sites.

Exemple 576. Authentication Request for Specified Realm

$consumer = new Zend_OpenId_Consumer();


if (!$consumer->login($_POST['openid_identifier'],
'example-3_3.php',
'http://*.php.net/')) {
die("OpenID login failed.");
}

This example implements only the second step of authentication; the first and third steps are
similar to the examples above.

2.4. Immediate Check


In some cases, an application need only check if a user is already logged
in to a trusted OpenID server without any interaction with the user. The
Zend_OpenId_Consumer::check method does precisely that. It is executed with the same
arguments as Zend_OpenId_Consumer::login, but it doesn't display any OpenID server
pages to the user. From the users point of view this process is transparent, and it appears as
though they never left the site. The third step succeeds if the user is already logged in and trusted
by the site, otherwise it will fail.

Exemple 577. Immediate Check without Interaction

$consumer = new Zend_OpenId_Consumer();


if (!$consumer->check($_POST['openid_identifier'], 'example-4_3.php')) {
die("OpenID login failed.");
}

This example implements only the second step of authentication; the first and third steps are
similar to the examples above.

2.5. Zend_OpenId_Consumer_Storage
There are three steps in the OpenID authentication procedure, and each step is performed by
a separate HTTP request. To store information between requests, Zend_OpenId_Consumer
uses internal storage.

Developers do not necessarily have to be aware of this storage because by default


Zend_OpenId_Consumer uses file-based storage under the temporary directory- similar
to PHP sessions. However, this storage may be not suitable in all cases. Some
developers may want to store information in a database, while others may need to use
common storage suitable for server farms. Fortunately, developers may easily replace
the default storage with their own. To specify a custom storage mechanism, one need
only extend the Zend_OpenId_Consumer_Storage class and pass this subclass to the
Zend_OpenId_Consumer constructor in the first argument.

The following example demonstrates a simple storage mechanism that uses Zend_Db as its
backend and exposes three groups of functions. The first group contains functions for working
with associations, while the second group caches discovery information, and the third group can

1071
Zend_OpenId

be used to check whether a response is unique. This class can easily be used with existing or
new databases; if the required tables don't exist, it will create them.

1072
$version,
$expires)
{
$table = $this->_discovery_table;
Zend_OpenId
$this->_db->insert($table, array(
'id' => $id,
'realId' => $realId,
'server' => $server,
Exemple 578. Database Storage
'version' => $version,
'expires' => $expires,
));

return true;
}

public function getDiscoveryInfo($id,


&$realId,
&$server,
&$version,
&$expires)
{
$table = $this->_discovery_table;
$this->_db->delete($table, $this->quoteInto('expires < ?', time()));
$select = $this->_db->select()
->from($table, array('realId', 'server', 'version', 'expires'))
->where('id = ?', $id);
$res = $this->_db->fetchRow($select);

if (is_array($res)) {
$realId = $res['realId'];
$server = $res['server'];
$version = $res['version'];
$expires = $res['expires'];
return true;
}
return false;
}

public function delDiscoveryInfo($id)


{
$table = $this->_discovery_table;
$this->_db->delete($table, $this->_db->quoteInto('id = ?', $id));
return true;
}

public function isUniqueNonce($nonce)


{
$table = $this->_nonce_table;
try {
$ret = $this->_db->insert($table, array(
'nonce' => $nonce,
));
} catch (Zend_Db_Statement_Exception $e) {
return false;
}
return true;
}

public function purgeNonces($date=null)


{
}
}

$db = Zend_Db::factory('Pdo_Sqlite',
array('dbname'=>'/tmp/openid_consumer.db'));
$storage = new DbStorage($db);
$consumer = new Zend_OpenId_Consumer($storage);

1073
Zend_OpenId

This example doesn't list the OpenID authentication code itself, but this code would be the same
as that for other examples in this chapter. examples.

2.6. Simple Registration Extension


In addition to authentication, the OpenID standard can be used for lightweight profile exchange to
make information about a user portable across multiple sites. This feature is not covered by the
OpenID authentication specification, but by the OpenID Simple Registration Extension protocol.
This protocol allows OpenID-enabled sites to ask for information about end users from OpenID
providers. Such information may include:

• nickname - any UTF-8 string that the end user uses as a nickname

• email - the email address of the user as specified in section 3.4.1 of RFC2822

• fullname - a UTF-8 string representation of the user's full name

• dob - the user's date of birth in the format 'YYYY-MM-DD'. Any values whose representation
uses fewer than the specified number of digits in this format should be zero-padded. In other
words, the length of this value must always be 10. If the end user does not want to reveal any
particular part of this value (i.e., year, month or day), it must be set to zero. For example, if
the user wants to specify that his date of birth falls in 1980, but not specify the month or day,
the value returned should be '1980-00-00'.

• gender - the user's gender: "M" for male, "F" for female

• postcode - a UTF-8 string that conforms to the postal system of the user's country

• country - the user's country of residence as specified by ISO3166

• language - the user's preferred language as specified by ISO639

• timezone - an ASCII string from a TimeZone database. For example, "Europe/Paris" or


"America/Los_Angeles".

An OpenID-enabled web site may ask for any combination of these fields. It may also strictly
require some information and allow users to provide or hide additional information. The following
example instantiates the Zend_OpenId_Extension_Sreg class, requiring a nickname and
optionally requests an email and a fullname.

Exemple 579. Sending Requests with a Simple Registration Extension

$sreg = new Zend_OpenId_Extension_Sreg(array(


'nickname'=>true,
'email'=>false,
'fullname'=>false), null, 1.1);
$consumer = new Zend_OpenId_Consumer();
if (!$consumer->login($_POST['openid_identifier'],
'example-6_3.php',
null,
$sreg)) {
die("OpenID login failed.");
}

As you can see, the Zend_OpenId_Extension_Sreg constructor accepts an array of OpenID


fields. This array has the names of fields as indexes to a flag indicating whether the field

1074
Zend_OpenId

is required; TRUE means the field is required and FALSE means the field is optional. The
Zend_OpenId_Consumer::login method accepts an extension or an array of extensions as
its fourth argument.

On the third step of authentication, the Zend_OpenId_Extension_Sreg object should


be passed to Zend_OpenId_Consumer::verify. Then on successful authentication the
Zend_OpenId_Extension_Sreg::getProperties method will return an associative array
of requested fields.

Exemple 580. Verifying Responses with a Simple Registration Extension

$sreg = new Zend_OpenId_Extension_Sreg(array(


'nickname'=>true,
'email'=>false,
'fullname'=>false), null, 1.1);
$consumer = new Zend_OpenId_Consumer();
if ($consumer->verify($_GET, $id, $sreg)) {
echo "VALID " . htmlspecialchars($id) ."<br>\n";
$data = $sreg->getProperties();
if (isset($data['nickname'])) {
echo "nickname: " . htmlspecialchars($data['nickname']) . "<br>\n";
}
if (isset($data['email'])) {
echo "email: " . htmlspecialchars($data['email']) . "<br>\n";
}
if (isset($data['fullname'])) {
echo "fullname: " . htmlspecialchars($data['fullname']) . "<br>\n";
}
} else {
echo "INVALID " . htmlspecialchars($id);
}

If the Zend_OpenId_Extension_Sreg object was created without any arguments, the user
code should check for the existence of the required data itself. However, if the object is created
with the same list of required fields as on the second step, it will automatically check for the
existence of required data. In this case, Zend_OpenId_Consumer::verify will return FALSE
if any of the required fields are missing.

Zend_OpenId_Extension_Sreg uses version 1.0 by default, because the specification


for version 1.1 is not yet finalized. However, some libraries don't fully support version 1.0.
For example, www.myopenid.com requires an SREG namespace in requests which is only
available in 1.1. To work with such a server, you must explicitly set the version to 1.1 in the
Zend_OpenId_Extension_Sreg constructor.

The second argument of the Zend_OpenId_Extension_Sreg constructor is a policy URL, that


should be provided to the user by the identity provider.

2.7. Integration with Zend_Auth


Zend Framework provides a special class to support user authentication: Zend_Auth. This
class can be used together with Zend_OpenId_Consumer. The following example shows how
OpenIdAdapter implements the Zend_Auth_Adapter_Interface with the authenticate
method. This performs an authentication query and verification.

The big difference between this adapter and existing ones, is that it works on two HTTP requests
and includes a dispatch code to perform the second or third step of OpenID authentication.

1075
<?php Zend_OpenId
class OpenIdAdapter implements Zend_Auth_Adapter_Interface {
private $_id = null;
Exemple 581. Zend_Auth Adapter for OpenID
public function __construct($id = null) {
$this->_id = $id;
}

public function authenticate() {


$id = $this->_id;
if (!empty($id)) {
$consumer = new Zend_OpenId_Consumer();
if (!$consumer->login($id)) {
$ret = false;
$msg = "Authentication failed.";
}
} else {
$consumer = new Zend_OpenId_Consumer();
if ($consumer->verify($_GET, $id)) {
$ret = true;
$msg = "Authentication successful";
} else {
$ret = false;
$msg = "Authentication failed";
}
}
return new Zend_Auth_Result($ret, $id, array($msg));
}
}

$status = "";
$auth = Zend_Auth::getInstance();
if ((isset($_POST['openid_action']) &&
$_POST['openid_action'] == "login" &&
!empty($_POST['openid_identifier'])) ||
isset($_GET['openid_mode'])) {
$adapter = new OpenIdAdapter(@$_POST['openid_identifier']);
$result = $auth->authenticate($adapter);
if ($result->isValid()) {
Zend_OpenId::redirect(Zend_OpenId::selfURL());
} else {
$auth->clearIdentity();
foreach ($result->getMessages() as $message) {
$status .= "$message<br>\n";
}
}
} else if ($auth->hasIdentity()) {
if (isset($_POST['openid_action']) &&
$_POST['openid_action'] == "logout") {
$auth->clearIdentity();
} else {
$status = "You are logged in as " . $auth->getIdentity() . "<br>\n";
}
}
?>
<html><body>
<?php echo htmlspecialchars($status);?>
<form method="post"><fieldset>
<legend>OpenID Login</legend>
<input type="text" name="openid_identifier" value="">
<input type="submit" name="openid_action" value="login">
<input type="submit" name="openid_action" value="logout">
</fieldset></form></body></html>

1076
Zend_OpenId

With Zend_Auth the end-user's identity is saved in the session's data. It may be checked with
Zend_Auth::hasIdentity and Zend_Auth::getIdentity.

2.8. Integration with Zend_Controller


Finally a couple of words about integration into Model-View-Controller applications: such Zend
Framework applications are implemented using the Zend_Controller class and they use
objects of the Zend_Controller_Response_Http class to prepare HTTP responses and
send them back to the user's web browser.

Zend_OpenId_Consumer doesn't provide any GUI capabilities but it performs


HTTP redirections on success of Zend_OpenId_Consumer::login and
Zend_OpenId_Consumer::check. These redirections may work incorrectly or not at
all if some data was already sent to the web browser. To properly perform HTTP
redirection in MVC code the real Zend_Controller_Response_Http should be sent
to Zend_OpenId_Consumer::login or Zend_OpenId_Consumer::check as the last
argument.

3. Zend_OpenId_Provider
Zend_OpenId_Provider can be used to implement OpenID servers. This chapter provides
examples that demonstrate how to build a very basic server. However, for implementation of
a production OpenID server (such as www.myopenid.com) you may have to deal with more
complex issues.

3.1. Quick Start


The following example includes code for creating a user account using
Zend_OpenId_Provider::register. The link element with rel="openid.server"
points to our own server script. If you submit this identity to an OpenID-enabled site, it will perform
authentication on this server.

The code before the <html> tag is just a trick that automatically creates a user account. You
won't need such code when using real identities.

Exemple 582. The Identity

<?php
// Set up test identity
define("TEST_SERVER", Zend_OpenId::absoluteURL("example-8.php"));
define("TEST_ID", Zend_OpenId::selfURL());
define("TEST_PASSWORD", "123");
$server = new Zend_OpenId_Provider();
if (!$server->hasUser(TEST_ID)) {
$server->register(TEST_ID, TEST_PASSWORD);
}
?>
<html><head>
<link rel="openid.server" href="<?php echo TEST_SERVER;?>" />
</head><body>
<?php echo TEST_ID;?>
</body></html>

The following identity server script handles two kinds of requests from OpenID-enabled
sites (for association and authentication). Both of them are handled by the same method:

1077
Zend_OpenId

Zend_OpenId_Provider::handle. The two arguments to the Zend_OpenId_Provider


constructor are URLs of login and trust pages, which ask for input from the end user.

On success, the method Zend_OpenId_Provider::handle returns a string that should be


passed back to the OpenID-enabled site. On failure, it returns FALSE. This example will return
an HTTP 403 response if Zend_OpenId_Provider::handle fails. You will get this response
if you open this script with a web browser, because it sends a non-OpenID conforming request.

Exemple 583. Simple Identity Provider

$server = new Zend_OpenId_Provider("example-8-login.php",


"example-8-trust.php");
$ret = $server->handle();
if (is_string($ret)) {
echo $ret;
} else if ($ret !== true) {
header('HTTP/1.0 403 Forbidden');
echo 'Forbidden';
}

It is a good idea to use a secure connection (HTTPS) for these scripts- especially
for the following interactive scripts- to prevent password disclosure.

The following script implements a login screen for an identity server using
Zend_OpenId_Provider and redirects to this page when a required user has not yet logged
in. On this page, a user will enter his password to login.

You should use the password "123" that was used in the identity script above.

On submit, the script calls Zend_OpenId_Provider::login with the accepted user's identity
and password, then redirects back to the main identity provider's script. On success, the
Zend_OpenId_Provider::login establishes a session between the user and the identity
provider and stores the information about the user, who is now logged in. All following requests
from the same user won't require a login procedure- even if they come from another OpenID
enabled web site.

Note that this session is between end-user and identity provider only. OpenID
enabled sites know nothing about it.

1078
Zend_OpenId

Exemple 584. Simple Login Screen

<?php
$server = new Zend_OpenId_Provider();

if ($_SERVER['REQUEST_METHOD'] == 'POST' &&


isset($_POST['openid_action']) &&
$_POST['openid_action'] === 'login' &&
isset($_POST['openid_identifier']) &&
isset($_POST['openid_password'])) {
$server->login($_POST['openid_identifier'],
$_POST['openid_password']);
Zend_OpenId::redirect("example-8.php", $_GET);
}
?>
<html>
<body>
<form method="post">
<fieldset>
<legend>OpenID Login</legend>
<table border=0>
<tr>
<td>Name:</td>
<td>
<input type="text"
name="openid_identifier"
value="<?php echo htmlspecialchars($_GET['openid_identity']);?>">
</td>
</tr>
<tr>
<td>Password:</td>
<td>
<input type="text"
name="openid_password"
value="">
</td>
</tr>
<tr>
<td>&amp;nbsp;</td>
<td>
<input type="submit"
name="openid_action"
value="login">
</td>
</tr>
</table>
</fieldset>
</form>
</body>
</html>

The fact that the user is now logged in doesn't mean that the authentication must necessarily
succeed. The user may decide not to trust particular OpenID enabled sites. The following trust
screen allows the end user to make that choice. This choice may either be made only for current
requests or forever. In the second case, information about trusted/untrusted sites is stored in
an internal database, and all following authentication requests from this site will be handled
automatically without user interaction.

1079
Zend_OpenId

Exemple 585. Simple Trust Screen

<?php
$server = new Zend_OpenId_Provider();

if ($_SERVER['REQUEST_METHOD'] == 'POST' &&


isset($_POST['openid_action']) &&
$_POST['openid_action'] === 'trust') {

if (isset($_POST['allow'])) {
if (isset($_POST['forever'])) {
$server->allowSite($server->getSiteRoot($_GET));
}
$server->respondToConsumer($_GET);
} else if (isset($_POST['deny'])) {
if (isset($_POST['forever'])) {
$server->denySite($server->getSiteRoot($_GET));
}
Zend_OpenId::redirect($_GET['openid_return_to'],
array('openid.mode'=>'cancel'));
}
}
?>
<html>
<body>
<p>A site identifying as
<a href="<?php echo htmlspecialchars($server->getSiteRoot($_GET));?>">
<?php echo htmlspecialchars($server->getSiteRoot($_GET));?>
</a>
has asked us for confirmation that
<a href="<?php echo htmlspecialchars($server->getLoggedInUser());?>">
<?php echo htmlspecialchars($server->getLoggedInUser());?>
</a>
is your identity URL.
</p>
<form method="post">
<input type="checkbox" name="forever">
<label for="forever">forever</label><br>
<input type="hidden" name="openid_action" value="trust">
<input type="submit" name="allow" value="Allow">
<input type="submit" name="deny" value="Deny">
</form>
</body>
</html>

Production OpenID servers usually support the Simple Registration Extension that allows
consumers to request some information about the user from the provider. In this case, the trust
page can be extended to allow entering requested fields or selecting a specific user profile.

3.2. Combined Provide Scripts


It is possible to combine all provider functionality in one script. In this case login and trust URLs
are omitted, and Zend_OpenId_Provider assumes that they point to the same page with the
additional "openid.action" GET argument.

The following example is not complete. It doesn't provide GUI code for the user,
instead performing an automatic login and trust relationship instead. This is done

1080
Zend_OpenId

just to simplify the example; a production server should include some code from
previous examples.

Exemple 586. Everything Together

$server = new Zend_OpenId_Provider();

define("TEST_ID", Zend_OpenId::absoluteURL("example-9-id.php"));
define("TEST_PASSWORD", "123");

if ($_SERVER['REQUEST_METHOD'] == 'GET' &&


isset($_GET['openid_action']) &&
$_GET['openid_action'] === 'login') {
$server->login(TEST_ID, TEST_PASSWORD);
unset($_GET['openid_action']);
Zend_OpenId::redirect(Zend_OpenId::selfUrl(), $_GET);
} else if ($_SERVER['REQUEST_METHOD'] == 'GET' &&
isset($_GET['openid_action']) &&
$_GET['openid_action'] === 'trust') {
unset($_GET['openid_action']);
$server->respondToConsumer($_GET);
} else {
$ret = $server->handle();
if (is_string($ret)) {
echo $ret;
} else if ($ret !== true) {
header('HTTP/1.0 403 Forbidden');
echo 'Forbidden';
}
}

If you compare this example with previous examples split in to separate pages, you will see only
the one difference besides the dispatch code: unset($_GET['openid_action']). This call
to unset is necessary to route the next request to main handler.

3.3. Simple Registration Extension


Again, the code before the <html> tag is just a trick to demonstrate functionality. It creates a
new user account and associates it with a profile (nickname and password). Such tricks aren't
needed in deployed providers where end users register on OpenID servers and fill in their profiles.
Implementing this GUI is out of scope for this manual.

1081
Zend_OpenId

Exemple 587. Identity with Profile

<?php
define("TEST_SERVER", Zend_OpenId::absoluteURL("example-10.php"));
define("TEST_ID", Zend_OpenId::selfURL());
define("TEST_PASSWORD", "123");
$server = new Zend_OpenId_Provider();
if (!$server->hasUser(TEST_ID)) {
$server->register(TEST_ID, TEST_PASSWORD);
$server->login(TEST_ID, TEST_PASSWORD);
$sreg = new Zend_OpenId_Extension_Sreg(array(
'nickname' =>'test',
'email' => 'test@test.com'
));
$root = Zend_OpenId::absoluteURL(".");
Zend_OpenId::normalizeUrl($root);
$server->allowSite($root, $sreg);
$server->logout();
}
?>
<html>
<head>
<link rel="openid.server" href="<?php echo TEST_SERVER;?>" />
</head>
<body>
<?php echo TEST_ID;?>
</body>
</html>

You should now pass this identity to the OpenID-enabled web site (use the Simple Registration
Extension example from the previous section), and it should use the following OpenID server
script.

This script is a variation of the script in the "Everything Together" example. It uses the
same automatic login mechanism, but doesn't contain any code for a trust page. The
user already trusts the example scripts forever. This trust was established by calling the
Zend_OpenId_Provider::allowSite() method in the identity script. The same method
associates the profile with the trusted URL. This profile will be returned automatically for a request
from the trusted URL.

To make Simple Registration Extension work, you must simply pass an


instance of Zend_OpenId_Extension_Sreg as the second argument to the
Zend_OpenId_Provider::handle() method.

1082
Zend_OpenId

Exemple 588. Provider with SREG

$server = new Zend_OpenId_Provider();


$sreg = new Zend_OpenId_Extension_Sreg();

define("TEST_ID", Zend_OpenId::absoluteURL("example-10-id.php"));
define("TEST_PASSWORD", "123");

if ($_SERVER['REQUEST_METHOD'] == 'GET' &&


isset($_GET['openid_action']) &&
$_GET['openid_action'] === 'login') {
$server->login(TEST_ID, TEST_PASSWORD);
unset($_GET['openid_action']);
Zend_OpenId::redirect(Zend_OpenId::selfUrl(), $_GET);
} else if ($_SERVER['REQUEST_METHOD'] == 'GET' &&
isset($_GET['openid_action']) &&
$_GET['openid_action'] === 'trust') {
echo "UNTRUSTED DATA" ;
} else {
$ret = $server->handle(null, $sreg);
if (is_string($ret)) {
echo $ret;
} else if ($ret !== true) {
header('HTTP/1.0 403 Forbidden');
echo 'Forbidden';
}
}

3.4. Anything Else?


Building OpenID providers is much less common than building OpenID-enabled sites, so this
manual doesn't cover all Zend_OpenId_Provider features exhaustively, as was done for
Zend_OpenId_Consumer.

To summamize, Zend_OpenId_Provider contains:

• A set of methods to build an end-user GUI that allows users to register and manage their
trusted sites and profiles

• An abstract storage layer to store information about users, their sites and their profiles. It also
stores associations between the provider and OpenID-enabled sites. This layer is very similar
to that of the Zend_OpenId_Consumer class. It also uses file storage by default, but may
used with another backend.

• An abstract user-association layer that may associate a user's web browser with a logged-
in identity

The Zend_OpenId_Provider class doesn't attempt to cover all possible features that can be
implemented by OpenID servers, e.g. digital certificates, but it can be extended easily using
Zend_OpenId_Extensions or by standard object-oriented extension.

1083
Zend_Paginator
1. Introduction
Zend_Paginator est un composant flexible pour paginer des collections de données et
présenter ces données aux utilisateurs.

Les buts principaux de la conception de Zend_Paginator sont les suivants :

• paginer des données arbitraires, et pas simplement issues de base de données relationnelle ;

• récupérer seulement les résultats qu'il est nécessaire d'afficher ;

• ne pas forcer les utilisateurs à adhérer à une seule manière d'afficher les données ou de
retourner les contrôles de pagination ;

• faiblement coupler Zend_Paginator envers les autres composants de Zend Framework,


ainsi les utilisateurs qui voudront l'utiliser indépendamment de Zend_View, Zend_Db, etc.
pourront le faire.

2. Utilisation
2.1. Paginer des collections de données
Afin de pouvoir paginer des éléments, Zend_Paginator doit posséder une manière générique
d'accéder aux sources de données. De ce fait, tous les accès aux données se font via des
adaptateurs de sources. Plusieurs adaptateurs existent par défaut :

Tableau 109. Adaptateurs pour Zend_Paginator


Adaptateur Description
Array Utilise un tableau PHP
DbSelect Utilise une instance de Zend_Db_Select qui
retourne un tableau
DbTableSelect Utilise une instance
Zend_Db_Table_Select, qui retournera
une instance de
Zend_Db_Table_Rowset_Abstract. Ceci
fournit aussi des informations supplémentaires
sur le jeu de résultats, tel que les noms de
colonne.
Iterator Utilise une instance implémentant Iterator
NULL N'utilise pas Zend_Paginator pour la
pagination. En revanche, les options et
capacités de contrôle de la pagination restent
disponibles.

Plutôt que de sélectionner chaque ligne correspondant à une requête fournie, les
adaptateurs DbSelect et DbTableSelect récupèrent seulement la quantité de
données nécessaire pour l'affichage de la page courante.

1084
Zend_Paginator

A cause de ceci, une seconde requête est générée dynamiquement pour


déterminer le nombre total de lignes correspondantes. Cependant, il est possible
de directement fournir un nombre ou un requête de dénombrement vous-même.
Regardez la méthode setRowCount() de l'adaptateur DbSelect pour de plus
amples informations.

Pour créer une instance de Zend_Paginator, vous devez spécifier un adaptateur à son
constructeur:

$paginator = new Zend_Paginator(new Zend_Paginator_Adapter_Array($array));

Pour une meilleure intégration, vous pouvez utiliser la fabrique factory():

$paginator = Zend_Paginator::factory($array);

Pour l'adaptateur NULL, il faut spécifier un chiffre à son constructeur en lieu et


place de la collection de données.

Bien que l'instance soit techniquement utilisable dans l'état, dans votre contrôleur d'action vous
devrez informer le paginateur du numéro de page demandé par l'utilisateur. Ceci lui permet
d'avancer à travers les données paginées.

$paginator->setCurrentPageNumber($page);

La manière la plus simple de suivre et scruter cette valeur est via l'URL. Nous recommandons
l'utilisation d'un routeur compatible avec Zend_Controller_Router_Interface, mais ceci
n'est pas nécessaire.

Voici une route que vous pourriez définir dans un fichier de configuration INI:

routes.example.route = articles/:articleName/:page
routes.example.defaults.controller = articles
routes.example.defaults.action = view
routes.example.defaults.page = 1
routes.example.reqs.articleName = \w+
routes.example.reqs.page = \d+

Avec une telle route (et en utilisant les composants MVC de Zend Framework), vous pourriez
spécifier le numéro de la page de cette manière :

$paginator->setCurrentPageNumber($this->_getParam('page'));

Il y a d'autres options disponibles, voyez la configuration pour plus de détails.

Enfin, il faut passer l'instance du paginateur à votre vue. Si vous utilisez Zend_View avec l'aide
d'action ViewRenderer, ceci fonctionnera :

$this->view->paginator = $paginator;

2.2. The DbSelect and DbTableSelect adapter


The usage of most adapters is pretty straight-forward. However, the database adapters require
a more detailed explanation regarding the retrieval and count of the data from the database.

1085
Zend_Paginator

To use the DbSelect and DbTableSelect adapters you don't have to retrieve the data upfront from
the database. Both adapters do the retrieval for you, aswell as the counting of the total pages.
If additional work has to be done on the database results the adapter getItems() method has
to be extended in your application.

Additionally these adapters do not fetch all records from the database Instead, the adapters
manipulates the original query to produce the corresponding COUNT query. Paginator then
executes that COUNT query to get the number of rows. This does require an extra round-trip to
the database, but this is many times faster than fetching an entire result set and using count().
Especially with large collections of data.

The database adapters will try and build the most efficient query that will execute on pretty much
all modern databases. However, depending on your database or even your own schema setup,
there might be more efficient ways to get a rowcount. For this scenario the database adapters
allow you to set a custom COUNT query. For example, if you keep track of the count of blog
posts in a separate table, you could achieve a faster count query with the following setup:

$adapter = new Zend_Paginator_Adapter_DbSelect($db->select()->from('posts'));


$adapter->setRowCount(
$db->select()->from('item_counts', array(Zend_Paginator_Adapter_DbSelect::ROW_COUNT_COLU
)

$paginator = new Zend_Paginator($adapter);

This approach will probably not give you a huge performance gain on small collections and/or
simple select queries. However, with complex queries and large collections, a similar approach
could give you a significant performance boost.

2.3. Rendre des pages avec les scripts de vue


Le script de vue va être utilisé pour rendre les éléments de la page (bien sûr si Zend_Paginator
est utilisé à cet effet), et pour afficher les éléments relatifs au contrôle de la pagination.

Comme Zend_Paginator implémente l'interface SPL IteratorAggregate, boucler sur les


éléments et les afficher est très simple.

<html>
<body>
<h1>Example</h1>
<?php if (count($this->paginator)): ?>
<ul>
<?php foreach ($this->paginator as $item): ?>
<li><?php echo $item; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<?php echo $this->paginationControl($this->paginator,
'Sliding',
'my_pagination_control.phtml'); ?>
</body>
</html>

Notez l'appel à l'aide de vue en fin de script. PaginationControl accepte jusqu'à quatre
paramètres : l'instance du paginateur, un type de défilement (optionnel), un partial de vue
(optionnel) et un tableau de paramètres additionnels.

1086
Zend_Paginator

Les second et troisième paramètres sont très importants. Alors que le partial est utiliser pour
déterminer comment présenter les données, le type de défilement définira la manière dont ils se
comportent. Disons que le partial ressemble à un contrôle de recherche, comme ce qui suit :

Que se passe-t-il lorsque l'utilisateur clique sur le lien "next" quelques fois? Plusieurs choses
peuvent arriver. Le numéro de la page courante pourrait rester au milieu (comme c'est le cas sur
Yahoo!), ou il pourrait aussi bien avancer à la fin de la fourchette des pages et apparaître encore
à gauche lorsque l'utilisateur clique alors sur "next". Le nombre de pages pourrait alors s'étendre
ou se comprimer alors que l'utilisateur avance ("scroll") à travers (comme chez Google).

Il existe 4 types de défilement intégrés dans Zend Framework :

Tableau 110. Types de défilement pour Zend_Paginator


Type de défilement Description
All Retourne toutes les pages. Très pratique
lorsqu'il y a peu de pages totales.
Elastic Un défilement de type Google qui s'étend et
se contracte au fur et à mesure que l'utilisateur
avance dans les pages de résultats.
Jumping Alors que l'utilisateur défile, le nombre de
pages avance à la fin d'une échelle donnée,
puis recommence au début de l'échelle
suivante.
Sliding Un défilement de type Yahoo! qui positionne
la page en cours au centre d'une échelle de
pages, le plus justement et près possible. Ce
type de défilement est le type par défaut.

Le quatrième et dernier paramètre est réservé pour un tableau associatif optionnel de variables
supplémentaires que vous voulez rendre disponible dans vos partiels de vues (disponible via
$this). Par exemple, ces valeurs permettent d'inclure des paramètres d'URL supplémentaires
pour les liens de pagination.

En spécifiant le partial de vue par défaut, le défilement et l'instance de vue, vous pouvez alors
vous affranchir totalement des appels à PaginationControl :

Zend_Paginator::setDefaultScrollingStyle('Sliding');
Zend_View_Helper_PaginationControl::setDefaultViewPartial(
'my_pagination_control.phtml'
);
$paginator->setView($view);

Utilisez dès lors un simple echo dans le script de vue pour le rendu du paginateur complet:

<?php echo $this->paginator; ?>

Bien sûr, il est possible d'utiliser Zend_paginator avec d'autres moteurs de


templates. Par exemple, avec Smarty vous pourriez faire ceci :

1087
Zend_Paginator

$smarty->assign('pages', $paginator->getPages());

Vous pouvez ainsi accéder aux valeurs du paginateur grâce à un template


comme ceci :

{$pages->pageCount}

2.3.1. Exemples de contrôles de pagination


Voici quelques exemples qui vous aideront à démarrer avec le paginateur:

Pagination de recherche :

<!--
Voir http://developer.yahoo.com/ypatterns/pattern.php?pattern=searchpagination
-->

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


<div class="paginationControl">
<!-- Previous page link -->
<?php if (isset($this->previous)): ?>
<a href="<?php echo $this->url(array('page' => $this->previous)); ?>">
Previous
</a> |
<?php else: ?>
<span class="disabled"> Previous</span> |
<?php endif; ?>
<!-- Numbered page links -->
<?php foreach ($this->pagesInRange as $page): ?>
<?php if ($page != $this->current): ?>
<a href="<?php echo $this->url(array('page' => $page)); ?>">
<?php echo $page; ?>
</a> |
<?php else: ?>
<?php echo $page; ?> |
<?php endif; ?>
<?php endforeach; ?>
<!-- Next page link -->
<?php if (isset($this->next)): ?>
<a href="<?php echo $this->url(array('page' => $this->next)); ?>">
Next
</a>
<?php else: ?>
<span class="disabled">Next </span>
<?php endif; ?>
</div>
<?php endif; ?>

Pagination d'objets :

<!--
Voir http://developer.yahoo.com/ypatterns/pattern.php?pattern=itempagination
-->

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


<div class="paginationControl">

1088
Zend_Paginator

<?php echo $this->firstItemNumber; ?> - <?php echo $this->lastItemNumber; ?>


of <?php echo $this->totalItemCount; ?>
<!-- First page link -->
<?php if (isset($this->previous)): ?>
<a href="<?php echo $this->url(array('page' => $this->first)); ?>">
First
</a> |
<?php else: ?>
<span class="disabled">First</span> |
<?php endif; ?>
<!-- Previous page link -->
<?php if (isset($this->previous)): ?>
<a href="<?php echo $this->url(array('page' => $this->previous)); ?>">
Previous
</a> |
<?php else: ?>
<span class="disabled"> Previous</span> |
<?php endif; ?>
<!-- Next page link -->
<?php if (isset($this->next)): ?>
<a href="<?php echo $this->url(array('page' => $this->next)); ?>">
Next
</a> |
<?php else: ?>
<span class="disabled">Next </span> |
<?php endif; ?>
<!-- Last page link -->
<?php if (isset($this->next)): ?>
<a href="<?php echo $this->url(array('page' => $this->last)); ?>">Last</a>
<?php else: ?>
<span class="disabled">Last</span>
<?php endif; ?>
</div>
<?php endif; ?>

Pagination Dropdown :

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


<select id="paginationControl" size="1">
<?php foreach ($this->pagesInRange as $page): ?>
<?php $selected = ($page == $this->current) ? ' selected="selected"' : ''; ?>
<option value="<?php echo $this->url(array('page' => $page)); ?>"
<?php echo $selected ?>>
<?php echo $page; ?>
</option>
<?php endforeach; ?>
</select>
<?php endif; ?>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.2/prototype.js">
</script>
<script type="text/javascript">
$('paginationControl').observe('change', function() {
window.location = this.options[this.selectedIndex].value;
})
</script>

1089
Zend_Paginator

2.3.2. Liste des propriétés


Les options suivantes sont disponibles pour contrôler la pagination dans les partials de vue :

Tableau 111. Propriétés disponibles aux partials de vue


Propriété Type Description
first entier Numéro de la première page
firstItemNumber entier Numéro absolu du premier
objet(item) dans cette page
firstPageInRange entier Première page dans l'échelle
retournée par le type de
défilement
current entier Numéro de la page en cours
currentItemCount entier Nombre d'objets sur cette page
itemCountPerPage integer Nombre d'objets maximum à
afficher par page
last entier Numéro de la dernière page
lastItemNumber entier Numéro absolu du dernier
objet sur cette page
lastPageInRange entier Dernière page dans l'échelle
retournée par le type de
défilement
next entier Numéro de la page suivante
pageCount entier Nombre de pages
pagesInRange tableau (array) Tableau des pages retournées
par le type de défilement
previous entier Numéro de la page précédente
totalItemCount entier Nombre total d'objets

3. Configuration
Zend_Paginator possède de nombreuses méthodes de configuration qui peuvent être
appelées :

Tableau 112. Méthodes de configuration de Zend_Paginator


Méthode Description
setCurrentPageNumber Règle le numéro de la page courante (par
défaut à 1).
setItemCountPerPage Règle le nombre maximum d'éléments à
afficher par page (par défaut à 10).
setPageRange Règle le nombre d'éléments à afficher dans le
contrôle de pagination (par défaut à 10). Note :
la plupart du temps ce nombre sera considéré
comme exact, mais les styles de défilement
ont cette option seulement si ils ont une ligne
directrice ou un point de départ (par exemple
Elastic).

1090
Zend_Paginator

Méthode Description
setView Règle l'instance de la vue, pour une facilité de
rendu.

4. Utilisation avancée
4.1. Adaptateurs de source de données personnalisée
À partir d'un moment, vous pourriez avoir besoin de parcourir un type de données qui n'est pas
couvert par les adaptateurs fournis par défaut. Dans ce cas, vous devrez écrire vos propres
adaptateurs.

Pour faire ceci, vous devez implémenter Zend_Paginator_Adapter_Interface. Il existe


deux méthodes requises :

• count()

• getItems($offset, $itemCountPerPage)

De plus, vous voudrez peut-être implémenter un constructeur qui prend votre source de données
comme paramètre et le stocke comme propriété protégée ou privée. La manière suivant laquelle
vous allez spécifiquement faire ceci, vous incombe.

Si vous avez déjà utilisé l'interface SPL Countable, vous êtes familier avec count(). Utilisé
avec Zend_Paginator, il s'agit du nombre total d'éléments dans la collection de données. De
plus, l'instance Zend_Paginator fournit une méthode countAllItems() qui proxie vers la
méthode count() de l'adaptateur.

La méthode getItems() est seulement légèrement plus compliquée. Pour ceci, les paramètres
sont un point de départ et un nombre d'éléments à afficher par page. Vous devez retourner la
portion appropriée de données. Pour un tableau, il s'agirait :

return array_slice($this->_array, $offset, $itemCountPerPage);

Regardez les adaptateurs fournis par défaut (ils implémentent tous


Zend_Paginator_Adapter_Interface) pour avoir une idée de la manière d'implémenter
votre propre adaptateur.

4.2. Styles de défilement personnalisés


Créer votre propre style de défilement requiert que vous implémentiez
Zend_Paginator_ScrollingStyle_Interface, qui définit une seule méthode,
getPages(). Et plus spécifiquement :

public function getPages(Zend_Paginator $paginator, $pageRange = null);

Cette méthode doit calculer des bornes inférieures et supérieures des numéros de page dans la
plage des pages dites "local" (c'est-à-dire qui sont proches de la page courante).

A moins que votre style étende un autre style de défilement (voir


Zend_Paginator_ScrollingStyle_Elastic par exemple), votre style personnalisé devra
inévitablement se terminer par quelque chose de similaire à ceci :

return $paginator->getPagesInRange($lowerBound, $upperBound);

1091
Zend_Paginator

Il n'y a rien de spécial au sujet de cet appel ; c'est simplement une méthode pratique pour vérifier
la validité de la limite inférieure et supérieure et pour renvoyer un tableau de ces bornes au
paginateur.

Quand vous êtes prêt à utiliser votre style de défilement, vous devez informer Zend_Paginator
dans quel dossier le chercher, en réalisant ceci :

$prefix = 'Mon_Paginator_StyleDefilement';
$path = 'Mon/Paginator/StyleDefilement/';
Zend_Paginator::addScrollingStylePrefixPath($prefix, $path);

4.3. Fonctionnalité de mise en cache


Zend_Paginator peut mettre en cache les données qu'il a déjà fourni, empêchant ainsi
l'adaptateur de les rechercher chaque fois qu'ils sont demandés. Pour informer le paginateur de
mettre en cache automatiquement les données issues de l'adaptateur, fournissez simplement
une instance de Zend_Cache_Core à sa méthode setCache() :

$paginator = Zend_Paginator::factory($someData);
$fO = array('lifetime' => 3600, 'automatic_serialization' => true);
$bO = array('cache_dir'=>'/tmp');
$cache = Zend_cache::factory('Core', 'File', $fO, $bO);
Zend_Paginator::setCache($cache);

Tant que Zend_Paginator possède une instance de Zend_Cache_Core, les données seront
mises en cache. Parfois vous ne voudrez pas mettre en cache les données même si vous avez
déjà fourni un instance de cache. Vous pourrez alors utiliser la méthode setCacheEnable() :

$paginator = Zend_Paginator::factory($someData);
// $cache est une instance de Zend_Cache_Core
Zend_Paginator::setCache($cache);
// ... plus loin dans le script
$paginator->setCacheEnable(false);
// le cache est maintenant désactivé

Quand un cache est paramétré, les données y sont automatiquement stockées et extraites. Il
peut alors être utile de vider le cache manuellement. Vous pouvez réaliser ceci en appelant
clearPageItemCache($pageNumber). Si vous ne passer aucun paramètre, le cache entier
sera vidé. Vous pouvez fournir optionnellement un paramètre représentant le numéro de page
à enlever du cache :

$paginator = Zend_Paginator::factory($someData);
Zend_Paginator::setCache($cache);
$items = $paginator->getCurrentItems();
// la page 1 est maintenant en cache
$page3Items = $paginator->getItemsByPage(3);
// la page 3 est maintenant en cache

// effacer le cache associé à la page 3


$paginator->clearPageItemCache(3);

// effacer tout le cache


$paginator->clearPageItemCache();

Changer le nombre d'éléments par page videra tout le cache comme s'il était devenu invalide :

1092
Zend_Paginator

$paginator = Zend_Paginator::factory($someData);
Zend_Paginator::setCache($cache);
// récupérer des éléments
$items = $paginator->getCurrentItems();

// toutes les données vont être effacées du cache :


$paginator->setItemCountPerPage(2);

Il est aussi possible de voir les données en cache et de les appeler directement grâce à la
méthode getPageItemCache() :

$paginator = Zend_Paginator::factory($someData);
$paginator->setItemCountPerPage(3);
Zend_Paginator::setCache($cache);

// récupérer des éléments


$items = $paginator->getCurrentItems();
$otherItems = $paginator->getItemsPerPage(4);

// voir ces éléments sous la forme d'un tableau à 2-dimensions :


var_dump($paginator->getPageItemCache());

4.4. Zend_Paginator_AdapterAggregate Interface


Depending on your application you might want to paginate objects, whose internal data-structure
is equal to existing adapters, but you don't want to break up your encapsulation to allow access
to this data. In other cases an object might be in a "has-an adapter" relationship, rather than the
"is-an adapter" relationsship that Zend_Paginator_Adapter_Abstract promotes. For this
cases you can use the Zend_Paginator_AdapterAggregate interface that behaves much
like the IteratorAggregate interface of the PHP SPL extension.

interface Zend_Paginator_AdapterAggregate
{
/**
* Return a fully configured Paginator Adapter from this method.
*
* @return Zend_Paginator_Adapter_Abstract
*/
public function getPaginatorAdapter();
}

The interface is fairly small and only expects you to return an instance of
Zend_Paginator_Adapter_Abstract. An Adapter Aggregate instance is then recognized
by both Zend_Paginator::factory and the constructor of Zend_Paginator and handled
accordingly.

1093
Zend_Pdf
1. Introduction
Zend_Pdf est un composant entièrement écrit en PHP5 permettant la manipulation de
documents PDF (Portable Document Format). Il peut charger des documents, créer, modifier
et les sauvegarder. Cela peut aider toute les applications PHP à générer dynamiquement des
documents PDF en modifiant un modèle existant ou en générant un document à partir de rien.
Zend_Pdf supporte les fonctionnalités suivantes :
1
• Créer un nouveau document ou en charger un qui existe déjà.

• Récupérer une version spécifique d'un document.

• Manipuler les pages d'un document. Changer l'ordre des pages, ajouter des nouvelles pages,
retirer des pages.

• Différents outils de dessins (lignes, rectangles, polygones, cercles, ellipses et secteurs).

• Dessiner du texte en utilisant une des 14 polices standard ou vos propres polices TrueType.

• Rotations.
2
• Inclure des images.

• Mise à jour incrémentale des fichiers PDF.

2. Créer et charger des documents PDF


La classe Zend_Pdf représente le document PDF en lui-même et fournis des méthodes pour
manipuler l'ensemble du document.

Pour créer un nouveau document, un nouvel objet Zend_Pdf doit être créé.

La classe Zend_Pdf fournis deux méthodes statiques pour charger un PDF existant. Ce sont
les méthodes Zend_Pdf::load() et Zend_Pdf::parse(). Les deux retournent un objet
Zend_Pdf ou lève une exception en cas d'erreur.

Exemple 589. Créer un nouveau document PDF ou en charger un existant

...
/// Crée un nouveau document PDF.
$pdf1 = new Zend_Pdf();

// Charge un document PDF depuis un fichier.


$pdf2 = Zend_Pdf::load($fileName);

// Charge un document PDF depuis une string


$pdf3 = Zend_Pdf::parse($pdfString);
...

Le format de fichier PDF supporte la mise à jour incrémentale d'un document. Ainsi chaque
fois que le document est mis à jour, une nouvelle version du document est créée. Le module
Zend_Pdf supporte la récupération d'une version spécifique.

1094
Zend_Pdf

La version peut-être donnée en second paramètre des méthodes Zend_Pdf::load() et


3
Zend_Pdf::parse() ou obligatoire dans le cas d'un appel à Zend_Pdf::rollback()

Exemple 590. Demander une version particulière d'un document PDF

...
// Charge la version précédente d'un document PDF.
$pdf1 = Zend_Pdf::load($fileName, 1);

// Charge la version précédente d'un document PDF.


$pdf2 = Zend_Pdf::parse($pdfString, 1);

// Charge la première version d'un document


$pdf3 = Zend_Pdf::load($fileName);
$revisions = $pdf3->revisions();
$pdf3->rollback($revisions - 1);
...

3. Sauvegarder les changement dans un document PDF


Il y a deux méthodes qui permettent la sauvegarde dans un document PDF. Ce sont
Zend_Pdf::save() et Zend_Pdf::render().

La méthode Zend_Pdf::save($filename, $updateOnly = false) sauvegarde un


document dans un fichier. Si $updateOnly est à TRUE, alors seulement les nouvelles sections
PDF sont ajoutées au fichier. Sinon le fichier est écrasé.

La méthode Zend_Pdf::render($filename, $newSegmentOnly = false) retourne


le document PDF dans une chaîne. Si $newSegmentOnly est à TRUE, alors seulement les
nouvelles sections du PDF sont retournées.

Exemple 591. Sauvegarder un document PDF

...
// Charge un document PDF.
$pdf = Zend_Pdf::load($fileName);
...
// Met à jour le document
$pdf->save($fileName, true);
// Sauvegarde le document dans un nouveau fichier.
$pdf->save($newFileName);

// Retourne le document PDF dans une string


$pdfString = $pdf->render();
...

4. Les pages d'un document


4.1. Création de page
Les pages d'un document PDF sont représentés par la classe Zend_Pdf_Page

Les pages d'un PDF proviennent d'un PDF existant, ou sont créées à partir de rien.
3
La méthode Zend_Pdf::rollback() doit être appelée avant tout changement. Sinon le comportement est indéfini.

1095
Zend_Pdf

Une nouvelle page peut-être obtenu en créant un nouvel objet Zend_Pdf_Page ou en appelant
la méthode Zend_Pdf::newPage()qui retourne un objet Zend_Pdf_Page. La différence est
que la méthode Zend_Pdf::newPage() crée une page directement attachée au document. A
la différence des pages non attachées à un document, elle ne peut-être utilisée dans plusieurs
4
documents PDF, mais est un peu plus performante. . C'est à vous de choisir quel approche
doit-être utilisée.

Les méthodes Zend_Pdf::newPage() et Zend_Pdf_Page prennent le même paramètre.


C'est la taille de la page ($x, $y) en point (1/72 inch soit 0,352778 mm), ou une constante
prédéfinie, qui correspond au format du papier :

• Zend_Pdf_Page::SIZE_A4

• Zend_Pdf_Page::SIZE_A4_LANDSCAPE

• Zend_Pdf_Page::SIZE_LETTER

• Zend_Pdf_Page::SIZE_LETTER_LANDSCAPE

Les pages du document sont stockées dans l'attribut public $pages de la classe Zend_Pdf.
C'est un tableau d'objet Zend_Pdf_Page. Il définit l'ensemble des pages, ainsi que l'ordre de
celle-ci et peut-être manipulé comme un tableau classique :

Exemple 592. Gestion des pages d'un document PDF

...
// Inverse l'ordre des pages
$pdf->pages = array_reverse($pdf->pages);
...
// Ajoute une nouvelle page
$pdf->pages[] = new Zend_Pdf_Page(Zend_Pdf_Page::SIZE_A4);
// Ajoute une nouvelle page
$pdf->pages[] = $pdf->newPage(Zend_Pdf_Page::SIZE_A4);

// Retire la page spécifiée


unset($pdf->pages[$id]);
...

4.2. Clonage de page


Les pages existantes d'un PDF peuvent être clonées en créant un nouvel objet Zend_Pdf_Page
avec la page existante comme paramètre :

4
C'est une limitation de la version courante du module Zend_Pdf. Ce sera corrigé dans une future version. Mais les pages non
attachées à un document donneront toujours de meilleurs résultats pour partager une page entre plusieurs documents.

1096
Zend_Pdf

Exemple 593. Cloner une page existante

...
// Stocke le modèle dans une variable séparée
$template = $pdf->pages[$templatePageIndex];
...
// Ajoute une nouvelle page
$page1 = new Zend_Pdf_Page($template);
$pdf->pages[] = $page1;
...

// Ajoute une autre page


$page2 = new Zend_Pdf_Page($template);
$pdf->pages[] = $page2;
...

// Enlève la page modèle du document


unset($pdf->pages[$templatePageIndex]);
...

C'est pratique si plusieurs pages doivent être créées sur le même modèle.

Important ! La page clonée partage quelques ressources PDF avec la page


modèle, donc ceci doit être utilisé seulement dans le même document qu'une
page modèle. Le document modifié peut être sauvegardé comme nouveau
document.

5. Dessiner
5.1. Géométrie
Le format PDF utilise la même géométrie que le format PostScript. Elle démarre d'en bas à
gauche et est mesuré en points (1/72 inch soit 0,352778 mm).

La taille d'une page peut-être récupéré depuis un objet page :

$width = $pdfPage->getWidth();
$height = $pdfPage->getHeight();

5.2. Couleurs
Le format PDF a d'excellentes capacités dans la représentation des couleurs. Le module
Zend_Pdf supporte les espaces de couleur : niveaux de gris, RGB et CMJN. Chacun
d'entre eux peut-être utilisé à chaque fois qu'un objet Zend_Pdf_Color est requis. Les
classes Zend_Pdf_Color_GrayScale, Zend_Pdf_Color_RGB et Zend_Pdf_Color_CMYK
fournissent cette fonctionnalité :

// $grayLevel (float). 0.0 (noir) - 1.0 (blanc)


$color1 = new Zend_Pdf_Color_GrayScale($grayLevel);

// $r, $g, $b (float).


// 0.0 (intensité mimimum) - 1.0 (intensité maximum)
$color2 = new Zend_Pdf_Color_RGB($r, $g, $b);

// $c, $m, $y, $k (float).


// 0.0 (intensité mimimum) - 1.0 (intensité maximum)

1097
Zend_Pdf

$color3 = new Zend_Pdf_Color_CMYK($c, $m, $y, $k);

Les différentes couleurs HTML sont aussi fourni avec la classe Zend_Pdf_Color_Html :

$color1 = new Zend_Pdf_Color_Html('#3366FF');


$color2 = new Zend_Pdf_Color_Html('silver');
$color3 = new Zend_Pdf_Color_Html('forestgreen');

5.3. Dessiner des formes


Toutes les opérations de dessins peuvent être réalisées dans le contexte d'une page PDF.

La classe Zend_Pdf_Page fournit les outils de dessins :

/**
* Dessine une ligne de x1,y1 à x2,y2.
*
* @param float $x1
* @param float $y1
* @param float $x2
* @param float $y2
* @return Zend_Pdf_Page
*/
public function drawLine($x1, $y1, $x2, $y2);

/**
* Draw a rounded rectangle.
*
* Fill types:
* Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE - fill rectangle and stroke (default)
* Zend_Pdf_Page::SHAPE_DRAW_STROKE - stroke rectangle
* Zend_Pdf_Page::SHAPE_DRAW_FILL - fill rectangle
*
* radius is an integer representing radius of the four corners, or an array
* of four integers representing the radius starting at top left, going
* clockwise
*
* @param float $x1
* @param float $y1
* @param float $x2
* @param float $y2
* @param integer|array $radius
* @param integer $fillType
* @return Zend_Pdf_Page
*/
public function drawRoundedRectangle($x1, $y1, $x2, $y2, $radius,
$fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE);

/**
* Dessine un rectangle.
*
* Type de remplissage:
* Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE
* - remplit le rectangle et dessine le contour (par défaut)
* Zend_Pdf_Page::SHAPE_DRAW_STROKE
* - trace uniquement le contour du rectangle
* Zend_Pdf_Page::SHAPE_DRAW_FILL
* - remplit le rectangle

1098
Zend_Pdf

*
* @param float $x1
* @param float $y1
* @param float $x2
* @param float $y2
* @return Zend_Pdf_Page
* @param integer $fillType
* @return Zend_Pdf_Page
*/
public function drawRectangle(
$x1, $y1, $x2, $y2, $fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE);

/**
* Dessine un polygone.
*
* Si $fillType est Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE
* ou Zend_Pdf_Page::SHAPE_DRAW_FILL,
* le polygone est automatiquement fermé.
* Regardez la description détaillée de ces méthodes dans la
* documentation du format PDF
* (section 4.4.2 Path painting Operators, Filling)
*
* @param array $x - tableau de float (les coordonnés X des sommets)
* @param array $y - tableau de float (les coordonnés Y des sommets)
* @param integer $fillType
* @param integer $fillMethod
* @return Zend_Pdf_Page
*/
public function drawPolygon(
$x, $y,
$fillType = Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE,
$fillMethod = Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING);

/**
* Dessine un cercle avec comme centre x, y et comme rayon radius.
*
* Les angles sont en radian
*
* Signatures des méthodes:
* drawCircle($x, $y, $radius);
* drawCircle($x, $y, $radius, $fillType);
* drawCircle($x, $y, $radius, $startAngle, $endAngle);
* drawCircle($x, $y, $radius, $startAngle, $endAngle, $fillType);
*
*
* Ce n'est pas réellement un cercle, car le format supporte
* uniquement des courbe de Bezier cubique.
* Mais c'est une très bonne approximation.
* La différence avec un vrai cercle est de au maximum 0.00026 radians
* (avec les angles PI/8, 3*PI/8, 5*PI/8, 7*PI/8, 9*PI/8, 11*PI/8,
* 13*PI/8 et 15*PI/8).
* Avec les angles 0, PI/4, PI/2, 3*PI/4, PI, 5*PI/4, 3*PI/2 et 7*PI/4
* c'est exactement la tangente d'un cercle.
*
* @param float $x
* @param float $y
* @param float $radius
* @param mixed $param4
* @param mixed $param5

1099
Zend_Pdf

* @param mixed $param6


* @return Zend_Pdf_Page
*/
public function drawCircle(
$x, $y, $radius, $param4 = null, $param5 = null, $param6 = null);

/**
* Dessine une ellipse dans le rectangle spécifié.
*
* Signatures des méthodes:
* drawEllipse($x1, $y1, $x2, $y2);
* drawEllipse($x1, $y1, $x2, $y2, $fillType);
* drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle);
* drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle, $fillType);
*
* Les angles sont en radians
*
* @param float $x1
* @param float $y1
* @param float $x2
* @param float $y2
* @param mixed $param5
* @param mixed $param6
* @param mixed $param7
* @return Zend_Pdf_Page
*/
public function drawEllipse(
$x1, $y1, $x2, $y2, $param5 = null, $param6 = null, $param7 = null);

5.4. Dessiner du texte


Les opérations de dessins existent bien sûr dans le contexte d'une page PDF. Vous pouvez
dessiner une seule ligne de texte à n'importe quelle endroit dans la page en fournissant les
coordonnées x et y de la ligne de base. La police courant ainsi que sa taille seront utilisées pour
le dessin (voir la description ci-dessous).

/**
* Dessine une ligne de texte à la position x,y.
*
* @param string $text
* @param float $x
* @param float $y
* @param string $charEncoding (optionnel) encodage des caractères du texte.
* Par défaut le réglage système est utilisé.
* @throws Zend_Pdf_Exception
* @return Zend_Pdf_Page
*/
public function drawText($text, $x, $y, $charEncoding = '');

Exemple 594. Dessiner une ligne dans la page

...
$pdfPage->drawText('Bonjour le monde!', 72, 720);
...

Par défaut, les chaînes de texte sont interprétées en utilisant l'encodage du système. Si vous
avez une chaîne qui utilise un encodage différent (comme les chaînes UTF-8 lues depuis

1100
Zend_Pdf

une fichier sur le disque, ou une chaîne MacRoman obtenue depuis une base de données),
vous pouvez indiquer l'encodage au moment du dessin et Zend_Pdf gérera la conversion pour
vous. Vous pouvez fournir des chaînes dans n'importe quel encodage supporté par la fonction
iconv() de PHP:

Exemple 595. Dessiner une chaîne UTF-8 sur une page

...
// Lit une chaîne UTF-8 à partir du disque
$unicodeString = fread($fp, 1024);

// Dessine une chaîne dans la page


$pdfPage->drawText($unicodeString, 72, 720, 'UTF-8');
...

5.5. Utiliser des polices de caractères


Zend_Pdf_Page::drawText() utilise la police courante ainsi que sa taille, qui sont définies
avec la méthode Zend_Pdf_Page::setFont() :

/**
* Choisit la police courante.
*
* @param Zend_Pdf_Resource_Font $font
* @param float $fontSize
* @return Zend_Pdf_Page
*/
public function setFont(Zend_Pdf_Resource_Font $font, $fontSize);

Les documents PDF supportent PostScript Type 1 et les polices TrueType, mais également
deux types spécifiques PDF, Type3 et les polices composites. Il y a aussi 14 polices Type 1
standard intégré dans tout lecteur de PDF : Courier (4 styles), Helvetica (4 styles), Times (4
styles), Symbol, et Zapf Dingbats.

Zend_Pdf supporte actuellement les 14 polices standard mais également vos propres
police TrueType. Les objets de police obtenus via une des deux fabriques méthodes :
Zend_Pdf_Font::fontWithName($fontName) pour les 14 polices PDF standard ou
Zend_Pdf_Font::fontWithPath($filePath) pour les polices personnalisées.

Exemple 596. Créer une police standard

...
// Crée une nouvelle police
$font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA);

// Applique la police
$pdfPage->setFont($font, 36);
...

Les constantes pour les 14 polices standard sont définis dans la classe Zend_Pdf_Font :

• Zend_Pdf_Font::FONT_COURIER

• Zend_Pdf_Font::FONT_COURIER_BOLD

• Zend_Pdf_Font::FONT_COURIER_ITALIC

1101
Zend_Pdf

• Zend_Pdf_Font::FONT_COURIER_BOLD_ITALIC

• Zend_Pdf_Font::FONT_TIMES

• Zend_Pdf_Font::FONT_TIMES_BOLD

• Zend_Pdf_Font::FONT_TIMES_ITALIC

• Zend_Pdf_Font::FONT_TIMES_BOLD_ITALIC

• Zend_Pdf_Font::FONT_HELVETICA

• Zend_Pdf_Font::FONT_HELVETICA_BOLD

• Zend_Pdf_Font::FONT_HELVETICA_ITALIC

• Zend_Pdf_Font::FONT_HELVETICA_BOLD_ITALIC

• Zend_Pdf_Font::FONT_SYMBOL

• Zend_Pdf_Font::FONT_ZAPFDINGBATS

Vous pouvez aussi prendre n'importe quelle police TrueType (extension habituelle ".ttf") ou
OpenType (".otf") si elles ont une silhouette TrueType. Pour l'instant non supportée, les polices
Mac Os X ".dfont" et les collections TrueType Microsoft (".ttc") seront intégrées dans une version
future.

Pour utiliser une police TrueType, vous devez fournir le chemin de fichier complet vers cette
police. Si la police ne peut pas être lue pour une quelconque raison, ou si ce n'est pas une police
TrueType, la méthode lèvera une exception :

Exemple 597. Créer une police TrueType

...
// Crée la nouvelle police
$goodDogCoolFont = Zend_Pdf_Font::fontWithPath('/chemin/vers/GOODDC__.TTF');

// Applique cette police


$pdfPage->setFont($goodDogCoolFont, 36);
...

Par défaut, les polices personnalisées seront incorporées dans le document PDF résultant. Cela
permet aux destinataires de voir la page comme prévu, même s'ils ne font pas installer les polices
appropriées sur leur système. En cas de problème avec la taille du fichier généré, vous pouvez
demander que la police ne soit pas incorporé en passant l'option 'ne pas inclure' à la méthode
de création :

Exemple 598. Créer une police TrueType sans l'incorporer dans le document PDF

...
// Crée la nouvelle police
$goodDogCoolFont =
Zend_Pdf_Font::fontWithPath('/chemin/vers/GOODDC__.TTF',
Zend_Pdf_Font::EMBED_DONT_EMBED);

// Applique cette police


$pdfPage->setFont($goodDogCoolFont, 36);
...

1102
Zend_Pdf

Si les polices ne sont pas incorporées mais que le destinataire du fichier PDF a ces polices
installées sur son système, il verra le document comme prévu. Si la police correcte n'est pas
installée, l'application de visualisation du PDF fera de son mieux pour synthétiser une police de
remplacement.

Quelques polices ont les règles de licence très spécifiques qui les empêchent d'être incorporées
dans des documents PDF. Donc vous devez faire attention, si vous essayez d'utiliser une police
qui ne peut pas être incorporée, la méthode de création lèvera une exception.

Vous pouvez toujours utiliser ces polices, mais vous devez passer le paramètre 'ne pas inclure'
comme décrit ci-dessous, ou vous pouvez simplement bloquer l'exception :

Exemple 599. Ne pas lever d'exception pour les polices ne pouvant être
incorporées

...
$font =
Zend_Pdf_Font::fontWithPath('/chemin/vers/PoliceNonIncorporable.ttf',
Zend_Pdf_Font::EMBED_SUPPRESS_EMBED_EXCEPTION);
...

Cette technique de suppression est préférée si vous permettez aux utilisateurs de choisir leurs
propres polices. Les polices qui peuvent être incorporées dans le document PDF le seront ; les
autres ne le seront pas.

Les fichiers de police peuvent être assez grands, certains peuvent atteindre des dizaines de
méga-octets. Par défaut, toutes les polices incorporées sont comprimées en utilisant le schéma
de compression Flate, ayant pour résultat un gain d'espace de 50% en moyenne. Si, pour une
quelconque raison, vous ne voulez pas comprimer la police, vous pouvez le neutraliser avec
une option :

Exemple 600. Ne pas compresser une police incorporée

...
$font =
Zend_Pdf_Font::fontWithPath('/chemin/vers/PoliceDeGrandeTaille.ttf',
Zend_Pdf_Font::EMBED_DONT_COMPRESS);
...

En conclusion, si nécessaire, vous pouvez combiner les options d'incorporation en employant


l'opérateur binaire OR :

Exemple 601. Combiner les options de polices incorporées

...
$font = Zend_Pdf_Font::fontWithPath(
$cheminVersPoliceQuelconque,
(Zend_Pdf_Font::EMBED_SUPPRESS_EMBED_EXCEPTION |
Zend_Pdf_Font::EMBED_DONT_COMPRESS));
...

5.6. Limitations des polices standard PDF


Les polices standard PDF emploient en interne plusieurs encodages sur un seul octet (voir PDF
Reference, Sixth Edition, version 1.7 - Annexe D pour plus de détails). Elles sont généralement
avec un jeu de caractère de type Latin1(excepté les polices Symbol and ZapfDingbats).

1103
Zend_Pdf

Zend_Pdf utilise l'encodage CP1252 (WinLatin1) pour tracer les textes avec les polices
standard.

Le texte peut encore être fourni dans n'importe quel autre encodage, qui doit être spécifié s'il
diffère de celui en cours. Seulement les caractères WinLatin1 seront tracés réellement.

Exemple 602. Combiner les options de polices embarqués

...
$font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_COURIER);
$pdfPage->setFont($font, 36)
->drawText('Euro sign - €', 72, 720, 'UTF-8')
->drawText('Text with umlauts - à è ì', 72, 650, 'UTF-8');
...

5.7. Extraction des polices


Depuis la version 1.5, Zend_Pdf fournit la possibilité d'extraire les polices des documents
chargés.

Ceci peut être utile lors des mises à jour de document avec ajout de texte. Sans cette
fonctionnalité vous devez attacher et probablement intégrer la police dans le document chaque
fois que vous voulez le mettre à jour.

Les objets Zend_Pdf et Zend_Pdf_Page fournissent une méthode spéciale pour extraire toutes
les polices mentionnés à l'intérieur d'un document ou d'une page :

Exemple 603. Extraction de polices à partir d'un document chargé

...
$pdf = Zend_Pdf::load($cheminVersDocument);
...
// Récupère toutes les polices du document
$listePolice = $pdf->extractFonts();
$pdf->pages[] = ($page = $pdf->newPage(Zend_Pdf_Page::SIZE_A4));
$yPosition = 700;
foreach ($listePolice as $police) {
$page->setFont($police, 15);
$page->drawText(
$police->getFontName(Zend_Pdf_Font::NAME_POSTSCRIPT, 'fr', 'UTF-8')
. ': Le renard brun rapide saute par-dessus le chien paresseux',
100,
$yPosition,
'UTF-8');
$yPosition -= 30;
}
...
// Récupère toutes les polices référencées dans la première page du document
$firstPage = reset($pdf->pages);
$firstPageFonts = $firstPage->extractFonts();
...

1104
Zend_Pdf

Exemple 604. Extraction d'une police à partir d'un document chargé en spécifiant
le nom de police

...
$pdf = new Zend_Pdf();
...
$pdf->pages[] = ($page = $pdf->newPage(Zend_Pdf_Page::SIZE_A4));

$police = Zend_Pdf_Font::fontWithPath($cheminVersPolices);
$page->setFont($police, $taillePolice);
$page->drawText($texte, $x, $y);
...
// Ce nom de police peut être stocké quelquepart...
$fontName = $font->getFontName(Zend_Pdf_Font::NAME_POSTSCRIPT, 'fr', 'UTF-8');
...
$pdf->save($cheminVersDocument);
...

...
$pdf = Zend_Pdf::load($cheminVersDocument);
...
$pdf->pages[] = ($page = $pdf->newPage(Zend_Pdf_Page::SIZE_A4));

$police = $pdf->extractFont($nomPolice);
/* $pageSource->extractFont($nomPolice) peut aussi être utilisé ici */
$page->setFont($police, $taillePolice);
$page->drawText($texte, $x, $y);
...
$pdf->save($cheminVersDocument, true /* mise à jour de type incrémental */);
...

Les polices extraites peuvent être utilisées à la place de n'importe quelle autre police avec les
limitations suivantes :

• La police extraite peut être employée seulement dans le cadre du document à partir duquel
elle a été extraite.

• Les possibles programmes de polices incorporées ne sont pas extraits réellement. La police
ainsi extraite ne peut pas fournir la métrique correcte de police et la police originale doit être
utilisée pour les calculs de largeur des textes :

...
$police = $pdf->extractFont($fontName);
$policeOriginal = Zend_Pdf_Font::fontWithPath($cheminVersPolices);

/* utilisation d'une police extraite */


$page->setFont($police, $taillePolice);
$xPosition = $x;
for ($charIndex = 0; $charIndex < strlen($text); $charIndex++) {
$page->drawText($text[$charIndex], $xPosition, $y);

// Use original font for text width calculation


$width = $originalFont->widthForGlyph(
$originalFont->glyphNumberForCharacter($text[$charIndex])
);
$xPosition += $width / $originalFont->getUnitsPerEm() * $taillePolice;
}
...

1105
Zend_Pdf

5.8. Insertion d'images


La classe Zend_Pdf_Page fournis la méthode drawImage() pour dessiner une image :

/**
* Insère une image à la position spécifiée dans la page
*
* @param Zend_Pdf_Resource_Image $image
* @param float $x1
* @param float $y1
* @param float $x2
* @param float $y2
* @return Zend_Pdf_Page
*/
public function drawImage(Zend_Pdf_Resource_Image $image, $x1, $y1, $x2, $y2);

Les objets Image peuvent être créés avec la méthode


Zend_Pdf_Image::imageWithPath($filePath) (les images JPG, PNG et TIFF sont
maintenant supportées) :

Exemple 605. Insertion d'images

...
//Charger une image
$image = Zend_Pdf_Image::imageWithPath('mon_image.jpg');

$pdfPage->drawImage($image, 100, 100, 400, 300);


...

Important ! Le support JPEG nécessite que l'extension PHP GD soit installé. Important ! Le
support PNG nécessite que l'extension ZLIB soit configuré pour accepter les images avec canaux
Alpha.

Lisez la documentation de PHP pour plus d'informations (http://www.php.net/manual/fr/


ref.image.php et http://www.php.net/manual/fr/ref.zlib.php).

5.9. Style de lignes


Le style de ligne est définit par l'épaisseur, la couleur et le style de tiret. Tout ces paramètres
peuvent être assignés par les méthodes de la classe Zend_Pdf_Page :

/** Choisit la couleur de ligne. */


public function setLineColor(Zend_Pdf_Color $color);

/** Choisit l'épaisseur de ligne. */


public function setLineWidth(float $width);

/**
* Choisit le modèle de tiret.
*
* modele est un tableau de floats: array(longueur_visible,
* longueur_invisible, longueur_visible, longueur_invisible,
* ...)
* phase est le décalage à partir du début de la ligne.
*
* @param array $modele

1106
Zend_Pdf

* @param array $phase


* @return Zend_Pdf_Page
*/
public function setLineDashingPattern($pattern, $phase = 0);

5.10. Style de remplissage


Les méthodes Zend_Pdf_Page::drawRectangle(), Zend_Pdf_Page::drawPoligon(),
Zend_Pdf_Page::drawCircle() et Zend_Pdf_Page::drawEllipse() prennent en
argument optionnel le type de remplissage: $fillType. Il peut être :

• Zend_Pdf_Page::SHAPE_DRAW_STROKE - trace le contour de la forme

• Zend_Pdf_Page::SHAPE_DRAW_FILL - remplit uniquement la forme

• Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE - remplissage et contour (par défaut)

La méthode Zend_Pdf_Page::drawPoligon() prend aussi paramètre supplémentaire


$fillMethod :

• $fillMethod = Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING (par défaut)

La référence du format PDF décrit la règle comme ceci :

The nonzero winding number rule determines whether a given point is inside
a path by conceptually drawing a ray from that point to infinity in any direction
and then examining the places where a segment of the path crosses the ray.
Starting with a count of 0, the rule adds 1 each time a path segment crosses
the ray from left to right and subtracts 1 each time a segment crosses from
right to left. After counting all the crossings, if the result is 0 then the point is
outside the path; otherwise it is inside. Note: The method just described does
not specify what to do if a path segment coincides with or is tangent to the
chosen ray. Since the direction of the ray is arbitrary, the rule simply chooses
a ray that does not encounter such problem intersections. For simple convex
paths, the nonzero winding number rule defines the inside and outside as
one would intuitively expect. The more interesting cases are those involving
complex or self-intersecting paths like the ones shown in Figure 4.10 (in a
PDF Reference). For a path consisting of a five-pointed star, drawn with five
connected straight line segments intersecting each other, the rule considers
the inside to be the entire area enclosed by the star, including the pentagon in
the center. For a path composed of two concentric circles, the areas enclosed
by both circles are considered to be inside, provided that both are drawn in
the same direction. If the circles are drawn in opposite directions, only the
"doughnut" shape between them is inside, according to the rule; the "doughnut
hole" is outside.

• Zend_Pdf_Page::FILL_METHOD_EVEN_ODD

La référence du format PDF décrit la règle comme ceci :

An alternative to the nonzero winding number rule is the even-odd rule. This
rule determines the "insideness" of a point by drawing a ray from that point
in any direction and simply counting the number of path segments that cross
the ray, regardless of direction. If this number is odd, the point is inside; if
even, the point is outside. This yields the same results as the nonzero winding

1107
Zend_Pdf

number rule for paths with simple shapes, but produces different results for
more complex shapes. Figure 4.11 (in a PDF Reference) shows the effects of
applying the even-odd rule to complex paths. For the five-pointed star, the rule
considers the triangular points to be inside the path, but not the pentagon in
the center. For the two concentric circles, only the "doughnut" shape between
the two circles is considered inside, regardless of the directions in which the
circles are drawn.

5.11. Transformations linéaires


5.11.1. Rotations
La page PDF page peut être tourné avant d'appliquer toute opération de dessin. Ceci peut être
fait avec la méthode Zend_Pdf_Page::rotate() :

/**
* Rotation de la page
*
* @param float $x - la coordonnée X du point de rotation
* @param float $y - la coordonnée X du point de rotation
* @param float $angle - angle de rotation
* @return Zend_Pdf_Page
*/
public function rotate($x, $y, $angle);

5.11.2. A partir de Zend Framework 1.8, mise à l'échelle


La mise à l'échelle est fournie par la méthode Zend_Pdf_Page::scale() :

/**
* Mise à l'échelle
*
* @param float $xScale - X dimention scale factor
* @param float $yScale - Y dimention scale factor
* @return Zend_Pdf_Page
*/
public function scale($xScale, $yScale);

5.11.3. A partir de Zend Framework 1.8, décalage


Le décalage du système de coordonnées est réalisé par la méthode
Zend_Pdf_Page::translate() :

/**
* Décalage du système de coordonnées
*
* @param float $xShift - coordonnées X du décalage
* @param float $yShift - coordonnées Y du décalage
* @return Zend_Pdf_Page
*/
public function translate($xShift, $yShift);

5.11.4. A partir de Zend Framework 1.8, mise en biais


La mise en biais de la page peut être réalisé par la méthode Zend_Pdf_Page::skew() :

1108
Zend_Pdf

/**
* Mise en biais du système de coordonnées
*
* @param float $x - the X co-ordinate of axis skew point
* @param float $y - the Y co-ordinate of axis skew point
* @param float $xAngle - X axis skew angle
* @param float $yAngle - Y axis skew angle
* @return Zend_Pdf_Page
*/
public function skew($x, $y, $xAngle, $yAngle);

5.12. Sauvegarder et restaurer l'état graphique


L'état graphique (police courante, taille de caractère, couleur de ligne, couleur de remplissage,
style de ligne, sens de la page, zone de dessin) peut-être sauvegarder à tout moment.
L'opération de sauvegarde empile le contexte dans une pile de contexte graphique, l'opération
de restauration récupère le contexte depuis la pile.

Il y a deux méthodes dans la classe Zend_Pdf_Page pour réaliser ces opérations :

/**
* Sauvegarde l'état graphique de la page.
* Cela prend un instantané des styles courants, des zones de dessins
* et de toutes les rotations/translations/changements de taille appliqués.
*
* @return Zend_Pdf_Page
*/
public function saveGS();

/**
* Restaure le dernier état graphique sauvegarder avec saveGS().
*
* @return Zend_Pdf_Page
*/
public function restoreGS();

5.13. Zone de dessin


Le format PDF et le module Zend_Pdf supporte le découpage de la zone de dessin. La zone
de dessin courante limite la zone de la page affectée par l'utilisation des opérateurs de dessins.
Initialement c'est toute la page.

La classe Zend_Pdf_Page fournit des méthodes pour les opérations de découpage.

/**
* Découpe la zone courante avec un rectangle.
*
* @param float $x1
* @param float $y1
* @param float $x2
* @param float $y2
* @return Zend_Pdf_Page
*/
public function clipRectangle($x1, $y1, $x2, $y2);

/**

1109
Zend_Pdf

* Découpe la zone courante avec un polygone.


*
* @param array $x - tableau de float (les coordonnées X des sommets)
* @param array $y - tableau de float (les coordonnées Y des sommets)
* @param integer $fillMethod
* @return Zend_Pdf_Page
*/
public function clipPolygon(
$x, $y, $fillMethod = Zend_Pdf_Page::FILL_METHOD_NON_ZERO_WINDING);

/**
* Découpe la zone courante avec un cercle.
*
* @param float $x
* @param float $y
* @param float $radius
* @param float $startAngle
* @param float $endAngle
* @return Zend_Pdf_Page
*/
public function clipCircle(
$x, $y, $radius, $startAngle = null, $endAngle = null);

/**
* Découpe la zone courante avec une ellipse.
*
* Signatures des méthodes:
* drawEllipse($x1, $y1, $x2, $y2);
* drawEllipse($x1, $y1, $x2, $y2, $startAngle, $endAngle);
*
* @todo s'occuper des cas spéciaux avec $x2-$x1 == 0 ou $y2-$y1 == 0
*
* @param float $x1
* @param float $y1
* @param float $x2
* @param float $y2
* @param float $startAngle
* @param float $endAngle
* @return Zend_Pdf_Page
*/
public function clipEllipse(
$x1, $y1, $x2, $y2, $startAngle = null, $endAngle = null);

5.14. Styles
La classe Zend_Pdf_Style fournit les fonctionnalités de style.

Les styles peuvent être utilisés pour stocker des paramètre d'état graphique et de les appliquer
à une page PDF en une seule opération :

/**
* Choisit le style à utiliser pour les futures opérations
* de dessin sur cette page
*
* @param Zend_Pdf_Style $style
* @return Zend_Pdf_Page
*/

1110
Zend_Pdf

public function setStyle(Zend_Pdf_Style $style);

/**
* Renvoie le style appliqué à la page.
*
* @return Zend_Pdf_Style|null
*/
public function getStyle();

La classe Zend_Pdf_Style fournit des méthodes pour choisir ou récupérer différents


paramètres de l'état graphique :

/**
* Choisit la couleur de ligne.
*
* @param Zend_Pdf_Color $color
* @return Zend_Pdf_Page
*/
public function setLineColor(Zend_Pdf_Color $color);

/**
* Récupère la couleur de ligne.
*
* @return Zend_Pdf_Color|null
* @return Zend_Pdf_Page
*/
public function getLineColor();

/**
* Choisit l'épaisseur de ligne.
*
* @param float $width
* @return Zend_Pdf_Page
*/
public function setLineWidth($width);

/**
* Récupère l'épaisseur de ligne.
*
* @return float
* @return Zend_Pdf_Page
*/
public function getLineWidth($width);

/**
* Choisit le style de tiret
*
* @param array $pattern
* @param float $phase
* @return Zend_Pdf_Page
*/
public function setLineDashingPattern($pattern, $phase = 0);

/**
* Récupère le style de tiret
*

1111
Zend_Pdf

* @return array
*/
public function getLineDashingPattern();

/**
* Récupère le modèle de tiret
*
* @return float
*/
public function getLineDashingPhase();

/**
* Choisit la couleur de remplissage.
*
* @param Zend_Pdf_Color $color
* @return Zend_Pdf_Page
*/
public function setFillColor(Zend_Pdf_Color $color);

/**
* Récupère la couleur de remplissage.
*
* @return Zend_Pdf_Color|null
*/
public function getFillColor();

/**
* Choisit la police.
*
* @param Zend_Pdf_Font $font
* @param Zend_Pdf_Resource_Font $font
* @param float $fontSize
*/
public function setFont(Zend_Pdf_Resource_Font $font, $fontSize);

/**
* Modifie la taille de police.
*
* @param float $fontSize
* @return Zend_Pdf_Page
*/
public function setFontSize($fontSize);

/**
* Récupère la police courante
*
* @return Zend_Pdf_Resource_Font $font
*/
public function getFont();

/**
* Récupère la taille de la police
*
* @return float $fontSize
*/

1112
Zend_Pdf

public function getFontSize();

5.15. Transparence
Le module Zend_Pdf supporte la gestion de la transparence.

La transparence peut être paramétré en utilisant la méthode Zend_Pdf_Page::setAlpha() :

/**
* Règle la transparence
*
* $alpha == 0 - transparent
* $alpha == 1 - opaque
*
* Transparency modes, supported by PDF:
* Normal (default), Multiply, Screen, Overlay, Darken,
* Lighten, ColorDodge, ColorBurn, HardLight,
* SoftLight, Difference, Exclusion
*
* @param float $alpha
* @param string $mode
* @throws Zend_Pdf_Exception
* @return Zend_Pdf_Page
*/
public function setAlpha($alpha, $mode = 'Normal');

6. Interactive Features
6.1. Destinations
A destination defines a particular view of a document, consisting of the following items:

• The page of the document to be displayed.

• The location of the document window on that page.

• The magnification (zoom) factor to use when displaying the page.

Destinations may be associated with outline items (Document Outline (bookmarks)), annotations
(Annotations), or actions (Actions). In each case, the destination specifies the view of the
document to be presented when the outline item or annotation is opened or the action is
performed. In addition, the optional document open action can be specified.

6.1.1. Supported Destination Types

The following types are supported by Zend_Pdf component.

6.1.1.1. Zend_Pdf_Destination_Zoom

Display the specified page, with the coordinates (left, top) positioned at the upper-left corner of
the window and the contents of the page magnified by the factor zoom.

Destination object may be created using Zend_Pdf_Destination_Zoom::create($page,


$left = null, $top = null, $zoom = null) method.

1113
Zend_Pdf

Where:

• $page is a destination page (a Zend_Pdf_Page object or a page number).

• $left is a left edge of the displayed page (float).

• $top is a top edge of the displayed page (float).

• $zoom is a zoom factor (float).

NULL, specified for $left, $top or $zoom parameter means "current viewer application value".

Zend_Pdf_Destination_Zoom class also provides the following methods:

• FloatgetLeftEdge();

• setLeftEdge(float $left);

• FloatgetTopEdge();

• setTopEdge(float $top);

• FloatgetZoomFactor();

• setZoomFactor(float $zoom);

6.1.1.2. Zend_Pdf_Destination_Fit

Display the specified page, with the coordinates (left, top) positioned at the upper-left corner of the
window and the contents of the page magnified by the factor zoom. Display the specified page,
with its contents magnified just enough to fit the entire page within the window both horizontally
and vertically. If the required horizontal and vertical magnification factors are different, use the
smaller of the two, centering the page within the window in the other dimension.

Destination object may be created using Zend_Pdf_Destination_Fit::create($page)


method.

Where $page is a destination page (a Zend_Pdf_Page object or a page number).

6.1.1.3. Zend_Pdf_Destination_FitHorizontally

Display the specified page, with the vertical coordinate top positioned at the top edge of the
window and the contents of the page magnified just enough to fit the entire width of the page
within the window.

Destination object may be created using


Zend_Pdf_Destination_FitHorizontally::create($page, $top) method.

Where:

• $page is a destination page (a Zend_Pdf_Page object or a page number).

• $top is a top edge of the displayed page (float).

Zend_Pdf_Destination_FitHorizontally class also provides the following methods:

1114
Zend_Pdf

• FloatgetTopEdge();

• setTopEdge(float $top);

6.1.1.4. Zend_Pdf_Destination_FitVertically

Display the specified page, with the horizontal coordinate left positioned at the left edge of the
window and the contents of the page magnified just enough to fit the entire height of the page
within the window.

Destination object may be created using


Zend_Pdf_Destination_FitVertically::create($page, $left) method.

Where:

• $page is a destination page (a Zend_Pdf_Page object or a page number).

• $left is a left edge of the displayed page (float).

Zend_Pdf_Destination_FitVertically class also provides the following methods:

• FloatgetLeftEdge();

• setLeftEdge(float $left);

6.1.1.5. Zend_Pdf_Destination_FitRectangle

Display the specified page, with its contents magnified just enough to fit the rectangle specified
by the coordinates left, bottom, right, and top entirely within the window both horizontally and
vertically. If the required horizontal and vertical magnification factors are different, use the smaller
of the two, centering the rectangle within the window in the other dimension.

Destination object may be created using


Zend_Pdf_Destination_FitRectangle::create($page, $left, $bottom,
$right, $top) method.

Where:

• $page is a destination page (a Zend_Pdf_Page object or a page number).

• $left is a left edge of the displayed page (float).

• $bottom is a bottom edge of the displayed page (float).

• $right is a right edge of the displayed page (float).

• $top is a top edge of the displayed page (float).

Zend_Pdf_Destination_FitRectangle class also provides the following methods:

• FloatgetLeftEdge();

• setLeftEdge(float $left);

• FloatgetBottomEdge();

1115
Zend_Pdf

• setBottomEdge(float $bottom);

• FloatgetRightEdge();

• setRightEdge(float $right);

• FloatgetTopEdge();

• setTopEdge(float $top);

6.1.1.6. Zend_Pdf_Destination_FitBoundingBox

Display the specified page, with its contents magnified just enough to fit its bounding box
entirely within the window both horizontally and vertically. If the required horizontal and vertical
magnification factors are different, use the smaller of the two, centering the bounding box within
the window in the other dimension.

Destination object may be created using


Zend_Pdf_Destination_FitBoundingBox::create($page, $left, $bottom,
$right, $top) method.

Where $page is a destination page (a Zend_Pdf_Page object or a page number).

6.1.1.7. Zend_Pdf_Destination_FitBoundingBoxHorizontally

Display the specified page, with the vertical coordinate top positioned at the top edge of the
window and the contents of the page magnified just enough to fit the entire width of its bounding
box within the window.

Destination object may be created using


Zend_Pdf_Destination_FitBoundingBoxHorizontally::create($page, $top)
method.

Where

• $page is a destination page (a Zend_Pdf_Page object or a page number).

• $top is a top edge of the displayed page (float).

Zend_Pdf_Destination_FitBoundingBoxHorizontally class also provides the


following methods:

• FloatgetTopEdge();

• setTopEdge(float $top);

6.1.1.8. Zend_Pdf_Destination_FitBoundingBoxVertically

Display the specified page, with the horizontal coordinate left positioned at the left edge of the
window and the contents of the page magnified just enough to fit the entire height of its bounding
box within the window.

Destination object may be created using


Zend_Pdf_Destination_FitBoundingBoxVertically::create($page, $left)
method.

1116
Zend_Pdf

Where

• $page is a destination page (a Zend_Pdf_Page object or a page number).

• $left is a left edge of the displayed page (float).

Zend_Pdf_Destination_FitBoundingBoxVertically class also provides the following


methods:

• FloatgetLeftEdge();

• setLeftEdge(float $left);

6.1.1.9. Zend_Pdf_Destination_Named

All destinations listed above are "Explicit Destinations".

In addition to this, PDF document may contain a dictionary of such destinations which
may be used to reference from outside the PDF (e.g. 'http://www.mycompany.com/
document.pdf#chapter3').

Zend_Pdf_Destination_Named objects allow to refer destinations from the document named


destinations dictionary.

Named destination object may be created using


Zend_Pdf_Destination_Named::create(string $name) method.

Zend_Pdf_Destination_Named class provides the only one additional method:

StringgetName();

6.1.2. Document level destination processing

Zend_Pdf class provides a set of destinations processing methods.

Each destination object (including named destinations) can be resolved using the
resolveDestination($destination) method. It returns corresponding Zend_Pdf_Page
object, if destination target is found, or NULL otherwise.

Zend_Pdf::resolveDestination() method also takes an optional boolean parameter


$refreshPageCollectionHashes, which is TRUE by default. It forces Zend_Pdf object to
refresh internal page collection hashes since document pages list may be updated by user
using Zend_Pdf::$pages property (Working with Pages). It may be turned off for performance
reasons, if it's known that document pages list wasn't changed since last method request.

Complete list of named destinations can be retrieved using


Zend_Pdf::getNamedDestinations() method. It returns an array of Zend_Pdf_Target
objects, which are actually either an explicit destination or a GoTo action (Actions).

Zend_Pdf::getNamedDestination(string $name) method returns specified named


destination (an explicit destination or a GoTo action).

PDF document named destinations dictionary may be updated with


Zend_Pdf::setNamedDestination(string $name, $destination) method,

1117
Zend_Pdf

where $destination is either an explicit destination (any destination except


Zend_Pdf_Destination_Named) or a GoTo action.

If NULL is specified in place of $destination, then specified named destination is removed.

Unresolvable named destinations are automatically removed from a document


while document saving.

Exemple 606. Destinations usage example

$pdf = new Zend_Pdf();


$page1 = $pdf->newPage(Zend_Pdf_Page::SIZE_A4);
$page2 = $pdf->newPage(Zend_Pdf_Page::SIZE_A4);
$page3 = $pdf->newPage(Zend_Pdf_Page::SIZE_A4);
// Page created, but not included into pages list

$pdf->pages[] = $page1;
$pdf->pages[] = $page2;

$destination1 = Zend_Pdf_Destination_Fit::create($page2);
$destination2 = Zend_Pdf_Destination_Fit::create($page3);

// Returns $page2 object


$page = $pdf->resolveDestination($destination1);

// Returns null, page 3 is not included into document yet


$page = $pdf->resolveDestination($destination2);

$pdf->setNamedDestination('Page2', $destination1);
$pdf->setNamedDestination('Page3', $destination2);

// Returns $destination2
$destination = $pdf->getNamedDestination('Page3');

// Returns $destination1
$pdf->resolveDestination(Zend_Pdf_Destination_Named::create('Page2'));

// Returns null, page 3 is not included into document yet


$pdf->resolveDestination(Zend_Pdf_Destination_Named::create('Page3'));

6.2. Actions
Instead of simply jumping to a destination in the document, an annotation or outline item can
specify an action for the viewer application to perform, such as launching an application, playing
a sound, or changing an annotation's appearance state.

6.2.1. Supported action types

The following action types are recognized while loading PDF document:

• Zend_Pdf_Action_GoTo - go to a destination in the current document.

• Zend_Pdf_Action_GoToR - go to a destination in another document.

• Zend_Pdf_Action_GoToE - go to a destination in an embedded file.

1118
Zend_Pdf

• Zend_Pdf_Action_Launch - launch an application or open or print a document.

• Zend_Pdf_Action_Thread - begin reading an article thread.

• Zend_Pdf_Action_URI - resolve a URI.

• Zend_Pdf_Action_Sound - play a sound.

• Zend_Pdf_Action_Movie - play a movie.

• Zend_Pdf_Action_Hide - hides or shows one or more annotations on the screen.

• Zend_Pdf_Action_Named - execute an action predefined by the viewer application:

• NextPage - Go to the next page of the document.

• PrevPage - Go to the previous page of the document.

• FirstPage - Go to the first page of the document.

• LastPage - Go to the last page of the document.

• Zend_Pdf_Action_SubmitForm - send data to a uniform resource locator.

• Zend_Pdf_Action_ResetForm - set fields to their default values.

• Zend_Pdf_Action_ImportData - import field values from a file.

• Zend_Pdf_Action_JavaScript - execute a JavaScript script.

• Zend_Pdf_Action_SetOCGState - set the state of one or more optional content groups.

• Zend_Pdf_Action_Rendition - control the playing of multimedia content (begin, stop,


pause, or resume a playing rendition).

• Zend_Pdf_Action_Trans - update the display of a document, using a transition dictionary.

• Zend_Pdf_Action_GoTo3DView - set the current view of a 3D annotation.

Only Zend_Pdf_Action_GoTo and Zend_Pdf_Action_URI actions can be created by user


now.

GoTo action object can be created using


Zend_Pdf_Action_GoTo::create($destination) method, where $destination is a
Zend_Pdf_Destination object or a string which can be used to identify named destination.

Zend_Pdf_Action_URI::create($uri[, $isMap]) method has to be used to create a


URI action (see API documentation for the details). Optional $isMap parameter is set to FALSE
by default.

It also supports the following methods:

6.2.2. Actions chaining

Actions objects can be chained using Zend_Pdf_Action::$next public property.

1119
Zend_Pdf

It's an array of Zend_Pdf_Action objects, which also may have their sub-actions.

Zend_Pdf_Action class supports RecursiveIterator interface, so child actions may be iterated


recursively:

$pdf = new Zend_Pdf();


$page1 = $pdf->newPage(Zend_Pdf_Page::SIZE_A4);
$page2 = $pdf->newPage(Zend_Pdf_Page::SIZE_A4);
// Page created, but not included into pages list
$page3 = $pdf->newPage(Zend_Pdf_Page::SIZE_A4);

$pdf->pages[] = $page1;
$pdf->pages[] = $page2;

$action1 = Zend_Pdf_Action_GoTo::create(
Zend_Pdf_Destination_Fit::create($page2));
$action2 = Zend_Pdf_Action_GoTo::create(
Zend_Pdf_Destination_Fit::create($page3));
$action3 = Zend_Pdf_Action_GoTo::create(
Zend_Pdf_Destination_Named::create('Chapter1'));
$action4 = Zend_Pdf_Action_GoTo::create(
Zend_Pdf_Destination_Named::create('Chapter5'));

$action2->next[] = $action3;
$action2->next[] = $action4;

$action1->next[] = $action2;

$actionsCount = 1; // Note! Iteration doesn't include top level action and


// walks through children only
$iterator = new RecursiveIteratorIterator(
$action1,
RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $chainedAction) {
$actionsCount++;
}

// Prints 'Actions in a tree: 4'


printf("Actions in a tree: %d\n", $actionsCount++);

6.2.3. Document Open Action


Special open action may be specify a destination to be displayed or an action to be performed
when the document is opened.

Zend_Pdf_Target Zend_Pdf::getOpenAction() method returns current document open


action (or NULL if open action is not set).

setOpenAction(Zend_Pdf_Target $openAction = null) method sets document open


action or clean it if $openAction is NULL.

6.3. Document Outline (bookmarks)


A PDF document may optionally display a document outline on the screen, allowing the user to
navigate interactively from one part of the document to another. The outline consists of a tree-
structured hierarchy of outline items (sometimes called bookmarks), which serve as a visual table
of contents to display the document's structure to the user. The user can interactively open and

1120
Zend_Pdf

close individual items by clicking them with the mouse. When an item is open, its immediate
children in the hierarchy become visible on the screen; each child may in turn be open or closed,
selectively revealing or hiding further parts of the hierarchy. When an item is closed, all of its
descendants in the hierarchy are hidden. Clicking the text of any visible item activates the item,
causing the viewer application to jump to a destination or trigger an action associated with the
item.

Zend_Pdf class provides public property $outlines which is an array of Zend_Pdf_Outline


objects.

$pdf = Zend_Pdf::load($path);

// Remove outline item


unset($pdf->outlines[0]->childOutlines[1]);

// Set Outline to be displayed in bold


$pdf->outlines[0]->childOutlines[3]->setIsBold(true);

// Add outline entry


$pdf->outlines[0]->childOutlines[5]->childOutlines[] =
Zend_Pdf_Outline::create('Chapter 2', 'chapter_2');

$pdf->save($path, true);

Outline attributes may be retrieved or set using the following methods:

• string getTitle() - get outline item title.

• setTitle(string $title) - set outline item title.

• boolean isOpen() - TRUE if outline is open by default.

• setIsOpen(boolean $isOpen) - set isOpen state.

• boolean isItalic() - TRUE if outline item is displayed in italic.

• setIsItalic(boolean $isItalic) - set isItalic state.

• boolean isBold() - TRUE if outline item is displayed in bold.

• setIsBold(boolean $isBold) - set isBold state.

• Zend_Pdf_Color_Rgb getColor() - get outline text color (NULL means black).

• setColor(Zend_Pdf_Color_Rgb $color) - set outline text color (NULL means black).

• Zend_Pdf_Target getTarget() - get outline target (action or explicit or named destination


object).

• setTarget(Zend_Pdf_Target|string $target) - set outline target (action or


destination). String may be used to identify named destination. NULL means 'no target'.

• array getOptions() - get outline attributes as an array.

• setOptions(array $options) - set outline options. The following options are recognized:
'title', 'open', 'color', 'italic', 'bold', and 'target'.

1121
Zend_Pdf

New outline may be created in two ways:

• Zend_Pdf_Outline::create(string $title[, Zend_Pdf_Target|string


$target])

• Zend_Pdf_Outline::create(array $options)

Each outline object may have child outline items listed in Zend_Pdf_Outline::
$childOutlines public property. It's an array of Zend_Pdf_Outline objects, so outlines are
organized in a tree.

Zend_Pdf_Outline class implements RecursiveArray interface, so child outlines may be


recursively iterated using RecursiveIteratorIterator:

$pdf = Zend_Pdf::load($path);

foreach ($pdf->outlines as $documentRootOutlineEntry) {


$iterator = new RecursiveIteratorIterator(
$documentRootOutlineEntry,
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $childOutlineItem) {
$OutlineItemTarget = $childOutlineItem->getTarget();
if ($OutlineItemTarget instanceof Zend_Pdf_Destination) {
if ($pdf->resolveDestination($OutlineItemTarget) === null) {
// Mark Outline item with unresolvable destination
// using RED color
$childOutlineItem->setColor(new Zend_Pdf_Color_Rgb(1, 0, 0));
}
} else if ($OutlineItemTarget instanceof Zend_Pdf_Action_GoTo) {
$OutlineItemTarget->setDestination();
if ($pdf->resolveDestination($OutlineItemTarget) === null) {
// Mark Outline item with unresolvable destination
// using RED color
$childOutlineItem->setColor(new Zend_Pdf_Color_Rgb(1, 0, 0));
}
}
}
}

$pdf->save($path, true);

All outline items with unresolved destinations (or destinations of GoTo actions)
are updated while document saving by setting their targets to NULL. So document
will not be corrupted by removing pages referenced by outlines.

6.4. Annotations
An annotation associates an object such as a note, sound, or movie with a location on a page of a
PDF document, or provides a way to interact with the user by means of the mouse and keyboard.

All annotations are represented by Zend_Pdf_Annotation abstract class.

Annotation may be attached to a page using


Zend_Pdf_Page::attachAnnotation(Zend_Pdf_Annotation $annotation) method.

1122
Zend_Pdf

Three types of annotations may be created by user now:

• Zend_Pdf_Annotation_Link::create($x1, $y1, $x2, $y2, $target) where


$target is an action object or a destination or string (which may be used in place of named
destination object).

• Zend_Pdf_Annotation_Text::create($x1, $y1, $x2, $y2, $text)

• Zend_Pdf_Annotation_FileAttachment::create($x1, $y1, $x2, $y2,


$fileSpecification)

A link annotation represents either a hypertext link to a destination elsewhere in the document
or an action to be performed.

A text annotation represents a "sticky note" attached to a point in the PDF document.

A file attachment annotation contains a reference to a file.

The following methods are shared between all annotation types:

• setLeft(float $left)

• float getLeft()

• setRight(float $right)

• float getRight()

• setTop(float $top)

• float getTop()

• setBottom(float $bottom)

• float getBottom()

• setText(string $text)

• string getText()

Text annotation property is a text to be displayed for the annotation or, if this type of annotation
does not display text, an alternate description of the annotation's contents in human-readable
form.

Link annotation objects also provide two additional methods:

• setDestination(Zend_Pdf_Target|string $target)

• Zend_Pdf_Target getDestination()

7. Informations du document et métadonnées


Un document PDF peut inclure des informations générales comme le titre du document, l'auteur
et les dates de création ou de modification.

1123
Zend_Pdf

Historiquement ces informations sont stockées dans une structure spéciale Info. Cette structure
est disponible en lecture/écriture sous la forme d'un tableau associatif en utilisant la propriété
publique properties des objets Zend_Pdf :

$pdf = Zend_Pdf::load($pdfPath);

echo $pdf->properties['Title'] . "\n";


echo $pdf->properties['Author'] . "\n";

$pdf->properties['Title'] = 'Nouveau Titre.';


$pdf->save($pdfPath);

Les clés suivantes sont définies par la norme PDF v1.4 (Acrobat 5) :

• Title - string, optionnel, le titre du document.

• Author - string, optionnel, le nom de la personne qui a créé le document.

• Subject - string, optionnel, le sujet du document.

• Keywords - string, optionnel, les mots clés associés au document.

• Creator - string, optionnel, si le document a été converti en PDF à partir d'un autre format, le
nom de l'application (par exemple, Adobe FrameMaker®) qui a créé le document original à
partir duquel il a été converti.

• Producer - string, optionnel, si le document a été converti en PDF à partir d'un autre format,
le nom de l'application (par exemple, Acrobat Distiller) qui l'a converti en PDF.

• CreationDate - string, optionnel, la date et l'heure auxquelles le document a été créé sous la
forme suivante : "D:YYYYMMDDHHmmSSOHH'mm'", où :

• YYYY est la date.

• MM est le mois.

• DD est le jour (01–31).

• HH est l'heure (00–23).

• mm est la minute (00–59).

• SS est la seconde (00–59).

• O est la différence de l'heure locale par rapport au temps universel (UT), dénoté par un des
caractères +, de #, ou de Z (voir ci-dessous).

• HH suivi par ' est la valeur absolue du décalage par rapport à l'UT en heures (00–23).

• mm suivi par ' est la valeur absolue du décalage par rapport à l'UT en minutes (00–59).
Le caractère apostrophe (') après "HH" et "mm" est un élément de la syntaxe. Chaque
champs après l'année est optionnel. (Le préfixe "D:", bien que lui aussi optionnel, est fortement
recommandé.) Les valeurs par défaut pour "MM" et "DD" sont à "01" ; tous les autres champs
numériques ont par défaut des valeurs à zéro. Un signe plus (+) en tant que valeur pour le
champs "0" signifie que l'heure locale est après l'UT, un signe moins (-) que l'heure locale est
avant l'UT, et la lettre "Z" que l'heure locale est égale à l'UT. Si aucune information concernant

1124
Zend_Pdf

l'UT n'est spécifiée, la différence par rapport à l'UT est considérée inconnue. Que le décalage
horaire soit connu ou non, le reste de la date devrait être exprimée en heure locale.

Par exemple la date "23 décembre 1998 à 19:52 (heure locale U.S. Pacifique)" est représentée
par la chaîne "D:199812231952#08'00'".

• ModDate - string, optionnel, la date et l'heure auxquelles le document a été le plus récemment
modifié, sous la même forme que CreationDate.

• Trapped - boolean, optionnel, indique si le document à été modifié pour inclure une information
de "trapping".

• true - Le document a été entièrement "trappé" ; aucun autre "trapping" n'est nécessaire.

• false - Le document n'a pas encore été "trappé" ; tout "trapping" reste encore à réaliser.

• null - Soit il est impossible de savoir si le document a été "trappé", soit il a été partiellement
"trappé" ; certains "trapping" additionnels sont nécessaires.

Depuis la version v1.6 de la norme PDF, les métadonnées peuvent être stockées dans un
document XML spécial attaché au document PDF (XMP - eXtensible Metadata Platform).

Ce document XML peut être récupéré et attaché au document PDF avec les méthodes
Zend_Pdf::getMetadata() et Zend_Pdf::setMetadata($metadata) :

$pdf = Zend_Pdf::load($pdfPath);
$metadata = $pdf->getMetadata();
$metadataDOM = new DOMDocument();
$metadataDOM->loadXML($metadata);

$xpath = new DOMXPath($metadataDOM);


$pdfPreffixNamespaceURI = $xpath->query('/rdf:RDF/rdf:Description')
->item(0)
->lookupNamespaceURI('pdf');
$xpath->registerNamespace('pdf', $pdfPreffixNamespaceURI);

$titleNode = $xpath->query('/rdf:RDF/rdf:Description/pdf:Title')
->item(0);
$title = $titleNode->nodeValue;
...

$titleNode->nodeValue = 'Nouveau titre';


$pdf->setMetadata($metadataDOM->saveXML());
$pdf->save($pdfPath);

Les propriétés communes du document sont dupliquées dans la structure Info et dans le
document de métadonnées (s'il est présent). Il est de la responsabilité de l'utilisateur de
l'application de les maintenir synchronisées.

8. Exemple d'utilisation du module Zend_Pdf


Cette section propose un exemple d'utilisation du module Zend_Pdf.

Le code source de l'exemple est disponible dans le fichier demos/Zend/Pdf/demo.php.

Il y a aussi un fichier test.pdf, qui peut être utilisé pour réaliser des tests.

1125
$page2->drawPolygon($x, $y,
Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE,
Zend_Pdf_Page::FILL_METHOD_EVEN_ODD);

// Dessine une ligne Zend_Pdf


$page2->setLineWidth(0.5)
->drawLine(0, 25, 340, 25);
Exemple 607. Exemple d'utilisation du module Zend_Pdf
$page2->restoreGS();

// Mouvement du système de coordonnées, mise en biais et mise à l'échelle


$page2->saveGS();
$page2->translate(60, 150) // Décalage du système de coordonnées
->skew(0, 0, 0, -M_PI/9) // Mise en biais du système de coordonnées
->scale(0.9, 0.9); // Mise à l'échelle du système de coordonnées

// Dessine un rectangle
$page2->setFillColor(new Zend_Pdf_Color_GrayScale(0.8))
->setLineColor(new Zend_Pdf_Color_GrayScale(0.2))
->setLineDashingPattern(array(3, 2, 3, 4), 1.6)
->drawRectangle(0, 50, 340, 0);

// Dessine un cercle
$page2->setLineDashingPattern(Zend_Pdf_Page::LINE_DASHING_SOLID)
->setFillColor(new Zend_Pdf_Color_Rgb(1, 0, 0))
->drawCircle(25, 25, 25);

// Dessine des secteurs


$page2->drawCircle(140, 25, 25, 2*M_PI/3, -M_PI/6)
->setFillColor(new Zend_Pdf_Color_Cmyk(1, 0, 0, 0))
->drawCircle(140, 25, 25, M_PI/6, 2*M_PI/3)
->setFillColor(new Zend_Pdf_Color_Rgb(1, 1, 0))
->drawCircle(140, 25, 25, -M_PI/6, M_PI/6);

// Dessine des ellipses


$page2->setFillColor(new Zend_Pdf_Color_Rgb(1, 0, 0))
->drawEllipse(190, 50, 340, 0)
->setFillColor(new Zend_Pdf_Color_Cmyk(1, 0, 0, 0))
->drawEllipse(190, 50, 340, 0, M_PI/6, 2*M_PI/3)
->setFillColor(new Zend_Pdf_Color_Rgb(1, 1, 0))
->drawEllipse(190, 50, 340, 0, -M_PI/6, M_PI/6);

// Dessine et remplit un polygone


$page2->setFillColor(new Zend_Pdf_Color_Rgb(1, 0, 1));
$x = array();
$y = array();
for ($count = 0; $count < 8; $count++) {
$x[] = 80 + 25*cos(3*M_PI_4*$count);
$y[] = 25 + 25*sin(3*M_PI_4*$count);
}
$page2->drawPolygon($x, $y,
Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE,
Zend_Pdf_Page::FILL_METHOD_EVEN_ODD);

// Dessine une ligne


$page2->setLineWidth(0.5)
->drawLine(0, 25, 340, 25);

$page2->restoreGS();

//--------------------------------------------------------------------------

if (isset($argv[2])) {
$pdf->save($argv[2]);
} else {
$pdf->save($argv[1], true ); /* met à jour */
}

1126
Zend_ProgressBar
1. Zend_ProgressBar
1.1. Introduction
Zend_ProgressBar est un composant pour créer et mettre à jour les barres de progression
dans différents environnements. Il consiste en un backend unique, qui affiche la progression au
travers de l'un des multiples adaptateurs. A chaque mise à jour, il prend un chemin absolu et
un message d'état, et appelle ensuite l'adaptateur avec certaines valeurs précalculées comme
le pourcentage et le temps restant estimé.

1.2. Utilisation basique de Zend_Progressbar


Zend_ProgressBar est assez simple d'utilisation. Vous créez simplement une nouvelle
instance de Zend_Progressbar, en définissant des valeurs minimum et maximum, et en
choisissant un adaptateur pour afficher les données. Si vous voulez travailler avec un fichier,
vous pouvez faire comme ceci :

$progressBar = new Zend_ProgressBar(0, $fileSize, $adapter);

while (!feof($fp)) {
// Faire quelque chose

$progressBar->update($currentByteCount);
}

$progressBar->finish();

Dans un premier temps, une instance de Zend_ProgressBar, avec une valeur minimum de
0, une valeur maximum correspondant à la taille totale du fichier et un adaptateur spécifique.
Ensuite on travaille avec le fichier et à chaque boucle la barre de progression est mise à jour
avec le nombre d'octets courant. A la fin de la boucle, le statut de la barre de progression est
réglé à terminé.

Zend_ProgressBar possède aussi une méthode refresh() qui recalcule le temps restant
estimé et met à jour l'adaptateur. Ceci est pratique quand il n'y a aucune donnée à mettre à jour
mais que vous souhaitez que la barre de progression soit mise à jour.

1.3. Adaptateurs standard


Zend_ProgressBar est fourni avec les deux adaptateurs suivants :

• Section 1.3.1, « Zend_ProgressBar_Adapter_Console »

• Section 1.3.2, « Zend_ProgressBar_Adapter_JsPush »

• Section 1.3.3, « Zend_ProgressBar_Adapter_JsPull »

1.3.1. Zend_ProgressBar_Adapter_Console
Zend_ProgressBar_Adapter_Console est un adaptateur de type texte pour les terminaux.
Il peut automatiquement détecter la largeur du terminal mais supporte aussi des largeurs

1127
Zend_ProgressBar

personnalisées. Vous pouvez définir quels éléments seront affichés avec la barre de progression
et personnaliser leur ordre. Vous pouvez aussi définir le style de la barre de progression elle-
même.

Reconnaissance automatique de la largeur de la console

shell_exec est nécessaire pour que ceci fonctionne sur les systèmes de type
*nix. Sur Windows, il y a toujours un terminal fixe de 80 caractères de large, donc
la reconnaissance automatique n'est pas nécessaire.

Vous pouvez paramétrer les options de l'adaptateur soit via les méthodes set* soit en
fournissant un tableau ("array") ou une instance Zend_Config en tant que premier paramètre
du constructeur. Les options disponibles sont :

• outputStream : un flux de sortie différent, si vous ne souhaitez pas utiliser STDOUT. Peut
être n'importe quel autre flux come php://stderr ou un chemin vers un fichier.

• width : soit un entier ou la constante AUTO de Zend_Console_ProgressBar.

• elements : soit NULL par défaut ou un tableau avec au moins l'une des constantes de
Zend_Console_ProgressBar suivantes comme valeur :

• ELEMENT_PERCENT : la valeur courante en pourcentage.

• ELEMENT_BAR : la barre qui va représenter le pourcentage.

• ELEMENT_ETA : le calcul automatique du temps restant estimé (NDT. : "Estimated Time for
Accomplishment"). Cet élément est affiché pour la première fois qu'après cinq secondes,
car durant ce temps, il n'est pas possible de calculer des résultats précis.

• ELEMENT_TEXT : un message de statut optionnel concernant le processus courant.

• textWidth : largeur en caractères de l'élément ELEMENT_TEXT. Par défaut vaut 20.

• charset : encodage de l'élément ELEMENT_TEXT. Par défaut vaut "utf-8".

• barLeftChar : un caractère qui est utilisé du côté gauche de l'indicateur de la barre de


progression.

• barRightChar : un caractère qui est utilisé du côté droit de l'indicateur de la barre de


progression.

• barIndicatorChar : un caractère qui est utilisé pour l'indicateur de la barre de progression.


Celui-ci peut être vide.

1.3.2. Zend_ProgressBar_Adapter_JsPush
Zend_ProgressBar_Adapter_JsPush est un adaptateur qui vous permet de mettre à jour
une barre de progression dans un navigateur au travers de Javascript. Ceci veut dire qu'une
seconde connexion n'est pas nécessaire pour recueillir le statut du processus courant, mais que
le processus lui-même envoie son statut directement au navigateur.

Vous pouvez paramétrer les options de l'adaptateur soit avec les méthodes set* soit en
fournissant un tableau ("array") ou une instance de Zend_Config contenant les options en tant
que premier paramètre du constructeur. Les options disponibles sont :

1128
Zend_ProgressBar

• updateMethodName : la méthode Javascript qui sera appelée à chaque mise à jour. La valeur
par défaut est Zend_ProgressBar_Update.

• finishMethodName : la méthode Javascript qui sera appelée lorsque le statut terminé sera
atteint. La valeur par défaut est NULL, qui veut dire que rien n'est fait.

L'utilisation de cet adaptateur est assez simple. Premièrement vous créez une barre de
progression pour le navigateur, soit avec Javascript ou auparavant en pur HTML. Ensuite vous
définissez une méthode de mise à jour et optionnellement une méthode de finalisation en
Javascript, les deux acceptant un objet JSON en tant qu'unique argument. Ensuite vous appelez
une page Web avec un processus chronophage dans une balise iframe ou object masqué.
Pendant que le processus tourne, l'adaptateur appelle la méthode de mise à jour à chaque mise
à jour avec un objet JSON, contenant le paramètres suivants :

• current : la valeur courante

• max : la valeur maximum

• percent : le pourcentage calculé

• timeTaken : le temps depuis quand le processus courant est en marche

• timeRemaining : le temps estimé pour que le processus se termine

• text : le message de statut optionnel, si fourni

1129
Zend_ProgressBar

Exemple 608. Exemple basique du fonctionnement côté-client

Cet exemple illustre un paramétrage basique du HTML, CSS et JavaScript pour l'adaptateur
JsPush :

<div id="zend-progressbar-container">
<div id="zend-progressbar-done"></div>
</div>

<iframe src="long-running-process.php" id="long-running-process"></iframe>

#long-running-process {
position: absolute;
left: -100px;
top: -100px;

width: 1px;
height: 1px;
}

#zend-progressbar-container {
width: 100px;
height: 30px;

border: 1px solid #000000;


background-color: #ffffff;
}

#zend-progressbar-done {
width: 0;
height: 30px;

background-color: #000000;
}

function Zend_ProgressBar_Update(data)
{
document.getElementById('zend-progressbar-done').style.width = data.percent + '%';
}

Ceci créera un simple conteneur avec une bordure noire et un bloc qui indique le niveau
du processus courant. Vous ne devez pas masquer l'iframe ou l'object par display:
none;, car dans ce cas les navigateurs comme Safari 2 ne chargeront pas le contenu réel.

Plutôt que de créer votre barre de progression personnalisée, vous pouvez utiliser une de
celles disponibles dans les librairies JavaScript comme Dojo, jQuery etc. Par exemple, il
existe :

• Dojo : http://dojotoolkit.org/book/dojo-book-0-9/part-2-dijit/user-assistance-and-feedback/
progress-bar

• jQuery : http://t.wits.sg/2008/06/20/jquery-progress-bar-11/

• MooTools : http://davidwalsh.name/dw-content/progress-bar.php

• Prototype : http://livepipe.net/control/progressbar

1130
Zend_ProgressBar

Intervalle de mise à jour


Vous devez faire attention à ne pas envoyer trop de mises à jour, puisque chaque
mise à jour a une taille minimum de 1ko. Ceci est requis par le navigateur
Safari pour rendre et exécuter l'appel de fonction. Internet Explorer possède une
limitation similaire mais à 256 octets.

1.3.3. Zend_ProgressBar_Adapter_JsPull
Zend_ProgressBar_Adapter_JsPull est l'opposé de jsPush, car il requiert de venir
récupérer les nouvelles mises à jour, plutôt que d'envoyer les mises à jour vers le
navigateur. Généralement, vous devriez utiliser l'adaptateur avec l'option de persistance de
Zend_ProgressBar. Lors de l'appel, l'adaptateur envoie une chaîne JSON vers le navigateur,
qui est comparable à la chaîne JSON envoyée par l'adaptateur jsPush. La seule différence est
qu'il contient un paramètre supplémentaire "finished", qui vaut FALSE quand update() est
appelée ou TRUE quand finish() est appelée.

Vous pouvez paramétrer les options de l'adaptateur soit avec les méthodes set* soit en
fournissant un tableau ("array") ou une instance de Zend_Config contenant les options en tant
que premier paramètre du constructeur. Les options disponibles sont :

• exitAfterSend : sort de la requête courante après que les données aient été envoyées au
navigateur. Vaut TRUE par défaut.

1131
Zend_Queue
1. Introduction
Zend_Queue provides a factory function to create specific queue client objects.

A message queue is a method for distributed processing. For example, a Job Broker application
may accept multiple applications for jobs from a variety of sources.

You could create a queue "/queue/applications" that would have a sender and a receiver.
The sender would be any available source that could connect to your message service or
indirectly to an application (web) that could connect to the message service.

The sender sends a message to the queue:

<resume>
<name>John Smith</name>
<location>
<city>San Francisco</city>
<state>California</state>
<zip>00001</zip>
</location>
<skills>
<programming>PHP</programming>
<programming>Perl</programming>
</skills>
</resume>

The recipient or consumer of the queue would pick up the message and process the resume.

There are many messaging patterns that can be applied to queues to abstract the flow of
control from the code and provide metrics, transformations, and monitoring of messages queues.
A good book on messaging patterns is Enterprise Integration Patterns: Designing, Building,
and Deploying Messaging Solutions (Addison-Wesley Signature Series) (ISBN-10 0321127420;
ISBN-13 978-0321127426).

2. Example usage
The below example of Zend_Queue shows a variety of features, including queue creation, queue
retrieval, message retrieval, message deletion, and sending messages.

// For configuration options


// @see Zend_Queue_Adapater::__construct()
$options = array(
'name' => 'queue1',
);

// Create an array queue


$queue = new Zend_Queue('Array', $options);

// Get list of queues


foreach ($queue->getQueues() as $name) {
echo $name, "\n";
}

1132
Zend_Queue

// Create a new queue


$queue2 = $queue->createQueue('queue2');

// Get number of messages in a queue (supports Countable interface from SPL)


echo count($queue);

// Get up to 5 messages from a queue


$messages = $queue->receive(5);

foreach ($messages as $i => $message) {


echo $message->body, "\n";

// We have processed the message; now we remove it from the queue.


$queue->deleteMessage($message);
}

// Send a message to the currently active queue


$queue->send('My Test Message');

// Delete a queue we created and all of it's messages


$queue->deleteQueue('queue2');

3. Framework
The Zend_Queue is a proxy that hides the details of the queue services. The
queue services are represented by Zend_Queue_Adapter_<service>. For example,
Zend_Queue_Adapter_Db is a queue that will use database tables to store and retrieve
messages.

Below is an example for using database tables for a queuing system:

$options = array(
'name' => 'queue1',
'driverOptions' => array(
'host' => '127.0.0.1',
'port' => '3306',
'username' => 'queue',
'password' => 'queue',
'dbname' => 'queue',
'type' => 'pdo_mysql'
)
);

// Create a database queue.


// Zend_Queue will prepend Zend_Queue_Adapter_ to 'Db' for the class name.
$queue = new Zend_Queue('Db', $options);

The Zend_Queue constructor will create a Zend_Queue_Adapter_Db and initialize the adapter
with the configuration settings.

The accepted configuration settings for each adapter are provided in the adapter notes.

Zend_Queue returns messages using the class Zend_Queue_Message_Iterator, which is


an implementation of SPL Iterator and Countable. Zend_Queue_Message_Iterator
contains an array of Zend_Queue_Message objects.

$messages = $queue->receive(5);

1133
Zend_Queue

foreach ($messages as $i => $message) {


echo "$i) Message => ", $message->body, "\n";
}

Any exceptions thrown are of class Zend_Queue_Exception.

3.1. Introduction
Zend_Queue is a proxy class that represents an adapter.

The send(), count($queue), and receive() methods are employed by each adapter to
interact with queues.

The createQueue(), deleteQueue() methods are used to manage queues.

3.2. Commonality among adapters


The queue services supported by Zend_Queue do not all support the same functions. For
example, Zend_Queue_Adapter_Array, Zend_Queue_Adapter_Db, support all functions,
while Zend_Queue_Adapter_Activemq does not support queue listing, queue deletion, or
counting of messages.

You can determine what functions are supported by using Zend_Queue::isSupported() or


Zend_Queue::getCapabilities().

• createQueue() - create a queue

• deleteQueue() - delete a queue

• send() - send a message

send() is not available in all adapters; the Zend_Queue_Adapter_Null does not support
send().

• receive() - receive messages

receive() is not available in all adapters; the Zend_Queue_Adapter_Null does not


support receive().

• deleteMessage() - delete a message

• count() - count the number of messages in a queue

• isExists() - checks the existence of a queue

receive() methods are employed by each adapter to interact with queues.

The createQueue() and deleteQueue() methods are used to manage queues.

4. Adapters
Zend_Queue supports all queues implementing the interface
Zend_Queue_Adapter_AdapterInterface. The following Message Queue services are
supported:

• Apache ActiveMQ.

• A database driven queue via Zend_Db.

1134
Zend_Queue

• A MemcacheQ queue driven via Memcache.

• Zend Platform's Job Queue.

• A local array. Useful for unit testing.

Limitations
Message transaction handling is not supported.

4.1. Specific Adapters - Configuration settings


If a default setting is indicated then the parameter is optional. If a default setting is not specified
then the parameter is required.

4.1.1. Apache ActiveMQ - Zend_Queue_Adapter_Activemq


Options listed here are known requirements. Not all messaging servers require username or
password.

• $options['name'] = '/temp/queue1';

This is the name of the queue that you wish to start using. (Required)

• $options['driverOptions']['host'] = 'host.domain.tld';

$options['driverOptions']['host'] = '127.0.0.1';

You may set host to an IP address or a hostname.

Default setting for host is '127.0.0.1'.

• $options['driverOptions']['port'] = 61613;

Default setting for port is 61613.

• $options['driverOptions']['username'] = 'username';

Optional for some messaging servers. Read the manual for your messaging server.

• $options['driverOptions']['password'] = 'password';

Optional for some messaging servers. Read the manual for your messaging server.

• $options['driverOptions']['timeout_sec'] = 2;

$options['driverOptions']['timeout_usec'] = 0;

This is the amount of time that Zend_Queue_Adapter_Activemq will wait for read activity
on a socket before returning no messages.

4.1.2. Db - Zend_Queue_Adapter_Db
Driver options are checked for a few required options such as type, host, username, password,
and dbname. You may pass along additional parameters for Zend_DB::factory() as
parameters in $options['driverOptions']. An example of an additional option not listed
here, but could be passed would be port.

1135
Zend_Queue

$options = array(
'driverOptions' => array(
'host' => 'db1.domain.tld',
'username' => 'my_username',
'password' => 'my_password',
'dbname' => 'messaging',
'type' => 'pdo_mysql',
'port' => 3306, // optional parameter.
),
'options' => array(
// use Zend_Db_Select for update, not all databases can support this
// feature.
Zend_Db_Select::FOR_UPDATE => true
)
);

// Create a database queue.


$queue = new Zend_Queue('Db', $options);

• $options['name'] = 'queue1';

This is the name of the queue that you wish to start using. (Required)

• $options['driverOptions']['type'] = 'Pdo';

type is the adapter you wish to have Zend_Db::factory() use. This is the first parameter
for the Zend_Db::factory() class method call.

• $options['driverOptions']['host'] = 'host.domain.tld';

$options['driverOptions']['host'] = '127.0.0.1';

You may set host to an IP address or a hostname.

Default setting for host is '127.0.0.1'.

• $options['driverOptions']['username'] = 'username';

• $options['driverOptions']['password'] = 'password';

• $options['driverOptions']['dbname'] = 'dbname';

The database name that you have created the required tables for. See the notes section below.

4.1.3. MemcacheQ - Zend_Queue_Adapter_Memcacheq


• $options['name'] = 'queue1';

This is the name of the queue that you wish to start using. (Required)

• $options['driverOptions']['host'] = 'host.domain.tld';

$options['driverOptions']['host'] = '127.0.0.1;'

You may set host to an IP address or a hostname.

Default setting for host is '127.0.0.1'.

• $options['driverOptions']['port'] = 22201;

1136
Zend_Queue

The default setting for port is 22201.

4.1.4. Zend Platform Job Queue -


Zend_Queue_Adapter_PlatformJobQueue
• $options['daemonOptions']['host'] = '127.0.0.1:10003';

The hostname and port corresponding to the Zend Platform Job Queue daemon you will use.
(Required)

• $options['daemonOptions']['password'] = '1234';

The password required for accessing the Zend Platform Job Queue daemon. (Required)

4.1.5. Array - Zend_Queue_Adapter_Array


• $options['name'] = 'queue1';

This is the name of the queue that you wish to start using. (Required)

4.2. Notes for Specific Adapters


The following adapters have notes:

4.2.1. Apache ActiveMQ


Visibility duration for Zend_Queue_Adapter_Activemq is not available.

While Apache's ActiveMQ will support multiple subscriptions, the Zend_Queue does not. You
must create a new Zend_Queue object for each individual subscription.

ActiveMQ queue/topic names must begin with one of:

• /queue/

• /topic/

• /temp-queue/

• /temp-topic/

For example: /queue/testing

The following functions are not supported:

• create() - create queue. Calling this function will throw an exception.

• delete() - delete queue. Calling this function will throw an exception.

• getQueues() - list queues. Calling this function will throw an exception.

4.2.2. Zend_Db
The database CREATE TABLE ( ... ) SQL statement can be found in Zend/Queue/Adapter/
Db/queue.sql.

1137
Zend_Queue

4.2.3. MemcacheQ
Memcache can be downloaded from http://www.danga.com/memcached/.

MemcacheQ can be downloaded from http://memcachedb.org/memcacheq/.

• deleteMessage() - Messages are deleted upon reception from the queue. Calling this
function would have no effect. Calling this function will throw an error.

• count() or count($adapter) - MemcacheQ does not support a method for counting the
number of items in a queue. Calling this function will throw an error.

4.2.4. Zend Platform Job Queue


Job Queue is a feature of Zend Platform's Enterprise Solution offering. It is not a traditional
message queue, and instead allows you to queue a script to execute, along with the parameters
you wish to pass to it. You can find out more about Job Queue on the zend.com website.

The following is a list of methods where this adapter's behavior diverges from the standard
offerings:

• create() - Zend Platform does not have the concept of discrete queues; instead, it allows
administrators to provide scripts for processing jobs. Since adding new scripts is restricted to
the administration interface, this method simply throws an exception indicating the action is
forbidden.

• isExists() - Just like create(), since Job Queue does not have a notion of named queues,
this method throws an exception when invoked.

• delete() - similar to create(), deletion of JQ scripts is not possible except via the admin
interface; this method raises an exception.

• getQueues() - Zend Platform does not allow introspection into the attached job handling
scripts via the API. This method throws an exception.

• count() - returns the total number of jobs currently active in the Job Queue.

• send() - this method is perhaps the one method that diverges most from other adapters. The
$message argument may be one of three possible types, and will operate differently based
on the value passed:

• string - the name of a script registered with Job Queue to invoke. If passed in this way, no
arguments are provided to the script.

• array - an array of values with which to configure a ZendApi_Job object. These may include
the following:

• script - the name of the Job Queue script to invoke. (Required)

• priority - the job priority to use when registering with the queue.

• name - a short string describing the job.

• predecessor - the ID of a job on which this one depends, and which must be executed
before this one may begin.

• preserved - whether or not to retain the job within the Job Queue history. By default,
off; pass a TRUE value to retain it.

1138
Zend_Queue

• user_variables - an associative array of all variables you wish to have in scope during
job execution (similar to named arguments).

• interval - how often, in seconds, the job should run. By default, this is set to 0, indicating
it should run once, and once only.

• end_time - an expiry time, past which the job should not run. If the job was set to run
only once, and end_time has passed, then the job will not be executed. If the job was
set to run on an interval, it will not execute again once end_time has passed.

• schedule_time - a UNIX timestamp indicating when to run the job; by default, 0,


indicating the job should run as soon as possible.

• application_id - the application identifier of the job. By default, this is NULL, indicating
that one will be automatically assigned by the queue, if the queue was assigned an
application ID.

As noted, only the script argument is required; all others are simply available to allow
passing more fine-grained detail on how and when to run the job.

• ZendApi_Job - finally, you may simply pass a ZendApi_Job instance, and it will be passed
along to Platform's Job Queue.

In all instances, send() returns a Zend_Queue_Message_PlatformJob object, which


provides access to the ZendApi_Job object used to communicate with Job Queue.

• receive() - retrieves a list of active jobs from Job Queue. Each job in the returned set will
be an instance of Zend_Queue_Message_PlatformJob.

• deleteMessage() - since this adapter only works with Job Queue, this method expects the
provided $message to be a Zend_Queue_Message_PlatformJob instance, and will throw
an exception otherwise.

4.2.5. Array (local)


The Array queue is a PHP array() in local memory. The Zend_Queue_Adapter_Array is
good for unit testing.

5. Customizing Zend_Queue
5.1. Creating your own adapter
Zend_Queue will accept any adapter that implements
Zend_Queue_Adapter_AdapterAbstract. You can create your own adapter by extending
one of the existing adapters, or the abstract class Zend_Queue_Adapter_AdapterAbstract.
I suggest reviewing Zend_Queue_Adapter_Array as this adapter is the easiest to
conceptualize.

class Custom_DbForUpdate extends Zend_Queue_Adapter_Db


{
/**
* @see code in tests/Zend/Queue/Custom/DbForUpdate.php
*
* Custom_DbForUpdate uses the SELECT ... FOR UPDATE to find it's rows.

1139
Zend_Queue

* this is more likely to produce the wanted rows than the existing code.
*
* However, not all databases have SELECT ... FOR UPDATE as a feature.
*
* Note: this was later converted to be an option for Zend_Queue_Adapter_Db
*
* This code still serves as a good example.
*/
}

$options = array(
'name' => 'queue1',
'driverOptions' => array(
'host' => '127.0.0.1',
'port' => '3306',
'username' => 'queue',
'password' => 'queue',
'dbname' => 'queue',
'type' => 'pdo_mysql'
)
);

$adapter = new Custom_DbForUpdate($options);


$queue = new Zend_Queue($adapter, $options);

You can also change the adapter on the fly as well.

$adapter = new MyCustom_Adapter($options);


$queue = new Zend_Queue($options);
$queue->setAdapter($adapter);
echo "Adapter: ", get_class($queue->getAdapter()), "\n";

or

$options = array(
'name' => 'queue1',
'namespace' => 'Custom',
'driverOptions' => array(
'host' => '127.0.0.1',
'port' => '3306',
'username' => 'queue',
'password' => 'queue',
'dbname' => 'queue',
'type' => 'pdo_mysql'
)
);
$queue = new Zend_Queue('DbForUpdate', $config); // loads Custom_DbForUpdate

5.2. Creating your own message class


Zend_Queue will also accept your own message class. Our variables start with an underscore.
For example:

class Zend_Queue_Message
{
protected $_data = array();
}

1140
Zend_Queue

You can extend the existing messaging class. See the example code in tests/Zend/Queue/
Custom/Message.php.

5.3. Creating your own message iterator class


Zend_Queue will also accept your own message iterator class. The message iterator
class is used to return messages from Zend_Queue_Adapter_Abstract::recieve().
Zend_Queue_Abstract::receive() should always return a container class like
Zend_Queue_Message_Iterator, even if there is only one message.

See the example filename in tests/Zend/Queue/Custom/Messages.php.

5.4. Creating your own queue class


Zend_Queue can also be overloaded easily.

See the example filename in tests/Zend/Queue/Custom/Queue.php.

6. Stomp
Zend_Queue_Stomp provides a basic client to communicate with Stomp compatible servers.
Some servers, such as Apache ActiveMQ and RabbitMQ, will allow you to communicate by other
methods, such as HTTP, and XMPP.

The Stomp protocol provides StompConnect which supports any Java Message Service (JMS)
provider. Stomp is supported by Apache ActiveMQ, RabbitMQ, stompserver, and Gozirra.

6.1. Stomp - Supporting classes


• Zend_Queue_Stomp_Frame. This class provides the basic functions for manipulating a
Stomp Frame.

• Zend_Queue_Stomp_Client. This class provides the basic functions to send() and


receive() Zend_Queue_Stomp_Frames to and from a Stomp compatible server.

1141
Zend_Reflection
1. Introduction
Zend_Reflection est un ensemble de fonctionnalités écrites par dessus l'API Reflection de
PHP, et propose un ensemble de nouvelles fonctionnalités :

• Possibilité de récupérer les types de retour des valeurs.

• Possibilité de récupérer les types des paramètres de fonctions.

• Possibilité de récupérer les types des attributs de classes.

• Les blocs de commentaires PHPDoc possèdent aussi une classe de réflexion. Ceci permet de
récupérer un bloc précis de documentation, notamment son nom, sa valeur et sa description,
longue ou courte.

• Les fichiers aussi possèdent leur propre classe de réflexion. Ceci permet l'introspection de
fichiers PHP afin de déterminer les classes et fonctions écrites dans un fichier.

• La possibilité de remplacer n'importe quelle classe de réflexion par la votre propre.

En général, Zend_Reflection fonctionne de la même manière que l'API Reflection de PHP,


elle propose par contre de nouvelles fonctionnalités.

2. Zend_Reflection Exemples
Exemple 609. Effectuer la réflexion sur un fichier

$r = new Zend_Reflection_File($filename);
printf(
"===> The %s file\n".
" has %d lines\n",
$r->getFileName(),
$r->getEndLine()
);

$classes = $r->getClasses();
echo " It has " . count($classes) . ":\n";
foreach ($classes as $class) {
echo " " . $class->getName() . "\n";
}

$functions = $r->getFunctions();
echo " It has " . count($functions) . ":\n";
foreach ($functions as $function) {
echo " " . $function->getName() . "\n";
}

1142
Zend_Reflection

Exemple 610. Effectuer la réflexion d'une classe

$r = new Zend_Reflection_Class($class);

printf(
"The class level docblock has the short description: %s\n".
"The class level docblock has the long description:\n%s\n",
$r->getDocblock()->getShortDescription(),
$r->getDocblock()->getLongDescription(),
);

// Get the declaring file reflection


$file = $r->getDeclaringFile();

Exemple 611. Effectuer la réflexion d'une méthode

$r = new Zend_Reflection_Method($class, $name);

printf(
"The method '%s' has a return type of %s",
$r->getName(),
$r->getReturn()
);

foreach ($r->getParameters() as $key => $param) {


printf(
"Param at position '%d' is of type '%s'\n",
$key,
$param->getType()
);
}

Exemple 612. Effectuer la réflexion d'un bloc de documentation

$r = new Zend_Reflection_Method($class, $name);


$docblock = $r->getDocblock();

printf(
"The short description: %s\n".
"The long description:\n%s\n",
$r->getDocblock()->getShortDescription(),
$r->getDocblock()->getLongDescription(),
);

foreach ($docblock->getTags() as $tag) {


printf(
"Annotation tag '%s' has the description '%s'\n",
$tag->getName(),
$tag->getDescription()
);
}

3. Réference de Zend_Reflection
Les classes de Zend_Reflection reprennent l'API de la Reflection PHP - mais avec une
différence importante : la Reflection PHP ne propose pas de manière d'introspecter les tags de
documentation PHPDoc, ni les types des variables paramètres ou encore les types de retour
des fonctions.

1143
Zend_Reflection

Zend_Reflection analyse les commentaires PHPDoc pour déterminer les types des variables
passées en paramètres ou de retour. Plus spécialement, les annotations @param et @return
sont utilisées, même s'il reste possible d'analyser les autres blocs de commentaire, ainsi que
leurs descriptions respectives.

Chaque objet de réflexion dans Zend_Reflection, surcharge la méthode getDocblock()


pour retourner une instance de Zend_Reflection_Docblock. Cette classe propose alors
l'introspection des blocs de commentaires et notamment des tags PHPDoc.

Zend_Reflection_File est une nouvelle classe qui permet d'introspecter les fichiers PHP à
la recherche de classes, fonctions ou encore code global PHP contenu à l'intérieur.

Enfin, la plupart des méthodes qui retournent des objets réflexion acceptent un second paramètre
permettant de spécifier la classe qui sera instanciée pour créer de tels objets.

3.1. Zend_Reflection_Docblock
Zend_Reflection_Docblock est le coeur de la valeur ajoutée par Zend_Reflection par
rapport à la Reflection PHP. Voici les méthodes proposées :

• getContents() : retourne tout le contenu du bloc.

• getStartLine() : retourne la position de départ du bloc dans le fichier.

• getEndLine() : retourne la position de fin du bloc dans le fichier.

• getShortDescription() : récupère la description courte (en général la première ligne de


commentaire).

• getLongDescription() : récupère la description longue du bloc.

• hasTag($name) : détermine si le bloc possède un tag particulier.

• getTag($name) : Récupère un tag particulier ou FALSE si celui-ci est absent.

• getTags($filter) : Récupère tous les tags qui correspondent au filtre $filter. Le type
de retour est un tableau d'objets Zend_Reflection_Docblock_Tag.

3.2. Zend_Reflection_Docblock_Tag
Zend_Reflection_Docblock_Tag propose la réflexion pour un tag individuel. La plupart des
tags se composent d'un nom et d'un description. Dans le cas de certains tags spéciaux, la classe
propose une méthode de fabrique qui retourne la bonne instance.

Voici les méthodes de Zend_Reflection_Docblock_Tag :

• factory($tagDocblockLine) : instancie la bonne classe de reflection pour le tag


correspondant et en retourne l'objet.

• getName() : retourne le nom du tag.

• getDescription() : retourne la description du tag.

3.3. Zend_Reflection_Docblock_Tag_Param
Zend_Reflection_Docblock_Tag_Param est une version spéciale de
Zend_Reflection_Docblock_Tag. La description du tag @param consiste en un

1144
Zend_Reflection

type, un nom de variable et une description. Elle ajoute les méthodes suivantes à
Zend_Reflection_Docblock_Tag :

• getType() : Retourne le type de la variable considérée par le tag.

• getVariableName() : Retourne le nom de la variable considérée par le tag.

3.4. Zend_Reflection_Docblock_Tag_Return
Comme Zend_Reflection_Docblock_Tag_Param,
Zend_Reflection_Docblock_Tag_Return est une version spéciale de
Zend_Reflection_Docblock_Tag. Le tag @return consiste en un type de retour et une
description. Elle ajoute les méthodes suivantes à Zend_Reflection_Docblock_Tag :

• getType(): retourne le type de retour.

3.5. Zend_Reflection_File
Zend_Reflection_File propose l'introspection de fichiers PHP. Grâce à cela, vous pouvez
déterminer les classes, fonctions ou le code pur PHP contenus dans un fichier PHP donné. Voici
les méthodes proposées :

• getFileName() : retourne le nom du fichier en cours de réflexion.

• getStartLine() : retourne la ligne de démarrage du fichier (toujours "1").

• getEndLine() : retourne la dernière ligne du fichier, donc le nombre de lignes.

• getDocComment($reflectionClass = 'Zend_Reflection_Docblock') : retourne


un objet de réflection de commentaire PHPDoc du fichier en cours d'analyse.

• getClasses($reflectionClass = 'Zend_Reflection_Class') : retourne un


tableau d'objets de réflexion de classe, pour les classes contenues dans le fichier en cours
d'analyse.

• getFunctions($reflectionClass = 'Zend_Reflection_Function') : retourne un


tableau d'objets de réflexion de fonction, pour les fonctions contenues dans le fichier en cours
d'analyse.

• getClass($name = null, $reflectionClass = 'Zend_Reflection_Class') :


retourne l'objet de réflexion pour la classe contenue dans le fichier en cours d'analyse.

• getContents() : retourne tout le contenu du fichier en cours d'analyse.

3.6. Zend_Reflection_Class
Zend_Reflection_Class étend ReflectionClass, et propose son API. Elle ajoute
juste une méthode, getDeclaringFile(), qui peut être utilisée pour créer un objet
Zend_Reflection_File.

Aussi, les méthodes suivantes proposent un argument supplémentaire pour spécifier sa propre
classe de réflexion:

• getDeclaringFile($reflectionClass = 'Zend_Reflection_File')

• getDocblock($reflectionClass = 'Zend_Reflection_Docblock')

1145
Zend_Reflection

• getInterfaces($reflectionClass = 'Zend_Reflection_Class')

• getMethod($reflectionClass = 'Zend_Reflection_Method')

• getMethods($filter = -1, $reflectionClass = 'Zend_Reflection_Method')

• getParentClass($reflectionClass = 'Zend_Reflection_Class')

• getProperty($name, $reflectionClass = 'Zend_Reflection_Property')

• getProperties($filter = -1, $reflectionClass =


'Zend_Reflection_Property')

3.7. Zend_Reflection_Extension
Zend_Reflection_Extension étend ReflectionExtension et propose son API. Elle
surcharge les méthodes suivantes afin d'ajouter un paramètre permettant de spécifier sa propre
classe de réflexion :

• getFunctions($reflectionClass = 'Zend_Reflection_Function') : retourne un


tableau d'objets réflexion représentants les fonctions définies par l'extension en question.

• getClasses($reflectionClass = 'Zend_Reflection_Class') : retourne un


tableau d'objets réflexion représentants les classes définies par l'extension en question.

3.8. Zend_Reflection_Function
Zend_Reflection_Function ajoute une méthode pour retrouver le type de retour de la
fonction introspéctée, et surcharge d'autres méthodes pour proposer de passer en paramètre
une classe de réflexion à utiliser.

• getDocblock($reflectionClass = 'Zend_Reflection_Docblock'): Retourne un


objet représentant les blocs de documentation.

• getParameters($reflectionClass = 'Zend_Reflection_Parameter') : Retourne


un tableau représentant les paramètres de la fonction analysée sous forme d'objets réflexion.

• getReturn() : Retourne le type de retour sous forme d'objet réflexion

3.9. Zend_Reflection_Method
Zend_Reflection_Method reprend l'API de Zend_Reflection_Function et surcharge la
méthode suivante:

• getParentClass($reflectionClass = 'Zend_Reflection_Class') : Retourne un


objet réflexion de la classe parente

3.10. Zend_Reflection_Parameter
Zend_Reflection_Parameter ajoute une méthode pour retrouver le type d'un paramètre, et
aussi surcharge certaines méthodes en rajoutant un paramètre permettant de spécifier sa propre
classe de réflexion.

• getDeclaringClass($reflectionClass = 'Zend_Reflection_Class') : retourne


un objet réflexion représentant la classe de déclaration du paramètre (si disponible).

1146
Zend_Reflection

• getClass($reflectionClass = 'Zend_Reflection_Class') : retourne un objet


réflexion représentant la classe de l'objet passé comme paramètre (si disponible).

• getDeclaringFunction($reflectionClass = 'Zend_Reflection_Function') :
retourne un objet réflexion représentant la fonction passée comme paramètre (si disponible).

• getType() : retourne le type du paramètre.

3.11. Zend_Reflection_Property
Zend_Reflection_Property surcharge une seule méthode afin de pouvoir spécifier le type
de classe de retour :

• getDeclaringClass($reflectionClass = 'Zend_Reflection_Class') : Retourne


un objet réflexion représentant la classe de l'objet passé comme paramètre (si disponible).

1147
Zend_Registry
1. Utiliser le registre
Un registre est un conteneur pour stocker des objets et des valeurs dans l'espace d'application.
En stockant la valeur dans le registre, le même objet est toujours disponible partout dans votre
application. Ce mécanisme est une alternative à l'utilisation du stockage global.

L'utilisation typique des registres dans Zend Framework est par des méthodes statiques dans
la classe Zend_Registry. Alternativement, la classe est un tableau, donc vous pouvez avoir
accès aux éléments stockés avec une interface semblable au tableau.

1.1. Mettre des valeurs dans le registre


Pour enregistrer une valeur dans le registre, il faut utiliser la méthode statique set().

Exemple 613. Exemple avec la méthode set()

Zend_Registry::set('index', $value);

La valeur peut être un objet, un tableau, ou un scalaire. Vous pouvez changer la valeur stockée
dans une entrée spécifique du registre en utilisant set() pour enregistrer une nouvelle valeur.

L'index peut être un scalaire (NULL, chaîne, ou nombre), comme un tableau ordinaire.

1.2. Lire des valeurs du registre


Pour récupérer une entrée dans le registre,il faut utiliser la méthode statique get().

Exemple 614. Exemple avec la méthode get()

$value = Zend_Registry::get('index');

La méthode getInstance() retourne l'objet registre en entier. Un objet registre est itératif,
rendant les valeurs stockées facilement accessibles.

Exemple 615. Exemple d'itération du registre

$registry = Zend_Registry::getInstance();

foreach ($registry as $index => $value) {


echo "Le registre index $index contient :\n";
var_dump($value);
}

1.3. Construire un objet registre


En plus de pouvoir accéder au registre grâce aux méthodes statiques, vous pous pouvez créer
une instance directement et l'utiliser en tant qu'objet.

1148
Zend_Registry

L'instance du registre à laquelle vous avez accès par les méthodes statiques est simplement
une instance et il est plus commode qu'il soit stocké statiquement, afin d'y avoir accès partout
dans votre application.

Utiliser le constructeur traditionnel new pour créer une instance du registre. Ceci vous donne la
possibilité d'initialiser les entrées du registre avec un tableau associatif.

Exemple 616. Exemple de construction d'un registre

$registry = new Zend_Registry(array('index' => $value));

Après avoir construit cette instance, vous pouvez l'utiliser avec les fonctions habituelles de
tableau, ou vous pouvez rendre cette instance statique en utilisant la méthode setInstance().

Exemple 617. Exemple d'initialisation d'un registre statique

$registry = new Zend_Registry(array('index' => $value));

Zend_Registry::setInstance($registry);

La méthode setInstance() lèvera une Zend_Exception si un registre statique a déjà été


initialisé lors de son premier accès.

1.4. Accéder au registre comme à un tableau


Si vous avez plusieurs valeurs à récupérer ou à enregistrer, vous pouvez trouver intéressant
d'avoir accès au registre avec une notation de type tableau.

Exemple 618. Exemple d'accès de type tableau

$registry = Zend_Registry::getInstance();

$registry['index'] = $value;

var_dump( $registry['index'] );

1.5. Accéder au registre comme à un objet


Vous pouvez trouver aussi intéressant d'accéder au registre d'une manière orientée objet
en utilisant les noms d'index comme des propriétés d'objet. Pour cela, vous devez spécifier
au constructeur du registre l'option ArrayObject::ARRAY_AS_PROPS et initialiser l'instance
statique. Vous devez faire ceci avant d'accéder au registre statique. Attention en utilisant cette
option, puisque certaines versions de PHP ont des bugs quand il utilise le registre avec cette
option.

Problèmes connus avec l'option


ArrayObject::ARRAY_AS_PROPS

Certaines versions de PHP sont réputées buggués lors de l'utilisation de l'option


de registre ArrayObject::ARRAY_AS_PROPS.

1149
Zend_Registry

Exemple 619. Exemple d'accès de type objet

// Dans votre fichier de lancement de l'application


$registry = new Zend_Registry(array(), ArrayObject::ARRAY_AS_PROPS)
Zend_Registry::setInstance($registry);
$registry->tree='apple';

// Ailleurs dans l'application


$registry = Zend_Registry::getInstance();

echo $registry->tree; // affiche 'apple'


$registry->index = $value;

var_dump($registry->index);

1.6. Vérifier si un index existe


Pour savoir si un index particulier du registre a une valeur, il faut utiliser la méthode statique
isRegistered().

Exemple 620. Exemple avec la méthode isRegistered()

if (Zend_Registry::isRegistered($index)) {
$value = Zend_Registry::get($index);
}

Pour savoir si un index particulier du registre de type tableau a une valeur, il faut utiliser la
fonction isset() comme vous le feriez avec un tableau ordinaire.

Exemple 621. Exemple avec la méthode isset()

$registry = Zend_Registry::getInstance();

// En utilisant la syntaxe de type tableau


if (isset($registry['index'])) {
var_dump( $registry['index'] );
}

// En utilisant la syntaxe de type objet, si activé


if (isset($registry->index)) {
var_dump( $registry->index );
}

1.7. Étendre le registre


Le registre statique est une instance de la classe Zend_Registry. Si vous voulez ajouter une
fonctionnalité au registre, vous pouvez créer une classe qui étend Zend_Registry et ensuite
vous pouvez spécifier cette classe comme la classe à utiliser pour le registre statique. Utilisez
la méthode statique setClassName() pour spécifier la classe.

La classe doit étendre Zend_Registry.

1150
Zend_Registry

Exemple 622. Exemple d'affectation d'un nom de classe au registre

Zend_Registry::setClassName('Mon_Registre');

Zend_Registry::set('index', $value);

L'enregistrement lève une Zend_Exception si vous essayez d'affecter un nom de classe après
que le registre ait eu un premier accès. Il est recommandé de spécifier le nom de classe pour
votre registre statique dans le fichier de lancement de votre application.

1.8. Décharger le registre statique


Bien que ce ne soit pas normalement nécessaire, vous pouvez décharger l'instance de votre
registre. Utilisez la méthode statique _unsetInstance().

Risque de perte de données


Quand vous utilisez le code _unsetInstance(), toutes les données dans le
registre statique sont perdues et ne peuvent pas être récupérées.

Vous pourriez utiliser cette méthode, par exemple, si vous voulez utiliser setInstance() ou
setClassName() après que l'objet de registre statique a été initialisé. Décharger l'instance
statique vous permet d'utiliser ces méthodes même après instanciation de l'objet registre. Utiliser
Zend_Registry de cette manière n'est pas recommandé dans les applications.

Exemple 623. Exemple avec la méthode _unsetInstance()

Zend_Registry::set('index', $value);

Zend_Registry::_unsetInstance();

// Changer la classe
Zend_Registry::setClassName('Mon_Registre');

Zend_Registry::set('index', $value);

1151
Zend_Rest
1. Introduction
Les services Web REST utilisent des formats XML spécifiques. Ces normes ad-hoc signifient que
la façon d'accéder à un service Web REST est différente pour chaque service. Les services Web
REST utilise typiquement les paramètres URL (données GET) ou les informations du chemin
pour demander des données, et les données POST pour envoyer des données.

Zend Framework fournit les possibilités de client et de serveur, qui, une fois utilisées ensemble
tiennent compte de beaucoup plus d'expérience d'interface "locale" par l'intermédiaire de l'accès
aux propriétés d'objet virtuel. Le composant serveur comporte l'exposition automatique des
fonctions et des classes employant un format compréhensible et simple de XML. En accédant à
ces services via le client, il est possible de rechercher facilement les données retournées lors de
l'appel à distance. Si vous souhaitez employer le client avec un service non basé sur le service
Zend_Rest_Server, il fournira un accès plus facile aux données.

En plus des composants Zend_Rest_Server et Zend_Rest_Client, les classes


Zend_Rest_Route et Zend_Rest_Controller sont fournies pour aider lors du routage des
requêtes vers les contrôleurs.

2. Zend_Rest_Client
2.1. Introduction
Utiliser le Zend_Rest_Client est très semblable à l'utilisation des objets de SoapClient
(SOAP web service extension). Vous pouvez simplement appeler les procédures de service de
REST comme méthodes de Zend_Rest_Client. Vous devez indiquer l'adresse complète du
service dans le constructeur de Zend_Rest_Client.

Exemple 624. Une requête REST basique

/**
* Connexion au serveur framework.zend.com server
*/
require_once 'Zend/Rest/Client.php';

$client = new Zend_Rest_Client('http://framework.zend.com/rest');

echo $client->sayHello('Davey', 'Day')->get();


// "Hello Davey, Good Day"

Différences dans les appels

Zend_Rest_Client tente de rendre les méthodes distantes de la même


manière que ses propres méthodes, la seule différence étant que vous devez
suivre l'appel de méthode get(), post(), put() ou delete(). Cet appel peut
être fait par l'intermédiaire de méthodes enchaînées ou dans des appels séparés
de méthode :

$client->sayHello('Davey', 'Day');

1152
Zend_Rest

echo $client->get();

2.2. Réponses
Toutes les demandes faites en utilisant Zend_Rest_Client retourne un objet
Zend_Rest_Client_Response. Cet objet a beaucoup de propriétés qui facilitent l'accès aux
résultats.

Quand le service est basé sur Zend_Rest_Server, Zend_Rest_Client peut faire plusieurs
suppositions au sujet de la réponse, y compris le statut de réponse (succès ou échec) et le type
de retour.

Exemple 625. État de la réponse

$result = $client->sayHello('Davey', 'Day')->get();

if ($result->isSuccess()) {
echo $result; // "Hello Davey, Good Day"
}

Dans l'exemple ci-dessus, vous pouvez voir que nous utilisons le résultat de la demande
comme un objet, pour appeler isSuccess(), et puis grâce à __toString(), nous pouvons
simplement faire echo sur l'objet pour récupérer le résultat. Zend_Rest_Client_Response
vous permettra de afficher n'importe quelle valeur scalaire. Pour les types complexes, vous
pouvez employer la notation type objet ou type tableau.

Si cependant, vous souhaitez questionner un service n'employant pas Zend_Rest_Server


l'objet de Zend_Rest_Client_Response se comportera comme un SimpleXMLElement.
Cependant, pour faciliter les choses, il questionnera automatiquement le XML en utilisant XPath
si la propriété n'est pas un descendant direct de l'élément racine du document. En plus, si vous
accédez à une propriété comme à une méthode, vous recevrez la valeur de PHP pour l'objet,
ou un tableau de résultats.

Exemple 626. Utiliser le service REST Technorati

$technorati = new Zend_Rest_Client('http://api.technorati.com/bloginfo');


$technorati->key($key);
$technorati->url('http://pixelated-dreams.com');
$result = $technorati->get();
echo $result->firstname() .' '. $result->lastname();

1153
Zend_Rest

Exemple 627. Exemple de réponse Technorati

<?xml version="1.0" encoding="utf-8"?>


<!-- generator="Technorati API version 1.0 /bloginfo" -->
<!DOCTYPE tapi PUBLIC "-//Technorati, Inc.//DTD TAPI 0.02//EN"
"http://api.technorati.com/dtd/tapi-002.xml">
<tapi version="1.0">
<document>
<result>
<url>http://pixelated-dreams.com</url>
<weblog>
<name>Pixelated Dreams</name>
<url>http://pixelated-dreams.com</url>
<author>
<username>DShafik</username>
<firstname>Davey</firstname>
<lastname>Shafik</lastname>
</author>
<rssurl>http://pixelated-dreams.com/feeds/index.rss2</rssurl>
<atomurl>http://pixelated-dreams.com/feeds/atom.xml</atomurl>
<inboundblogs>44</inboundblogs>
<inboundlinks>218</inboundlinks>
<lastupdate>2006-04-26 04:36:36 GMT</lastupdate>
<rank>60635</rank>
</weblog>
<inboundblogs>44</inboundblogs>
<inboundlinks>218</inboundlinks>
</result>
</document>
</tapi>

Ici nous accédons aux propriétés firstname et lastname.Bien que ce ne soient pas les
éléments supérieurs, elles sont automatiquement retournées quand on accède par le nom.

Éléments multiples

Si des éléments multiples sont trouvés en accédant à une valeur de nom, un


tableau d'élément SimpleXMLElement sera retourné ; l'accès par l'intermédiaire
de la notation de méthode retournera un tableau de valeurs.

2.3. Arguments de requêtes


A moins que vous ne fassiez une demande à un service basé sur Zend_Rest_Server, il y a
des chances que vous devez envoyer des arguments multiples avec votre requête. Ceci est fait
en appelant une méthode avec le nom de l'argument, en passant la valeur comme premier (et
seul) argument. Chacun de ces appels de méthode renvoie l'objet lui-même, tenant compte de
l'enchaînement, ou de l'utilisation habituelle. Le premier appel, ou le premier argument si vous
passez plus d'un argument, est toujours considéré comme la méthode en appelant un service
Zend_Rest_Server.

1154
Zend_Rest

Exemple 628. Affecter des arguments de requêtes

$client = new Zend_Rest_Client('http://example.org/rest');

$client->arg('value1');
$client->arg2('value2');
$client->get();

// or

$client->arg('value1')->arg2('value2')->get();

Les deux méthodes dans l'exemple ci-dessus, auront comme conséquence l'obtention des
arguments suivants : ?method=arg&arg1=value1&arg=value1&arg2=value2

Vous noterez que le premier appel de $client->arg('value1'); a eu comme conséquence


method=arg&arg1=value1 et arg=value1 ; ceci afin que Zend_Rest_Server puisse
comprendre la demande correctement, plutôt que d'exiger la connaissance préalable du service.

Sévérité de Zend_Rest_Client

Tout service REST qui est strict au sujet des arguments qu'il reçoit échouera
probablement en utilisant Zend_Rest_Client, en raison du comportement
décrit ci-dessus. Ce n'est pas une pratique courante et ne devrait pas poser des
problèmes.

3. Zend_Rest_Server
3.1. Introduction
Zend_Rest_Server est prévu comme un serveur supportant l'ensemble des fonctionnalités d'un
serveur REST.

3.2. Utilisation d'un serveur REST


Exemple 629. Utilisation basique Zend_Rest_Server - Avec des classes

$server = new Zend_Rest_Server();


$server->setClass('Mon_Service_Classe');
$server->handle();

1155
Zend_Rest

Exemple 630. Utilisation basique Zend_Rest_Server - Avec des fonctions

/**
* Dit Bonjour
*
* @param string $qui
* @param string $quand
* @return string
*/
function ditBonjour($qui, $quand)
{
return "Bonjour $qui, bonne $quand";
}

$server = new Zend_Rest_Server();


$server->addFunction('ditBonjour');
$server->handle();

3.3. Appelé un service Zend_Rest_Server


Pour appeler un service Zend_Rest_Server, vous devez fournir un argument de method GET/
POST avec une valeur qui est la méthode que vous souhaitez appeler. Vous pouvez alors ajouter
tout nombre d'arguments en utilisant le nom de l'argument (c.-à-d. "qui ") ou en utilisant 'arg' suivi
de la position numérique de l'argument (c.-à-d. "arg1").

Index numérique

Les arguments numériques utilisent 1 comme point de départ.

Pour appeler le ditBonjour de l'exemple ci-dessus, vous pouvez employer soit :

?method=ditBonjour&qui=Davey&quand=journée

or:

?method=ditBonjour&arg1=Davey&arg2=journée

3.4. Envoyer un statut personnalisé


En envoyant des valeurs, pour ajouter un statut personnalisé, vous pouvez envoyer un tableau
avec une clé status.

1156
Zend_Rest

Exemple 631. Renvoyer un statut personnalisé

/**
* Dit Bonjour
*
* @param string $qui
* @param string $quand
* @return array
*/
function ditBonjour($qui, $quand)
{
return array('msg' => "Une erreur est apparue", 'status' => false);
}

$server = new Zend_Rest_Server();


$server->addFunction('ditBonjour');
$server->handle();

3.5. Renvoyer une réponse XML personnalisée


Si vous voulez retourner du XML personnalisé, retournez simplement un objet DOMDocument,
DOMElement ou SimpleXMLElement.

Exemple 632. Renvoyer une réponse XML personnalisée

/**
* Dit Bonjour
*
* @param string $who
* @param string $when
* @return SimpleXMLElement
*/
function ditBonjour($qui, $quand)
{
$xml ='<?xml version="1.0" encoding="ISO-8859-1"?>
<mysite>
<value>Salut $qui! J\'espère que tu passes une bonne $when</value>
<constant>200</constant>
</mysite>';

$xml = simplexml_load_string($xml);
return $xml;
}

$server = new Zend_Rest_Server();


$server->addFunction('ditBonjour');

$server->handle();

La réponse du service sera retournée sans modification au client.

1157
Zend_Search_Lucene
1. Vue d'ensemble
1.1. Introduction
Zend_Search_Lucene est un moteur de recherche de contenus principalement textuels écrit
entièrement en PHP 5. Comme il stocke ses index sur le système de fichiers et qu'il ne requiert
pas de base de données, il peut offrir des fonctionnalités de recherche à presque n'importe quel
site écrit en PHP. Zend_Search_Lucene dispose des caractéristiques suivantes :

• "Ranked searching" - les meilleurs résultats sont retournés en premier.

• Plusieurs puissants types de requêtes : phrase, booléen, joker (wildcard), proximité, intervalle
et bien d'autres.

• Recherche par champ spécifique (p. ex. titre, auteur, contenus)

Zend_Search_Lucene est dérivé du projet Apache Lucene. Les versions actuelles de


format d'index Lucene supportées (à partir de Zend Framework 1.6) sont 1.4 à 2.3. Pour plus
d'informations sur Lucene, rendez-vous sur http://lucene.apache.org/java/docs/.

Les implémentations précédentes de Zend_Search_Lucene supportent les


formats d'indexation Lucene 1.4 (1.9) à 2.1.

A partir de Zend Framework 1.5, tout index créé en utilisant une version
antérieure à la 2.1 et automatiquement mis à niveau au format Lucene 2.1
après la mise à jour de Zend_Search_Lucene et ne sera pas compatible avec
les implémentations de Zend_Search_Lucene incluses dans Zend Framework
1.0.x.

1.2. Objet "Document" et "Field"


Zend_Search_Lucene travaille avec des documents comme objets de base pour l'indexation.
Un document est divisé en champs possédant un nom et du contenu dans lequel on pourra
chercher.

Un document est représenté par la classe Zend_Search_Lucene_Document. Les objets de


cette classe contiennent des instances de Zend_Search_Lucene_Field qui représentent les
champs du document.

Il est important de noter que n'importe quelle information peut être ajoutée à l'index. Des
informations propres à l'application ou des métadonnées peuvent être stockées dans le
document, puis récupérées durant la recherche.

Il est de la responsabilité de votre application de gérer l'indexation. Cela signifie que les données
peuvent être indexées depuis n'importe quelle source accessible par votre application. Par
exemple, elles peuvent provenir du système de fichier, d'une base de données, d'un formulaire
HTML, etc.

La classe Zend_Search_Lucene_Field fournit plusieurs méthodes statiques pour créer des


champs avec différentes caractéristiques :

1158
Zend_Search_Lucene

$doc = new Zend_Search_Lucene_Document();

// Le champ n'est pas "tokenizé", mais il est indexé et stocké dans l'index.
// Les champs stockés peuvent être récupéré depuis l'index.
$doc->addField(Zend_Search_Lucene_Field::Keyword('doctype',
'autogenerated'));

// Le champ n'est ni "tokenizé", ni indexé, mais il est stocké dans l'index.


$doc->addField(Zend_Search_Lucene_Field::UnIndexed('created',
time()));

// Un champ chaîne binaire qui n'est ni "tokenizé", ni indexé, mais


// stocké dans l'index.
$doc->addField(Zend_Search_Lucene_Field::Binary('icon',
$iconData));

// Un champ "tokenizé", indexé et stocké dans l'index.


$doc->addField(Zend_Search_Lucene_Field::Text('annotation',
'Document annotation text'));

// Un champ "tokenizé" et indexé, mais pas stocké dans l'index.


$doc->addField(Zend_Search_Lucene_Field::UnStored('contents',
'My document content'));

Chacune de ces méthodes (à l'exception de Zend_Search_Lucene_Field::Binary())


possède un paramètre optionnel $encoding servant à spécifier l'encodage de la chaîne entrée.

L'encodage peut différer par document, voire par champ au sein d'un même document :

$doc = new Zend_Search_Lucene_Document();


$doc->addField(Zend_Search_Lucene_Field::Text('title',
$title,
'iso-8859-1'));
$doc->addField(Zend_Search_Lucene_Field::UnStored('contents',
$contents,
'utf-8'));

Si le paramètre d'encodage est omis, la locale courante est alors utilisée pour le déterminer à
l'exécution. Par exemple :

setlocale(LC_ALL, 'de_DE.iso-8859-1');
...
$doc->addField(Zend_Search_Lucene_Field::UnStored('contents', $contents));

Les champs sont toujours stockés et retournés depuis l'index en UTF-8. Toute conversion
requise vers UTF-8 est effectuée automatiquement.

Les analyseurs de texte (voir plus bas) peuvent également convertir du texte vers d'autres
encodages. Actuellement, l'analyseur par défaut convertit le texte au format "ASCII/TRANSLIT".
Soyez prudent, cependant; cette conversion peut déprendre de la locale.

Le nom des champs est défini par vous dans la méthode addField().

Java Lucene utilise le champ "contents" comme champ de recherche par défaut.
Zend_Search_Lucene cherche par défaut dans tous les champs. Cela dit, ce comportement
est configurable. Consultez le chapitre "Champ de recherche par défaut" pour plus de détails.

1159
Zend_Search_Lucene

1.3. Comprendre les types de champs


• Les champs Keyword (mot-clé) sont stockés ET indexés. Cela signifie qu'ils peuvent être
aussi bien cherchés dans l'index qu'affichés dans les résultats de la recherche. Ils ne sont
pas divisés en plusieurs mots par "tokenization". Les champs d'énumérations dans une base
de donnée se transposent généralement assez bien en champs de type Keyword dans
Zend_Search_Lucene.

• Les champs UnIndexed (non-indexé) ne peuvent pas être utilisés dans la recherche. En
revanche, ils peuvent être retournés dans les résultats. Des timestamps de base de données,
des clés primaires, des chemins de fichiers et d'autres identifiants externes sont autant de
bons exemples d'utilisation des champs de type UnIndexed.

• Les champs Binary (binaire) ne sont ni "tokenizés", ni indexés, mais ils sont stockés dans
le but d'être retournés dans les résultats de recherche. Ils peuvent être utilisés pour stocker
n'importe quelle donnée encodée en chaîne binaire, telle qu'une icône par exemple.

• Les champs Text (texte) sont stockés, indexés et "tokenizés". Les champs de type Text sont
appropriés pour stocker des informations telles que sujets et titres sur lesquels on veut pouvoir
effectuer des recherches, mais également les utiliser dans l'affichage des résultats.

• Les champs UnStored sont "tokenizés" et indexés, mais pas stockés dans l'index. Il est
recommandé d'utiliser ce type de champ pour indexer les textes conséquents. Stocker
des données implique la création d'index plus volumineux sur le disque. Donc si vous
disposez de données sur lesquelles vous voulez uniquement effectuer des recherches sans
nécessairement afficher ces données dans les résultats, utilisez un champ de type UnStored.
Le type UnStored est pratique lorsque vous utilisez un index Zend_Search_Lucene en
combinaison avec une base de données relationnelle. Vous pouvez indexer des gros champs
de données dans des champs de type UnStored et les extraire de la base de données
relationnelle en utilisant un champ séparé en tant qu'identifiant.

Tableau 113. Les types Zend_Search_Lucene_Field

Type de champ Stocké Indexé "Tokenizé" Binaire


Keyword Oui Oui Non Non
UnIndexed Oui Non Non Non
Binary Oui Non Non Oui
Text Oui Oui Oui Non
UnStored Non Oui Oui Non

1.4. Documents HTML


Zend_Search_Lucene offre une fonctionnalité d'analyse HTML. Les documents peuvent être
créés directement à d'un fichier ou d'une chaîne HTML :

$doc = Zend_Search_Lucene_Document_Html::loadHTMLFile($filename);
$index->addDocument($doc);
...
$doc = Zend_Search_Lucene_Document_Html::loadHTML($htmlString);
$index->addDocument($doc);

La classe Zend_Search_Lucene_Document_Html utilise les méthodes


DOMDocument::loadHTML() et DOMDocument::loadHTMLFile() pour analyser la source

1160
Zend_Search_Lucene

HTML, ainsi il n'est pas nécessaire que le HTML soit bien formé ou au format XHTML. Par contre,
ces méthodes prennent en compte l'encodage spécifié dans la balise méta "http-equiv".

La classe Zend_Search_Lucene_Document_Html reconnaît le titre d'une page HTML, son


corps ("body"), ainsi que les métadonnées de son entête.

Le champ "title" correspond au contenu de la balise /html/head/title. Il est stocké dans l'index,
"tokenizé" et disponible pour la recherche.

Le champ "body" correspond au contenu de la balise "body" du fichier ou de la chaîne HTML. Il


ne prend pas en compte les scripts, les commentaires ou les attributs.

Les méthodes loadHTML() et loadHTMLFile() de la classe


Zend_Search_Lucene_Document_Html possèdent également un deuxième argument
optionnel. Si sa valeur est true, le body sera alors stocké dans l'index et pourra être retourné
dans les résultats de recherche. Par défaut, le body est "tokenizé", indexé, mais pas stocké.

The third parameter of loadHTML() and loadHTMLFile() methods optionally specifies source
HTML document encoding. It's used if encoding is not specified using Content-type HTTP-EQUIV
meta tag.

Les autres métadonnées génèrent des champs additionnels dans le document. Le champ
"name" prend sa valeur dans l'attribut "name" de la métadonnées. Le champ "value" prend sa
valeur dans l'attribut "content" de la métadonnées. Ces deux champs sont "tokenizés", indexés
et stockés. Ainsi les documents peuvent être cherchés à travers leurs métadonnées (p. ex. par
mots-clés).

Les documents analysés peuvent être enrichis par le programmeur avec d'autres champs :

$doc = Zend_Search_Lucene_Document_Html::loadHTML($htmlString);
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('created',
time()));
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('updated',
time()));
$doc->addField(Zend_Search_Lucene_Field::Text('annotation',
'Document annotation text'));
$index->addDocument($doc);

Les liens des documents ne sont pas inclus dans le document généré, mais ils peuvent être
récupérés avec les méthodes Zend_Search_Lucene_Document_Html::getLinks() et
Zend_Search_Lucene_Document_Html::getHeaderLinks() :

$doc = Zend_Search_Lucene_Document_Html::loadHTML($htmlString);
$linksArray = $doc->getLinks();
$headerLinksArray = $doc->getHeaderLinks();

A partir de Zend Framework 1.6, il est également possible


d'exclure les balises "link" dont l'attribut rel vaut 'nofollow'. Utilisez
Zend_Search_Lucene_Document_Html::setExcludeNoFollowLinks($true) pour
activer cette option.

La méthode Zend_Search_Lucene_Document_Html::getExcludeNoFollowLinks()
retourne la valeur courante du flag "Exclude nofollow links".

1.5. Documents Word 2007


Zend_Search_Lucene offre une fonctionnalité d'analyse de documents Word 2007. On peut
créer directement un document depuis un fichier Word 2007 :

1161
Zend_Search_Lucene

$doc = Zend_Search_Lucene_Document_Docx::loadDocxFile($filename);
$index->addDocument($doc);

La classe Zend_Search_Lucene_Document_Docx utilise la classe ZipArchive et les


méthodes de simplexml pour analyser le document source. Si la classe ZipArchive (issue
du module php_zip) n'est pas disponible, Zend_Search_Lucene_Document_Docx ne sera
pas non plus disponible dans le Zend Framework.

La classe Zend_Search_Lucene_Document_Docx reconnaît les métadonnées et le texte des


documents. Les métadonnées sont constituées, suivant le contenu du document, du nom de
fichier (filename), sujet (subject), créateur (creator), mots-clés (keywords), description, auteur
de la dernière modification (lastModifiedBy), révision (revision), date de modification (modified),
date de création (created).

Le champ "filename" correspond au nom du fichier Word 2007.

Le champ "title" correspond au titre du document.

Le champ "subject" correspond au sujet du document.

Le champ "creator" correspond à l'auteur du document.

Le champ "keywords" contient les mots-clés du document.

Le champ "description" correspond à la description du document.

Le champ "lastModifiedBy" correspond au nom de l'utilisateur qui a modifié en dernier le


document.

Le champ "revision" correspond au numéro actuel de la version du document.

Le champ "modified" contient la date de dernière modification du document.

Le champ "created" contient la date de création du document.

Le champ "body" contient le véritable contenu du document Word 2007. Il n'inclut que le texte
normal. Les commentaires et révisions ne sont pas inclus.

La méthode loadDocxFile() de la classe Zend_Search_Lucene_Document_Docx


possède également un second argument optionnel. S'il est défini à TRUE, le champ "body" sera
alors également stocké dans l'index et pourra être affiché dans les résultats de recherche. Par
défaut, le champ "body" est "tokenizé" et indexé, mais pas stocké.

Les documents parsés peuvent être étendus par le programmeur avec d'autres champs :

$doc = Zend_Search_Lucene_Document_Docx::loadDocxFile($filename);
$doc->addField(Zend_Search_Lucene_Field::UnIndexed(
'indexTime',
time())
);
$doc->addField(Zend_Search_Lucene_Field::Text(
'annotation',
'Document annotation text')
);
$index->addDocument($doc);

1162
Zend_Search_Lucene

1.6. Document Powerpoint 2007


Zend_Search_Lucene offre une fonctionnalité d'analyse de documents Powerpoint 2007. On
peut créer directement un document depuis un fichier Powerpoint 2007 :

$doc = Zend_Search_Lucene_Document_Pptx::loadPptxFile($filename);
$index->addDocument($doc);

La classe Zend_Search_Lucene_Document_Pptx utilise la classe ZipArchive et les


méthodes de simplexml pour analyser le document source. Si la classe ZipArchive (issue
du module php_zip) n'est pas disponible, Zend_Search_Lucene_Document_Pptx ne sera
pas non plus disponible dans le Zend Framework.

La classe Zend_Search_Lucene_Document_Pptx reconnaît les métadonnées et le texte des


documents. Les métadonnées sont constituées, suivant le contenu du document, du nom de
fichier (filename), sujet (subject), créateur (creator), mots-clés (keywords), description, auteur
de la dernière modification (lastModifiedBy), révision (revision), date de modification (modified),
date de création (created).

Le champ "filename" correspond au nom du fichier Powerpoint 2007.

Le champ "title" correspond au titre du document.

Le champ "subject" correspond au sujet du document.

Le champ "creator" correspond à l'auteur du document.

Le champ "keywords" contient les mots-clés du document.

Le champ "description" correspond à la description du document.

Le champ "lastModifiedBy" correspond au nom de l'utilisateur qui a modifié en dernier le


document.

Le champ "revision" correspond au numéro actuel de la version du document.

Le champ "modified" contient la date de dernière modification du document.

Le champ "created" contient la date de création du document.

Le champ "body" contient le véritable contenu de toutes les slides, ainsi que les notes dans le
document Powerpoint 2007.

La méthode loadPptxFile() de la classe Zend_Search_Lucene_Document_Pptx


possède également un second argument optionnel. S'il est défini à true, le champ "body" sera
alors également stocké dans l'index et pourra être affiché dans les résultats de recherche. Par
défaut, le champ "body" est "tokenizé" et indexé, mais pas stocké.

Les documents analysés peuvent être étendus par le programmeur avec d'autres champs :

$doc = Zend_Search_Lucene_Document_Pptx::loadPptxFile($filename);
$doc->addField(Zend_Search_Lucene_Field::UnIndexed(
'indexTime',
time()));
$doc->addField(Zend_Search_Lucene_Field::Text(
'annotation',

1163
Zend_Search_Lucene

'Document annotation text'));


$index->addDocument($doc);

1.7. Documents Excel 2007


Zend_Search_Lucene offre une fonctionnalité d'analyse de documents Excel 2007. On peut
créer directement un document depuis un fichier Excel 2007 :

$doc = Zend_Search_Lucene_Document_Xlsx::loadXlsxFile($filename);
$index->addDocument($doc);

La classe Zend_Search_Lucene_Document_Xlsx utilise la classe ZipArchive et les


méthodes de simplexml pour analyser le document source. Si la classe ZipArchive (issue
du module php_zip) n'est pas disponible, Zend_Search_Lucene_Document_Xlsx ne sera
pas non plus disponible dans le Zend Framework.

La classe Zend_Search_Lucene_Document_Xlsx reconnaît les métadonnées et le texte des


documents. Les métadonnées sont constituées, suivant le contenu du document, du nom de
fichier (filename), sujet (subject), créateur (creator), mots-clés (keywords), description, auteur
de la dernière modification (lastModifiedBy), révision (revision), date de modification (modified),
date de création (created).

Le champ "filename" correspond au nom du fichier Excel 2007.

Le champ "title" correspond au titre du document.

Le champ "subject" correspond au sujet du document.

Le champ "creator" correspond à l'auteur du document.

Le champ "keywords" contient les mots-clés du document.

Le champ "description" correspond à la description du document.

Le champ "lastModifiedBy" correspond au nom de l'utilisateur qui a modifié en dernier le


document.

Le champ "revision" correspond au numéro actuel de la version du document.

Le champ "modified" contient la date de dernière modification du document.

Le champ "created" contient la date de création du document.

Le champ "body" contient le véritable contenu de toutes les cellules de toutes les feuilles de
calcul du document Excel 2007.

La méthode loadXlsxFile() de la classe Zend_Search_Lucene_Document_Xlsx


possède également un second argument optionnel. S'il est défini à true, le champ "body" sera
alors également stocké dans l'index et pourra être affiché dans les résultats de recherche. Par
défaut, le champ "body" est "tokenizé" et indexé, mais pas stocké.

Les documents analysés peuvent être étendus par le programmeur avec d'autres champs :

$doc = Zend_Search_Lucene_Document_Xlsx::loadXlsxFile($filename);
$doc->addField(Zend_Search_Lucene_Field::UnIndexed(
'indexTime',

1164
Zend_Search_Lucene

time()));
$doc->addField(Zend_Search_Lucene_Field::Text(
'annotation',
'Document annotation text'));
$index->addDocument($doc);

2. Créer des index


2.1. Créer un nouvel index
La création et la mise à jour des index sont implémentées dans le composant
Zend_Search_Lucene, ainsi que dans le projet Java Lucene. Vous pouvez utiliser l'une
ou l'autre de ces options pour créer des index dans lesquels Zend_Search_Lucene pourra
chercher.

Le listing ci-dessous donne un exemple d'indexation d'un fichier en utilisant l'API d'indexation
de Zend_Search_Lucene :

// Création de l'index
$index = Zend_Search_Lucene::create('/data/my-index');

$doc = new Zend_Search_Lucene_Document();

// Stockage de l'URL du document afin de pouvoir l'identifier dans les résultats de recherch
$doc->addField(Zend_Search_Lucene_Field::Text('url', $docUrl));

// Indexation des contenus du document


$doc->addField(Zend_Search_Lucene_Field::UnStored('contents', $docContent));

// Ajout du document à l'index


$index->addDocument($doc);

Les documents nouvellement ajoutés sont immédiatement recherchables dans l'index.

2.2. Mettre à jour un index


La même procédure est utilisée pour mettre à jour un index existant. La seule différence est
l'appel de la méthode open() à la place de create().

// Ouverture d'un index existant


$index = Zend_Search_Lucene::open('/data/my-index');

$doc = new Zend_Search_Lucene_Document();


// Stockage de l'URL du document afin de pouvoir l'identifier dans les résultats de recherch
$doc->addField(Zend_Search_Lucene_Field::Text('url', $docUrl));
// Indexation des contenus du document
$doc->addField(Zend_Search_Lucene_Field::UnStored('contents',
$docContent));

// Ajout du document à l'index


$index->addDocument($doc);

2.3. Mise à jour de Documents


Le format de fichier d'un index Lucene ne permet pas la mise à jour d'un document. Les
documents doivent être supprimés puis réinsérés dans l'index afin d'être mis à jour efficacement.

1165
Zend_Search_Lucene

La méthode Zend_Search_Lucene::delete() utilise un identifiant interne de document. Cet


identifiant peut être récupéré dans une requête en demandant la propriété 'id' :

$removePath = ...;
$hits = $index->find('path:' . $removePath);
foreach ($hits as $hit) {
$index->delete($hit->id);
}

2.4. Récupération de la taille de l'index


Il existe deux méthodes pour récupérer la taille d'un index dans Zend_Search_Lucene.

La méthode Zend_Search_Lucene::maxDoc() retourne un de plus que le plus grand


nombre possible de documents. Il s'agit en fait du nombre total de documents dans
l'index, y compris les documents supprimés. Cette méthode a une méthode synonyme :
Zend_Search_Lucene::count().

La méthode Zend_Search_Lucene::numDocs() retourne le nombre total de documents non


supprimés.

$indexSize = $index->count();
$documents = $index->numDocs();

La méthode Zend_Search_Lucene::isDeleted($id) peut être utilisée pour vérifier si un


document a été supprimé.

for ($count = 0; $count < $index->maxDoc(); $count++) {


if ($index->isDeleted($count)) {
echo "Le document #$id a été supprimé.\n";
}
}

L'optimisation d'index retire les documents supprimés et resserre les identifiants de documents
dans un intervalle plus petit. Ainsi, un identifiant interne de document peut être modifié durant
l'optimisation de l'index.

2.5. Optimisation d'index


Un index Lucene est composé de plusieurs segments. Chaque segment est un ensemble de
données complètement indépendant des autres.

Les fichiers de segment d'index Lucene ne peuvent pas être mis à jour conceptuellement. Une
mise à jour de segment requiert une réorganisation complète de tous les segments. Consultez
les formats de fichiers d'index pour plus de détails (http://lucene.apache.org/java/2_3_0/
1
fileformats.html) Les nouveaux documents sont ajoutés à l'index en créant de nouveaux
segments.

L'augmentation du nombre de segments réduit la qualité de l'index, mais l'optimisation de l'index


remédie à ce problème. L'optimisation a pour principale activité de fusionner plusieurs segments
en un seul. Ce processus ne met pas à jour les segments. Il génère un nouveau segment plus
gros et met à jour la liste des segments ('segments' file).
1
Le format de fichier d'index supporté actuellement est la version 2.3 (depuis Zend Framework 1.6).

1166
Zend_Search_Lucene

L'optimisation complète de l'index peut être déclenchée en appelant la méthode


Zend_Search_Lucene::optimize(). Elle va fusionner tous les segments de l'index en un
seul nouveau segment :

// Ouverture d'un index existant.


$index = Zend_Search_Lucene::open('/data/my-index');

// Optimisation de l'index.
$index->optimize();

L'optimisation automatique de l'index est lancée pour garder les index dans un état cohérent.

L'optimisation automatique est un processus itératif géré par plusieurs options d'index. Il s'agit
de fusionner les très petits segments pour obtenir de plus gros segments, puis de fusionner ces
segments obtenus vers des segments encore plus gros et ainsi de suite.

2.5.1. Option d'optimisation automatique MaxBufferedDocs


MaxBufferedDocs correspond au nombre minimum de documents requis avant que les
documents présents en mémoire dans le buffer soit écris dans un nouveau segment.

MaxBufferedDocs peut être récupéré ou défini en appelant $index-


>getMaxBufferedDocs() ou $index->setMaxBufferedDocs($maxBufferedDocs).

Sa valeur par défaut est 10.

2.5.2. Option d'optimisation automatique MaxMergeDocs


MaxMergeDocs correspond à un nombre maximal de documents fusionnés via
addDocument(). Des petites valeurs (p. ex., moins de 10'000) sont préférables pour de
l'indexation interactive, du fait que cela limite les pauses durant l'indexation à quelques secondes.
Des valeurs plus grandes sont meilleures pour les indexations en tâches planifiées (batch) et
des recherches plus rapides.

MaxMergeDocs peut être récupéré ou défini en appelant $index->getMaxMergeDocs() ou


$index->setMaxMergeDocs($maxMergeDocs).

Sa valeur par défaut est PHP_INT_MAX.

2.5.3. Option d'optimisation automatique MergeFactor


MergeFactor détermine à quelle fréquence les segments d'index sont fusionnés par
addDocument(). Avec des petites valeurs, on utilise moins de RAM durant l'indexation et les
recherche sur des index non optimisés sont plus rapides, mais la vitesse d'indexation est plus
lente. Avec des valeurs plus grandes, on utilise plus de RAM durant l'indexation, et tandis que
les recherches sur les index non optimisés sont plus lentes, l'indexation est plus rapide. Au final,
les grandes valeurs (> 10) sont préférables pour les indexations planifiées (batch), et les valeurs
plus petites (< 10) pour les index qui sont maintenus de manière interactives.

L'option MergeFactor constitue une bonne estimation pour le nombre moyen de segments
fusionnés par une passe d'auto-optimisation. Des valeurs trop grandes produisent un nombre
trop important de segments car ils ne sont pas fusionnés. Cela peut causer l'erreur "failed to
open stream: Too many open files". Cette limitation est dépendante du système.

MergeFactor peut être récupéré ou défini par les méthodes $index->getMergeFactor() ou


$index->setMergeFactor($mergeFactor).

1167
Zend_Search_Lucene

Sa valeur par défaut est 10.

Lucene Java et Luke (Lucene Index Toolbox - http://www.getopt.org/luke/) peuvent aussi être
utilisés pour optimiser un index. La dernière version de Luke (v0.8) est basée sur Lucene v2.3 et
est compatible avec l'implémentation courante du composant Zend_Search_Lucene (ZF 1.6).
Les versions précédentes de Zend_Search_Lucene nécessitent d'autres versions des outils
de Java Lucene :

• ZF 1.5 - Java Lucene 2.1 (Luke tool v0.7.1 - http://www.getopt.org/luke/luke-0.7.1/)

• ZF 1.0 - Java Lucene 1.4 - 2.1 (Luke tool v0.6 - http://www.getopt.org/luke/luke-0.6/)

2.6. Permissions
Par défaut, les fichiers d'index sont disponibles en lecture et écriture par tout le monde.

Il est possible de surcharger ce comportement grâce à la méthode


Zend_Search_Lucene_Storage_Directory_Filesystem::setDefaultFilePermissions()
:

// Récupération des permissions par défaut


$currentPermissions =
Zend_Search_Lucene_Storage_Directory_Filesystem::getDefaultFilePermissions();

// Donne la permission lecture-écriture uniquement à l'utilisateur et au groupe courant.


Zend_Search_Lucene_Storage_Directory_Filesystem::setDefaultFilePermissions(0660);

2.7. Limitations
2.7.1. Taille de l'index
La taille de l'index est limité à 2GB sur les plate-formes 32 bits.

Utilisez des plate-formes 64 bits pour des index plus gros.

2.7.2. Systèmes de fichiers supportés


Zend_Search_Lucene utilise flock() pour fournir des recherches concurrentes, la mise à
jour des index et l'optimisation.

Selon la documentation PHP, "flock() ne fonctionnera pas sur NFS et plusieurs autres
systèmes de fichiers en réseaux".

N'utilisez pas de systèmes de fichiers en réseaux avec Zend_Search_Lucene.

3. Searching an Index
3.1. Building Queries
There are two ways to search the index. The first method uses query parser to construct a
query from a string. The second is to programmatically create your own queries through the
Zend_Search_Lucene API.

Before choosing to use the provided query parser, please consider the following:

1168
Zend_Search_Lucene

1. If you are programmatically creating a query string and then parsing it with the query parser
then you should consider building your queries directly with the query API. Generally speaking,
the query parser is designed for human-entered text, not for program-generated text.

2. Untokenized fields are best added directly to queries and not through the query parser. If a
field's values are generated programmatically by the application, then the query clauses for
this field should also be constructed programmatically. An analyzer, which the query parser
uses, is designed to convert human-entered text to terms. Program-generated values, like
dates, keywords, etc., should be added with the query API.

3. In a query form, fields that are general text should use the query parser. All others, such as
date ranges, keywords, etc., are better added directly through the query API. A field with a
limited set of values that can be specified with a pull-down menu should not be added to a
query string that is subsequently parsed but instead should be added as a TermQuery clause.

4. Boolean queries allow the programmer to logically combine two or more queries into new one.
Thus it's the best way to add additional criteria to a search defined by a query string.

Both ways use the same API method to search through the index:

$index = Zend_Search_Lucene::open('/data/my_index');

$index->find($query);

The Zend_Search_Lucene::find() method determines the input type automatically and


uses the query parser to construct an appropriate Zend_Search_Lucene_Search_Query
object from an input of type string.

It is important to note that the query parser uses the standard analyzer to tokenize separate parts
of query string. Thus all transformations which are applied to indexed text are also applied to
query strings.

The standard analyzer may transform the query string to lower case for case-insensitivity, remove
stop-words, and stem among other transformations.

The API method doesn't transform or filter input terms in any way. It's therefore more suitable
for computer generated or untokenized fields.

3.1.1. Query Parsing


Zend_Search_Lucene_Search_QueryParser::parse() method may be used to parse
query strings into query objects.

This query object may be used in query construction API methods to combine user entered
queries with programmatically generated queries.

Actually, in some cases it's the only way to search for values within untokenized fields:

$userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);

$pathTerm = new Zend_Search_Lucene_Index_Term(


'/data/doc_dir/' . $filename, 'path'
);
$pathQuery = new Zend_Search_Lucene_Search_Query_Term($pathTerm);

1169
Zend_Search_Lucene

$query = new Zend_Search_Lucene_Search_Query_Boolean();


$query->addSubquery($userQuery, true /* required */);
$query->addSubquery($pathQuery, true /* required */);

$hits = $index->find($query);

Zend_Search_Lucene_Search_QueryParser::parse() method also takes an optional


encoding parameter, which can specify query string encoding:

$userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr,
'iso-8859-5');

If the encoding parameter is omitted, then current locale is used.

It's also possible to specify the default query string encoding with
Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding() method:

Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('iso-8859-5');
...
$userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);

Zend_Search_Lucene_Search_QueryParser::getDefaultEncoding() returns the


current default query string encoding (the empty string means "current locale").

3.2. Search Results


The search result is an array of Zend_Search_Lucene_Search_QueryHit objects. Each of
these has two properties: $hit->id is a document number within the index and $hit->score
is a score of the hit in a search result. The results are ordered by score (descending from highest
score).

The Zend_Search_Lucene_Search_QueryHit object also exposes each field of the


Zend_Search_Lucene_Document found in the search as a property of the hit. In the following
example, a hit is returned with two fields from the corresponding document: title and author.

$index = Zend_Search_Lucene::open('/data/my_index');

$hits = $index->find($query);

foreach ($hits as $hit) {


echo $hit->score;
echo $hit->title;
echo $hit->author;
}

Stored fields are always returned in UTF-8 encoding.

Optionally, the original Zend_Search_Lucene_Document object can be returned from the


Zend_Search_Lucene_Search_QueryHit. You can retrieve stored parts of the document by
using the getDocument() method of the index object and then get them by getFieldValue()
method:

$index = Zend_Search_Lucene::open('/data/my_index');

$hits = $index->find($query);
foreach ($hits as $hit) {

1170
Zend_Search_Lucene

// return Zend_Search_Lucene_Document object for this hit


echo $document = $hit->getDocument();

// return a Zend_Search_Lucene_Field object


// from the Zend_Search_Lucene_Document
echo $document->getField('title');

// return the string value of the Zend_Search_Lucene_Field object


echo $document->getFieldValue('title');

// same as getFieldValue()
echo $document->title;
}

The fields available from the Zend_Search_Lucene_Document object are determined at the
time of indexing. The document fields are either indexed, or index and stored, in the document
by the indexing application (e.g. LuceneIndexCreation.jar).

Note that the document identity ('path' in our example) is also stored in the index and must be
retrieved from it.

3.3. Limiting the Result Set


The most computationally expensive part of searching is score calculation. It may take several
seconds for large result sets (tens of thousands of hits).

Zend_Search_Lucene gives the possibility to limit result set size with


getResultSetLimit() and setResultSetLimit() methods:

$currentResultSetLimit = Zend_Search_Lucene::getResultSetLimit();

Zend_Search_Lucene::setResultSetLimit($newLimit);

The default value of 0 means 'no limit'.


2
It doesn't give the 'best N' results, but only the 'first N' .

3.4. Results Scoring


Zend_Search_Lucene uses the same scoring algorithms as Java Lucene. All hits in the search
result are ordered by score by default. Hits with greater score come first, and documents having
higher scores should match the query more precisely than documents having lower scores.

Roughly speaking, search hits that contain the searched term or phrase more frequently will have
a higher score.

A hit's score can be retrieved by accessing the score property of the hit:

$hits = $index->find($query);

foreach ($hits as $hit) {


echo $hit->id;
echo $hit->score;
}

2
Returned hits are still ordered by score or by the specified order, if given.

1171
Zend_Search_Lucene

The Zend_Search_Lucene_Search_Similarity class is used to calculate the score for


each hit. See Extensibility. Scoring Algorithms section for details.

3.5. Search Result Sorting


By default, the search results are ordered by score. The programmer can change this behavior
by setting a sort field (or a list of fields), sort type and sort order parameters.

$index->find() call may take several optional parameters:

$index->find($query [, $sortField [, $sortType [, $sortOrder]]]


[, $sortField2 [, $sortType [, $sortOrder]]]
...);

A name of stored field by which to sort result should be passed as the $sortField parameter.

$sortType may be omitted or take the following enumerated values: SORT_REGULAR (compare
items normally- default value), SORT_NUMERIC (compare items numerically), SORT_STRING
(compare items as strings).

$sortOrder may be omitted or take the following enumerated values: SORT_ASC (sort in
ascending order- default value), SORT_DESC (sort in descending order).

Examples:

$index->find($query, 'quantity', SORT_NUMERIC, SORT_DESC);

$index->find($query, 'fname', SORT_STRING, 'lname', SORT_STRING);

$index->find($query, 'name', SORT_STRING, 'quantity', SORT_NUMERIC, SORT_DESC);

Please use caution when using a non-default search order; the query needs to retrieve
documents completely from an index, which may dramatically reduce search performance.

3.6. Search Results Highlighting


Zend_Search_Lucene provides two options for search results highlighting.

The first one is utilizing Zend_Search_Lucene_Document_Html class (see HTML documents


section for details) using the following methods:

/**
* Highlight text with specified color
*
* @param string|array $words
* @param string $colour
* @return string
*/
public function highlight($words, $colour = '#66ffff');

/**
* Highlight text using specified View helper or callback function.
*
* @param string|array $words Words to highlight. Words could be organized
using the array or string.

1172
Zend_Search_Lucene

* @param callback $callback Callback method, used to transform


(highlighting) text.
* @param array $params Array of additionall callback parameters passed
through into it (first non-optional parameter
is an HTML fragment for highlighting)
* @return string
* @throws Zend_Search_Lucene_Exception
*/
public function highlightExtended($words, $callback, $params = array())

To customize highlighting behavior use highlightExtended() method


3
with specified callback, which takes one or more parameters ,
or extend Zend_Search_Lucene_Document_Html class and redefine
applyColour($stringToHighlight, $colour) method used as a default highlighting
4
callback.

View helpers also can be used as callbacks in context of view script:

$doc->highlightExtended('word1 word2 word3...', array($this, 'myViewHelper'));

The result of highlighting operation is retrieved by Zend_Search_Lucene_Document_Html-


>getHTML() method.

Highlighting is performed in terms of current analyzer. So all forms of the word(s)


recognized by analyzer are highlighted.

E.g. if current analyzer is case insensitive and we request to highlight 'text' word,
then 'text', 'Text', 'TEXT' and other case combinations will be highlighted.

In the same way, if current analyzer supports stemming and we request to


highlight 'indexed', then 'index', 'indexing', 'indices' and other word forms will be
highlighted.

On the other hand, if word is skipped by current analyzer (e.g. if short words filter
is applied to the analyzer), then nothing will be highlighted.

The second option is to use Zend_Search_Lucene_Search_Query-


>highlightMatches(string $inputHTML[, $defaultEncoding = 'UTF-8'[,
Zend_Search_Lucene_Search_Highlighter_Interface $highlighter]]) method:

$query = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);
$highlightedHTML = $query->highlightMatches($sourceHTML);

Optional second parameter is a default HTML document encoding. It's used if encoding is not
specified using Content-type HTTP-EQUIV meta tag.

Optional third parameter is a highlighter object which has to implement


Zend_Search_Lucene_Search_Highlighter_Interface interface:

interface Zend_Search_Lucene_Search_Highlighter_Interface
{
3
The first is an HTML fragment for highlighting and others are callback behavior dependent. Returned value is a highlighted HTML
fragment.
4
In both cases returned HTML is automatically transformed into valid XHTML.

1173
Zend_Search_Lucene

/**
* Set document for highlighting.
*
* @param Zend_Search_Lucene_Document_Html $document
*/
public function setDocument(Zend_Search_Lucene_Document_Html $document);

/**
* Get document for highlighting.
*
* @return Zend_Search_Lucene_Document_Html $document
*/
public function getDocument();

/**
* Highlight specified words (method is invoked once per subquery)
*
* @param string|array $words Words to highlight. They could be
organized using the array or string.
*/
public function highlight($words);
}

Where Zend_Search_Lucene_Document_Html object is an object constructed


from the source HTML provided to the Zend_Search_Lucene_Search_Query-
>highlightMatches() method.

If $highlighter parameter is omitted, then


Zend_Search_Lucene_Search_Highlighter_Default object is instantiated and used.

Highlighter highlight() method is invoked once per subquery, so it has an ability to


differentiate highlighting for them.

Actually, default highlighter does this walking through predefined color table. So you can
implement your own highlighter or just extend the default and redefine color table.

Zend_Search_Lucene_Search_Query->htmlFragmentHighlightMatches() has
similar behavior. The only difference is that it takes as an input and returns HTML fragment
without <>HTML>, <HEAD>, <BODY> tags. Nevertheless, fragment is automatically transformed
to valid XHTML.

4. Langage de requêtes
Java Lucene et Zend_Search_Lucene fournissent des langages de requêtes plutôt puissants.

Ces langages sont pratiquement pareils, exceptées les quelques différences ci-dessous.

La syntaxe complète du langage de requêtes Java Lucene peut être trouvée ici.

4.1. Termes
Une requête est décomposée en termes et opérateurs. Il y a 3 types de termes : le termes
simples, les phrases et les sous-requêtes.

Un terme simple est un simple mot, tel que "test" ou "hello".

Une phrase est un groupe de mots inclus dans des double guillemets, tel que "hello dolly".

1174
Zend_Search_Lucene

Une sous-requête est une requête incluse dans des parenthèses, tel que "(hello dolly)".

De multiples termes peuvent être combinés ensemble avec des opérateurs booléens pour former
des requêtes complexes (voyez ci-dessous).

4.2. Champs
Lucene supporte les champs de données. Lorsque vous effectuez une recherche, vous pouvez
soit spécifier un champ, soit utiliser le champ par défaut. Le nom du champ dépend des données
indexées et le champ par défaut est défini par les paramètres courants.

La première différence et la plus significative avec Java Lucene est que par défaut les termes
sont cherchés dans tous les champs.

Il y a deux méthodes statiques dans la classe Zend_Search_Lucene qui permettent au


développeur de configurer ces paramètres :

$defaultSearchField = Zend_Search_Lucene::getDefaultSearchField();
...
Zend_Search_Lucene::setDefaultSearchField('contents');

La valeur NULL indique que la recherche est effectuée dans tous les champs. C'est le
paramétrage par défaut

Vous pouvez chercher dans des champs spécifiques en tapant le nom du champ suivi de ":",
suivi du terme que vous cherchez.

Par exemple, prenons un index Lucene contenant deux champs -title et text- avec text comme
champ par défaut. Si vous voulez trouver le document ayant pour titre "The Right Way" qui
contient le text "don't go this way", vous pouvez entrer :

title:"The Right Way" AND text:go

or

title:"Do it right" AND go

"text" étant le champ par défaut, l'indicateur de champ n'est pas requis.

Note: Le champ n'est valable que pour le terme, la phrase ou la sous-requête qu'il précède
directement, ainsi la requête

title:Do it right

ne trouvera que "Do" dans le champ 'title'. Elle trouvera "it" et "right" dans le champ par défaut
(si le champ par défaut est défini) ou dans tous les champs indexés (si le champ par défaut est
défini à NULL).

4.3. Jokers (Wildcards)


Lucene supporte les recherches avec joker sur un ou plusieurs caractères au sein des termes
simples (mais pas dans les phrases).

Pour effectuez une recherche avec joker sur un seul caractère, utilisez le symbole "?".

1175
Zend_Search_Lucene

Pour effectuez une recherche avec joker sur plusieurs caractères, utilisez le symbole "*".

La recherche avec un joker sur un seul caractère va faire correspondre le terme avec le "?"
remplacé par n'importe quel autre caractère unique. Par exemple, pour trouver "text" ou "test"
vous pouvez utiliser la recherche :

te?t

Multiple character wildcard searches look for 0 or more characters when matching strings against
terms. For example, to search for test, tests or tester, you can use the search:

test*

You can use "?", "*" or both at any place of the term:

*wr?t*

It searches for "write", "wrote", "written", "rewrite", "rewrote" and so on.

Starting from ZF 1.7.7 wildcard patterns need some non-wildcard prefix. Default prefix length is
5
3 (like in Java Lucene). So "*", "te?t", "*wr?t*" terms will cause an exception .

It can be altered using


Zend_Search_Lucene_Search_Query_Wildcard::getMinPrefixLength() and
Zend_Search_Lucene_Search_Query_Wildcard::setMinPrefixLength() methods.

4.4. Term Modifiers


Lucene supports modifying query terms to provide a wide range of searching options.

"~" modifier can be used to specify proximity search for phrases or fuzzy search for individual
terms.

4.5. Range Searches


Range queries allow the developer or user to match documents whose field(s) values are
between the lower and upper bound specified by the range query. Range Queries can be
inclusive or exclusive of the upper and lower bounds. Sorting is performed lexicographically.

mod_date:[20020101 TO 20030101]

This will find documents whose mod_date fields have values between 20020101 and 20030101,
inclusive. Note that Range Queries are not reserved for date fields. You could also use range
queries with non-date fields:

title:{Aida TO Carmen}

This will find all documents whose titles would be sorted between Aida and Carmen, but not
including Aida and Carmen.

Inclusive range queries are denoted by square brackets. Exclusive range queries are denoted
by curly brackets.
5
Please note, that it's not a Zend_Search_Lucene_Search_QueryParserException, but a
Zend_Search_Lucene_Exception. It's thrown during query rewrite (execution) operation.

1176
Zend_Search_Lucene

If field is not specified then Zend_Search_Lucene searches for specified interval through all
fields by default.

{Aida TO Carmen}

4.6. Fuzzy Searches


Zend_Search_Lucene as well as Java Lucene supports fuzzy searches based on the
Levenshtein Distance, or Edit Distance algorithm. To do a fuzzy search use the tilde, "~", symbol
at the end of a Single word Term. For example to search for a term similar in spelling to "roam"
use the fuzzy search:

roam~

This search will find terms like foam and roams. Additional (optional) parameter can specify the
required similarity. The value is between 0 and 1, with a value closer to 1 only terms with a higher
similarity will be matched. For example:

roam~0.8

The default that is used if the parameter is not given is 0.5.

4.7. Matched terms limitation


Wildcard, range and fuzzy search queries may match too many terms. It may cause incredible
search performance downgrade.

So Zend_Search_Lucene sets a limit of matching terms per query (subquery). This limit
can be retrieved and set using Zend_Search_Lucene::getTermsPerQueryLimit()/
Zend_Search_Lucene::setTermsPerQueryLimit($limit) methods.

Default matched terms per query limit is 1024.

4.8. Proximity Searches


Lucene supports finding words from a phrase that are within a specified word distance in a string.
To do a proximity search use the tilde, "~", symbol at the end of the phrase. For example to search
for a "Zend" and "Framework" within 10 words of each other in a document use the search:

"Zend Framework"~10

4.9. Boosting a Term


Java Lucene and Zend_Search_Lucene provide the relevance level of matching documents
based on the terms found. To boost the relevance of a term use the caret, "^", symbol with a
boost factor (a number) at the end of the term you are searching. The higher the boost factor,
the more relevant the term will be.

Boosting allows you to control the relevance of a document by boosting individual terms. For
example, if you are searching for

PHP framework

and you want the term "PHP" to be more relevant boost it using the ^ symbol along with the boost
factor next to the term. You would type:

1177
Zend_Search_Lucene

PHP^4 framework

This will make documents with the term PHP appear more relevant. You can also boost phrase
terms and subqueries as in the example:

"PHP framework"^4 "Zend Framework"

By default, the boost factor is 1. Although the boost factor must be positive, it may be less than
1 (e.g. 0.2).

4.10. Boolean Operators


Boolean operators allow terms to be combined through logic operators. Lucene supports AND,
"+", OR, NOT and "-" as Boolean operators. Java Lucene requires boolean operators to be ALL
CAPS. Zend_Search_Lucene does not.

AND, OR, and NOT operators and "+", "-" defines two different styles to construct boolean
queries. Unlike Java Lucene, Zend_Search_Lucene doesn't allow these two styles to be mixed.

If the AND/OR/NOT style is used, then an AND or OR operator must be present between all
query terms. Each term may also be preceded by NOT operator. The AND operator has higher
precedence than the OR operator. This differs from Java Lucene behavior.

4.10.1. AND
The AND operator means that all terms in the "AND group" must match some part of the searched
field(s).

To search for documents that contain "PHP framework" and "Zend Framework" use the query:

"PHP framework" AND "Zend Framework"

4.10.2. OR
The OR operator divides the query into several optional terms.

To search for documents that contain "PHP framework" or "Zend Framework" use the query:

"PHP framework" OR "Zend Framework"

4.10.3. NOT
The NOT operator excludes documents that contain the term after NOT. But an "AND group"
which contains only terms with the NOT operator gives an empty result set instead of a full set
of indexed documents.

To search for documents that contain "PHP framework" but not "Zend Framework" use the query:

"PHP framework" AND NOT "Zend Framework"

4.10.4. &&, ||, and ! operators


&&, ||, and ! may be used instead of AND, OR, and NOT notation.

1178
Zend_Search_Lucene

4.10.5. +
The "+" or required operator stipulates that the term after the "+" symbol must match the
document.

To search for documents that must contain "Zend" and may contain "Framework" use the query:

+Zend Framework

4.10.6. -
The "-" or prohibit operator excludes documents that match the term after the "-" symbol.

To search for documents that contain "PHP framework" but not "Zend Framework" use the query:

"PHP framework" -"Zend Framework"

4.10.7. No Operator
If no operator is used, then the search behavior is defined by the "default boolean operator".

This is set to OR by default.

That implies each term is optional by default. It may or may not be present within document, but
documents with this term will receive a higher score.

To search for documents that requires "PHP framework" and may contain "Zend Framework"
use the query:

+"PHP framework" "Zend Framework"

The default boolean operator may be set or retrieved with the


Zend_Search_Lucene_Search_QueryParser::setDefaultOperator($operator)
and Zend_Search_Lucene_Search_QueryParser::getDefaultOperator() methods,
respectively.

These methods operate with the Zend_Search_Lucene_Search_QueryParser::B_AND


and Zend_Search_Lucene_Search_QueryParser::B_OR constants.

4.11. Grouping
Java Lucene and Zend_Search_Lucene support using parentheses to group clauses to form
sub queries. This can be useful if you want to control the precedence of boolean logic operators
for a query or mix different boolean query styles:

+(framework OR library) +php

Zend_Search_Lucene supports subqueries nested to any level.

4.12. Field Grouping


Lucene also supports using parentheses to group multiple clauses to a single field.

To search for a title that contains both the word "return" and the phrase "pink panther" use the
query:

1179
Zend_Search_Lucene

title:(+return +"pink panther")

4.13. Escaping Special Characters


Lucene supports escaping special characters that are used in query syntax. The current list of
special characters is:

+ - && || ! ( ) { } [ ] ^ " ~ * ? : \

+ and - inside single terms are automatically treated as common characters.

For other instances of these characters use the \ before each special character you'd like to
escape. For example to search for (1+1):2 use the query:

\(1\+1\)\:2

5. API de construction de requêtes


En plus du parsage automatique d'une requête en chaîne de caractères, il est également possible
de construire cette requête à l'aide de l'API de requête.

Les requêtes utilisateur peuvent être combinées avec les requêtes créées à travers l'API de
requêtes. Utilisez simplement le parseur de requêtes pour construire une requête à partir d'une
chaîne :

$query = Zend_Search_Lucene_Search_QueryParser::parse($queryString);

5.1. Les Exceptions du parseur de requêtes


Le parseur de requêtes peut générer deux types d'exceptions :

• Une Zend_Search_Lucene_Exception est levée si quelque-chose d'anormal se produit


dans le parseur même.

• Une Zend_Search_Lucene_Search_QueryParserException est levée s'il y a une


erreur dans la syntaxe de la requête.

C'est une bonne idée d'attraper les


Zend_Search_Lucene_Search_QueryParserExceptions et de les traiter de manière
appropriée :

try {
$query = Zend_Search_Lucene_Search_QueryParser::parse($queryString);
} catch (Zend_Search_Lucene_Search_QueryParserException $e) {
echo "Query syntax error: " . $e->getMessage() . "\n";
}

La même technique devrait être utilisée pour la méthode find() d'un objet
Zend_Search_Lucene.

Depuis la version 1.5, les exceptions de parsage de requête sont supprimées


par défaut. Si la requête ne respecte pas le langage de requêtes, elle
est "tokenizée" à l'aide de l'analyseur par défaut et tous les termes
"tokenizés" sont utilisés dans la recherche. Pour activer les exceptions, utilisez

1180
Zend_Search_Lucene

Zend_Search_Lucene_Search_QueryParser::dontSuppressQueryParsingExceptions().
Les méthodes
Zend_Search_Lucene_Search_QueryParser::suppressQueryParsingExceptions()
et
Zend_Search_Lucene_Search_QueryParser::queryParsingExceptionsSuppressed()
sont également destinées à gérer le comportement de gestion des exceptions.

5.2. Requête sur un terme


Les requêtes de termes peuvent être utilisées pour une recherche sur un seul terme.

Requête par chaîne de caractères:

word1

ou

Construction de la requête via l'API:

$term = new Zend_Search_Lucene_Index_Term('word1', 'field1');


$query = new Zend_Search_Lucene_Search_Query_Term($term);
$hits = $index->find($query);

L'argument field est optionnel. Zend_Search_Lucene cherche dans tous les champs indexés
si aucun champ n'a été spécifié :

// Recherche de 'word1' dans tous les champs indexés.


$term = new Zend_Search_Lucene_Index_Term('word1');
$query = new Zend_Search_Lucene_Search_Query_Term($term);
$hits = $index->find($query);

5.3. Requête multi-termes


Les requêtes multi-termes peuvent être utilisées pour chercher sur une collection de termes.

Chaque terme dans une collection peut être défini comme requis, interdit, ou aucun des deux.

• requis signifie que les documents ne correspondant pas au terme ne correspondront pas à
la requête;

• interdit signifie que les documents correspondant au terme ne correspondront pas à la requête;

• aucun des deux, dans ce cas les documents n'ont pas l'interdiction, ni l'obligation de
correspondre au terme. Cela dit, un document devra correspondre au moins à l'un des termes
pour correspondre à la requête.

Si des termes optionnels sont ajoutés à une requête possédant des termes requis, les deux
requêtes auront les mêmes résultats, mais les termes optionnels pourraient influer sur le score
des documents retournés.

Les deux méthodes de recherche peuvent être utilisées pour les requêtes multi-termes.

Requête par chaîne de caractères:

+word1 author:word2 -word3

1181
Zend_Search_Lucene

• '+' est utilisé pour définir un terme requis.

• '-' est utilisé pour définir un terme interdit.

• Le préfixe 'field:' est utilisé pour indiqué un champ sur lequel on veut chercher. S'il est omis,
la recherche se fera sur tous les champs.

or

Construction de la requête via l'API:

$query = new Zend_Search_Lucene_Search_Query_MultiTerm();


$query->addTerm(new Zend_Search_Lucene_Index_Term('word1'), true);
$query->addTerm(new Zend_Search_Lucene_Index_Term('word2', 'author'),
null);
$query->addTerm(new Zend_Search_Lucene_Index_Term('word3'), false);
$hits = $index->find($query);

Il est également possible de spécifier des listes de termes dans le contructeur de la requête
multi-termes :

$terms = array(new Zend_Search_Lucene_Index_Term('word1'),


new Zend_Search_Lucene_Index_Term('word2', 'author'),
new Zend_Search_Lucene_Index_Term('word3'));
$signs = array(true, null, false);
$query = new Zend_Search_Lucene_Search_Query_MultiTerm($terms, $signs);
$hits = $index->find($query);

Le tableau $signs contient des informations sur le type de chaque terme :

• TRUE est utilisé pour définir un terme requis.

• FALSE est utilisé pour définir un terme interdit.

• NULL est utilisé pour définir un terme qui n'est ni requis, ni interdit.

5.4. Requête booléene


Les requêtes booléenes permettent de construire une requête qui utilise d'autres requêtes et
des opérateurs booléens.

Chaque sous-requête dans une collection peut être définie comme requis, interdit, ou optionnel.

• requis signifie que les documents ne correspondant pas à la sous-requête ne correspondront


pas à la requête;

• interdit signifie que les documents correspondant à la sous-requête ne correspondront pas à


la requête;

• optionel, dans ce cas les documents n'ont pas l'interdiction, ni l'obligation de correspondre à la
sous-requête. Cela dit, un document devra correspondre au moins à l'une des sous-requêtes
pour correspondre à la requête.

Si des sous-requêtes optionnelles sont ajoutées à une requête possédant des sous-requêtes
requises, les deux requêtes auront les mêmes résultats, mais les sous-requêtes optionnelles
pourraient influer sur le score des documents retournés.

1182
Zend_Search_Lucene

Les deux méthodes de recherche peuvent être utilisées pour les requêtes booléenes.

Requête par chaîne de caractères:

+(word1 word2 word3) (author:word4 author:word5) -(word6)

• '+' est utilisé pour définir une sous-requêtes requise.

• '-' est utilisé pour définir une sous-requêtes interdite.

• Le préfixe 'field:' est utilisé pour indiqué un champ sur lequel on veut chercher. S'il est omis,
la recherche se fera sur tous les champs.

or

Construction de la requête via l'API:

$query = new Zend_Search_Lucene_Search_Query_Boolean();


$subquery1 = new Zend_Search_Lucene_Search_Query_MultiTerm();
$subquery1->addTerm(new Zend_Search_Lucene_Index_Term('word1'));
$subquery1->addTerm(new Zend_Search_Lucene_Index_Term('word2'));
$subquery1->addTerm(new Zend_Search_Lucene_Index_Term('word3'));
$subquery2 = new Zend_Search_Lucene_Search_Query_MultiTerm();
$subquery2->addTerm(new Zend_Search_Lucene_Index_Term('word4', 'author'));
$subquery2->addTerm(new Zend_Search_Lucene_Index_Term('word5', 'author'));
$term6 = new Zend_Search_Lucene_Index_Term('word6');
$subquery3 = new Zend_Search_Lucene_Search_Query_Term($term6);
$query->addSubquery($subquery1, true /* required */);
$query->addSubquery($subquery2, null /* optional */);
$query->addSubquery($subquery3, false /* prohibited */);
$hits = $index->find($query);

Il est également possible de spécifier des listes de sous-requêtes dans le constructeur d'une
requêtes booléene :

...
$subqueries = array($subquery1, $subquery2, $subquery3);
$signs = array(true, null, false);
$query = new Zend_Search_Lucene_Search_Query_Boolean($subqueries, $signs);
$hits = $index->find($query);

Le tableau $signs contient des informations sur le type de chaque sous-requête :

• TRUE est utilisé pour définir une sous-requête requise.

• FALSE est utilisé pour définir une sous-requête interdite.

• NULL est utilisé pour définir une sous-requête qui n'est ni requise, ni interdite.

Chaque requête qui utilise des opérateurs booléens peut être réécrite en utilisant les notations
de signes et construites à l'aide de l'API. Par exemple :

word1 AND (word2 AND word3 AND NOT word4) OR word5

est équivalent à

1183
Zend_Search_Lucene

(+(word1) +(+word2 +word3 -word4)) (word5)

5.5. Requête Joker (wildcard)


Les requêtes Joker peuvent être utilisées pour chercher des documents contenant des chaînes
de caractères qui correspondent aux modèles (pattern) spécifiés.

Le symbole '?' est utilisé comme un joker d'un seul caractère.

Le symbole '*' est utilisé comme un joker pour plusieurs caractères.

Requête par chaîne de caractères:

field1:test*

ou

Construction de la requête via l'API:

$pattern = new Zend_Search_Lucene_Index_Term('test*', 'field1');


$query = new Zend_Search_Lucene_Search_Query_Wildcard($pattern);
$hits = $index->find($query);

L'argument field est optionnel. Zend_Search_Lucene cherche dans tous les champs indexés
si aucun champ n'a été spécifié :

$pattern = new Zend_Search_Lucene_Index_Term('test*');


$query = new Zend_Search_Lucene_Search_Query_Wildcard($pattern);
$hits = $index->find($query);

5.6. Requête floue (fuzzy query)


Les requêtes floues peuvent être utilisées pour chercher des documents contenant des chaînes
de caractères qui correspondent à des termes similaires au terme cherché.

Requête par chaîne de caractères:

field1:test~

Cette requête va correspondre à des documents contenant 'test', 'text', 'best' ou d'autres mots
similaires.

ou

Construction de la requête via l'API:

$term = new Zend_Search_Lucene_Index_Term('test', 'field1');


$query = new Zend_Search_Lucene_Search_Query_Fuzzy($term);
$hits = $index->find($query);

Un indice de similarité (optional similarity) peut être spécifié après le signe "~".

Requête par chaîne de caractères:

1184
Zend_Search_Lucene

field1:test~0.4

ou

Construction de la requête via l'API:

$term = new Zend_Search_Lucene_Index_Term('test', 'field1');


$query = new Zend_Search_Lucene_Search_Query_Fuzzy($term, 0.4);
$hits = $index->find($query);

L'argument field est optionnel. Zend_Search_Lucene cherche dans tous les champs indexés
si aucun champ n'a été spécifié :

$term = new Zend_Search_Lucene_Index_Term('test');


$query = new Zend_Search_Lucene_Search_Query_Fuzzy($term);
$hits = $index->find($query);

5.7. Requête de phrase


Les requêtes de phrase peuvent être utilisées pour chercher une phrase dans des documents.

Les requêtes de phrase sont très flexible et permettent à l'utilisateur ou au développeur de


chercher des phrases exactes aussi bien que des phrases 'imprécises'.

Les phrases peuvent aussi contenir des trous ou des termes aux mêmes places; elles peuvent
être générées par l'analyseur dans différents buts. Par exemple, un terme peut être dupliqué
pour augmenter son poids, ou plusieurs synonymes peuvent être placés sur une seule et unique
position.

$query1 = new Zend_Search_Lucene_Search_Query_Phrase();


// Ajoute 'word1' à la position relative 0.
$query1->addTerm(new Zend_Search_Lucene_Index_Term('word1'));
// Ajoute 'word2' à la position relative 1.
$query1->addTerm(new Zend_Search_Lucene_Index_Term('word2'));
// Ajoute 'word3' à la position relative 3.
$query1->addTerm(new Zend_Search_Lucene_Index_Term('word3'), 3);
...
$query2 = new Zend_Search_Lucene_Search_Query_Phrase(
array('word1', 'word2', 'word3'), array(0,1,3));
...
// Requête sans trou.
$query3 = new Zend_Search_Lucene_Search_Query_Phrase(
array('word1', 'word2', 'word3'));
...
$query4 = new Zend_Search_Lucene_Search_Query_Phrase(
array('word1', 'word2'), array(0,1), 'annotation');

Une requête de phrase peut être construite en une seule étape à l'aide
du constructeur ou étape par étape avec des appels à la méthode
Zend_Search_Lucene_Search_Query_Phrase::addTerm().

Le constructeur de la classe Zend_Search_Lucene_Search_Query_Phrase prends trois


arguments optionnels :

Zend_Search_Lucene_Search_Query_Phrase(
[array $terms[, array $offsets[, string $field]]]

1185
Zend_Search_Lucene

);

Le paramètre $terms est un tableau de chaînes de caractères qui contient une collection de
termes pour une phrase. S'il est omis ou égal à NULL, une requête vide sera construite.

Le paramètre $offsets est un tableau d'entiers qui contient les positions des termes dans la
phrase. S'il est omis ou égale à NULL, les positions des termes seront implicitement séquentielles
sans trou.

Le paramètre $field est un chaîne de caractères qui indique le champ dans lequel chercher.
S'il est omis ou égal à NULL, la recherche se fera dans le champ par défaut.

Ainsi :

$query =
new Zend_Search_Lucene_Search_Query_Phrase(array('zend', 'framework'));

va chercher la phrase 'zend framework' dans tous les champs.

$query = new Zend_Search_Lucene_Search_Query_Phrase(


array('zend', 'download'), array(0, 2)
);

va chercher la phrase 'zend ????? download' et correspondra à 'zend platform download', 'zend
studio download', 'zend core download', 'zend framework download', etc.

$query = new Zend_Search_Lucene_Search_Query_Phrase(


array('zend', 'framework'), null, 'title'
);

va chercher la phrase 'zend framework' dans le champ 'title'.

La méthode Zend_Search_Lucene_Search_Query_Phrase::addTerm() prends deux


arguments, un Zend_Search_Lucene_Index_Term requis et une position optionnelle :

Zend_Search_Lucene_Search_Query_Phrase::addTerm(
Zend_Search_Lucene_Index_Term $term[, integer $position]
);

Le paramètre $term décrit le prochain terme dans la phrase. Il doit indiquer le même champ
que les termes précédents, sinon une exception sera levée.

Le paramètre $position indique la position du terme dans la phrase.

Ainsi :

$query = new Zend_Search_Lucene_Search_Query_Phrase();


$query->addTerm(new Zend_Search_Lucene_Index_Term('zend'));
$query->addTerm(new Zend_Search_Lucene_Index_Term('framework'));

va chercher la phrase 'zend framework'.

$query = new Zend_Search_Lucene_Search_Query_Phrase();


$query->addTerm(new Zend_Search_Lucene_Index_Term('zend'), 0);
$query->addTerm(new Zend_Search_Lucene_Index_Term('framework'), 2);

1186
Zend_Search_Lucene

va chercher la phrase 'zend ????? download' et correspondra à 'zend platform download', 'zend
studio download', 'zend core download', 'zend framework download', etc.

$query = new Zend_Search_Lucene_Search_Query_Phrase();


$query->addTerm(new Zend_Search_Lucene_Index_Term('zend', 'title'));
$query->addTerm(new Zend_Search_Lucene_Index_Term('framework', 'title'));

va chercher la phrase 'zend framework' dans le champ 'title'.

Le 'slop factor' établit le nombre d'autres mots autorisés entre les mots spécifiés dans la requête
de phrase. S'il est défini à zéro, la requête correspondante sera une recherche d'une phrase
exacte. Pour des valeurs supérieures à zéro, cela fonctionne comme les opérateurs WITHIN
ou NEAR.

Le 'slop factor' est en fait une distance d'édition, où les éditions consistent à déplacer les
termes dans la phrase recherchée. Par exemple, inverser l'ordre de deux mots requiert deux
déplacements (le premier déplacement positionne les mots l'un sur l'autre), donc pour permettre
le réarrangement de phrase, le 'slop factor' doit être d'au moins deux.

Les correspondances les plus exactes possèdent un meilleur score que celles ayant eu recours
au 'slop factor'; ainsi les résultats de recherche sont classés par exactitude. Le 'slop factor' est
à zéro par défaut, requérant des correspondances exactes.

Le 'slop factor' peut être assigné après la création de la requête :

// Requêtes sans trou.


$query =
new Zend_Search_Lucene_Search_Query_Phrase(array('word1', 'word2'));
// Search for 'word1 word2', 'word1 ... word2'
$query->setSlop(1);
$hits1 = $index->find($query);
// Recherche pour 'word1 word2', 'word1 ... word2',
// 'word1 ... ... word2', 'word2 word1'
$query->setSlop(2);
$hits2 = $index->find($query);

5.8. Requête d'intervalle


Les requêtes d'intervalle sont dédiées à la recherche de termes dans un intervalle spécifié.

Requête par chaîne de caractères:

mod_date:[20020101 TO 20030101]
title:{Aida TO Carmen}

ou

Construction de la requête via l'API:

$from = new Zend_Search_Lucene_Index_Term('20020101', 'mod_date');


$to = new Zend_Search_Lucene_Index_Term('20030101', 'mod_date');
$query = new Zend_Search_Lucene_Search_Query_Range(
$from, $to, true // inclusive
);
$hits = $index->find($query);

1187
Zend_Search_Lucene

L'argument field est optionnel. Zend_Search_Lucene cherche dans tous les champs indexés
si aucun champ n'a été spécifié :

$from = new Zend_Search_Lucene_Index_Term('Aida');


$to = new Zend_Search_Lucene_Index_Term('Carmen');
$query = new Zend_Search_Lucene_Search_Query_Range(
$from, $to, false // non-inclusive
);
$hits = $index->find($query);

L'une ou l'autre (mais pas les deux) des bornes peut être définie à NULL. Dans ce cas,
Zend_Search_Lucene cherche depuis le début ou jusqu'à la fin du dictionnaire pour le(s)
champs spécifié(s) :

// recherche pour ['20020101' TO ...]


$from = new Zend_Search_Lucene_Index_Term('20020101', 'mod_date');
$query = new Zend_Search_Lucene_Search_Query_Range(
$from, null, true // inclusive
);
$hits = $index->find($query);

6. Jeu de caractères
6.1. Support UTF-8 et caractères sur un octet
Zend_Search_Lucene utilise l'UTF-8 en interne. Les fichiers d'index stockent des données
Unicode dans le "format UTF-8 modifié" de Java. Zend_Search_Lucene supporte totalement
6
ce format, à une exception près.

L'encodage des caractères d'entrée peut être spécifié grâce à l'API de Zend_Search_Lucene.
Les données seront converties automatiquement en UTF-8.

6.2. Analyseur de texte par défaut


Cependant, l'analyseur de texte par défaut (aussi utilisé par l'analyseur de requête) utilise
ctype_alpha().

ctype_alpha() n'est pas compatible UTF-8, donc l'analyseur convertit le texte vers "ASCII//
TRANSLIT" avant l'indexation. Le même processus est utilisé de manière transparente lors du
7
requêtage.

L'analyseur par défaut isole les chiffres. Utilisez le parseur "Num" si vous voulez
que les chiffres soient considérés comme des mots.

6.3. Analyseurs de texte compatibles UTF-8


Zend_Search_Lucene contient aussi des analyseurs compatibles UTF-8 :
Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8,

6
Zend_Search_Lucene supporte seulement les caractères Basic Multilingual Plane (BMP) (de 0x0000 à 0xFFFF) et ne supporte pas
les "caractères supplémentaires" (caractères dont les codes sont supérieurs à 0xFFFF).

Java 2 représente ces caractères comme une paire de char (16-bit), le premier depuis l'échelle haute (0xD800-0xDBFF), le second pour
l'échelle basse (0xDC00-0xDFFF). Ils sont alors encodés comme des caractères UTF-8 standards sur six octets. La représentation
UTF-8 standard utilise elle 4 octets pour les caractères supplémentaires.
7
La conversion vers 'ASCII//TRANSLIT' peut dépendre de la locale courante ou de l'OS.

1188
Zend_Search_Lucene

Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num,
Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8_CaseInsensitive,
Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive.

N'importe quel analyseur peut être activé avec un code comme celui-ci:

Zend_Search_Lucene_Analysis_Analyzer::setDefault(
new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8());

Les analyseurs UTF-8 ont été améliorés dans Zend Framework 1.5. Les
anciennes versions considéraient les caractères non-ASCII comme des lettres.
Les nouveaux analyseurs sont quant à eux plus précis sur ce point.

Ceci pourrait vous obliger à reconstruire votre index afin que vos données et
vos requêtes de recherche soient au même format. Des résultats faux peuvent
apparaître sinon.

Tous ces analyseurs nécessitent que la libraire PCRE (Perl-compatible regular expressions) soit
compilée avec le support d'UTF-8. Ce support d'UTF-8 pour PCRE est activé par défaut dans les
sources des libraires PCRE livrées avec PHP, mais si vous avez utilisé des librairies partagées
pour la compilation de PHP, alors le support d'UTF-8 peut dépendre de l'OS.

Utilisez ce code pour vérifier si le support d'UTF-8 est assuré pour PCRE :

if (@preg_match('/\pL/u', 'a') == 1) {
echo "support UTF-8 pour PCRE activé.\n";
} else {
echo "support UTF-8 pour PCRE désactivé.\n";
}

Les analyseurs UTF-8 insensibles à la casse ont aussi besoin de l'extension mbstring pour être
activés.

Si vous voulez les analyseurs UTF-8 insensibles à la casse, mais que vous n'avez pas mbstring,
normalisez alors vos données avant de les indexer ainsi que vos requêtes avant vos recherches,
ceci en les tranformant en casse minuscule :

// Indexation
setlocale(LC_CTYPE, 'de_DE.iso-8859-1');

...

Zend_Search_Lucene_Analysis_Analyzer::setDefault(
new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8());

...

$doc = new Zend_Search_Lucene_Document();

$doc->addField(Zend_Search_Lucene_Field::UnStored(
'contents', strtolower($contents))
);

// champ titre (indexed, unstored)


$doc->addField(Zend_Search_Lucene_Field::UnStored(

1189
Zend_Search_Lucene

'title', strtolower($title))
);

// champ titre (unindexed, stored)


$doc->addField(Zend_Search_Lucene_Field::UnIndexed('_title', $title));

// Recherche
setlocale(LC_CTYPE, 'de_DE.iso-8859-1');

...

Zend_Search_Lucene_Analysis_Analyzer::setDefault(
new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8());

...

$hits = $index->find(strtolower($query));

7. Extensibilité
7.1. Analyse de texte
La classe Zend_Search_Lucene_Analysis_Analyzer est utilisé par l'indexeur afin de
transformer en segments les champs texte du document.

Les méthodes Zend_Search_Lucene_Analysis_Analyzer::getDefault() et


Zend_Search_Lucene_Analysis_Analyzer::setDefault() sont utilisées pour
récupérer et définir l'analyseur par défaut.

Vous pouvez assigner votre propre analyseur de texte ou choisir parmi un ensemble
d'analyseurs prédéfinis : Zend_Search_Lucene_Analysis_Analyzer_Common_Text
et Zend_Search_Lucene_Analysis_Analyzer_Common_Text_CaseInsensitive (par
défaut). Tout deux interprètent les segments comme des séquences de
lettres. Zend_Search_Lucene_Analysis_Analyzer_Common_Text_CaseInsensitive
convertit tous les segments en minuscule.

Pour changer d'analyseur :

Zend_Search_Lucene_Analysis_Analyzer::setDefault(
new Zend_Search_Lucene_Analysis_Analyzer_Common_Text());
...
$index->addDocument($doc);

La classe Zend_Search_Lucene_Analysis_Analyzer_Common a été conçu pour être


l'ancêtre de tous les analyseurs définis par l'utilisateur. L'utilisateur doit uniquement définir les
méthodes reset() et nextToken(), qui prennent leur chaîne de caractères depuis la propriété
$_input et retournent les segments un par un (une valeur NULL indique la fin du flux).

La méthode nextToken() doit appeler la méthode normalize() sur chacun des segments.
Ce qui vous permet d'utiliser des filtres de segments avec votre analyseur.

Voici l'exemple d'analyseur personnalisé, qui accepte des mots contenant des chiffres comme
terme :

1190
Zend_Search_Lucene

/**
Exemple 633. Analyseur de texte personnalisé
* Voici un analyseur de texte qui traite les mots contenant des chiffres comme
* un seul terme
*/
class My_Analyzer extends Zend_Search_Lucene_Analysis_Analyzer_Common
{
private $_position;
/**
* Remet à Zéro le flux de segments
*/
public function reset()
{
$this->_position = 0;
}
/**
* API du flux de segmentation
* Récupère le segment suivant
* Retourne null à la fin du flux
*
* @return Zend_Search_Lucene_Analysis_Token|null
*/
public function nextToken()
{
if ($this->_input === null) {
return null;
}
while ($this->_position < strlen($this->_input)) {
// Saute les espaces
while ($this->_position < strlen($this->_input) &&
!ctype_alnum( $this->_input[$this->_position] )) {
$this->_position++;
}
$termStartPosition = $this->_position;
// lit le segment
while ($this->_position < strlen($this->_input) &&
ctype_alnum( $this->_input[$this->_position] )) {
$this->_position++;
}
// Segment vide, fin de flux.
if ($this->_position == $termStartPosition) {
return null;
}
$token = new Zend_Search_Lucene_Analysis_Token(
substr($this->_input,
$termStartPosition,
$this->_position -
$termStartPosition),
$termStartPosition,
$this->_position);
$token = $this->normalize($token);
if ($token !== null) {
return $token;
}
// Continue si le segment est sauté
}
return null;
}
}
Zend_Search_Lucene_Analysis_Analyzer::setDefault(
new My_Analyzer());

1191
Zend_Search_Lucene

7.2. Filtrage des segments


L'analyseur Zend_Search_Lucene_Analysis_Analyzer_Common offre aussi un
mécanisme de filtrage des segments.

La classe Zend_Search_Lucene_Analysis_TokenFilter fournit une interface abstraites


pour ces filtres. Vos propres filtres devraient étendre cette classe directement ou indirectement.

Chaque filtre personnalisé doit implémenter la méthode normalize() qui devrait transformer
le segment en entrée ou signaler que le segment courant doit être sauté.

Il y a trois filtres déjà défini dans le sous-paquet d'analyse :

• Zend_Search_Lucene_Analysis_TokenFilter_LowerCase

• Zend_Search_Lucene_Analysis_TokenFilter_ShortWords

• Zend_Search_Lucene_Analysis_TokenFilter_StopWords

Le filtre LowerCase filtre est déjà utilisé par défaut par l'analyseur
Zend_Search_Lucene_Analysis_Analyzer_Common_Text_CaseInsensitive.

Les filtres ShortWords et StopWords peuvent être utilisés avec des analyseurs prédéfinis ou
personnalisés comme ceci :

$stopWords = array('a', 'an', 'at', 'the', 'and', 'or', 'is', 'am');


$stopWordsFilter =
new Zend_Search_Lucene_Analysis_TokenFilter_StopWords($stopWords);
$analyzer =
new Zend_Search_Lucene_Analysis_Analyzer_Common_TextNum_CaseInsensitive();
$analyzer->addFilter($stopWordsFilter);
Zend_Search_Lucene_Analysis_Analyzer::setDefault($analyzer);

$shortWordsFilter = new Zend_Search_Lucene_Analysis_TokenFilter_ShortWords();


$analyzer =
new Zend_Search_Lucene_Analysis_Analyzer_Common_TextNum_CaseInsensitive();
$analyzer->addFilter($shortWordsFilter);
Zend_Search_Lucene_Analysis_Analyzer::setDefault($analyzer);

Le constructeur Zend_Search_Lucene_Analysis_TokenFilter_StopWords prends un


tableau de stop-words en entrée. Mais les stop-words peuvent aussi être chargé à partir d'un
fichier :

$stopWordsFilter = new Zend_Search_Lucene_Analysis_TokenFilter_StopWords();


$stopWordsFilter->loadFromFile($my_stopwords_file);
$analyzer =
new Zend_Search_Lucene_Analysis_Analyzer_Common_TextNum_CaseInsensitive();
$analyzer->addFilter($stopWordsFilter);
Zend_Search_Lucene_Analysis_Analyzer::setDefault($analyzer);

Ce fichier doit être un simple fichier texte avec un mot par ligne. Le caractère '#' transforme la
ligne en commentaire.

Le constructeur de la classe
Zend_Search_Lucene_Analysis_TokenFilter_ShortWords a un argument optionnel. Il
s'agit de la longueur maximum de mot, elle est définie par défaut à 2.

1192
Zend_Search_Lucene

7.3. Algorithme de score


Le score d'un document d pour une requête q est défini comme suit :

score(q,d) = sum( tf(t in d) * idf(t) * getBoost(t.field in d) *


lengthNorm(t.field in d) ) * coord(q,d) * queryNorm(q)

tf(t in d) - Zend_Search_Lucene_Search_Similarity::tf($freq) - un facteur de score


basé sur la fréquence d'un terme ou d'une phrase dans un document.

idf(t) - Zend_Search_Lucene_Search_Similarity::idf($input, $reader) - un


facteur de score pour un terme simple de l'index spécifié.

getBoost(t.field in d) - le facteur d'impulsion pour le champ du terme.

lengthNorm($term) - la valeur de normalisation pour un champ donné du nombre total de terme


contenu dans un champ. Cette valeur est stockée dans l'index. Ces valeurs, ainsi que celle du
champ d'impulsion, sont stocké dans un index et multipliées par le score de hits par code de
recherche sur chaque champ.

La correspondance au sein de champs plus long est moins précise, ainsi l'implémentation de
cette méthode retourne généralement de plus petites valeurs quand numTokens est important,
et de plus grandes valeurs lorsque numTokens est petit.

coord(q,d) - Zend_Search_Lucene_Search_Similarity::coord($overlap,
$maxOverlap) - un facteur de score basé sur la fraction de tout les termes de la recherche
que le document contient.

La présence d'une grande partie des termes de la requête indique une meilleure correspondance
avec la requête, ainsi les implémentations de cette méthode retourne habituellement de plus
grandes valeurs lorsque le ration entre ces paramètres est grand que lorsque le ratio entre elle
est petit.

queryNorm(q) - la valeur de normalisation pour la requête en fonction de la somme des poids au


carré de chaque terme de la requête. Cette valeur est ensuite multipliée par le poids de chacun
des termes de la requête.

Ceci n'affecte pas le classement, mais tente plutôt de faire des scores à partir de différentes
requêtes comparables entre elles.

Les algorithmes de score peuvent être personnalisés en définissant


votre propre classe de similitude. Pour ce faire, étendez la classe
Zend_Search_Lucene_Search_Similarity comme défini ci-dessous, puis appelez la
méthode Zend_Search_Lucene_Search_Similarity::setDefault($similarity);
afin de la définir par défaut.

class MySimilarity extends Zend_Search_Lucene_Search_Similarity {


public function lengthNorm($fieldName, $numTerms) {
return 1.0/sqrt($numTerms);
}
public function queryNorm($sumOfSquaredWeights) {
return 1.0/sqrt($sumOfSquaredWeights);
}
public function tf($freq) {
return sqrt($freq);
}
/**
* Ceci n'est pas encore utilisé. Cela évalue le nombre de correspondance

1193
Zend_Search_Lucene

* d'expressions vagues, basé sur une distance d'édition.


*/
public function sloppyFreq($distance) {
return 1.0;
}
public function idfFreq($docFreq, $numDocs) {
return log($numDocs/(float)($docFreq+1)) + 1.0;
}
public function coord($overlap, $maxOverlap) {
return $overlap/(float)$maxOverlap;
}
}
$mySimilarity = new MySimilarity();
Zend_Search_Lucene_Search_Similarity::setDefault($mySimilarity);

7.4. Conteneur de stockage


La classe abstraite Zend_Search_Lucene_Storage_Directory définit la fonctionnalité de
répertoire.

Le constructeur Zend_Search_Lucene utilise soit une chaîne soit un objet


Zend_Search_Lucene_Storage_Directory en paramètre.

La classe Zend_Search_Lucene_Storage_Directory_Filesystem implémente la


fonctionnalité de répertoire pour un système de fichier.

Si une chaîne est utilisé comme paramètre du constructeur Zend_Search_Lucene, le lecteur


(Zend_Search_Lucene object) le considère comme un chemin dans le système de fichier et
instancie l'objet Zend_Search_Lucene_Storage_Directory_Filesystem.

Vous pouvez définir votre propre implémentation de répertoire en étendant la classe


Zend_Search_Lucene_Storage_Directory.

Les méthodes deZend_Search_Lucene_Storage_Directory :

abstract class Zend_Search_Lucene_Storage_Directory {


/**
* Ferme le stockage.
*
* @return void
*/
abstract function close();
/**
* Crée un nouveau fichier vide dans le répertoire dont le nom est $filename.
*
* @param string $name
* @return void
*/
abstract function createFile($filename);
/**
* Supprime un fichier existant du répertoire.
*
* @param string $filename
* @return void
*/
abstract function deleteFile($filename);
/**
* Retourne true si un fichier portant le nom donné existe.
*

1194
Zend_Search_Lucene

* @param string $filename


* @return boolean
*/
abstract function fileExists($filename);
/**
* Retourne la taille d'un $filename dans le répertoire.
*
* @param string $filename
* @return integer
*/
abstract function fileLength($filename);
/**
* Retourne le timestamp UNIX de la date de modification de $filename.
*
* @param string $filename
* @return integer
*/
abstract function fileModified($filename);
/**
* Renomme un fichier existant dans le répertoire.
*
* @param string $from
* @param string $to
* @return void
*/
abstract function renameFile($from, $to);
/**
* Définit la date de modification de $filename à la date de maintenant.
*
* @param string $filename
* @return void
*/
abstract function touchFile($filename);
/**
* Retourne un objet Zend_Search_Lucene_Storage_File object pour un $filename
* donné dans le répertoire
*
* @param string $filename
* @return Zend_Search_Lucene_Storage_File
*/
abstract function getFileObject($filename);
}

La méthode getFileObject($filename) de l'instance


Zend_Search_Lucene_Storage_Directory retourne un objet
Zend_Search_Lucene_Storage_File.

La classe abstraite Zend_Search_Lucene_Storage_File implémente l'abstraction de


fichiers et les primitives de lecture de fichier d'index.

Vous devez aussi étendre Zend_Search_Lucene_Storage_File dans votre implémentation


de répertoire.

Seulement deux méthodes de Zend_Search_Lucene_Storage_File doivent être


surchargées dans votre implémentation :

class MyFile extends Zend_Search_Lucene_Storage_File {


/**
* Définit l'indicateur de position du fichier and avance le pointeur

1195
Zend_Search_Lucene

* de fichier.
* La nouvelle position, calculé en octets depuis le début du fichier,
* est obtenu en ajoutant l'offset à la position spécifiée par $whence,
* dont les valeurs sont définit comme suit :
* SEEK_SET - Définit la position comme égale aux octets de l'offset.
* SEEK_CUR - Définit la position à la position courante plus l'offset.
* SEEK_END - Définit la position à la fin du fichier plus l'offset.
*(Pour déplacer à une position avant la fin du fichier, vous devrez passer
* une valeur négative à l'offset.)
* En cas de succès, retourne 0; sinon, retourne -1
*
* @param integer $offset
* @param integer $whence
* @return integer
*/
public function seek($offset, $whence=SEEK_SET) {
...
}
/**
* Lit $length octets dans le fichier et avance le pointeur de fichier.
*
* @param integer $length
* @return string
*/
protected function _fread($length=1) {
...
}
}

8. Agir avec Lucene Java


8.1. Formats de fichier
Les formats des fichiers d'index de Zend_Search_Lucene sont compatibles avec la version
de Lucene Java 1.4 ou plus.

Une description détaillée de ce format est disponible ici: http://lucene.apache.org/java/2_3_0/


8
fileformats.html .

8.2. Répertoire Index


Après la création de l'index, le répertoire d'index contiendra plusieurs fichiers:

• le fichier des segments est une liste des segments de l'index.

• Les fichiers *.cfs contiennent les segments de l'index. Notez qu'un index optimisé a toujours
un seul segment.

• Les fichiers effaçables sont des fichiers qui ne sont plus utilisés par l'index, mais qui n'ont
pas pu être supprimés.

8.3. Code source Java


Le programme Java ci-après montre comment indexer un fichier en utilisant Java Lucene :

/**
8
La version du format de fichier supporté actuellement est la 2.3 (depuis Zend Framework 1.6).

1196
Zend_Search_Lucene

* Index creation:
*/
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.document.*;

import java.io.*

...

IndexWriter indexWriter = new IndexWriter("/data/my_index",


new SimpleAnalyzer(), true);

...

String filename = "/path/to/file-to-index.txt"


File f = new File(filename);

Document doc = new Document();


doc.add(Field.Text("path", filename));
doc.add(Field.Keyword("modified",DateField.timeToString(f.lastModified())));
doc.add(Field.Text("author", "unknown"));
FileInputStream is = new FileInputStream(f);
Reader reader = new BufferedReader(new InputStreamReader(is));
doc.add(Field.Text("contents", reader));

indexWriter.addDocument(doc);

9. Avancé
9.1. Depuis Zend Framework 1.6, gestion des transformations de
format d'index
Zend_Search_Lucene fonctionne avec les index Lucene Java 1.4-1.9, 2.1 et 2.3.

Le format actuel de l'index peut être obtenu par $index->getFormatVersion(). Ceci


retourne une de ces valeurs :

• Zend_Search_Lucene::FORMAT_PRE_2_1 pour le format 1.4-1.9.

• Zend_Search_Lucene::FORMAT_2_1 pour le format 2.1 (utilisé aussi pour 2.2).

• Zend_Search_Lucene::FORMAT_2_3 pour le format 2.3.

Les modifications de l'index n'arrivent que si une mise à jour de l'index est faite. Ceci arrive
lorsqu'un nouveau document est ajouté à l'index, ou lors de l'optimisation manuelle de l'index
par $index->optimize().

Dans un tel cas, Zend_Search_Lucene peut convertir l'index vers une version plus haute. Ceci
arrive toujours pour le format Zend_Search_Lucene::FORMAT_PRE_2_1, alors transformé
en format 2.1.

Vous pouvez gérer ces conversions et notamment le format


d'arrivée avec $index->setFormatVersion(), qui prend comme paramètre
Zend_Search_Lucene::FORMAT_2_1 ou Zend_Search_Lucene::FORMAT_2_3 :

• Zend_Search_Lucene::FORMAT_2_1 ne fait rien puisque les format pre-2.1 sont convertis


vers ce format (2.1)

1197
Zend_Search_Lucene

• Zend_Search_Lucene::FORMAT_2_3 force la conversion vers le format 2.3.

Les conversions vers des versions antérieure de formats ne sont pas supportées.

Important!

Les formats ne peuvent pas être convertis vers des versions antérieures. Gardez
une copie de sauvegarde si ceci s'avère nécessaire, car après une conversion il
ne sera plus possible de faire marche arrière.

9.2. Utiliser les propriétés statiques de l'index


L'objet Zend_Search_Lucene utilise la méthode de destructeur pour valider ses changements
et faire ses optimisations et nettoyages.

Il stocke les documents ajoutés en mémoire et les vide dans un segment sur le disque en fonction
du paramètre MaxBufferedDocs.

Si la limite MaxBufferedDocs n'est pas atteinte, alors il y aura des documents non
sauvegardés qui seront sauvés comme nouveau segment lors de la destruction de l'objet. La
procédure d'optimisation automatique est lancée si nécessaire, cela dépend des paramètres
MaxBufferedDocs, MaxMergeDocs et MergeFactor.

Les propriétés statiques d'un objet sont détruites après la dernière ligne de code exécutée.

class Searcher {
private static $_index;

public static function initIndex() {


self::$_index = Zend_Search_Lucene::open('path/to/index');
}
}

Searcher::initIndex();

Aussi, le destructeur est correctement invoqué à ce point de l'exécution du programme.

Un problème potentiel peut être les exceptions. Celles envoyées dans un destructeur d'un objet
statique n'ont pas de contexte, car le destructeur est appelé après la fin d'exécution du script.

Vous pouvez alors voir une "Fatal error: Exception thrown without a stack frame in Unknown on
line 0" au lieu de l'exception décrivant réellement le contexte.

Zend_Search_Lucene propose alors un détournement de ce problème avec la méthode


commit(). Elle sauvegarde les changements et libère la mémoire utilisée pour stocker
les segments. Vous pouvez utiliser la méthode commit n'importe quand, même plusieurs
fois, pendant l'exécution de votre script. Vous pouvez aussi continuer à utiliser l'objet
Zend_Search_Lucene pour rechercher, ajouter ou supprimer des document, même après une
opération de commit (validation). L'appel à commit() est simplement une sécurité pour éviter
les problème d'exception dans le destructeur de Zend_Search_Lucene :

class Searcher {
private static $_index;

public static function initIndex() {

1198
Zend_Search_Lucene

self::$_index = Zend_Search_Lucene::open('path/to/index');
}

...

public static function commit() {


self::$_index->commit();
}
}

Searcher::initIndex();

...

// Script shutdown routine


...
Searcher::commit();
...

10. Bonnes pratiques


10.1. Nommage des champs
Il n'y a pas de limitation pour les noms de champs dans Zend_Search_Lucene.

Cependant, il est préférable de ne pas utiliser les noms 'id' et 'score' afin d'éviter toute ambiguïté
dans les propriétés de QueryHit.

Les propriétés id et score de Zend_Search_Lucene_Search_QueryHit font toujours


référence à l'identifiant interne du document Lucene et au score de hit. Si le document indexé
possède les mêmes champs stockés, vous devrez utiliser la méthode getDocument() pour
y accéder :

$hits = $index->find($query);

foreach ($hits as $hit) {


// Récupérer le champ de document 'title'
$title = $hit->title;

// Récupérer le champ de document 'contents'


$contents = $hit->contents;

// Récupérer l'id interne du document Lucene


$id = $hit->id;

// Récupérer le score de hit


$score = $hit->score;

// Récupérer le champ de document 'id'


$docId = $hit->getDocument()->id;

// Récupérer le champ de document 'score'


$docId = $hit->getDocument()->score;

// Un autre moyen de récupérer le champ 'title'


$title = $hit->getDocument()->title;
}

1199
Zend_Search_Lucene

10.2. Performance de l'indexation


La performance de l'indexation est un compromis entre les ressources utilisées, le temps
d'indexation et la qualité de l'index.

La qualité de l'index est complètement déterminée par le nombre de segments de l'index.

Chaque segment d'index et une portion de données entièrement indépendante. Ainsi plus un
index contient de segments, plus il sera gourmand en mémoire et en temps de calcul lors de
la recherche.

L'optimisation d'index est un processus consistant à fusionner plusieurs segments en un seul


nouveau segment. Un index totalement optimisé ne contient qu'un seul segment.

L'optimisation complète de l'index peut être effectuée avec la méthode optimize() :

$index = Zend_Search_Lucene::open($indexPath);

$index->optimize();

L'optimisation d'index fonctionne avec des "data streams" et ne consomme pas pas une grande
quantité de mémoire, mais nécessite des ressources de processeur et du temps.

Par nature, les segments d'index de Lucene ne peuvent pas être mis à jour (l'opération de mise à
jour nécessite une réécriture complète du segment). Ainsi, l'ajout de nouveau(x) document(s) à
un index implique toujours la génération d'un nouveau segment. De fait, cela dégrade la qualité
de l'index.

Une optimisation automatique d'un index est effectuée après chaque génération de segment et
consiste en la fusion des segments partiels.

Il y a trois options pour contrôler le comportement de l'auto-optimisation (voir la section


Optimisation d'index) :

• MaxBufferedDocs représente le nombre maximum de documents qui peuvent être mis en


mémoire tampon avant qu'un nouveau segment soit généré et écrit sur le disque dur.

• MaxMergeDocs représente le nombre maximum de documents qui seront fusionnés dans un


nouveau segment lors du processus d'auto-optimisation.

• MergeFactor détermine à quelle fréquence l'auto-optimisation est effectuée.

Toutes ces options sont des propriétés de la classe Zend_Search_Lucene,


pas des propriétés d'index. Elles n'affectent que les instances de
Zend_Search_Lucene et peuvent varier selon les scripts.

MaxBufferedDocs n'a aucun effet si vous n'indexez qu'un seul document par exécution de script.
En revanche, il est très important pour les indexations massives ("batch indexing"). Plus sa
valeur est élevée, meilleures seront les performances d'indexation, mais plus la consommation
de mémoire sera importante.

Il n'existe pas de manière simple de calculer la meilleure valeur pour le paramètre


MaxBufferedDocs car cela dépend de la taille moyenne des documents, de l'analyseur utilisé
et de la mémoire disponible.

1200
Zend_Search_Lucene

Une bonne méthode pour trouver une valeur correcte consiste à effectuer plusieurs tests avec
9
les documents les plus volumineux que vous vous attendez à voir figurer dans l'index. . Une
bonne pratique consiste à ne pas utiliser plus de la moitié de la mémoire allouée.

MaxMergeDocs limite la taille d'un segment (en termes de nombre de documents). De


ce fait, il limite également la durée de l'auto-optimisation en garantissant que la méthode
addDocument() ne sera pas exécutée plus d'un certain nombre de fois. C'est très important
dans le cadre d'applications interactives.

Diminuer la valeur du paramètre MaxMergeDocs peut aussi améliorer les performances lors de
l'indexation en masse ("batch indexing"). L'auto-optimisation est un processus itératif et utilise
une technique ascendante. Les petits segments sont fusionnés vers de plus gros segments qui
sont eux-mêmes fusionnés vers des segments encore plus gros, etc. L'optimisation complète
est achevée lorsqu'il ne reste qu'un seul gros segment.

De petits segments détériore généralement la qualité de l'index. Un grand nombre de petits


segments peut aussi déclencher l'erreur "Too many open files" déterminée par les limitations du
10
système d'exploitation .

En général, l'optimisation d'index en arrière-plan devrait être effectuée pour les modes
d'indexation interactifs et la valeur de MaxMergeDocs ne devrait pas être trop faible pour les
indexations de masse ("batch indexing").

MergeFactor affecte la fréquence d'auto-optimisation. De faibles valeurs augmenteront la


qualité des index non-optimisés. Des valeurs plus importantes amélioreront les performances
de l'indexation, mais également le nombre de segments fusionnés. Ce qui peut également
déclencher l'erreur "Too many open files".

MergeFactor groupe les segments d'index par leur taille :

1. Pas plus grand que MaxBufferedDocs.

2. Plus grand que MaxBufferedDocs, mais pas plus grand que MaxBufferedDocs*MergeFactor.

3. Plus grand que MaxBufferedDocs*MergeFactor, mais pas plus grand que


MaxBufferedDocs*MergeFactor*MergeFactor.

4. ...

Zend_Search_Lucene vérifie à chaque appel de addDocument() si la fusion de n'importe


quel segment pour déplacer le segment nouvellement créé dans le groupe suivant. Si c'est le
cas, la fusion est effectuée.

Ainsi, un index avec N groupes peut contenir MaxBufferedDocs + (N-1)*MergeFactor segments


(N-1)
et contient au moins MaxBufferedDocs*MergeFactor documents.

La formule ci-dessous donne une bonne approximation du nombre de segments dans un index :

Nombre de segments <= MaxBufferedDocs + MergeFactor*log MergeFactor (Nombre de


documents/MaxBufferedDocs)

MaxBufferedDocs est déterminé par la mémoire allouée. Cela permet pour le facteur de fusion
(MergeFactor) approprié d'avoir un nombre raisonnable de segments.
9
memory_get_usage() et memory_get_peak_usage() peuvent être utilisées pour contrôler l'utilisation de la mémoire.
10
Zend_Search_Lucene maintient chaque segment ouvert pour améliorer les performances de recherche.

1201
Zend_Search_Lucene

L'optimisation du paramètre MergeFactor est plus efficace pour les performances de l'indexation
de masse (batch indexing) que MaxMergeDocs. Mais cette méthode manque un peu de
finesse. Le mieux est d'utiliser l'estimation ci-dessus pour optimiser MergeFactor, puis de jouer
avec MaxMergeDocs pour obtenir les meilleures performances d'indexation de masse (batch
indexing).

10.3. Indexation à l'arrêt du programme


L'instance de Zend_Search_Lucene effectue quelques tâches à la sortie du programme si des
documents ont été ajoutés à l'index mais pas écrits dans un nouveau segment.

Elle peut également déclencher le processus d'auto-optimisation.

L'objet qui représente l'index est automatiquement fermé lorsque lui, ainsi que tous les objets de
résultats de requête qui lui sont associés, sont hors de portée du script principal.

Si l'objet d'index est stocké dans une variable globale, il ne sera fermé qu'à la fin de l'exécution
11
du script .

Le processus d'exception de PHP est également fermé à ce moment.

Cela n'empêche pas la fermeture normale du processus de l'index, mais cela peut empêcher un
diagnostic d'erreur précis si une erreur survient durant la fermeture.

Il y a deux moyens qui peuvent permettre d'éviter ce problème.

Le premier est de forcer l'index à sortir de la portée (du scope) :

$index = Zend_Search_Lucene::open($indexPath);

...

unset($index);

Le second est d'effectuer une opération de commit avant la fin du script exécution :

$index = Zend_Search_Lucene::open($indexPath);

$index->commit();

Cette possibilité est également décrite dans la section "Avancé - Utiliser les propriétés statiques
de l'index".

10.4. Récupération de documents par leur id unique


C'est une pratique commune de stocker un identifiant unique de document dans l'index. Par
exemple, une url, un chemin ou un identifiant tiré d'une base de données.

Zend_Search_Lucene fournit une méthode termDocs() pour récupérer des documents


contenant les termes spécifiés.

C'est plus efficace que d'utiliser la méthode find() :


11
Cela peut aussi se produire s'il y a une référence à l'index ou à l'un de ses résultats de recherche dans une structure de données
cyclique, car le ramasse-miettes de PHP ne récupère les objets avec des références cycliques qu'en fin d'exécution de script

1202
Zend_Search_Lucene

// Récupération de documents avec la méthode find()


// en utilisant une querystring
$query = $idFieldName . ':' . $docId;
$hits = $index->find($query);
foreach ($hits as $hit) {
$title = $hit->title;
$contents = $hit->contents;
...
}
...

// Récupération de documents avec la méthode find()


// en utilisant l'API de requête.
$term = new Zend_Search_Lucene_Index_Term($docId, $idFieldName);
$query = new Zend_Search_Lucene_Search_Query_Term($term);
$hits = $index->find($query);
foreach ($hits as $hit) {
$title = $hit->title;
$contents = $hit->contents;
...
}

...

// Récupération de documents avec la méthode termDocs()


$term = new Zend_Search_Lucene_Index_Term($docId, $idFieldName);
$docIds = $index->termDocs($term);
foreach ($docIds as $id) {
$doc = $index->getDocument($id);
$title = $doc->title;
$contents = $doc->contents;
...
}

10.5. Utilisation de la mémoire


Zend_Search_Lucene est un module relativement gourmand en mémoire.

Il utilise la mémoire pour mettre en cache certaines informations et optimiser la recherche, ainsi
que les performances de l'indexation.

La mémoire requise diffère selon les modes.


ème12
L'index du dictionnaire des termes est chargé durant la recherche. Il s'agit de chaque 128
terme du dictionnaire complet.

De fait, la consommation de mémoire augmente si vous avez un grand nombre de termes


uniques. Cela peut arriver si vous utilisez des phrases non "tokenizées" comme champ de
recherche ou que vous indexez un large volume d'informations non-textuelles.

Un index non-optimisé consiste en plusieurs segments. Cela augmente également l'utilisation de


mémoire. Les segments étant indépendants, chacun possède son propre dictionnaire de termes
et index de dictionnaire de termes. Si un index consiste en N segments, il risque, dans le pire
des cas, de multiplier par N la consommation de mémoire. Lancez l'optimisation de l'index en
fusionnant tous les segments afin d'éviter de telles consommations de mémoire.
12
Le format de fichier Lucene permet de configurer ce nombre, mais Zend_Search_Lucene n'expose pas cette possibilité dans
l'API. Cependant vous pouvez toujours configurer ce nombre si l'index est géré par une autre implémentation de Lucene.

1203
Zend_Search_Lucene

L'indexation utilise la même quantité de mémoire que la recherche, plus de la mémoire pour
mettre les documents en tampon. La quantité de mémoire peut être gérée par le paramètre
MaxBufferedDocs.

L'optimisation d'index (complète ou partielle) utilise un processus de type flux ("streaming") et


ne requiert pas une grosse quantité de mémoire.

10.6. Encodage
Zend_Search_Lucene travaille avec des chaînes en UTF-8 en interne. Ainsi toutes les chaînes
de caractères retournée par Zend_Search_Lucene sont encodées en UTF-8.

Vous ne devriez pas être concernés par l'encodage si vous travaillez avec des chaîne purement
ASCII, mais vous devez être prudent si ce n'est pas le cas.

Un mauvais encodage peut causer des notices (erreur) durant la conversation d'encodage, voire
la perte de données.

Zend_Search_Lucene offre un large éventail de possibilités d'encodage pour les documents


indexés et les requêtes analysées.

L'encodage peut être explicitement spécifié en passant un paramètre optionnel à la méthode de


création d'un champ :

$doc = new Zend_Search_Lucene_Document();


$doc->addField(Zend_Search_Lucene_Field::Text('title',
$title,
'iso-8859-1'));
$doc->addField(Zend_Search_Lucene_Field::UnStored('contents',
$contents,
'utf-8'));

C'est le meilleur moyen d'éviter toute ambiguïté dans les encodages utilisés.

Si le paramètre optionnel de l'encodage est omis, la locale courante est utilisée. La locale
courante peut contenir des données d'encodage en plus des spécification de langue :

setlocale(LC_ALL, 'fr_FR');
...

setlocale(LC_ALL, 'de_DE.iso-8859-1');
...

setlocale(LC_ALL, 'ru_RU.UTF-8');
...

La même approche est utilisée pour définir l'encodage des chaînes de requête.

Si l'encodage n'est pas spécifié, la locale courante est utilisée pour le déterminer.

L'encodage peut être passée comme paramètre optionnel si la requête est analysée
explicitement avant la recherche :

$query =
Zend_Search_Lucene_Search_QueryParser::parse($queryStr, 'iso-8859-5');
$hits = $index->find($query);
...

1204
Zend_Search_Lucene

L'encodage par défaut peut également être spécifié avec la méthode setDefaultEncoding()
:

Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('iso-8859-1');
$hits = $index->find($queryStr);
...
chaîne vide sous-entend "locale courante".

Si l'encodage correct est spécifié, il pourra être correctement interprété par l'analyseur. Le
comportement dépend de quel analyseur est utilisé. Consultez la section sur les Jeu de
caractères pour plus de détails.

10.7. Maintenance de l'index


Il devrait être clair que Zend_Search_Lucene comme toute autre implémentation de Lucene
ne comporte pas de "base de données".

Les index ne devrait pas être utilisés pour du stockage de données. Ils ne fournissent pas
de fonctionnalités de backup/restauration partiel, journalisation, logs, transactions et beaucoup
d'autres fonctionnalités assimilées aux systèmes de gestion de bases de données.

Cependant, Zend_Search_Lucene tente de garder ses index dans un état constant en tout
temps.

Le backup et la restauration d'un index devrait être effectué en copiant le contenu du répertoire
de l'index.

Si pour une raison quelconque, un index devait être corrompu, il devrait être restauré ou
complètement reconstruit.

C'est donc une bonne idée de faire des backups des gros index et de stocker les logs de
modifications pour pouvoir effectuer des restaurations manuelles et des opérations de "roll-
forward" si nécessaire. Cette pratique réduit considérablement le temps de restauration.

1205
Zend_Serializer
1. Introduction
Zend_Serializer utilise une interface basée sur des adaptateurs afin de générer des
représentations stockables de types php et inversement.

Exemple 634. Utiliser Zend_Serializer

Pour instancier un sérialiseur, vous devriez utiliser la méthode de fabrique d'adaptateurs:

$serializer = Zend_Serializer::factory('PhpSerialize');
// $serializer est instance de Zend_Serializer_Adapter_AdapterInterface,
// précisémment Zend_Serializer_Adapter_PhpSerialize

try {
$serialized = $serializer->serialize($data);
// $serialized est une chaine

$unserialized = $serializer->unserialize($serialized);
// ici $data == $unserialized
} catch (Zend_Serializer_Exception $e) {
echo $e;
}

La méhode serialize génère une chaine. Pour regénérer la donnée utilisez la méthode
unserialize.

Si une erreur survient à la sérialisation ou désérialisation, Zend_Serializer enverra une


Zend_Serializer_Exception.

Pour configurer l'adaptateur, vous pouvez passer un tableau ou un objet instance de


Zend_Config à la méthode factory ou aux méthode un-/serialize:

$serializer = Zend_Serializer::factory('Wddx', array(


'comment' => 'serialized by Zend_Serializer',
));

try {
$serialized = $serializer->serialize($data, array('comment' => 'change comment'));
$unserialized = $serializer->unserialize($serialized, array(/* options pour unserialize
} catch (Zend_Serializer_Exception $e) {
echo $e;
}

Les options passées à factory sont valides pour l'objet crée. Vous pouvez alors changer ces
options grâce à la méthode setOption(s). Pour changer des options pour un seul appel,
passez celles-ci en deuxième arguement des méthodes serialize ou unserialize.

1.1. Utiliser l'interface statique de Zend_Serializer


Vous pouvez enregistrer une adaptateur spécifique comme adaptateur par défaut à utiliser avec
Zend_Serializer. Par défaut, l'adaptateur enregistré est PhpSerialize mais vous pouvez
le changer au moyen de la méthode statique setDefaultAdapter().

1206
Zend_Serializer

Zend_Serializer::setDefaultAdapter('PhpSerialize', $options);
// ou
$serializer = Zend_Serializer::factory('PhpSerialize', $options);
Zend_Serializer::setDefaultAdapter($serializer);

try {
$serialized = Zend_Serializer::serialize($data, $options);
$unserialized = Zend_Serializer::unserialize($serialized, $options);
} catch (Zend_Serializer_Exception $e) {
echo $e;
}

2. Zend_Serializer_Adapter
Les adaptateurs Zend_Serializer servent à changer les méthodes de sérialisation
facilement.

Chaque adaptateurs possède ses propres atouts et inconvénients. Dans certains cas, certains
types PHP (objets) ne peuvent être représentés sous forme de chaines. Dans ce cas, ces types
seront convertis vers un type sérialisable (par exemple, les objets seront convertis en tableaux).
Ci ceci échoue, une exception Zend_Serializer_Exception sera alors envoyée.

Voici une liste des adaptateurs disponibles.

2.1. Zend_Serializer_Adapter_PhpSerialize
Cet adaptateur utilise les fonctions PHP un/serialize et constitue un bon choix d'adaptateur
par défaut.

Aucune option de configuration n'existe pour cet adaptateur.

2.2. Zend_Serializer_Adapter_Igbinary
Igbinary est un logiciel Open Source crée par Sulake Dynamoid Oy. C'est un remplaçant du
sérialiseur utiliser par PHP. Au lieu d'utiliser une représentation textuelle (couteuse en temps et
en poids), igbinary représente les structures de données PHP dans un format binaire compact.
Les gains sont importants lorsqu'un système de stockage comme memcache est utilisé pour les
données sérialisées.

L'extension PHP igbinary est requise pour l'utilisation de cet adaptateur.

Aucune option de configuration n'existe pour cet adaptateur.

2.3. Zend_Serializer_Adapter_Wddx
WDDX (Web Distributed Data eXchange) est à la fois un langage de programmation, une
plateforme et un mecanisme de transport de données entre différents environnements.

Cet adaptateur utilise simplement les fonctions PHP wddx_*(). Veuillez lire le manuel PHP afin
de vérifier la disponibilité et l'installation de ces fonctions.

Aussi, l'extension PHP SimpleXML est utilisée pour vérifier si une valeur NULL retournée par
wddx_unserialize() est basée sur une donnée sérialisée NULL ou au contraire des données
non valides

Les options disponibles sont:

1207
Zend_Serializer

Tableau 114. Options Zend_Serializer_Adapter_Wddx

Option Type de donnée Valeur par défaut Description


comment chaine Un commentaire qui
apparait dans l'en-tête
du paquet.

2.4. Zend_Serializer_Adapter_Json
L'adaptateur JSON acréer un pont vers Zend_Json et/ou ext/json (l'extension json de PHP).
Pour plus d'informations, lisez le manuel de Zend_Json.

Les options disponibles sont:

Tableau 115. Options Zend_Serializer_Adapter_Json

Option Type de donnée Valeur par défaut Description


cycleCheck booléen false Voyez Section 3.1,
« Objets JSON »
objectDecodeType Zend_Json::TYPE_* Zend_Json::TYPE_ARRAY
Voyez Section 3.1,
« Objets JSON »
enableJsonExprFinder booléen false Voyez Section 3.4,
« JSON Expressions »

2.5. Zend_Serializer_Adapter_Amf 0 et 3
Les adaptateurs AMF, Zend_Serializer_Adapter_Amf0 et
Zend_Serializer_Adapter_Amf3, sont un pont vers le sérialiseur du composant Zend_Amf.
Veuillez lire la documentation de Zend_Amf documentation pour plus d'informations.

Aucune option de configuration n'existe pour cet adaptateur.

2.6. Zend_Serializer_Adapter_PythonPickle
Cet adaptateur convertit des types PHP vers une chaine Python Pickle Grâce à lui, vous pouvez
lire en Python des données sérialisées de PHP et inversement.

Les options disponibles sont:

Tableau 116. Options Zend_Serializer_Adapter_PythonPickle

Option Type de donnée Valeur par défaut Description


protocol entier (0 | 1 | 2 | 3) 0 La version du
protocole Pickle pour
serialize

Le transtypage (PHP vers Python) se comporte comme suit:

Tableau 117. Le transtypage (PHP vers Python)

Type PHP Type Python


NULL None
booléen booléen

1208
Zend_Serializer

Type PHP Type Python


entier entier
flottant flottant
chaine chaine
tableau liste
tableau associatif dictionnaire
objet dictionnaire

Le transtypage (Python vers PHP) se comporte comme suit:

Tableau 118. Transtypage (Python vers PHP):

Type Python Type PHP


None NULL
booléen booléen
entier entier
long entier | flottant | chaine |
Zend_Serializer_Exception
flottant flottant
chaine chaine
octets chaine
chaine Unicode chaine UTF-8
list tableau
tuple tableau
dictionnaire tableau associatif
Tout autre type Zend_Serializer_Exception

2.7. Zend_Serializer_Adapter_PhpCode
Cet adaptateur génère une chaine représentant du code analysable par PHP via var_export().A
la désérialisation, les données seront exécutées par eval.

Aucune option de configuration n'existe pour cet adaptateur.

Désérialiser des objets


Les objets seront sérialisés en utilisant la méthode magique__set_state Si la
classe ne propose pas cette méthode, une erreur fatale aboutira.

Utilisation de eval()
L'adaptateur PhpCode utilise eval() pour désérialiser. Ceci mène à des
problèmes de performance et de sécurité, un nouveau processus sera crée.
Typiquement, vous devriez utiliser l'adaptateur PhpSerialize à moins que
vous ne vouliez que les données sérialisées ne soient analysables à l'oeil
humain.

1209
Zend_Server
1. Introduction
La famille de classes Zend_Server fournit des fonctionnalités pour les différentes classes
serveur, notamment Zend_XmlRpc_Server, Zend_Rest_Server, Zend_Json_Server et
Zend_Soap_Wsdl. Zend_Server_Interface fournit une interface qui imite la classe
SoapServer de PHP5; toutes les classes serveur devraient implémenter cette interface de
manière à fournir une API serveur standard.

L'arbre Zend_Server_Reflection fournit un mécanisme standard permettant de réaliser


l'introspection de fonctions et de classes afin de s'en servir comme callback avec les
classes serveur, et fournit des données appropriées pour les méthodes getFunctions() et
loadFunctions() de Zend_Server_Interface.

2. Zend_Server_Reflection
2.1. Introduction
Zend_Server_Reflection fournit un mécanisme standard pour exécuter l'introspection de
fonction et de classe pour utiliser avec des classes serveur. Il est basé sur l'API de réflexion de
PHP 5, et l'améliore pour fournir des méthodes de recherche des types et des descriptions de
paramètre et de valeur de retour, une liste complète des prototypes de fonction et de méthode
(c.-à-d., toutes les combinaisons d'appels valides possibles), et des descriptions de fonction/
méthode.

Typiquement, cette fonctionnalité sera seulement utilisée par les développeurs des classes
serveur pour le framework.

2.2. Utilisation
L'utilisation de base est simple :

$class = Zend_Server_Reflection::reflectClass('Ma_Classe');
$function = Zend_Server_Reflection::reflectFunction('ma_fonction');

// Récupère les prototypes


$prototypes = $reflection->getPrototypes();

// Parcoure chaque prototype pour une fonction


foreach ($prototypes as $prototype) {

// Récupère les prototypes des types de retour


echo "Return type: ", $prototype->getReturnType(), "\n";

// Récupère les paramètres


$parameters = $prototype->getParameters();

echo "Paramètres: \n";


foreach ($parameters as $parameter) {
// Récupère le type d'un paramètre
echo " ", $parameter->getType(), "\n";
}

1210
Zend_Server

// Récupère l'espace de noms d'une classe, d'une fonction, ou d'une méthode.


// Les espaces de noms peuvent être définis au moment de l'instanciation
// (deuxième argument), ou en utilisant setNamespace()
$reflection->getNamespace();

reflectFunction() retourne un objet Zend_Server_Reflection_Function.


reflectClass retourne un objet Zend_Server_Reflection_Class. Veuillez vous référer
à la documentation d'API pour voir quelles méthodes sont disponibles pour chacun.

1211
Zend_Service
1. Introduction
Zend_Service est une classe abstraite qui sert de fondation à l'implémentation des services
Web, comme SOAP ou REST.

Zend_Service offre un support pour tout service Web basé sur REST à travers
Zend_Rest_Client.

En plus d'être capable d'étendre Zend_Service et d'utiliser Zend_Rest_Client pour des


services Web basé sur REST, Zend Framework fournit un support pour les services Web
populaires. Consultez les sections suivantes pour des informations spécifiques à chaque service
Web supporté.

• Akismet

• Amazon

• Audioscrobbler

• Del.icio.us

• Flickr

• Simpy

• SlideShare

• StrikeIron

• Yahoo!

D'autres services devraient être ajoutés prochainement.

2. Zend_Service_Akismet
2.1. Introduction
Zend_Service_Akismet provides a client for the Akismet API. The Akismet service is used to
determine if incoming data is potentially spam. It also exposes methods for submitting data as
known spam or as false positives (ham). It was originally intended to help categorize and identify
spam for Wordpress, but it can be used for any type of data.

Akismet requires an API key for usage. You can get one by signing up for a WordPress.com
account. You do not need to activate a blog. Simply acquiring the account will provide you with
the API key.

Akismet requires that all requests contain a URL to the resource for which data is being filtered.
Because of Akismet's origins in WordPress, this resource is called the blog URL. This value
should be passed as the second argument to the constructor, but may be reset at any time using
the setBlogUrl() method, or overridden by specifying a 'blog' key in the various method calls.

1212
Zend_Service

2.2. Verify an API key


Zend_Service_Akismet::verifyKey($key) is used to verify that an Akismet API key is
valid. In most cases, you will not need to check, but if you need a sanity check, or to determine
if a newly acquired key is active, you may do so with this method.

// Instantiate with the API key and a URL to the application or


// resource being used
$akismet = new Zend_Service_Akismet($apiKey,
'http://framework.zend.com/wiki/');
if ($akismet->verifyKey($apiKey) {
echo "Key is valid.\n";
} else {
echo "Key is not valid\n";
}

If called with no arguments, verifyKey() uses the API key provided to the constructor.

verifyKey() implements Akismet's verify-key REST method.

2.3. Check for spam


Zend_Service_Akismet::isSpam($data) is used to determine if the data provided is
considered spam by Akismet. It accepts an associative array as the sole argument. That array
requires the following keys be set:

• user_ip, the IP address of the user submitting the data (not your IP address, but that of a
user on your site).

• user_agent, the reported UserAgent string (browser and version) of the user submitting the
data.

The following keys are also recognized specifically by the API:

• blog, the fully qualified URL to the resource or application. If not specified, the URL provided
to the constructor will be used.

• referrer, the content of the HTTP_REFERER header at the time of submission. (Note
spelling; it does not follow the header name.)

• permalink, the permalink location, if any, of the entry the data was submitted to.

• comment_type, the type of data provided. Values specified in the API include 'comment',
'trackback', 'pingback', and an empty string (''), but it may be any value.

• comment_author, the name of the person submitting the data.

• comment_author_email, the email of the person submitting the data.

• comment_author_url, the URL or home page of the person submitting the data.

• comment_content, the actual data content submitted.

You may also submit any other environmental variables you feel might be a factor in determining
if data is spam. Akismet suggests the contents of the entire $_SERVER array.

1213
Zend_Service

The isSpam() method will return either TRUE or FALSE, or throw an exception if the API key
is invalid.

Exemple 635. isSpam() Usage

$data = array(
'user_ip' => '111.222.111.222',
'user_agent' => 'Mozilla/5.0 ' . (Windows; U; Windows NT ' .
'5.2; en-GB; rv:1.8.1) Gecko/20061010 ' .
'Firefox/2.0',
'comment_type' => 'contact',
'comment_author' => 'John Doe',
'comment_author_email' => 'nospam@myhaus.net',
'comment_content' => "I'm not a spammer, honest!"
);
if ($akismet->isSpam($data)) {
echo "Sorry, but we think you're a spammer.";
} else {
echo "Welcome to our site!";
}

isSpam() implements the comment-check Akismet API method.

2.4. Submitting known spam


Spam data will occasionally get through the filter. If you discover spam that you feel should have
been caught, you can submit it to Akismet to help improve their filter.

Zend_Service_Akismet::submitSpam() takes the same data array as passed to


isSpam(), but does not return a value. An exception will be raised if the API key used is invalid.

Exemple 636. submitSpam() Usage

$data = array(
'user_ip' => '111.222.111.222',
'user_agent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.2;' .
'en-GB; rv:1.8.1) Gecko/20061010 Firefox/2.0',
'comment_type' => 'contact',
'comment_author' => 'John Doe',
'comment_author_email' => 'nospam@myhaus.net',
'comment_content' => "I'm not a spammer, honest!"
);
$akismet->submitSpam($data));

submitSpam() implements the submit-spam Akismet API method.

2.5. Submitting false positives (ham)


Data will occasionally be trapped erroneously as spam by Akismet. For this reason, you should
probably keep a log of all data trapped as spam by Akismet and review it periodically. If you
find such occurrences, you can submit the data to Akismet as "ham", or a false positive (ham
is good, spam is not).

Zend_Service_Akismet::submitHam() takes the same data array as passed to isSpam()


or submitSpam(), and, like submitSpam(), does not return a value. An exception will be
raised if the API key used is invalid.

1214
Zend_Service

Exemple 637. submitHam() Usage

$data = array(
'user_ip' => '111.222.111.222',
'user_agent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.2;' .
'en-GB; rv:1.8.1) Gecko/20061010 Firefox/2.0',
'comment_type' => 'contact',
'comment_author' => 'John Doe',
'comment_author_email' => 'nospam@myhaus.net',
'comment_content' => "I'm not a spammer, honest!"
);
$akismet->submitHam($data));

submitHam() implements the submit-ham Akismet API method.

2.6. Zend-specific Methods


While the Akismet API only specifies four methods, Zend_Service_Akismet has several
additional methods that may be used for retrieving and modifying internal properties.

• getBlogUrl() and setBlogUrl() allow you to retrieve and modify the blog URL used in
requests.

• getApiKey() and setApiKey() allow you to retrieve and modify the API key used in
requests.

• getCharset() and setCharset() allow you to retrieve and modify the character set used
to make the request.

• getPort() and setPort() allow you to retrieve and modify the TCP port used to make the
request.

• getUserAgent() and setUserAgent() allow you to retrieve and modify the HTTP user
agent used to make the request. Note: this is not the user_agent used in data submitted to the
service, but rather the value provided in the HTTP User-Agent header when making a request
to the service.

The value used to set the user agent should be of the form some user agent/
version | Akismet/version. The default is Zend Framework/ZF-VERSION |
Akismet/1.11, where ZF-VERSION is the current Zend Framework version as stored in the
Zend_Framework::VERSION constant.

3. Zend_Service_Amazon
3.1. Introduction
Zend_Service_Amazon est une API simple pour utiliser les Web services d'Amazon.
Zend_Service_Amazon a deux APIs : une plutôt traditionnelle qui suit la propre API d'Amazon,
et un "Query API" simplifiée pour construire facilement des requêtes de recherche, même
compliquées.

Zend_Service_Amazon permet aux développeurs de récupérer des informations disponible


sur le site Amazon.com directement à travers l'API Amazon Web Services. Les exemples
incluent :

• Le stockage de données informatives, comme des images, des descriptions, le prix et plus

1215
Zend_Service

• Revues éditoriales et commerciales

• Des produits et accessoires similaires

• Les offres Amazon.com

• Les listes ListMania

Pour pouvoir utiliser Zend_Service_Amazon, vous devez avant tout avoir une clé "developer
API" Amazon ainsi que votre clé secrète. Pour obtenir une telle clé et pour plus d'informations,
vous pouvez visitez le site Web Amazon Web Services. A partir du 15 août 2009, vous ne pourrez
utiliser l'API Amazon à travers Zend_Service_Amazon, quand spécifiant la clé secrète.

Attention
Votre clé "developer API" et votre clé secret sont liées à votre identité Amazon,
donc faites en sorte de les conserver privées.

Exemple 638. Recherche sur Amazon en utilisant l'API traditionnelle

Dans cet exemple, nous recherchons les livres sur PHP disponibles chez Amazon et boucler
sur les résultats pour les afficher.

$amazon = new Zend_Service_Amazon('AMAZON_API_KEY', 'US', 'AMAZON_SECRET_KEY');


$response = $amazon->itemSearch(array('SearchIndex' => 'Books',
'Keywords' => 'php'));
$results = $amazon->itemSearch(array('SearchIndex' => 'Books',
'Keywords' => 'php'));
foreach ($results as $result) {
echo $result->Title . '<br />';
}

Exemple 639. Recherche sur Amazon en utilisant l'API de requête

Ici nous cherchons aussi les livres sur PHP disponibles chez Amazon, mais en utilisant l'API
de requête, qui ressemble au modèle de conception Interface Fluide.

$query = new Zend_Service_Amazon_Query('AMAZON_API_KEY',


'US',
'AMAZON_SECRET_KEY');
$query->category('Books')->Keywords('PHP');
$results = $query->search();
foreach ($results as $result) {
echo $result->Title . '<br />';
}

3.2. Codes de pays


Par défaut, Zend_Service_Amazon se connecte au Web service Amazon américain ("US").
Pour se connecter depuis un pays différent, il vous suffit simplement de définir, comme second
paramètre du constructeur, la chaîne de caractère correspondant au code du pays :

Exemple 640. Choisir un service Web Amazon d'un pays

// Connexion à Amazon France


$amazon = new Zend_Service_Amazon('AMAZON_API_KEY', 'FR', 'AMAZON_SECRET_KEY');

1216
Zend_Service

Codes de pays

Les codes de pays valides sont CA, DE, FR, JP, UK, et US.

3.3. Rechercher un produit Amazon spécifique avec son ASIN


La méthode itemLookup() fournit la possibilité de rechercher un produit Amazon particulier
lorsque son ASIN est connu.

Exemple 641. Rechercher une produit Amazon spécifique avec son ASIN

$amazon = new Zend_Service_Amazon('AMAZON_API_KEY', 'US', 'AMAZON_SECRET_KEY');


$item = $amazon->itemLookup('B0000A432X');

La méthode itemLookup() accepte aussi un second paramètre optionnel pour gérer les
options de recherche. Pour les détails complets et une liste des options disponibles, visitez la
documentation Amazon correspondante. .

Information sur les images

Pour récupérer les informations d'images pour vos résultats de recherche, vous
devez définir l'option ResponseGroup à Medium ou Large.

3.4. Lancer des recherches de produits sur Amazon


Rechercher des produits basés sur tous les divers critères disponibles sont rendus simples grâce
à la méthode itemSearch(), comme le montre l'exemple suivant :

Exemple 642. Lancer des recherches de produits sur Amazon

$amazon = new Zend_Service_Amazon('AMAZON_API_KEY', 'US', 'AMAZON_SECRET_KEY');


$results = $amazon->itemSearch(array('SearchIndex' => 'Books',
'Keywords' => 'php'));
foreach ($results as $result) {
echo $result->Title . '<br />';
}

Exemple 643. Utilisation de l'option ResponseGroup

L'option ResponseGroup est utilisée pour contrôler les informations spécifiques qui sont
retournées dans la réponse.

$amazon = new Zend_Service_Amazon('AMAZON_API_KEY', 'US', 'AMAZON_SECRET_KEY');


$results = $amazon->itemSearch(array(
'SearchIndex' => 'Books',
'Keywords' => 'php',
'ResponseGroup' => 'Small,ItemAttributes,Images,'
. 'SalesRank,Reviews,EditorialReview,'
. 'Similarities,ListmaniaLists'
));
foreach ($results as $result) {
echo $result->Title . '<br />';
}

1217
Zend_Service

La méthode itemSearch() accepte un seul tableau en paramètre pour gérer les options de
recherche. Pour plus de détails et une liste des options disponibles, visitez la documentation
Amazon correspondante

La classe Zend_Service_Amazon_Query est une enveloppe simple


d'utilisation de cette méthode.

3.5. Utiliser l'API alternative de requêtes


3.5.1. Introduction
Zend_Service_Amazon_Query fournit une API alternative pour utiliser le service Web
Amazon. L'API alternative utilise le modèle de conception 'Interface Fluide'. C'est à dire que les
appels peuvent-être fait en utilisant une chaîne d'appels de méthodes (ie $obj->method()-
>method2($arg))

L'API Zend_Service_Amazon_Query utilise la surcharge pour mettre en place facilement une


recherche d'article, et ainsi vous permettre de chercher en se basant sur les critères spécifiés.
Chacune de ces options est fournie en tant qu'appel de méthode, et chaque paramètre de
méthode correspond à la valeur des options nommées.

Exemple 644. Rechercher sur Amazon en utilisant l'API alternative de requêtes

Dans cet exemple, l'API de requêtes alternative est utilisée comme une interface fluide pour
spécifier les options et leurs valeurs respectives :

$query = new Zend_Service_Amazon_Query('MY_API_KEY', 'US', 'AMAZON_SECRET_KEY');


$query->Category('Books')->Keywords('PHP');
$results = $query->search();
foreach ($results as $result) {
echo $result->Title . '<br />';
}

Cela définit l'option Category à "Livres" et Keywords à "PHP".

Pour plus d'information sur les options disponibles, vous pouvez vous référer à la
documentation spécifique.

3.6. Classes Zend_Service_Amazon


Les classes suivantes sont toutes retournées par Zend_Service_Amazon::itemLookup()
et Zend_Service_Amazon::itemSearch():

• Zend_Service_Amazon_Item

• Zend_Service_Amazon_Image

• Zend_Service_Amazon_ResultSet

• Zend_Service_Amazon_OfferSet

• Zend_Service_Amazon_Offer

• Zend_Service_Amazon_SimilarProduct

• Zend_Service_Amazon_Accessories

1218
Zend_Service

• Zend_Service_Amazon_CustomerReview

• Zend_Service_Amazon_EditorialReview

• Zend_Service_Amazon_ListMania

3.6.1. Zend_Service_Amazon_Item
Zend_Service_Amazon_Item est le type de classe utilisé pour représenter un produit Amazon
retourné par le service Web. Elle récupère tous les attributs des articles, incluant le titre, la
description, les revues, etc.

3.6.1.1. Zend_Service_Amazon_Item::asXML()

string asXML();

Retourne le XML original de l'article

3.6.1.2. Propriétés

Zend_Service_Amazon_Item a un nombre de propriétés directement relié à leur contre-


parties de l'API standard Amazon.

Tableau 119. Propriétés de Zend_Service_Amazon_Item

Nom Type Description


ASIN string Amazon Item ID
DetailPageURL string URL pour la page de détail des
articles
SalesRank int Niveau de vente pour cet
article
SmallImage Zend_Service_Amazon_Image Petite image de l'article
MediumImage Zend_Service_Amazon_Image Image moyenne de l'article
LargeImage Zend_Service_Amazon_Image Grande image de l'article
Subjects array Sujets de l'article
Les offres Sommaire des offres, et offres
Zend_Service_Amazon_OfferSet
pour l'article
CustomerReviews array Les revues clients
sont représentées comme
un tableau d'objets
Zend_Service_Amazon_CustomerReview
EditorialReviews array Les revues éditoriales
sont représentées comme
un tableau d'objets
Zend_Service_Amazon_EditorialReview
SimilarProducts array Les produits similaires
sont représentés comme
un tableau d'objets
Zend_Service_Amazon_SimilarProduct
Accessories array Les accessoires pour
l'article sont représentés

1219
Zend_Service

Nom Type Description


comme un tableau d'objets
Zend_Service_Amazon_Accessories
Tracks array Un tableau contenant le
nombre de pistes ainsi que les
noms pour les CDs ou DVDs
musicaux
ListmaniaLists array Les listes Listmania
reliées à un article,
comme un tableau d'objets
Zend_Service_Amazon_ListmaniaList
PromotionalTag string Balise promotionnelle de
l'article

Retour à la liste des classes

3.6.2. Zend_Service_Amazon_Image
Zend_Service_Amazon_Image représente une image distante pour un produit.

3.6.2.1. Propriétés

Tableau 120. Propriétés de Zend_Service_Amazon_Image

Name Type Description


Url Zend_Uri Url distante de l'image
Height int La hauteur (en pixels) de
l'image
Width int La largeur (en pixels) de
l'image

Retour à la liste des classes

3.6.3. Zend_Service_Amazon_ResultSet
Des objets Zend_Service_Amazon_ResultSet sont retournés par
Zend_Service_Amazon::itemSearch() et vous permettent de gérer facilement les différents
résultats retournés.

SeekableIterator

Implémente l'itérateur SeekableIterator pour une itération simple (en


utilisant foreach), aussi bien que l'accès direct à une URL spécifique en utilisant
seek().

3.6.3.1. Zend_Service_Amazon_ResultSet::totalResults()

int totalResults();

Retourne le nombre total de résultats de la recherche

Retour à la liste des classes

1220
Zend_Service

3.6.4. Zend_Service_Amazon_OfferSet
Chaque résultat retourné par Zend_Service_Amazon::itemSearch() et
Zend_Service_Amazon::itemLookup() contient un objet Zend_Service_Amazon_OfferSet
au travers duquel il est possible de récupérer les informations de prix de l'article.

3.6.4.1. Propriétés

Tableau 121. Propriétés de Zend_Service_Amazon_OfferSet


Name Type Description
LowestNewPrice int Le plus bas prix pour l'article en
condition "New" (ie les articles
neufs)
LowestNewPriceCurrency string La devise pour le
LowestNewPrice
LowestOldPrice int Le plus bas prix pour l'article en
condition "Used" (ie les articles
d'occasion)
LowestOldPriceCurrency string La devise pour le
LowestOldPrice
TotalNew int Le nombre total des conditions
"new" disponibles pour cet
article (ie le nombre de
modèles neufs en stock)
TotalUsed int Le nombre total des conditions
"used" disponible pour cet
article (ie le nombre de
modèles d'occasion en stock)
TotalCollectible int Le nombre total des conditions
"collectible" disponible pour cet
article (ie le nombre de pièces
de collection en stock)
TotalRefurbished int Le nombre total des conditions
"refurbished" disponible pour
cet article (ie le nombre de
pièces remise à neuf en stock)
Offers array Un tableau d'objets
Zend_Service_Amazon_Offer

Retour à la liste des classes

3.6.5. Zend_Service_Amazon_Offer
Chaque offre pour un article est retourné sous la forme d'un objet
Zend_Service_Amazon_Offer.

3.6.5.1. Zend_Service_Amazon_Offer Properties

Tableau 122. Propriétés de Zend_Service_Amazon_Offer


Name Type Description
MerchantId string ID Amazon du fournisseur

1221
Zend_Service

Name Type Description


GlancePage string URL de la page avec un
résumé du fournisseur
Condition string Condition de cet article
OfferListingId string ID de la liste d'offre
Price int Prix de l'article
CurrencyCode string Code de la devise pour le prix
de l'article
Availability string Disponibilité de l'article
IsEligibleForSuperSaverShipping
boolean Est-ce que l'article est éligible
ou pas pour un "Super Saver
Shipping"

Retour à la liste des classes

3.6.6. Zend_Service_Amazon_SimilarProduct
Lors de la recherche d'articles, Amazon retourne aussi une liste de produits similaires
qui pourraient intéresser le visiteur. Chacun d'entre eux est retourné dans un objet
Zend_Service_Amazon_SimilarProduct.

Chaque objet contient l'information qui vous permet de faire les requêtes suivantes pour obtenir
les informations complètes sur un article.

3.6.6.1. Propriétés

Tableau 123. Propriétés de Zend_Service_Amazon_SimilarProduct

Name Type Description


ASIN string Identifiant unique d'un produit
Amazon (ASIN)
Title string Intitulé du produit

Retour à la liste des classes

3.6.7. Zend_Service_Amazon_Accessories
Les accessoires pour un article retourné sont représentés comme un objet
Zend_Service_Amazon_Accessories.

3.6.7.1. Propriétés

Tableau 124. Propriétés de Zend_Service_Amazon_Accessories

Name Type Description


ASIN string Identifiant unique d'un produit
Amazon (ASIN)
Title string Intitulé du produit

Retour à la liste des classes

1222
Zend_Service

3.6.8. Zend_Service_Amazon_CustomerReview

Chaque revue de client est retournée sous la forme d'un objet


Zend_Service_Amazon_CustomerReview.

3.6.8.1. Propriétés

Tableau 125. Propriétés de Zend_Service_Amazon_CustomerReview

Name Type Description


Rating string Evaluation de l'article
HelpfulVotes string Votes pour "Ce commentaire
vous a-t'il été utile ?"
CustomerId string Identifiant du client
TotalVotes string Total des votes
Date string Date de la revue
Summary string Sommaire de la revue
Content string Contenu de la revue

Retour à la liste des classes

3.6.9. Zend_Service_Amazon_EditorialReview

Chaque revue éditoriale d'un article est retournée dans un objet


Zend_Service_Amazon_EditorialReview.

3.6.9.1. Propriétés

Tableau 126. Propriétés de Zend_Service_Amazon_EditorialReview

Name Type Description


Source string Source de la revue éditoriale
Content string Contenu de la revue

Retour à la liste des classes

3.6.10. Zend_Service_Amazon_Listmania

Chaque résultat de liste ListMania est retourné dans un objet


Zend_Service_Amazon_Listmania.

3.6.10.1. Propriétés

Tableau 127. Propriétés de Zend_Service_Amazon_Listmania

Name Type Description


ListId string Identifiant de la liste
ListName string Nom de la liste

Retour à la liste des classes

1223
Zend_Service

4. Zend_Service_Amazon_Ec2
4.1. Introduction
Zend_Service_Amazon_Ec2 provides an interface to Amazon Elastic Clound Computing
(EC2).

4.2. What is Amazon Ec2?


Amazon EC2 is a web service that enables you to launch and manage server instances in
Amazon's data centers using APIs or available tools and utilities. You can use Amazon EC2
server instances at any time, for as long as you need, and for any legal purpose.

4.3. Static Methods


To make using the Ec2 class easier to use there are two static methods that can be invoked
from any of the Ec2 Elements. The first static method is setKeys which will defind you AWS
Access Keys as default keys. When you then create any new object you don't need to pass in
any keys to the constructor.

Exemple 645. setKeys() Example

Zend_Service_Amazon_Ec2_Ebs::setKeys('aws_key','aws_secret_key');

To set the region that you are working in you can call the setRegion to set which Amazon Ec2
Region you are working in. Currently there is only two region available us-east-1 and eu-west-1.
If an invalid value is passed it will throw an exception stating that.

Exemple 646. setRegion() Example

Zend_Service_Amazon_Ec2_Ebs::setRegion('us-east-1');

Set Amazon Ec2 Region


Alternativly you can set the region when you create each class as the third
parameter in the constructor method.

5. Zend_Service_Amazon_Ec2: Instances
5.1. Instance Types
Amazon EC2 instances are grouped into two families: standard and High-CPU. Standard
instances have memory to CPU ratios suitable for most general purpose applications; High-CPU
instances have proportionally more CPU resources than memory (RAM) and are well suited
for compute-intensive applications. When selecting instance types, you might want to use less
powerful instance types for your web server instances and more powerful instance types for your
database instances. Additionally, you might want to run CPU instance types for CPU-intensive
data processing tasks.

One of the advantages of EC2 is that you pay by the instance hour, which makes it convenient
and inexpensive to test the performance of your application on different instance families and
types. One good way to determine the most appropriate instance family and instance type is to
launch test instances and benchmark your application.

1224
Zend_Service

Instance Types
The instance types are defined as constants in the code. Column eight in the
table is the defined constant name

Tableau 128. Available Instance Types

Type CPU Memory Storage Platform I/O Name Constant


Name
Small 1 EC2 1.7 GB 160 GB 32-bit Moderate m1.small Zend_Service_Amazon_E
Compute instance
Unit (1 storage
virtual core (150 GB
with 1 EC2 plus 10
Compute GB root
Unit) partition)
Large 4 EC2 7.5 GB 850 GB 64-bit High m1.large Zend_Service_Amazon_E
Compute instance
Units (2 storage (2
virtual x 420 GB
cores with plus 10
2 EC2 GB root
Compute partition)
Units
each)
Extra 8 EC2 15 GB 1,690 GB 64-bit High m1.xlarge Zend_Service_Amazon_E
Large Compute instance
Units (4 storage (4
virtual x 420 GB
cores with plus 10
2 EC2 GB root
Compute partition)
Units
each)
High-CPU 5 EC2 1.7 GB 350 GB 32-bit Moderate c1.medium Zend_Service_Amazon_E
Medium Compute instance
Units (2 storage
virtual (340 GB
cores with plus 10
2.5 EC2 GB root
Compute partition)
Units
each)
High-CPU 20 EC2 7 GB 1,690 GB 64-bit High c1.xlarge Zend_Service_Amazon_E
Extra Compute instance
Large Units (8 storage (4
virtual x 420 GB
cores with plus 10
2.5 EC2 GB root
Compute partition)
Units
each)

1225
Zend_Service

5.2. Running Amazon EC2 Instances


This section describes the operation methods for maintaining Amazon EC2 Instances.

Exemple 647. Starting New Ec2 Instances

run will launch a specified number of EC2 Instances. run takes an array of parameters to
start, below is a table containing the valid values.

Tableau 129. Valid Run Options


Name Description Required
imageId ID of the AMI with which to Yes
launch instances.
minCount Minimum number of No
instances to launch. Default:
1
maxCount Maximum number of No
instances to launch. Default:
1
keyName Name of the key pair with No
which to launch instances.
If you do not provide a
key, all instances will be
inaccessible.
securityGroup Names of the security groups No
with which to associate the
instances.
userData The user data available No
to the launched instances.
This should not be Base64
encoded.
instanceType Specifies the instance type. No
Default: m1.small
placement Specifies the availability No
zone in which to launch
the instance(s). By default,
Amazon EC2 selects an
availability zone for you.
kernelId The ID of the kernel with No
which to launch the instance.
ramdiskId The ID of the RAM disk with No
which to launch the instance.
blockDeviceVirtualName Specifies the virtual name No
to map to the corresponding
device name. For example:
instancestore0
blockDeviceName Specifies the device to which No
you are mapping a virtual
name. For example: sdb

1226
Zend_Service

Name Description Required


monitor Turn on AWS CloudWatch No
Instance Monitoring

run will return information about each instance that is starting up.

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance('aws_key',


'aws_secret_key');
$return = $ec2_instance->run(array('imageId' => 'ami-509320',
'keyName' => 'myKey',
'securityGroup' => array('web',
'default')));

Exemple 648. Rebooting an Ec2 Instances

reboot will reboot one or more instances.

This operation is asynchronous; it only queues a request to reboot the specified instance(s).
The operation will succeed if the instances are valid and belong to the user. Requests to
reboot terminated instances are ignored.

reboot returns boolean TRUE or FALSE

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance('aws_key',


'aws_secret_key');
$return = $ec2_instance->reboot('instanceId');

Exemple 649. Terminating an Ec2 Instances

terminate shuts down one or more instances. This operation is idempotent; if you
terminate an instance more than once, each call will succeed.

terminate returns boolean TRUE or FALSE

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance('aws_key',


'aws_secret_key');
$return = $ec2_instance->terminate('instanceId');

Terminated Instances

Terminated instances will remain visible after termination (approximately one


hour).

5.3. Amazon Instance Utilities


In this section you will find out how to retreive information, the console output and see if an
instance contains a product code.

1227
Zend_Service

Exemple 650. Describing Instances

describe returns information about instances that you own.

If you specify one or more instance IDs, Amazon EC2 returns information for those instances.
If you do not specify instance IDs, Amazon EC2 returns information for all relevant instances.
If you specify an invalid instance ID, a fault is returned. If you specify an instance that you
do not own, it will not be included in the returned results.

describe will return an array containing information on the instance.

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance('aws_key',


'aws_secret_key');
$return = $ec2_instance->describe('instanceId');

Terminated Instances
Recently terminated instances might appear in the returned results. This interval
is usually less than one hour. If you do not want terminated instances to be
returned, pass in a second variable of boolean TRUE to describe and the
terminated instances will be ignored.

Exemple 651. Describing Instances By Image Id

describeByImageId is functionally the same as describe but it will only return the
instances that are using the provided imageId.

describeByImageId will return an array containing information on the instances thare


were started by the passed in imageId

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance('aws_key',


'aws_secret_key');
$return = $ec2_instance->describeByImageId('imageId');

Terminated Instances
Recently terminated instances might appear in the returned results. This interval
is usually less than one hour. If you do not want terminated instances to be
returned, pass in a second variable of boolean TRUE to describe and the
terminated instances will be ignored.

Exemple 652. Retreiving Console Output

consoleOutput retrieves console output for the specified instance.

Instance console output is buffered and posted shortly after instance boot, reboot, and
termination. Amazon EC2 preserves the most recent 64 KB output which will be available
for at least one hour after the most recent post.

consoleOutput returns an array containing the instanceId, timestamp from the last
output and the output from the console.

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance('aws_key',


'aws_secret_key');
$return = $ec2_instance->consoleOutput('instanceId');

1228
Zend_Service

Exemple 653. Confirm Product Code on an Instance

confirmProduct returns TRUE if the specified product code is attached to the specified
instance. The operation returns FALSE if the product code is not attached to the instance.

The confirmProduct operation can only be executed by the owner of the AMI. This feature
is useful when an AMI owner is providing support and wants to verify whether a user's
instance is eligible.

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance('aws_key',


'aws_secret_key');
$return = $ec2_instance->confirmProduct('productCode', 'instanceId');

Exemple 654. Turn on CloudWatch Monitoring on an Instance(s)

monitor returns the list of instances and their current state of the CloudWatch Monitoring.
If the instance does not currently have Monitoring enabled it will be turned on.

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance('aws_key',


'aws_secret_key');
$return = $ec2_instance->monitor('instanceId');

Exemple 655. Turn off CloudWatch Monitoring on an Instance(s)

monitor returns the list of instances and their current state of the CloudWatch Monitoring.
If the instance currently has Monitoring enabled it will be turned off.

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance('aws_key',


'aws_secret_key');
$return = $ec2_instance->unmonitor('instanceId');

6. Zend_Service_Amazon_Ec2: Windows Instances


Using Amazon EC2 instances running Windows is similar to using instances running Linux and
UNIX. The following are the major differences between instances that use Linux or UNIX and
Windows:

• Remote Desktop—To access Windows instances, you use Remote Desktop instead of SSH.

• Administrative Password—To access Windows instances the first time, you must obtain the
administrative password using the ec2-get-password command.

• Simplified Bundling—To bundle a Windows instance, you use a single command that shuts
down the instance, saves it as an AMI, and restarts it.

As part of this service, Amazon EC2 instances can now run Microsoft Windows Server 2003.
Our base Windows image provides you with most of the common functionality associated with
Windows. However, if you require more than two concurrent Windows users or need to leverage
applications that require LDAP, Kerberos, RADIUS, or other credential services, you must use
Windows with Authentication Services. For example, Microsoft Exchange Server and Microsoft
SharePoint Server require Windows with Authentication Services.

To get started using Windows instances, we recommend using the AWS


Management Console. There are differences in pricing between Windows and
Windows with Authentication Services instances. For information on pricing, go
to the Amazon EC2 Product Page.

1229
Zend_Service

Amazon EC2 currently provides the following Windows AMIs:

• Windows Authenticated (32-bit)

• Windows Authenticated (64-bit)

• Windows Anonymous (32-bit)

• Windows Anonymous (64-bit)

The Windows public AMIs that Amazon provides are unmodified versions of Windows with the
following two exceptions: we added drivers to improve the networking and disk I/O performance
and we created the Amazon EC2 configuration service. The Amazon EC2 configuration service
performs the following functions:

• Randomly sets the Administrator password on initial launch, encrypts the password with the
user's SSH key, and reports it to the console. This operation happens upon initial AMI launch.
If you change the password, AMIs that are created from this instance use the new password.

• Configures the computer name to the internal DNS name. To determine the internal DNS
name, see Using Instance Addressing.

• Sends the last three system and application errors from the event log to the console. This
helps developers to identify problems that caused an instance to crash or network connectivity
to be lost.

6.1. Windows Instances Usage


Exemple 656. Bundles an Amazon EC2 instance running Windows

bundle() has three require paramters and one optional

• instanceId The instance you want to bundle

• s3Bucket Where you want the ami to live on S3

• s3Prefix The prefix you want to assign to the AMI on S3

• uploadExpiration The expiration of the upload policy. Amazon recommends 12 hours or


longer. This is based in nubmer of minutes. Default is 1440 minutes (24 hours)

bundle() returns a multi-demential array that contains instanceId, bundleId, state,


startTime, updateTime, progress s3Bucket and s3Prefix.

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance_Windows('aws_key',


'aws_secret_key');
$return = $ec2_instance->bundle('instanceId', 's3Bucket', 's3Prefix');

Exemple 657. Describes current bundling tasks

describeBundle() Describes current bundling tasks

describeBundle() returns a multi-demential array that contains instanceId, bundleId,


state, startTime, updateTime, progress s3Bucket and s3Prefix.

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance_Windows('aws_key',


'aws_secret_key');
$return = $ec2_instance->describeBundle('bundleId');

1230
Zend_Service

Exemple 658. Cancels an Amazon EC2 bundling operation

cancelBundle() Cancels an Amazon EC2 bundling operation

cancelBundle() returns a multi-demential array that contains instanceId, bundleId, state,


startTime, updateTime, progress s3Bucket and s3Prefix.

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance_Windows('aws_key',


'aws_secret_key');
$return = $ec2_instance->cancelBundle('bundleId');

7. Zend_Service_Amazon_Ec2: Reserved Instances


With Amazon EC2 Reserved Instances, you can make a low one-time payment for each instance
to reserve and receive a significant discount on the hourly usage charge for that instance.

Amazon EC2 Reserved Instances are based on instance type and location (region and
Availability Zone) for a specified period of time (e.g., 1 year or 3 years) and are only available
for Linux or UNIX instances.

7.1. How Reserved Instances are Applied


Reserved Instances are applied to instances that meet the type/location criteria during the
specified period. In this example, a user is running the following instances:

• (4) m1.small instances in Availability Zone us-east-1a

• (4) c1.medium instances in Availability Zone us-east-1b

• (2) c1.xlarge instances in Availability Zone us-east-1b

The user then purchases the following Reserved Instances.

• (2) m1.small instances in Availability Zone us-east-1a

• (2) c1.medium instances in Availability Zone us-east-1a

• (2) m1.xlarge instances in Availability Zone us-east-1a

Amazon EC2 applies the two m1.small Reserved Instances to two of the instances in Availability
Zone us-east-1a. Amazon EC2 doesn't apply the two c1.medium Reserved Instances because
the c1.medium instances are in a different Availability Zone and does not apply the m1.xlarge
Reserved Instances because there are no running m1.xlarge instances.

7.2. Reserved Instances Usage


Exemple 659. Describes Reserved Instances that you purchased

describeInstances() will return information about a reserved instance or instances that


you purchased.

describeInstances() returns a multi-demential array that contains


reservedInstancesId, instanceType, availabilityZone, duration, fixedPrice, usagePrice,
productDescription, instanceCount and state.

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance_Reserved('aws_key',


'aws_secret_key');
$return = $ec2_instance->describeInstances('instanceId');

1231
Zend_Service

Exemple 660. Describe current Reserved Instance Offerings available

describeOfferings() Describes Reserved Instance offerings that are available for


purchase. With Amazon EC2 Reserved Instances, you purchase the right to launch Amazon
EC2 instances for a period of time (without getting insufficient capacity errors) and pay a
lower usage rate for the actual time used.

describeOfferings() returns a multi-demential array that contains


reservedInstancesId, instanceType, availabilityZone, duration, fixedPrice, usagePrice and
productDescription.

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance_Reserved('aws_key',


'aws_secret_key');
$return = $ec2_instance->describeOfferings();

Exemple 661. Turn off CloudWatch Monitoring on an Instance(s)

purchaseOffering() Purchases a Reserved Instance for use with your account. With
Amazon EC2 Reserved Instances, you purchase the right to launch Amazon EC2 instances
for a period of time (without getting insufficient capacity errors) and pay a lower usage rate
for the actual time used.

purchaseOffering() returns the reservedInstanceId.

$ec2_instance = new Zend_Service_Amazon_Ec2_Instance_Reserved('aws_key',


'aws_secret_key');
$return = $ec2_instance->purchaseOffering('offeringId', 'instanceCount');

8. Zend_Service_Amazon_Ec2: CloudWatch Monitoring


Amazon CloudWatch is an easy-to-use web service that provides comprehensive monitoring for
Amazon Elastic Compute Cloud (Amazon EC2) and Elastic Load Balancing. For more details
information check cout the Amazon CloudWatch Developers Guide

8.1. CloudWatch Usage


Exemple 662. Listing Aviable Metrics

listMetrics() returns a list of up to 500 valid metrics for which there is recorded data
available to a you and a NextToken string that can be used to query for the next set of results.

$ec2_ebs = new Zend_Service_Amazon_Ec2_CloudWatch('aws_key','aws_secret_key');


$return = $ec2_ebs->listMetrics();

1232
Zend_Service

Exemple 663. Return Statistics for a given metric

getMetricStatistics() Returns data for one or more statistics of given a metric.

The maximum number of datapoints that the Amazon CloudWatch service


will return in a single GetMetricStatistics request is 1,440. If a request is made
that would generate more datapoints than this amount, Amazon CloudWatch
will return an error. You can alter your request by narrowing the time range
(StartTime, EndTime) or increasing the Period in your single request. You
may also get all of the data at the granularity you originally asked for by
making multiple requests with adjacent time ranges.

getMetricStatistics() only requires two parameters but it also has four additional
parameters that are optional.

• Required:

• MeasureName The measure name that corresponds to the measure for the gathered
metric. Valid EC2 Values are CPUUtilization, NetworkIn, NetworkOut, DiskWriteOps
DiskReadBytes, DiskReadOps, DiskWriteBytes. Valid Elastic Load Balancing Metrics are
Latency, RequestCount, HealthyHostCount UnHealthyHostCount. For more information
click here

• Statistics The statistics to be returned for the given metric. Valid values are Average,
Maximum, Minimum, Samples, Sum. You can specify this as a string or as an array of
values. If you don't specify one it will default to Average instead of failing out. If you specify
an incorrect option it will just skip it. For more information click here

• Optional:

• Dimensions Amazon CloudWatch allows you to specify one Dimension to further filter
metric data on. If you don't specify a dimension, the service returns the aggregate of all
the measures with the given measure name and time range.

• Unit The standard unit of Measurement for a given Measure. Valid Values: Seconds,
Percent, Bytes, Bits, Count, Bytes/Second, Bits/Second, Count/Second, and None.
Constraints: When using count/second as the unit, you should use Sum as the statistic
instead of Average. Otherwise, the sample returns as equal to the number of requests
instead of the number of 60-second intervals. This will cause the Average to always equals
one when the unit is count/second.

• StartTime The timestamp of the first datapoint to return, inclusive. For example,
2008-02-26T19:00:00+00:00. We round your value down to the nearest minute. You can
set your start time for more than two weeks in the past. However, you will only get data
for the past two weeks. (in ISO 8601 format). Constraints: Must be before EndTime.

• EndTime The timestamp to use for determining the last datapoint to return. This is the
last datapoint to fetch, exclusive. For example, 2008-02-26T20:00:00+00:00 (in ISO 8601
format).

$ec2_ebs = new Zend_Service_Amazon_Ec2_CloudWatch('aws_key','aws_secret_key');


$return = $ec2_ebs->getMetricStatistics(
array('MeasureName' => 'NetworkIn',
'Statistics' => array('Average')));

1233
Zend_Service

9. Zend_Service_Amazon_Ec2: Amazon Machine Images


(AMI)
Amazon Machine Images (AMIs) are preconfigured with an ever-growing list of operating
systems.

9.1. AMI Information Utilities


Exemple 664. Register an AMI with EC2

register Each AMI is associated with an unique ID which is provided by the Amazon EC2
service through the RegisterImage operation. During registration, Amazon EC2 retrieves the
specified image manifest from Amazon S3 and verifies that the image is owned by the user
registering the image.

register returns the imageId for the registered Image.

$ec2_img = new Zend_Service_Amazon_Ec2_Image('aws_key','aws_secret_key');


$ip = $ec2_img->register('imageLocation');

Exemple 665. Deregister an AMI with EC2

deregister, Deregisters an AMI. Once deregistered, instances of the AMI can no longer
be launched.

deregister returns boolean TRUE or FALSE.

$ec2_img = new Zend_Service_Amazon_Ec2_Image('aws_key','aws_secret_key');


$ip = $ec2_img->deregister('imageId');

Exemple 666. Describe an AMI

describe Returns information about AMIs, AKIs, and ARIs available to the user.
Information returned includes image type, product codes, architecture, and kernel and RAM
disk IDs. Images available to the user include public images available for any user to launch,
private images owned by the user making the request, and private images owned by other
users for which the user has explicit launch permissions.

Tableau 130. Launch permissions fall into three categories

Name Description
public The owner of the AMI granted launch
permissions for the AMI to the all group.
All users have launch permissions for these
AMIs.
explicit The owner of the AMI granted launch
permissions to a specific user.

1234
Zend_Service

Name Description
implicit A user has implicit launch permissions for all
AMIs he or she owns.

The list of AMIs returned can be modified by specifying AMI IDs, AMI owners, or users with
launch permissions. If no options are specified, Amazon EC2 returns all AMIs for which the
user has launch permissions.

If you specify one or more AMI IDs, only AMIs that have the specified IDs are returned. If
you specify an invalid AMI ID, a fault is returned. If you specify an AMI ID for which you do
not have access, it will not be included in the returned results.

If you specify one or more AMI owners, only AMIs from the specified owners and for which
you have access are returned. The results can include the account IDs of the specified
owners, amazon for AMIs owned by Amazon or self for AMIs that you own.

If you specify a list of executable users, only users that have launch permissions for the
AMIs are returned. You can specify account IDs (if you own the AMI(s)), self for AMIs for
which you own or have explicit permissions, or all for public AMIs.

describe returns an array for all the images that match the critera that was passed
in. The array contains the imageId, imageLocation, imageState, imageOwnerId, isPublic,
architecture, imageType, kernelId, ramdiskId and platform.

$ec2_img = new Zend_Service_Amazon_Ec2_Image('aws_key','aws_secret_key');


$ip = $ec2_img->describe();

9.2. AMI Attribute Utilities


Exemple 667. Modify Image Attributes

Modifies an attribute of an AMI

Tableau 131. Valid Attributes

Name Description
launchPermission Controls who has permission to launch the
AMI. Launch permissions can be granted to
specific users by adding userIds.

To make the AMI public, add the all group.

1235
Zend_Service

Name Description
productCodes Associates a product code with AMIs. This
allows developers to charge users for using
AMIs. The user must be signed up for the
product before they can launch the AMI. This
is a write once attribute; after it is set, it
cannot be changed or removed.

modifyAttribute returns boolean TRUE or FALSE.

$ec2_img = new Zend_Service_Amazon_Ec2_Image('aws_key','aws_secret_key');


// modify the launchPermission of an AMI
$return = $ec2_img->modifyAttribute('imageId',
'launchPermission',
'add',
'userId',
'userGroup');

// set the product code of the AMI.


$return = $ec2_img->modifyAttribute('imageId',
'productCodes',
'add',
null,
null,
'productCode');

Exemple 668. Reset an AMI Attribute

resetAttribute will reset the attribute of an AMI to its default value. The productCodes
attribute cannot be reset.

$ec2_img = new Zend_Service_Amazon_Ec2_Image('aws_key','aws_secret_key');


$return = $ec2_img->resetAttribute('imageId', 'launchPermission');

Exemple 669. Describe AMI Attribute

describeAttribute returns information about an attribute of an AMI. Only one attribute


can be specified per call. Currently only launchPermission and productCodes are supported.

describeAttribute returns an array with the value of the attribute that was requested.

$ec2_img = new Zend_Service_Amazon_Ec2_Image('aws_key','aws_secret_key');


$return = $ec2_img->describeAttribute('imageId', 'launchPermission');

10. Zend_Service_Amazon_Ec2: Elastic Block Stroage (EBS)


Amazon Elastic Block Store (Amazon EBS) is a new type of storage designed specifically for
Amazon EC2 instances. Amazon EBS allows you to create volumes that can be mounted as
devices by Amazon EC2 instances. Amazon EBS volumes behave like raw unformatted external
block devices. They have user supplied device names and provide a block device interface. You
can load a file system on top of Amazon EBS volumes, or use them just as you would use a
block device.

You can create up to twenty Amazon EBS volumes of any size (from one GiB up to one TiB).
Each Amazon EBS volume can be attached to any Amazon EC2 instance in the same Availability
Zone or can be left unattached.

1236
Zend_Service

Amazon EBS provides the ability to create snapshots of your Amazon EBS volumes to Amazon
S3. You can use these snapshots as the starting point for new Amazon EBS volumes and can
protect your data for long term durability.

10.1. Create EBS Volumes and Snapshots


Exemple 670. Create a new EBS Volume

Creating a brand new EBS Volume requires the size and which zone you want the EBS
Volume to be in.

createNewVolume will return an array containing information about the new Volume which
includes the volumeId, size, zone, status and createTime.

$ec2_ebs = new Zend_Service_Amazon_Ec2_Ebs('aws_key','aws_secret_key');


$return = $ec2_ebs->createNewVolume(40, 'us-east-1a');

Exemple 671. Create an EBS Volume from a Snapshot

Creating an EBS Volume from a snapshot requires the snapshot_id and which zone you
want the EBS Volume to be in.

createVolumeFromSnapshot will return an array containing information about the new


Volume which includes the volumeId, size, zone, status, createTime and snapshotId.

$ec2_ebs = new Zend_Service_Amazon_Ec2_Ebs('aws_key','aws_secret_key');


$return = $ec2_ebs->createVolumeFromSnapshot('snap-78a54011', 'us-east-1a');

Exemple 672. Create a Snapshot of an EBS Volume

Creating a Snapshot of an EBS Volume requires the volumeId of the EBS Volume.

createSnapshot will return an array containing information about the new Volume
Snapshot which includes the snapshotId, volumeId, status, startTime and progress.

$ec2_ebs = new Zend_Service_Amazon_Ec2_Ebs('aws_key','aws_secret_key');


$return = $ec2_ebs->createSnapshot('volumeId');

10.2. Describing EBS Volumes and Snapshots


Exemple 673. Describing an EBS Volume

describeVolume allows you to get information on an EBS Volume or a set of EBS


Volumes. If nothing is passed in then it will return all EBS Volumes. If only one EBS Volume
needs to be described a string can be passed in while an array of EBS Volume Id's can be
passed in to describe them.

describeVolume will return an array with information about each Volume which includes
the volumeId, size, status and createTime. If the volume is attached to an instance, an
addition value of attachmentSet will be returned. The attachment set contains information
about the instance that the EBS Volume is attached to, which includes volumeId, instanceId,
device, status and attachTime.

$ec2_ebs = new Zend_Service_Amazon_Ec2_Ebs('aws_key','aws_secret_key');


$return = $ec2_ebs->describeVolume('volumeId');

1237
Zend_Service

Exemple 674. Describe Attached Volumes

To return a list of EBS Volumes currently attached to a running instance you can call
this method. It will only return EBS Volumes attached to the instance with the passed in
instanceId.

describeAttachedVolumes returns the same information as the describeVolume but


only for the EBS Volumes that are currently attached to the specified instanceId.

$ec2_ebs = new Zend_Service_Amazon_Ec2_Ebs('aws_key','aws_secret_key');


$return = $ec2_ebs->describeAttachedVolumes('instanceId');

Exemple 675. Describe an EBS Volume Snapshot

describeSnapshot allows you to get information on an EBS Volume Snapshot or a set of


EBS Volume Snapshots. If nothing is passed in then it will return information about all EBS
Volume Snapshots. If only one EBS Volume Snapshot needs to be described its snapshotId
can be passed in while an array of EBS Volume Snapshot Id's can be passed in to describe
them.

describeSnapshot will return an array containing information about each EBS Volume
Snapshot which includes the snapshotId, volumeId, status, startTime and progress.

$ec2_ebs = new Zend_Service_Amazon_Ec2_Ebs('aws_key','aws_secret_key');


$return = $ec2_ebs->describeSnapshot('volumeId');

10.3. Attach and Detaching Volumes from Instances


Exemple 676. Attaching an EBS Volume

attachVolume will attach an EBS Volume to a running Instance. To attach a volume you
need to specify the volumeId, the instanceId and the device (ex: /dev/sdh).

attachVolume will return an array with information about the attach status which contains
volumeId, instanceId, device, status and attachTime

$ec2_ebs = new Zend_Service_Amazon_Ec2_Ebs('aws_key','aws_secret_key');


$return = $ec2_ebs->attachVolume('volumeId', 'instanceid', '/dev/sdh');

Exemple 677. Detaching an EBS Volume

detachVolume will detach an EBS Volume from a running Instance. detachVolume


requires that you specify the volumeId with the optional instanceId and device name that
was passed when attaching the volume. If you need to force the detachment you can set
the forth parameter to be TRUE and it will force the volume to detach.

detachVolume returns an array containing status information about the EBS Volume which
includes volumeId, instanceId, device, status and attachTime.

$ec2_ebs = new Zend_Service_Amazon_Ec2_Ebs('aws_key','aws_secret_key');


$return = $ec2_ebs->detachVolume('volumeId');

Forced Detach
You should only force a detach if the previous detachment attempt did not
occur cleanly (logging into an instance, unmounting the volume, and detaching

1238
Zend_Service

normally). This option can lead to data loss or a corrupted file system. Use this
option only as a last resort to detach a volume from a failed instance. The instance
will not have an opportunity to flush file system caches or file system meta data.
If you use this option, you must perform file system check and repair procedures.

10.4. Deleting EBS Volumes and Snapshots


Exemple 678. Deleting an EBS Volume

deleteVolume will delete an unattached EBS Volume.

deleteVolume will return boolean TRUE or FALSE.

$ec2_ebs = new Zend_Service_Amazon_Ec2_Ebs('aws_key','aws_secret_key');


$return = $ec2_ebs->deleteVolume('volumeId');

Exemple 679. Deleting an EBS Volume Snapshot

deleteSnapshot will delete an EBS Volume Snapshot.

deleteSnapshot returns booleen TRUE or FALSE.

$ec2_ebs = new Zend_Service_Amazon_Ec2_Ebs('aws_key','aws_secret_key');


$return = $ec2_ebs->deleteSnapshot('snapshotId');

11. Zend_Service_Amazon_Ec2: Elastic IP Addresses


By default, all Amazon EC2 instances are assigned two IP addresses at launch: a private (RFC
1918) address and a public address that is mapped to the private IP address through Network
Address Translation (NAT).

If you use dynamic DNS to map an existing DNS name to a new instance's public IP address, it
might take up to 24 hours for the IP address to propagate through the Internet. As a result, new
instances might not receive traffic while terminated instances continue to receive requests.

To solve this problem, Amazon EC2 provides elastic IP addresses. Elastic IP addresses are
static IP addresses designed for dynamic cloud computing. Elastic IP addresses are associated
with your account, not specific instances. Any elastic IP addresses that you associate with your
account remain associated with your account until you explicitly release them. Unlike traditional
static IP addresses, however, elastic IP addresses allow you to mask instance or Availability
Zone failures by rapidly remapping your public IP addresses to any instance in your account.

Exemple 680. Allocating a new Elastic IP

allocate will assign your account a new Elastic IP Address.

allocate returns the newly allocated ip.

$ec2_eip = new Zend_Service_Amazon_Ec2_Elasticip('aws_key','aws_secret_key');


$ip = $ec2_eip->allocate();

// print out your newly allocated elastic ip address;


print $ip;

1239
Zend_Service

Exemple 681. Describing Allocated Elastic IP Addresses

describe has an optional paramater to describe all of your allocated Elastic IP addresses
or just some of your allocated addresses.

describe returns an array that contains information on each Elastic IP Address which
contains the publicIp and the instanceId if it is assocated.

$ec2_eip = new Zend_Service_Amazon_Ec2_Elasticip('aws_key','aws_secret_key');


// describe all
$ips = $ec2_eip->describe();

// describe a subset
$ips = $ec2_eip->describe(array('ip1', 'ip2', 'ip3'));

// describe a single ip address


$ip = $ec2_eip->describe('ip1');

Exemple 682. Releasing Elastic IP

release will release an Elastic IP to Amazon.

Returns a boolean TRUE or FALSE.

$ec2_eip = new Zend_Service_Amazon_Ec2_Elasticip('aws_key','aws_secret_key');


$ec2_eip->release('ipaddress');

Exemple 683. Associates an Elastic IP to an Instance

associate will assign an Elastic IP to an already running instance.

Returns a boolean TRUE or FALSE.

$ec2_eip = new Zend_Service_Amazon_Ec2_Elasticip('aws_key','aws_secret_key');


$ec2_eip->associate('instance_id', 'ipaddress');

Exemple 684. Disassociate an Elastic IP from an instance

disassociate will disassociate an Elastic IP from an instance. If you terminate an Instance


it will automaticly disassociate the Elastic IP address for you.

Returns a boolean TRUE or FALSE.

$ec2_eip = new Zend_Service_Amazon_Ec2_Elasticip('aws_key','aws_secret_key');


$ec2_eip->disassociate('ipaddress');

12. Zend_Service_Amazon_Ec2: Keypairs


Keypairs are used to access instances.

Exemple 685. Creating a new Amazon Keypair

create, creates a new 2048 bit RSA key pair and returns a unique ID that can be used to
reference this key pair when launching new instances.

create returns an array which contains the keyName, keyFingerprint and keyMaterial.

$ec2_kp = new Zend_Service_Amazon_Ec2_Keypair('aws_key','aws_secret_key');


$return = $ec2_kp->create('my-new-key');

1240
Zend_Service

Exemple 686. Deleting an Amazon Keypair

delete, will delete the key pair. This will only prevent it from being used with new instances.
Instances currently running with the keypair will still allow you to access them.

delete returns boolean TRUE or FALSE

$ec2_kp = new Zend_Service_Amazon_Ec2_Keypair('aws_key','aws_secret_key');


$return = $ec2_kp->delete('my-new-key');

Exemple 687. Describe an Amazon Keypair

describe returns information about key pairs available to you. If you specify key pairs,
information about those key pairs is returned. Otherwise, information for all registered key
pairs is returned.

describe returns an array which contains keyName and keyFingerprint

$ec2_kp = new Zend_Service_Amazon_Ec2_Keypair('aws_key','aws_secret_key');


$return = $ec2_kp->describe('my-new-key');

13. Zend_Service_Amazon_Ec2: Regions and Availability


Zones
Amazon EC2 provides the ability to place instances in different regions and Availability Zones.
Regions are dispersed in separate geographic areas or countries. Availability Zones are located
within regions and are engineered to be insulated from failures in other Availability Zones and
provide inexpensive low latency network connectivity to other Availability Zones in the same
region. By launching instances in separate Availability Zones, you can protect your applications
from the failure of a single Availability Zone.

13.1. Amazon EC2 Regions


Amazon EC2 provides multiple regions so you can launch Amazon EC2 instances in locations
that meet your requirements. For example, you might want to launch instances in Europe to be
closer to your European customers or to meet legal requirements.

Each Amazon EC2 region is designed to be completely isolated from the other Amazon EC2
regions. This achieves the greatest possible failure independence and stability, and it makes the
locality of each EC2 resource unambiguous.

Exemple 688. Viewing the available regions

describe is used to find out which regions your account has access to.

describe will return an array containing information about which regions are available.
Each array will contain regionName and regionUrl.

$ec2_region = new Zend_Service_Amazon_Ec2_Region('aws_key','aws_secret_key');


$regions = $ec2_region->describe();

foreach($regions as $region) {
print $region['regionName'] . ' -- ' . $region['regionUrl'] . '<br />';
}

1241
Zend_Service

13.2. Amazon EC2 Availability Zones


When you launch an instance, you can optionally specify an Availability Zone. If you do not
specify an Availability Zone, Amazon EC2 selects one for you in the region that you are using.
When launching your initial instances, we recommend accepting the default Availability Zone,
which allows Amazon EC2 to select the best Availability Zone for you based on system health and
available capacity. Even if you have other instances running, you might consider not specifying
an Availability Zone if your new instances do not need to be close to, or separated from, your
existing instances.

Exemple 689. Viewing the available zones

describe is used to find out which what the status is of each availability zone.

describe will return an array containing information about which zones are available. Each
array will contain zoneName and zoneState.

$ec2_zones = new Zend_Service_Amazon_Ec2_Availabilityzones('aws_key',


'aws_secret_key');
$zones = $ec2_zones->describe();

foreach($zones as $zone) {
print $zone['zoneName'] . ' -- ' . $zone['zoneState'] . '<br />';
}

14. Zend_Service_Amazon_Ec2: Security Groups


A security group is a named collection of access rules. These access rules specify which ingress
(i.e., incoming) network traffic should be delivered to your instance. All other ingress traffic will
be discarded.

You can modify rules for a group at any time. The new rules are automatically enforced for all
running instances and instances launched in the future.

Maximum Security Groups

You can create up to 100 security groups.

14.1. Security Group Maintenance


Exemple 690. Create a new Security Group

create a new security group. Every instance is launched in a security group. If no security
group is specified during launch, the instances are launched in the default security group.
Instances within the same security group have unrestricted network access to each other.
Instances will reject network access attempts from other instances in a different security
group.

create returns boolean TRUE or FALSE

$ec2_sg = new Zend_Service_Amazon_Ec2_Securitygroups('aws_key',


'aws_secret_key');
$return = $ec2_sg->create('mygroup', 'my group description');

1242
Zend_Service

Exemple 691. Describe a Security Group

describe returns information about security groups that you own.

If you specify security group names, information about those security groups is returned.
Otherwise, information for all security groups is returned. If you specify a group that does
not exist, a fault is returned.

describe will return an array containing information about security groups which includes
the ownerId, groupName, groupDescription and an array containing all the rules for that
security group.

$ec2_sg = new Zend_Service_Amazon_Ec2_Securitygroups('aws_key',


'aws_secret_key');
$return = $ec2_sg->describe('mygroup');

Exemple 692. Delete a Security Group

delete will remove the security group. If you attempt to delete a security group that contains
instances, a fault is returned. If you attempt to delete a security group that is referenced
by another security group, a fault is returned. For example, if security group B has a rule
that allows access from security group A, security group A cannot be deleted until the allow
rule is removed.

delete returns boolean TRUE or FALSE.

$ec2_sg = new Zend_Service_Amazon_Ec2_Securitygroups('aws_key',


'aws_secret_key');
$return = $ec2_sg->delete('mygroup');

14.2. Authorizing Access


Exemple 693. Authorizing by IP

authorizeIp Adds permissions to a security group based on an IP address, protocol type


and port range.

Permissions are specified by the IP protocol (TCP, UDP or ICMP), the source of the request
(by IP range or an Amazon EC2 user-group pair), the source and destination port ranges
(for TCP and UDP), and the ICMP codes and types (for ICMP). When authorizing ICMP, -1
can be used as a wildcard in the type and code fields.

Permission changes are propagated to instances within the security group as quickly as
possible. However, depending on the number of instances, a small delay might occur.

authorizeIp returns boolean TRUE or FALSE

$ec2_sg = new Zend_Service_Amazon_Ec2_Securitygroups('aws_key',


'aws_secret_key');
$return = $ec2_sg->authorizeIp('mygroup',
'protocol',
'fromPort',
'toPort',
'ipRange');

1243
Zend_Service

Exemple 694. Authorize By Group

authorizeGroup Adds permissions to a security group.

Permission changes are propagated to instances within the security group as quickly as
possible. However, depending on the number of instances, a small delay might occur.

authorizeGroup returns boolean TRUE or FALSE.

$ec2_sg = new Zend_Service_Amazon_Ec2_Securitygroups('aws_key',


'aws_secret_key');
$return = $ec2_sg->authorizeGroup('mygroup', 'securityGroupName', 'ownerId');

14.3. Revoking Access


Exemple 695. Revoke by IP

revokeIp Revokes permissions to a security group based on an IP address, protocol type


and port range. The permissions used to revoke must be specified using the same values
used to grant the permissions.

Permissions are specified by the IP protocol (TCP, UDP or ICMP), the source of the request
(by IP range or an Amazon EC2 user-group pair), the source and destination port ranges
(for TCP and UDP), and the ICMP codes and types (for ICMP). When authorizing ICMP, -1
can be used as a wildcard in the type and code fields.

Permission changes are propagated to instances within the security group as quickly as
possible. However, depending on the number of instances, a small delay might occur.

revokeIp returns boolean TRUE or FALSE

$ec2_sg = new Zend_Service_Amazon_Ec2_Securitygroups('aws_key',


'aws_secret_key');
$return = $ec2_sg->revokeIp('mygroup',
'protocol',
'fromPort',
'toPort',
'ipRange');

Exemple 696. Revoke By Group

revokeGroup Adds permissions to a security group. The permissions to revoke must be


specified using the same values used to grant the permissions.

Permission changes are propagated to instances within the security group as quickly as
possible. However, depending on the number of instances, a small delay might occur.

revokeGroup returns boolean TRUE or FALSE.

$ec2_sg = new Zend_Service_Amazon_Ec2_Securitygroups('aws_key',


'aws_secret_key');
$return = $ec2_sg->revokeGroup('mygroup', 'securityGroupName', 'ownerId');

1244
Zend_Service

15. Zend_Service_Amazon_S3
15.1. Introduction
Amazon S3 provides a simple web services interface that can be used to store and retrieve any
amount of data, at any time, from anywhere on the web. It gives any developer access to the
same highly scalable, reliable, fast, inexpensive data storage infrastructure that Amazon uses
to run its own global network of web sites. The service aims to maximize benefits of scale and
to pass those benefits on to developers.

15.2. Registering with Amazon S3


Before you can get started with Zend_Service_Amazon_S3, you must first register for an
account. Please see the S3 FAQ page on the Amazon website for more information.

After registering, you will receive an application key and a secret key. You will need both to
access the S3 service.

15.3. API Documentation


The Zend_Service_Amazon_S3 class provides the PHP wrapper to the Amazon S3 REST
interface. Please consult the Amazon S3 documentation for detailed description of the service.
You will need to be familiar with basic concepts in order to use this service.

15.4. Features
Zend_Service_Amazon_S3 provides the following functionality:

• A single point for configuring your amazon.s3 authentication credentials that can be used
across the amazon.s3 namespaces.

• A proxy object that is more convenient to use than an HTTP client alone, mostly removing the
need to manually construct HTTP POST requests to access the REST service.

• A response wrapper that parses each response body and throws an exception if an error
occurred, alleviating the need to repeatedly check the success of many commands.

• Additional convenience methods for some of the more common operations.

15.5. Getting Started


Once you have registered with Amazon S3, you're ready to store your first data object on the
S3. The objects on S3 are stored in containers, called "buckets". Bucket names are unique on
S3, and each user can have no more than 100 buckets simultaneously. Each bucket can contain
unlimited amount of objects, identified by name.

The following example demonstrates creating a bucket, storing and retrieving the data.

1245
Zend_Service

Exemple 697. Zend_Service_Amazon_S3 Usage Example

require_once 'Zend/Service/Amazon/S3.php';

$s3 = new Zend_Service_Amazon_S3($my_aws_key, $my_aws_secret_key);

$s3->createBucket("my-own-bucket");

$s3->putObject("my-own-bucket/myobject", "somedata");

echo $s3->getObject("my-own-bucket/myobject");

Since Zend_Service_Amazon_S3 service requires authentication, you should pass your


credentials (AWS key and secret key) to the constructor. If you only use one account, you can
set default credentials for the service:

require_once 'Zend/Service/Amazon/S3.php';

Zend_Service_Amazon_S3::setKeys($my_aws_key, $my_aws_secret_key);
$s3 = new Zend_Service_Amazon_S3();

15.6. Bucket operations


All objects in S3 system are stored in buckets. Bucket has to be created before any storage
operation. Bucket name is unique in the system, so you can not have bucket named the same
as someone else's bucket.

Bucket name can contain lowercase letters, digits, periods (.), underscores (_), and dashes
(-). No other symbols allowed. Bucket name should start with letter or digit, and be 3 to 255
characters long. Names looking like an IP address (e.g. "192.168.16.255") are not allowed.

• createBucket() creates a new bucket.

• cleanBucket() removes all objects that are contained in a bucket.

• removeBucket() removes the bucket from the system. The bucket should be empty to be
removed.

Exemple 698. Zend_Service_Amazon_S3 Bucket Removal Example

require_once 'Zend/Service/Amazon/S3.php';

$s3 = new Zend_Service_Amazon_S3($my_aws_key, $my_aws_secret_key);

$s3->cleanBucket("my-own-bucket");
$s3->removeBucket("my-own-bucket");

• getBuckets() returns the list of the names of all buckets belonging to the user.

1246
Zend_Service

Exemple 699. Zend_Service_Amazon_S3 Bucket Listing Example

require_once 'Zend/Service/Amazon/S3.php';

$s3 = new Zend_Service_Amazon_S3($my_aws_key, $my_aws_secret_key);

$list = $s3->getBuckets();
foreach($list as $bucket) {
echo "I have bucket $bucket\n";
}

• isBucketAvailable() check if the bucket exists and returns TRUE if it does.

15.7. Object operations


The object is the basic storage unit in S3. Object stores unstructured data, which can be any
size up to 4 gigabytes. There's no limit on how many objects can be stored on the system.

The object are contained in buckets. Object is identified by name, which can be any utf-8 string.
It is common to use hierarchical names (such as Pictures/Myself/CodingInPHP.jpg) to
organise object names. Object name is prefixed with bucket name when using object functions,
so for object "mydata" in bucket "my-own-bucket" the name would be my-own-bucket/
mydata.

Objects can be replaced (by rewriting new data with the same key) or deleted, but not modified,
appended, etc. Object is always stored whole.

By default, all objects are private and can be accessed only by their owner. However, it is possible
to specify object with public access, in which case it will be available through the URL: http://
s3.amazonaws.com/[bucket-name]/[object-name].

• putObject($object, $data, $meta) created an object with name $object (should


contain the bucket name as prefix!) having $data as its content.

Optional $meta parameter is the array of metadata, which currently supports the following
parameters as keys:

S3_CONTENT_TYPE_HEADER MIME content type of the data. If not specified, the type will be
guessed according to the file extension of the object name.

S3_ACL_HEADER The access to the item. Following access constants can be


used:

S3_ACL_PRIVATE Only the owner has access to the


item.

S3_ACL_PUBLIC_READ Anybody can read the object,


but only owner can write. This
is setting may be used to store
publicly accessible content.

S3_ACL_PUBLIC_WRITE Anybody can read or write the


object. This policy is rarely
useful.

1247
Zend_Service

S3_ACL_AUTH_READ Only the owner has write


access to the item, and other
authenticated S3 users have
read access. This is useful
for sharing data between S3
accounts without exposing them
to the public.
By default, all the items are private.

Exemple 700. Zend_Service_Amazon_S3 Public


Object Example

require_once 'Zend/Service/Amazon/S3.php';

$s3 = new Zend_Service_Amazon_S3($my_aws_key, $my_aws_secret

$s3->putObject("my-own-bucket/Pictures/Me.png", file_get_con
array(Zend_Service_Amazon_S3::S3_ACL_HEADER =>
Zend_Service_Amazon_S3::S3_ACL_PUBLIC_READ));
// or:
$s3->putFile("me.png", "my-own-bucket/Pictures/Me.png",
array(Zend_Service_Amazon_S3::S3_ACL_HEADER =>
Zend_Service_Amazon_S3::S3_ACL_PUBLIC_READ));
echo "Go to http://s3.amazonaws.com/my-own-bucket/Pictures/M

• getObject($object) retrieves object data from the storage by name.

• removeObject($object) removes the object from the storage.

• getInfo($object) retrieves the metadata information about the object. The function will
return array with metadata information. Some of the useful keys are:

type The MIME type of the item.

size The size of the object data.

mtime UNIX-type timestamp of the last modification for the object.

etag The ETag of the data, which is the MD5 hash of the data, surrounded by quotes (").
The function will return FALSE if the key does not correspond to any existing object.

• getObjectsByBucket($bucket) returns the list of the object keys, contained in the bucket.

Exemple 701. Zend_Service_Amazon_S3 Object Listing Example

require_once 'Zend/Service/Amazon/S3.php';

$s3 = new Zend_Service_Amazon_S3($my_aws_key, $my_aws_secret_key);

$list = $s3->getObjectsByBucket("my-own-bucket");
foreach($list as $name) {
echo "I have $name key:\n";
$data = $s3->getObject("my-own-bucket/$name");
echo "with data: $data\n";
}

• isObjectAvailable($object) checks if the object with given name exists.

1248
Zend_Service

• putFile($path, $object, $meta) puts the content of the file in $path into the object
named $object.

The optional $meta argument is the same as for putObject. If the content type is omitted,
it will be guessed basing on the source file name.

15.8. Data Streaming


It is possible to get and put objects using not stream data held in memory but files or PHP streams.
This is especially useful when file sizes are large in order not to overcome memory limits.

To receive object using streaming, use method getObjectStream($object, $filename).


This method will return Zend_Http_Response_Stream, which can be used as described in
HTTP Client Data Streaming section.

Exemple 702. Zend_Service_Amazon_S3 Data Streaming Example

$response = $amazon->getObjectStream("mybycket/zftest");
// copy file
copy($response->getStreamName(), "my/downloads/file");
// use stream
$fp = fopen("my/downloads/file2", "w");
stream_copy_to_stream($response->getStream(), $fp);

Second parameter for getObjectStream() is optional and specifies target file to write the
data. If not specified, temporary file is used, which will be deleted after the respons eobject is
destroyed.

To send object using streaming, use putFileStream() which has the same signature as
putFile() but will use streaming and not read the file into memory.

Also, you can pass stream resource to putObject() method data parameter, in which case
the data will be read from the stream when sending the request to the server.

15.9. Stream wrapper


In addition to the interfaces described above, Zend_Service_Amazon_S3 also supports
operating as a stream wrapper. For this, you need to register the client object as the stream
wrapper:

Exemple 703. Zend_Service_Amazon_S3 Streams Example

require_once 'Zend/Service/Amazon/S3.php';

$s3 = new Zend_Service_Amazon_S3($my_aws_key, $my_aws_secret_key);

$s3->registerStreamWrapper("s3");

mkdir("s3://my-own-bucket");
file_put_contents("s3://my-own-bucket/testdata", "mydata");

echo file_get_contents("s3://my-own-bucket/testdata");

Directory operations (mkdir, rmdir, opendir, etc.) will operate on buckets and thus their
arguments should be of the form of s3://bucketname. File operations operate on objects.
Object creation, reading, writing, deletion, stat and directory listing is supported.

1249
Zend_Service

16. Zend_Service_Amazon_Sqs
16.1. Introduction
Amazon Simple Queue Service (Amazon SQS) offers a reliable, highly scalable, hosted queue
for storing messages as they travel between computers. By using Amazon SQS, developers can
simply move data between distributed components of their applications that perform different
tasks, without losing messages or requiring each component to be always available. Amazon
SQS makes it easy to build an automated workflow, working in close conjunction with the Amazon
Elastic Compute Cloud (Amazon EC2) and the other AWS infrastructure web services.

Amazon SQS works by exposing Amazon's web-scale messaging infrastructure as a web


service. Any computer on the Internet can add or read messages without any installed
software or special firewall configurations. Components of applications using Amazon SQS can
run independently, and do not need to be on the same network, developed with the same
technologies, or running at the same time.

16.2. Registering with Amazon SQS


Before you can get started with Zend_Service_Amazon_Sqs, you must first register for an
account. Please see the SQS FAQ page on the Amazon website for more information.

After registering, you will receive an application key and a secret key. You will need both to
access the SQS service.

16.3. API Documentation


The Zend_Service_Amazon_Sqs class provides the PHP wrapper to the Amazon SQS REST
interface. Please consult the Amazon SQS documentation for detailed description of the service.
You will need to be familiar with basic concepts in order to use this service.

16.4. Features
Zend_Service_Amazon_Sqs provides the following functionality:

• A single point for configuring your amazon.sqs authentication credentials that can be used
across the amazon.sqs namespaces.

• A proxy object that is more convenient to use than an HTTP client alone, mostly removing the
need to manually construct HTTP POST requests to access the REST service.

• A response wrapper that parses each response body and throws an exception if an error
occurred, alleviating the need to repeatedly check the success of many commands.

• Additional convenience methods for some of the more common operations.

16.5. Getting Started


Once you have registered with Amazon SQS, you're ready to create your queue and store some
messages on SQS. Each queue can contain unlimited amount of messages, identified by name.

The following example demonstrates creating a queue, storing and retrieving messages.

1250
Zend_Service

Exemple 704. Zend_Service_Amazon_Sqs Usage Example

$sqs = new Zend_Service_Amazon_Sqs($my_aws_key, $my_aws_secret_key);

$queue_url = $sqs->create('test');

$message = 'this is a test';


$message_id = $sqs->send($queue_url, $message);

foreach ($sqs->receive($queue_url) as $message) {


echo $message['body'].'<br/>';
}

Since the Zend_Service_Amazon_Sqs service requires authentication, you should pass your
credentials (AWS key and secret key) to the constructor. If you only use one account, you can
set default credentials for the service:

Zend_Service_Amazon_Sqs::setKeys($my_aws_key, $my_aws_secret_key);
$sqs = new Zend_Service_Amazon_Sqs();

16.6. Queue operations


All messages SQS are stored in queues. A queue has to be created before any message
operations. Queue names must be unique under your access key and secret key.

Queue names can contain lowercase letters, digits, periods (.), underscores (_), and dashes (-).
No other symbols allowed. Queue names can be a maximum of 80 characters.

• create() creates a new queue.

• delete() removes all messages in the queue.

Exemple 705. Zend_Service_Amazon_Sqs Queue Removal Example

$sqs = new Zend_Service_Amazon_Sqs($my_aws_key, $my_aws_secret_key);


$queue_url = $sqs->create('test_1');
$sqs->delete($queue_url);

• count() gets the approximate number of messages in the queue.

Exemple 706. Zend_Service_Amazon_Sqs Queue Count Example

$sqs = new Zend_Service_Amazon_Sqs($my_aws_key, $my_aws_secret_key);


$queue_url = $sqs->create('test_1');
$sqs->send($queue_url, 'this is a test');
$count = $sqs->count($queue_url); // Returns '1'

• getQueues() returns the list of the names of all queues belonging to the user.

Exemple 707. Zend_Service_Amazon_Sqs Queue Listing Example

$sqs = new Zend_Service_Amazon_Sqs($my_aws_key, $my_aws_secret_key);


$list = $sqs->getQueues();
foreach($list as $queue) {
echo "I have queue $queue\n";
}

1251
Zend_Service

16.7. Message operations


After a queue is created, simple messages can be sent into the queue then received at a later
point in time. Messages can be up to 8KB in length. If longer messages are needed please see
S3. There is no limit to the number of messages a queue can contain.

• sent($queue_url, $message) send the $message to the $queue_url SQS queue URL.

Exemple 708. Zend_Service_Amazon_Sqs Message Send Example

$sqs = new Zend_Service_Amazon_Sqs($my_aws_key, $my_aws_secret_key);


$queue_url = $sqs->create('test_queue');
$sqs->send($queue_url, 'this is a test message');

• receive($queue_url) retrieves messages from the queue.

Exemple 709. Zend_Service_Amazon_Sqs Message Receive Example

$sqs = new Zend_Service_Amazon_Sqs($my_aws_key, $my_aws_secret_key);


$queue_url = $sqs->create('test_queue');
$sqs->send($queue_url, 'this is a test message');
foreach ($sqs->receive($queue_url) as $message) {
echo "got message ".$message['body'].'<br/>';
}

• deleteMessage($queue_url, $handle) deletes a message from a queue. A message


must first be received using the receive() method before it can be deleted.

Exemple 710. Zend_Service_Amazon_Sqs Message Delete Example

$sqs = new Zend_Service_Amazon_Sqs($my_aws_key, $my_aws_secret_key);


$queue_url = $sqs->create('test_queue');
$sqs->send($queue_url, 'this is a test message');
foreach ($sqs->receive($queue_url) as $message) {
echo "got message ".$message['body'].'<br/>';

if ($sqs->deleteMessage($queue_url, $message['handle'])) {
echo "Message deleted";
}
else {
echo "Message not deleted";
}
}

17. Zend_Service_Audioscrobbler
17.1. Introduction
Zend_Service_Audioscrobbler is a simple API for using the Audioscrobbler REST
Web Service. The Audioscrobbler Web Service provides access to its database
of Users, Artists, Albums, Tracks, Tags, Groups, and Forums. The methods of
the Zend_Service_Audioscrobbler class begin with one of these terms. The
syntax and namespaces of the Audioscrobbler Web Service are mirrored in
Zend_Service_Audioscrobbler. For more information about the Audioscrobbler REST Web
Service, please visit the Audioscrobbler Web Service site.

1252
Zend_Service

17.2. Users
In order to retrieve information for a specific user, the setUser() method is first used to select
the user for which data are to be retrieved. Zend_Service_Audioscrobbler provides several
methods for retrieving data specific to a single user:

• userGetProfileInformation(): Returns a SimpleXML object containing the current


user's profile information.

• userGetTopArtists(): Returns a SimpleXML object containing a list of the current user's


most listened to artists.

• userGetTopAlbums(): Returns a SimpleXML object containing a list of the current user's


most listened to albums.

• userGetTopTracks(): Returns a SimpleXML object containing a list of the current user's


most listened to tracks.

• userGetTopTags(): Returns a SimpleXML object containing a list of tags most applied by


the current user.

• userGetTopTagsForArtist(): Requires that an artist be set via setArtist(). Returns


a SimpleXML object containing the tags most applied to the current artist by the current user.

• userGetTopTagsForAlbum(): Requires that an album be set via setAlbum(). Returns a


SimpleXML object containing the tags most applied to the current album by the current user.

• userGetTopTagsForTrack(): Requires that a track be set via setTrack(). Returns a


SimpleXML object containing the tags most applied to the current track by the current user.

• userGetFriends(): Returns a SimpleXML object containing the user names of the current
user's friends.

• userGetNeighbours(): Returns a SimpleXML object containing the user names of people


with similar listening habits to the current user.

• userGetRecentTracks(): Returns a SimpleXML object containing the 10 tracks most


recently played by the current user.

• userGetRecentBannedTracks(): Returns a SimpleXML object containing a list of the 10


tracks most recently banned by the current user.

• userGetRecentLovedTracks(): Returns a SimpleXML object containing a list of the 10


tracks most recently loved by the current user.

• userGetRecentJournals(): Returns a SimpleXML object containing a list of the current


user's most recent journal entries.

• userGetWeeklyChartList(): Returns a SimpleXML object containing a list of weeks for


which there exist Weekly Charts for the current user.

• userGetRecentWeeklyArtistChart(): Returns a SimpleXML object containing the most


recent Weekly Artist Chart for the current user.

• userGetRecentWeeklyAlbumChart(): Returns a SimpleXML object containing the most


recent Weekly Album Chart for the current user.

• userGetRecentWeeklyTrackChart(): Returns a SimpleXML object containing the most


recent Weekly Track Chart for the current user.

1253
Zend_Service

• userGetPreviousWeeklyArtistChart($fromDate, $toDate): Returns a


SimpleXML object containing the Weekly Artist Chart from $fromDate to $toDate for the
current user.

• userGetPreviousWeeklyAlbumChart($fromDate, $toDate): Returns a SimpleXML


object containing the Weekly Album Chart from $fromDate to $toDate for the current user.

• userGetPreviousWeeklyTrackChart($fromDate, $toDate): Returns a SimpleXML


object containing the Weekly Track Chart from $fromDate to $toDate for the current user.

Exemple 711. Retrieving User Profile Information

In this example, we use the setUser() and userGetProfileInformation() methods


to retrieve a specific user's profile information:

$as = new Zend_Service_Audioscrobbler();


// Set the user whose profile information we want to retrieve
$as->setUser('BigDaddy71');
// Retrieve BigDaddy71's profile information
$profileInfo = $as->userGetProfileInformation();
// Display some of it
print "Information for $profileInfo->realname "
. "can be found at $profileInfo->url";

Exemple 712. Retrieving a User's Weekly Artist Chart

$as = new Zend_Service_Audioscrobbler();


// Set the user whose profile weekly artist chart we want to retrieve
$as->setUser('lo_fye');
// Retrieves a list of previous weeks for which there are chart data
$weeks = $as->userGetWeeklyChartList();
if (count($weeks) < 1) {
echo 'No data available';
}
sort($weeks); // Order the list of weeks

$as->setFromDate($weeks[0]); // Set the starting date


$as->setToDate($weeks[0]); // Set the ending date

$previousWeeklyArtists = $as->userGetPreviousWeeklyArtistChart();

echo 'Artist Chart For Week Of '


. date('Y-m-d h:i:s', $as->from_date)
. '<br />';

foreach ($previousWeeklyArtists as $artist) {


// Display the artists' names with links to their profiles
print '<a href="' . $artist->url . '">' . $artist->name . '</a><br />';
}

17.3. Artists
Zend_Service_Audioscrobbler provides several methods for retrieving data about a
specific artist, specified via the setArtist() method:

• artistGetRelatedArtists(): Returns a SimpleXML object containing a list of Artists


similar to the current Artist.

1254
Zend_Service

• artistGetTopFans(): Returns a SimpleXML object containing a list of Users who listen


most to the current Artist.

• artistGetTopTracks(): Returns a SimpleXML object containing a list of the current Artist's


top-rated Tracks.

• artistGetTopAlbums(): Returns a SimpleXML object containing a list of the current Artist's


top-rated Albums.

• artistGetTopTags(): Returns a SimpleXML object containing a list of the Tags most


frequently applied to current Artist.

Exemple 713. Retrieving Related Artists

$as = new Zend_Service_Audioscrobbler();


// Set the artist for whom you would like to retrieve related artists
$as->setArtist('LCD Soundsystem');
// Retrieve the related artists
$relatedArtists = $as->artistGetRelatedArtists();
foreach ($relatedArtists as $artist) {
// Display the related artists
print '<a href="' . $artist->url . '">' . $artist->name . '</a><br />';
}

17.4. Tracks
Zend_Service_Audioscrobbler provides two methods for retrieving data specific to a single
track, specified via the setTrack() method:

• trackGetTopFans(): Returns a SimpleXML object containing a list of Users who listen most
to the current Track.

• trackGetTopTags(): Returns a SimpleXML object containing a list of the Tags most


frequently applied to the current Track.

17.5. Tags
Zend_Service_Audioscrobbler provides several methods for retrieving data specific to a
single tag, specified via the setTag() method:

• tagGetOverallTopTags(): Returns a SimpleXML object containing a list of Tags most


frequently used on Audioscrobbler.

• tagGetTopArtists(): Returns a SimpleXML object containing a list of Artists to whom the


current Tag was most frequently applied.

• tagGetTopAlbums(): Returns a SimpleXML object containing a list of Albums to which the


current Tag was most frequently applied.

• tagGetTopTracks(): Returns a SimpleXML object containing a list of Tracks to which the


current Tag was most frequently applied.

17.6. Groups
Zend_Service_Audioscrobbler provides several methods for retrieving data specific to a
single group, specified via the setGroup() method:

• groupGetRecentJournals(): Returns a SimpleXML object containing a list of recent


journal posts by Users in the current Group.

1255
Zend_Service

• groupGetWeeklyChart(): Returns a SimpleXML object containing a list of weeks for which


there exist Weekly Charts for the current Group.

• groupGetRecentWeeklyArtistChart(): Returns a SimpleXML object containing the


most recent Weekly Artist Chart for the current Group.

• groupGetRecentWeeklyAlbumChart(): Returns a SimpleXML object containing the most


recent Weekly Album Chart for the current Group.

• groupGetRecentWeeklyTrackChart(): Returns a SimpleXML object containing the most


recent Weekly Track Chart for the current Group.

• groupGetPreviousWeeklyArtistChart($fromDate, $toDate): Requires


setFromDate() and setToDate(). Returns a SimpleXML object containing the Weekly
Artist Chart from the current fromDate to the current toDate for the current Group.

• groupGetPreviousWeeklyAlbumChart($fromDate, $toDate): Requires


setFromDate() and setToDate(). Returns a SimpleXML object containing the Weekly
Album Chart from the current fromDate to the current toDate for the current Group.

• groupGetPreviousWeeklyTrackChart($fromDate, $toDate): Returns a


SimpleXML object containing the Weekly Track Chart from the current fromDate to the current
toDate for the current Group.

17.7. Forums
Zend_Service_Audioscrobbler provides a method for retrieving data specific to a single
forum, specified via the setForum() method:

• forumGetRecentPosts(): Returns a SimpleXML object containing a list of recent posts in


the current forum.

18. Zend_Service_Delicious
18.1. Introduction
Zend_Service_Delicious est une API pour accéder aux Web services XML et JSON de
del.icio.us. Ce composant vous donne, si vous avez les droits, un accès en lecture-écriture à
vos entrées sur del.icio.us. Il permet également un accès en lecture seule aux données de tous
les utilisateurs.

Exemple 714. Récupérer toutes vos entrées

$delicious = new Zend_Service_Delicious('identifiant', 'mot_de_passe');


$posts = $delicious->getAllPosts();

foreach ($posts as $post) {


echo "--\n";
echo "Titre: {$post->getTitle()}\n";
echo "Url: {$post->getUrl()}\n";
}

18.2. Récupérer vos entrées


Zend_Service_Delicious fournis trois méthodes pour récupérer vos entrées : getPosts(),
getRecentPosts() et getAllPosts(). Elles retournent toutes une instance de la classe
Zend_Service_Delicious_PostList, qui contient toutes les entrées récupérées.

1256
Zend_Service

/**
* Récupère les entrées correspondants aux arguments. Si la date ou
* l'url n'est pas précisée, la date la plus récente
* sera prise en compte.
*
* @param string $tag Optionnel pour filtrer par tag
* @param Zend_Date $dt Optionnel pour filtrer par date
* @param string $url Optionnel pour filtrer par url
* @return Zend_Service_Delicious_PostList
*/
public function getPosts($tag = null, $dt = null, $url = null);

/**
* Récupère les dernières entrées
*
* @param string $tag Optionnel pour filtrer par tag
* @param string $count Nombre maximum d'entrées à récupérer
* (15 par défaut)
* @return Zend_Service_Delicious_PostList
*/
public function getRecentPosts($tag = null, $count = 15);

/**
* Récupère toutes les entrées
*
* @param string $tag Optionnel pour filtrer par tag
* @return Zend_Service_Delicious_PostList
*/
public function getAllPosts($tag = null);

18.3. Zend_Service_Delicious_PostList
Des instances de cette classe sont retournées par les méthodes
getPosts(), getAllPosts(),getRecentPosts(), et getUserPosts() de
Zend_Service_Delicious.

Pour faciliter l'accès au données cette classe implémente les interfaces Countable, Iterator,
etArrayAccess.

Exemple 715. Accéder à la liste des entrées

$delicious = new Zend_Service_Delicious('nom_d_utilisateur',


'mot_de_passe');
$posts = $delicious->getAllPosts();

// Affiche le nombre d'entrées


echo count($posts);

// Itération sur les entrées


foreach ($posts as $post) {
echo "--\n";
echo "Titre: {$post->getTitle()}\n";
echo "Url: {$post->getUrl()}\n";
}

// Affiche une entrée en utilisant un tableau


echo $posts[0]->getTitle();

1257
Zend_Service

Dans cette implémentation les méthodes ArrayAccess::offsetSet() et


ArrayAccess::offsetUnset() lèvent des exceptions. Ainsi, du code tel que
unset($posts[0]); ou $posts[0] = 'A'; lèvera une exception car ces
propriétés sont en lecture seule.

Les objets d'entrées ont deux capacités de filtrage incorporées. Les entrées peuvent être filtrées
par étiquette et URL.

Exemple 716. Filtrage d'une entrée par une étiquette spécifique

Les entrées peuvent être filtrées par une (des) étiquette(s) spécifique(s) en utilisant
withTags(). Par confort, withTag() est aussi fourni quand il est nécessaire 'e ne
spécifier qu'une seule étiquette

$delicious = new Zend_Service_Delicious('nom_d_utilisateur',


'mot_de_passe');
$posts = $delicious->getAllPosts();

// Affiche les entrées ayant les étiquettes "php" et "zend"


foreach ($posts->withTags(array('php', 'zend')) as $post) {
echo "Title: {$post->getTitle()}\n";
echo "Url: {$post->getUrl()}\n";
}

Exemple 717. Filtrage d'une entrée par URL

Les entrées peuvent être filtrées par URL correspondant à une expression régulière
spécifiée en utilisant la méthode withUrl() :

$delicious = new Zend_Service_Delicious('nom_d_utilisateur',


'mot_de_passe');
$posts = $delicious->getAllPosts();

// Affiche les entrées ayant "help" dans l'URL


foreach ($posts->withUrl('/help/') as $post) {
echo "Title: {$post->getTitle()}\n";
echo "Url: {$post->getUrl()}\n";
}

18.4. Édition des entrées


Exemple 718. Édition d'une entrée

$delicious = new Zend_Service_Delicious('nom_d_utilisateur',


'mot_de_passe');
$posts = $delicious->getPosts();

// change le titre
$posts[0]->setTitle('Nouveau Titre');
// sauvegarde le changement
$posts[0]->save();

1258
Zend_Service

Exemple 719. Enchaînement des appels de méthode

Toutes les méthodes "setter" renvoient l'objet Zend_Service_Delicious_PostList


vous pouvez donc chaîner les appels aux méthodes en utilisant une interface fluide.

$delicious = new Zend_Service_Delicious('nom_d_utilisateur',


'mot_de_passe');
$posts = $delicious->getPosts();

$posts[0]->setTitle('Nouveau Titre')
->setNotes('Nouvelle note')
->save();

18.5. Supprimer des entrées


Il y a deux moyens de supprimer une entrée, en spécifiant son URL ou en appelant la méthode
delete() sur un objet Zend_Service_Delicious_PostList.

Exemple 720. Suppression d'une entrée

$delicious = new Zend_Service_Delicious('nom_d_utilisateur',


'mot_de_passe');

// en spécifiant l' URL


$delicious->deletePost('http://framework.zend.com');

// en appelant la méthode de l'objet Zend_Service_Delicious_PostList


$posts = $delicious->getPosts();
$posts[0]->delete();

// une autre façon d'utiliser deletePost()


$delicious->deletePost($posts[0]->getUrl());

18.6. Ajout d'entrées


Pour ajouter une entrée vous devez appeler la méthode createNewPost(), qui renvoie
un objet Zend_Service_Delicious_Post. Quand vous éditez l'entrée, vous devez la
sauvegarder dans la base de donnée de del.icio.us en appelant la méthode save().

Exemple 721. Ajouter une entrée

$delicious = new Zend_Service_Delicious('nom_d_utilisateur',


'mot_de_passe');

// créé et sauvegarde une nouvelle entrée (en chainant les méthodes)


$delicious->createNewPost('Zend Framework', 'http://framework.zend.com')
->setNotes('Page d\'accueil de Zend Framework')
->save();

// créé et sauvegarde une nouvelle entrée (sans enchaîner les méthodes)


$newPost = $delicious->createNewPost('Zend Framework',
'http://framework.zend.com');
$newPost->setNotes('Page d\'accueil de Zend Framework');
$newPost->save();

1259
Zend_Service

18.7. Les étiquettes ("tags")


Exemple 722. Récupérer les étiquettes

$delicious = new Zend_Service_Delicious('nom_d_utilisateur',


'mot_de_passe');

// récupère tous les étiquettes


print_r($delicious->getTags());

// renomme l'étiquette "ZF" en "zendFramework"


$delicious->renameTag('ZF', 'zendFramework');

18.8. Les groupes d'étiquettes


Exemple 723. Gestion des groupes d'étiquette

$delicious = new Zend_Service_Delicious('nom_d_utilisateur',


'mot_de_passe');

// récupère tous les groupes


print_r($delicious->getBundles());

// efface le groupe someBundle


$delicious->deleteBundle('someBundle');

// ajoute un groupe
$delicious->addBundle('newBundle', array('tag1', 'tag2'));

18.9. Données publiques


L'API Web del.icio.us autorise l'accès aux données publiques de tous les utilisateurs.

Tableau 132. Méthodes pour récupérer les données publiques

Nom Description Type de retour


getUserFans() Récupère les fans d'un Array
utilisateur
getUserNetwork() Récupère le réseau d'un Array
utilisateur
getUserPosts() Récupère les entrées d'un Zend_Service_Delicious_PostList
utilisateur
getUserTags() Récupère les étiquettes d'un Array
utilisateur

Si vous utilisez uniquement ces méthodes, le nom d'utilisateur et le


mot de passe ne sont pas obligatoires pour créer un nouvel objet
Zend_Service_Delicious.

1260
Zend_Service

Exemple 724. Récupérer les données publiques

// nom d'utilisateur et mot de passe optionnels


$delicious = new Zend_Service_Delicious();

// récupère les fans de l'utilisateur someUser


print_r($delicious->getUserFans('someUser'));

// récupère le réseau de l'utilisateur someUser


print_r($delicious->getUserNetwork('someUser'));

// récupère les Tags de l'utilisateur someUser


print_r($delicious->getUserTags('someUser'));

18.9.1. Entrées publiques


Quand vous récupérez des entrées publiques, la méthode getUserPosts()
retourne un objet Zend_Service_Delicious_PostList qui contient des objets
Zend_Service_Delicious_SimplePost. Ces derniers contiennent des informations
basiques sur l'entrée : URL, title, notes, and tags.

Tableau 133. Méthodes de la classe Zend_Service_Delicious_SimplePost

Nom Description Type de retour


getNotes() Récupère les notes de l'entrée String
getTags() Récupère les étiquettes de Array
l'entrée
getTitle() Récupère le titre de l'entrée String
getUrl() Récupère l'URL de l'entrée String

18.10. Client HTTP


Zend_Service_Delicious utilise Zend_Rest_Client pour effectuer les requêtes
HTTP sur le Web service de del.icio.us. Pour modifier le client HTTP utiliser par
Zend_Service_Delicious, vous devez modifier le client HTTP de Zend_Rest_Client.

Exemple 725. Modifier le client HTTP de Zend_Rest_Client

$myHttpClient = new My_Http_Client();


Zend_Rest_Client::setHttpClient($myHttpClient);

Quand vous effectuez plus d'une requête avec Zend_Service_Delicious vous pouvez
accélérez vos requêtes en configurant votre client HTTP pour qu'il ne ferme pas les connexions.

Exemple 726. Configurer votre client HTTP pour qu'il ne ferme pas les connexions

Zend_Rest_Client::getHttpClient()->setConfig(array(
'keepalive' => true
));

En raison de quelques problèmes de del.icio.us avec 'ssl2' (environs 2


secondes pour une requête), quand un objet Zend_Service_Delicious est

1261
Zend_Service

construit, le transport SSL de Zend_Rest_Client est configuré sur 'ssl' au


lieu de la valeur par défaut 'ssl2'.

19. Zend_Service_DeveloperGarden
19.1. Introduction to DeveloperGarden
DeveloperGarden is the name for the "Open Development services" of the German Telekom.
The "Open Development services" are a set of SOAP API Services.

The family of Zend_Service_DeveloperGarden components provides a clean and simple


interface to the DeveloperGarden API and additionally offers functionality to improve handling
and performance.

• BaseUserService: Class to manage API quota and user accounting details.

• IpLocation: Locale the given IP and returns geo coordinates. Works only with IPs allocated in
the network of the german telekom.

• LocalSearch: Allows you to search with options nearby or around a given geo coordinate or
city.

• SendSms: Send a Sms or Flash Sms to a given number.

• SmsValidation: You can validate a number to use it with SendSms for also supply a back
channel.

• VoiceCall: Initiates a call between two numbers.

• ConferenceCall: You can configure a whole conference room with participants for an adhoc
conference or you can also schedule your conference.

The backend SOAP API is documented here.

19.1.1. Sign Up for an Account


Before you can start using the DeveloperGarden API, you must first sign up for an account.

19.1.2. The Environment


With the DeveloperGarden API you have the possibility to choose 3 different environments to
work on.

• production: In Production environement you have to pay for calls, sms and other payable
services.

• sandbox: In the Sandbox mode you can use the same features with some limitations like in
the production just without to pay for them. Normally during development you can test your
application.

• mock: The Mock environment allows you to build your application and have results but you
don not initiate any action on the API side.

For every environment and service are some special features (options) available for testing.
Please look here for details.

1262
Zend_Service

19.1.3. Your configuration


You can pass to all classes an array of configuration values. Possible values are:

• username: Your DeveloperGarden API username.

• password: Your DeveloperGarden API password.

• environment: The environment that you selected.

Exemple 727. Configuration Example

require_once 'Zend/Service/DeveloperGarden/SendSms.php';
$config = array(
'username' => 'yourUsername',
'password' => 'yourPassword',
'environment' => Zend_Service_DeveloperGarden_SendSms::ENV_PRODUCTION,
);
$service = new Zend_Service_DeveloperGarden_SendSms($config);

19.2. BaseUserService
The class can be used to set and get quota values for the services and to fetch account details.

The getAccountBalance() method is there to fetch an array of account id's with the current
balance status (credits).

Exemple 728. Get account balance example

$service = new Zend_Service_DeveloperGarden_BaseUserService($config);


print_r($service->getAccountBalance());

19.2.1. Get quota information


You can fetch quota informations for a specific service module with the provided methods.

Exemple 729. Get quota information example

$service = new Zend_Service_DeveloperGarden_BaseUserService($config);


$result = $service->getSmsQuotaInformation(
Zend_Service_DeveloperGarden_BaseUserService::ENV_PRODUCTION
);
echo 'Sms Quota:<br />';
echo 'Max Quota: ', $result->getMaxQuota(), '<br />';
echo 'Max User Quota: ', $result->getMaxUserQuota(), '<br />';
echo 'Quota Level: ', $result->getQuotaLevel(), '<br />';

You get a Result object that contains all information that you need, optional you can pass to
the QuotaInformation method the environment constant to fetch the quota for the specific
environment.

Here a list of all getQuotaInformation methods:

• getConfernceCallQuotaInformation()

• getIPLocationQuotaInformation()

• getLocalSearchQuotaInformation()

1263
Zend_Service

• getSmsQuotaInformation()

• getVoiceCallQuotaInformation()

19.2.2. Change quota information


To change the current quota use one of the changeQuotaPool methods. First parameter is the
new pool value and the second one is the environment.

Exemple 730. Change quota information example

$service = new Zend_Service_DeveloperGarden_BaseUserService($config);


$result = $service->changeSmsQuotaPool(
1000,
Zend_Service_DeveloperGarden_BaseUserService::ENV_PRODUCTION
);
if (!$result->hasError()) {
echo 'updated Quota Pool';
}

Here a list of all changeQuotaPool methods:

• changeConferenceCallQuotaPool()

• changeIPLocationQuotaPool()

• changeLocalSearchQuotaPool()

• changeSmsQuotaPool()

• changeVoiceCallQuotaPool()

19.3. IP Location
This service allows you to retrieve location information for a given IP address.

There are some limitations:

• The IP address must be in the T-Home network

• Just the next big city will be resolved

• IPv6 is not supported yet

Exemple 731. Locate a given IP

$service = new Zend_Service_DeveloperGarden_IpLocation($config);


$service->setEnvironment(
Zend_Service_DeveloperGarden_IpLocation::ENV_MOCK
);
$ip = new Zend_Service_DeveloperGarden_IpLocation_IpAddress('127.0.0.1');
print_r($service->locateIp($ip));

19.4. Local Search


The Local Search service provides the local search machine suchen.de via a the web service
interface. For more details, refer to the documentation.

1264
Zend_Service

Exemple 732. Locate a Restaurant

$service = new Zend_Service_DeveloperGarden_LocalSearch($config);


$search = new Zend_Service_DeveloperGarden_LocalSearch_SearchParameters();
/**
* @see http://www.developergarden.com/static/docu/en/ch04s02s06s04.html
*/
$search->setWhat('pizza')
->setWhere('jena');
print_r($service->localSearch($search));

19.5. Send SMS


The Send SMS service is used to send normal and Flash SMS to any number.

The following restrictions apply to the use of the SMS service:

• An SMS or Flash SMS in the production environment must not be longer than 765 characters
and must not be sent to more than 10 recipients.

• An SMS or Flash SMS in the sandbox environment is shortened and enhanced by a note in
the DeveloperGarden. The maximum length of the message sent is 160 characters.
• In the sandbox environment, a maximum of 10 SMS can be sent per day.

• The following characters are counted twice: | ^ € { } [ ] ~ \ LF (line break)

• If an SMS or Flash SMS is longer than 160 characters, one message is charged for each 153
characters (quota and credit).

• Delivery cannot be guaranteed for SMS or Flash SMS to landline numbers.

• The sender can exist of a maximum of 11 characters. Permitted characters are letters and
numbers.

• The specification of a phone number as the sender is only permitted if the phone number has
been validated. (See: SMS Validation)

Exemple 733. Sending an SMS

$service = new Zend_Service_DeveloperGarden_SendSms($config);


$sms = $service->createSms(
'+49-172-123456; +49-177-789012',
'your test message',
'yourname'
);
print_r($service->send($sms));

19.6. SMS Validation


The SMS Validation service allows the validation of physical phone number to be used as the
sender of an SMS.

First, call setValidationKeyword() to receive an SMS with a keyword.

After you get your keyword, you have to use the validate() to validate your number with the
keyword against the service.

With the method getValidatedNumbers(), you will get a list of all already validated numbers
and the status of each.

1265
Zend_Service

Exemple 734. Request validation keyword

$service = new Zend_Service_DeveloperGarden_SmsValidation($config);


print_r($service->sendValidationKeyword('+49-172-123456'));

Exemple 735. Validate a number with a keyword

$service = new Zend_Service_DeveloperGarden_SmsValidation($config);


print_r($service->validate('TheKeyWord', '+49-172-123456'));

To invalidate a validated number, call the method inValidate().

19.7. Voice Call


The Voice Call service is used for setting up a voice connection between two telephone
connections. For specific details please read the API Documentation.

Normally the Service works as followed:

• Call the first participant.

• If the connection is successful, call the second participant.

• If second participant connects succesfully, both participants are connected.

• The call is open until one of the participants hangs up or the expire mechanism intercepts.

Exemple 736. Call two numbers

$service = new Zend_Service_DeveloperGarden_VoiceCall($config);


$aNumber = '+49-30-000001';
$bNumber = '+49-30-000002';
$expiration = 30; // seconds
$maxDuration = 300; // 5 mins
$newCall = $service->newCall($aNumber, $bNumber, $expiration, $maxDuration);
echo $newCall->getSessionId();

If the call is initiated, you can ask the result object for the session ID and use this session ID for
an additional call to the callStatus or tearDownCall() methods. The second parameter on
the callStatus() method call extends the expiration for this call.

Exemple 737. Call two numbers, ask for status, and cancel

$service = new Zend_Service_DeveloperGarden_VoiceCall($config);


$aNumber = '+49-30-000001';
$bNumber = '+49-30-000002';
$expiration = 30; // seconds
$maxDuration = 300; // 5 mins

$newCall = $service->newCall($aNumber, $bNumber, $expiration, $maxDuration);

$sessionId = $newCall->getSessionId();

$service->callStatus($sessionId, true); // extend the call

sleep(10); // sleep 10s and then tearDown

$service->tearDownCall($sessionId);

1266
Zend_Service

19.8. ConferenceCall
Conference Call allows you to setup and start a phone conference.

The following features are available:

• Conferences with an immediate start

• Conferences with a defined start date

• Recurring conference series

• Adding, removing, and muting of participants from a conference

• Templates for conferences

Here is a list of currently implemented API methods:

• createConference() creates a new conference

• updateConference() updates an existing conference

• commitConference() saves the conference, and, if no date is configured, immediately


starts the conference

• removeConference() removes a conference

• getConferenceList() returns a list of all configured conferences

• getConferenceStatus() displays information for an existing conference

• getParticipantStatus() displays status information about a conference participant

• newParticipant() creates a new participant

• addParticipant() adds a participant to a conference

• updateParticipant() updates a participant, usually to mute or redial the participant

• removeParticipant() removes a participant from a conference

• getRunningConference() requests the running instance of a planned conference

• createConferenceTemplate() creates a new conference template

• getConferenceTemplate() requests an existing conference template

• updateConferenceTemplate() updates existing conference template details

• removeConferenceTemplate() removes a conference template

• getConferenceTemplateList() requests all conference templates of an owner

• addConferenceTemplateParticipant() adds a conference participant to conference


template

• getConferenceTemplateParticipant() displays details of a participant of a conference


template

• updateConferenceTemplateParticipant() updates participant details within a


conference template

1267
Zend_Service

• removeConferenceTemplateParticipant() removes a participant from a conference


template

Exemple 738. Ad-Hoc conference

$client = new Zend_Service_DeveloperGarden_ConferenceCall($config);

$conferenceDetails = new Zend_Service_DeveloperGarden_ConferenceCall_ConferenceDetail(


'Zend-Conference', // name for the conference
'this is my private zend conference', // description
60 // duration in seconds
);

$conference = $client->createConference('MyName', $conferenceDetails);

$part1 = new Zend_Service_DeveloperGarden_ConferenceCall_ParticipantDetail(


'Jon',
'Doe',
'+49-123-4321',
'your.name@example.com',
true
);

$client->newParticipant($conference->getConferenceId(), $part1);
// add a second, third ... participant

$client->commitConference($conference->getConferenceId());

19.9. Performance and Caching


You can setup various caching options to improve the performance for resolving WSDL and
authentication tokens.

First of all, you can setup the internal SoapClient (PHP) caching values.

Exemple 739. WSDL cache options

Zend_Service_DeveloperGarden_SecurityTokenServer_Cache::setWsdlCache([PHP CONSTANT]);

The [PHP CONSTANT] can be one of the following values:

• WSDL_CACHE_DISC: enabled disc caching

• WSDL_CACHE_MEMORY: enabled memory caching

• WSDL_CACHE_BOTH: enabled disc and memory caching

• WSDL_CACHE_NONE: disabled both caching

If you want also to cache the result for calls to the SecuritTokenServer you can setup a
Zend_Cache instance and pass it to the setCache().

Exemple 740. SecurityTokenServer cache option

$cache = Zend_Cache::factory('Core', ...);


Zend_Service_DeveloperGarden_SecurityTokenServer_Cache::setCache($cache);

1268
Zend_Service

20. Zend_Service_Flickr
20.1. Introduction
Zend_Service_Flickr est une API simple pour utiliser le service Web REST de Flick. Pour
pouvoir utiliser les services Web Flickr, vous devez avoir une clé d'utilisation de l'API. Pour
obtenir une telle clé, et pour plus d'information sur le service Web REST de Flickr, veuillez vous
référez à la documentation de l'API Flickr.

Dans l'exemple suivant, nous allons utiliser la méthode tagSearch() pour rechercher des
photos ayant "php" dans les tags.

Exemple 741. Simple recherche de photos sur Flickr

$flickr = new Zend_Service_Flickr('MA_CLE_API');

$results = $flickr->tagSearch("php");

foreach ($results as $result) {


echo $result->title . '<br />';
}

Paramètres optionnels

tagSearch() accepte un tableau d'options comme second paramètre


optionnel.

20.2. Trouver les photos et les informations des utilisateurs Flickr


Zend_Service_Flickrfournit plusieurs façons différentes de récupérer des informations sur
les utilisateurs.

• userSearch(): Accepte une chaîne de caractère de balise délimitée par des espaces, et
un tableau d'options en second paramètre optionnel. Elle retourne un jeu de photos sous la
forme d'un objet Zend_Service_Flickr_ResultSet.

• getIdByUsername(): Retourne l'identifiant utilisateur, correspondant à son nom


d'utilisateur.

• getIdByEmail(): Retourne l'identifiant utilisateur correspondant à l'adresse émail donnée.

Exemple 742. Trouver les photos publiques d'un utilisateur Flickr par son adresse
émail

Dans cet exemple, nous havons une adresse émail d'un utilisateur Flickr, et nous
recherchons les photos publiques des utilisateurs en utilisant la méthode userSearch() :

$flickr = new Zend_Service_Flickr('MA_CLE_API');

$results = $flickr->userSearch($userEmail);

foreach ($results as $result) {


echo $result->title . '<br />';
}

1269
Zend_Service

20.3. Trouver des photos dans le pool d'un groupe


Zend_Service_Flickr vous permet de récupérer les photos issues du pool d'un groupe à
partir de son ID. Utilisez pour cela la méthode groupPoolGetPhotos() :

Exemple 743. Récupération les photos du pool d'un groupe grâce à son ID

$flickr = new Zend_Service_Flickr('MA_CLE_API');

$results = $flickr->groupPoolGetPhotos($groupId);

foreach ($results as $result) {


echo $result->title . '<br />';
}

Paramètre optionnel
groupPoolGetPhotos() accepte un second paramètre optionnel sous la
forme d'un tableau d'options.

20.4. Récupérer les détails d'une image


Zend_Service_Flickr permet de récupérer facilement et rapidement, les détails d'une image
grâce à son ID. Utilisez simplement la méthode getImageDetails(), comme dans l'exemple
suivant :

Exemple 744. Récupérer les détails d'une image

Une fois que vous avez l'identifiant de l'image Flickr, il est simple de retrouver les
informations qui lui sont associées :

$flickr = new Zend_Service_Flickr('MA_CLE_API');

$image = $flickr->getImageDetails($imageId);

echo "ID de l'image : $imageId, taille : "


. "$image->width x $image->height pixels.<br />\n";
echo "<a href=\"$image->clickUri\">Clicker pour l'image</a>\n";

20.5. Classes de résultats Zend_Service_Flickr


Les classes suivantes sont toutes retournées par tagSearch() et userSearch() :

• Zend_Service_Flickr_ResultSet

• Zend_Service_Flickr_Result

• Zend_Service_Flickr_Image

20.5.1. Zend_Service_Flickr_ResultSet
Représente le jeu de résultats d'une recherche sur Flickr.

Implémente l'itérateur SeekableIterator (ie en utilisant foreach), ainsi


qu'un accès direct à un résultat particulier en utilisant seek().

1270
Zend_Service

20.5.1.1. Propriétés

Tableau 134. Propriétés Zend_Service_Flickr_ResultSet

Nom Type Description


totalResultsAvailable int Nombre total de résultats
disponibles
totalResultsReturned int Nombre total de résultats
retournés
firstResultPosition int ??? The offset in the total result
set of this result set ???

20.5.1.2. Zend_Service_Flickr_ResultSet::totalResults()

int totalResults();

Retourne le nombre de totale de résultats dans ce jeu de résultats.

Retour à la liste des classes

20.5.2. Zend_Service_Flickr_Result

Un seule image résultant d'une requête sur Flickr.

20.5.2.1. Propriétés

Tableau 135. Propriétés Zend_Service_Flickr_Result

Nom Type Description


id string Identifiant de l'image
owner string Le NSID du propriétaire de la
photo.
secret string La clé utilisée dans la
construction de l'URL.
server string Le nom du serveur à utiliser
pour construire l'URL.
title string Le titre de la photo.
ispublic string La photo est publique.
isfriend string Vous pouvez voir la photo
parce que vous êtes un ami du
propriétaire de cette photo.
isfamily string Vous pouvez voir la photo
parce que vous êtes de la
famille du propriétaire de cette
photo.
license string La licence sous laquelle cette
photo est disponible.
dateupload string La date à laquelle la photo a
été uploadée.

1271
Zend_Service

Nom Type Description


datetaken string La date à laquelle la photo a
été prise.
ownername string Le screenname du propriétaire
de la photo.
iconserver string Le serveur utilisé pour
l'assemblage des ??? icon
URLs ???.
Square Zend_Service_Flickr_Image Une miniature de l'image au
format 75x75 pixels.
Thumbnail Zend_Service_Flickr_Image Une miniature de l'image de
100 pixels.
Small Zend_Service_Flickr_Image Une version en 240 pixels de
l'image.
Medium Zend_Service_Flickr_Image Une version en 500 pixel
version de l'image.
Large Zend_Service_Flickr_Image Une version en 640 pixel
version de l'image.
Original Zend_Service_Flickr_Image L'image originale.

Retour à la liste des classes

20.5.3. Zend_Service_Flickr_Image
Représente une image retournée pour une recherche Flickr.

20.5.3.1. Propriétés

Tableau 136. Propriétés Zend_Service_Flickr_Image


Nom Type Description
uri string URI de l'image originale.
clickUri string URI cliquable (ie la page Flickr)
de l'image.
width int Largeur de l'image.
height int Hauteur de l'image.

Retour à la liste des classes

21. Zend_Service_LiveDocx
21.1. Introduction to LiveDocx
LiveDocx is a SOAP service that allows developers to generate word processing documents by
combining structured data from PHP with a template, created in a word processor. The resulting
document can be saved as a PDF, DOCX, DOC, HTML or RTF file. LiveDocx implements mail-
merge in PHP.

The family of Zend_Service_LiveDocx components provides a clean and simple interface to


the LiveDocx API and additionally offers functionality to improve network performance.

1272
Zend_Service

In addition to this section of the manual, if you are interested in learning more about
Zend_Service_LiveDocx and the backend SOAP service LiveDocx, please take a look at the
following resources:

• Shipped demonstration applications. There are a large number of demonstration applications


in the directory /demos/Zend/Service/LiveDocx of the Zend Framework distribution file or trunk
version, checked out of the standard SVN repository. These are designed to get you up to
speed with Zend_Service_LiveDocx within a matter of minutes.

• Zend_Service_LiveDocx blog and web site.

• LiveDocx SOAP API documentation.

• LiveDocx WSDL.

• LiveDocx blog and web site.

21.1.1. Sign Up for an Account


Before you can start using LiveDocx, you must first sign up for an account. The account is
completely free of charge and you only need to specify a username, password and e-mail
address. Your login credentials will be dispatched to the e-mail address you supply, so please
type carefully.

21.1.2. Templates and Documents


LiveDocx differentiates between the following terms: 1) template and 2) document. In order
to fully understand the documentation and indeed the actual API, it is important that any
programmer deploying LiveDocx understands the difference.

The term template is used to refer to the input file, created in a word processor, containing
formatting and text fields. You can download an example template, stored as a DOCX file. The
term document is used to refer to the output file that contains the template file, populated with
data - i.e. the finished document. You can download an example document, stored as a PDF file.

21.1.3. Supported File Formats


LiveDocx supports the following file formats:

21.1.3.1. Template File Formats (input)

Templates can be saved in any of the following file formats:

• DOCX - Office Open XML format

• DOC - Microsoft Word DOC format

• RTF - Rich text file format

• TXD - TX Text Control format

21.1.3.2. Document File Formats (output):

The resulting document can be saved in any of the following file formats:

• DOCX - Office Open XML format

• DOC - Microsoft Word DOC format

• HTML - XHTML 1.0 transitional format

1273
Zend_Service

• RTF - Rich text file format

• PDF - Acrobat Portable Document Format

• TXD - TX Text Control format

• TXT - ANSI plain text

21.1.3.3. Image File Formats (output):

The resulting document can be saved in any of the following graphical file formats:

• BMP - Bitmap image format

• GIF - Graphics Interchange Format

• JPG - Joint Photographic Experts Group format

• PNG - Portable Network Graphics format

• TIFF - Tagged Image File Format

• WMF - Windows Meta File format

21.2. Zend_Service_LiveDocx_MailMerge
Zend_Service_LiveDocx_MailMerge is the mail-merge object in the
Zend_Service_LiveDocx family.

21.2.1. Document Generation Process


The document generation process can be simplified with the following equation:

Template + Data = Document

Or expressed by the following diagram:

1274
Zend_Service

Data is inserted into template to create a document (view larger).

A template, created in a word processing application, such as Microsoft Word, is loaded into
LiveDocx. Data is then inserted into the template and the resulting document is saved to any
supported format.

21.2.2. Creating Templates in Microsoft Word 2007

Start off by launching Microsoft Word and creating a new document. Next, open up the Field
dialog box. This looks as follows:

Microsoft Word 2007 Field dialog box (view larger).

Using this dialog, you can insert the required merge fields into your document. Below is a
screenshot of a license agreement in Microsoft Word 2007. The merge fields are marked as
{ MERGEFIELD FieldName }:

1275
Zend_Service

Template in Microsoft Word 2007 (view larger).

Now, save the template as template.docx.

In the next step, we are going to populate the merge fields with textual data from PHP.

Cropped template in Microsoft Word 2007 (view larger).

To populate the merge fields in the above cropped screenshot of the template in Microsoft Word,
all we have to code is as follows:

$phpLiveDocx = new Zend_Service_LiveDocx_MailMerge();

$phpLiveDocx->setUsername('myUsername')
->setPassword('myPassword');

$phpLiveDocx->setLocalTemplate('template.docx');

1276
Zend_Service

$phpLiveDocx->assign('software', 'Magic Graphical Compression Suite v1.9')


->assign('licensee', 'Henry Döner-Meyer')
->assign('company', 'Co-Operation');

$phpLiveDocx->createDocument();

$document = $phpLiveDocx->retrieveDocument('pdf');

file_put_contents('document.pdf', $document);

The resulting document is written to disk in the file document.pdf. This file can now be post-
processed, sent via e-mail or simply displayed, as is illustrated below in Document Viewer 2.26.1
on Ubuntu 9.04:

Resulting document as PDF in Document Viewer 2.26.1 (view larger).

21.2.3. Advanced Mail-Merge


Zend_Service_LiveDocx_MailMerge allows designers to insert any number of text fields
into a template. These text fields are populated with data when createDocument() is called.

In addition to text fields, it is also possible specify regions of a document, which should be
repeated.

1277
Zend_Service

For example, in a telephone bill it is necessary to print out a list of all connections, including
the destination number, duration and cost of each call. This repeating row functionality can be
achieved with so called blocks.

Blocks are simply regions of a document, which are repeated when createDocument() is
called. In a block any number of block fields can be specified.

Blocks consist of two consecutive document targets with a unique name. The following
screenshot illustrates these targets and their names in red:

(view larger).

The format of a block is as follows:

blockStart_ + unique name


blockEnd_ + unique name

For example:

blockStart_block1
blockEnd_block1

The content of a block is repeated, until all data assigned in the block fields has been injected
into the template. The data for block fields is specified in PHP as a multi-assoc array.

The following screenshot of a template in Microsoft Word 2007 shows how block fields are used:

1278
Zend_Service

Template, illustrating blocks in Microsoft Word 2007 (view larger).

The following code populates the above template with data.

$phpLiveDocx = new Zend_Service_LiveDocx_MailMerge();

$phpLiveDocx->setUsername('myUsername')
->setPassword('myPassword');

$phpLiveDocx->setLocalTemplate('template.doc');

$billConnections = array(
array(
'connection_number' => '+49 421 335 912',
'connection_duration' => '00:00:07',
'fee' => '€ 0.03',
),
array(
'connection_number' => '+49 421 335 913',
'connection_duration' => '00:00:07',
'fee' => '€ 0.03',
),
array(
'connection_number' => '+49 421 335 914',
'connection_duration' => '00:00:07',
'fee' => '€ 0.03',
),

1279
Zend_Service

array(
'connection_number' => '+49 421 335 916',
'connection_duration' => '00:00:07',
'fee' => '€ 0.03',
),
);

$phpLiveDocx->assign('connection', $billConnections);

// ... assign other data here ...

$phpLiveDocx->createDocument();
$document = $phpLiveDocx->retrieveDocument('pdf');
file_put_contents('document.pdf', $document);

The data, which is specified in the array $billConnections is repeated in the template in the
block connection. The keys of the array (connection_number, connection_duration and
fee) are the block field names - their data is inserted, one row per iteration.

The resulting document is written to disk in the file document.pdf. This file can now be post-
processed, sent via e-mail or simply displayed, as is illustrated below in Document Viewer 2.26.1
on Ubuntu 9.04:

Resulting document as PDF in Document Viewer 2.26.1 (view larger).

1280
Zend_Service

You can download the DOC template file and the resulting PDF document.

NOTE: blocks may not be nested.

21.2.4. Generating bitmaps image files

In addition to document file formats, Zend_Service_LiveDocx_MailMerge also allows


documents to be saved to a number of image file formats (BMP, GIF, JPG, PNG and TIFF). Each
page of the document is saved to one file.

The following sample illustrates the use of getBitmaps($fromPage, $toPage,


$zoomFactor, $format) and getAllBitmaps($zoomFactor, $format).

$fromPage is the lower-bound page number of the page range that should be returned as an
image and $toPage the upper-bound page number. $zoomFactor is the size of the images, as
a percent, relative to the original page size. The range of this parameter is 10 to 400. $format
is the format of the images returned by this method. The supported formats can be obtained by
calling getImageFormats().

$date = new Zend_Date();


$date->setLocale('en_US');

$phpLiveDocx = new Zend_Service_LiveDocx_MailMerge();

$phpLiveDocx->setUsername('myUsername')
->setPassword('myPassword');

$phpLiveDocx->setLocalTemplate('template.docx');

$phpLiveDocx->assign('software', 'Magic Graphical Compression Suite v1.9')


->assign('licensee', 'Daï Lemaitre')
->assign('company', 'Megasoft Co-operation')
->assign('date', $date->get(Zend_Date::DATE_LONG))
->assign('time', $date->get(Zend_Date::TIME_LONG))
->assign('city', 'Lyon')
->assign('country', 'France');

$phpLiveDocx->createDocument();

// Get all bitmaps


// (zoomFactor, format)
$bitmaps = $phpLiveDocx->getAllBitmaps(100, 'png');

// Get just bitmaps in specified range


// (fromPage, toPage, zoomFactor, format)
// $bitmaps = $phpLiveDocx->getBitmaps(2, 2, 100, 'png');

foreach ($bitmaps as $pageNumber => $bitmapData) {


$filename = sprintf('documentPage%d.png', $pageNumber);
file_put_contents($filename, $bitmapData);
}

This produces two files (documentPage1.png and documentPage2.png) and writes them to
disk in the same directory as the executable PHP file.

1281
Zend_Service

documentPage1.png (view larger).

1282
Zend_Service

documentPage2.png (view larger).

21.2.5. Local vs. Remote Templates


Templates can be stored locally, on the client machine, or remotely, on the server. There are
advantages and disadvantages to each approach.

In the case that a template is stored locally, it must be transfered from the client to the server on
every request. If the content of the template rarely changes, this approach is inefficient. Similarly,
if the template is several megabytes in size, it may take considerable time to transfer it to the
server. Local template are useful in situations in which the content of the template is constantly
changing.

The following code illustrates how to use a local template.

$phpLiveDocx = new Zend_Service_LiveDocx_MailMerge();

$phpLiveDocx->setUsername('myUsername')
->setPassword('myPassword');

$phpLiveDocx->setLocalTemplate('./template.docx');

// assign data and create document

1283
Zend_Service

In the case that a template is stored remotely, it is uploaded once to the server and then
simply referenced on all subsequent requests. Obviously, this is much quicker than using a local
template, as the template does not have to be transfered on every request. For speed critical
applications, it is recommended to use the remote template method.

The following code illustrates how to upload a template to the server:

$phpLiveDocx = new Zend_Service_LiveDocx_MailMerge();

$phpLiveDocx->setUsername('myUsername')
->setPassword('myPassword');

$phpLiveDocx->uploadTemplate('template.docx');

The following code illustrates how to reference the remotely stored template on all subsequent
requests:

$phpLiveDocx = new Zend_Service_LiveDocx_MailMerge();

$phpLiveDocx->setUsername('myUsername')
->setPassword('myPassword');

$phpLiveDocx->setRemoteTemplate('template.docx');

// assign data and create document

21.2.6. Getting Information

Zend_Service_LiveDocx_MailMerge provides a number of methods to get information on


field names, available fonts and supported formats.

Exemple 745. Get Array of Field Names in Template

The following code returns and displays an array of all field names in the specified template.
This functionality is useful, in the case that you create an application, in which an end-user
can update a template.

$phpLiveDocx = new Zend_Service_LiveDocx_MailMerge();

$phpLiveDocx->setUsername('myUsername')
->setPassword('myPassword');

$templateName = 'template-1-text-field.docx';
$phpLiveDocx->setLocalTemplate($templateName);

$fieldNames = $phpLiveDocx->getFieldNames();
foreach ($fieldNames as $fieldName) {
printf('- %s%s', $fieldName, PHP_EOL);
}

1284
Zend_Service

Exemple 746. Get Array of Block Field Names in Template

The following code returns and displays an array of all block field names in the specified
template. This functionality is useful, in the case that you create an application, in which an
end-user can update a template. Before such templates can be populated, it is necessary
to find out the names of the contained block fields.

$phpLiveDocx = new Zend_Service_LiveDocx_MailMerge();

$phpLiveDocx->setUsername('myUsername')
->setPassword('myPassword');

$templateName = 'template-block-fields.doc';
$phpLiveDocx->setLocalTemplate($templateName);

$blockNames = $phpLiveDocx->getBlockNames();
foreach ($blockNames as $blockName) {
$blockFieldNames = $phpLiveDocx->getBlockFieldNames($blockName);
foreach ($blockFieldNames as $blockFieldName) {
printf('- %s::%s%s', $blockName, $blockFieldName, PHP_EOL);
}
}

Exemple 747. Get Array of Fonts Installed on Server

The following code returns and displays an array of all fonts installed on the server. You can
use this method to present a list of fonts which may be used in a template. It is important
to inform the end-user about the fonts installed on the server, as only these fonts may be
used in a template. In the case that a template contains fonts, which are not available on
the server, font-substitution will take place. This may lead to undesirable results.

$phpLiveDocx = new Zend_Service_LiveDocx_MailMerge();

$phpLiveDocx->setUsername('myUsername')
->setPassword('myPassword');

Zend_Debug::dump($phpLiveDocx->getFontNames());

NOTE: As the return value of this method changes very infrequently, it is highly
recommended to use a cache, such as Zend_Cache - this will considerably speed up your
application.

Exemple 748. Get Array of Supported Template File Formats

The following code returns and displays an array of all supported template file formats. This
method is particularly useful in the case that a combo list should be displayed that allows
the end-user to select the input format of the documentation generation process.

$phpLiveDocx = new Zend_Service_LiveDocx_MailMerge()

$phpLiveDocx->setUsername('myUsername')
->setPassword('myPassword');

Zend_Debug::dump($phpLiveDocx->getTemplateFormats());

NOTE: As the return value of this method changes very infrequently, it is highly
recommended to use a cache, such as Zend_Cache - this will considerably speed up your
application.

1285
Zend_Service

Exemple 749. Get Array of Supported Document File Formats

The following code returns and displays an array of all supported document file formats. This
method is particularly useful in the case that a combo list should be displayed that allows
the end-user to select the output format of the documentation generation process.

$phpLiveDocx = new Zend_Service_LiveDocx_MailMerge();

$phpLiveDocx->setUsername('myUsername')
->setPassword('myPassword');

Zend_Debug::dump($phpLiveDocx->getDocumentFormats());

Exemple 750. Get Array of Supported Image File Formats

The following code returns and displays an array of all supported image file formats. This
method is particularly useful in the case that a combo list should be displayed that allows
the end-user to select the output format of the documentation generation process.

$phpLiveDocx = new Zend_Service_LiveDocx_MailMerge();

$phpLiveDocx->setUsername('myUsername')
->setPassword('myPassword');

Zend_Debug::dump($phpLiveDocx->getImageFormats());

NOTE: As the return value of this method changes very infrequently, it is highly
recommended to use a cache, such as Zend_Cache - this will considerably speed up your
application.

22. Zend_Service_Nirvanix
22.1. Introduction
Nirvanix provides an Internet Media File System (IMFS), an Internet storage service that allows
applications to upload, store and organize files and subsequently access them using a standard
Web Services interface. An IMFS is distributed clustered file system, accessed over the Internet,
and optimized for dealing with media files (audio, video, etc). The goal of an IMFS is to provide
massive scalability to deal with the challenges of media storage growth, with guaranteed access
and availability regardless of time and location. Finally, an IMFS gives applications the ability to
access data securely, without the large fixed costs associated with acquiring and maintaining
physical storage assets.

22.2. Registering with Nirvanix


Before you can get started with Zend_Service_Nirvanix, you must first register for an
account. Please see the Getting Started page on the Nirvanix website for more information.

After registering, you will receive a Username, Password, and Application Key. All three are
required to use Zend_Service_Nirvanix.

22.3. API Documentation


Access to the Nirvanix IMFS is available through both SOAP and a faster REST service.
Zend_Service_Nirvanix provides a relatively thin PHP 5 wrapper around the REST service.

1286
Zend_Service

Zend_Service_Nirvanix aims to make using the Nirvanix REST service easier but
understanding the service itself is still essential to be successful with Nirvanix.

The Nirvanix API Documentation provides an overview as well as detailed information using
the service. Please familiarize yourself with this document and refer back to it as you use
Zend_Service_Nirvanix.

22.4. Features
Nirvanix's REST service can be used effectively with PHP using the SimpleXML extension
and Zend_Http_Client alone. However, using it this way is somewhat inconvenient due to
repetitive operations like passing the session token on every request and repeatedly checking
the response body for error codes.

Zend_Service_Nirvanix provides the following functionality:

• A single point for configuring your Nirvanix authentication credentials that can be used across
the Nirvanix namespaces.

• A proxy object that is more convenient to use than an HTTP client alone, mostly removing the
need to manually construct HTTP POST requests to access the REST service.

• A response wrapper that parses each response body and throws an exception if an error
occurred, alleviating the need to repeatedly check the success of many commands.

• Additional convenience methods for some of the more common operations.

22.5. Getting Started


Once you have registered with Nirvanix, you're ready to store your first file on the IMFS. The most
common operations that you will need to do on the IMFS are creating a new file, downloading
an existing file, and deleting a file. Zend_Service_Nirvanix provides convenience methods
for these three operations.

$auth = array('username' => 'your-username',


'password' => 'your-password',
'appKey' => 'your-app-key');

$nirvanix = new Zend_Service_Nirvanix($auth);


$imfs = $nirvanix->getService('IMFS');

$imfs->putContents('/foo.txt', 'contents to store');

echo $imfs->getContents('/foo.txt');

$imfs->unlink('/foo.txt');

The first step to using Zend_Service_Nirvanix is always to authenticate against the service.
This is done by passing your credentials to the Zend_Service_Nirvanix constructor above.
The associative array is passed directly to Nirvanix as POST parameters.

Nirvanix divides its web services into namespaces. Each namespace encapsulates a group
of related operations. After getting an instance of Zend_Service_Nirvanix, call the
getService() method to create a proxy for the namespace you want to use. Above, a proxy
for the IMFS namespace is created.

1287
Zend_Service

After you have a proxy for the namespace you want to use, call methods on it. The proxy will allow
you to use any command available on the REST API. The proxy may also make convenience
methods available, which wrap web service commands. The example above shows using the
IMFS convenience methods to create a new file, retrieve and display that file, and finally delete
the file.

22.6. Understanding the Proxy


In the previous example, we used the getService() method to return a proxy object to the
IMFS namespace. The proxy object allows you to use the Nirvanix REST service in a way that's
closer to making a normal PHP method call, as opposed to constructing your own HTTP request
objects.

A proxy object may provide convenience methods. These are methods that the
Zend_Service_Nirvanix provides to simplify the use of the Nirvanix web services. In
the previous example, the methods putContents(), getContents(), and unlink() do
not have direct equivalents in the REST API. They are convenience methods provided by
Zend_Service_Nirvanix that abstract more complicated operations on the REST API.

For all other method calls to the proxy object, the proxy will dynamically convert the method call
to the equivalent HTTP POST request to the REST API. It does this by using the method name
as the API command, and an associative array in the first argument as the POST parameters.

Let's say you want to call the REST API method RenameFile, which does not have a convenience
method in Zend_Service_Nirvanix:

$auth = array('username' => 'your-username',


'password' => 'your-password',
'appKey' => 'your-app-key');

$nirvanix = new Zend_Service_Nirvanix($auth);


$imfs = $nirvanix->getService('IMFS');

$result = $imfs->renameFile(array('filePath' => '/path/to/foo.txt',


'newFileName' => 'bar.txt'));

Above, a proxy for the IMFS namespace is created. A method, renameFile(), is then called on
the proxy. This method does not exist as a convenience method in the PHP code, so it is trapped
by __call() and converted into a POST request to the REST API where the associative array
is used as the POST parameters.

Notice in the Nirvanix API documentation that sessionToken is required for this method but
we did not give it to the proxy object. It is added automatically for your convenience.

The result of this operation will either be a Zend_Service_Nirvanix_Response object


wrapping the XML returned by Nirvanix, or a Zend_Service_Nirvanix_Exception if an
error occurred.

22.7. Examining Results


The Nirvanix REST API always returns its results in XML. Zend_Service_Nirvanix parses
this XML with the SimpleXML extension and then decorates the resulting SimpleXMLElement
with a Zend_Service_Nirvanix_Response object.

The simplest way to examine a result from the service is to use the built-in PHP functions like
print_r():

1288
Zend_Service

<?php
$auth = array('username' => 'your-username',
'password' => 'your-password',
'appKey' => 'your-app-key');

$nirvanix = new Zend_Service_Nirvanix($auth);


$imfs = $nirvanix->getService('IMFS');

$result = $imfs->putContents('/foo.txt', 'fourteen bytes');


print_r($result);
?>
Zend_Service_Nirvanix_Response Object
(
[_sxml:protected] => SimpleXMLElement Object
(
[ResponseCode] => 0
[FilesUploaded] => 1
[BytesUploaded] => 14
)
)

You can access any property or method of the decorated SimpleXMLElement. In the above
example, $result->BytesUploaded could be used to see the number of bytes received.
Should you want to access the SimpleXMLElement directly, just use $result->getSxml().

The most common response from Nirvanix is success (ResponseCode of zero). It is not
normally necessary to check ResponseCode because any non-zero result will throw a
Zend_Service_Nirvanix_Exception. See the next section on handling errors.

22.8. Handling Errors


When using Nirvanix, it's important to anticipate errors that can be returned by the service and
handle them appropriately.

All operations against the REST service result in an XML return payload that contains a
ResponseCode element, such as the following example:

<Response>
<ResponseCode>0</ResponseCode>
</Response>

When the ResponseCode is zero such as in the example above, the operation was successful.
When the operation is not successful, the ResponseCode is non-zero and an ErrorMessage
element should be present.

To alleviate the need to repeatedly check if the ResponseCode is non-zero,


Zend_Service_Nirvanix automatically checks each response returned by Nirvanix. If the
ResponseCode indicates an error, a Zend_Service_Nirvanix_Exception will be thrown.

$auth = array('username' => 'your-username',


'password' => 'your-password',
'appKey' => 'your-app-key');
$nirvanix = new Zend_Service_Nirvanix($auth);

try {

1289
Zend_Service

$imfs = $nirvanix->getService('IMFS');
$imfs->unlink('/a-nonexistant-path');

} catch (Zend_Service_Nirvanix_Exception $e) {


echo $e->getMessage() . "\n";
echo $e->getCode();
}

In the example above, unlink() is a convenience method that wraps the DeleteFiles
command on the REST API. The filePath parameter required by the DeleteFiles command
contains a path that does not exist. This will result in a Zend_Service_Nirvanix exception
being thrown with the message "Invalid path" and code 70005.

The Nirvanix API Documentation describes the errors associated with each command.
Depending on your needs, you may wrap each command in a try block or wrap many commands
in the same try block for convenience.

23. Zend_Service_ReCaptcha
23.1. Introduction
Zend_Service_ReCaptcha fournit un client pour le Service Web reCAPTCHA. D'après le site
de reCAPTCHA, "reCAPTCHA est un service gratuit de CAPTCHA qui aide à la numérisation
de livres." Chaque reCAPTCHA requière que l'utilisateur saisisse 2 mots, le premier est le
CAPTCHA, et le second est issu de texte scanné que les OCR (Optical Character Recognition)
ne peuvent identifier.

Pour utiliser le service reCAPTCHA, vous devez créer un compte et enregistrer un ou plusieurs
domaines d'utilisation afin de générer une clé publique et une privée.

23.2. Utilisation la plus simple


Instanciez un objet Zend_Service_ReCaptcha en lui passant vos clés publique et privée :

Exemple 751. Créer une instance de service ReCaptcha

$recaptcha = new Zend_Service_ReCaptcha($pubKey, $privKey);

Pour rendre le reCAPTCHA, appelez simplement la méthode getHTML() :

Exemple 752. Afficher le ReCaptcha

echo $recaptcha->getHTML();

Lorsque le formulaire est envoyé, vous devriez recevoir 2 champs 'recaptcha_challenge_field'


et 'recaptcha_response_field'. Passez les alors à la méthode verify() :

$result = $recaptcha->verify(
$_POST['recaptcha_challenge_field'],
$_POST['recaptcha_response_field']
);

Une fois que vous possédez le résultat, vérifiez sa validité. Il s'agit d'un objet
Zend_Service_ReCaptcha_Response qui possède une méthode isValid().

1290
Zend_Service

Exemple 753. Vérifier les champs de formulaire

if (!$result->isValid()) {
// Validation échouée
}

Encore plus simple : utilisez l'adaptateur ReCaptcha de Zend_Captcha, ou utilisez cet


adaptateur comme backend pour l'élément formulaire Captcha. Dans ces 2 cas, le rendu et la
validation du reCAPTCHA sont assurés pour vous.

23.3. Hiding email addresses


Zend_Service_ReCaptcha_MailHide can be used to hide email addresses. It will replace
a part of an email address with a link that opens a popup window with a ReCaptcha challenge.
Solving the challenge will reveal the complete email address.

In order to use this component you will need an account, and generate public and private keys
for the mailhide API.

Exemple 754. Using the mail hide component

// The mail address we want to hide


$mail = 'mail@example.com';

// Create an instance of the mailhide component, passing it your public and private keys
// the mail address you want to hide
$mailHide = new Zend_Service_ReCaptcha_Mailhide();
$mailHide->setPublicKey($pubKey);
$mailHide->setPrivateKey($privKey);
$mailHide->setEmail($mail);

// Display it
print($mailHide);

The example above will display "m...@example.com" where "..." has a link that opens up a popup
windows with a ReCaptcha challenge.

The public key, private key and the email address can also be specified in the constructor of the
class. A fourth argument also exists that enables you to set some options for the component.
The available options are listed in the following table:

Tableau 137. Zend_Service_ReCaptcha_MailHide options


Option Description Expected Values Default Value
linkTitle The title attribute of the string 'Reveal this e-mail
link address'
linkHiddenText The text that includes string '...'
the popup link
popupWidth The width of the popup int 500
window
popupHeight The height of the int 300
popup window

The configuration options can be set by sending it as the fourth argument to the constructor
or by calling the setOptions($options) which takes an associative array or an instance of
Zend_Config.

1291
Zend_Service

Exemple 755. Generating many hidden email addresses

// Create an instance of the mailhide component, passing it your public and private keys
// well the mail address you want to hide
$mailHide = new Zend_Service_ReCaptcha_Mailhide();
$mailHide->setPublicKey($pubKey);
$mailHide->setPrivateKey($privKey);
$mailHide->setOptions(array(
'linkTitle' => 'Click me',
'linkHiddenText' => '+++++',
));

// The addresses we want to hide


$mailAddresses = array(
'mail@example.com',
'johndoe@example.com',
'janedoe@example.com',
);

foreach ($mailAddresses as $mail) {


$mailHide->setEmail($mail);
print($mailHide);
}

24. Zend_Service_Simpy
24.1. Introduction
Zend_Service_Simpy permet l'interaction avec les services Web du réseau social de partage
de 'marque-pages' (de 'favoris', de 'liens') Simpy.

Pour utiliser Zend_Service_Simpy, vous devez posséder un compte. Pour ceci, voyez le site
Web de Simpy. Pour plus d'informations sur l'API REST de Simpy, voyez sa documentation .

Les sections qui suivent vont vous indiquer les éléments sur lesquels vous pouvez agir en
utilisant l'API de Simpy, via Zend_Service_Simpy.

• Liens: Créer, requêter, mettre à jour, supprimer

• Mots-clés: requêter, supprimer, renommer, fusionner, éclater

• Notes: Créer, requêter, mettre à jour, supprimer

• Listes: récupérer, récupérer tout

24.2. Liens
Lors d'interactions avec les liens, ceux-ci sont retournées dans l'ordre descendant par date
d'ajout. Vous pouvez les chercher par titre, auteur, mots-clés, notes ou même via le contenu de
leur page. Vous pouvez chercher selon tous ces critères avec des phrases, des booléens ou
des jokers. Voyez la syntaxe de recherche et les champs de recherche depuis la FAQ de Simpy,
pour plus d'informations.

1292
Zend_Service

Exemple 756. Requêter des liens

$simpy = new Zend_Service_Simpy('yourusername', 'yourpassword');

/* Recherche les 10 liens les plus récents */


$linkQuery = new Zend_Service_Simpy_LinkQuery();
$linkQuery->setLimit(10);

/* Récupère et affiche les liens */


$linkSet = $simpy->getLinks($linkQuery);
foreach ($linkSet as $link) {
echo '<a href="';
echo $link->getUrl();
echo '">';
echo $link->getTitle();
echo '</a><br />';
}

/* Recherche les 5 derniers liens ajoutés,


contenant 'PHP' dans leur titre */
$linkQuery->setQueryString('title:PHP');
$linkQuery->setLimit(5);

/* Cherche tous les liens avec le mot 'French' dans le titre


et le mot-clé 'language' */
$linkQuery->setQueryString('+title:French +tags:language');

/* Cherche tous les liens avec le mot 'French' dans le titre


et pas le mot-clé 'travel' */
$linkQuery->setQueryString('+title:French -tags:travel');

/* Cherche tous les liens ajoutés le 9/12/06 */


$linkQuery->setDate('2006-12-09');

/* Cherche tous les liens ajoutés après le 9/12/06 (exclu)*/


$linkQuery->setAfterDate('2006-12-09');

/* Cherche tous les liens ajoutés avant le 9/12/06 (exclu)*/


$linkQuery->setBeforeDate('2006-12-09');

/* Cherche tous les liens ajoutés entre le 1/12/06 et le 9/12/06 (exclues) */


$linkQuery->setBeforeDate('2006-12-01');
$linkQuery->setAfterDate('2006-12-09');

Les liens sont représentés de manière unique par leur URL. Ainsi tenter de sauvegarder un lien
ayant le même URL qu'un lien existant va l'écraser.

1293
Zend_Service

Exemple 757. Modifier des liens

$simpy = new Zend_Service_Simpy('yourusername', 'yourpassword');

/* Sauvegarde un lien */
$simpy->saveLink(
'Zend Framework' // Title
'http://framework.zend.com', // URL
Zend_Service_Simpy_Link::ACCESSTYPE_PUBLIC, // Access Type
'zend, framework, php' // Tags
'Zend Framework home page' // Alternative title
'This site rocks!' // Note
);

/* Ecrase le lien avec les nouvelles données */


$simpy->saveLink(
'Zend Framework'
'http://framework.zend.com',
Zend_Service_Simpy_Link::ACCESSTYPE_PRIVATE, // Access Type has changed
'php, zend, framework' // Tags have changed order
'Zend Framework' // Alternative title has changed
'This site REALLY rocks!' // Note has changed
);

/* Effacement du lien */
$simpy->deleteLink('http://framework.zend.com');

/* Effacement de plusieurs liens */


$linkSet = $this->_simpy->getLinks();
foreach ($linkSet as $link) {
$this->_simpy->deleteLink($link->getUrl());
}

24.3. Mots-clés
Les mots-clés sont récupérés dans l'ordre descendant, par le nombre de liens utilisant le mot-clé.

1294
Zend_Service

Exemple 758. Travailler avec les mots-clés

$simpy = new Zend_Service_Simpy('yourusername', 'yourpassword');

/* Sauvegarde d'un lien avec des mots-clés */


$simpy->saveLink(
'Zend Framework' // Title
'http://framework.zend.com', // URL
Zend_Service_Simpy_Link::ACCESSTYPE_PUBLIC, // Access Type
'zend, framework, php' // Tags
);

/* Récupère la liste de tous les mots-clés utilisés par les liens


et les notes */
$tagSet = $simpy->getTags();

/* Affiche chaque mot-clé avec le nombre de liens les utilisant */


foreach ($tagSet as $tag) {
echo $tag->getTag();
echo ' - ';
echo $tag->getCount();
echo '<br />';
}

/* Efface le mot-clé 'zend' de tous les liens l'utilisant */


$simpy->removeTag('zend');

/* Renome le mot-clé 'framework' vers 'frameworks' */


$simpy->renameTag('framework', 'frameworks');

/* Eclate le mot-clé 'frameworks' en 'framework' et 'development',


ce qui va effacer le mot-clé 'frameworks' et ajouter les mots-clés
'framework' et 'development' pour tous les liens l'utilisant
anciennement */
$simpy->splitTag('frameworks', 'framework', 'development');

/* Cette opération de fusion est l'opposé de l'opération ci-dessus */


$simpy->mergeTags('framework', 'development', 'frameworks');

24.4. Notes
Les notes peuvent être sauvées, récupérées, effacées. Elles possèdent un identifiant numérique
unique.

1295
Zend_Service

Exemple 759. Travailler avec les notes

$simpy = new Zend_Service_Simpy('yourusername', 'yourpassword');

/* Sauvegarde une note */


$simpy->saveNote(
'Test Note', // Title
'test,note', // Tags
'This is a test note.' // Description
);

/* Ecrase une note existante */


$simpy->saveNote(
'Updated Test Note', // Title
'test,note,updated', // Tags
'This is an updated test note.', // Description
$note->getId() // Unique identifier
);

/* Recherche les 10 notes les plus récentes */


$noteSet = $simpy->getNotes(null, 10);

/* Affiche ces notes */


foreach ($noteSet as $note) {
echo '<p>';
echo $note->getTitle();
echo '<br />';
echo $note->getDescription();
echo '<br >';
echo $note->getTags();
echo '</p>';
}

/* Cherche les notes avec le mot 'PHP' dans leur titre */


$noteSet = $simpy->getNotes('title:PHP');

/* Cherche les notes avec le mot 'PHP' dans leur titre et pas le mot
'framework' dans leur description */
$noteSet = $simpy->getNotes('+title:PHP -description:framework');

/* Efface une note */


$simpy->deleteNote($note->getId());

24.5. Listes de surveillance


Les listes de surveillance ne peuvent qu'être requêtées via l'API Simpy. Vous devez donc vous
assurer qu'elles sont correctement créées, depuis le site Web de Simpy, il n'est pas possible de
les créer ou les supprimer depuis l'API.

1296
Zend_Service

Exemple 760. Récupérer des listes de surveillance

$simpy = new Zend_Service_Simpy('yourusername', 'yourpassword');

/* Récupérer une liste de listes de surveillance */


$watchlistSet = $simpy->getWatchlists();

/* Affiche les données de chaque liste */


foreach ($watchlistSet as $watchlist) {
echo $watchlist->getId();
echo '<br />';
echo $watchlist->getName();
echo '<br />';
echo $watchlist->getDescription();
echo '<br />';
echo $watchlist->getAddDate();
echo '<br />';
echo $watchlist->getNewLinks();
echo '<br />';

foreach ($watchlist->getUsers() as $user) {


echo $user;
echo '<br />';
}

foreach ($watchlist->getFilters() as $filter) {


echo $filter->getName();
echo '<br />';
echo $filter->getQuery();
echo '<br />';
}
}

/* Récupère une liste de surveillance par son identifiant */


$watchlist = $simpy->getWatchlist($watchlist->getId());
$watchlist = $simpy->getWatchlist(1);

25. Introduction
Le composant Zend_Service_SlideShare est utilisé dans l'interaction avec les services Web
de slideshare.net, plate-forme servant d'hébergement de diaporamas. Grâce à ce composant,
vous pouvez intégrer des diaporamas de Slideshare, dans votre propre site Web, ou même
uploader des nouveaux diaporamas sur votre compte Slideshare, depuis votre site Web.

25.1. Démarrage avec Zend_Service_SlideShare


Pour utiliser Zend_Service_SlideShare, vous devez créer au préalable un compte sur
slideshare.net (plus d'informations à ce sujet ici), afin de recevoir votre clé d'API et votre login /
mot de passe, indispensables pour utiliser le service Web.

Une fois votre compte créé, vous pouvez utiliser Zend_Service_SlideShare en créant une
instance de Zend_Service_SlideShare en lui passant vos identifiants :

// Crée une instance du composant


$ss = new Zend_Service_SlideShare('APIKEY',
'SHAREDSECRET',
'USERNAME',

1297
Zend_Service

'PASSWORD');

25.2. L'objet SlideShow


Chaque diaporama issu de Zend_Service_SlideShare est matérialisé par un objet
Zend_Service_SlideShare_SlideShow (que ce soit pour uploader ou récupérer des
diaporamas). Pour information, voici un pseudo code de cette classe :

class Zend_Service_SlideShare_SlideShow {

/**
* Récupère l'emplacement du diaporama
*/
public function getLocation() {
return $this->_location;
}

/**
* Récupère la transcription du diaporama
*/
public function getTranscript() {
return $this->_transcript;
}

/**
* Associe un mot-clé au diaporama
*/
public function addTag($tag) {
$this->_tags[] = (string)$tag;
return $this;
}

/**
* Associe des mots-clés au diaporama
*/
public function setTags(Array $tags) {
$this->_tags = $tags;
return $this;
}

/**
* Récupère tous les mots-clés associés au diaporama
*/
public function getTags() {
return $this->_tags;
}

/**
* Règle le nom de fichier du diaporama dans le système
* de fichiers local (pour l'upload d'un nouveau diaporama)
*/
public function setFilename($file) {
$this->_slideShowFilename = (string)$file;
return $this;
}

/**
* Rècupère le nom de fichier du diaporama dans le système
* de fichiers local qui sera uploadé

1298
Zend_Service

*/
public function getFilename() {
return $this->_slideShowFilename;
}

/**
* Récupère l'ID du diaporama
*/
public function getId() {
return $this->_slideShowId;
}

/**
* Récupère le code HTML utilisé pour la projection du diaporama
*/
public function getEmbedCode() {
return $this->_embedCode;
}

/**
* Récupère l'URI de la vignette du diaporama
*/
public function getThumbnailUrl() {
return $this->_thumbnailUrl;
}

/**
* Règle le titre du diaporama
*/
public function setTitle($title) {
$this->_title = (string)$title;
return $this;
}

/**
* Récupère le titre du diaporama
*/
public function getTitle() {
return $this->_title;
}

/**
* Régle la description du diaporama
*/
public function setDescription($desc) {
$this->_description = (string)$desc;
return $this;
}

/**
* Récupère la description du diaporama
*/
public function getDescription() {
return $this->_description;
}

/**
* Récupère le statut (numérique) du diaporama sur le serveur
*/
public function getStatus() {

1299
Zend_Service

return $this->_status;
}

/**
* Récupère la description textuelle du statut du diaporama
* sur le serveur
*/
public function getStatusDescription() {
return $this->_statusDescription;
}

/**
* Récupère le lien permanent du diaporama
*/
public function getPermaLink() {
return $this->_permalink;
}

/**
* Récupère le nombre de diapositives que le diaporama comprend
*/
public function getNumViews() {
return $this->_numViews;
}
}

La classe présentée ci dessus ne montre que les méthodes qui sont sensées
être utilisées par les développeurs. D'autres méthodes internes au composant
existent.

Lors de l'utilisation de Zend_Service_SlideShare, la classe de données Slideshow sera


souvent utilisée pour parcourir, ajouter, ou modifier des diaporamas.

25.3. Récupérer un diaporama simplement


La manière la plus simple d'utiliser Zend_Service_SlideShare est la récupération d'un
diaporama depuis son ID, fournit par le service slideshare.net, ceci est effectué via la méthode
getSlideShow() de l'objet Zend_Service_SlideShare. Le résultat de cette méthode est
un objet de type Zend_Service_SlideShare_SlideShow.

// Création d'une instance du composant


$ss = new Zend_Service_SlideShare('APIKEY',
'SHAREDSECRET',
'USERNAME',
'PASSWORD');

$slideshow = $ss->getSlideShow(123456);

print "Titre du diaporama : {$slideshow->getTitle()}<br/>\n";


print "Nombre de diapositives : {$slideshow->getNumViews()}<br/>\n";

25.4. Récupérer des groupes de diaporamas


Si vous ne connaissez pas l'ID spécifique d'un diaporama vous intéressant, il est possible de
récupérer des groupes de diaporamas, en utilisant une de ces trois méthodes :

• Diaporamas depuis un compte spécifique

1300
Zend_Service

La méthode getSlideShowsByUsername() va retourner tous les diaporamas depuis un


compte utilisateur.

• Diaporamas contenant des tags spécifiques

La méthode getSlideShowsByTag va retourner un ensemble de diaporamas comportant


certains tags (mots-clés).

• Diaporamas depuis un groupe

La méthode getSlideShowsByGroup récupère tous les diaporamas d'un groupe donné.

Voici un exemple utilisant les méthodes décrites ci-dessus :

// Crée une nouvelle instance du composant


$ss = new Zend_Service_SlideShare('APIKEY',
'SHAREDSECRET',
'USERNAME',
'PASSWORD');

$starting_offset = 0;
$limit = 10;

// Récupère les 10 premiers de chaque type


$ss_user = $ss->getSlideShowsByUser('username', $starting_offset, $limit);
$ss_tags = $ss->getSlideShowsByTag('zend', $starting_offset, $limit);
$ss_group = $ss->getSlideShowsByGroup('mygroup', $starting_offset, $limit);

// Itère sur les diaporamas


foreach($ss_user as $slideshow) {
print "Titre du diaporama : {$slideshow->getTitle}<br/>\n";
}

25.5. Politique de cache de Zend_Service_SlideShare


Par défaut, Zend_Service_SlideShare va mettre en cache toute requête concernant le
service Web, dans le système de fichier (par défaut : /tmp), ceci pour une durée de 12 heures.
Si vous voulez changer ce comportement, vous devez passer votre propre objet Zend_Cache
en utilisant la méthode setCacheObject :

$frontendOptions = array(
'lifetime' => 7200,
'automatic_serialization' => true);
$backendOptions = array(
'cache_dir' => '/webtmp/');

$cache = Zend_Cache::factory('Core',
'File',
$frontendOptions,
$backendOptions);

$ss = new Zend_Service_SlideShare('APIKEY',


'SHAREDSECRET',
'USERNAME',
'PASSWORD');
$ss->setCacheObject($cache);

1301
Zend_Service

$ss_user = $ss->getSlideShowsByUser('username', $starting_offset, $limit);

25.6. Changer le comportement du client HTTP


Si pour une raison quelconque vous souhaitez changer le comportement de l'objet client
HTTP utilisé pour interroger le service Web, vous pouvez créer votre propre instance de
Zend_Http_Client (voyez Zend_Http). Ceci peut être utile par exemple pour spécifier un
timeout ou toute autre chose :

$client = new Zend_Http_Client();


$client->setConfig(array('timeout' => 5));

$ss = new Zend_Service_SlideShare('APIKEY',


'SHAREDSECRET',
'USERNAME',
'PASSWORD');
$ss->setHttpClient($client);
$ss_user = $ss->getSlideShowsByUser('username', $starting_offset, $limit);

26. Zend_Service_StrikeIron
Zend_Service_StrikeIron provides a PHP 5 client to StrikeIron web services. See the
following sections:

• Section 26, « Zend_Service_StrikeIron »

• Section 27, « Zend_Service_StrikeIron: Bundled Services »

• Section 28, « Zend_Service_StrikeIron: Advanced Uses »

26.1. Overview
StrikeIron offers hundreds of commercial data services ("Data as a Service") such as Online
Sales Tax, Currency Rates, Stock Quotes, Geocodes, Global Address Verification, Yellow/White
Pages, MapQuest Driving Directions, Dun & Bradstreet Business Credit Checks, and much,
much more.

Each StrikeIron web service shares a standard SOAP (and REST) API, making it easy to
integrate and manage multiple services. StrikeIron also manages customer billing for all services
in a single account, making it perfect for solution providers. Get started with free web services
at http://www.strikeiron.com/sdp.

StrikeIron's services may be used through the PHP 5 SOAP extension alone. However, using
StrikeIron this way does not give an ideal PHP-like interface. The Zend_Service_StrikeIron
component provides a lightweight layer on top of the SOAP extension for working with StrikeIron
services in a more convenient, PHP-like manner.

The PHP 5 SOAP extension must be installed and enabled to use


Zend_Service_StrikeIron.

The Zend_Service_StrikeIron component provides:

• A single point for configuring your StrikeIron authentication credentials that can be used across
many StrikeIron services.

1302
Zend_Service

• A standard way of retrieving your StrikeIron subscription information such as license status
and the number of hits remaining to a service.

• The ability to use any StrikeIron service from its WSDL without creating a PHP wrapper class,
and the option of creating a wrapper for a more convenient interface.

• Wrappers for three popular StrikeIron services.

26.2. Registering with StrikeIron


Before you can get started with Zend_Service_StrikeIron, you must first register for a
StrikeIron developer account.

After registering, you will receive a StrikeIron username and password. These will be used when
connecting to StrikeIron using Zend_Service_StrikeIron.

You will also need to sign up for StrikeIron's Super Data Pack Web Service.

Both registration steps are free and can be done relatively quickly through the StrikeIron website.

26.3. Getting Started


Once you have registered for a StrikeIron account and signed up for the Super Data Pack, you're
ready to start using Zend_Service_StrikeIron.

StrikeIron consists of hundreds of different web services. Zend_Service_StrikeIron can be


used with many of these services but provides supported wrappers for three of them:

• ZIP Code Information

• US Address Verification

• Sales & Use Tax Basic

The class Zend_Service_StrikeIron provides a simple way of specifying your StrikeIron


account information and other options in its constructor. It also has a factory method that will
return clients for StrikeIron services:

$strikeIron = new Zend_Service_StrikeIron(array('username' => 'your-username',


'password' => 'your-password'));

$taxBasic = $strikeIron->getService(array('class' => 'SalesUseTaxBasic'));

The getService() method will return a client for any StrikeIron service by the name of
its PHP wrapper class. In this case, the name SalesUseTaxBasic refers to the wrapper
class Zend_Service_StrikeIron_SalesUseTaxBasic. Wrappers are included for three
services and described in Bundled Services.

The getService() method can also return a client for a StrikeIron service that does not yet
have a PHP wrapper. This is explained in Using Services by WSDL.

26.4. Making Your First Query


Once you have used the getService() method to get a client for a particular StrikeIron service,
you can utilize that client by calling methods on it just like any other PHP object.

$strikeIron = new Zend_Service_StrikeIron(array('username' => 'your-username',

1303
Zend_Service

'password' => 'your-password'));

// Get a client for the Sales & Use Tax Basic service
$taxBasic = $strikeIron->getService(array('class' => 'SalesUseTaxBasic'));

// Query tax rate for Ontario, Canada


$rateInfo = $taxBasic->getTaxRateCanada(array('province' => 'ontario'));
echo $rateInfo->province;
echo $rateInfo->abbreviation;
echo $rateInfo->GST;

In the example above, the getService() method is used to return a client to the Sales & Use
Tax Basic service. The client object is stored in $taxBasic.

The getTaxRateCanada() method is then called on the service. An associative array is used to
supply keyword parameters to the method. This is the way that all StrikeIron methods are called.

The result from getTaxRateCanada() is stored in $rateInfo and has properties like
province and GST.

Many of the StrikeIron services are as simple to use as the example above. See Bundled Services
for detailed information on three StrikeIron services.

26.5. Examining Results


When learning or debugging the StrikeIron services, it's often useful to dump the result
returned from a method call. The result will always be an object that is an instance of
Zend_Service_StrikeIron_Decorator. This is a small decorator object that wraps the
results from the method call.

The simplest way to examine a result from the service is to use the built-in PHP functions like
print_r():

<?php
$strikeIron = new Zend_Service_StrikeIron(array('username' => 'your-username',
'password' => 'your-password'));

$taxBasic = $strikeIron->getService(array('class' => 'SalesUseTaxBasic'));

$rateInfo = $taxBasic->getTaxRateCanada(array('province' => 'ontario'));


print_r($rateInfo);
?>
Zend_Service_StrikeIron_Decorator Object
(
[_name:protected] => GetTaxRateCanadaResult
[_object:protected] => stdClass Object
(
[abbreviation] => ON
[province] => ONTARIO
[GST] => 0.06
[PST] => 0.08
[total] => 0.14
[HST] => Y
)
)

In the output above, we see that the decorator ($rateInfo) wraps an object named
GetTaxRateCanadaResult, the result of the call to getTaxRateCanada().

1304
Zend_Service

This means that $rateInfo has public properties like abbreviation, province, and GST.
These are accessed like $rateInfo->province.

StrikeIron result properties sometimes start with an uppercase letter such as Foo
or Bar where most PHP object properties normally start with a lowercase letter
as in foo or bar. The decorator will automatically do this inflection so you may
read a property Foo as foo.

If you ever need to get the original object or its name out of the decorator, use the respective
methods getDecoratedObject() and getDecoratedObjectName().

26.6. Handling Errors


The previous examples are naive, i.e. no error handling was shown. It's possible that StrikeIron
will return a fault during a method call. Events like bad account credentials or an expired
subscription can cause StrikeIron to raise a fault.

An exception will be thrown when such a fault occurs. You should anticipate and catch these
exceptions when making method calls to the service:

$strikeIron = new Zend_Service_StrikeIron(array('username' => 'your-username',


'password' => 'your-password'));

$taxBasic = $strikeIron->getService(array('class' => 'SalesUseTaxBasic'));

try {

$taxBasic->getTaxRateCanada(array('province' => 'ontario'));

} catch (Zend_Service_StrikeIron_Exception $e) {

// error handling for events like connection


// problems or subscription errors

The exceptions thrown will always be Zend_Service_StrikeIron_Exception.

It's important to understand the difference between exceptions and normal failed method calls.
Exceptions occur for exceptional conditions, such as the network going down or your subscription
expiring. Failed method calls that are a common occurrence, such as getTaxRateCanada()
not finding the province you supplied, will not result an in exception.

Every time you make a method call to a StrikeIron service, you should check the
response object for validity and also be prepared to catch an exception.

26.7. Checking Your Subscription


StrikeIron provides many different services. Some of these are free, some are available on a trial
basis, and some are pay subscription only. When using StrikeIron, it's important to be aware of
your subscription status for the services you are using and check it regularly.

Each StrikeIron client returned by the getService method has the ability to check the
subscription status for that service using the getSubscriptionInfo() method of the client:

1305
Zend_Service

// Get a client for the Sales & Use Tax Basic service
$strikeIron = new Zend_Service_StrikeIron(array('username' => 'your-username',
'password' => 'your-password'));

$taxBasic = $strikeIron->getService(array('class => 'SalesUseTaxBasic'));

// Check remaining hits for the Sales & Use Tax Basic service
$subscription = $taxBasic->getSubscriptionInfo();
echo $subscription->remainingHits;

The getSubscriptionInfo() method will return an object that typically has a


remainingHits property. It's important to check the status on each service that you are using.
If a method call is made to StrikeIron after the remaining hits have been used up, an exception
will occur.

Checking your subscription to a service does not use any remaining hits to the service. Each
time any method call to the service is made, the number of hits remaining will be cached and this
cached value will be returned by getSubscriptionInfo() without connecting to the service
again. To force getSubscriptionInfo() to override its cache and query the subscription
information again, use getSubscriptionInfo(true).

27. Zend_Service_StrikeIron: Bundled Services


Zend_Service_StrikeIron comes with wrapper classes for three popular StrikeIron
services.

27.1. ZIP Code Information


Zend_Service_StrikeIron_ZipCodeInfo provides a client for StrikeIron's Zip Code
Information Service. For more information on this service, visit these StrikeIron resources:

• Zip Code Information Service Page

• Zip Code Information Service WSDL

The service contains a getZipCode() method that will retrieve information about a United
States ZIP code or Canadian postal code:

$strikeIron = new Zend_Service_StrikeIron(array('username' => 'your-username',


'password' => 'your-password'));

// Get a client for the Zip Code Information service


$zipInfo = $strikeIron->getService(array('class' => 'ZipCodeInfo'));

// Get the Zip information for 95014


$response = $zipInfo->getZipCode(array('ZipCode' => 95014));
$zips = $response->serviceResult;

// Display the results


if ($zips->count == 0) {
echo 'No results found';
} else {
// a result with one single zip code is returned as an object,
// not an array with one element as one might expect.
if (! is_array($zips->zipCodes)) {
$zips->zipCodes = array($zips->zipCodes);

1306
Zend_Service

// print all of the possible results


foreach ($zips->zipCodes as $z) {
$info = $z->zipCodeInfo;

// show all properties


print_r($info);

// or just the city name


echo $info->preferredCityName;
}
}

// Detailed status information


// http://www.strikeiron.com/exampledata/StrikeIronZipCodeInformation_v3.pdf
$status = $response->serviceStatus;

27.2. U.S. Address Verification


Zend_Service_StrikeIron_USAddressVerification provides a client for StrikeIron's
U.S. Address Verification Service. For more information on this service, visit these StrikeIron
resources:

• U.S. Address Verification Service Page

• U.S. Address Verification Service WSDL

The service contains a verifyAddressUSA() method that will verify an address in the United
States:

$strikeIron = new Zend_Service_StrikeIron(array('username' => 'your-username',


'password' => 'your-password'));

// Get a client for the Zip Code Information service


$verifier = $strikeIron->getService(array('class' => 'USAddressVerification'));

// Address to verify. Not all fields are required but


// supply as many as possible for the best results.
$address = array('firm' => 'Zend Technologies',
'addressLine1' => '19200 Stevens Creek Blvd',
'addressLine2' => '',
'city_state_zip' => 'Cupertino CA 95014');

// Verify the address


$result = $verifier->verifyAddressUSA($address);

// Display the results


if ($result->addressErrorNumber != 0) {
echo $result->addressErrorNumber;
echo $result->addressErrorMessage;
} else {
// show all properties
print_r($result);

// or just the firm name


echo $result->firm;

1307
Zend_Service

// valid address?
$valid = ($result->valid == 'VALID');
}

27.3. Sales & Use Tax Basic


Zend_Service_StrikeIron_SalesUseTaxBasic provides a client for StrikeIron's Sales &
Use Tax Basic service. For more information on this service, visit these StrikeIron resources:

• Sales & Use Tax Basic Service Page

• Sales & Use Tax Basic Service WSDL

The service contains two methods, getTaxRateUSA() and getTaxRateCanada(), that will
retrieve sales and use tax data for the United States and Canada, respectively.

$strikeIron = new Zend_Service_StrikeIron(array('username' => 'your-username',


'password' => 'your-password'));

// Get a client for the Sales & Use Tax Basic service
$taxBasic = $strikeIron->getService(array('class' => 'SalesUseTaxBasic'));

// Query tax rate for Ontario, Canada


$rateInfo = $taxBasic->getTaxRateCanada(array('province' => 'foo'));
print_r($rateInfo); // show all properties
echo $rateInfo->GST; // or just the GST (Goods & Services Tax)

// Query tax rate for Cupertino, CA USA


$rateInfo = $taxBasic->getTaxRateUS(array('zip_code' => 95014));
print_r($rateInfo); // show all properties
echo $rateInfo->state_sales_tax; // or just the state sales tax

28. Zend_Service_StrikeIron: Advanced Uses


This section describes the more advanced uses of Zend_Service_StrikeIron.

28.1. Using Services by WSDL


Some StrikeIron services may have a PHP wrapper class available, such as those described in
Bundled Services. However, StrikeIron offers hundreds of services and many of these may be
usable even without creating a special wrapper class.

To try a StrikeIron service that does not have a wrapper class available, give the wsdl option
to getService() instead of the class option:

$strikeIron = new Zend_Service_StrikeIron(array('username' => 'your-username',


'password' => 'your-password'));

// Get a generic client to the Reverse Phone Lookup service


$phone = $strikeIron->getService(
array('wsdl' => 'http://ws.strikeiron.com/ReversePhoneLookup?WSDL')
);

$result = $phone->lookup(array('Number' => '(408) 253-8800'));


echo $result->listingName;

1308
Zend_Service

// Zend Technologies USA Inc

Using StrikeIron services from the WSDL will require at least some understanding of the WSDL
files. StrikeIron has many resources on its site to help with this. Also, Jan Schneider from the
Horde project has written a small PHP routine that will format a WSDL file into more readable
HTML.

Please note that only the services described in the Bundled Services section are officially
supported.

28.2. Viewing SOAP Transactions


All communication with StrikeIron is done using the SOAP extension. It is sometimes useful to
view the XML exchanged with StrikeIron for debug purposes.

Every StrikeIron client (subclass of Zend_Service_StrikeIron_Base) contains a


getSoapClient() method to return the underlying instance of SOAPClient used to
communicate with StrikeIron.

PHP's SOAPClient has a trace option that causes it to remember the XML exchanged during
the last transaction. Zend_Service_StrikeIron does not enable the trace option by default
but this can easily by changed by specifying the options that will be passed to the SOAPClient
constructor.

To view a SOAP transaction, call the getSoapClient() method to get the SOAPClient
instance and then call the appropriate methods like __getLastRequest() and
__getLastRequest():

$strikeIron =
new Zend_Service_StrikeIron(array('username' => 'your-username',
'password' => 'your-password',
'options' => array('trace' => true)));

// Get a client for the Sales & Use Tax Basic service
$taxBasic = $strikeIron->getService(array('class' => 'SalesUseTaxBasic'));

// Perform a method call


$taxBasic->getTaxRateCanada(array('province' => 'ontario'));

// Get SOAPClient instance and view XML


$soapClient = $taxBasic->getSoapClient();
echo $soapClient->__getLastRequest();
echo $soapClient->__getLastResponse();

29. Zend_Service_Technorati
29.1. Introduction
Zend_Service_Technorati provides an easy, intuitive and object-oriented interface for using
the Technorati API. It provides access to all available Technorati API queries and returns the
original XML response as a friendly PHP object.

Technorati is one of the most popular blog search engines. The API interface enables developers
to retrieve information about a specific blog, search blogs matching a single tag or phrase and
get information about a specific author (blogger). For a full list of available queries please see
the Technorati API documentation or the Available Technorati queries section of this document.

1309
Zend_Service

29.2. Getting Started


Technorati requires a valid API key for usage. To get your own API Key you first need to create
a new Technorati account, then visit the API Key section.

API Key limits


You can make up to 500 Technorati API calls per day, at no charge. Other usage
limitations may apply, depending on the current Technorati API license.

Once you have a valid API key, you're ready to start using Zend_Service_Technorati.

29.3. Making Your First Query


In order to run a query, first you need a Zend_Service_Technorati instance with a valid API
key. Then choose one of the available query methods, and call it providing required arguments.

Exemple 761. Sending your first query

// create a new Zend_Service_Technorati


// with a valid API_KEY
$technorati = new Zend_Service_Technorati('VALID_API_KEY');

// search Technorati for PHP keyword


$resultSet = $technorati->search('PHP');

Each query method accepts an array of optional parameters that can be used to refine your query.

Exemple 762. Refining your query

// create a new Zend_Service_Technorati


// with a valid API_KEY
$technorati = new Zend_Service_Technorati('VALID_API_KEY');

// filter your query including only results


// with some authority (Results from blogs with a handful of links)
$options = array('authority' => 'a4');

// search Technorati for PHP keyword


$resultSet = $technorati->search('PHP', $options);

A Zend_Service_Technorati instance is not a single-use object. That is, you


don't need to create a new instance for each query call; simply use your current
Zend_Service_Technorati object as long as you need it.

Exemple 763. Sending multiple queries with the same Zend_Service_Technorati


instance

// create a new Zend_Service_Technorati


// with a valid API_KEY
$technorati = new Zend_Service_Technorati('VALID_API_KEY');

// search Technorati for PHP keyword


$search = $technorati->search('PHP');

// get top tags indexed by Technorati


$topTags = $technorati->topTags();

1310
Zend_Service

29.4. Consuming Results


You can get one of two types of result object in response to a query.

The first group is represented by Zend_Service_Technorati_*ResultSet objects.


A result set object is basically a collection of result objects. It extends the basic
Zend_Service_Technorati_ResultSet class and implements the SeekableIterator
PHP interface. The best way to consume a result set object is to loop over it with the PHP
foreach statement.

Exemple 764. Consuming a result set object

// create a new Zend_Service_Technorati


// with a valid API_KEY
$technorati = new Zend_Service_Technorati('VALID_API_KEY');

// search Technorati for PHP keyword


// $resultSet is an instance of Zend_Service_Technorati_SearchResultSet
$resultSet = $technorati->search('PHP');

// loop over all result objects


foreach ($resultSet as $result) {
// $result is an instance of Zend_Service_Technorati_SearchResult
}

Because Zend_Service_Technorati_ResultSet implements the SeekableIterator


interface, you can seek a specific result object using its position in the result collection.

Exemple 765. Seeking a specific result set object

// create a new Zend_Service_Technorati


// with a valid API_KEY
$technorati = new Zend_Service_Technorati('VALID_API_KEY');

// search Technorati for PHP keyword


// $resultSet is an instance of Zend_Service_Technorati_SearchResultSet
$resultSet = $technorati->search('PHP');

// $result is an instance of Zend_Service_Technorati_SearchResult


$resultSet->seek(1);
$result = $resultSet->current();

SeekableIterator works as an array and counts positions starting from index


0. Fetching position number 1 means getting the second result in the collection.

The second group is represented by special standalone result objects.


Zend_Service_Technorati_GetInfoResult,
Zend_Service_Technorati_BlogInfoResult and
Zend_Service_Technorati_KeyInfoResult act as wrappers for additional objects, such
as Zend_Service_Technorati_Author and Zend_Service_Technorati_Weblog.

1311
Zend_Service

Exemple 766. Consuming a standalone result object

// create a new Zend_Service_Technorati


// with a valid API_KEY
$technorati = new Zend_Service_Technorati('VALID_API_KEY');

// get info about weppos author


$result = $technorati->getInfo('weppos');

$author = $result->getAuthor();
echo '<h2>Blogs authored by ' . $author->getFirstName() . " " .
$author->getLastName() . '</h2>';
echo '<ol>';
foreach ($result->getWeblogs() as $weblog) {
echo '<li>' . $weblog->getName() . '</li>';
}
echo "</ol>";

Please read the Zend_Service_Technorati Classes section for further details about response
classes.

29.5. Handling Errors


Each Zend_Service_Technorati query method throws a
Zend_Service_Technorati_Exception exception on failure with a meaningful error
message.

There are several reasons that may cause a Zend_Service_Technorati query to fail.
Zend_Service_Technorati validates all parameters for any query request. If a parameter
is invalid or it contains an invalid value, a new Zend_Service_Technorati_Exception
exception is thrown. Additionally, the Technorati API interface could be temporally unavailable,
or it could return a response that is not well formed.

You should always wrap a Technorati query with a try...catch block.

Exemple 767. Handling a Query Exception

$technorati = new Zend_Service_Technorati('VALID_API_KEY');


try {
$resultSet = $technorati->search('PHP');
} catch(Zend_Service_Technorati_Exception $e) {
echo "An error occurred: " $e->getMessage();
}

29.6. Checking Your API Key Daily Usage


From time to time you probably will want to check your API key daily usage. By default
Technorati limits your API usage to 500 calls per day, and an exception is returned by
Zend_Service_Technorati if you try to use it beyond this limit. You can get information about
your API key usage using the Zend_Service_Technorati::keyInfo() method.

Zend_Service_Technorati::keyInfo() returns a
Zend_Service_Technorati_KeyInfoResult object. For full details please see the API
reference guide.

1312
Zend_Service

Exemple 768. Getting API key daily usage information

$technorati = new Zend_Service_Technorati('VALID_API_KEY');


$key = $technorati->keyInfo();

echo "API Key: " . $key->getApiKey() . "<br />";


echo "Daily Usage: " . $key->getApiQueries() . "/" .
$key->getMaxQueries() . "<br />";

29.7. Available Technorati Queries


Zend_Service_Technorati provides support for the following queries:

• Cosmos

• Search

• Tag

• DailyCounts

• TopTags

• BlogInfo

• BlogPostTags

• GetInfo

29.7.1. Technorati Cosmos

Cosmos query lets you see what blogs are linking to a given URL. It returns
a Zend_Service_Technorati_CosmosResultSet object. For full details please see
Zend_Service_Technorati::cosmos() in the API reference guide.

Exemple 769. Cosmos Query

$technorati = new Zend_Service_Technorati('VALID_API_KEY');


$resultSet = $technorati->cosmos('http://devzone.zend.com/');

echo "<p>Reading " . $resultSet->totalResults() .


" of " . $resultSet->totalResultsAvailable() .
" available results</p>";
echo "<ol>";
foreach ($resultSet as $result) {
echo "<li>" . $result->getWeblog()->getName() . "</li>";
}
echo "</ol>";

29.7.2. Technorati Search

The Search query lets you see what blogs contain a given search string. It returns
a Zend_Service_Technorati_SearchResultSet object. For full details please see
Zend_Service_Technorati::search() in the API reference guide.

1313
Zend_Service

Exemple 770. Search Query

$technorati = new Zend_Service_Technorati('VALID_API_KEY');


$resultSet = $technorati->search('zend framework');

echo "<p>Reading " . $resultSet->totalResults() .


" of " . $resultSet->totalResultsAvailable() .
" available results</p>";
echo "<ol>";
foreach ($resultSet as $result) {
echo "<li>" . $result->getWeblog()->getName() . "</li>";
}
echo "</ol>";

29.7.3. Technorati Tag


The Tag query lets you see what posts are associated with a given tag. It returns
a Zend_Service_Technorati_TagResultSet object. For full details please see
Zend_Service_Technorati::tag() in the API reference guide.

Exemple 771. Tag Query

$technorati = new Zend_Service_Technorati('VALID_API_KEY');


$resultSet = $technorati->tag('php');

echo "<p>Reading " . $resultSet->totalResults() .


" of " . $resultSet->totalResultsAvailable() .
" available results</p>";
echo "<ol>";
foreach ($resultSet as $result) {
echo "<li>" . $result->getWeblog()->getName() . "</li>";
}
echo "</ol>";

29.7.4. Technorati DailyCounts


The DailyCounts query provides daily counts of posts containing the queried keyword. It returns
a Zend_Service_Technorati_DailyCountsResultSet object. For full details please see
Zend_Service_Technorati::dailyCounts() in the API reference guide.

Exemple 772. DailyCounts Query

$technorati = new Zend_Service_Technorati('VALID_API_KEY');


$resultSet = $technorati->dailyCounts('php');

foreach ($resultSet as $result) {


echo "<li>" . $result->getDate() .
"(" . $result->getCount() . ")</li>";
}
echo "</ol>";

29.7.5. Technorati TopTags


The TopTags query provides information on top tags indexed by Technorati. It returns
a Zend_Service_Technorati_TagsResultSet object. For full details please see
Zend_Service_Technorati::topTags() in the API reference guide.

1314
Zend_Service

Exemple 773. TopTags Query

$technorati = new Zend_Service_Technorati('VALID_API_KEY');


$resultSet = $technorati->topTags();

echo "<p>Reading " . $resultSet->totalResults() .


" of " . $resultSet->totalResultsAvailable() .
" available results</p>";
echo "<ol>";
foreach ($resultSet as $result) {
echo "<li>" . $result->getTag() . "</li>";
}
echo "</ol>";

29.7.6. Technorati BlogInfo

The BlogInfo query provides information on what blog, if any, is associated with a given URL. It
returns a Zend_Service_Technorati_BlogInfoResult object. For full details please see
Zend_Service_Technorati::blogInfo() in the API reference guide.

Exemple 774. BlogInfo Query

$technorati = new Zend_Service_Technorati('VALID_API_KEY');


$result = $technorati->blogInfo('http://devzone.zend.com/');

echo '<h2><a href="' . (string) $result->getWeblog()->getUrl() . '">' .


$result->getWeblog()->getName() . '</a></h2>';

29.7.7. Technorati BlogPostTags

The BlogPostTags query provides information on the top tags used by a specific blog. It
returns a Zend_Service_Technorati_TagsResultSet object. For full details please see
Zend_Service_Technorati::blogPostTags() in the API reference guide.

Exemple 775. BlogPostTags Query

$technorati = new Zend_Service_Technorati('VALID_API_KEY');


$resultSet = $technorati->blogPostTags('http://devzone.zend.com/');

echo "<p>Reading " . $resultSet->totalResults() .


" of " . $resultSet->totalResultsAvailable() .
" available results</p>";
echo "<ol>";
foreach ($resultSet as $result) {
echo "<li>" . $result->getTag() . "</li>";
}
echo "</ol>";

29.7.8. Technorati GetInfo

The GetInfo query tells you things that Technorati knows about a member. It returns
a Zend_Service_Technorati_GetInfoResult object. For full details please see
Zend_Service_Technorati::getInfo() in the API reference guide.

1315
Zend_Service

Exemple 776. GetInfo Query

$technorati = new Zend_Service_Technorati('VALID_API_KEY');


$result = $technorati->getInfo('weppos');

$author = $result->getAuthor();
echo "<h2>Blogs authored by " . $author->getFirstName() . " " .
$author->getLastName() . "</h2>";
echo "<ol>";
foreach ($result->getWeblogs() as $weblog) {
echo "<li>" . $weblog->getName() . "</li>";
}
echo "</ol>";

29.7.9. Technorati KeyInfo

The KeyInfo query provides information on daily usage of an API key. It returns
a Zend_Service_Technorati_KeyInfoResult object. For full details please see
Zend_Service_Technorati::keyInfo() in the API reference guide.

29.8. Zend_Service_Technorati Classes


The following classes are returned by the various Technorati queries. Each
Zend_Service_Technorati_*ResultSet class holds a type-specific result set which
can be easily iterated, with each result being contained in a type result object. All result
set classes extend Zend_Service_Technorati_ResultSet class and implement the
SeekableIterator interface, allowing for easy iteration and seeking to a specific result.

• Zend_Service_Technorati_ResultSet

• Zend_Service_Technorati_CosmosResultSet

• Zend_Service_Technorati_SearchResultSet

• Zend_Service_Technorati_TagResultSet

• Zend_Service_Technorati_DailyCountsResultSet

• Zend_Service_Technorati_TagsResultSet

• Zend_Service_Technorati_Result

• Zend_Service_Technorati_CosmosResult

• Zend_Service_Technorati_SearchResult

• Zend_Service_Technorati_TagResult

• Zend_Service_Technorati_DailyCountsResult

• Zend_Service_Technorati_TagsResult

• Zend_Service_Technorati_GetInfoResult

• Zend_Service_Technorati_BlogInfoResult

1316
Zend_Service

• Zend_Service_Technorati_KeyInfoResult

Zend_Service_Technorati_GetInfoResult,
Zend_Service_Technorati_BlogInfoResult and
Zend_Service_Technorati_KeyInfoResult represent exceptions to the
above because they don't belong to a result set and they don't
implement any interface. They represent a single response object
and they act as a wrapper for additional Zend_Service_Technorati
objects, such as Zend_Service_Technorati_Author and
Zend_Service_Technorati_Weblog.

The Zend_Service_Technorati library includes additional convenient classes


representing specific response objects. Zend_Service_Technorati_Author represents
a single Technorati account, also known as a blog author or blogger.
Zend_Service_Technorati_Weblog represents a single weblog object, along with all
specific weblog properties such as feed URLs or blog name. For full details please see
Zend_Service_Technorati in the API reference guide.

29.8.1. Zend_Service_Technorati_ResultSet
Zend_Service_Technorati_ResultSet is the most essential result set. The scope of this
class is to be extended by a query-specific child result set class, and it should never be used
to initialize a standalone object. Each of the specific result sets represents a collection of query-
specific Zend_Service_Technorati_Result objects.

Zend_Service_Technorati_ResultSet implements the PHP SeekableIterator


interface, and you can iterate all result objects via the PHP foreach statement.

Exemple 777. Iterating result objects from a resultset collection

// run a simple query


$technorati = new Zend_Service_Technorati('VALID_API_KEY');
$resultSet = $technorati->search('php');

// $resultSet is now an instance of


// Zend_Service_Technorati_SearchResultSet
// it extends Zend_Service_Technorati_ResultSet
foreach ($resultSet as $result) {
// do something with your
// Zend_Service_Technorati_SearchResult object
}

29.8.2. Zend_Service_Technorati_CosmosResultSet
Zend_Service_Technorati_CosmosResultSet represents a Technorati Cosmos query
result set.

Zend_Service_Technorati_CosmosResultSet extends
Zend_Service_Technorati_ResultSet.

29.8.3. Zend_Service_Technorati_SearchResultSet
Zend_Service_Technorati_SearchResultSet represents a Technorati Search query
result set.

1317
Zend_Service

Zend_Service_Technorati_SearchResultSet extends
Zend_Service_Technorati_ResultSet.

29.8.4. Zend_Service_Technorati_TagResultSet
Zend_Service_Technorati_TagResultSet represents a Technorati Tag query result set.

Zend_Service_Technorati_TagResultSet extends
Zend_Service_Technorati_ResultSet.

29.8.5. Zend_Service_Technorati_DailyCountsResultSet
Zend_Service_Technorati_DailyCountsResultSet represents a Technorati
DailyCounts query result set.

Zend_Service_Technorati_DailyCountsResultSet extends
Zend_Service_Technorati_ResultSet.

29.8.6. Zend_Service_Technorati_TagsResultSet
Zend_Service_Technorati_TagsResultSet represents a Technorati TopTags or
BlogPostTags queries result set.

Zend_Service_Technorati_TagsResultSet extends
Zend_Service_Technorati_ResultSet.

29.8.7. Zend_Service_Technorati_Result
Zend_Service_Technorati_Result is the most essential result object. The scope of this
class is to be extended by a query specific child result class, and it should never be used to
initialize a standalone object.

29.8.8. Zend_Service_Technorati_CosmosResult
Zend_Service_Technorati_CosmosResult represents a single Technorati Cosmos query
result object. It is never returned as a standalone object, but it always belongs to a valid
Zend_Service_Technorati_CosmosResultSet object.

Zend_Service_Technorati_CosmosResult extends
Zend_Service_Technorati_Result.

29.8.9. Zend_Service_Technorati_SearchResult
Zend_Service_Technorati_SearchResult represents a single Technorati Search query
result object. It is never returned as a standalone object, but it always belongs to a valid
Zend_Service_Technorati_SearchResultSet object.

Zend_Service_Technorati_SearchResult extends
Zend_Service_Technorati_Result.

1318
Zend_Service

29.8.10. Zend_Service_Technorati_TagResult

Zend_Service_Technorati_TagResult represents a single Technorati Tag query result


object. It is never returned as a standalone object, but it always belongs to a valid
Zend_Service_Technorati_TagResultSet object.

Zend_Service_Technorati_TagResult extends
Zend_Service_Technorati_Result.

29.8.11. Zend_Service_Technorati_DailyCountsResult

Zend_Service_Technorati_DailyCountsResult represents a single Technorati


DailyCounts query result object. It is never returned as a standalone object, but it always belongs
to a valid Zend_Service_Technorati_DailyCountsResultSet object.

Zend_Service_Technorati_DailyCountsResult extends
Zend_Service_Technorati_Result.

29.8.12. Zend_Service_Technorati_TagsResult

Zend_Service_Technorati_TagsResult represents a single Technorati TopTags or


BlogPostTags query result object. It is never returned as a standalone object, but it always
belongs to a valid Zend_Service_Technorati_TagsResultSet object.

Zend_Service_Technorati_TagsResult extends
Zend_Service_Technorati_Result.

29.8.13. Zend_Service_Technorati_GetInfoResult

Zend_Service_Technorati_GetInfoResult represents a single Technorati GetInfo query


result object.

29.8.14. Zend_Service_Technorati_BlogInfoResult

Zend_Service_Technorati_BlogInfoResult represents a single Technorati BlogInfo


query result object.

29.8.15. Zend_Service_Technorati_KeyInfoResult

Zend_Service_Technorati_KeyInfoResult represents a single Technorati KeyInfo query


result object. It provides information about your Technorati API Key daily usage.

30. Zend_Service_Twitter
30.1. Introduction
Zend_Service_Twitter provides a client for the Twitter REST API.
Zend_Service_Twitter allows you to query the public timeline. If you provide a username

1319
Zend_Service

and password for Twitter, it will allow you to get and update your status, reply to friends, direct
message friends, mark tweets as favorite, and much more.

Zend_Service_Twitter is implementing a REST service, and all methods return an instance


of Zend_Rest_Client_Result.

Zend_Service_Twitter is broken up into subsections so you can easily identify which type
of call is being requested.

• account makes sure that your account credentials are valid, checks your API rate limit, and
ends the current session for the authenticated user.

• status retrieves the public and user timelines and shows, updates, destroys, and retrieves
replies for the authenticated user.

• user retrieves friends and followers for the authenticated user and returns extended
information about a passed user.

• directMessage retrieves the authenticated user's received direct messages, deletes direct
messages, and sends new direct messages.

• friendship creates and removes friendships for the authenticated user.

• favorite lists, creates, and removes favorite tweets.

• block blocks and unblocks users from following you.

30.2. Authentication
With the exception of fetching the public timeline, Zend_Service_Twitter requires
authentication to work. Twitter currently uses HTTP Basic Authentication. You can pass in your
username or registered email along with your password for Twitter to login.

Exemple 778. Creating the Twitter Class

The following code sample is how you create the Twitter service, pass in your username
and password, and verify that they are correct.

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');

// verify your credentials with Twitter


$response = $twitter->account->verifyCredentials();

You can also pass in an array that contains the username and password as the first
argument.

$userInfo = array('username' => 'foo', 'password' => 'bar');


$twitter = new Zend_Service_Twitter($userInfo);

// verify your credentials with Twitter


$response = $twitter->account->verifyCredentials();

30.3. Account Methods


• verifyCredentials() tests if supplied user credentials are valid with minimal overhead.

1320
Zend_Service

Exemple 779. Verifying credentials

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->account->verifyCredentials();

• endSession() signs users out of client-facing applications.

Exemple 780. Sessions ending

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->account->endSession();

• rateLimitStatus() returns the remaining number of API requests available to the


authenticating user before the API limit is reached for the current hour.

Exemple 781. Rating limit status

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->account->rateLimitStatus();

30.4. Status Methods


• publicTimeline() returns the 20 most recent statuses from non-protected users with a
custom user icon. The public timeline is cached by Twitter for 60 seconds.

Exemple 782. Retrieving public timeline

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->status->publicTimeline();

• friendsTimeline() returns the 20 most recent statuses posted by the authenticating user
and that user's friends.

Exemple 783. Retrieving friends timeline

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->status->friendsTimeline();

The friendsTimeline() method accepts an array of optional parameters to modify the


query.

• since narrows the returned results to just those statuses created after the specified date/
time (up to 24 hours old).

• page specifies which page you want to return.

• userTimeline() returns the 20 most recent statuses posted from the authenticating user.

Exemple 784. Retrieving user timeline

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->status->userTimeline();

The userTimeline() method accepts an array of optional parameters to modify the query.

1321
Zend_Service

• id specifies the ID or screen name of the user for whom to return the friends_timeline.

• since narrows the returned results to just those statuses created after the specified date/
time (up to 24 hours old).

• page specifies which page you want to return.

• count specifies the number of statuses to retrieve. May not be greater than 200.

• show() returns a single status, specified by the id parameter below. The status' author will
be returned inline.

Exemple 785. Showing user status

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->status->show(1234);

• update() updates the authenticating user's status. This method requires that you pass in the
status update that you want to post to Twitter.

Exemple 786. Updating user status

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->status->update('My Great Tweet');

The update() method accepts a second additional parameter.

• in_reply_to_status_id specifies the ID of an existing status that the status to be posted


is in reply to.

• replies() returns the 20 most recent @replies (status updates prefixed with @username)
for the authenticating user.

Exemple 787. Showing user replies

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->status->replies();

The replies() method accepts an array of optional parameters to modify the query.

• since narrows the returned results to just those statuses created after the specified date/
time (up to 24 hours old).

• page specifies which page you want to return.

• since_id returns only statuses with an ID greater than (that is, more recent than) the
specified ID.

• destroy() destroys the status specified by the required id parameter.

Exemple 788. Deleting user status

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->status->destroy(12345);

1322
Zend_Service

30.5. User Methods


• friends()r eturns up to 100 of the authenticating user's friends who have most recently
updated, each with current status inline.

Exemple 789. Retrieving user friends

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->user->friends();

The friends() method accepts an array of optional parameters to modify the query.

• id specifies the ID or screen name of the user for whom to return a list of friends.

• since narrows the returned results to just those statuses created after the specified date/
time (up to 24 hours old).

• page specifies which page you want to return.

• followers() returns the authenticating user's followers, each with current status inline.

Exemple 790. Retrieving user followers

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->user->followers();

The followers() method accepts an array of optional parameters to modify the query.

• id specifies the ID or screen name of the user for whom to return a list of followers.

• page specifies which page you want to return.

• show() returns extended information of a given user, specified by ID or screen name as per
the required id parameter below.

Exemple 791. Showing user informations

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->user->show('myfriend');

30.6. Direct Message Methods


• messages() returns a list of the 20 most recent direct messages sent to the authenticating
user.

Exemple 792. Retrieving recent direct messages received

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->directMessage->messages();

The message() method accepts an array of optional parameters to modify the query.

• since_id returns only direct messages with an ID greater than (that is, more recent than)
the specified ID.

1323
Zend_Service

• since narrows the returned results to just those statuses created after the specified date/
time (up to 24 hours old).

• page specifies which page you want to return.

• sent() returns a list of the 20 most recent direct messages sent by the authenticating user.

Exemple 793. Retrieving recent direct messages sent

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->directMessage->sent();

The sent() method accepts an array of optional parameters to modify the query.

• since_id returns only direct messages with an ID greater than (that is, more recent than)
the specified ID.

• since narrows the returned results to just those statuses created after the specified date/
time (up to 24 hours old).

• page specifies which page you want to return.

• new() sends a new direct message to the specified user from the authenticating user.
Requires both the user and text parameters below.

Exemple 794. Sending direct message

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->directMessage->new('myfriend', 'mymessage');

• destroy() destroys the direct message specified in the required id parameter. The
authenticating user must be the recipient of the specified direct message.

Exemple 795. Deleting direct message

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->directMessage->destroy(123548);

30.7. Friendship Methods


• create() befriends the user specified in the id parameter with the authenticating user.

Exemple 796. Creating friend

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->friendship->create('mynewfriend');

• destroy() discontinues friendship with the user specified in the id parameter and the
authenticating user.

Exemple 797. Deleting friend

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->friendship->destroy('myoldfriend');

1324
Zend_Service

• exists() tests if a friendship exists between the user specified in the id parameter and the
authenticating user.

Exemple 798. Checking friend existence

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->friendship->exists('myfriend');

30.8. Favorite Methods


• favorites() returns the 20 most recent favorite statuses for the authenticating user or user
specified by the id parameter.

Exemple 799. Retrieving favorites

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->favorite->favorites();

The favorites() method accepts an array of optional parameters to modify the query.

• id specifies the ID or screen name of the user for whom to request a list of favorite statuses.

• page specifies which page you want to return.

• create() favorites the status specified in the id parameter as the authenticating user.

Exemple 800. Creating favorites

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->favorite->create(12351);

• destroy() un-favorites the status specified in the id parameter as the authenticating user.

Exemple 801. Deleting favorites

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->favorite->destroy(12351);

30.9. Block Methods


• exists() checks if the authenticating user is blocking a target user and can optionally return
the blocked user's object if a block does exists.

Exemple 802. Checking if block exists

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');

// returns true or false


$response = $twitter->block->exists('blockeduser');

// returns the blocked user's info if the user is blocked


$response2 = $twitter->block->exists('blockeduser', true);

The favorites() method accepts a second optional parameter.

1325
Zend_Service

• returnResult specifies whether or not return the user object instead of just TRUE or
FALSE.

• create() blocks the user specified in the id parameter as the authenticating user and
destroys a friendship to the blocked user if one exists. Returns the blocked user in the
requested format when successful.

Exemple 803. Blocking a user

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->block->create('usertoblock);

• destroy() un-blocks the user specified in the id parameter for the authenticating user.
Returns the un-blocked user in the requested format when successful.

Exemple 804. Removing a block

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');


$response = $twitter->block->destroy('blockeduser');

• blocking() returns an array of user objects that the authenticating user is blocking.

Exemple 805. Who are you blocking

$twitter = new Zend_Service_Twitter('myusername', 'mysecretpassword');

// return the full user list from the first page


$response = $twitter->block->blocking();

// return an array of numeric user IDs from the second page


$response2 = $twitter->block->blocking(2, true);

The favorites() method accepts two optional parameters.

• page specifies which page ou want to return. A single page contains 20 IDs.

• returnUserIds specifies whether to return an array of numeric user IDs the authenticating
user is blocking instead of an array of user objects.

30.10. Zend_Service_Twitter_Search
30.10.1. Introduction
Zend_Service_Twitter_Search provides a client for the Twitter Search API. The Twitter
Search service is use to search Twitter. Currently, it only returns data in Atom or JSON format,
but a full REST service is in the future, which will support XML responses.

30.10.2. Twitter Trends


Returns the top ten queries that are currently trending on Twitter. The response includes the time
of the request, the name of each trending topic, and the url to the Twitter Search results page
for that topic. Currently the search API for trends only supports a JSON return so the function
returns an array.

$twitterSearch = new Zend_Service_Twitter_Search();


$twitterTrends = $twitterSearch->trends();

1326
Zend_Service

foreach ($twitterTrends as $trend) {


print $trend['name'] . ' - ' . $trend['url'] . PHP_EOL
}

The return array has two values in it:

• name is the name of trend.

• url is the URL to see the tweets for that trend.

30.10.3. Searching Twitter


Using the search method returns tweets that match a specific query. There are a number of
Search Operators that you can use to query with.

The search method can accept six different optional URL parameters passed in as an array:

• lang restricts the tweets to a given language. lang must be given by an ISO 639-1 code.

• rpp is the number of tweets to return per page, up to a maximum of 100.

• page specifies the page number to return, up to a maximum of roughly 1500 results (based
on rpp * page).

• since_id returns tweets with status IDs greater than the given ID.

• show_user specifies whether to add ">user<:" to the beginning of the tweet. This is useful for
readers that do not display Atom's author field. The default is "FALSE".

• geocode returns tweets by users located within a given radius of the given latitude/longitude,
where the user's location is taken from their Twitter profile. The parameter value is specified
by "latitude,longitude,radius", where radius units must be specified as either "mi" (miles) or
"km" (kilometers).

Exemple 806. JSON Search Example

The following code sample will return an array with the search results.

$twitterSearch = new Zend_Service_Twitter_Search('json');


$searchResults = $twitterSearch->search('zend', array('lang' => 'en'));

Exemple 807. ATOM Search Example

The following code sample will return a Zend_Feed_Atom object.

$twitterSearch = new Zend_Service_Twitter_Search('atom');


$searchResults = $twitterSearch->search('zend', array('lang' => 'en'));

30.10.4. Zend-specific Accessor Methods


While the Twitter Search API only specifies two methods, Zend_Service_Twitter_Search
has additional methods that may be used for retrieving and modifying internal properties.

• getResponseType() and setResponseType() allow you to retrieve and modify the


response type of the search between JSON and Atom.

1327
Zend_Service

31. Zend_Service_WindowsAzure
31.1. Introduction
Windows Azure is the name for Microsoft’s Software + Services platform, an operating system in
the cloud providing services for hosting, management, scalable storage with support for simple
blobs, tables, and queues, as well as a management infrastructure for provisioning and geo-
distribution of cloud-based services, and a development platform for the Azure Services layer.

31.2. Installing the Windows Azure SDK


There are two development scenario's when working with Windows Azure.

• You can develop your application using Zend_Service_WindowsAzure and the Windows
Azure SDK, which provides a local developent environment of the services provided by
Windows Azure's cloud infrastructure.

• You can develop your application using Zend_Service_WindowsAzure, working directly


with the Windows Azure cloud infrastructure.

The first case requires you to install the Windows Azure SDK on your development machine. It
is currently only available for Windows environments; progress is being made on a Java-based
version of the SDK which can run on any platform.

The latter case requires you to have an account at Azure.com.

31.3. API Documentation


The Zend_Service_WindowsAzure class provides the PHP wrapper to the Windows Azure
REST interface. Please consult the REST documentation for detailed description of the service.
You will need to be familiar with basic concepts in order to use this service.

31.4. Features
Zend_Service_WindowsAzure provides the following functionality:

• PHP classes for Windows Azure Blobs, Tables and Queues (for CRUD operations)

• Helper Classes for HTTP transport, AuthN/AuthZ, REST and Error Management

• Manageability, Instrumentation and Logging support

31.5. Architecture
Zend_Service_WindowsAzure provides access to Windows Azure's storage, computation
and management interfaces by abstracting the REST/XML interface Windows Azure provides
into a simple PHP API.

An application built using Zend_Service_WindowsAzure can access Windows Azure's


features, no matter if it is hosted on the Windows Azure platform or on an in-premise web server.

31.6. Zend_Service_WindowsAzure_Storage_Blob
Blob Storage stores sets of binary data. Blob storage offers the following three resources: the
storage account, containers, and blobs. Within your storage account, containers provide a way
to organize sets of blobs within your storage account.

1328
Zend_Service

Blob Storage is offered by Windows Azure as a REST API which is wrapped by the
Zend_Service_WindowsAzure_Storage_Blob class in order to provide a native PHP
interface to the storage account.

31.6.1. API Examples

This topic lists some examples of using the Zend_Service_WindowsAzure_Storage_Blob


class. Other features are available in the download package, as well as a detailed API
documentation of those features.

31.6.1.1. Creating a storage container

Using the following code, a blob storage container can be created on development storage.

Exemple 808. Creating a storage container

$storageClient = new Zend_Service_WindowsAzure_Storage_Blob();


$result = $storageClient->createContainer('testcontainer');

echo 'Container name is: ' . $result->Name;

31.6.1.2. Deleting a storage container

Using the following code, a blob storage container can be removed from development storage.

Exemple 809. Deleting a storage container

$storageClient = new Zend_Service_WindowsAzure_Storage_Blob();


$storageClient->deleteContainer('testcontainer');

31.6.1.3. Storing a blob

Using the following code, a blob can be uploaded to a blob storage container on development
storage. Note that the container has already been created before.

Exemple 810. Storing a blob

$storageClient = new Zend_Service_WindowsAzure_Storage_Blob();

// upload /home/maarten/example.txt to Azure


$result = $storageClient->putBlob(
'testcontainer', 'example.txt', '/home/maarten/example.txt'
);

echo 'Blob name is: ' . $result->Name;

31.6.1.4. Copying a blob

Using the following code, a blob can be copied from inside the storage account. The advantage
of using this method is that the copy operation occurs in the Azure cloud and does not involve
downloading the blob. Note that the container has already been created before.

1329
Zend_Service

Exemple 811. Copying a blob

$storageClient = new Zend_Service_WindowsAzure_Storage_Blob();

// copy example.txt to example2.txt


$result = $storageClient->copyBlob(
'testcontainer', 'example.txt', 'testcontainer', 'example2.txt'
);

echo 'Copied blob name is: ' . $result->Name;

31.6.1.5. Downloading a blob

Using the following code, a blob can be downloaded from a blob storage container on
development storage. Note that the container has already been created before and a blob has
been uploaded.

Exemple 812. Downloading a blob

$storageClient = new Zend_Service_WindowsAzure_Storage_Blob();

// download file to /home/maarten/example.txt


$storageClient->getBlob(
'testcontainer', 'example.txt', '/home/maarten/example.txt'
);

31.6.1.6. Making a blob publicly available

By default, blob storage containers on Windows Azure are protected from public viewing. If any
user on the Internet should have access to a blob container, its ACL can be set to public. Note
that this applies to a complete container and not to a single blob!

Using the following code, blob storage container ACL can be set on development storage. Note
that the container has already been created before.

Exemple 813. Making a blob publicly available

$storageClient = new Zend_Service_WindowsAzure_Storage_Blob();

// make container publicly available


$storageClient->setContainerAcl('testcontainer', Zend_Service_WindowsAzure_Storage_Blob:

31.6.2. Root container


Windows Azure Blob Storage provides support to work with a "root container". This
means that a blob can be stored in the root of your storage account, i.e. http://
myaccount.blob.core.windows.net/somefile.txt.

In order to work with the root container, it should first be created using the createContainer()
method, naming the container $root. All other operations on the root container should be issued
with the container name set to $root.

31.6.3. Blob storage stream wrapper


The Windows Azure SDK for PHP provides support for registering a blob storage client as a
PHP file stream wrapper. The blob storage stream wrapper provides support for using regular

1330
Zend_Service

file operations on Windows Azure Blob Storage. For example, one can open a file from Windows
Azure Blob Storage with the fopen() function:

Exemple 814. Example usage of blob storage stream wrapper

$fileHandle = fopen('azure://mycontainer/myfile.txt', 'r');

// ...

fclose($fileHandle);

In order to do this, the Windows Azure SDK for PHP blob storage client must be registered as a
stream wrapper. This can be done by calling the registerStreamWrapper() method:

Exemple 815. Registering the blob storage stream wrapper

$storageClient = new Zend_Service_WindowsAzure_Storage_Blob();


$storageClient->registerStreamWrapper(); // registers azure:// on this storage client

// or:

$storageClient->registerStreamWrapper('blob://'); // regiters blob:// on this storage cl

To unregister the stream wrapper, the unregisterStreamWrapper() method can be used.

31.6.4. Shared Access Signature

Windows Azure Bob Storage provides a feature called "Shared Access Signatures". By default,
there is only one level of authorization possible in Windows Azure Blob Storage: either a
container is private or it is public. Shared Access Signatures provide a more granular method of
authorization: read, write, delete and list permissions can be assigned on a container or a blob
and given to a specific client using an URL-based model.

An example would be the following signature:

http://phpstorage.blob.core.windows.net/phpazuretestshared1?st=2009-08-17T09%3A06%3A17Z&se=2009-08-17T09%3A5

The above signature gives write access to the "phpazuretestshared1" container of the
"phpstorage" account.

31.6.4.1. Generating a Shared Access Signature

When you are the owner of a Windows Azure Bob Storage account, you
can create and distribute a shared access key for any type of resource in
your account. To do this, the generateSharedAccessUrl() method of the
Zend_Service_WindowsAzure_Storage_Blob storage client can be used.

The following example code will generate a Shared Access Signature for write access in a
container named "container1", within a timeframe of 3000 seconds.

1331
Zend_Service

Exemple 816. Generating a Shared Access Signature for a container

$storageClient = new Zend_Service_WindowsAzure_Storage_Blob();


$sharedAccessUrl = storageClient->generateSharedAccessUrl(
'container1',
'',
'c',
'w',
$storageClient ->isoDate(time() - 500),
$storageClient ->isoDate(time() + 3000)
);

The following example code will generate a Shared Access Signature for read access in a blob
named test.txt in a container named "container1" within a time frame of 3000 seconds.

Exemple 817. Generating a Shared Access Signature for a blob

$storageClient = new Zend_Service_WindowsAzure_Storage_Blob();


$sharedAccessUrl = storageClient->generateSharedAccessUrl(
'container1',
'test.txt',
'b',
'r',
$storageClient ->isoDate(time() - 500),
$storageClient ->isoDate(time() + 3000)
);

31.6.4.2. Working with Shared Access Signatures from others

When you receive a Shared Access Signature from someone else, you can use the Windows
Azure SDK for PHP to work with the addressed resource. For example, the following signature
can be retrieved from the owner of a storage account:

http://phpstorage.blob.core.windows.net/phpazuretestshared1?st=2009-08-17T09%3A06%3A17Z&se=2009-08-17T09%3A5

The above signature gives write access to the "phpazuretestshared1" "container" of the
phpstorage account. Since the shared key for the account is not known, the Shared Access
Signature can be used to work with the authorized resource.

Exemple 818. Consuming a Shared Access Signature for a container

$storageClient = new Zend_Service_WindowsAzure_Storage_Blob(


'blob.core.windows.net', 'phpstorage', ''
);
$storageClient->setCredentials(
new Zend_Service_WindowsAzure_Credentials_SharedAccessSignature()
);
$storageClient->getCredentials()->setPermissionSet(array(
'http://phpstorage.blob.core.windows.net/phpazuretestshared1?st=2009-08-17T09%3A06%3
));
$storageClient->putBlob(
'phpazuretestshared1', 'NewBlob.txt', 'C:\Files\dataforazure.txt'
);

Note that there was no explicit permission to write to a specific blob. Instead, the Windows Azure
SDK for PHP determined that a permission was required to either write to that specific blob, or

1332
Zend_Service

to write to its container. Since only a signature was available for the latter, the Windows Azure
SDK for PHP chose those credentials to perform the request on Windows Azure blob storage.

31.7. Zend_Service_WindowsAzure_Storage_Table
The Table service offers structured storage in the form of tables.

Table Storage is offered by Windows Azure as a REST API which is wrapped by the
Zend_Service_WindowsAzure_Storage_Table class in order to provide a native PHP
interface to the storage account.

This topic lists some examples of using the Zend_Service_WindowsAzure_Storage_Table


class. Other features are available in the download package, as well as a detailed API
documentation of those features.

Note that development table storage (in the Windows Azure SDK) does not support all features
provided by the API. Therefore, the examples listed on this page are to be used on Windows
Azure production table storage.

31.7.1. Operations on tables


This topic lists some samples of operations that can be executed on tables.

31.7.1.1. Creating a table

Using the following code, a table can be created on Windows Azure production table storage.

Exemple 819. Creating a table

$storageClient = new Zend_Service_WindowsAzure_Storage_Table(


'table.core.windows.net', 'myaccount', 'myauthkey'
);
$result = $storageClient->createTable('testtable');

echo 'New table name is: ' . $result->Name;

31.7.1.2. Listing all tables

Using the following code, a list of all tables in Windows Azure production table storage can be
queried.

Exemple 820. Listing all tables

$storageClient = new Zend_Service_WindowsAzure_Storage_Table(


'table.core.windows.net', 'myaccount', 'myauthkey'
);
$result = $storageClient->listTables();
foreach ($result as $table) {
echo 'Table name is: ' . $table->Name . "\r\n";
}

31.7.2. Operations on entities


Tables store data as collections of entities. Entities are similar to rows. An entity has a primary
key and a set of properties. A property is a named, typed-value pair, similar to a column.

1333
Zend_Service

The Table service does not enforce any schema for tables, so two entities in the same table may
have different sets of properties. Developers may choose to enforce a schema on the client side.
A table may contain any number of entities.

Zend_Service_WindowsAzure_Storage_Table provides 2 ways of working with entities:

• Enforced schema

• No enforced schema

All examples will make use of the following enforced schema class.

Exemple 821. Enforced schema used in samples

class SampleEntity extends Zend_Service_WindowsAzure_Storage_TableEntity


{
/**
* @azure Name
*/
public $Name;

/**
* @azure Age Edm.Int64
*/
public $Age;

/**
* @azure Visible Edm.Boolean
*/
public $Visible = false;
}

Note that if no schema class is passed into table storage


methods, Zend_Service_WindowsAzure_Storage_Table automatically works with
Zend_Service_WindowsAzure_Storage_DynamicTableEntity.

31.7.2.1. Enforced schema entities

To enforce a schema on the client side using the


Zend_Service_WindowsAzure_Storage_Table class, you can create a class which
inherits Zend_Service_WindowsAzure_Storage_TableEntity. This class provides some
basic functionality for the Zend_Service_WindowsAzure_Storage_Table class to work
with a client-side schema.

Base properties provided by Zend_Service_WindowsAzure_Storage_TableEntity are:

• PartitionKey (exposed through getPartitionKey() and setPartitionKey())

• RowKey (exposed through getRowKey() and setRowKey())

• Timestamp (exposed through getTimestamp() and setTimestamp())

• Etag value (exposed through getEtag() and setEtag())

Here's a sample class inheriting Zend_Service_WindowsAzure_Storage_TableEntity:

1334
Zend_Service

Exemple 822. Sample enforced schema class

class SampleEntity extends Zend_Service_WindowsAzure_Storage_TableEntity


{
/**
* @azure Name
*/
public $Name;

/**
* @azure Age Edm.Int64
*/
public $Age;

/**
* @azure Visible Edm.Boolean
*/
public $Visible = false;
}

The Zend_Service_WindowsAzure_Storage_Table class will map any class inherited from


Zend_Service_WindowsAzure_Storage_TableEntity to Windows Azure table storage
entities with the correct data type and property name. All there is to storing a property in Windows
Azure is adding a docblock comment to a public property or public getter/setter, in the following
format:

Exemple 823. Enforced property

/**
* @azure <property name in Windows Azure> <optional property type>
*/
public $<property name in PHP>;

Let's see how to define a propety "Age" as an integer on Windows Azure table storage:

Exemple 824. Sample enforced property

/**
* @azure Age Edm.Int64
*/
public $Age;

Note that a property does not necessarily have to be named the same on Windows Azure table
storage. The Windows Azure table storage property name can be defined as well as the type.

The following data types are supported:

• Edm.Binary - An array of bytes up to 64 KB in size.

• Edm.Boolean - A boolean value.

• Edm.DateTime - A 64-bit value expressed as Coordinated Universal Time (UTC). The


supported DateTime range begins from 12:00 midnight, January 1, 1601 A.D. (C.E.),
Coordinated Universal Time (UTC). The range ends at December 31st, 9999.

• Edm.Double - A 64-bit floating point value.

1335
Zend_Service

• Edm.Guid - A 128-bit globally unique identifier.

• Edm.Int32 - A 32-bit integer.

• Edm.Int64 - A 64-bit integer.

• Edm.String - A UTF-16-encoded value. String values may be up to 64 KB in size.

31.7.2.2. No enforced schema entities (a.k.a. DynamicEntity)

To use the Zend_Service_WindowsAzure_Storage_Table class


without defining a schema, you can make use of the
Zend_Service_WindowsAzure_Storage_DynamicTableEntity class. This class inherits
Zend_Service_WindowsAzure_Storage_TableEntity like an enforced schema class
does, but contains additional logic to make it dynamic and not bound to a schema.

Base properties provided by


Zend_Service_WindowsAzure_Storage_DynamicTableEntity are:

• PartitionKey (exposed through getPartitionKey() and setPartitionKey())

• RowKey (exposed through getRowKey() and setRowKey())

• Timestamp (exposed through getTimestamp() and setTimestamp())

• Etag value (exposed through getEtag() and setEtag())

Other properties can be added on the fly. Their Windows Azure table storage type will be
determined on-the-fly:

Exemple 825. Dynamicaly adding properties to


Zend_Service_WindowsAzure_Storage_DynamicTableEntity

$target = new Zend_Service_WindowsAzure_Storage_DynamicTableEntity(


'partition1', '000001'
);
$target->Name = 'Name'; // Will add property "Name" of type "Edm.String"
$target->Age = 25; // Will add property "Age" of type "Edm.Int32"

Optionally, a property type can be enforced:

Exemple 826. Forcing property types on


Zend_Service_WindowsAzure_Storage_DynamicTableEntity

$target = new Zend_Service_WindowsAzure_Storage_DynamicTableEntity(


'partition1', '000001'
);
$target->Name = 'Name'; // Will add property "Name" of type "Edm.String"
$target->Age = 25; // Will add property "Age" of type "Edm.Int32"

// Change type of property "Age" to "Edm.Int32":


$target->setAzurePropertyType('Age', 'Edm.Int64');

The Zend_Service_WindowsAzure_Storage_Table class automatically works with


Zend_Service_WindowsAzure_Storage_TableEntity if no specific class is passed into
Table Storage methods.

1336
Zend_Service

31.7.2.3. Entities API examples

31.7.2.3.1. Inserting an entity

Using the following code, an entity can be inserted into a table named "testtable". Note that the
table has already been created before.

Exemple 827. Inserting an entity

$entity = new SampleEntity ('partition1', 'row1');


$entity->FullName = "Maarten";
$entity->Age = 25;
$entity->Visible = true;

$storageClient = new Zend_Service_WindowsAzure_Storage_Table(


'table.core.windows.net', 'myaccount', 'myauthkey'
);
$result = $storageClient->insertEntity('testtable', $entity);

// Check the timestamp and etag of the newly inserted entity


echo 'Timestamp: ' . $result->getTimestamp() . "\n";
echo 'Etag: ' . $result->getEtag() . "\n";

31.7.2.3.2. Retrieving an entity by partition key and row key

Using the following code, an entity can be retrieved by partition key and row key. Note that the
table and entity have already been created before.

Exemple 828. Retrieving an entity by partition key and row key

$storageClient = new Zend_Service_WindowsAzure_Storage_Table(


'table.core.windows.net', 'myaccount', 'myauthkey'
);
$entity= $storageClient->retrieveEntityById(
'testtable', 'partition1', 'row1', 'SampleEntity'
);

31.7.2.3.3. Updating an entity

Using the following code, an entity can be updated. Note that the table and entity have already
been created before.

Exemple 829. Updating an entity

$storageClient = new Zend_Service_WindowsAzure_Storage_Table(


'table.core.windows.net', 'myaccount', 'myauthkey'
);
$entity = $storageClient->retrieveEntityById(
'testtable', 'partition1', 'row1', 'SampleEntity'
);

$entity->Name = 'New name';


$result = $storageClient->updateEntity('testtable', $entity);

If you want to make sure the entity has not been updated before, you can make sure the Etag
of the entity is checked. If the entity already has had an update, the update will fail to make sure
you do not overwrite any newer data.

1337
Zend_Service

Exemple 830. Updating an entity (with Etag check)

$storageClient = new Zend_Service_WindowsAzure_Storage_Table(


'table.core.windows.net', 'myaccount', 'myauthkey'
);
$entity = $storageClient->retrieveEntityById(
'testtable', 'partition1', 'row1', 'SampleEntity'
);

$entity->Name = 'New name';

// last parameter instructs the Etag check:


$result = $storageClient->updateEntity('testtable', $entity, true);

31.7.2.3.4. Deleting an entity

Using the following code, an entity can be deleted. Note that the table and entity have already
been created before.

Exemple 831. Deleting an entity

$storageClient = new Zend_Service_WindowsAzure_Storage_Table(


'table.core.windows.net', 'myaccount', 'myauthkey'
);
$entity = $storageClient->retrieveEntityById(
'testtable', 'partition1', 'row1', 'SampleEntity'
);
$result = $storageClient->deleteEntity('testtable', $entity);

31.7.2.4. Performing queries

Queries in Zend_Service_WindowsAzure_Storage_Table table storage can be performed


in two ways:

• By manually creating a filter condition (involving learning a new query language)

• By using the fluent interface provided by the


Zend_Service_WindowsAzure_Storage_Table

Using the following code, a table can be queried using a filter condition. Note that the table and
entities have already been created before.

Exemple 832. Performing queries using a filter condition

$storageClient = new Zend_Service_WindowsAzure_Storage_Table(


'table.core.windows.net', 'myaccount', 'myauthkey'
);
$entities = $storageClient->storageClient->retrieveEntities(
'testtable',
'Name eq \'Maarten\' and PartitionKey eq \'partition1\'',
'SampleEntity'
);

foreach ($entities as $entity) {


echo 'Name: ' . $entity->Name . "\n";
}

1338
Zend_Service

Using the following code, a table can be queried using a fluent interface. Note that the table and
entities have already been created before.

Exemple 833. Performing queries using a fluent interface

$storageClient = new Zend_Service_WindowsAzure_Storage_Table(


'table.core.windows.net', 'myaccount', 'myauthkey'
);
$entities = $storageClient->storageClient->retrieveEntities(
'testtable',
$storageClient->select()
->from($tableName)
->where('Name eq ?', 'Maarten')
->andWhere('PartitionKey eq ?', 'partition1'),
'SampleEntity'
);

foreach ($entities as $entity) {


echo 'Name: ' . $entity->Name . "\n";
}

31.7.2.5. Batch operations

This topic demonstrates how to use the table entity group transaction features provided by
Windows Azure table storage. Windows Azure table storage supports batch transactions on
entities that are in the same table and belong to the same partition group. A transaction can
include at most 100 entities.

The following example uses a batch operation (transaction) to insert a set of entities into the
"testtable" table. Note that the table has already been created before.

Exemple 834. Executing a batch operation

$storageClient = new Zend_Service_WindowsAzure_Storage_Table(


'table.core.windows.net', 'myaccount', 'myauthkey'
);

// Start batch
$batch = $storageClient->startBatch();

// Insert entities in batch


$entities = generateEntities();
foreach ($entities as $entity) {
$storageClient->insertEntity($tableName, $entity);
}

// Commit
$batch->commit();

31.7.3. Table storage session handler

When running a PHP application on the Windows Azure platform in a load-balanced mode
(running 2 Web Role instances or more), it is important that PHP session data can be
shared between multiple Web Role instances. The Windows Azure SDK for PHP provides the
Zend_Service_WindowsAzure_SessionHandler class, which uses Windows Azure Table
Storage as a session handler for PHP applications.

1339
Zend_Service

To use the Zend_Service_WindowsAzure_SessionHandler session handler, it should be


registered as the default session handler for your PHP application:

Exemple 835. Registering table storage session handler

$storageClient = new Zend_Service_WindowsAzure_Storage_Table(


'table.core.windows.net', 'myaccount', 'myauthkey'
);

$sessionHandler = new Zend_Service_WindowsAzure_SessionHandler(


$storageClient , 'sessionstable'
);
$sessionHandler->register();

The above classname registers the Zend_Service_WindowsAzure_SessionHandler


session handler and will store sessions in a table called "sessionstable".

After registration of the Zend_Service_WindowsAzure_SessionHandler session handler,


sessions can be started and used in the same way as a normal PHP session:

Exemple 836. Using table storage session handler

$storageClient = new Zend_Service_WindowsAzure_Storage_Table(


'table.core.windows.net', 'myaccount', 'myauthkey'
);

$sessionHandler = new Zend_Service_WindowsAzure_SessionHandler(


$storageClient , 'sessionstable'
);
$sessionHandler->register();

session_start();

if (!isset($_SESSION['firstVisit'])) {
$_SESSION['firstVisit'] = time();
}

// ...

The Zend_Service_WindowsAzure_SessionHandler session handler


should be registered before a call to session_start() is made!

31.8. Zend_Service_WindowsAzure_Storage_Queue
The Queue service stores messages that may be read by any client who has access to the
storage account.

A queue can contain an unlimited number of messages, each of which can be up to 8 KB in size.
Messages are generally added to the end of the queue and retrieved from the front of the queue,
although first in/first out (FIFO) behavior is not guaranteed. If you need to store messages larger
than 8 KB, you can store message data as a queue or in a table and then store a reference to
the data as a message in a queue.

Queue Storage is offered by Windows Azure as a REST API which is wrapped by the
Zend_Service_WindowsAzure_Storage_Queue class in order to provide a native PHP
interface to the storage account.

1340
Zend_Service

31.8.1. API Examples


This topic lists some examples of using the Zend_Service_WindowsAzure_Storage_Queue
class. Other features are available in the download package, as well as a detailed API
documentation of those features.

31.8.1.1. Creating a queue

Using the following code, a queue can be created on development storage.

Exemple 837. Creating a queue

$storageClient = new Zend_Service_WindowsAzure_Storage_Queue();


$result = $storageClient->createQueue('testqueue');

echo 'Queue name is: ' . $result->Name;

31.8.1.2. Deleting a queue

Using the following code, a queue can be removed from development storage.

Exemple 838. Deleting a queue

$storageClient = new Zend_Service_WindowsAzure_Storage_Queue();


$storageClient->deleteQueue('testqueue');

31.8.1.3. Adding a message to a queue

Using the following code, a message can be added to a queue on development storage. Note
that the queue has already been created before.

Exemple 839. Adding a message to a queue

$storageClient = new Zend_Service_WindowsAzure_Storage_Queue();

// 3600 = time-to-live of the message, if omitted defaults to 7 days


$storageClient->putMessage('testqueue', 'This is a test message', 3600);

31.8.1.4. Reading a message from a queue

Using the following code, a message can be read from a queue on development storage. Note
that the queue and message have already been created before.

Exemple 840. Reading a message from a queue

$storageClient = new Zend_Service_WindowsAzure_Storage_Queue();

// retrieve 10 messages at once


$messages = $storageClient->getMessages('testqueue', 10);

foreach ($messages as $message) {


echo $message->MessageText . "\r\n";
}

The messages that are read using getMessages() will be invisible in the queue for 30 seconds,
after which the messages will re-appear in the queue. To mark a message as processed and
remove it from the queue, use the deleteMessage() method.

1341
Zend_Service

Exemple 841. Marking a message as processed

$storageClient = new Zend_Service_WindowsAzure_Storage_Queue();

// retrieve 10 messages at once


$messages = $storageClient->getMessages('testqueue', 10);

foreach ($messages as $message) {


echo $message . "\r\n";

// Mark the message as processed


$storageClient->deleteMessage('testqueue', $message);
}

31.8.1.5. Check if there are messages in a queue

Using the following code, a queue can be checked for new messages. Note that the queue and
message have already been created before.

Exemple 842. Check if there are messages in a queue

$storageClient = new Zend_Service_WindowsAzure_Storage_Queue();

// retrieve 10 messages at once


$messages = $storageClient->peekMessages('testqueue', 10);

foreach ($messages as $message) {


echo $message->MessageText . "\r\n";
}

Note that messages that are read using peekMessages() will not become invisible in the queue,
nor can they be marked as processed using the deleteMessage() method. To do this, use
getMessages() instead.

32. Zend_Service_Yahoo
32.1. Introduction
Zend_Service_Yahoo est une API simple pour utiliser les APIs REST de Yahoo!
Zend_Service_Yahoo vous permet de rechercher dans Yahoo! Web Search, Yahoo! News,
Yahoo! Local et Yahoo! Images. Pour pouvoir utiliser l'API REST de Yahoo!, vous devez avoir un
identifiant Yahoo Application. Pour obtenir un identifiant Yahoo Application, veuillez compléter
et soumettre le formulaire de demande d'identifiant Yahoo! Application.

32.2. Rechercher sur le Web avec Yahoo!


Zend_Service_Yahoo vous permet d'effectuer des recherches sur le net avec Yahoo! en
utilisant la méthode webSearch(), qui accepte une chaîne de requête en paramètre, et un
tableau d'options de recherche comme second paramètre. Pour la liste détaillée des options,
veuillez vous référer à la documentation Yahoo! Web Search. La méthode webSearch()
retourne un objet Zend_Service_Yahoo_WebResultSet.

1342
Zend_Service

Exemple 843. Rechercher sur le Web avec Yahoo!

$yahoo = new Zend_Service_Yahoo("ID_APPLICATION_YAHOO");


$results = $yahoo->webSearch('PHP');
foreach ($results as $result) {
echo $result->Title .'<br />';
}

32.3. Trouver des images avec Yahoo!


Vous pouvez rechercher des images avec Yahoo! en utilisant la méthode imageSearch() de
Zend_Service_Yahoo. Cette méthode accepte une chaîne de requête en paramètres, et un
tableau d'options en second paramètre optionnel. Pour la liste complète des options, veuillez
vous référer à la documentation Yahoo! Image Search.

Exemple 844. Trouver des images avec Yahoo!

$yahoo = new Zend_Service_Yahoo("ID_APPLICATION_YAHOO");


$results = $yahoo->imageSearch('PHP');
foreach ($results as $result) {
echo $result->Title .'<br />';
}

32.4. Trouver des vidéos avec Yahoo!


Vous pouvez rechercher des vidéos avec Yahoo! en utilisant la méthode videoSearch()
de Zend_Service_Yahoo. Pour la liste complète des options, veuillez vous référer à la
documentation Yahoo! Video Search.

Exemple 845. Trouver des vidéos avec Yahoo!

$yahoo = new Zend_Service_Yahoo("YAHOO_APPLICATION_ID");


$results = $yahoo->videoSearch('PHP');
foreach ($results as $result) {
echo $result->Title .'<br />';
}

32.5. Trouver des entreprises et des services locaux avec Yahoo!


Vous pouvez rechercher des entreprises et des services locaux avec Yahoo!, en utilisant la
méthode localSearch(). Pour plus de détails, veuillez vous référer à la documentation Yahoo!
Local Search.

Exemple 846. Trouver des entreprises locales et des services avec Yahoo!

$yahoo = new Zend_Service_Yahoo("ID_APPLICATION_YAHOO");


$results = $yahoo->localSearch('Ordinateurs Apple', array('zip' => '95014'));
foreach ($results as $result) {
echo $result->Title .'<br />';
}

32.6. Rechercher dans Yahoo! News


Rechercher dans Yahoo! News est simple, il vous suffit simplement d'utiliser la méthode
newsSearch(), comme le montre l'exemple suivant. Pour plus de détails, veuillez vous référer
à la documentation Yahoo! News Search.

1343
Zend_Service

Exemple 847. Recherche dans Yahoo! News

$yahoo = new Zend_Service_Yahoo("ID_APPLICATION_YAHOO");


$results = $yahoo->newsSearch('PHP');
foreach ($results as $result) {
echo $result->Title .'<br />';
}

32.7. Rechercher avec Yahoo! Site Explorer Inbound Links


Rechercher avec Yahoo! Site Explorer Inbound Links est simple, il vous suffit simplement
d'utiliser la méthode inlinkDataSearch() comme le montre l'exemple suivant. Pour plus
de détails, veuillez vous référer à la documentation Yahoo! Site Explorer Inbound Links
Documentation.

Exemple 848. Recherche avec Yahoo! Site Explorer Inbound Links

$yahoo = new Zend_Service_Yahoo("ID_APPLICATION_YAHOO");


$results = $yahoo->inlinkDataSearch('http://framework.zend.com/');
foreach ($results as $result) {
echo $result->Title .'<br />';
}

32.8. Rechercher avec Yahoo! Site Explorer's PageData


Rechercher avec Yahoo! Site Explorer's PageData est simple, il vous suffit simplement d'utiliser
la méthode pageDataSearch() comme le montre l'exemple suivant. Pour plus de détails,
veuillez vous référer à la documentation Yahoo! Site Explorer PageData Documentation.

Exemple 849. Recherche avec Yahoo! Site Explorer's PageData

$yahoo = new Zend_Service_Yahoo("ID_APPLICATION_YAHOO");


$results = $yahoo->pageDataSearch('http://framework.zend.com/');
foreach ($results as $result) {
echo $result->Title .'<br />';
}

32.9. Classes Zend_Service_Yahoo


Les classes sont toutes retournées par les diverses recherches Yahoo!. Chaque type de
recherche retourne un jeu de résultat spécifique sur lequel on peut facilement itérer, avec
chaque résultat contenu dans un résultat du type de l'objet. Toutes les classes de jeu de résultat
implémentent l'interface SeekableIterator, permettant des itérations et une recherche sur
un résultat particulier.

• Zend_Service_Yahoo_ResultSet

• Zend_Service_Yahoo_WebResultSet

• Zend_Service_Yahoo_ImageResultSet

• Zend_Service_Yahoo_VideoResultSet

• Zend_Service_Yahoo_LocalResultSet

1344
Zend_Service

• Zend_Service_Yahoo_NewsResultSet

• Zend_Service_Yahoo_InlinkDataResultSet

• Zend_Service_Yahoo_PageDataResultSet

• Zend_Service_Yahoo_Result

• Zend_Service_Yahoo_WebResult

• Zend_Service_Yahoo_ImageResult

• Zend_Service_Yahoo_VideoResult

• Zend_Service_Yahoo_LocalResult

• Zend_Service_Yahoo_NewsResult

• Zend_Service_Yahoo_InlinkDataResult

• Zend_Service_Yahoo_PageDataResult

• Zend_Service_Yahoo_Image

32.9.1. Zend_Service_Yahoo_ResultSet
Chaque jeu de résultat spécifique à la recherche est étendu de cette classe de base.

Chaque jeu de résultat spécifique à la recherche retourne un objet Zend_Service_Yahoo_Result


spécifique à la recherche.

32.9.1.1. Zend_Service_Yahoo_ResultSet::totalResults()

int totalResults();

Retourne le nombre de résultats retourné par la recherche.

32.9.1.2. Propriétés

Tableau 138. Zend_Service_Yahoo_ResultSet

Nom Type Description


totalResultsAvailable int Nombre total de résultats
trouvés.
totalResultsReturned int Nombre de résultats pour le jeu
de résultat courant.
firstResultPosition int Position du premier résultat
dans ce jeu, par rapport au
nombre total des résultats.

Retour à la liste des classes

32.9.2. Zend_Service_Yahoo_WebResultSet
Zend_Service_Yahoo_WebResultSet représente un jeu de résultat Yahoo! Web Search.

1345
Zend_Service

Zend_Service_Yahoo_WebResultSet étend
Zend_Service_Yahoo_ResultSet.

Retour à la liste des classes

32.9.3. Zend_Service_Yahoo_ImageResultSet
Zend_Service_Yahoo_ImageResultSet représente un jeu de résultat Yahoo! Image
Search.

Zend_Service_Yahoo_ImageResultSet étend
Zend_Service_Yahoo_ResultSet

Retour à la liste des classes

32.9.4. Zend_Service_Yahoo_VideoResultSet
Zend_Service_Yahoo_VideoResultSet représente un jeu de résultat Yahoo! Video
Search.

Zend_Service_Yahoo_VideoResultSet étend
Zend_Service_Yahoo_ResultSet

Retour à la liste des classes

32.9.5. Zend_Service_Yahoo_LocalResultSet
Zend_Service_Yahoo_LocalResultSet représente un jeu de résultats Yahoo! Local
Search.

Tableau 139. Propriétés de Zend_Service_Yahoo_LocalResultSet

Nom Type Description


resultSetMapURL string L'URL de la page Web
contenant une carte graphique
contenant tous les résultats
affichés dessus.

Zend_Service_Yahoo_LocalResultSet étend
Zend_Service_Yahoo_ResultSet

Retour à la liste des classes

32.9.6. Zend_Service_Yahoo_NewsResultSet
Zend_Service_Yahoo_NewsResultSet représente un jeu de résultat Yahoo! News Search.

Zend_Service_Yahoo_NewsResultSet étend
Zend_Service_Yahoo_ResultSet

1346
Zend_Service

Retour à la liste des classes

32.9.7. Zend_Service_Yahoo_InlinkDataResultSet
Zend_Service_Yahoo_InlinkDataResultSet représente un jeu de résultat Yahoo!
Inbound Link Search.

Zend_Service_Yahoo_InlinkDataResultSet étend
Zend_Service_Yahoo_ResultSet

Retour à la liste des classes

32.9.8. Zend_Service_Yahoo_PageDataResultSet
Zend_Service_Yahoo_PageDataResultSet représente un jeu de résultat Yahoo!
PageData Search.

Zend_Service_Yahoo_PageDataResultSet étend
Zend_Service_Yahoo_ResultSet

Retour à la liste des classes

32.9.9. Zend_Service_Yahoo_Result
Chaque résultat spécifique à la recherche est étendu de cette classe de base.

32.9.9.1. Propriétés

Tableau 140. Propriétés de Zend_Service_Yahoo_Result

Nom Type Description


Title string Titre du résultat
Url string URL du résultat
ClickUrl string URL pour pointer sur ce
résultat

Retour à la liste des classes

32.9.10. Zend_Service_Yahoo_WebResult
Chaque résultat d'une recherche Web est retourné comme un objet
Zend_Service_Yahoo_WebResult.

32.9.10.1. Propriétés

Tableau 141. Propriétés de Zend_Service_Yahoo_WebResult

Nom Type Description


Summary string Sommaire du résultat
MimeType string type Mime du résultat

1347
Zend_Service

Nom Type Description


ModificationDate string Timestamp UNIX de la date
de la dernière modification du
résultat.
CacheUrl string URL Yahoo! du cache Web du
résultat, s'il existe.
CacheSize int Taille du cache.

Retour à la liste des classes

32.9.11. Zend_Service_Yahoo_ImageResult
Chaque recherche d'image est retournée comme un objet
Zend_Service_Yahoo_ImageResult.

32.9.11.1. Propriétés

Tableau 142. Propriétés de Zend_Service_Yahoo_ImageResult

Nom Type Description


Summary string Sommaire du résultat
RefererUrl string L'URL de la page qui contient
l'image
FileSize int La taille (en octets) de l'image
FileFormat string Le format de l'image (bmp, gif,
jpeg, png, etc.)
Height int La hauteur de l'image
Width int LA largeur de l'image
Thumbnail Zend_Service_Yahoo_Image Vignette de l'image

Retour à la liste des classes

32.9.12. Zend_Service_Yahoo_VideoResult
Chaque recherche de vidéo est retournée comme un objet
Zend_Service_Yahoo_VideoResult.

32.9.12.1. Propriétés

Tableau 143. Propriétés de Zend_Service_Yahoo_VideoResult

Nom Type Description


Summary string Sommaire du résultat
RefererUrl string L'URL de la page qui contient
la vidéo
FileSize int La taille (en octets) de la vidéo
FileFormat string Le format de la vidéo
(avi, flash, mpeg, msmedia,
quicktime, realmedia, etc.)

1348
Zend_Service

Nom Type Description


Height int La hauteur de la vidéo en
pixels
Width int La largeur de la vidéo en pixels
Duration int La durée de la vidéo en
secondes
Channels int Nombre de canaux audio de la
vidéo
Streaming boolean La vidéo est-elle en streaming
ou pas ?
Thumbnail Zend_Service_Yahoo_Image Vignette de la vidéo

Retour à la liste des classes

32.9.13. Zend_Service_Yahoo_LocalResult
Chaque résultat de recherche locale est retourné dans un objet
Zend_Service_Yahoo_LocalResult.

32.9.13.1. Propriétés

Tableau 144. Propriétés de Zend_Service_Yahoo_LocalResult

Nom Type Description


Address string Adresse de la rue du résultat
City string Ville dans laquelle réside le
résultat
State string État dans lequel réside le
résultat
Phone string Numéro de téléphone du
résultat
Rating int Appréciation des utilisateurs
pour ce résultat
Distance float Distance entre l'endroit où
vous vous trouvez et le résultat
MapUrl string L'URL d'une carte pour le
résultat
BusinessUrl string L'URL du site de l'entreprise,
s'il est connu
BusinessClickUrl string L'URL pour faire un lien sur
le site de l'entreprise, s'il est
connu

Retour à la liste des classes

32.9.14. Zend_Service_Yahoo_NewsResult
Chaque résultat de News Search est retourné comme un objet
Zend_Service_Yahoo_NewsResult.

1349
Zend_Service

32.9.14.1. Propriétés

Tableau 145. Propriétés de Zend_Service_Yahoo_NewsResult

Nom Type Description


Summary string Sommaire du résultat
NewsSource string L'entreprise qui a distribué
l'article
NewsSourceUrl string L'URL de l'entreprise qui a
distribué l'article
Language string La langue de l'article
PublishDate string La date de publication de
l'article, au format timestamp
UNIX
ModificationDate string La date de la dernière
modification de l'article, au
format timestamp UNIX
Thumbnail Zend_Service_Yahoo_Image Miniature de l'image pour cet
article, si elle existe

Retour à la liste des classes

32.9.15. Zend_Service_Yahoo_InlinkDataResult
Chaque résultat de Inbound Link Search est retourné comme un objet
Zend_Service_Yahoo_InlinkDatabResult.

Retour à la liste des classes

32.9.16. Zend_Service_Yahoo_PageDataResult
Chaque résultat de Page Data Search est retourné comme un objet
Zend_Service_Yahoo_PageDataResult.

Retour à la liste des classes

32.9.17. Zend_Service_Yahoo_Image
Toutes les images retournées, par Yahoo! Image Search ou Yahoo! News Search sont
représentées par un objet Zend_Service_Yahoo_Image.

32.9.17.1. Propriétés

Tableau 146. Propriétés de Zend_Service_Yahoo_Image

Nom Type Description


Url string URL de l'image
Width int Largeur de l'image
Height int Hauteur de l'image

Retour à la liste des classes

1350
Zend_Session
1. Introduction
L'équipe Auth de Zend Framework apprécie considérablement votre feedback et vos
contributions sur notre liste émail : fw-auth@lists.zend.com.

Dans les applications Web écrites en PHP, une session représente un raccordement logique
entre le côté serveur, des données persistantes et un client particulier (par exemple, un
navigateur Web). Zend_Session aide à contrôler et à préserver les données de session,
un complément logique des données de type cookie, en cas de demande de page multiples
par le même client. À la différence des données de cookie, les données de session ne sont
pas stockées du côté client, et elles sont seulement partagées avec le client quand le code
source du côté serveur rend volontairement disponible les données par l'intermédiaire d'une
réponse à une demande du client. Dans le cadre de ce composant et de cette documentation,
le terme "données de session" se rapportent aux données du côté serveur stockées dans
$_SESSION, contrôlées par Zend_Session, et individuellement manipulées par des objets
Zend_Session_Namespace. Les espaces de noms de session permettent d'accéder aux
données de session en utilisant les espaces de noms classiques implémentés logiquement en
tant que groupes nommés de tableaux associatifs, indexés par des chaînes (semblables aux
tableaux habituels de PHP).

Les instances Zend_Session_Namespace sont des objets accesseurs pour les sous-parties
nommées de $_SESSION. Le composant Zend_Session encapsule l'extension session
de PHP existante avec une interface d'administration et de gestion, afin de fournir une
API à Zend_Session_Namespace pour les espaces de noms de session persistants.
Zend_Session_Namespace fournit une interface normalisée et orientée objet pour travailler
en espaces de noms persistants à l'intérieur du mécanisme standard des sessions de
PHP. Le support existe pour les espaces de noms anonymes et les espaces de nom de
session authentifiés (par exemple, "login"). Zend_Auth, le composant d'authentification de
Zend Framework emploie Zend_Session_Namespace pour stocker les informations liées aux
utilisateurs authentifiés. Puisque Zend_Session emploie les fonctions normales de l'extension
session de PHP, tous les options et réglages familiers de configuration s'appliquent (voir http://
www.php.net/session), avec en bonus la facilité d'accès par une interface orientée objet et un
comportement par défaut fournissant les meilleures pratiques et une intégration sans problèmes
dans Zend Framework. Ainsi, un id standard de session PHP, stocké soit dans un cookie côté
client ou incorporé dans l'URL, maintient l'association entre un client et des données de session.

La fonction de gestion de session par défaut session_set_save_handler ne maintient pas cette


association dans un faisceau (NDT. : "cluster") de serveurs sous certaines conditions car les
données de session sont sauvegardées seulement sur le serveur qui répond à la requête. Si
une requête peut être réalisée par un serveur différent de celui où les données de session sont
sauvegardées, alors le serveur appelé n'aura pas accès aux données de session (si elles ne sont
pas disponibles dans un système de fichiers en réseau). Une liste additionnelle de gestionnaire
de session sera fournie, dès que possible. Les membres de la communauté sont encouragés à
suggérer et soumettre des gestionnaires de sauvegardes à la liste fw-auth@lists.zend.com. Un
gestionnaire de sauvegarde compatible Zend_Db a été signalé à la liste.

2. Usage basique
Les instances Zend_Session_Namespace fournissent l'API primaire pour manipuler les
données de session dans Zend Framework. Les espaces de noms sont utilisés pour isoler toutes

1351
Zend_Session

les données de session, bien qu'un espace de noms par défaut existe pour ceux qui veulent juste
un endroit pour stocker toutes leurs données de session. Zend_Session utilise ext/session
et sa superglobale spéciale $_SESSION comme mécanisme de stockage pour les données
d'état de session. Bien que $_SESSION est toujours disponible dans l'espace global de PHP,
les développeurs devraient s'abstenir d'accéder directement à elle, alors que Zend_Session
et Zend_Session_Namespace fournissent plus efficacement et plus solidement leur suite de
fonctionnalités liées à session.

Chaque instance de Zend_Session_Namespace correspond à une entrée dans le tableau de


la superglobale $_SESSION, où l'espace de noms est utilisée comme une clé.

$monNamespace = new Zend_Session_Namespace('monNamespace');

// $monNamespace corresponds to $_SESSION['monNamespace']

Il est possible d'utiliser Zend_Session conjointement avec d'autre code utilisant directement
$_SESSION. Cependant, pour éviter les problèmes, il est fortement recommandé que ce
code utilise seulement les parties de $_SESSION ne correspondant pas aux instances de
Zend_Session_Namespace.

2.1. Tutoriel d'exemples


Si aucun espace de noms n'est spécifié lors de l'instanciation de Zend_Session_Namespace,
toutes les données sont stockées de manière transparente dans un espace de noms appelé
"Default". Zend_Session n'est pas prévu pour fonctionner directement sur le contenu des
conteneurs des espaces de noms. Au lieu de cela, nous utilisons Zend_Session_Namespace.
L'exemple ci-dessous montre l'utilisation de cet espace de noms par défaut, en montrant
comment compter le nombre de fois qu'un utilisateur a vu une page sur le site Web. Pour tester
cet exemple, ajouter le code suivant à votre fichier d'amorçage ZF :

Exemple 850. Compter le nombre de pages vues

$defaultNamespace = new Zend_Session_Namespace('Default');

if (isset($defaultNamespace->numberOfPageRequests)) {
$defaultNamespace->numberOfPageRequests++;
// ceci s'incrémente à chaque chargement de page.
} else {
$defaultNamespace->numberOfPageRequests = 1;
// première page
}

echo "Page demandée lors de cette session : ",


$defaultNamespace->numberOfPageRequests;

Quand de multiples modules utilisent des instances de Zend_Session_Namespace ayant


différents espaces de noms, chaque module obtient une encapsulation pour ses propres
données de session. Le constructeur de Zend_Session_Namespace peut recevoir un
paramètre facultatif $namespace, qui permet aux développeurs la partition des données
de session dans des espaces de noms séparés. Les espaces de noms fournissent une
manière efficace et populaire de protéger un sous-ensemble de données de session contre un
changement accidentel dû à des collisions de noms.

Les noms des espaces de noms sont limités à des chaînes de caractères PHP non-vides qui
ne commencent par un tiret-bas ("_"). De plus, seuls les composants coeur de Zend Framework
devraient employer un nom d'espace de noms commençant par "Zend".

1352
Zend_Session

Exemple 851. Nouvelle méthode : les espaces de noms évitent les collisions

// Dans le composant Zend_Auth


$authNamespace = new Zend_Session_Namespace('Zend_Auth');
$authNamespace->user = "monusername";

// Dans un composant service web


$webServiceNamespace = new Zend_Session_Namespace('Un_Service_Web');
$webServiceNamespace->user = "monwebusername";

L'exemple ci-dessus réalise la même chose que celui ci-dessous, excepté que les objets de
session ci-dessus préserve l'encapsulation des données de session dans leur espace de noms
respectif.

Exemple 852. Ancienne méthode : accès aux sessions PHP

$_SESSION['Zend_Auth']['user'] = "monusername";
$_SESSION['Un_Service_Web']['user'] = "monwebusername";

2.2. Énumérer les espaces de noms de session


Zend_Session_Namespace fournit une interface IteratorAggregate complète, incluant le
support de l'instruction foreach :

Exemple 853. Énumération des sessions

$unNamespace =
new Zend_Session_Namespace('un_namespace_avec_des_donnes_presentes');

foreach ($unNamespace as $index => $valeur) {


echo "unNamespace->$index = '$valeur';\n";
}

2.3. Accesseurs pour les espaces de noms de session


Zend_Session_Namespace implémente __get(), __set(), __isset(), et __unset().
Les méthodes magiques ne devraient pas être utilisées directement, excepté à l'intérieur d'une
sous-classe. Au lieu de cela, utilisez les opérateurs normaux pour appeler ces méthodes
magiques, comme :

Exemple 854. Accéder aux données de session

$namespace = new Zend_Session_Namespace();


// Espace de noms par défaut

$namespace->foo = 100;

echo "\$namespace->foo = $namespace->foo\n";

if (!isset($namespace->bar)) {
echo "\$namespace->bar n'existe pas\n";
}

unset($namespace->foo);

1353
Zend_Session

3. Utilisation avancée
Même si les exemples de l'utilisation basique sont une manière parfaitement acceptable d'utiliser
les sessions dans Zend Framework, il existe de bonnes pratiques à considérer. Cette section
détaille plus finement le traitement des sessions et présente des utilisations plus avancées du
composant Zend_Session.

3.1. Démarrer une session


Si vous voulez que toutes les requêtes aient une session facilitée avec Zend_Session, alors
démarrez la session dans votre fichier d'amorçage :

Exemple 855. Démarrer la session globale

Zend_Session::start();

En démarrant la session dans votre fichier d'amorçage, vous empêcher la possibilité de


démarrer votre session après l'envoi d'en-têtes à votre navigateur, ce qui entraîne la levée
d'une exception, et peut être une page cassée pour les visiteurs de votre site. Divers
usages avancés nécessitent premièrement Zend_Session::start(). (D'autant plus sur les
utilisations avancées suivantes.)

Il existe quatre manières différentes pour démarrer une session, quand on utilise
Zend_Session. Deux sont mauvaises.

1. Mauvaise : n'activez pas session.auto_start de PHP. Si vous n'avez pas la possibilité


de désactiver ce réglage dans le php.ini, ou que vous utilisez mod_php (ou équivalent), et
que le réglage est déjà activé dans le php.ini, alors ajoutez le code suivant à votre fichier
.htaccess (habituellement votre dossier de démarrage HTML) :

php_value session.auto_start 0

2. Mauvaise : n'utilisez pas la fonction session_start() directement. Si vous


utilisez directement session_start(), et que vous démarrez en utilisant
Zend_Session_Namespace, une exception sera levée par Zend_Session::start()
("session has already been started"). Si vous appelez session_start(), après avoir utilisé
Zend_Session_Namespace ou démarré explicitement Zend_Session::start(), une
erreur de niveau E_NOTICE sera générée, et l'appel sera ignoré.

3. Correcte : utilisez Zend_Session::start(). Si vous voulez que toutes vos requêtes aient
et utilisent les sessions, alors placez cette fonction le plus tôt possible et sans condition dans
votre fichier d'amorçage. Les sessions ont un coût. Si certaines requêtes nécessitent les
sessions, mais que les autres n'en ont pas besoin, alors :

• Sans conditions, réglez l'option strict à TRUE en utilisant


Zend_Session::setOptions() dans votre fichier d'amorçage.

• Appelez Zend_Session::start(), uniquement pour les requêtes qui


nécessitent l'usage des sessions, avant la première instanciation d'un objet
Zend_Session_Namespace().

• Utilisez "new Zend_Session_Namespace()" normalement, quand nécessaire, mais


faites attention que Zend_Session::start() soit appelée auparavant.

1354
Zend_Session

L'option strict empêche new Zend_Session_Namespace() d'automatiquement


démarrer une session en utilisant Zend_Session::start(). Ainsi, cette option aide
les développeurs d'application Zend Framework universelles à imposer une décision de
conception afin d'empêcher l'utilisation de sessions pour certaines requêtes, puisqu'une erreur
sera levée en utilisant cette option et en instanciant Zend_Session_Namespace, avant un
appel explicite de Zend_Session::start(). N'employez pas cette option dans le code
de la librairie coeur du ZF, car seuls les développeurs universels peuvent faire ce choix
de design. Les développeurs doivent considérer avec précaution l'impact de l'utilisation de
Zend_Session::setOptions(), puisque ces options ont un effet global, suite à leur
correspondance avec les options sous-jacentes pour ext/session.

4. Correcte : instanciez simplement Zend_Session_Namespace() quand nécessaire, la


session PHP sous-jacente sera automatiquement démarrée. Ceci permet un usage
extrêmement simple qui fonctionne dans la plupart des cas. Cependant, vous êtes
responsable de vous assurer que le premier new Zend_Session_Namespace() intervient
avant que toute sortie (par exemple en-têtes HTTP) ait été envoyée par PHP au client, si vous
utilisez le réglage par défaut, sessions basées sur les cookies (fortement recommandé). Voir
Section 4.2, « L'erreur: "Headers Already Sent" » pour plus d'informations.

3.2. Verrouiller les espaces de noms de session


Les espaces de noms de session peuvent être verrouillés, pour éviter tout risque d'altération des
données dans cet espace. Utilisez lock() pour attribuer à un espace de nommage spécifique
le mode lecture seule,unLock() pour attribuer le mode lecture / écriture, et isLocked()
pour tester si un espace de nommage a été auparavant verrouillé. Les verrouillages sont
transitoires et ne persistent pas d'une requête à l'autre. Verrouiller un espace de nommage
n'a pas d'effet sur les méthodes de réglages des objets stockés dans cet espace, mais
empêche l'utilisation des méthodes de réglage de l'espace de noms destiné à détruire ou à
remplacer les objets stockés dans l'espace. De la même manière, verrouiller les instances
Zend_Session_Namespace n'empêche pas l'accès direct à l'alias dans tableau de stockage
$_SESSION (voir PHP references).

Exemple 856. Verrouillage des espaces de noms de session

$userProfileNamespace =
new Zend_Session_Namespace('userProfileNamespace');

// vérrouillons une session en lecture seule


$userProfileNamespace->lock();

// dévérrouillage si déjà vérrouillé


if ($userProfileNamespace->isLocked()) {
$userProfileNamespace->unLock();
}

3.3. Expiration d'un espace de noms


Des limites peuvent être affectées à la durée de vie soit des espaces de noms soit de
clés individuelles dans cet espace. Les cas d'utilisation habituels incluent le passage d'une
information temporaire entre requêtes, et la diminution de l'exposition à un potentiel risque de
sécurité par la suppression de l'accès à des informations sensibles potentielles à une certaine
heure après que l'authentification ait eu lieu. L'expiration peut être basée sur les secondes
écoulées, ou basées sur le concept de "hops", où un "hop" apparaît à chaque requête successive.

1355
Zend_Session

Exemple 857. Exemple d'expiration

$s = new Zend_Session_Namespace('expireAll');
$s->a = 'apple';
$s->p = 'pear';
$s->o = 'orange';

$s->setExpirationSeconds(5, 'a');
// expire seulement pour la clé "a" dans 5 secondes

// expiration de tout l'espace de nommage dans 5 "hops"


$s->setExpirationHops(5);

$s->setExpirationSeconds(60);
// L'espace de noms "expireAll" sera marqué "expired"
// soit à la première requête reçue après 60 secondes,
// soit dans 5 hops, en fonction de ce qui arrivera en premier.

Quand vous travaillez avec des données de session expirées dans la requête courante,
des précautions doivent être prises concernant leur utilisation. Bien que les données soient
retournées par référence, modifier les données expirées ne les rendra pas persistantes dans
la requête courante. Dans le but de remettre à zéro leur temps d'expiration, transférez les
données dans des variables temporaires, utilisez l'espace de nommage pour les effacer, et
ensuite réaffectez les clés appropriées de nouveau.

3.4. Encapsulation de session et Contrôleurs


Les espaces de noms peuvent aussi être utilisés pour séparer l'accès aux sessions par contrôleur
afin de protéger les variables d'une quelconque contamination. Par exemple, un contrôleur
d'authentification pourrait garder ces données de session séparées de tous les autres contrôleurs
pour des raisons de sécurité.

Exemple 858. Sessions nommées par contrôleur avec expiration automatique

Le code suivant, partie d'un contrôleur destiné à afficher une question dans un test, initie
une variable booléenne pour représenter l'acceptation ou non d'une réponse à la question
soumise. Dans ce cas, l'utilisateur de l'application a 300 secondes pour répondre à la
question affichée.

$testSpace = new Zend_Session_Namespace('testSpace');


$testSpace->setExpirationSeconds(300, 'accept_answer');
// expire seulement cette variable
$testSpace->accept_answer = true;

Ci-dessous, le contrôleur qui analyse les réponses aux questions du test détermine
l'acceptation ou non d'une réponse en se basant sur le fait que l'utilisateur a répondu dans
le temps alloué :

// contrôleur analysant la réponse


$testSpace = new Zend_Session_Namespace('testSpace');
if ($testSpace->accept_answer === true) {
// dans le temps autorisé
}
else {
// pas dans le temps autorisé
}

1356
Zend_Session

3.5. Limiter les instances multiples par espace de noms


Bien que le verrouillage de session fournisse un bon degré de protection contre l'utilisation
inattendue des données dans un espace de noms, Zend_Session_Namespace offre aussi la
possibilité d'empêcher la création d'instances multiples correspondant à un unique espace de
noms.

Pour activer ce comportement, réglez à TRUE le second argument du constructeur quand vous
créez la dernière instance autorisée de Zend_Session_Namespace. Tout tentative suivante
d'instanciation du même espace de noms entraînera la levée d'une exception.

Exemple 859. Limiter l'accès à un espace de noms à une instance unique

// créer une instance d'espace


$authSpaceAccessor1 = new Zend_Session_Namespace('Zend_Auth');

// créer une autre instance du même espace,


// mais désactiver toute nouvelle instance
$authSpaceAccessor2 = new Zend_Session_Namespace('Zend_Auth', true);

// créer une référence est toujours possible


$authSpaceAccessor3 = $authSpaceAccessor2;

$authSpaceAccessor1->foo = 'bar';

assert($authSpaceAccessor2->foo, 'bar');

try {
$aNamespaceObject = new Zend_Session_Namespace('Zend_Auth');
} catch (Zend_Session_Exception $e) {
echo "Cannot instantiate this namespace "
. "since $authSpaceAccessor2 was created\n";
}

Le second paramètre dans le constructeur ci-dessus informe Zend_Session_Namespace


que toute future instance avec l'espace de noms "Zend_Auth" sera refusée. Tenter
de créer une instance entraînera la levée d'une exception par le constructeur. Le
développeur devient responsable de stocker quelque part une référence à l'instance de
l'objet ($authSpaceAccessor1, $authSpaceAccessor2, ou $authSpaceAccessor3 dans
l'exemple ci-dessus), si l'accès à l'espace de noms de session est nécessaire plus tard dans
la même requête. Par exemple, le développeur peut stocker la référence dans une variable
statique , ajouter la référence au registre (voir Zend_Registry), ou sinon la rendre disponible pour
les autres méthodes qui peuvent avoir accès à cet espace de noms.

3.6. Travailler avec les tableaux


A cause de l'histoire de l'implémentation des méthodes magiques dans PHP, la modification
d'un tableau à l'intérieur d'un espace de noms peut ne pas fonctionner avec les versions de
PHP inférieures à 5.2.1. Si vous travaillez exclusivement avec des versions de PHP 5.2.1 ou
supérieur., alors vous pouvez passer la section suivante.

1357
Zend_Session

Exemple 860. Modifier un tableau de données avec un espace de noms de session

Le code suivant illustre le problème qui peut être reproduit :

$sessionNamespace = new Zend_Session_Namespace();


$sessionNamespace->array = array();
$sessionNamespace->array['testKey'] = 1;
// ne fonctionne pas comme attendu avant PHP 5.2.1
echo $sessionNamespace->array['testKey'];

Exemple 861. Construire les tableaux avant le stockage en session

Si possible, évitez le problème en stockant les tableaux dans un espace de noms de session
seulement après que toutes les clés et les valeurs aient été définies :

$sessionNamespace = new Zend_Session_Namespace('Foo');


$sessionNamespace->array = array('a', 'b', 'c');

Si vous utilisez une version de PHP affectée et avez besoin de modifier un tableau après l'avoir
assigné à une clé dans l'espace de noms, vous pouvez utiliser l'une des solutions suivantes :

Exemple 862. Solution : réassigner un tableau modifié

Dans le code suivant, une copie du tableau stocké est créée, modifiée, et réassignée à la
place d'où provenait la copie, en effaçant le tableau original.

$sessionNamespace = new Zend_Session_Namespace();

// assigne le tableau initial


$sessionNamespace->array = array('fruit' => 'pomme');

// copie du tableau
$tmp = $sessionNamespace->array;

// modification de la copie
$tmp['fruit'] = 'poire';

// ré-assignation de la copie dans l'espace de noms


$sessionNamespace->array = $tmp;

echo $sessionNamespace->array['fruit']; // affiche "poire"

Exemple 863. Solution : stocker un tableau contenant une référence

Autrement, stockez un tableau contenant une référence au tableau désiré, et y accéder


indirectement.

$myNamespace = new Zend_Session_Namespace('myNamespace');


$a = array(1, 2, 3);
$myNamespace->someArray = array( &$a );
$a['foo'] = 'bar';
echo $myNamespace->someArray['foo']; // affiche "bar"

3.7. Utiliser les sessions avec des objets


Si vous prévoyez de rendre persistant des objets dans les sessions PHP, pensez qu'ils peuvent
être sérialisé pour le stockage. Ainsi, tout objet persistant dans les sessions PHP doit être

1358
Zend_Session

désérialisé après sa récupération à partir du stockage. L'implication est que le développeur doit
s'assurer que les classes des objets persistants doivent avoir été définies avant que l'objet ne soit
désérialisé du stockage. Si aucune classe n'est définie pour l'objet désérialisé, alors il devient
une instance de stdClass.

3.8. Utiliser les sessions avec les tests unitaires


Zend Framework s'appuie sur PHPUnit pour faciliter ses propres tests. Beaucoup de
développeurs étendent la suite des tests unitaires pour couvrir le code de leurs
applications. L'exception "Zend_Session is currently marked as read-only" (NDT. :
"Zend_Session est actuellement marquée en lecture seule") est levée lors de l'exécution
des tests unitaires, si une méthode d'écriture est utilisée après la clôture de la
session. Cependant les tests unitaires employant Zend_Session requièrent une attention
particulière, car la fermeture (Zend_Session::writeClose()), ou la destruction d'une
session (Zend_Session::destroy()) empêche tout futur changement ou suppression
de clés dans un Zend_Session_Namespace. Ce comportement est un résultat direct du
mécanisme fondamental de l'extension session et des fonctions PHP session_destroy() et
session_write_close(), qui n'a pas de mécanisme de marche arrière ("undo") pour faciliter
le réglage/démontage avec les tests unitaires.

Pour contourner ceci, regardez le test unitaire testSetExpirationSeconds() dans tests/


Zend/Session/SessionTest.php et SessionTestHelper.php, qui utilise le code PHP
exec() pour charger un processus séparé. Le nouveau processus simule plus précisément
une seconde requête successive du navigateur. Le processus séparé démarre avec une
session "propre", comme n'importe quelle exécution de PHP pour une requête Web. Ainsi, tout
changement fait à $_SESSION dans le processus appelant devient disponible dans le processus
enfant, pourvu que le parent ait fermé la session avant d'utiliser exec().

1359
Zend_Session

Exemple 864. Utilisation de PHPUnit pour tester le code écrit avec Zend_Session*

// tester setExpirationSeconds()
require 'tests/Zend/Session/SessionTestHelper.php';
// voir aussi SessionTest.php dans trunk/
$script = 'SessionTestHelper.php';
$s = new Zend_Session_Namespace('espace');
$s->a = 'abricot';
$s->o = 'orange';
$s->setExpirationSeconds(5);

Zend_Session::regenerateId();
$id = Zend_Session::getId();
session_write_close();
// relâche la session donc le processus suivant peut l'utiliser
sleep(4); // pas assez long pour les éléments expirent
exec($script . "expireAll $id expireAll", $result);
$result = $this->sortResult($result);
$expect = ';a === abricot;o === orange;p === pear';
$this->assertTrue($result === $expect,
"iteration over default Zend_Session namespace failed; "
. "expecting result === '$expect', but got '$result'");

sleep(2);
// assez long pour que les éléments expirent
// (total de 6 secondes écoulées, avec une expiration de 5)
exec($script . "expireAll $id expireAll", $result);
$result = array_pop($result);
$this->assertTrue($result === '',
"iteration over default Zend_Session namespace failed; "
. "expecting result === '', but got '$result')");
session_start(); // redémarre artificiellement une session suspendue

// Ceci peut être découpé dans un test séparé, mais en réalité,


// si quoi que ce soit reste de la partie précédente et contamine
// les tests suivants, alors c'est un bug dont nous voulons avoir
// des informations
$s = new Zend_Session_Namespace('expireGuava');
$s->setExpirationSeconds(5, 'g');
// maintenant essayons d'expirer seulement une clé dans l'espace
$s->g = 'guava';
$s->p = 'peach';
$s->p = 'plum';

session_write_close();
// relâche la session donc le processus suivant peut l'utiliser
sleep(6); // pas assez long pour les éléments expirent
exec($script . "expireAll $id expireGuava", $result);
$result = $this->sortResult($result);
session_start(); // redémarre artificiellement la session suspendue
$this->assertTrue($result === ';p === plum',
"iteration over named Zend_Session namespace failed (result=$result)");

4. Gestion générale de la session


Le comportement des sessions peut être modifié en utilisant les méthodes statiques de la
classe Zend_Session. Il s'agit du comportement global des sessions dans toute l'application,
incluant la configuration des options usuelles offertes par ext/session, ceci en utilisant

1360
Zend_Session

Zend_Session::setOptions(). Ainsi, des problèmes de sécurité peuvent apparaître si vous


utilisez mal le support de stockage des sessions save_path ou encore si vous négligez le
cookie utilisé par ext/session.

4.1. Options de configuration


Lors de la création du premier namespace de session, Zend_Session va automatiquement
démarrer la session PHP, sauf si celle-ci a été démarrée avec Zend_Session::start()
auparavant. La session PHP résultante utilisera les options de configuration par défaut de
Zend_Session, sauf si ceux-ci ont été modifiés à l'aide de Zend_Session::setOptions().

Pour assigner une option de configuration, passez son nom (la partie qui suit "session."
dans les options de configuration de ext/session) comme clé au tableau passé à
Zend_Session::setOptions(). La valeur correspondante dans le tableau sera alors utilisée
comme valeur de l'option. Si vous omettez une option, alors celles par défaut recommandées
par Zend_Session seront utilisées, sinon si elles n'existent pas, les valeurs par défaut de php.ini.
Les retours et les idées quant aux "options recommandées" sont appréciées et peuvent être
envoyées à fw-auth@lists.zend.com.

1361
Zend_Session

Exemple 865. Utiliser Zend_Config pour configurer Zend_Session

Pour configurer le composant en utilisant un objet Zend_Config_Ini, ajoutez ces


paramètres au fichier INI en question:

; Paramètres de production
[production]
; bug_compat_42
; bug_compat_warn
; cache_expire
; cache_limiter
; cookie_domain
; cookie_lifetime
; cookie_path
; cookie_secure
; entropy_file
; entropy_length
; gc_divisor
; gc_maxlifetime
; gc_probability
; hash_bits_per_character
; hash_function
; name doit être unique pour chaque application partageant le même nom de domaine
name = UNIQUE_NAME
; referer_check
; save_handler
; save_path
; serialize_handler
; use_cookies
; use_only_cookies
; use_trans_sid

; remember_me_seconds = <integer seconds>


; strict = on|off

; Development hérite de production, mais redéfinit certaines valeurs


[development : production]
; N'oubliez pas de créer ce dossier et d'attribuer à PHP les droits 'rwx'.
save_path = /home/myaccount/zend_sessions/myapp
use_only_cookies = on
; Le cookie de session durera 10 jours
remember_me_seconds = 864000

Ensuite, chargez ce fichier de configuration, et passez sa représentation tableau à


Zend_Session::setOptions():

$config = new Zend_Config_Ini('myapp.ini', 'development');

require_once 'Zend/Session.php';
Zend_Session::setOptions($config->toArray());

La plupart des options ne nécessitent pas d'explications étant donné qu'elles font parti des
options de ext/session, documentées dans le manuel officiel de PHP, cependant les options
particulières méritent une description:

• bool strict : désactive le démarrage automatique de Zend_Session lorsque new


Zend_Session_Namespace() est utilisé.

1362
Zend_Session

• int remember_me_seconds : temps de vie du cookie de session, une fois le navigateur client
fermé.

• string save_path : Cette valeur est dépendante du système sur lequel PHP est lancé. Un
chemin absolu vers un dossier lisible et écrivable à PHP devrait être utilisé (dans le cas
d'utilisation d'un dossier pour le support des sessions). Si le chemin n'est pas pleinement
accessible à PHP, Zend_Session lancera une exception à son démarrage (lorsque start()
est appelée.

Attention aux failles de sécurité

Si le chemin des sessions est accessible en lecture à d'autres applications,


alors le vol de session peut être possible. Si le dossier est accessible en
écriture à d'autres applications, alors l'empoisonnement de sessions peut
être possible. SI le chemin est partagé avec d'autres utilisateurs ou d'autres
applications PHP, plusieurs problèmes de sécurité peuvent apparaître,
incluant le vol de session, et les collisions de ramasse-miette (garbage
collection) (Un process d'une autre application PHP déclenche une collecte
sur vos fichiers de session).

Par exemple, un pirate peut visiter le site d'une victime pour obtenir un cookie
de session. Il modifie ensuite le chemin du cookie afin que celui-ci soit envoyé
à sa propre application (en partage sur le même serveur que le votre), et
il exécute var_dump($_SESSION). Il obtient alors des informations sur les
variables de session que vous stockez, et il peut les modifier pour retourner
sur votre site. L'empoisonnement a eu lieu. Même si deux applications sur
le même serveur ne partagent pas le même dossier save_path, si celui-ci
est devinable, l'attaquant peut alors l'utiliser sur sa propre application et dans
certaines configurations de PHP, accéder à la session de l'application victime.
La valeur du save_path ne doit pas être rendue publique ou devinable, le
dossier doit se trouver dans un endroit isolé et sécurisé.

• string name - La valeur doit être choisie de manière unique pour chaque application.

Risque de sécurité

Si la valeur php.ini de session.name n'est pas unique (celle par défaut


"PHPSESSID"), et qu'il existe plusieurs applications accessible via le même
domaine, alors elle partagerons leurs données pour les visiteurs. Aussi, des
problème de corruption peuvent apparaître.

• bool use_only_cookies - Afin d'éviter d'autres failles de sécurité (concernant le trans-sid),


ne changez pas cette option.

Risque de sécurité

Si cette option n'est pas activée, un attaquant peut facilement fixer un


id de session d'une victime en lui envoyant des liens tels que http://
www.example.com/index.php?PHPSESSID=fixed_session_id. La
fixation fonctionne si la victime n'a pas déjà un identifiant de session sur le
site example.com. Lorsque la victime utilise un identifiant de session qu'un
attaquant connaît, il peut alors se faire passer pour elle.

1363
Zend_Session

4.2. L'erreur: "Headers Already Sent"


Si vous voyez l'erreur, "Cannot modify header information - headers already sent", ou, "You must
call ... before any output has been sent to the browser; output started in ...", analysez tout de
suite d'où vient la fuite grâce au message d'erreur. Toute action entraînant un envoi d'en-têtes
HTTP, comme envoyer un cookie, doit être effectuée avant d'envoyer du contenu standard (non
bufferisé), sauf si le buffer de sortie de PHP est activé.

• Utiliser le buffer de sortie résout souvent le problème, et peut améliorer les performances. Par
exemple, une valeur php.ini, "output_buffering = 65535" active un buffer de 64K.
Même si le buffer de sortie peut améliorer les performances lorsqu'il est bien configuré, se
reposer sur lui concernant les erreurs "headers already sent" n'est pas suffisant. En effet, sa
taille peut être dépassé entraînant son vidage, et le problème revient.

• Aussi, il convient d'organiser l'application de manière à ce que les envois d'en-tête se passent
avant l'envoi de contenu.

• Si Zend_Session produit ce message, cherchez la cause grâce au message d'erreur indiquant


d'où provient "la fuite". Aussi, des opérations comme destroy() envoient des en-têtes
concernant la destruction du cookie de session. Si vous ne voulez pas ces informations
envoyées, utilisez alors destroy(false).

• Supprimez tous les balises de fermeture "?>", si elles terminent du code PHP. Elles sont
facultatives et les nouvelles lignes blanches éventuelles en fin de fichier ne seront pas
envoyées, car parsées par PHP.

4.3. Identifiants de session


Les bonnes pratiques d'utilisation des sessions avec Zend Framework passent par un cookie,
plutôt que se reporter à l'URL concernant l'identifiant de session. Par défaut, le composant
Zend_Session est bloqué sur l'utilisation unique du cookie comme moyen de propagation de
l'identifiant de session. La session PHP va alors utiliser cet identifiant de manière à identifier
de manière unique chaque client (navigateur) qui s'y connecte, et maintenir un état entre leurs
transactions, donnant l'impression de conservation de données. Zend_Session_* utilise alors
le tableau ($_SESSION) et vous y donne accès d'une manière objet élégante. Attention, si
un attaquant arrive à accéder au cookie de session d'une victime, il pourra alors tromper le
serveur, et se faire passer pour la victime. Ce comportement n'est pas unique à PHP, ni à Zend
Framework, mais au Web en général, et au protocole HTTP. La méthode regenerateId()
permet de changer l'identifiant de session stocké dans le cookie du client, par un autre, en théorie
imprévisible. Notez que par la suite, nous confondons les termes 'client' et 'navigateur', même
si ceci n'est pas tout à fait juste.

Changer l'identifiant de session permet d'aider contre le vol de données. Si un attaquant possède
l'identifiant d'une victime, le changer ne changera rien pour la victime, mais provoquera une
invalidation de la session de l'attaquant, qui ne connaît alors pas la nouvelle valeur de l'identifiant
de session. Non seulement regenerateId() change l'identifiant de session, mais en plus il
migre les données de l'ancien identifiant vers le nouveau, invalidant totalement l'ancien.

Quand régénérer cet identifiant ? En théorie, mettre Zend_Session::regenerateId() en


bootstrap est la manière la plus adaptée pour sécuriser une session. Cependant, ceci a un
coût non négligeable, car il faut alors à chaque fois régénérer un identifiant, et renvoyer un
nouveau cookie au client. Il est alors nécessaire de déterminer les situations 'à risque', et
régénérer alors l'identifiant de session dans de telles situations. Ces situations peuvent être par
exemple l'authentification d'un client, ou encore son élévation de privilèges. Si vous appelez

1364
Zend_Session

rememberMe(), n'appelez alors pas regenerateId(), car elle sera appelée de manière
automatique.

4.3.1. Vol de session et fixation


Éviter les failles cross-site script (XSS) aide à éviter le vol de session. Selon Secunia, les
problèmes XSS sont fréquents, quelque soit le langage utilisé pour créer l'application Web.
Plutôt que de se considérer invulnérable, considérez votre application de manière à minimiser
l'impact d'une éventuelle faille XSS. Avec XSS, l'attaquant n'a pas besoin d'accéder au trafic
de la victime, sur le réseau. Si la victime possède déjà un cookie de session, javascript peut
permettre à l'attaquant de voler celui-ci, et donc la session. Dans le cas de victimes sans cookie,
l'attaquant peut utiliser XSS pour créer un cookie avec un session id connu, et l'envoyer à la
victime, fixant ainsi la session. L'attaquant peut dès lors visualiser toute la session de la victime
au fur et à mesure que celle-ci surfe, sans se rendre compte de rien. Cependant, l'attaquant
ne peut modifier l'état de la session du coté PHP ( la fermer par exemple ), sauf si l'application
possède d'autres vulnérabilités (CSRF), ou si le save_path est modifiable.

En elle-même, la fonction Zend_Session::regenerateId() utilisée à la première utilisation


de la session, ne protège pas contre la fixation. Ceci peut paraître contradictoire, mais un
attaquant peut très bien initialiser une session de lui-même, qui sera alors rafraîchie (régénérée),
et dont il connaîtra alors l'identifiant. Il n'aura plus qu'à fixer cet identifiant dans un javascript pour
qu'une victime l'utilise, et la faille est à nouveau présente. Aussi, fixer la session par l'URL est
extrêmement simple, mais n'est possible que lorsque use_only_cookies = off.

Le vol de session ne peut se remarqué que si vous arrivez à faire la différence entre l'attaquant
et la victime. Ce n'est pas chose simple, et les techniques utilisées ne sont jamais fiables
à 100%. L'IP peut être utilisée, même si celle-ci n'est pas totalement fiable. Les en-têtes du
navigateur Web, eux, le sont déjà plus (lorsque 2 requêtes successives avec le même identifiant
de session arrivent au serveur, si l'une prétend être issue de FireFox et l'autre d'Opéra, alors très
probablement qu'il s'agit de 2 personnes différentes, mais ayant le même identifiant de session.
Typiquement : l'attaquant et sa victime.) Il est très difficile de différencier l'attaquant et la victime,
c'est d'ailleurs impossible dans la suite de cas suivants :

• l'attaquant initialise une session pour obtenir un identifiant valide.

• l'attaquant utilise une faille XSS pour envoyer un cookie de session à une victime, possédant
son propre identifiant de session (fixation).

• l'attaquant et la victime utilisent le même navigateur, sont derrière le même proxy.

Le code suivant permet d'empêcher l'attaquant de connaître l'identifiant de session de la victime


(sauf s'il arrive à le fixer):

Exemple 866. Vol et fixation, protections

$defaultNamespace = new Zend_Session_Namespace();

if (!isset($defaultNamespace->initialized)) {
Zend_Session::regenerateId();
$defaultNamespace->initialized = true;
}

4.4. rememberMe(integer $seconds)


Par défaut, la session se termine lorsque le client ferme son navigateur. Il peut cependant
être nécessaire de faire en sorte que même après la fermeture, le cookie de session persiste

1365
Zend_Session

un certain temps dans le navigateur. Utilisez Zend_Session::rememberMe() avant tout


démarrage de la session, afin de spécifier à celle-ci qu'elle devra utiliser un cookie persistant
du coté du client. Ce cookie persistera alors $seconds secondes. Si vous ne précisez pas de
temps, remember_me_seconds, sera utilisé. Cette valeur se paramètre d'ailleurs au moyen de
Zend_Session::setOptions().

4.5. forgetMe()
Cette fonction est analogue à rememberMe() sauf qu'elle demande au cookie de session du
navigateur client d'être détruit à la fermeture de celui-ci (et non éventuellement après X temps).

4.6. sessionExists()
Utilisez cette méthode afin de savoir si une session existe pour le client (la requête) actuel. Ceci
doit être utilisé avant le démarrage de la session.

4.7. destroy(bool $remove_cookie = true, bool


$readonly = true)
Zend_Session::destroy() détruit la session et toutes les données la concernant.
Cependant, aucune variable dans PHP n'est affectée, donc vos namespaces de session
(instances de Zend_Session_Namespace) restent lisibles. Pour compléter la "déconnexion",
laissez le premier paramètre à TRUE (par défaut), demandant l'expiration du cookie de
session du client. $readonly permet d'empêcher la future création de namespaces (new
Zend_Session_Namespace) ou des opérations d'écriture via Zend_Session.

Si vous voyez le message d'erreur "Cannot modify header information - headers already
sent", alors tentez de ne pas utiliser TRUE comme valeur du premier argument (ceci demande
l'expiration du cookie de session, ou voyez Section 4.2, « L'erreur: "Headers Already Sent" ».
Ainsi, Zend_Session::destroy(true) doit être appelé avant tout envoi d'en-tête HTTP par
PHP, ou alors la bufferisation de sortie doit être activée (sans que celui-ci ne déborde).

Exception
Par défaut, $readonly est activé et toute opération future d'écriture dans la
session lèvera une exception.

4.8. stop()
Cette méthode ne fait rien d'autre que de verrouiller la session en écriture. Tout appel futur
d'écriture via des instances de Zend_Session_Namespace ou Zend_Session lèvera une
exception.

4.9. writeClose($readonly = true)


Ferme la session coté serveur, soit enregistre les variables de session dans le support, et
détache $_SESSION de son support de stockage. Le paramètre optionnel $readonly empêche
alors toute future écriture via Zend_Session ou Zend_Session_Namespace. Ces écritures
lèveront une exception.

Exception
Par défaut, $readonly est activé, et donc tout appel d'écriture futur dans
la session générera une exception. Certaines applications peuvent nécessiter

1366
Zend_Session

de conserver un accès en écriture dans $_SESSION, même si ce tableau a


été déconnecté de son support de stockage avec session_write_close().
Ainsi, Zend Framework propose cette option en passant à FALSE la valeur de
$readonly, mais ce n'est pas une pratique conseillée.

4.10. expireSessionCookie()
Cette méthode envoie un cookie d'identifiant de session périmé au client. Quelque fois cette
technique est utilisée pour déconnecter le client de sa session.

4.11. setSaveHandler(Zend_Session_SaveHandler_Interface
$interface)
Cette méthode propose une correspondance orientée objet de
session_set_save_handler().

4.12. namespaceIsset($namespace)
Cette méthode permet de déterminer si un namespace existe dans la session.

Exception

Une exception sera levée si la session n'est pas lisible (n'a pas été démarrée).

4.13. namespaceUnset($namespace)
Utilisez Zend_Session::namespaceUnset($namespace) pour détruire un namespace
entier de la session. Comme pour les tableaux PHP, si le tableau est détruit, les objets à l'intérieur
ne le sont pas s'il reste des références vers eux dans d'autres tableaux ou objets toujours
accessibles. Ainsi namespaceUnset() ne détruit pas "en profondeur" la variable de session
associée au namespace. Voyez les références en PHP pour plus d'infos.

Exception

Une exception sera envoyée si le namespace n'est pas écrivable (après un appel
à destroy()).

4.14. namespaceGet($namespace)
Déprécié: Utilisez getIterator() dans Zend_Session_Namespace. Cette méthode
retourne un tableau du contenu du namespace $namespace. Si vous avez une raison de
conserver cette méthode, faites nous part de vos remarques à fw-auth@lists.zend.com.

Exception

Une exception sera levée si la session n'est pas lisible (n'a pas été démarrée).

4.15. getIterator()
getIterator() retourne un ArrayObject contenant tous les noms des namespaces de
session.

1367
Zend_Session

Exception

Une exception sera levée si la session n'est pas lisible (n'a pas été démarrée).

5. Zend_Session_SaveHandler_DbTable
Le paramétrage basique pour Zend_Session_SaveHandler_DbTable doit contenir au moins
quatre colonnes, décrites dans une configuration de type array ou objet Zend_Config :
"primary" qui est la clé primaire et reçoit par défaut l'ID de session dont le format est par défaut
une chaîne de 32 caractères ; "modifiedColumn" qui est le timestamp Unix de la date de dernière
modification ; "lifetimeColumn" qui est la durée de vie de la session ("modified" + "lifetime" doit
être supérieur à "time()") ; et "dataColumn" qui est la donnée sérialisée stockée en session.

Exemple 867. Paramétrage basique

CREATE TABLE `session` (


`id` char(32),
`modified` int,
`lifetime` int,
`data` text,
PRIMARY KEY (`id`)
);

// Préparation de l'adaptateur de connexion à la base de données


$db = Zend_Db::factory('Pdo_Mysql', array(
'host' =>'example.com',
'username' => 'dbuser',
'password' => '******',
'dbname' => 'dbname'
));

// Vous pouvez soit passer l'adaptateur par défaut à Zend_Db_Table


// ou l'objet $db dans votre tableau $config
Zend_Db_Table_Abstract::setDefaultAdapter($db);
$config = array(
'name' => 'session',
'primary' => 'id',
'modifiedColumn' => 'modified',
'dataColumn' => 'data',
'lifetimeColumn' => 'lifetime'
);

// Création de votre Zend_Session_SaveHandler_DbTable


// et paramétrage du gestionnaire de sauvegarde à Zend_Session
Zend_Session::setSaveHandler(new Zend_Session_SaveHandler_DbTable($config));

// Démarrage de la session
Zend_Session::start();

// Vous pouvez maintenant utiliser Zend_Session comme avant

Vous pouvez aussi utiliser des colonnes multiples pour votre clé primaire de
Zend_Session_SaveHandler_DbTable.

1368
Zend_Session

Exemple 868. Utilisation d'une clé primaire multi-colonnes

CREATE TABLE `session` (


`session_id` char(32) NOT NULL,
`save_path` varchar(32) NOT NULL,
`name` varchar(32) NOT NULL DEFAULT '',
`modified` int,
`lifetime` int,
`session_data` text,
PRIMARY KEY (`Session_ID`, `save_path`, `name`)
);

// Préparation de l'adaptateur de connexion à la base de données comme ci-dessus


// NOTE : cette configuration est fournie à Zend_Db_Table donc tout élément spécifique à
$config = array(
'name' => 'session',
// Nom de la table comme pour Zend_Db_Table
'primary' => array(
'session_id',
// l'ID de session fourni par PHP
'save_path',
// session.save_path
'name',
// session name
),
'primaryAssignment' => array(
// vous devez avertir le gestionnaire de sauvegarde quelles colonnes
// vous utilisez en tant que clé primaire. L'ORDRE EST IMPORTANT.
'sessionId',
// - la première colonne de la clé primaire est l'ID de session
'sessionSavePath',
// - la seconde colonne de la clé primaire est le "save path"
'sessionName',
// - la troisième colonne de la clé primaire est le "session name"
),
'modifiedColumn' => 'modified',
// date de la dernière modification
'dataColumn' => 'session_data',
// donnée sérialisée
'lifetimeColumn' => 'lifetime',
// durée de vie de l'enregistrement
);

// Informez Zend_Session d'utiliser votre gestionnaire de sauvegarde


Zend_Session::setSaveHandler(
new Zend_Session_SaveHandler_DbTable($config)
);

// Démarrage de la session
Zend_Session::start();

// Utilisez Zend_Session normalement

1369
Zend_Soap
1. Zend_Soap_Server
La classe Zend_Soap_Server a été créée pour simplifier la création d'un service Web SOAP
en PHP.

Elle peut être utilisée en mode WSDL ou non-WSDL, et elle utilise des fonctions ou des classes
pour définir le service Web rendu.

Lorsque le composant Zend_Soap_Server fonctionne en mode WSDL, il utilise le document


WSDL pour décrire le comportement des objets du serveur ainsi que les options de transport
vers les clients.

Un document WSDL peut être auto-généré en utilisant le composant


Zend_Soap_AutoDiscovery, ou alors construit manuellement avec la classe Zend_Soap_Wsdl
ou tout autre outil de génération de XML

Si le mode non-WSDL est utilisé, alors toutes les options du protocole doivent être configurées.

1.1. Constructeur de Zend_Soap_Server


Le constructeur de Zend_Soap_Server s'utilise différemment selon que l'on fonctionne en
mode WSDL ou non.

1.1.1. Constructeur de Zend_Soap_Server en mode WSDL


Le constructeur de Zend_Soap_Server prend 2 paramètres optionnel en mode WSDL:
1
1. $wsdl, l'URI permettant l'accès au fichier WSDL .
2
2. $options - options de création des objets serveurs .

Les options suivantes sont reconnues en mode WSDL :

• "soap_version" ("soapVersion") : version du protocole SOAP à utiliser (SOAP_1_1 ou


SOAP_1_2).

• "actor" : l'URI du serveur SOAP.

• "classmap" ("classMap") : utilisé pour faire correspondre des types WSDL à des classes
PHP.

L'option doit être un tableau avec pour clés les types WSDL et pour valeur les classes PHP
correspondantes.

• "encoding" : encodage interne des caractères (l'encodage externe est toujours UTF-8).

• "wsdl" : équivalent à un appel à setWsdl($wsdlValue)

1.1.2. Constructeur de Zend_Soap_Server en mode non-WSDL


Le premier paramètre du constructeur doit être mis à la valeur NULL si vous voulez utiliser
Zend_Soap_Server en mode non-WSDL.

1370
Zend_Soap

Vous devez aussi spécifier "uri" dans ce cas (voir juste après).

Le second paramètre de constructeur est un tableau ($options) d'options permettant la


3
création de l'objet serveur SOAP. .

Les options suivantes sont reconnues en mode non-WSDL :

• "soap_version" ("soapVersion") : version SOAP à utiliser (SOAP_1_1 ou SOAP_1_2).

• "actor" : l'URI du serveur SOAP.

• "classmap" ("classMap") : utilisé pour faire correspondre des types WSDL à des classes PHP.

L'option doit être un tableau avec pour clés les types WSDL et pour valeur les classes PHP
correspondantes.

• "encoding" : encodage interne des caractères (l'encodage externe est toujours UTF-8).

• "wsdl" : équivalent à un appel à setWsdl($wsdlValue).

1.2. Méthodes de définitions de l'API du service


Il existe 2 manières de déclarer l'API de votre serveur SOAP.

La première consiste à attacher des classes à l'objet Zend_Soap_Server, celles-ci devront


alors décrire l'API du service en totalité :

...
class MyClass {
/**
* Cette méthode accepte ...
*
* @param integer $inputParam
* @return string
*/
public function method1($inputParam) {
...
}

/**
* Cette méthode accepte ...
*
* @param integer $inputParam1
* @param string $inputParam2
* @return float
*/
public function method2($inputParam1, $inputParam2) {
...
}

...
}
...
$server = new Zend_Soap_Server(null, $options);
// Connecte la classe au serveur Soap
$server->setClass('MyClass');
// Connecte un objet déjà initialisé au serveur Soap
$server->setObject(new MyClass());

3
Les options se configurent aussi plus tard, grâce à la méthode setOptions($options)

1371
Zend_Soap

...
$server->handle();

Important!
Vous devriez complètement décrire chaque méthode grâce aux blocs de
commentaires PHPDoc dans le cas où vous souhaitez utiliser l'auto découverte
du service pour préparer le WSDL correspondant.

La seconde manière de décrire l'API de votre service Web est d'utiliser des fonctions PHP
conjointement avec les méthodes addFunction() ou loadFunctions() :

...
/**
* Cette fonction ...
*
* @param integer $inputParam
* @return string
*/
function function1($inputParam) {
...
}

/**
* Cette fonction ...
*
* @param integer $inputParam1
* @param string $inputParam2
* @return float
*/
function function2($inputParam1, $inputParam2) {
...
}
...
$server = new Zend_Soap_Server(null, $options);
$server->addFunction('function1');
$server->addFunction('function2');
...
$server->handle();

1.3. Gestion des objets de requête et de réponse


Avancée
Cette section décrit la gestion avancée des requêtes et réponses SOAP et pourra
être évitée.

Le composant Zend_Soap_Server effectue des requêtes et récupère des réponses, ceci


automatiquement. Il est possible d'intercepter la requête/réponse pour ajouter du pré ou post
processus.

1.3.1. Requête
La méthode Zend_Soap_Server::handle() utilise la requête depuis le flux d'entrée standard
('php://input'). Le comportement peut être changé en passant des paramètres à la méthode
handle() ou en spécifiant sa propre requête grâce à la méthode setRequest() :

1372
Zend_Soap

...
$server = new Zend_Soap_Server(...);
...
// Affecte une requête personnalisée
$server->handle($request);
...
// Affecte une requête personnalisée
$server->setRequest();
$server->handle();

Un objet de requête peut être représenté de plusieurs manières différentes :

• DOMDocument (casté en XML)

• DOMNode (le DOMDocument attaché est extrait et casté en XML)

• SimpleXMLElement (casté en XML)

• stdClass (__toString() est appelée et son contenu est vérifié comme XML valide)

• chaînes de caractères (vérifiée comme XML valide)

La dernière requête utilisée et traitée peut être récupérée en utilisant la méthode


getLastRequest() :

...
$server = new Zend_Soap_Server(...);
...
$server->handle();
$request = $server->getLastRequest();

1.3.2. Réponse
Zend_Soap_Server::handle() émet automatiquement la réponse vers le flux standard de
sortie. Ce comportement peut être changé en utilisant setReturnResponse() avec une valeur
4
TRUE ou FALSE en paramètre. . La réponse générée par handle() est alors retournée et non
plus émise.

...
$server = new Zend_Soap_Server(...);
...
// Récupère la réponse plutôt que de l'émettre
$server->setReturnResponse(true);
...
$response = $server->handle();
...

Autrement, la dernière réponse peut être récupérer avec la méthode getLastResponse() :

...
$server = new Zend_Soap_Server(...);
...
$server->handle();
$response = $server->getLastResponse();
...

4
L'état actuel du drapeau de retour de la réponse peut être vérifié via la méthode setReturnResponse() sans paramètre.

1373
Zend_Soap

2. Zend_Soap_Client
Zend_Soap_Client est une classe destinée à simplifier l'interrogation de services SOAP.

Cette classe peut être utilisée en mode WSDL ou non WSDL.

Lorsque Zend_Soap_Client fonctionne en mode WSDL, il utilise le document WSDL pour définir
les options de la couche de transport des données.

Le fichier WSDL est en général fournit par le service auquel vous souhaitez accéder. Si
la description WSDL n'est pas disponible, vous pouvez vouloir utiliser Zend_Soap_Client
en mode non WSDL . Dans ce cas, toutes les options du protocole devront être définies
explicitement dans la classe Zend_Soap_Client.

2.1. Constructeur de Zend_Soap_Client


Le constructeur de Zend_Soap_Client accepte 2 paramètres:

• $wsdl : l'URI du fichier WSDL.

• $options : options de création.

Ces deux paramètres peuvent être insérés après construction, ceci grâce aux méthodes
setWsdl($wsdl) et setOptions($options).

Important!
Si vous utilisez Zend_Soap_Client en mode non WSDL, vous devez fournir les
options 'location' et 'uri'.

Les options suivantes sont reconnues:

• 'soap_version' ('soapVersion') : version du protocole SOAP à utiliser (SOAP_1_1 ou


SOAP_1_2).

• 'classmap' ('classMap') : doit être utilisé pour faire correspondre des types WSDL à des classes
PHP.

Cette option doit être un tableau avec comme clés les types WSDL et comme valeurs les
noms des classes PHP.

• 'encoding' : encodage interne des caractères (l'encodage externe est toujours UTF-8).

• 'wsdl' : qui est équivalent à un appel à setWsdl($wsdlValue).

Changer cette option peut faire basculer Zend_Soap_Client en mode WSDL ou non WSDL.

• 'uri' : cible du service SOAP (requis pour le mode non WSDL, inusité en mode WSDL).

• 'location' : l'URL à requêter (requis pour le mode non WSDL, inusité en mode WSDL).

• 'style' : style de requête (inusité en mode WSDL): SOAP_RPC ou SOAP_DOCUMENT.

• 'use' : méthode d'encodage des messages (inusité en mode WSDL): SOAP_ENCODED ou


SOAP_LITERAL.

• 'login' et 'password' : login et password pour l'authentification HTTP.

1374
Zend_Soap

• 'proxy_host', 'proxy_port', 'proxy_login', et 'proxy_password' : utilisés pour une connexion


HTTP via un proxy.

• 'local_cert' et 'passphrase' : options d'authentification HTTPS.

• 'compression' : options de compression ; c'est une


combinaison entre SOAP_COMPRESSION_ACCEPT, SOAP_COMPRESSION_GZIP et
SOAP_COMPRESSION_DEFLATE, qui peuvent être utilisées de cette manière :

// Accepte une response compressée


$client = new Zend_Soap_Client("some.wsdl",
array('compression' => SOAP_COMPRESSION_ACCEPT));
...
// Compresse les requêtes avec gzip et un taux de 5
$client = new Zend_Soap_Client("some.wsdl",
array('compression' =>
SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP | 5));
...
// Compresse les requêtes en utilisant deflate
$client = new Zend_Soap_Client("some.wsdl",
array('compression' =>
SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_DEFLATE));

2.2. Effectuer des requêtes SOAP


Lorsqu'un objet Zend_Soap_Client est crée, nous sommes prêts à créer des requêtes SOAP.

Chaque méthode du service Web est liée à une méthode virtuelle de l'objet
Zend_Soap_Client, qui s'utilise de manière tout à fait classique comme PHP le définit.

Voici un exemple :

...
//****************************************************************
// Code du serveur
//****************************************************************
// class MyClass {
// /**
// * Cette méthode utilise ...
// *
// * @param integer $inputParam
// * @return string
// */
// public function method1($inputParam) {
// ...
// }
//
// /**
// * Cette méthode utilise ...
// *
// * @param integer $inputParam1
// * @param string $inputParam2
// * @return float
// */
// public function method2($inputParam1, $inputParam2) {
// ...
// }
//

1375
Zend_Soap

// ...
// }
// ...
// $server = new Zend_Soap_Server(null, $options);
// $server->setClass('MyClass');
// ...
// $server->handle();
//
//****************************************************************
// Fin du code du serveur
//****************************************************************

$client = new Zend_Soap_Client("MyService.wsdl");


...
// $result1 est une chaine
$result1 = $client->method1(10);
...
// $result2 est un flottant
$result2 = $client->method2(22, 'some string');

3. WSDL

La classe Zend_Soap_Wsdl est utilisée par le composant Zend_Soap_Server


pour manipuler des documents WSDL. Néanmoins, vous pouvez vous-même
utiliser les services fournis par cette classe pour vos propres besoins. La
classe Zend_Soap_Wsdl contient à la fois un analyseur et un constructeur de
documents WSDL.

Si vous ne voulez pas l'utiliser pour vos propres besoins, vous pouvez alors
passer cette section de la documentation.

3.1. Constructeur Zend_Soap_Wsdl


Le constructeur de Zend_Soap_Wsdl prend 3 paramètres :

1. $name - nom du service Web décrit.

2. $uri - URI d'accès au fichier WSDL. (Une référence dans le système de fichier local est
possible.)

3. $strategy - identifiant optionnel pour identifier la détection de stratégie des types


complexes. Ceci est un booléen $extractComplexTypes avant la version 1.7 et peut
toujours être paramétrer via un booléen pour la compatibilité ascendante. Par défaut le
comportement de détection de la 1.6 est activé. Pour avoir de plus amples informations
concernant les stratégies de détection des types complexes, lisez : Section 3.10.2, « Ajouter
des infos sur les types complexes ».

3.2. addMessage()
addMessage($name, $parts) ajoute un message de description au document WSDL (/
definitions/message de l'élément).

Chaque message correspond à une méthode en terme de fonctionnalité de


Zend_Soap_Server et Zend_Soap_Client.

1376
Zend_Soap

Le paramètre $name représente le nom du message.

Le paramètre $parts est un tableau de paramètre des messages décrivant les paramètres
d'appel SOAP. Le tableau est associatif: 'nom du paramètre' (nom du paramètre d'appel SOAP)
=> 'type du paramètre'.

La correspondance de types est effectuée grâce à addTypes() et addComplexType()(voyez


après).

Les paramètres de messages peuvent être soit "element", soit "type" (voyez
http://www.w3.org/TR/wsdl#_messages).

"element" doit correspondre à un élément de définition de type. "type" correspond


à une entrée complexType.

Tous les types standards XSD possèdent une définition "element" et


"complexType" (Voyez http://schemas.xmlsoap.org/soap/encoding/).

Tous les éléments non standards, qui doivent être ajoutés avec la méthode
Zend_Soap_Wsdl::addComplexType(), sont décrits en utilisant un noeud
"complexType" décrits dans la section "/definitions/types/schema/" du document
WSDL.

Ainsi, la méthode addMessage() utilise toujours un attribut "type" pour décrire


des types.

3.3. addPortType()
addPortType($name) ajoute un nouveau type de portage au document WSDL (/definitions/
portType).

Ceci fait la jointure entre des méthodes du service décrites en tant qu'implémentations de
Zend_Soap_Server.

Voyez http://www.w3.org/TR/wsdl#_porttypes pour plus de détails.

3.4. addPortOperation()
addPortOperation($portType, $name, $input = false, $output = false,
$fault = false) ajoute des définitions de portage au portage défini dans le document WSDL
(/definitions/portType/operation).

Chaque opération de portage correspond à une méthode de classe (si le Web Service est basé
sur une classe) ou à une fonction (si le Web Service est basé sur des fonctions), ceci en terme
d'implémentation de Zend_Soap_Server.

Cette méthode ajoute aussi les messages d'opération correspondants aux portages, ceci dépend
des paramètres $input, $output and $fault.

Zend_Soap_Server génère 2 messages pour chaque opération de portage


lorsque le service est décrit au travers de la classe Zend_Soap_Server:

• Le message d'entrée nommé $methodName . 'Request'.

1377
Zend_Soap

• Les message de sortie nommé $methodName . 'Response'.

Voyez http://www.w3.org/TR/wsdl#_request-response pour les détails.

3.5. addBinding()
addBinding($name, $portType) ajoute de nouvelles correspondances (bindings) au
document WSDL (/definitions/binding).

Le noeud du document WSDL "binding" définit le format du message et les détails du protocole
pour les opérations et messages définis par un portage "portType" particulier (voyez http://
www.w3.org/TR/wsdl#_bindings).

La méthode crée le noeud de correspondance et le retourne. Il peut alors être utilisé.

L'implémentation de Zend_Soap_Server utilise le nom $serviceName . "Binding" pour la


correspondance ("binding") de l'élément du document WSDL.

3.6. addBindingOperation()
addBindingOperation($binding, $name, $input = false, $output = false,
$fault = false) ajoute une opération à l'élément de correspondance avec le nom spécifié
(/definitions/binding/operation).

Cette méthode prend un objet XML_Tree_Node tel que retourné par addBinding(), en
paramètre ($binding) pour ajouter un élément "operation" avec des entrées input/output/false
dépendantes des paramètres spécifiés.

Zend_Soap_Server ajoute les correspondances pour chaque méthode du Web


Service avec des entrées et sorties, définissant l'élément "soap:body" comme
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/
soap/encoding/"/>

Voyez les détails à http://www.w3.org/TR/wsdl#_bindings.

3.7. addSoapBinding()
addSoapBinding($binding, $style = 'document', $transport = 'http://
schemas.xmlsoap.org/soap/http') ajoute des correspondances (bindings) SOAP
("soap:binding") à l'élément (déjà lié à un portage de type) avec le style et le transport spécifié
(Zend_Soap_Server utilise le style RPC sur HTTP).

L'élément "/definitions/binding/soap:binding" est alors utilisé pour spécifier que la


correspondance est relative au format du protocole SOAP.

Voyez http://www.w3.org/TR/wsdl#_bindings pour les détails.

3.8. addSoapOperation()
addSoapOperation($binding, $soap_action) ajoute une opération SOAP
("soap:operation") à l'élément de correspondance avec l'action spécifiée. L'attribut "style" de
l'élément "soap:operation" n'est pas utilisé alors que le modèle de programmation (RPC-oriented
ou document-oriented) devrait utiliser la méthode addSoapBinding()

1378
Zend_Soap

L'attribut "soapAction" de l'élément "/definitions/binding/soap:operation" spécifie la valeur de l'en-


tête SOAPAction pour l'opération. Cet attribut est requis pour SOAP sur HTTP et ne doit pas
être renseigné pour les autres modes de transports.

Zend_Soap_Server utilise $serviceUri . '#' . $methodName pour le nom de l'action


SOAP.

Voyez http://www.w3.org/TR/wsdl#_soap:operation pour plus de détails.

3.9. addService()
addService($name, $port_name, $binding, $location) ajoute un élément "/
definitions/service" au document WSDL avec le nom du Web Service spécifié, le nom du portage,
la correspondance, et l'adresse.

WSDL 1.1 autorise d'avoir plusieurs types de portage par service. Cette particularité n'est pas
utilisée dans Zend_Soap_Server et est non supportée par la classe Zend_Soap_Wsdl.

Utilisations de Zend_Soap_Server :

• $name . 'Service' comme nom du Web Service,

• $name . 'Port' comme nom de portage des types,


5
• 'tns:' . $name . 'Binding' comme nom de la correspondance,
6
• l'URI du script en tant qu'URI du service pour les Web Service utilisant des classes.

où $name est un nom de classe pour le Web Service utilisant des classes, ou un nom de script
pour le Web Service qui utilise des fonctions.

Voyez http://www.w3.org/TR/wsdl#_services pour les détails.

3.10. Correspondance de type


Le WSDL de Zend_Soap utilise les correspondances suivantes pour faire correspondre les type
SOAP à des types PHP :

• chaînes PHP <-> xsd:string.

• entiers PHP <-> xsd:int.

• flottants PHP <-> xsd:float.

• booléens PHP <-> xsd:boolean.

• tableaux PHP <-> soap-enc:Array.

• objets PHP <-> xsd:struct.

• Classe PHP <-> basé sur la stratégie des types complexes (Voir : Section 3.10.2, « Ajouter
7
des infos sur les types complexes ») .

• Type PHP vide <-> void.

• Si le type na aucune correspondance avec les valeurs ci-dessus, alors xsd:anyType est
utilisé.

1379
Zend_Soap

Où xsd: est l'espace de noms "http://www.w3.org/2001/XMLSchema", soap-enc: est l'espace


de noms "http://schemas.xmlsoap.org/soap/encoding/", tns: est un "espace de noms cible"
pour le service.

3.10.1. Récupérer des infos sur les types


getType($type) peut être utilisée pour récupérer la correspondance d'un type PHP spécifié :

...
$wsdl = new Zend_Soap_Wsdl('My_Web_Service', $myWebServiceUri);

...
$soapIntType = $wsdl->getType('int');

...
class MyClass {
...
}
...
$soapMyClassType = $wsdl->getType('MyClass');

3.10.2. Ajouter des infos sur les types complexes


addComplexType($type) est utilisée pour ajouter des types complexes (classes PHP) à un
document WSDL.

C'est automatiquement utilisé par la méthode getType() pour ajouter les types complexes des
paramètres de méthodes ou des types retournés.

Sa détection et son algorithme de construction est basé sur la détection de stratégie des
types complexes couramment active. Vous pouvez paramétrer la stratégie de détection soit
en spécifiant le nom de classe sous la forme d'une chaîne de caractères ou une instance
implémentant Zend_Soap_Wsdl_Strategy_Interface en tant que troisième paramètre
du constructeur ou en utilisant la fonction setComplexTypeStrategy($strategy) de
Zend_Soap_Wsdl. Les stratégies de détection suivantes existent couramment :

• la classe Zend_Soap_Wsdl_Strategy_DefaultComplexType : activé par défaut (quand


aucun troisième paramètre n'est fourni). Itère parmi les attributs publics d'un type de classe et
les enregistre en tant que sous-types d'un type d'objet complexe.

• la classe Zend_Soap_Wsdl_Strategy_AnyType : caste tous les types complexes en un


type XSD simple xsd:anyType. Attention ce raccourci pour la détection des types complexes
peut probablement seulement être géré avec des langages faiblement typés comme le PHP.

• la classe Zend_Soap_Wsdl_Strategy_ArrayOfTypeSequence : cette stratégie permet


de spécifier les paramètres de retour de type : int[] ou string[]. A partir de Zend
Framework 1.9, il peut gérer des types PHP simples comme int, string, boolean, float ainsi
que des objets ou des tableaux d'objets.

• la classe Zend_Soap_Wsdl_Strategy_ArrayOfTypeComplex : cette stratégie permet


de détecter des tableaux complexes d'objets. Les types d'objets sont détectés sur la base
de Zend_Soap_Wsdl_Strategy_DefaultComplexType et un tableau enveloppe cette
définition.

• la classe Zend_Soap_Wsdl_Strategy_Composite : cette stratégie peut combiner toutes


les stratégies en connectant les types complexes PHP (nom de classe) à la stratégie

1380
Zend_Soap

désirée grâce à la méthode connectTypeToStrategy($type, $strategy). Une carte


de correspondance complète de types peut être fourni au constructeur sous la forme d'un
tableau de paires $type -> $strategy. Le second paramètre spécifie la stratégie par
défaut si un type inconnu est ajouté. La valeur par défaut de ce paramètre est la stratégie
Zend_Soap_Wsdl_Strategy_DefaultComplexType.

la méthode addComplexType() crée un élément "/definitions/types/xsd:schema/


xsd:complexType" pour chaque type complexe décrit avec le nom d'une classe PHP spécifiée.

Les propriétés des classes doivent posséder un bloc de documentation avec le type PHP en
question, afin que la propriété soit incluse dans la description WSDL.

addComplexType() vérifie sur le type est déjà décrit dans la section des types du document
WSDL.

Ceci évite les duplications et récursions si cette méthode est appelée plus d'une fois.

Voyez http://www.w3.org/TR/wsdl#_types pour plus de détails.

3.11. addDocumentation()
addDocumentation($input_node, $documentation) ajoute de la documentation lisible
("human readable") grâce à l'élément optionnel "wsdl:document".

L'élément "/definitions/binding/soap:binding" est utilisé pour dire que la correspondance est liée
au format du protocole SOAP.

Voyez http://www.w3.org/TR/wsdl#_documentation pour les détails.

3.12. Récupérer un document WSDL finalisé


toXML(), toDomDocument() et dump($filename = false) peuvent être utilisées pour
récupérer un document WSDL sous forme de XML, de structure DOM, ou de fichier.

4. Auto découverte
4.1. Introduction à l'auto découverte
Les fonctionnalités SOAP de Zend Framework sont proposées afin de simplifier l'accès aux
services Web de type SOAP.

SOAP est un protocole d'échange de données indépendant d'un langage. Il peut donc être utilisé
avec une autre technologie que PHP.

Il y a trois configurations d'utilisation de SOAP avec Zend Framework :

1. SOAP serveur application PHP <---> SOAP client application PHP

2. SOAP serveur application non PHP <---> SOAP client application PHP

3. SOAP serveur application PHP <---> SOAP client application non PHP

Il est indispensable de connaître les fonctionnalités qu'offre un serveur SOAP, afin de pouvoir
communiquer avec lui. WSDL est alors utilisé pour décrire en détail l'API des services disponibles
sur un serveur SOAP.

1381
Zend_Soap

Le langage WSDL est assez complexe (voyez http://www.w3.org/TR/wsdl pour les détails ). Il
est donc difficile d'écrire une définition WSDL correcte, à la main.

Un autre problème concerne la synchronisation des changements dans l'API avec des fichiers
WSDL déjà existants.

Ces 2 problèmes peuvent être résolus avec la génération automatique de WSDL, qui permet
d'analyser une classe ou des fonctions, d'en extraire les paramètres d'entrée/sortie, et de générer
un fichier WSDL correct et compréhensible par le serveur et les clients SOAP.

Il y a deux façons d'utiliser Zend Framework pour une application serveur SOAP:

• Utiliser des classes.

• Utiliser des fonctions.

Ces deux façons sont supportées par la fonctionnalité d'auto génération de Zend Framework.

Zend_Soap_AutoDiscovery supporte aussi la correspondance des types PHP vers les types
XSD.

Voici un exemple d'utilisation de l'auto découverte. La fonction handle() génère le fichier WSDL
et l'envoie au navigateur :

class My_SoapServer_Class {
...
}

$autodiscover = new Zend_Soap_AutoDiscover();


$autodiscover->setClass('My_SoapServer_Class');
$autodiscover->handle();

Si vous avez besoin d'accéder au fichier WSDL généré soit pour le sauvegarder dans un fichier
ou en tant que chaîne de caractères, vous pouvez utiliser les méthodes dump($filename) ou
toXml() que la classe AutoDiscover fournit.

Zend_Soap_Autodiscover n'est pas un serveur SOAP


Il est très important de noter, que la classe Zend_Soap_Autodiscover n'agit
pas en tant que serveur SOAP elle-même. Elle génère seulement le WSDL et le
fournit à ceux qui accèdent à l'URL qu'elle écoute.

Par défaut l'URI de SOAP est 'http://' .$_SERVER['HTTP_HOST'] .


$_SERVER['SCRIPT_NAME'], mais ceci peut être changé avec
la méthode setUri() ou le paramètre de constructeur de la
classe Zend_Soap_AutoDiscover. L'URI doit correspondre à un
Zend_Soap_Server qui écoute les requêtes.

if(isset($_GET['wsdl'])) {
$autodiscover = new Zend_Soap_AutoDiscover();
$autodiscover->setClass('HelloWorldService');
$autodiscover->handle();
} else {
// pointing to the current file here
$soap = new Zend_Soap_Server("http://example.com/soap.php?wsdl");
$soap->setClass('HelloWorldService');
$soap->handle();

1382
Zend_Soap

4.2. Auto découverte de classe


Si une classe est utilisée dans un serveur SOAP, alors celle-ci devrait aussi être fournie à
Zend_Soap_AutoDiscovery afin d'en générer le fichier WSDL :

$autodiscover = new Zend_Soap_AutoDiscover();


$autodiscover->setClass('My_SoapServer_Class');
$autodiscover->handle();

Les règles suivantes sont utilisées lors de la génération du fichier WSDL :

• Le fichier WSDL généré décrit un service Web de type RPC.

• Le nom du service crée sera le nom de la classe utilisée.

• 'http://' .$_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] est utilisé


comme URI où le fichier WSDL est disponible par défaut mais ceci peut être surchargé avec
la méthode setUri().

Cet URI est aussi utilisé comme un espace de nom cible pour tous les noms du service
(incluant les types complexes décrits éventuellement).

• Les méthodes de la classe sont jointes dans un Port Type.

$className . 'Port' est utilisé comme nom de Port Type.

• Chaque méthode de la classe est enregistrée comme une opération.

• Chaque prototype de méthode génère des messages de requête/réponse correspondants.

Une méthode peut avoir plusieurs prototypes si des paramètres sont optionnels.

Important !
L'auto génération du fichier WSDL (avec auto découverte de la classe) utilise les
blocs de documentation de PHP insérés par le développeur dans ses classes,
afin de trouver les types retournés. De ce fait, pour les types scalaires, c'est le
seul moyen de les déterminer de manière sûre, et concernant les types de retour
des méthodes, c'est le seul moyen de les découvrir (PHP étant faiblement typé).

Ceci signifie que documenter de manière correcte vos classes et méthodes n'est
pas seulement une bonne pratique, c'est tout simplement essentiel pour partager
vos classes en tant que services SOAP auto générés.

4.3. Auto découverte des fonctions


Si des fonctions doivent être utilisées (partagées) via un serveur SOAP, alors elles doivent être
passées à Zend_Soap_AutoDiscovery pour générer un fichier WSDL :

$autodiscover = new Zend_Soap_AutoDiscover();


$autodiscover->addFunction('function1');
$autodiscover->addFunction('function2');
$autodiscover->addFunction('function3');

1383
Zend_Soap

...
$autodiscover->handle();

Les règles suivantes sont utilisées lors de la génération du fichier WSDL :

• Le fichier WSDL généré décrit un service web de type RPC.

• Le nom du service crée sera le nom du script analysé (utilisé).

• 'http://' .$_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] est utilisé


comme URI pour rechercher le fichier WSDL.

Cet URI est aussi utilisé comme un espace de nom cible pour tous les noms du service
(incluant les types complexes décrits éventuellement).

• Les fonctions sont encapsulées dans un Port Type.

$functionName . 'Port' est utilisé comme nom de Port Type.

• Chaque fonction est enregistrée comme opération possible.

• Chaque prototype de fonction génère des messages de requête/réponse correspondants.

Une fonction peut avoir plusieurs prototypes si des paramètres sont optionnels.

Important!
L'auto génération du fichier WSDL (avec auto découverte des fonctions) utilise
les blocs de documentation de PHP insérés par le développeur dans ses
fonctions, afin de trouver les types retournés. De ce fait, pour les types scalaires,
c'est le seul moyen de les déterminer de manière sûre, et concernant les types de
retour des méthodes, c'est le seul moyen de les découvrir (PHP étant faiblement
typé).

Ceci signifie que documenter de manière correcte vos fonctions n'est pas
seulement une bonne pratique, c'est tout simplement essentiel pour partager vos
fonctions en tant que services SOAP auto générés.

4.4. Types de donnée auto découverts


Les types de données d'entrée/sortie sont convertis en types spéciaux pour le réseau, suivant
ces règles :

• Chaînes strings <-> xsd:string.

• Entiers PHP <-> xsd:int.

• Flottants PHP (décimaux) <-> xsd:float.

• Booléens PHP <-> xsd:boolean.

• Tableaux PHP <-> soap-enc:Array.

• Objets PHP <-> xsd:struct.

• Classe PHP <-> basé sur la stratégie des types complexes (Voir : Section 3.10.2, « Ajouter
8
des infos sur les types complexes ») .

1384
Zend_Soap

• type[] or object[] (c'est-à-dire int[]) <-> basé sur la stratégie des types complexes

• Void PHP <-> type vide.

• Si le type n'est pas reconnu en tant que l'un de ceux-ci, alors xsd:anyType est utilisé.

Où xsd: est l'espace "http://www.w3.org/2001/XMLSchema", soap-enc: est l'espace "http://


schemas.xmlsoap.org/soap/encoding/", tns: est "l'espace de nom cible" du service.

4.5. Styles de liaisons WSDL


WSDL offre différents mécanismes et styles de transport. Ceci affecte les balises
soap:binding et soap:body à l'intérieur de la section binding du WSDL. Différents clients
ont différentes conditions quant aux options qui sont vraiment utilisées. Par conséquent vous
pouvez placer les styles avant d'appeler n'importe quelle méthode setClass ou addFunction
de la classe AutoDiscover.

$autodiscover = new Zend_Soap_AutoDiscover();


// Par défaut il s'agit de 'use' => 'encoded'
// et 'encodingStyle' => 'http://schemas.xmlsoap.org/soap/encoding/'
$autodiscover->setOperationBodyStyle(array('use' => 'literal', 'namespace' => 'http://framew

// Par défaut il s'agit de 'style' => 'rpc'


// et 'transport' => 'http://schemas.xmlsoap.org/soap/http'
$autodiscover->setBindingStyle(array('style' => 'document', 'transport' => 'http://framework
...
$autodiscover->addFunction('myfunc1');
$autodiscover->handle();

1385
Zend_Tag
1. Introduction
Zend_Tag est une suite de composants permettant de manipuler des entités taguables. Ce
composant propose 2 classes dans ce but, Zend_Tag_Item et Zend_Tag_ItemList. Aussi,
l'interface Zend_Tag_Taggable vous permet d'utiliser vos modèles dans des tags avec
Zend_Tag.

Zend_Tag_Item est un composant proposant les fonctionnalités basiques pour traiter des tags
dans Zend_Tag. Une entités taguables consiste en un titre et un poids (nombre d'occurrences).
Il existe aussi d'autres paramètres utilisés par Zend_Tag.

Pour grouper plusieurs entités ensemble, Zend_Tag_ItemList propose un itérateur de tableau


et des fonctions pour calculer le poids absolu des valeurs en fonction du poids de chaque entité.

Exemple 869. Utiliser Zend_Tag

Cet exemple montre comment créer une liste de tags en pondérant chacun d'eux.

// Crée la liste
$list = new Zend_Tag_ItemList();

// Ajoute des entités dans la liste


$list[] = new Zend_Tag_Item(array('title' => 'Code', 'weight' => 50));
$list[] = new Zend_Tag_Item(array('title' => 'Zend Framework', 'weight' => 1));
$list[] = new Zend_Tag_Item(array('title' => 'PHP', 'weight' => 5));

// Valeurs absolues des entités


$list->spreadWeightValues(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));

// Sortie
foreach ($list as $item) {
printf("%s: %d\n", $item->getTitle(), $item->getParam('weightValue'));
}

Ceci va afficher les 3 entités Code, Zend Framework et PHP avec les valeurs absolues 10,
1 et 2.

2. Zend_Tag_Cloud
Zend_Tag_Cloud est la partie qui s'occupe du rendu dans Zend_Tag. par défaut, elle utilise
un ensemble de décorateurs HTML , ce qui permet de créer des nuages de tags pour un site,
mais elle met aussi à votre disposition 2 classes abstraites vous permettant de créer vos propres
rendus, par exemple pour créer des tags rendus en PDF.

Vous pouvez instancier et configurer Zend_Tag_Cloud de manière classique, ou via un tableau


ou un objet Zend_Config. Voici les options disponibles:

• cloudDecorator : défini le décorateur du nuage. Ceci peut être un objet, un nom de classe
qui sera chargée par pluginloader, une instance de Zend_Tag_Cloud_Decorator_Cloud
ou un tableau contenant les clés decorator et optionnellement options, qui est elle-même
un tableau passé comme options au constructeur du décorateur.

1386
Zend_Tag

• tagDecorator : le décorateur d'un tag individuel. Ceci peut être un objet, un nom de classe
qui sera chargée par pluginloader, une instance de Zend_Tag_Cloud_Decorator_Cloud
ou un tableau contenant les clés decorator et optionnellement options, qui est elle-même
un tableau passé comme options au constructeur du décorateur.

• pluginLoader : un chargeur de classe à utiliser. Doit implémenter l'interface


Zend_Loader_PluginLoader_Interface.

• prefixPath : préfixes de chemins à ajouter au chargeur de classes. Doit être un tableau


contenant les préfixes et les chemins. Les éléments invalides seront ignorés.

• itemList : une liste d'entités à utiliser. Doit être une instance de Zend_Tag_ItemList.

• tags : une liste de tags à assigner au nuage. Chacun doit implémenter Zend_Tag_Taggable
ou être un tableau qui pourra être utilisé pour instancier Zend_Tag_Item.

Exemple 870. Utiliser Zend_Tag_Cloud

Cet exemple illustre les manipulations de base pour créer un nuage de tags, ajouter des
tags et afficher le rendu.

// Crée un nuage et assigne des tags statiques


$cloud = new Zend_Tag_Cloud(array(
'tags' => array(
array('title' => 'Code', 'weight' => 50,
'params' => array('url' => '/tag/code')),
array('title' => 'Zend Framework', 'weight' => 1,
'params' => array('url' => '/tag/zend-framework')),
array('title' => 'PHP', 'weight' => 5,
'params' => array('url' => '/tag/php')),
)
));

// Rendu du nuage
echo $cloud;

Ceci affichera le nuage de tags, avec les polices par défaut.

2.1. Decorateurs
Zend_Tag_Cloud a besoin de 2 types de décorateurs afin de rendre le nuage. Un
décorateur pour rendre chacun des tags, et un décorateur pour rendre le nuage lui-même.
Zend_Tag_Cloud propose un décorateur par défaut qui formate le nuage en HTML. Il utilise
par défaut des listes ul/li et des tailles de polices différentes selon les poids des tags.

2.1.1. Décorateur HTML


Le décorateur HTML va rendre chaque tag dans un élément ancré, entouré d'un élément li.
L'ancre est fixe et ne peut être changée, mais l'élément peut lui l'être.

Paramètre d'URL
Une ancre étant ajoutée à chaque tag, vous devez spécifier une URL pour chacun
d'eux.

Le décorateur de tags peut utiliser des tailles de police différentes pour chaque ancre, ou pour
chaque classe de liste. Les options suivantes sont disponibles:

1387
Zend_Tag

• fontSizeUnit : définit l'unité utilisée dans la taille des polices. em, ex, px, in, cm, mm, pt,
pc et %.

• minFontSize : Taille minimale de la police (poids le plus faible) (doit être un entier).

• maxFontSize : Taille maximale de la police (poids le plus fort) (doit être un entier).

• classList : un tableau de classes utilisées dans les tags.

• htmlTags : un tableau de tags HTML entourant l'ancre. Chaque élément peut être une chaîne
de caractères, utilisée comme type d'élément, ou un tableau contenant une liste d'attributs
pour l'élément. La clé du tableau est alors utilisée pour définir le type de l'élément.

2.1.2. Décorateur HTML de nuage


Le décorateur HTML de nuage va entourer les tags avec une balise ul. Vous pouvez changer la
balise, en utiliser plusieurs, utiliser un séparateur. Voici les options:

• separator : définit le séparateur utilisé entre chaque tag.

• htmlTags : un tableau de balises HTML entourant chaque tag. Chaque élément peut être
une chaîne de caractères, utilisée comme type d'élément, ou un tableau contenant une liste
d'attributs pour l'élément. La clé du tableau est alors utilisée pour définir le type de l'élément.

1388
Zend_Test
1. Introduction
Zend_Test fournit les outils pour faciliter les tests unitaires de vos applications Zend
Framework. Pour le moment, nous offrons des éléments permettant de tester les applications
MVC réalisées avec Zend Framework.

2. Zend_Test_PHPUnit
Zend_Test_PHPUnit fournit un TestCase pour les applications MVC qui contient des
assertions qui permettent de tester toute une variété de responsabilités. La manière la plus facile
de comprendre ce qui peut être fait est de regarder l'exemple suivant.

1389
Zend_Test

•L'exemple
Quand un utilisateur
suivant se simple
est un connecte,test ilpour
doit être redirigé vers
un choses.
contrôleur sa page de profil,permettant
et cette page
Cet
• Leexemple
formulaire
Exemple particulier
de login
871. suppose
doit être
Exemple d'un différentes
affiché
TestCase Premièrement,
aux utilisateurs la majeure partie de
UserController
non-authentifiés.
d'une application de login de
doit
vérifieraffichée des
différentes infofrmations
choses particulières.
: déplacé dans un plugin. Ceci simplifie le paramétrage dans le
notre fichier d'amorçage a été
cas des tests en spécifiant rapidement votre environnement, et ainsi vous permet d'amorcer
votre application en une seule ligne. Ensuite, notre exemple suppose que le chargement
automatique ("autoload") est activé donc nous n'avons pas à nous soucier de charger les
class
classesUserControllerTest
appropriées (comme leextends Zend_Test_PHPUnit_ControllerTestCase
bon contrôleur, le bon plugin, etc.)
{
public function setUp()
{
$this->bootstrap = array($this, 'appBootstrap');
parent::setUp();
}

public function appBootstrap()


{
$this->frontController->registerPlugin(
new Bugapp_Plugin_Initialize('development')
);
}

public function testCallWithoutActionShouldPullFromIndexAction()


{
$this->dispatch('/user');
$this->assertController('user');
$this->assertAction('index');
}

public function testIndexActionShouldContainLoginForm()


{
$this->dispatch('/user');
$this->assertAction('index');
$this->assertQueryCount('form#loginForm', 1);
}

public function testValidLoginShouldGoToProfilePage()


{
$this->request->setMethod('POST')
->setPost(array(
'username' => 'foobar',
'password' => 'foobar'
));
$this->dispatch('/user/login');
$this->assertRedirectTo('/user/view');

$this->resetRequest()
->resetResponse();
$this->request->setMethod('GET')
->setPost(array());
$this->dispatch('/user/view');
$this->assertRoute('default');
$this->assertModule('default');
$this->assertController('user');
$this->assertAction('view');
$this->assertNotRedirect();
$this->assertQuery('dl');
$this->assertQueryContentContains('h2', 'User: foobar');
}
Cet
} exemple pourrait être écrit plus simplement : toutes les assertions ne sont pas
nécessaires et sont fournies seulement à titre d'illustration. Cependant, il montre bien
combien il est simple de tester vos applications.

1390
Zend_Test

2.1. Amorcer votre TestCase


Comme noté dans l'exemple de login, tous les tests MVC doivent
étendre Zend_Test_PHPUnit_ControllerTestCase. Cette classe étend elle-même
PHPUnit_Framework_TestCase, et vous fournit donc toute la structure et les assertions
que vous attendez de PHPUnit - ainsi que quelques échafaudages et assertions spécifiques à
l'implémentation MVC de Zend Framework.

Si vous voulez tester votre application MVC, vous devez d'abord l'amorcer ("bootstrap"). Il existe
plusieurs manières pour faire ceci, toutes celles-ci s'articulent autour de la propriété publique
$bootstrap.

Premièrement, et probablement le plus simple, créez simplement une instance de


Zend_Application comme vous la souhaitez dans votre fichier index.php, et assignez la
à la propriété $bootstrap. Typiquement, vous réaliserez ceci dans votre méthode setUp() ;
vous devrez ensuite parent::setUp() :

class UserControllerTest extends Zend_Test_PHPUnit_ControllerTestCase


{
public function setUp()
{
// Assign and instantiate in one step:
$this->bootstrap = new Zend_Application(
'testing',
APPLICATION_PATH . '/configs/application.ini'
);
parent::setUp();
}
}

Deuxièmement, vous pouvez paramétrer cette propriété pour qu'elle pointe vers un fichier. Si
vous faîtes ceci, le fichier ne doit pas distribuer le contrôleur frontal, mais seulement paramétrer
celui-ci et faire tout réglage spécifique à votre application.

class UserControllerTest extends Zend_Test_PHPUnit_ControllerTestCase


{
public $bootstrap = '/chemin/vers/amorcage/fichier.php'

// ...
}

Troisièmement, vous pouvez fournir un callback PHP qui doit être exécuter pour amorcer votre
application. Cet exemple est montré dans l'exemple de login. Si le callback est une fonction ou
une méthode statique, ceci peut être paramétrer au niveau de la classe :

class UserControllerTest extends Zend_Test_PHPUnit_ControllerTestCase


{
public $bootstrap = array('App', 'bootstrap');

// ...
}

Dans le cas où une instance d'objet est nécessaire, nous recommandons de réaliser ceci dans
votre méthode setUp() :

class UserControllerTest extends Zend_Test_PHPUnit_ControllerTestCase


{

1391
Zend_Test

public function setUp()


{
// Utilisez la méthode "start" de l'instance d'objet Bootstrap :
$bootstrap = new Bootstrap('test');
$this->bootstrap = array($bootstrap, 'start');
parent::setUp();
}
}

Notez l'appel de parent::setUp(); ceci est nécessaire puisque la méthode setUp() de


Zend_Test_PHPUnit_ControllerTestCase exécutera le reste du processus d'amorçage
(incluant l'appel du callback).

En utilisation normale, la méthode setUp() amorcera l'application. Ce premier processus inclue


le nettoyage de l'environnement pour rendre un état de requête propre, va réinitialiser tout plugins
ou aides, va réinitialiser l'instance du contrôleur frontal, et créer de nouveaux objets de requête
et de réponse. Une fois ceci fait, la méthode va faire un include() du fichier spécifié dans
$bootstrap, ou appeler le callback spécifié.

L'amorçage doit être le proche possible de ce que fera réellement votre application. Cependant,
il y a plusieurs avertissements :

• Ne fournissez pas d'implémentations alternatives des objets


"Request" et "Response" ; ils ne seront pas utilisés.
Zend_Test_PHPUnit_ControllerTestCase utilise des objets de requête et de
réponse personnalisés, respectivement Zend_Controller_Request_HttpTestCase et
Zend_Controller_Response_HttpTestCase. Ces objets fournissent des méthodes pour
paramétrer l'environnement de requête dans le but souhaité, et récupérer les objets de
réponse façonnés.

• N'espérez pas faire des tests spécifiques de serveur. Autrement dit, ces tests ne garantissent
pas que le code va s'exécuter sur un serveur avec une configuration spécifique, mais
simplement que l'application va fonctionner comme souhaité si le routeur est capable de router
une requête donnée. À cet effet, ne paramétrez pas d'en-têtes spécifiques au serveur dans
l'objet de requête.

Une fois que votre application est amorcée, vous pouvez commencer à écrire vos tests.

2.2. Tester vos contrôleurs et vos applications MVC


Une fois , votre fichier d'amorçage en place, vous pouvez commencer à tester. Tester est
typiquement ce que vous auriez pu faire avec une suite de test PHPUnit ("test suite"), avec
quelques petites différences mineures.

Premièrement, vous devez distribuer l'URL à tester en utilisant la méthode dispatch() de


TestCase :

class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase


{
// ...

public function testPageAccueil()


{
$this->dispatch('/');
// ...
}

1392
Zend_Test

Il y a des moments, cependant, où vous devez fournir des informations supplémentaires - des
variables GET et POST, des informations de COOKIE, etc. Vous pouvez peupler la requête avec
ces informations :

class FooControllerTest extends Zend_Test_PHPUnit_ControllerTestCase


{
// ...

public function testBarActionShouldReceiveAllParameters()


{
// Passer les variables GET :
$this->request->setQuery(array(
'foo' => 'bar',
'bar' => 'baz',
));

// Passer les variables POST :


$this->request->setPost(array(
'baz' => 'bat',
'lame' => 'bogus',
));

// Paramètrer une valeur de cookie :


$this->request->setCookie('user', 'matthew');
// ou plusieurs :
$this->request->setCookies(array(
'timestamp' => time(),
'host' => 'foobar',
));

// Ajouter des en-têtes :


$this->request->setHeader('X-Requested-With', 'XmlHttpRequest');

// Définir le type de requête :


$this->request->setMethod('POST');

// Distribuer :
$this->dispatch('/foo/bar');

// ...
}
}

Maintenant que la requête est construite, il est temps de créer des assertions.

2.2.1. Controller Tests and the Redirector Action Helper

The redirect action helper issues an exit() statement when using the method
gotoAndExit() and will then obviously also stops a test running for this
method. For testability of your application dont use that method on the redirector!

Due to its nature the redirector action helper plugin issues a redirect and exists
after this. Because you cannot test parts of an application that issue exit calls
Zend_Test_PHPUnit_ControllerTestCase automatically disables the exit part of the

1393
Zend_Test

redirector which can cause different behaviours in tests and the real application. To make sure
redirect work correctly you should it them in the following way:

class MyController extends Zend_Controller_Action


{
public function indexAction()
{
if($someCondition == true) {
return $this->_redirect(...);
} else if($anotherCondition == true) {
$this->_redirector->gotoSimple("foo");
return;
}

// do some stuff here


}
}

Depending on your application this is not enough as additional action,


preDispatch() or postDispatch() logic might be executed. This cannot be
handled in a good way with Zend Test currently.

2.3. Assertions
Les assertions sont le coeur des tests unitaires; vous les utilisez pour vérifier que le résultat
est bien celui que vous attendiez. A cette fin, Zend_Test_PHPUnit_ControllerTestCase
fournit un certain nombre d'assertions pour simplifier le test de vos applications et contrôleurs
MVC.

2.3.1. Les assertions par sélecteurs CSS


Les sélecteurs CSS sont une manière simple de vérifier que certaines constructions sont bien
présentes dans le contenu de votre réponse. Cela rend aussi plus simple de s'assurer que les
éléments nécessaires pour les librairies Javascript et/ou l'intégration d'AJAX sont présents ; la
plupart des bibliothèques Javascript fournissent des mécanismes pour charger des éléments
DOM sur la base des sélecteurs CSS, ainsi la syntaxe sera identique.

Cette fonctionnalité est fournie via Zend_Dom_Query, et intégré à un jeu d'assertions de type
"Query*". Chacune de ces assertions prend un sélecteur CSS en tant que premier argument,
avec optionnellement des arguments additionnels et/ou un message d'erreur, basé sur le type
d'assertion. Vous pouvez trouver les règles d'écriture des électeurs CSS dans le chapitre
Zend_Dom_Query - Aspect théorique. Les assertion "Query*" incluent :

• assertQuery($path, $message = '') : vérifie qu'un ou plusieurs éléments DOM


correspondant au sélecteur CSS fourni sont présents. Si un $message est présent, il sera
ajouté en cas d'échec de l'assertion.

• assertQueryContentContains($path, $match, $message = '') : vérifie qu'un ou


plusieurs éléments DOM correspondant au sélecteur CSS fourni sont présents, et qu'au moins
un de ceux-ci contient le contenu fournit dans $match. Si un $message est présent, il sera
ajouté en cas d'échec de l'assertion.

• assertQueryContentRegex($path, $pattern, $message = '') : vérifie qu'un ou


plusieurs éléments DOM correspondant au sélecteur CSS fourni sont présents, et qu'au moins
un de ceux-ci correspond à l'expression régulière fournie dans $pattern. Si un $message
est présent, il sera ajouté en cas d'échec de l'assertion.

1394
Zend_Test

• assertQueryCount($path, $count, $message = '') : vérifie qu'un nombre


exact $count d'éléments DOM correspondant au sélecteur CSS fourni sont présents. Si un
$message est présent, il sera ajouté en cas d'échec de l'assertion.

• assertQueryCountMin($path, $count, $message = '') : vérifie qu'au moins un


nombre $count d'éléments DOM correspondant au sélecteur CSS fourni sont présents. Si un
$message est présent, il sera ajouté en cas d'échec de l'assertion. Note : spécifier une valeur
de 1 pour $count est la même chose qu'un simple assertQuery().

• assertQueryCountMax($path, $count, $message = '') : vérifie qu'il n'y a pas plus


d'un nombre $count d'éléments DOM correspondant au sélecteur CSS fourni sont présents.
Si un $message est présent, il sera ajouté en cas d'échec de l'assertion. Note : spécifier une
valeur de 1 pour $count est la même chose qu'un simple assertQuery().

De plus, toutes les méthodes ci-dessus possèdent une variante "Not" qui correspond
à l'assertion négative : assertNotQuery(), assertNotQueryContentContains(),
assertNotQueryContentRegex(), et assertNotQueryCount(). (Notez que les versions
CountMin et CountMax n'ont pas de variantes pour des raisons évidentes).

2.3.2. Les assertions XPath


Certains développeurs sont plus familiers avec XPath qu'avec des sélecteurs CSS, ainsi les
variantes XPath des toutes les assertions Query sont aussi fournies. Il s'agit de :

• assertXpath($path, $message = '')

• assertNotXpath($path, $message = '')

• assertXpathContentContains($path, $match, $message = '')

• assertNotXpathContentContains($path, $match, $message = '')

• assertXpathContentRegex($path, $pattern, $message = '')

• assertNotXpathContentRegex($path, $pattern, $message = '')

• assertXpathCount($path, $count, $message = '')

• assertNotXpathCount($path, $count, $message = '')

• assertXpathCountMin($path, $count, $message = '')

• assertNotXpathCountMax($path, $count, $message = '')

2.3.3. Les assertions de redirections


Souvent une action va redirigé le visiteur. Plutôt que de suivre cette redirection,
Zend_Test_PHPUnit_ControllerTestCase vous permet de tester ces redirections avec
un jeu d'assertions :

• assertRedirect($message = '') : vérifie simplement qu'une redirection est apparue.

• assertNotRedirect($message = '') : vérifie qu'aucune redirection n'est apparue.

• assertRedirectTo($url, $message = '') : vérifie qu'une redirection est apparue, et


que la valeur de l'en-tête "Location" est l' $url fourni.

• assertNotRedirectTo($url, $message = '') : vérifie soit qu'aucune redirection n'est


apparue, ou que la valeur de l'en-tête "Location" n'est pas l' $url fourni.

1395
Zend_Test

• assertRedirectRegex($pattern, $message = '') : vérifie qu'une redirection est


apparue, et que la valeur de l'en-tête "Location" correspond à l'expression régulière fourni
dans $pattern.

• assertNotRedirectRegex($pattern, $message = '') : vérifie soit qu'aucune


redirection n'est apparue, ou que la valeur de l'en-tête "Location" ne correspond pas à
l'expression régulière fourni dans $pattern.

2.3.4. Les assertions d'en-têtes de réponses


En plus de vérifier les en-têtes de redirection, vous avez souvent besoin de vérifier des codes
de réponse HTTP et des en-têtes spécifiques - par exemple, pour déterminer si une action
entraînera une réponse 404 ou 500, ou pour s'assurer qu'une réponse JSON contient bien l'en-
tête Content-Type approprié. Les assertions suivantes sont disponibles :

• assertResponseCode($code, $message = '') : vérifie qu'une réponse renvoie le


code de réponse HTTP fourni.

• assertHeader($header, $message = '') : vérifie qu'une réponse renvoie l'en-tête


fourni.

• assertHeaderContains($header, $match, $message = '') : vérifie qu'une réponse


renvoie l'en-tête fourni et que son contenu vaut la chaîne fournie.

• assertHeaderRegex($header, $pattern, $message = '') : vérifie qu'une réponse


renvoie l'en-tête fourni et que son contenu correspond à l'expression régulière fournie.

De plus, toutes les méthodes ci-dessus possèdent une variante "Not" qui correspond à
l'assertion négative.

2.3.5. Les assertions de requêtes


Il est souvent pratique de vérifier l'action, le contrôleur et le module dernièrement exécuté ; ou,
vous pouvez vouloir vérifier quelle route a été utilisée. Les assertions suivantes peuvent vous
aider dans ce cas :

• assertModule($module, $message = '') : vérifie que le module fourni a été utilisé


lors de la dernière action distribuée.

• assertController($controller, $message = '') : vérifie que le contrôleur fourni


a été utilisé lors de la dernière action distribuée.

• assertAction($action, $message = '') : vérifie que l'action fournie est bien la


dernière distribuée.

• assertRoute($route, $message = '') : vérifie que la route nommée fournie a été


utilisée par le routeur.

De plus, toutes les méthodes ci-dessus possèdent une variante "Not" qui correspond à
l'assertion négative.

2.4. Exemples
Savoir comment configurer votre infrastructure de tests et comment faire des assertions est
seulement la moitié du travail ; maintenant il est temps de commencer à regarder quelques
scénarios réels de test pour voir comment vous pouvez les étendre.

1396
Considérons une tâche habituelle d'un site Web : l'authentification et l'enregistrement
d'utilisateurs. Dans notre exemple, nous avons défini un contrôleur "UserController"
$this->resetRequest()
public function testCallWithoutActionShouldPullFromIndexAction()
pour {gérer ceci, ->resetResponse();
il requiert le conditions suivantes :
Écrivons maintenant les tests : Zend_Test
$this->dispatch('/user');
$this->request->setPost(array());
$this->assertController('user');
$this->assertAction('index');
} // ...
Exemple
} 872. Test d'un contrôleur "UserController"
public function testLoginFormShouldContainLoginAndRegistrationForms()
//
{ ...
} $this->dispatch('/user');
$this->assertQueryCount('form', 2);
}

public function testInvalidCredentialsShouldResultInRedisplayOfLoginForm()


{
$request = $this->getRequest();
$request->setMethod('POST')
->setPost(array(
'username' => 'bogus',
'password' => 'reallyReallyBogus',
));
$this->dispatch('/user/login');
$this->assertNotRedirect();
$this->assertQuery('form');
}

public function testValidLoginShouldRedirectToProfilePage()


{
$this->loginUser('foobar', 'foobar');
}

public function testAuthenticatedUserShouldHaveCustomizedProfilePage()


{
$this->loginUser('foobar', 'foobar');
$this->request->setMethod('GET');
$this->dispatch('/user/view');
$this->assertNotRedirect();
$this->assertQueryContentContains('h2', 'foobar');
}

public function testAuthenticatedUsersShouldBeRedirectedToProfilePageWhenVisitingLog


{
$this->loginUser('foobar', 'foobar');
$this->request->setMethod('GET');
$this->dispatch('/user');
$this->assertRedirectTo('/user/view');
}

public function testUserShouldRedirectToLoginPageOnLogout()


{
$this->loginUser('foobar', 'foobar');
$this->request->setMethod('GET');
$this->dispatch('/user/logout');
$this->assertRedirectTo('/user');
}

public function testRegistrationShouldFailWithInvalidData()


Cette{application peut utiliser une base de données. Si oui, vous aurez besoin probablement
d'un certain échafaudage
$data = array( pour s'assurer que la base de données est dans une configuration
initiale et testable au début de
'username' => chaque essai.not
'This will PHPUnit
work',fournit déjà une fonctionnalité pour
faire ceci ; lisez ceci
'email' dans la=>documentation
'this is anPHPUnit.
invalid Nous
Notez également que nous utilisons la structure du document recommandons
email',
dans d'utiliser
nos essais. Par une
exemple,
base de données séparée
'password' pour
=> les tests et
'Th1s!s!nv@l1d', pour la production, et recommandons
dans le test final, nous recherchons un formulaire qui a un noeud avec la classe "errors" ; ceci en
particulier 'passwordVerification'
d'employer un fichier SQLite ou => 'wrong!',
une base de données en mémoire, d'autant que
nous permet ); de déterminer simplement la présence des erreurs de validation de formulaire,
les
et deuxnous
sans options s'exécutent
inquiéter de quellestrèserreurs
bien, sans nécessité
spécifiques d'un serveur
pourraient séparé,
avoir été et peuvent
levées.
Notez $request = $this->getRequest();
utiliserque ces tests
la plupart de sont
la laconiques,
syntaxe SQL et, pour la plupart, ne recherchent pas le contenu réel.
Au lieu de$request->setMethod('POST')
cela, ils recherchent des objets construits dans la réponse - codes et en-têtes de
réponse, et noeuds ->setPost($data);
DOM. Ceci vous permet de vérifier que la structure est comme prévue
$this->dispatch('/user/register');
- sans entraîner un échec dans vos tests à chaque fois qu'un contenu est ajouté au site.
$this->assertNotRedirect();
1397 .errors');
$this->assertQuery('form
}
}
Zend_Test

3. Zend_Test_PHPUnit_Db
Couper l'accès aux données au modèle métier requiert souvent l'utilisation d'une base de
données pour les tests. Mais la base est persistente entre les tests, et leur isolation est donc
rompue, de plus, configurer une base de données pour des tests peut vite s'avérer complexe.
L'extension sur les bases de données de PHPUnit simplifie les procédures de tests en offrant
des mécanismes de preconditions et postconditions sur la base entre les tests. Ce composant
étend donc l'extension base de données de PHPUnit en ajoutant du code spécifique à Zend
Framework.

Les tests de base de données peuvent être résumés en 2 notions : DataSets et DataTables. En
interne, PHPUnit peut créer un objet dont la structure est callée sur une base de données dont
les tables et les enregistrements sont montés depuis un fichier de configuration ou un contenu
réel. Cet objet abstrait peut alors être comparé à des structures. Un cas courant en tests de base
de données consiste à configurer des tables en les remplissant de données fictives, éxecuter du
code "utile", puis comparer la base de données avec une structure. Zend_Test_PHPUnit_Db
simplifie cette tâche en offrant la possibilité de créer des DataSets et des DataTables provenant
d'instances de Zend_Db_Table_Abstract ou Zend_Db_Table_Rowset_Abstract.

Aussi, ce composant permet l'utilisation de n'importe quel Zend_Db_Adapter_Abstract


alors qu'à l'originine PHPUnit ne fonctionne qu'avec PDO. Un adaptateur de test basé sur
Zend_Db_Adapter_Abstract est aussi inclus. Il permet d'instancier un adaptateur qui ne
requiert aucune base de données réelle.

3.1. Quickstart
3.1.1. Configurer un cas de tests Database
Nous allons à présent écrire des tests pour la base de données Bug de la documentation
sur Zend_Db_Table. D'abord, nous testons qu'insérer un nouveau bug est bien
sauvegardé en base. Nous devons créer un cas de tests sous forme de classe étendant
Zend_Test_PHPUnit_DatabaseTestCase. Cette classe étend elle- même PHPUnit
Database Extension, qui étend alors PHPUnit_Framework_TestCase. Un cas de test pour
base de données contient deux méthodes abstraites à définir, une concernant la connexion à la
base et l'autre concernant les données à utiliser comme source pour les tests.

Il est recommandé de se familiariser à l'extension PHPUnit Database afin de


suivre nos exemples sereinnement. Bien que nous expliquions tous les concepts
dans cette documentation, il peut être intéressant de lire la documentation de
PHPUnit avant de suivre nos exemples.

class BugsTest extends Zend_Test_PHPUnit_DatabaseTestCase


{
private $_connectionMock;

/**
* Retourne la connexion de test
*
* @return PHPUnit_Extensions_Database_DB_IDatabaseConnection
*/
protected function getConnection()
{
if($this->_connectionMock == null) {
$connection = Zend_Db::factory(...);
$this->_connectionMock = $this->createZendDbConnection(

1398
Zend_Test

$connection, 'zfunittests'
);
Zend_Db_Table_Abstract::setDefaultAdapter($connection);
}
return $this->_connectionMock;
}

/**
* @return PHPUnit_Extensions_Database_DataSet_IDataSet
*/
protected function getDataSet()
{
return $this->createFlatXmlDataSet(
dirname(__FILE__) . '/_files/bugsSeed.xml'
);
}
}

Ici, nous créons la connexion à la base et nous y injectons des données fictives de test. Les
éléments suivants sont importants à noter :

• Vous ne pouvez retourner directement un objet Zend_Db_Adapter_Abstract depuis


getConnection(), mais un objet spécifique à PHPUnit qui est généré grâce à la méthode
createZendDbConnection().

• Le schéma de la base (tables et bases de données) n'est pas recrée entre chaque test. Les
bases de données et les tables doivent être créees à la main avant de lancer les tests.

• Les tests vident la base durant setUp() et y insèrent les données en provenance de
getDataSet().

• Les jeux de données (DataSets) doivent implémenter


PHPUnit_Extensions_Database_DataSet_IDataSet. Il en existe quelques uns, basés
sur XML ou YAML et ils sont inclus dans PHPUnit et permettent de décrire les données
fictives pour les tests. Vous devriez vous reporter à la documentation de PHPUnit pour des
informations complémentaires ou plus à jour concernant les DataSets.

3.1.2. Spécifier un jeu de données (DataSet)


Dans l'exemple précédent, nous avons préciser un fichier de jeu de données. Nous allons
maintenant le créer, au format XML :

<?xml version="1.0" encoding="UTF-8" ?>


<dataset>
<zfbugs bug_id="1" bug_description="system needs electricity to run"
bug_status="NEW" created_on="2007-04-01 00:00:00"
updated_on="2007-04-01 00:00:00" reported_by="goofy"
assigned_to="mmouse" verified_by="dduck" />
<zfbugs bug_id="2" bug_description="Implement Do What I Mean function"
bug_status="VERIFIED" created_on="2007-04-02 00:00:00"
updated_on="2007-04-02 00:00:00" reported_by="goofy"
assigned_to="mmouse" verified_by="dduck" />
<zfbugs bug_id="3" bug_description="Where are my keys?" bug_status="FIXED"
created_on="2007-04-03 00:00:00" updated_on="2007-04-03 00:00:00"
reported_by="dduck" assigned_to="mmouse" verified_by="dduck" />
<zfbugs bug_id="4" bug_description="Bug no product" bug_status="INCOMPLETE"
created_on="2007-04-04 00:00:00" updated_on="2007-04-04 00:00:00"
reported_by="mmouse" assigned_to="goofy" verified_by="dduck" />

1399
Zend_Test

</dataset>

Nous allons travailler sur ces quatre entrées dans la table "zfbugs" après. Le script MySQL
suivant est nécessaire pour l'exemple:

CREATE TABLE IF NOT EXISTS `zfbugs` (


`bug_id` int(11) NOT NULL auto_increment,
`bug_description` varchar(100) default NULL,
`bug_status` varchar(20) default NULL,
`created_on` datetime default NULL,
`updated_on` datetime default NULL,
`reported_by` varchar(100) default NULL,
`assigned_to` varchar(100) default NULL,
`verified_by` varchar(100) default NULL,
PRIMARY KEY (`bug_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 ;

3.1.3. Quelques tests initiaux


Maintenant que nous avons écrits les deux méthodes obligatoires pour
Zend_Test_PHPUnit_DatabaseTestCase et que nous avons préciser avec quoi remplir la
base et ses tables, nous pouvons commencer à écrire des tests afin d'effectuer des assertions.
Voyons un test pour l'insertion d'un nouveau bug

class BugsTest extends Zend_Test_PHPUnit_DatabaseTestCase


{
public function testBugInsertedIntoDatabase()
{
$bugsTable = new Bugs();

$data = array(
'created_on' => '2007-03-22 00:00:00',
'updated_on' => '2007-03-22 00:00:00',
'bug_description' => 'Something wrong',
'bug_status' => 'NEW',
'reported_by' => 'garfield',
'verified_by' => 'garfield',
'assigned_to' => 'mmouse',
);

$bugsTable->insert($data);

$ds = new Zend_Test_PHPUnit_Db_DataSet_QueryDataSet(


$this->getConnection()
);
$ds->addTable('zfbugs', 'SELECT * FROM zfbugs');

$this->assertDataSetsEqual(
$this->createFlatXmlDataSet(dirname(__FILE__)
. "/_files/bugsInsertIntoAssertion.xml"),
$ds
);
}
}

Au dessus de la ligne $bugsTable->insert($data);, tout devrait vous être familier.


La ligne d'après contient le nom de la méthode d'assertion. Nous souhaitons vérifier
qu'après l'insertion d'un bug, la base a été correctement mise à jour avec les

1400
Zend_Test

données. Ainsi, nous utilisons un objet de requête de jeu de données, instance de


Zend_Test_PHPUnit_Db_DataSet_QueryDataSet et nous lui fournissons notre connexion
à la base de données. Puis nous indiquons à notre objet de requête qu'il contient une
table "zfbugs" contenant les données d'une requête SQL statement. Cet état actuel est alors
comparé à un état contenu dans un fichier XML "bugsInsertIntoAssertions.xml". Ce fichier
XML est le même que celui des données d'origine, à l'exception qu'il contient lui les données
supplémentaires attendues:

<?xml version="1.0" encoding="UTF-8" ?>


<dataset>
<!-- Les 4 enregistrement précédents, puis: -->
<zfbugs bug_id="5" bug_description="Something wrong" bug_status="NEW"
created_on="2007-03-22 00:00:00" updated_on="2007-03-22 00:00:00"
reported_by="garfield" assigned_to="mmouse" verified_by="garfield" />
</dataset>

Il existe d'autres manière de vérifier que l'état actuel de la base est équivalent à un état attendu.
La table "Bugs" de l'exemple connait déja sont état interne, utilisons ceci à notre avantage.
L'exemple suivant teste que la suppression de données dans la table est possible:

class BugsTest extends Zend_Test_PHPUnit_DatabaseTestCase


{
public function testBugDelete()
{
$bugsTable = new Bugs();

$bugsTable->delete(
$bugsTable->getAdapter()->quoteInto("bug_id = ?", 4)
);

$ds = new Zend_Test_PHPUnit_Db_DataSet_DbTableDataSet();


$ds->addTable($bugsTable);

$this->assertDataSetsEqual(
$this->createFlatXmlDataSet(dirname(__FILE__)
. "/_files/bugsDeleteAssertion.xml"),
$ds
);
}
}

Ici nous créons un objet représentant un jeu de données pour une table, instance de
Zend_Test_PHPUnit_Db_DataSet_DbTableDataSet. Il prend en paramètre un objet
Zend_Db_Table_Abstract et l'ajoute au jeu de données avec le nom de la table, dans notre
exemple : "zfbugs". Vous pourriez ajouter plus de données dans le jeu de données en utilisant
addTable() plusieurs fois.

Ici nous ne possédons qu'une seule table et nous la comparons à un état défini dans
"bugsDeleteAssertion.xml" qui est en fait le jeu de données original moins la données supprimée :
celle ayant l'id 4.

Voyons maintenant comment vérifier que deux tables soient identiques (et non deux jeux de
données correspondants à de telles tables). Ajoutons un test à notre scénario qui va vérifier la
mise à jour de données.

class BugsTest extends Zend_Test_PHPUnit_DatabaseTestCase


{

1401
Zend_Test

public function testBugUpdate()


{
$bugsTable = new Bugs();

$data = array(
'updated_on' => '2007-05-23',
'bug_status' => 'FIXED'
);

$where = $bugsTable->getAdapter()->quoteInto('bug_id = ?', 1);

$bugsTable->update($data, $where);

$rowset = $bugsTable->fetchAll();

$ds = new Zend_Test_PHPUnit_Db_DataSet_DbRowset($rowset);


$assertion = $this->createFlatXmlDataSet(
dirname(__FILE__) . '/_files/bugsUpdateAssertion.xml'
);
$expectedRowsets = $assertion->getTable('zfbugs');

$this->assertTablesEqual(
$expectedRowsets, $ds
);
}
}

Ici, nous récupérons l'état de la table depuis un objet Zend_Db_Table_Rowset_Abstract


au moyen de Zend_Test_PHPUnit_Db_DataSet_DbRowset($rowset) qui crée une
représentation de l'état interne des données du rowset. Nous comparons enfin cet état grâce à
l'assertion $this->assertTablesEqual()

3.2. Utilisation, API et possibilités d'extension


Le Quickstart permet déja de se rendre compte des capacités de tests d'une base de
données avec PHPUnit et Zend Framework. Cette section donne un aperçu de l'API de
Zend_Test_PHPUnit_Db ainsi que de son fonctionnement interne.

Remarque sur les tests de bases de données

Tout comme les TestCase de vos contrôleurs, les tests de bases de données
sont efféctués au niveau intégration. Ils utilisent différentes couches applicatives
pour lancer les tests et à ce titre devraient être utilisés avec précaution.

Notez que tester la logique métier au seul moyen de tests d'intégration


comme ceux fournis avec Zend_Test de Zend Framework est une mauvaise
pratique. Les tests d'intégration sont là pour prouver le bon fonctionnement de
l'assemblage des composants entre eux, ils ne doivent donc pas remplacer des
tests unitaires éffectués plus bas dans les couches de votre logique métier.

3.2.1. La classe Zend_Test_PHPUnit_DatabaseTestCase


La classe Zend_Test_PHPUnit_DatabaseTestCase étend
PHPUnit_Extensions_Database_TestCase, celle-ci permet de configurer un jeu de
données concernant la base, pour chaque test. L'implementation du Zend Framework offre
quelques fonctionalités supplémentaires par rapport à l'extension PHPUnit concernant les bases

1402
Zend_Test

de données, ceci dans le but d'utiliser des ressources provenant de Zend_Db. Voici le scénario
classique d'un test de base de données :

1. Pour chaque test, PHPUnit crée une instance de la classe de tests (TestCase) et lance la
méthode setUp().

2. Le scénario de test (TestCase) crée à son tour une instance du testeur de base de données
(Database Tester) qui s'occupe de la construction et destruction de la base de données.

3. Le testeur de base de données récupère la connexion à la base et le jeu de données initiales


grâce à getConnection() et getDataSet() qui sont toutes deux des méthodes abstraites
que vous devez implémenter dans votre scénario de test.

4. Par défaut le testeur vide les tables spécifiées dans le jeu de données, puis peuple la base
avec le jeu de données.

5. Lorsque le testeur a fini de monter la base, PHPUnit lance votre test.

6. Après que votre test ait fini, tearDown() est appelée. Cette méthode n'exécute aucune action
du la base de données elle-même car les actions à mener sont efféctuées en setUp() (vider
les tables).

Le test de la base s'attend à ce que la base de données et les tables soient


présentes. Il n'existe pas de mécanisme pour créer/détruire des base de données
et/ou des tables.

La classe Zend_Test_PHPUnit_DatabaseTestCase permet les tests de base de données


à l'echelle du Zend Framework.

Le tableau suivant liste uniquement les nouvelles méthodes par rapport à la


classe PHPUnit_Extensions_Database_TestCase, dont l'API est documentée dans la
documentation de PHPUnit.

Tableau 147. Méthodes de Zend_Test_PHPUnit_DatabaseTestCase


Méthode Description
Créer une connexion compatible avec
createZendDbConnection(Zend_Db_Adapter_Abstract
$connection, $schema) l'extension PHPUnit Database depuis une
instance de Zend_Db_Adapter_Abstract.
Cette méthode devrait être utilisée dans
la configuration du scénario de tests
en implémentant la méthode abstraite
getConnection().
getAdapter() Méthode permettant l'accès à l'instance
de Zend_Db_Adapter_Abstract qui est
encapsulée dans la connexion efféctuée par
PHPUnit au moyen de getConnection().
Créer un objet représentant les données
createDbRowset(Zend_Db_Table_Rowset_Abstract
$rowset, $tableName = null) d'une table depuis une instance
de Zend_Db_Table_Rowset_Abstract
donnée. La table reliée au rowset est choisie
lorsque $tableName est NULL.
createDbTable(Zend_Db_Table_Abstract Créer un objet qui représente les
$table, $where = null, $order = données contenues dans une instance
null, $count = null, $offset = null) de Zend_Db_Table_Abstract donnée. La

1403
Zend_Test

Méthode Description
récupération des données est faite grâce
à fetchAll(), les paramètres additionnels
peuvent servir à limiter les données retournées.
createDbTableDataSet(array Crée un jeu de données basé sur les
$tables=array()) tables $tables, tableau d'instances de
Zend_Db_Table_Abstract.

3.2.2. Intégrer les tests de bases de données avec les tests de


contrôleurs
PHP n'autorise pas l'héritage multiple, donc vous ne pouvez utiliser les tests de contrôleurs
et de bases de données en même temps via héritage. Cependant, vous pouvez utiliser
Zend_Test_PHPUnit_Db_SimpleTester dans vos tests de contrôleurs pour configurer un
environnement relatif à la base pour chaque test de contrôleur.

Exemple 873. Exemple d'intégration d'une base de données

Cet exemple reprend le test de UserController utilisé dans la documentation de


Zend_Test_PHPUnit_ControllerTestCase et y inclut la gestion d'une base de
données.

class UserControllerTest extends Zend_Test_PHPUnit_ControllerTestCase


{
public function setUp()
{
$this->setupDatabase();
$this->bootstrap = array($this, 'appBootstrap');
parent::setUp();
}

public function setupDatabase()


{
$db = Zend_Db::factory(...);
$connection = new Zend_Test_PHPUnit_Db_Connection($db,
'database_schema_name');
$databaseTester = new Zend_Test_PHPUnit_Db_SimpleTester($connection);

$databaseFixture =
new PHPUnit_Extensions_Database_DataSet_FlatXmlDataSet(
dirname(__FILE__) . '/_files/initialUserFixture.xml'
);

$databaseTester->setupDatabase($databaseFixture);
}
}

Ici le jeu de données XML "initialUserFixture.xml" est utilisé pour monter des données en
base avant chaque test, exactement de la même manière que DatabaseTestCase le fait
en interne.

3.3. Utiliser l'adaptateur de tests


Il peut être nécessaire quelques fois de vouloir tester l'application, mais sans base de données
réelle physique. Zend_Test_DbAdapter offre des possibilités d'utiliser une implémentation de
Zend_Db_Adapter_Abstract sans avoir à ouvrir une connexion vers une base physique. En

1404
Zend_Test

plus, cet adaptateur est très facilement déguisable car aucun paramètre de constructeur n'est
nécessaire.

L'adaptateur de tests agit comme une pile pour des résultats de base. L'ordre des résultats doit
être implémenté manuellement ce qui peut devenir assez complexe, mais cet adaptateur est très
pratique dans le cas où un ensemble logique de requêtes est éxecuté et que vous connaissez
l'ordre précis dans lequel les résultats doivent être retournés.

$adapter = new Zend_Test_DbAdapter();


$stmt1Rows = array(array('foo' => 'bar'), array('foo' => 'baz'));
$stmt1 = Zend_Test_DbStatement::createSelectStatement($stmt1Rows);
$adapter->appendStatementToStack($stmt1);

$stmt2Rows = array(array('foo' => 'bar'), array('foo' => 'baz'));


$stmt2 = Zend_Test_DbStatement::createSelectStatement($stmt2Rows);
$adapter->appendStatementToStack($stmt2);

$rs = $adapter->query('SELECT ...'); // Retourne Statement 2


while ($row = $rs->fetch()) {
echo $rs['foo']; // Prints "Bar", "Baz"
}
$rs = $adapter->query('SELECT ...'); // Retourne Statement 1

Le comportement des adaptateurs réels est simulé afin que des méthodes telles que
fetchAll(), fetchObject(), fetchColumn() puissent fonctionner avec l'adaptateur de
tests.

Bien sûr, INSERT, UPDATE et DELETE peuvent être empilés aussi, mais vous ne pourrez alors
tester que $stmt->rowCount() car ces types de requêtes ne retournent pas de résultats.

$adapter = new Zend_Test_DbAdapter();


$adapter->appendStatementToStack(
Zend_Test_DbStatement::createInsertStatement(1)
);
$adapter->appendStatementToStack(
Zend_Test_DbStatement::createUpdateStatement(2)
);
$adapter->appendStatementToStack(
Zend_Test_DbStatement::createDeleteStatement(10
));

Par défaut, le profiler est activé pour que vous puissiez récupérer la requête éxecutée de manière
textuelle, avec ses paramètres donc.

$adapter = new Zend_Test_DbAdapter();


$stmt = $adapter->query("SELECT * FROM bugs");

$qp = $adapter->getProfiler()->getLastQueryProfile();

echo $qp->getQuerY(); // SELECT * FROM bugs

L'adaptateur de test ne vérifie jamais si la requête spécifiée est réellement de type SELECT,
DELETE, INSERT ou UPDATE. L'ordre exact de retour des données doit être spécifié
manuellement dans l'adaptateur de tests.

L'adaptateur de tests définit aussi les méthodes listTables(), describeTables() et


lastInsertId(). De plus en utilisant setQuoteIdentifierSymbol() vous pouvez
spécifier quel symbole utilisé pour l'échappement, par défaut aucun n'est utilisé.

1405
Zend_Text
1. Zend_Text_Figlet
Zend_Text_Figlet est un composant qui permet aux développeurs de créer des textes
dénommés FIGlet. Un texte FIGlet test une chaîne de caractères, qui est représenté en "ASCII-
art". FIGlet utilise une format de police spécial , nommée FLT (FigLet Font). Par défaut, une
police standard est fourni avec Zend_Text_Figlet, mais vous pouvez ajouter des polices
additionnels à http://www.figlet.org.

Polices compressée
Zend_Text_Figlet supporte les polices compressées en gzip. Ceci veut
dire que vous pouvez prendre un fichier .flf et le gzipper. Pour permettre
à Zend_Text_Figlet de les reconnaître, les polices gzippées doivent avoir
l'extension .gz. De plus, pour pouvoir utiliser les polices compressées, vous
devez activer l'extension GZIP de PHP.

Encodage
Zend_Text_Figlet considère que vos chaînes sont encodées en UTF-8 par
défaut. Si ce n'est pas le cas, vous pouvez fournir le type d'encodage des
caractères en tant que second paramètre à la méthode render().

Il existe plusieurs options pour un FIGlet. Quand vous instanciez Zend_Text_Figlet, vous
pouvez les fournir sous la forme d'un tableau ou d'un objet Zend_Config.

• font : défini la police utilisée pour le rendu. Par défaut la police incorporé sera utilisée.

• outputWidth : défini la largeur maximum de la chaîne résultat. Ceci est utilisé pour le retour
à la ligne automatique ainsi que pour la justification. Attention cependant à de trop petites
valeurs, qui pourraient induire un comportement indéfini. La valeur par défaut est 80.

• handleParagraphs : un booléen qui indique, comment les nouvelles lignes sont gérées.
Réglé à TRUE, les nouvelles lignes uniques sont ignorées et traitées comme un espace unique.
Seules des nouvelles lignes multiples seront gérées comme telles. La valeur par défaut est
FALSE.

• justification : peut être une des valeurs de type


Zend_Text_Figlet::JUSTIFICATION_*. Il existe JUSTIFICATION_LEFT,
JUSTIFICATION_CENTER et JUSTIFICATION_RIGHT. La justification par défaut est défini
par la valeur de rightToLeft.

• rightToLeft : défini la direction d'écriture du texte. Peut être


Zend_Text_Figlet::DIRECTION_LEFT_TO_RIGHT ou
Zend_Text_Figlet::DIRECTION_RIGHT_TO_LEFT. Par défaut le réglage du fichier de
police est utilisé. Quand aucune justification n'est définie, un texte écrit de droite à gauche est
automatiquement aligné à droite.

• smushMode : un entier qui définit comme chaque caractère est fusionné avec les autres. Peut
être la somme de multiple valeurs de type Zend_Text_Figlet::SM_*. Il existe les modes
de fusion suivant : SM_EQUAL, SM_LOWLINE, SM_HIERARCHY, SM_PAIR, SM_BIGX,

1406
Zend_Text

SM_HARDBLANK, SM_KERN et SM_SMUSH. Une valeur de 0 ne désactive pas entièrement


la fusion, mais force la valeur SM_KERN, tandis que la valeur de -1 la désactive. Une
explication des différents modes de fusion peut être trouvé ici. Par défaut le réglage de la police
est utilisé. L'option du mode de fusion est normalement seulement utilisé par les concepteurs
de police testant les différents mode de disposition d'une nouvelle police.

Exemple 874. Utilisation Zend_Text_Figlet

Cet exemple illustre une utilisation basique de Zend_Text_Figlet pour créer une texte
FIGlet simple :

$figlet = new Zend_Text_Figlet();


echo $figlet->render('Zend');

En considérant que vous utilisez une police à espacement fixe, vous obtiendrez quelque
chose comme ceci :

______ ______ _ __ ______


|__ // | ___|| | \| || | __ \\
/ // | ||__ | ' || | | \ ||
/ //__ | ||___ | . || | |__/ ||
/_____|| |_____|| |_|\_|| |_____//
`-----`' `-----` `-` -`' -----`

2. Zend_Text_Table
Zend_Text_Table est un composant pour créer à la volée des tables de type texte avec
différents décorateurs. Ceci peut être utile, si vous souhaitez soit envoyé des données
structurées dans des emails textuels, qui sont sont utilisés pour leurs polices mono-
espacés, ou pour afficher des informations sous forme de tableaux dans une application CLI.
Zend_Text_Table supporte les colonnes multi-lignes, les fusions de colonnes ainsi que
l'alignement.

Encodage
Zend_Text_Table suppose que vos chaînes sont encodés en
UTF-8 par défaut. Si ce n'est pas le cas, vous pouvez fournir
l'encodage en tant que paramètre du constructeur ou à la
méthode setContent de Zend_Text_Table_Column. Alternativement
si vous avez un encodage différent dans le processus complet,
vous pouvez définir l'encodage d'entrée ("input") standard avec
Zend_Text_Table::setInputCharset($charset). Dans le cas où vous
avez besoin d'un autre encodage pour la sortie ("output") de la table, vous pouvez
le paramétrer avec Zend_Text_Table::setOutputCharset($charset).

Un objet Zend_Text_Table consiste en des lignes, qui contiennent des colonnes, représenté
par Zend_Text_Table_Row et Zend_Text_Table_Column. Lors de la création d'une table,
vous pouvez fournir un tableau avec les options pour la table. Celles-ci sont :

• columnWidths (obligatoire) : un tableau définissant toutes les largeurs de colonnes en


nombre de caractères.

• decorator : le décorateur à utiliser pour les bordures de la table. Le défaut est unicode,
mais vous pouvez aussi spécifier ascii ou fournir une instance d'un objet décorateur
personnalisé.

1407
Zend_Text

• padding : le remplissage gauche et droit de la colonne en caractères. Le remplissage par


défaut est zéro.

• AutoSeparate : la manière comment les lignes sont séparées avec des lignes horizontales.
Par défaut, il y a une séparation entre chaque ligne. Ceci est défini entant que bitmask
contenant une ou plus des constantes de Zend_Text_Table suivantes :

• Zend_Text_Table::AUTO_SEPARATE_NONE

• Zend_Text_Table::AUTO_SEPARATE_HEADER

• Zend_Text_Table::AUTO_SEPARATE_FOOTER

• Zend_Text_Table::AUTO_SEPARATE_ALL
Où "header" est toujours la première ligne, et "footer" est toujours la dernière.

Les lignes sont simplement ajoutées à la table en créant une nouvelle instance de
Zend_Text_Table_Row, et en l'ajoutant à la table via la méthode appendRow. Les lignes
elle-même n'ont pas d'options. Vous pouvez aussi fournir un tableau directement à la méthode
appendRow, qui le convertira automatiquement en des objets Row, contenant les multiples objets
Column.

De la même manière vous pouvez ajouter les colonnes aux lignes. Créez un instance de
Zend_Text_Table_Column et ensuite paramétrer les options de colonnes soit dans le
constructeur ou plus tard par les méthodes set*. Le premier paramètre est le contenu de la
colonne qui peut avoir des lignes multiples, elles sont dans le meilleur des cas séparées par le
caractère \n. Le second paramètre définit l'alignement, qui est left par défaut et peut être l'une
des constantes de la classe Zend_Text_Table_Column :

• ALIGN_LEFT

• ALIGN_CENTER

• ALIGN_RIGHT

Le troisième paramètre est le colspan ("fusion") de la colonne. Par exemple, quand vous
choisissez "2 comme colspan, la colonne va déborder sur deux colonnes de la table. Le dernier
paramètre définit l'encodage du contenu, qui peut être fourni, si le contenu n'est ni de l'ASCII ni de
l'UTF-8. Pour ajouter la colonne à la ligne, vous appelez simplement appendColumn dans votre
objet Row avec l'objet Column en tant que paramètre. Alternativement vous pouvez directement
fournir la chaîne à la méthode appendColumn.

Pour finalement effectuer le rendu de la table, vous pouvez soit utiliser la méthode render
de la table, ou utilisez la méthode magique __toString en faisant echo $table; ou
$tableString = (string) $table.

1408
Zend_Text

Exemple 875. Utilisation de Zend_Text_Table

Cet exemple illustre un utilisation basique de Zend_Text_Table pour créer une table
simple :

$table = new Zend_Text_Table(array('columnWidths' => array(10, 20)));

// Either simple
$table->appendRow(array('Zend', 'Framework'));

// Or verbose
$row = new Zend_Text_Table_Row();

$row->appendColumn(new Zend_Text_Table_Column('Zend'));
$row->appendColumn(new Zend_Text_Table_Column('Framework'));

$table->appendRow($row);

echo $table;

Ceci entraînera l'affichage suivant :

#################################
#Zend #Framework #
#################################

1409
Zend_TimeSync
1. Introduction
Zend_TimeSync est capable de recevoir une information temporelle depuis un serveur de
temps, en utilisant les protocoles NTP ou SNTP. Avec Zend_TimeSync, Zend Framework peut
fonctionner sans se soucier de la configuration du temps (de la date) du serveur sur lequel il
tourne.

Pour se rendre indépendant du temps actuel sur le serveur, Zend_TimeSync fonctionne en


calculant des différences entre le temps du serveur, et le temps réel actuel, en envoyant et
recevant des paquets vers un serveur de gestion du temps, grâce aux protocoles NTP ou SNTP.

En tâche de fond
Zend_TimeSync ne peut pas changer le temps sur le serveur, mais il peut en
revanche retourner un objet Zend_Date de différence de temps, pour travailler
avec.

1.1. Pourquoi Zend_TimeSync ?


Pourquoi donc utiliser Zend_TimeSync ?

En théorie, sur un serveur, un service (démon) tourne sur le système d'exploitation, pour
s'occuper de la synchronisation précise du temps, avec un serveur distant de temps. Cependant
il est possible que votre OS ne supporte pas ceci, ou que vous n'ayez pas les droits, ou la
possibilité de gérer un tel service de synchronisation. Zend_TimeSync prend alors tout son
sens.

Voici quelques exemples dans lesquels Zend_TimeSync est tout à fait adapté et utile :

• Serveur sans service de synchronisation du temps

Si votre application tourne sur un serveur qui ne possède pas de service de synchronisation du
temps, alors utiliser Zend_TimeSync vous permettra de gérer le temps dans votre application.

• Serveurs de base de données séparés

Si votre serveur de base de données est installé sur un serveur distant, et qu'il n'est
pas synchronisé temporellement avec votre serveur applicatif, alors vous rencontrerez des
problèmes si vous utilisez des timestamps.

• Serveurs multiples

Si votre application fonctionne au travers de multiples serveurs applicatifs, il est possible que
ceux-ci ne soient pas synchronisés au niveau du temps, et entre eux. Des problèmes vont
alors apparaître lorsque des données proviennent de plusieurs serveurs différents, et sont
traitées ensemble.

• Processus de Batch

Si vous utilisez des fichiers batchs, ou des applications en ligne de commande, et que celles-
ci nécessitent une synchronisation temporelle absente sur votre système.

1410
Zend_TimeSync

Dans tous ces cas là, Zend_TimeSync est une solution parfaite lorsque vous ne pouvez installer
de service sur vos serveurs.

1.2. Qu'est ce que NTP ?


Le Network Time Protocol (NTP) est un protocole utilisé pour la synchronisation du temps
des systèmes informatiques au travers du réseau. NTP utilise le port UDP 123 comme couche
de transport. Voyez cet article wikipédia pour plus d'informations sur le protocole.

1.3. Qu'est ce que SNTP?


Le Simple Network Time Protocol (SNTP) est un protocole utilisé pour la synchronisation
du temps des systèmes informatiques au travers du réseau. SNTP utilise le port UDP 37 comme
couche de transport. Il est très semblable à NTP, mais plus simple (comme son nom l'indique).

1.4. Problèmes courants d'utilisation


Faites attention avec l'utilisation de Zend_TimeSync. Vous devrez garder en tête certains
détails concernant la structure de la synchronisation temporelle, et du Web lui-même. Les
bonnes pratiques pour éviter ces problèmes sont décrites ici. Lisez les bien avant d'utiliser
Zend_TimeSync.

1.5. Décider quel serveur de temps utiliser


Décider du serveur de temps à utiliser est assez minutieux. Vous devrez prendre en
considération les paramètres suivants :

• La distance

Bien entendu la distance entre votre serveur et le serveur de temps est importante. Afin de
réduire la charge réseau et d'obtenir des réponses plus rapides, veillez à utiliser un serveur
de temps proche géographiquement de votre serveur applicatif.

• La vitesse

La vitesse à laquelle les serveur de temps vont vous répondre est importante. Certains sont
souvent saturés. Faîtes des mesures.

• Leur nombre

N'utilisez pas systématiquement le même serveur de temps pour vous synchroniser. Si vous
envoyez trop de requêtes vers un serveur de temps, celui-ci pourra vous bannir. Utilisez un
pool de serveurs dont vous assurerez la rotation.

Mais où donc trouver des serveurs de temps ? Déjà, essayez votre LAN. En effet il est possible
que vous disposiez d'un serveur de temps interne à votre structure. Sinon vous pouvez utiliser
l'un des nombreux serveurs publics. Il sera alors intéressant d'utiliser un pool de serveurs. Un
pool est un serveur vous donnant aléatoirement l'adresse d'un serveur de temps, en fonction de
critères, comme la distance. C'est une solution tout à fait adaptée pour assurer une rotation des
serveurs, et éviter tous les problèmes mentionnés ci-dessus.

Voyez www.pool.ntp.org afin de récupérer le pool le plus proche de vous. Par exemple pour un
serveur en France 0.europe.pool.ntp.org pourra faire l'affaire.

1411
Zend_TimeSync

2. Utiliser Zend_TimeSync
Zend_TimeSync peut retourner le temps de n'importe quel serveur via NTP ou SNTP. Il peut
aussi gérer de multiples serveurs.

Dans tous les exemples qui suivront, nous utiliserons un pool de serveurs
générique public : 0.europe.pool.ntp.org. De votre côté, il est conseillé d'utiliser
le pool le plus proche possible géographiquement de votre position. Lisez http://
www.pool.ntp.org pour plus d'informations.

2.1. Requêter un serveur de temps public


Cette opération est très simple, il suffit de préciser le serveur de temps à utiliser.

$server = new Zend_TimeSync('0.pool.ntp.org');

print $server->getDate()->getIso();

Que se passe-t-il en arrière plan de Zend_TimeSync ? Tout d'abord la syntaxe est vérifiée. Ainsi,
"0.pool.ntp.org" est vérifié et reconnu comme pouvant être un serveur de temps. Ensuite
l'appel à getDate() génère une requête vers le serveur de temps qui retourne son temps.
Zend_TimeSync va alors calculer la différence entre ce temps retourné, et le temps actuel du
serveur sur lequel le script tourne, et retourner finalement un objet Zend_Date représentant le
temps actuel, juste et corrigé.

Pour plus de détails sur les objets Zend_Date et leurs méthodes, voyez la documentation de
Zend_Date.

2.2. Serveurs de temps multiples


Tous les serveurs de temps ne sont pas disponibles tout le temps, à 100%. Il peuvent subir
des opérations de maintenance, ou tout simplement se retrouver saturés. Dans de tels cas, une
exception sera levée.

Zend_TimeSync peut gérer plusieurs serveurs, et se connecter automatiquement au suivant, si


le précédent ne répond pas. Passez un tableau de serverus de temps au constructeur de l'objet,
ou utilisez la méthode addServer() :

$server = new Zend_TimeSync(array('0.pool.ntp.org',


'1.pool.ntp.org',
'2.pool.ntp.org'));
$server->addServer('3.pool.ntp.org');

print $server->getDate()->getIso();

Vous pouvez ajouter une infinité de serveurs, et Zend_TimeSync basculera automatiquement


au suivant, si un ne répond pas.

Vous devriez aussi nommer vos serveurs de temps. Ceci se fait au moyen de la clé du tableau
de serveurs, ou en second paramètre de la méthode addServer() :

$server = new Zend_TimeSync(array('generic' => '0.pool.ntp.org',


'fallback' => '1.pool.ntp.org',

1412
Zend_TimeSync

'reserve' => '2.pool.ntp.org'));


$server->addServer('3.pool.ntp.org', 'additional');

print $server->getDate()->getIso();

En nommant vos serveurs, vous pourrez en interroger un en particulier comme nous allons le
voir.

2.3. Les protocoles des serveurs de temps


La plupart des serveurs publics de temps utilisent le protocole NTP. Mais d'autres protocoles
existent.

Vous pouvez spécifier le protocole dans l'adresse du serveur de temps. Zend_TimeSync en


supporte deux actuellement. Celui par défaut est NTP. Si vous omettez le protocole dans
l'adresse, c'est NTP qui sera utilisé.

$server = new Zend_TimeSync(array('generic' => 'ntp:\\0.pool.ntp.org',


'fallback' => 'ntp:\\1.pool.ntp.org',
'reserve' => 'ntp:\\2.pool.ntp.org'));
$server->addServer('sntp:\\internal.myserver.com', 'additional');

print $server->getDate()->getIso();

Zend_TimeSync peut donc gérer plusieurs serveurs, et plusieurs protocoles, en même temps.

2.4. Utiliser les ports pour les serveurs de temps


Comme tous les protocoles, NTP et SNTP utilisent des ports par défaut.

Quelque fois il peut être nécessaire de préciser le port à utiliser. Si c'est le cas, rajoutez le
simplement à l'adresse du serveur à utiliser, sinon Zend_TimeSync utilisera celui par défaut.

$server = new Zend_TimeSync(array('generic' => 'ntp:\\0.pool.ntp.org:200',


'fallback' => 'ntp:\\1.pool.ntp.org'));
$server->addServer('sntp:\\internal.myserver.com:399', 'additional');

print $server->getDate()->getIso();

2.5. Options pour les serveurs de temps


Actuellement seule une option est utilisée en interne par Zend_TimeSync. Mais vous pouvez
en utiliser autant que vous voulez.

L'option timeout définit le nombre de secondes au delà duquel la connexion sera considérée
comme cassée. La valeur par défaut est 1, donc Zend_TimeSync changera de serveur si la
réponse du serveur actuellement interrogé met plus d'une seconde à arriver.

Grâce à setOptions(), vous passez un tableau d'options que vous voulez. La clé du
tableau représente le nom de l'option en question et la valeur, sa valeur. Pour voir les options
déjà affectées, utilisez la méthode getOptions(). Elle accepte une clé nommant l'option à
récupérer, ou alors si aucun paramètre ne lui est passé, la méthode retournera toutes les options
connues.

Zend_TimeSync::setOptions(array('timeout' => 3, 'myoption' => 'timesync'));


$server = new Zend_TimeSync(array('generic' => 'ntp:\\0.pool.ntp.org',

1413
Zend_TimeSync

'fallback' => 'ntp:\\1.pool.ntp.org'));


$server->addServer('sntp:\\internal.myserver.com', 'additional');

print $server->getDate()->getIso();
print_r(Zend_TimeSync::getOptions();
print "Timeout = " . Zend_TimeSync::getOptions('timeout');

Comme vous pouvez le noter, les options de Zend_TimeSync sont statiques, ainsi chaque
instance de Zend_TimeSync possèdera les mêmes options.

2.6. Utiliser des serveurs de temps différents


Par défaut la requête utilisera le premier serveur défini, et ainsi de suite. Il peut être nécessaire
parfois, de spécifier un serveur précis que l'on souhaite interroger. Utilisez setServer() et
passez lui le nom du serveur que vous souhaitez interroger prochainement. Pour savoir le
serveur qui va être utilisé, getServer() vous sera utile.

$server = new Zend_TimeSync(array('generic' => 'ntp:\\0.pool.ntp.org',


'fallback' => 'ntp:\\1.pool.ntp.org'));
$server->addServer('sntp:\\internal.myserver.com', 'additional');

$actual = $server->getServer();
$server = $server->setServer('additional');

2.7. Informations sur les serveurs de temps


Les serveurs de temps fournissent certes le temps, mais aussi d'autres informations. Pour
prendre connaissance de ces informations, utilisez la méthode getInfo().

$server = new Zend_TimeSync(array('generic' => 'ntp:\\0.pool.ntp.org',


'fallback' => 'ntp:\\1.pool.ntp.org'));

print_r ($server->getInfo());

Des protocoles et des serveurs différents, retourneront des informations différentes.

2.8. Gérer les exceptions


Les exceptions sont collectées pour tous les serveurs et sont retournées en tant que tableau.
Vous pourrez ainsi itérer sur vos exceptions, voyez plutôt :

$serverlist = array(
// invalid servers
'invalid_a' => 'ntp://a.foo.bar.org',
'invalid_b' => 'sntp://b.foo.bar.org',
);

$server = new Zend_TimeSync($serverlist);

try {
$result = $server->getDate();
echo $result->getIso();
} catch (Zend_TimeSync_Exception $e) {

$exceptions = $e->get();

1414
Zend_TimeSync

foreach ($exceptions as $key => $myException) {


echo $myException->getMessage();
echo '<br />';
}
}

1415
Zend_Tool
1. Using Zend_Tool On The Command Line
The CLI, or command line tool (internally known as the console tool), is currently the primary
interface for dispatching Zend_Tool requests. With the CLI tool, developers can issue tooling
requests inside the "command line window", also commonly known as a "terminal" window. This
environment is predominant in the *nix environment, but also has a common implementation in
windows with the cmd.exe, console2 and also with the Cygwin project.

1.1. Installation
1.1.1. Download And Go

First download Zend Framework. This can be done by going to framework.zend.com and
downloading the latest release. After you've downloaded the package and placed it on your
system. The next step is to make the zf command available to your system. The easiest way to
do this, is to copy the proper files from the bin/ directory of the download, and place these files
within the same directory as the location of the php cli binary.

1.1.2. Installing Via Pear

To install via PEAR, you must use the 3rd party zfcampus.org site to retrieve the latest Zend
Framework PEAR package. These packages are typically built within a day of an official Zend
Framework release. The benefit of installing via the PEAR package manager is that during the
install process, the ZF library will end up on the include_path, and the zf.php and zf scripts will
end up in a place on your system that will allow you to run them without any additional setup.

pear discover-channel pear.zfcampus.org


pear install zfcampus/zf

That is it. After the initial install, you should be able to continue on by running the zf command.
Go good way to check to see if it't there is to run zf --help

1.1.3. Installing by Hand

Installing by hand refers to the process of forcing the zf.php and Zend Framework library to work
together when they are placed in non-convential places, or at least, in a place that your system
cannot dispatch from easily (typical of programs in your system PATH).

If you are on a *nix or mac system, you can also create a link from somewhere in your path to
the zf.sh file. If you do this, you do not need to worry about having Zend Framework's library on
your include_path, as the zf.php and zf.sh files will be able to access the library relative to where
they are (meaning the ./bin/ files are ../library/ relative to the Zend Framework library).

There are a number of other options available for setting up the zf.php and library on your system.
These options revolve around setting specific environment variables. These are described in the
later section on "customizing the CLI environement". The environment variables for setting the
zf.php include_path, ZF_INCLUDE_PATH and ZF_INCLUDE_PATH_PREPEND, are the ones
of most interest.

1416
Zend_Tool

1.2. General Purpose Commands


1.2.1. Version
This will show the current version number of the copy of Zend Framework the zf.php tool is using.

zf show version

1.2.2. Built-in Help


The built-in help system is the primary place where you can get up-to-date information on what
your system is capable of doing. The help system is dynamic in that as providers are added to
your system, they are automatically dispatchable, and as such, the parameters required to run
them will be in the help screen. The easiest way to retrieve the help screen is the following:

zf --help

This will give you an overview of the various capabilities of the system. Sometimes, there are
more finite commands than can be run, and to gain more information about these, you might
have to run a more specialized help command. For specialized help, simply replace any of the
elements of the command with a "?". This will tell the help system that you want more information
about what commands can go in place of the question mark. For example:

zf ? controller

The above means "show me all 'actions' for the provider 'controller'"; while the following:

zf show ?

means "show me all providers that support the 'show' action". This works for drilling down into
options as well as you can see in the following examples:

zf show version.? (show any specialties)


zf show version ? (show any options)

1.2.3. Manifest
This will show what information is in the tooling systems manifest. This is more important for
provider developers than casual users of the tooling system.

zf show manifest

1.3. Project Specific Commands


1.3.1. Project
The project provider is the first command you might want to run. This will setup the basic structure
of your application. This is required before any of the other providers can be executed.

zf create project MyProjectName

This will create a project in a directory called ./MyProjectName. From this point on, it is important
to note that any subsequent commands on the command line must be issued from within the
project directory you had just created. So, after creation, changing into that directory is required.

1417
Zend_Tool

1.3.2. Project
The module provider allows for the easy creation of a Zend Framework module. A module follows
the hMVC pattern loosely. When creating modules, it will take the same structure used at the
application/ level, and duplicate it inside of the chosen name for your module, inside of the
"modules" directory of the application/ directory without duplicating the modules directory itself.
For example:

zf create module Blog

This will create a module named Blog at application/modules/Blog, and all of the artifacts that
a module will need.

1.3.3. Controller
The controller provider is responsible for creating (mostly) empty controllers as well as their
corresponding view script directories and files. To utilize it to create an 'Auth' controlller, for
example, execute:

zf create controller Auth

This will create a controller named Auth, specifically it will create a file at application/controllers/
AuthController.php with the AuthController inside. If you wish to create a controller for a module,
use any of the following:

zf create controller Post 1 Blog


zf create controller Post -m Blog
zf create controller Post --module=Blog

Note: In the first command, 1 is the value for the "includeIndexAction" flag.

1.3.4. Action
To create an action within an existing controller:

zf create action login Auth


zf create action login -c Auth
zf create action login --controller-name=Auth

1.3.5. View
To create a view outside of the normal controller/action creation, you would use one of the
following:

zf create view Auth my-script-name


zf create view -c Auth -a my-script-name

This will create a view script in the controller folder of Auth.

1.3.6. Model
The model provider is only responsible for creating the proper model files, with the proper name
inside the application folder. For example

1418
Zend_Tool

zf create model User

If you wish to create a model within a specific module:

zf create model Post -m Blog

The above will create a 'Post' model inside of the 'Blog' module.

1.3.7. Form
The form provider is only responsible for creating the proper form file and init() method, with the
proper name inside the application folder. For example:

zf create form Auth

If you wish to create a model within a specific module:

zf create form Comment -m Blog

The above will create a 'Comment' form inside of the 'Blog' module.

1.3.8. DbAdapter
To configure a DbAdapter, you will need to provide the information as a url encoded string. This
string needs to be in quotes on the command line.

For example, to enter the following information:

• adapter: Pdo_Mysql

• username: test

• password: test

• dbname: test

The following will have to be run on the command line:

zf configure dbadapter "adapter=Pdo_Mysql&username=test&password=test&dbname=test"

This assumes you wish to store this information inside of the 'production' space of the application
configuration file. The following will demonstrate an sqlite configuration, in the 'development'
section of the application config file.

zf configure dbadapter "adapter=Pdo_Sqlite&dbname=../data/test.db" development


zf configure dbadapter "adapter=Pdo_Sqlite&dbname=../data/test.db" -s development

1.3.9. DbTable
The DbTable provider is responsible for creating Zend_Db_Table model/data access files for
your application to consume, with the proper class name, and in the proper location in the
application. The two important pieces of information are the DbTable name, and the actual
database table name. For example:

1419
Zend_Tool

zf create dbtable User user


zf create dbtable User -a user

// also accepts a force option to overwrite existing files


zf create dbtable User user -f
zf create dbtable User user --force-override

The DbTable provider is also capable of creating the proper files by scanning the database
configured with the above DbAdapter provider.

zf create dbtable.from-database

When executing the above, it might make sense to use the pretend / "-p" flag first so that you
can see what would be done, and what tables can be found in the database.

zf -p create dbtable.from-database

1.3.10. Layout
Currently, the only supported action for layouts is simply to enable them will setup the proper keys
in the application.ini file for the application resource to work, and create the proper directories
and layout.phtml file.

zf enable layout

1.4. Environment Customization


1.4.1. The Storage Directory
The storage directory is important so that providers may have a place to find custom user
generated logic that might change the way they behave. One example can be found below is
the placement of a custom project profile file.

zf --setup storage-directory

1.4.2. The Configuration File


This will create the proper zf.ini file. This should be run after zf --setup storage-
directory. If it is not, it will be located inside the users home directory. If it is, it will be located
inside the users storage directory.

zf --setup config-file

1.4.3. Environment Locations


These should be set if you wish to override the default places where zf will attempt to read their
values.

• ZF_HOME

• the directory this tool will look for a home directory

• directory must exist

1420
Zend_Tool

• search order:

• ZF_HOME environment variable

• HOME environment variable

• then HOMEPATH environment variable

• ZF_STORAGE_DIRECTORY

• where this tool will look for a storage directory

• directory must exist

• search order:

• ZF_STORAGE_DIRECTORY environment variable

• $homeDirectory/.zf/ directory

• ZF_CONFIG_FILE

• where this tool will look for a configuration file

• search order:

• ZF_CONFIG_FILE environment variable

• $homeDirectory/.zf.ini file if it exists

• $storageDirectory/zf.ini file if it exists

• ZF_INCLUDE_PATH

• set the include_path for this tool to use this value

• original behavior:

• use php's include_path to find ZF

• use the ZF_INCLUDE_PATH environment variable

• use the path ../library (relative to zf.php) to find ZF

• ZF_INCLUDE_PATH_PREPEND

• prepend the current php.ini include_path with this value

2. Extending Zend_Tool
2.1. Overview of Zend_Tool
Zend_Tool_Framework is a framework for exposing common functionalities such as the
creation of project scaffolds, code generation, search index generation, and much more.
Functionality may be written and exposed via PHP classes dropped into the PHP include_path,
providing incredible flexibility of implementation. The functionality may then be consumed by

1421
Zend_Tool

writing implementation and/or protocol-specific clients -- such as console clients, XML-RPC,


SOAP, and much more.

Zend_Tool_Project builds on and extends the capabilities of Zend_Tool_Framework to


that of managing a "project". In general, a "project" is a planned endeavor or an initiative. In the
computer world, projects generally are a collection of resources. These resources can be files,
directories, databases, schemas, images, styles, and more.

2.2. Zend_Tool_Framework Extensions


2.2.1. Overall Architecture
Zend_Tool_Framework provides the following:

• Common interfaces and abstracts that allow developers to create functionality and capabilities
that are dispatchable by tooling clients.

• Base client functionality and a concrete console implementation that connect external tools
and interfaces to the Zend_Tool_Framework. The Console client may be used in CLI
environments such as unix shells and the Windows console.

• "Provider" and "Manifest" interfaces that can be utilized by the tooling system. "Providers"
represent the functional aspect of the framework, and define the actions that tooling clients
may call. "Manifests" act as metadata registries that provide additional context for the various
defined providers.

• An introspective loading system that will scan the environment for providers and determine
what is required to dispatch them.

• A standard set of system providers that allow the system to report what the full capabilities
of the system are as well as provide useful feedback. This also includes a comprehensive
"Help System".

Definitions that you should be aware of through this manual with respect to
Zend_Tool_Framework include:

• Zend_Tool_Framework - The framework which exposes tooling capabilities.

• Tooling Client - A developer tool that connects to and consumes Zend_Tool_Framework.

• Client - The subsystem of Zend_Tool_Framework that exposes an interface such that tooling
clients can connect, query and execute commands.

• Console Client / Command Line Interface / zf.php - The tooling client for the command line.

• Provider - A subsystem and a collection of built-in functionality that the framework exports.

• Manifest - A subsystem for defining, organizing, and disseminating provider requirement data.

• Zend_Tool_Project Provider - A set of providers specifically for creating and maintaining


Zend Framework-based projects.

2.2.2. Understanding the CLI Client


The CLI, or command line tool (internally known as the console tool), is currently the primary
interface for dispatching Zend_Tool requests. With the CLI tool, developers can issue tooling

1422
Zend_Tool

requests inside the "command line windows", also commonly known as a "terminal" window. This
environment is predominant in the *nix environment, but also has a common implementation in
windows with the cmd.exe, console2 and also with the Cygwin project.

2.2.2.1. Setting up the CLI tool

To issue tooling requests via the command line client, you first need to set up the client so that
your system can handle the "zf" command. The command line client, for all intents and purposes,
is the .sh or .bat file that is provided with your Zend Framework distribution. In trunk, it can be
found here: http://framework.zend.com/svn/framework/standard/trunk/bin/.

As you can see, there are 3 files in the /bin/ directory: a zf.php, zf.sh, and zf.bat. The
zf.sh and the zf.bat are the operating system specific client wrappers: zf.sh for the *nix
environment, and zf.bat for the Win32 environment. These client wrappers are responsible
for finding the proper php.exe, finding the zf.php, and passing on the client request. The
zf.php is the responsible for handling understanding your environment, constructing the proper
include_path, and passing what is provided on the command line to the proper library component
for dispatching.

Ultimately, you want to ensure two things to make everything work regardless of the operating
system you are on:

1. zf.sh/zf.bat is reachable from your system path. This is the ability to call zf from anywhere
on your command line, regardless of what your current working directory is.

2. ZendFramework/library is in your include_path.

Note: while the above are the most ideal requirements, you can simply download
Zend Framework and expect it to work as ./path/to/zf.php some command.

2.2.2.2. Setting up the CLI tool on Unix-like Systems

The most common setup in the *nix environment, is to copy the zf.sh and zf.php into the
same directory as your PHP binary. This can generally be found in one of the following places:

/usr/bin
/usr/local/bin
/usr/local/ZendServer/bin/
/Applications/ZendServer/bin/

To find out the location of your PHP binary, you can execute 'which php' on the command
line. This will return the location of the PHP binary you will be using to run PHP scripts in this
environment.

The next order of business is to ensure that Zend Framework library is set up correctly inside
of the system PHP include_path. To find out where your include_path is located, you can
execute php -i and look for the include_path variable, or more succinctly, execute php -i |
grep include_path. Once you have found where your include_path is located (this will generally
be something like /usr/lib/php, /usr/share/php, /usr/local/lib/php, or similar),
ensure that the contents of the /library/ directory are put inside your include_path specified
directory.

Once you have done those two things, you should be able to issue a command and get back
the proper response like this:

1423
Zend_Tool

If you do not see this type of output, go back and check your setup to ensure you have all of the
necessary pieces in the proper place.

There are a couple of alternative setups you might want to employ depending on your servers
configuration, your level of access, or for other reasons.

Alternative Setup involves keeping the Zend Framework download together as is, and creating
a link from a PATH location to the zf.sh. What this means is you can place the contents of
the ZendFramework download into a location such as /usr/local/share/ZendFramework,
or more locally like /home/username/lib/ZendFramework, and creating a symbolic link to
the zf.sh.

Assuming you want to put the link inside /usr/local/bin (this could also work for placing the
link inside /home/username/bin/ for example) you would issue a command similar to this:

ln -s /usr/local/share/ZendFramework/bin/zf.sh /usr/local/bin/zf

# OR (for example)
ln -s /home/username/lib/ZendFramework/bin/zf.sh /home/username/bin/zf

This will create a link which you should be able to access globally on the command line.

2.2.2.3. Setting up the CLI tool on Windows

The most common setup in the Windows Win32 environment, is to copy the zf.bat and zf.php
into the same directory as your PHP binary. This can generally be found in one of the following
places:

1424
Zend_Tool

C:\PHP
C:\Program Files\ZendServer\bin\
C:\WAMP\PHP\bin

You should be able to run php.exe on the command line. If you are not able to, first check the
documentation that came with your PHP distribution, or ensure that the path to php.exe is in
your Windows PATH environment variable.

The next order of business is to ensure that Zend Framework library is set up correctly inside of
the system PHP include_path. To find out where your include_path is located, you can type php
-i and look for the include_path variable, or more succinctly execute php -i | grep include_path
if you have Cygwin setup with grep available. Once you have found where your include_path
is located (this will generally be something like C:\PHP\pear, C:\PHP\share, C:\Program
%20Files\ZendServer\share or similar), ensure that the contents of the library/ directory
are put inside your include_path specified directory.

Once you have done those two things, you should be able to issue a command and get back
the proper response like this:

If you do not see this type of output, go back and check your setup to ensure you have all of the
necessary pieces in the proper place.

There are a couple of alternative setups you might want to employ depending on your server's
configuration, your level of access, or for other reasons.

1425
Zend_Tool

Alternative Setup involves keeping the Zend Framework download together as is, and altering
both your system PATH as well as the php.ini file. In your user's environment, make sure to
add C:\Path\To\ZendFramework\bin, so that your zf.bat file is executable. Also, alter the
php.ini file to ensure that C:\Path\To\ZendFramework\library is in your include_path.

2.2.2.4. Other Setup Considerations

If for some reason you do not want Zend Framework library inside your include_path, there is
another option. There are two special environment variables that zf.php will utilize to determine
the location of your Zend Framework installation.

The first is ZEND_TOOL_INCLUDE_PATH_PREPEND, which will prepend the value of this


environment variable to the system (php.ini) include_path before loading the client.

Alternatively, you might want to use ZEND_TOOL_INCLUDE_PATH to completely replace the


system include_path for one that makes sense specifically for the zf command line tool.

2.2.3. Creating Providers

In general, a provider, on its own, is nothing more than the shell for a developer to bundle up
some capabilities they wish to dispatch with the command line (or other) clients. It is an analogue
to what a "controller" is inside of your MVC application.

2.2.3.1. How Zend Tool finds your Providers

By default Zend Tool uses the BasicLoader to find all the providers that you
can run. It recursivly iterates all include path directories and opens all files
that end with "Manifest.php" or "Provider.php". All classes in these files are
inspected if they implement either Zend_Tool_Framework_Provider_Interface or
Zend_Tool_Framework_Manifest_ProviderManifestable. Instances of the provider
interface make up for the real functionality and all their public methods are accessible as provider
actions. The ProviderManifestable interface however requires the implementation of a method
getProviders() which returns an array of instantiated provider interface instances.

The following naming rules apply on how you can access the providers that were found by the
IncludePathLoader:

• The last part of your classname split by underscore is used for the provider name, e.g.
"My_Provider_Hello" leads to your provider being accessible by the name "hello".

• If your provider has a method getName() it will be used instead of the previous method to
determine the name.

• If your provider has "Provider" as prefix, e.g. it is called My_HelloProvider it will be stripped
from the name so that the provider will be called "hello".

The IncludePathLoader does not follow symlinks, that means you cannot link
provider functionality into your include paths, they have to be physically present
in the include paths.

1426
Zend_Tool

Exemple 876. Exposing Your Providers with a Manifest

You can expose your providers to Zend Tool by offering a manifest with
a special filename ending with "Manifest.php". A Provider Manifest is an
implementation of the Zend_Tool_Framework_Manifest_ProviderManifestable and requires
the getProviders() method to return an array of instantiated providers. In anticipation
of our first own provider My_Component_HelloProvider we will create the following
manifest:

class My_Component_Manifest
implements Zend_Tool_Framework_Manifest_ProviderManifestable
{
public function getProviders()
{
return array(
new My_Component_HelloProvider()
);
}
}

2.2.3.2. Basic Instructions for Creating Providers

As an example, if a developer wants to add the capability of showing the version of a datafile that
his 3rd party component is working from, there is only one class the developer would need to
implement. Assuming the component is called My_Component, he would create a class named
My_Component_HelloProvider in a file named HelloProvider.php somewhere on the
include_path. This class would implement Zend_Tool_Framework_Provider_Interface,
and the body of this file would only have to look like the following:

class My_Component_HelloProvider
implements Zend_Tool_Framework_Provider_Interface
{
public function say()
{
echo 'Hello from my provider!';
}
}

Given that code above, and assuming the developer wishes to access this functionality through
the console client, the call would look like this:

% zf say hello
Hello from my provider!

2.2.3.3. The response object

As discussed in the architecture section Zend Tool allows to hook different clients for using your
Zend Tool providers. To keep compliant with different clients you should use the response object
to return messages from your providers instead of using echo() or a similiar output mechanism.
Rewritting our hello provider with this knowledge it looks like:

class My_Component_HelloProvider
extends Zend_Tool_Framework_Provider_Abstract
{
public function say()

1427
Zend_Tool

{
$this->_registry->getResponse
->appendContent("Hello from my provider!");
}
}

As you can see one has to extend the Zend_Tool_Framework_Provider_Abstract to gain


access to the Registry which holds the Zend_Tool_Framework_Client_Response instance.

2.2.3.4. Advanced Development Information

2.2.3.4.1. Passing Variables to a Provider

The above "Hello World" example is great for simple commands, but what about something more
advanced? As your scripting and tooling needs grow, you might find that you need the ability
to accept variables. Much like function signatures have parameters, your tooling requests can
also accept parameters.

Just as each tooling request can be isolated to a method within a class, the parameters of a
tooling request can also be isolated in a very well known place. Parameters of the action methods
of a provider can include the same parameters you want your client to utilize when calling that
provider and action combination. For example, if you wanted to accept a name in the above
example, you would probably do this in OO code:

class My_Component_HelloProvider
implements Zend_Tool_Framework_Provider_Interface
{
public function say($name = 'Ralph')
{
echo 'Hello' . $name . ', from my provider!';
}
}

The above example can then be called via the command line zf say hello Joe. "Joe" will be
supplied to the provider as a parameter of the method call. Also note, as you see that the
parameter is optional, that means it is also optional on the command line, so that zf say hello
will still work, and default to the name "Ralph".

2.2.3.4.2. Prompt the User for Input

There are cases when the workflow of your provider requires to prompt the user for input. This
can be done by requesting the client to ask for more the required input by calling:

class My_Component_HelloProvider
extends Zend_Tool_Framework_Provider_Abstract
{
public function say($name = 'Ralph')
{
$nameResponse = $this->_registry
->getClient()
->promptInteractiveInput("Whats your name?");
$name = $name->getContent();

echo 'Hello' . $name . ', from my provider!';


}
}

1428
Zend_Tool

This command throws an exception if the current client is not able to handle interactive requests.
In case of the default Console Client however you will be asked to enter the name.

2.2.3.4.3. Pretending to execute a Provider Action

Another interesting feature you might wish to implement is pretendability. Pretendabilty is the
ability for your provider to "pretend" as if it is doing the requested action and provider combination
and give the user as much information about what it would do without actually doing it. This
might be an important notion when doing heavy database or filesystem modifications that the
user might not otherwise want to do.

Pretendability is easy to implement. There are two parts to this feature: 1) marking the provider
as having the ability to "pretend", and 2) checking the request to ensure the current request was
indeed asked to be "pretended". This feature is demonstrated in the code sample below.

class My_Component_HelloProvider
extends Zend_Tool_Framework_Provider_Abstract
implements Zend_Tool_Framework_Provider_Pretendable
{
public function say($name = 'Ralph')
{
if ($this->_registry->getRequest()->isPretend()) {
echo 'I would say hello to ' . $name . '.';
} else {
echo 'Hello' . $name . ', from my provider!';
}
}
}

To run the provider in pretend mode just call:

% zf --pretend say hello Ralph


I would say hello Ralph.

2.2.3.4.4. Verbose and Debug modes

You can also run your provider actions in "verbose" or "debug" modes. The semantics in regard
to this actions have to be implemented by you in the context of your provider. You can access
debug or verbose modes with:

class My_Component_HelloProvider
implements Zend_Tool_Framework_Provider_Interface
{
public function say($name = 'Ralph')
{
if($this->_registry->getRequest()->isVerbose()) {
echo "Hello::say has been called\n";
}
if($this->_registry->getRequest()->isDebug()) {
syslog(LOG_INFO, "Hello::say has been called\n");
}
}
}

2.2.3.4.5. Accessing User Config and Storage

Using the Enviroment variable ZF_CONFIG_FILE or the .zf.ini in your home directory
you can inject configuration parameters into any Zend Tool provider. Access to this

1429
Zend_Tool

configuration is available via the registry that is passed to your provider if you extend
Zend_Tool_Framework_Provider_Abstract.

class My_Component_HelloProvider
extends Zend_Tool_Framework_Provider_Abstract
{
public function say()
{
$username = $this->_registry->getConfig()->username;
if(!empty($username)) {
echo "Hello $username!";
} else {
echo "Hello!";
}
}
}

The returned configuration is of the type Zend_Tool_Framework_Client_Config but


internally the __get() and __set() magic methods proxy to a Zend_Config of the given
configuration type.

The storage allows to save arbitrary data for later reference. This can be useful for batch
processing tasks or for re-runs of your tasks. You can access the storage in a similar way like
the configuration:

class My_Component_HelloProvider
extends Zend_Tool_Framework_Provider_Abstract
{
public function say()
{
$aValue = $this->_registry->getStorage()->get("myUsername");
echo "Hello $aValue!";
}
}

The API of the storage is very simple:

class Zend_Tool_Framework_Client_Storage
{
public function setAdapter($adapter);
public function isEnabled();
public function put($name, $value);
public function get($name, $defaultValue=null);
public function has($name);
public function remove($name);
public function getStreamUri($name);
}

When designing your providers that are config or storage aware remember to
check if the required user-config or storage keys really exist for a user. You won't
run into fatal errors when none of these are provided though, since empty ones
are created upon request.

2.3. Zend_Tool_Project Extensions


Zend_Tool_Project exposes a rich set of functionality and capabilities that make the task of
creating new providers, specficially those targetting project easier and more manageable.

1430
Zend_Tool

2.3.1. Overall Architecture


This same concept applies to Zend Framework projects. In Zend Framework projects, you have
controllers, actions, views, models, databases and so on and so forth. In terms of Zend_Tool,
we need a way to track these types of resources - thus Zend_Tool_Project.

Zend_Tool_Project is capable of tracking project resources throughout the development of


a project. So, for example, if in one command you created a controller, and in the next command
you wish to create an action within that controller, Zend_Tool_Project is gonna have to know
about the controller file you created so that you can (in the next action), be able to append that
action to it. This is what keeps our projects up to date and stateful.

Another important point to understand about projects is that typically, resources are organized
in a hierarchical fashion. With that in mind, Zend_Tool_Project is capable of serializing the
current project into a internal representation that allows it to keep track of not only what resources
are part of a project at any given time, but also where they are in relation to one another.

2.3.2. Creating Providers


Project specific providers are created in the same fashion as plain framework providers, with one
exception: project providers must extend the Zend_Tool_Project_Provider_Abstract.
This class comes with some significant functionality that helps developers load existing project,
obtian the profile object, and be able to search the profile, then later store any changes to the
current project profile.

class My_Component_HelloProvider
extends Zend_Tool_Project_Provider_Abstract
{
public function say()
{
$profile = $this->_loadExistingProfile();

/* ... do project stuff here */

$this->_storeProfile();
}
}

1431
Zend_Tool_Framework
1. Introduction
Zend_Tool_Framework is a framework for exposing common functionalities such as the
creation of project scaffolds, code generation, search index generation, and much more.
Functionality may be written and exposed via PHP classes dropped into the PHP include_path,
providing incredible flexibility of implementation. The functionality may then be consumed by
writing implementation and/or protocol-specific clients -- such as console clients, XML-RPC,
SOAP, and much more.

Zend_Tool_Framework provides the following:

• Common interfaces and abstracts that allow developers to create functionality and capabilities
that are dispatchable by tooling clients.

• Base client functionality and a concrete console implementation that connect external tools
and interfaces to the Zend_Tool_Framework. The Console client may be used in CLI
environments such as unix shells and the Windows console.

• "Provider" and "Manifest" interfaces that can be utilized by the tooling system. "Providers"
represent the functional aspect of the framework, and define the actions that tooling clients
may call. "Manifests" act as metadata registries that provide additional context for the various
defined providers.

• An introspective loading system that will scan the environment for providers and determine
what is required to dispatch them.

• A standard set of system providers that allow the system to report what the full capabilities
of the system are as well as provide useful feedback. This also includes a comprehensive
"Help System".

Definitions that you should be aware of through this manual with respect to
Zend_Tool_Framework include:

• Zend_Tool_Framework - The framework which exposes tooling capabilities.

• Tooling Client - A developer tool that connects to and consumes Zend_Tool_Framework.

• Client - The subsystem of Zend_Tool_Framework that exposes an interface such that tooling
clients can connect, query and execute commands.

• Console Client / Command Line Interface / zf.php - The tooling client for the command line.

• Provider - A subsystem and a collection of built-in functionality that the framework exports.

• Manifest - A subsystem for defining, organizing, and disseminating provider requirement data.

• Zend_Tool_Project Provider - A set of providers specifically for creating and maintaining


Zend Framework-based projects.

2. Using the CLI Tool


The CLI, or command line tool (internally known as the console tool), is currently the primary
interface for dispatching Zend_Tool requests. With the CLI tool, developers can issue tooling

1432
Zend_Tool_Framework

requests inside the "command line windows", also commonly known as a "terminal" window. This
environment is predominant in the *nix environment, but also has a common implementation in
windows with the cmd.exe, console2 and also with the Cygwin project.

2.1. Setting up the CLI tool


To issue tooling requests via the command line client, you first need to set up the client so that
your system can handle the "zf" command. The command line client, for all intents and purposes,
is the .sh or .bat file that is provided with your Zend Framework distribution. In trunk, it can be
found here: http://framework.zend.com/svn/framework/standard/trunk/bin/.

As you can see, there are 3 files in the /bin/ directory: a zf.php, zf.sh, and zf.bat. The
zf.sh and the zf.bat are the operating system specific client wrappers: zf.sh for the *nix
environment, and zf.bat for the Win32 environment. These client wrappers are responsible
for finding the proper php.exe, finding the zf.php, and passing on the client request. The
zf.php is the responsible for handling understanding your environment, constructing the proper
include_path, and passing what is provided on the command line to the proper library component
for dispatching.

Ultimately, you want to ensure two things to make everything work regardless of the operating
system you are on:

1. zf.sh/zf.bat is reachable from your system path. This is the ability to call zf from anywhere
on your command line, regardless of what your current working directory is.

2. ZendFramework/library is in your include_path.

Note: while the above are the most ideal requirements, you can simply download
Zend Framework and expect it to work as ./path/to/zf.php some command.

2.2. Setting up the CLI tool on Unix-like Systems


The most common setup in the *nix environment, is to copy the zf.sh and zf.php into the
same directory as your PHP binary. This can generally be found in one of the following places:

/usr/bin
/usr/local/bin
/usr/local/ZendServer/bin/
/Applications/ZendServer/bin/

To find out the location of your PHP binary, you can execute 'which php' on the command
line. This will return the location of the PHP binary you will be using to run PHP scripts in this
environment.

The next order of business is to ensure that Zend Framework library is set up correctly inside
of the system PHP include_path. To find out where your include_path is located, you can
execute php -i and look for the include_path variable, or more succinctly, execute php -i |
grep include_path. Once you have found where your include_path is located (this will generally
be something like /usr/lib/php, /usr/share/php, /usr/local/lib/php, or similar),
ensure that the contents of the /library/ directory are put inside your include_path specified
directory.

Once you have done those two things, you should be able to issue a command and get back
the proper response like this:

1433
Zend_Tool_Framework

If you do not see this type of output, go back and check your setup to ensure you have all of the
necessary pieces in the proper place.

There are a couple of alternative setups you might want to employ depending on your servers
configuration, your level of access, or for other reasons.

Alternative Setup involves keeping the Zend Framework download together as is, and creating
a link from a PATH location to the zf.sh. What this means is you can place the contents of
the ZendFramework download into a location such as /usr/local/share/ZendFramework,
or more locally like /home/username/lib/ZendFramework, and creating a symbolic link to
the zf.sh.

Assuming you want to put the link inside /usr/local/bin (this could also work for placing the
link inside /home/username/bin/ for example) you would issue a command similar to this:

ln -s /usr/local/share/ZendFramework/bin/zf.sh /usr/local/bin/zf

# OR (for example)
ln -s /home/username/lib/ZendFramework/bin/zf.sh /home/username/bin/zf

This will create a link which you should be able to access globally on the command line.

1434
Zend_Tool_Framework

2.3. Setting up the CLI tool on Windows


The most common setup in the Windows Win32 environment, is to copy the zf.bat and zf.php
into the same directory as your PHP binary. This can generally be found in one of the following
places:

C:\PHP
C:\Program Files\ZendServer\bin\
C:\WAMP\PHP\bin

You should be able to run php.exe on the command line. If you are not able to, first check the
documentation that came with your PHP distribution, or ensure that the path to php.exe is in
your Windows PATH environment variable.

The next order of business is to ensure that Zend Framework library is set up correctly inside of
the system PHP include_path. To find out where your include_path is located, you can type php
-i and look for the include_path variable, or more succinctly execute php -i | grep include_path
if you have Cygwin setup with grep available. Once you have found where your include_path
is located (this will generally be something like C:\PHP\pear, C:\PHP\share, C:\Program
%20Files\ZendServer\share or similar), ensure that the contents of the library/ directory
are put inside your include_path specified directory.

Once you have done those two things, you should be able to issue a command and get back
the proper response like this:

1435
Zend_Tool_Framework

If you do not see this type of output, go back and check your setup to ensure you have all of the
necessary pieces in the proper place.

There are a couple of alternative setups you might want to employ depending on your server's
configuration, your level of access, or for other reasons.

Alternative Setup involves keeping the Zend Framework download together as is, and altering
both your system PATH as well as the php.ini file. In your user's environment, make sure to
add C:\Path\To\ZendFramework\bin, so that your zf.bat file is executable. Also, alter the
php.ini file to ensure that C:\Path\To\ZendFramework\library is in your include_path.

2.4. Other Setup Considerations


If for some reason you do not want Zend Framework library inside your include_path, there is
another option. There are two special environment variables that zf.php will utilize to determine
the location of your Zend Framework installation.

The first is ZEND_TOOL_INCLUDE_PATH_PREPEND, which will prepend the value of this


environment variable to the system (php.ini) include_path before loading the client.

Alternatively, you might want to use ZEND_TOOL_INCLUDE_PATH to completely replace the


system include_path for one that makes sense specifically for the zf command line tool.

2.5. Where To Go Next?


At this point, you should be set up to start initiating some more "interesting" commands. To get
going, you can issue the zf --help command to see what is available to you.

1436
Zend_Tool_Framework

Continue on to the Zend_Tool_Project "Create Project" section to understand how to use


the zf script for project creation.

3. Architecture
3.1. Registry
Because providers and manifests may come from anywhere in the include_path, a registry is
provided to simplify access to the various pieces of the toolchain. This registry is injected into
registry-aware components, which may then pull dependencies from them as necessary. Most
dependencies registered with the registry will be sub-component-specific repositories.

1437
Zend_Tool_Framework

The interface for the registry consists of the following definition:

interface Zend_Tool_Framework_Registry_Interface
{
public function setClient(Zend_Tool_Framework_Client_Abstract $client);
public function getClient();
public function setLoader(Zend_Tool_Framework_Loader_Abstract $loader);
public function getLoader();
public function setActionRepository(
Zend_Tool_Framework_Action_Repository $actionRepository
);
public function getActionRepository();
public function setProviderRepository(
Zend_Tool_Framework_Provider_Repository $providerRepository
);
public function getProviderRepository();
public function setManifestRepository(
Zend_Tool_Framework_Manifest_Repository $manifestRepository
);
public function getManifestRepository();
public function setRequest(Zend_Tool_Framework_Client_Request $request);
public function getRequest();
public function setResponse(Zend_Tool_Framework_Client_Response $response);
public function getResponse();
}

The various objects the registry manages will be discussed in their appropriate sections.

Classes that should be registry-aware should implement


Zend_Tool_Framework_Registry_EnabledInterface. This interface merely allows
initialization of the registry in the target class.

interface Zend_Tool_Framework_Registry_EnabledInterface
{
public function setRegistry(
Zend_Tool_Framework_Registry_Interface $registry
);
}

3.2. Providers
Zend_Tool_Framework_Provider represents the functional or "capability" aspect of the
framework. Fundamentally, Zend_Tool_Framework_Provider will provide the interfaces
necessary to produce "providers", or bits of tooling functionality that can be called and used inside
the Zend_Tool_Framework toolchain. The simplistic nature of implementing this provider
interface allows the developer a "one-stop-shop" of adding functionality or capabilities to
Zend_Tool_Framework.

The provider interface is an empty interface and enforces no methods (this is the Marker Interface
pattern):

interface Zend_Tool_Framework_Provider_Interface
{}

Or, if you wish, you can implement the base (or abstract) Provider which will give you access to
the Zend_Tool_Framework_Registry:

1438
Zend_Tool_Framework

abstract class Zend_Tool_Framework_Provider_Abstract


implements Zend_Tool_Framework_Provider_Interface,
Zend_Tool_Registry_EnabledInterface
{
protected $_registry;
public function setRegistry(
Zend_Tool_Framework_Registry_Interface $registry
);
}

3.3. Loaders
The purpose of a Loader is to find Providers and Manifest files that contain
classes which implement either Zend_Tool_Framework_Provider_Interface or
Zend_Tool_Framework_Manifest_Interface. Once these files are found by a loader,
providers are loaded into the Provider Repository and manifest metadata is loaded into the
Manifest Repository.

To implement a loader, one must extend the following abstract class:

abstract class Zend_Tool_Framework_Loader_Abstract


{

abstract protected function _getFiles();

public function load()


{
/** ... */
}
}

The _getFiles() method should return an array of files (absolute paths). The built-in
loader supplied with Zend Framework is called the IncludePath loader. By default, the Tooling
framework will use an include_path based loader to find files that might include Providers or
Manifest Metadata objects. Zend_Tool_Framework_Loader_IncludePathLoader, without
any other options, will search for files inside the include path that end in Mainfest.php,
Tool.php or Provider.php. Once found, they will be tested (by the load() method of
the Zend_Tool_Framework_Loader_Abstract) to determine if they implement any of the
supported interfaces. If they do, an instance of the found class is instantiated, and it is appended
to the proper repository.

class Zend_Tool_Framework_Loader_IncludePathLoader
extends Zend_Tool_Framework_Loader_Abstract
{

protected $_filterDenyDirectoryPattern = '.*(/|\\\\).svn';


protected $_filterAcceptFilePattern = '.*(?:Manifest|Provider)\.php$';

protected function _getFiles()


{
/** ... */
}
}

As you can see, the IncludePath loader will search all include_paths for the files that match the
$_filterAcceptFilePattern and not match the $_filterDenyDirectoryPattern.

1439
Zend_Tool_Framework

3.4. Manifests
In short, the Manifest shall contain specific or arbitrary metadata that is useful to any provider or
client, as well as be responsible for loading any additional providers into the provider repository.

To introduce metadata into the manifest repository, all one must do is


implement the empty Zend_Tool_Framework_Manifest_Interface, and provide a
getMetadata() method which shall return an array of objects that implement
Zend_Tool_Framework_Manifest_Metadata.

interface Zend_Tool_Framework_Manifest_Interface
{
public function getMetadata();
}

Metadata objects are loaded (by a loader defined below) into the Manifest Repository
(Zend_Tool_Framework_Manifest_Repository). Manifests will be processed after all
Providers have been found to be loaded into the provider repository. This shall allow Manifests
to create Metadata objects based on what is currently inside the provider repository.

There are a few different metadata classes that can be used to describe metadata. The
Zend_Tool_Framework_Manifest_Metadata is the base metadata object. As you can see
by the following code snippet, the base metadata class is fairly lightweight and abstract in nature:

class Zend_Tool_Framework_Metadata_Basic
{

protected $_type = 'Global';


protected $_name = null;
protected $_value = null;
protected $_reference = null;

public function getType();


public function getName();
public function getValue();
public function getReference();
/** ... */
}

There are other built in metadata classes as well for describing more specialized metadata:
ActionMetadata and ProviderMetadata. These classes will help you describe in more
detail metadata that is specific to either actions or providers, and the reference is expected to be
a reference to an action or a provider respectively. These classes are described in the following
code snippet.

class Zend_Tool_Framework_Manifest_ActionMetadata
extends Zend_Tool_Framework_Manifest_Metadata
{

protected $_type = 'Action';


protected $_actionName = null;

public function getActionName();


/** ... */
}

1440
Zend_Tool_Framework

class Zend_Tool_Framework_Manifest_ProviderMetadata
extends Zend_Tool_Framework_Manifest_Metadata
{

protected $_type = 'Provider';


protected $_providerName = null;
protected $_actionName = null;
protected $_specialtyName = null;

public function getProviderName();


public function getActionName();
public function getSpecialtyName();
/** ... */
}

'Type' in these classes is used to describe the type of metadata the object is responsible for. In
the cases of the ActionMetadata, the type would be 'Action', and conversely in the case of the
ProviderMetadata the type is 'Provider'. These metadata types will also include additional
structured information about both the "thing" they are describing as well as the object (the
getReference()) they are referencing with this new metadata.

In order to create your own metadata type, all one must do is extend the base
Zend_Tool_Framework_Manifest_Metadata class and return these new metadata objects
via a local Manifest class or object. These user based classes will live in the Manifest Repository

Once these metadata objects are in the repository, there are then two different methods that can
be used in order to search for them in the repository.

class Zend_Tool_Framework_Manifest_Repository
{
/**
* To use this method to search, $searchProperties should contain the names
* and values of the key/value pairs you would like to match within the
* manifest.
*
* For Example:
* $manifestRepository->findMetadatas(array(
* 'action' => 'Foo',
* 'name' => 'cliActionName'
* ));
*
* Will find any metadata objects that have a key with name 'action' value
* of 'Foo', AND a key named 'name' value of 'cliActionName'
*
* Note: to either exclude or include name/value pairs that exist in the
* search criteria but do not appear in the object, pass a bool value to
* $includeNonExistentProperties
*/
public function findMetadatas(Array $searchProperties = array(),
$includeNonExistentProperties = true);

/**
* The following will return exactly one of the matching search criteria,
* regardless of how many have been returned. First one in the manifest is
* what will be returned.
*/
public function findMetadata(Array $searchProperties = array(),
$includeNonExistentProperties = true)
{

1441
Zend_Tool_Framework

$metadatas = $this->getMetadatas($searchProperties,
$includeNonExistentProperties);
return array_shift($metadatas);
}
}

Looking at the search methods above, the signatures allow for extremely flexible searching. In
order to find a metadata object, simply pass in an array of matching constraints via an array. If the
data is accessible through the Property accessor (the getSomething() methods implemented
on the metadata object), then it will be passed back to the user as a "found" metadata object.

3.5. Clients
Clients are the interface which bridges a user or external tool into the Zend_Tool_Framework
system. Clients can come in all shapes and sizes: RPC endpoints, Command Line Interface, or
even a web interface. Zend_Tool has implemented the command line interface as the default
interface for interacting with the Zend_Tool_Framework system.

To implement a client, one would need to extend the following abstract class:

abstract class Zend_Tool_Framework_Client_Abstract


{
/**
* This method should be implemented by the client implementation to
* construct and set custom loaders, request and response objects.
*
* (not required, but suggested)
*/
protected function _preInit();

/**
* This method should be implemented by the client implementation to parse
* out and set up the request objects action, provider and parameter
* information.
*/
abstract protected function _preDispatch();

/**
* This method should be implemented by the client implementation to take
* the output of the response object and return it (in an client specific
* way) back to the Tooling Client.
*
* (not required, but suggested)
*/
abstract protected function _postDispatch();
}

As you can see, there 1 method is required to fulfill the needs of a client (two others suggested),
the initialization, prehandling and post handling. For a more in depth study of how the command
line client works, please see the source code.

4. Creating Providers to use with Zend_Tool_Framework


In general, a provider, on its own, is nothing more than the shell for a developer to bundle up
some capabilities they wish to dispatch with the command line (or other) clients. It is an analogue
to what a "controller" is inside of your MVC application.

1442
Zend_Tool_Framework

4.1. How Zend Tool finds your Providers


By default Zend Tool uses the IncludePathLoader to find all the providers that
you can run. It recursivly iterates all include path directories and opens all
files that end with "Manifest.php" or "Provider.php". All classes in these files are
inspected if they implement either Zend_Tool_Framework_Provider_Interface or
Zend_Tool_Framework_Manifest_ProviderManifestable. Instances of the provider
interface make up for the real functionality and all their public methods are accessible as provider
actions. The ProviderManifestable interface however requires the implementation of a method
getProviders() which returns an array of instantiated provider interface instances.

The following naming rules apply on how you can access the providers that were found by the
IncludePathLoader:

• The last part of your classname split by underscore is used for the provider name, e.g.
"My_Provider_Hello" leads to your provider being accessible by the name "hello".

• If your provider has a method getName() it will be used instead of the previous method to
determine the name.

• If your provider has "Provider" as prefix, e.g. it is called My_HelloProvider it will be stripped
from the name so that the provider will be called "hello".

The IncludePathLoader does not follow symlinks, that means you cannot link
provider functionality into your include paths, they have to be physically present
in the include paths.

Exemple 877. Exposing Your Providers with a Manifest

You can expose your providers to Zend Tool by offering a manifest with
a special filename ending with "Manifest.php". A Provider Manifest is an
implementation of the Zend_Tool_Framework_Manifest_ProviderManifestable and requires
the getProviders() method to return an array of instantiated providers. In anticipation
of our first own provider My_Component_HelloProvider we will create the following
manifest:

class My_Component_Manifest
implements Zend_Tool_Framework_Manifest_ProviderManifestable
{
public function getProviders()
{
return array(
new My_Component_HelloProvider()
);
}
}

4.2. Basic Instructions for Creating Providers


As an example, if a developer wants to add the capability of showing the version of a datafile that
his 3rd party component is working from, there is only one class the developer would need to
implement. Assuming the component is called My_Component, he would create a class named
My_Component_HelloProvider in a file named HelloProvider.php somewhere on the
include_path. This class would implement Zend_Tool_Framework_Provider_Interface,
and the body of this file would only have to look like the following:

1443
Zend_Tool_Framework

class My_Component_HelloProvider
implements Zend_Tool_Framework_Provider_Interface
{
public function say()
{
echo 'Hello from my provider!';
}
}

Given that code above, and assuming the developer wishes to access this functionality through
the console client, the call would look like this:

% zf say hello
Hello from my provider!

4.3. The response object


As discussed in the architecture section Zend Tool allows to hook different clients for using your
Zend Tool providers. To keep compliant with different clients you should use the response object
to return messages from your providers instead of using echo() or a similiar output mechanism.
Rewritting our hello provider with this knowledge it looks like:

class My_Component_HelloProvider
extends Zend_Tool_Framework_Provider_Abstract
{
public function say()
{
$this->_registry->getResponse
->appendContent("Hello from my provider!");
}
}

As you can see one has to extend the Zend_Tool_Framework_Provider_Abstract to gain


access to the Registry which holds the Zend_Tool_Framework_Client_Response instance.

4.4. Advanced Development Information


4.4.1. Passing Variables to a Provider
The above "Hello World" example is great for simple commands, but what about something more
advanced? As your scripting and tooling needs grow, you might find that you need the ability
to accept variables. Much like function signatures have parameters, your tooling requests can
also accept parameters.

Just as each tooling request can be isolated to a method within a class, the parameters of a
tooling request can also be isolated in a very well known place. Parameters of the action methods
of a provider can include the same parameters you want your client to utilize when calling that
provider and action combination. For example, if you wanted to accept a name in the above
example, you would probably do this in OO code:

class My_Component_HelloProvider
implements Zend_Tool_Framework_Provider_Interface
{
public function say($name = 'Ralph')
{
echo 'Hello' . $name . ', from my provider!';

1444
Zend_Tool_Framework

}
}

The above example can then be called via the command line zf say hello Joe. "Joe" will be
supplied to the provider as a parameter of the method call. Also note, as you see that the
parameter is optional, that means it is also optional on the command line, so that zf say hello
will still work, and default to the name "Ralph".

4.4.2. Prompt the User for Input


There are cases when the workflow of your provider requires to prompt the user for input. This
can be done by requesting the client to ask for more the required input by calling:

class My_Component_HelloProvider
extends Zend_Tool_Framework_Provider_Abstract
{
public function say($name = 'Ralph')
{
$nameResponse = $this->_registry
->getClient()
->promptInteractiveInput("Whats your name?");
$name = $name->getContent();

echo 'Hello' . $name . ', from my provider!';


}
}

This command throws an exception if the current client is not able to handle interactive requests.
In case of the default Console Client however you will be asked to enter the name.

4.4.3. Pretending to execute a Provider Action


Another interesting feature you might wish to implement is pretendability. Pretendabilty is the
ability for your provider to "pretend" as if it is doing the requested action and provider combination
and give the user as much information about what it would do without actually doing it. This
might be an important notion when doing heavy database or filesystem modifications that the
user might not otherwise want to do.

Pretendability is easy to implement. There are two parts to this feature: 1) marking the provider
as having the ability to "pretend", and 2) checking the request to ensure the current request was
indeed asked to be "pretended". This feature is demonstrated in the code sample below.

class My_Component_HelloProvider
extends Zend_Tool_Framework_Provider_Abstract
implements Zend_Tool_Framework_Provider_Pretendable
{
public function say($name = 'Ralph')
{
if ($this->_registry->getRequest()->isPretend()) {
echo 'I would say hello to ' . $name . '.';
} else {
echo 'Hello' . $name . ', from my provider!';
}
}
}

To run the provider in pretend mode just call:

1445
Zend_Tool_Framework

% zf --pretend say hello Ralph


I would say hello Ralph.

4.4.4. Verbose and Debug modes


You can also run your provider actions in "verbose" or "debug" modes. The semantics in regard
to this actions have to be implemented by you in the context of your provider. You can access
debug or verbose modes with:

class My_Component_HelloProvider
implements Zend_Tool_Framework_Provider_Interface
{
public function say($name = 'Ralph')
{
if($this->_registry->getRequest()->isVerbose()) {
echo "Hello::say has been called\n";
}
if($this->_registry->getRequest()->isDebug()) {
syslog(LOG_INFO, "Hello::say has been called\n");
}
}
}

4.4.5. Accessing User Config and Storage


Using the Enviroment variable ZF_CONFIG_FILE or the .zf.ini in your home directory
you can inject configuration parameters into any Zend Tool provider. Access to this
configuration is available via the registry that is passed to your provider if you extend
Zend_Tool_Framework_Provider_Abstract.

class My_Component_HelloProvider
extends Zend_Tool_Framework_Provider_Abstract
{
public function say()
{
$username = $this->_registry->getConfig()->username;
if(!empty($username)) {
echo "Hello $username!";
} else {
echo "Hello!";
}
}
}

The returned configuration is of the type Zend_Tool_Framework_Client_Config but


internally the __get() and __set() magic methods proxy to a Zend_Config of the given
configuration type.

The storage allows to save arbitrary data for later reference. This can be useful for batch
processing tasks or for re-runs of your tasks. You can access the storage in a similar way like
the configuration:

class My_Component_HelloProvider
extends Zend_Tool_Framework_Provider_Abstract
{
public function say()
{

1446
Zend_Tool_Framework

$aValue = $this->_registry->getStorage()->get("myUsername");
echo "Hello $aValue!";
}
}

The API of the storage is very simple:

class Zend_Tool_Framework_Client_Storage
{
public function setAdapter($adapter);
public function isEnabled();
public function put($name, $value);
public function get($name, $defaultValue=null);
public function has($name);
public function remove($name);
public function getStreamUri($name);
}

When designing your providers that are config or storage aware remember to
check if the required user-config or storage keys really exist for a user. You won't
run into fatal errors when none of these are provided though, since empty ones
are created upon request.

5. Shipped System Providers


In addition to the more useful project based providers that come shipped with
Zend_Tool_Project, there are also some more basic, but interesting providers that come built
into Zend_Tool_Framework. Some of these exist for the purpose of providing a means via the
command line to extract information, such as the version, while others are intended to aid the
developer when creating additional providers.

5.1. The Version Provider


The Version provider is included so that you may determine which version of the framework that
the zf or Zend_Tool is currently set to work with.

Through the command line, simply run zf show version.

5.2. The Manifest Provider


The Manifest provider is included so that you may determine what kind of "manifest" information is
available during the Zend_Tool runtime. Manifest data is information that is attached to specific
objects during Zend_Tool's runtime. Inside the manifest you will find the console specific
namings that you are expected to use when calling certain commands. Data found in the manifest
can be used by any provider or client on an as-needed basis.

Through the command line, simply run zf show manifest.

6. Extending and Configuring Zend_Tool_Framework


6.1. Customizing Zend_Tool Console Client
As of Zend Framework 1.9, Zend_Tool_Framework allows developers to store information,
provider specific configuration values, and custom files in a special location on the developers

1447
Zend_Tool_Framework

machine. These configuration values and files can be used by providers to extend functionality,
customize functionality, or any other reasons a provider sees fit.

The primary purpose, and the purpose most immediately used by existing providers is to allow
developers to customize the way the "out of the box" providers do work.

One of the more commonly requested features is to be able to provide custom project profiles to
Zend_Tool_Project's Project Provider. This would allow developers to store a custom profile
in a special place that can be used repeatedly by the Zend_Tool system in order to build custom
profiles. Another commonly requested feature is to be able to configure the behavior of providers
with a configuration setting. In order to achieve this, not only do we have to have a Zend_Tool
configuration file, but we also have to have a place to find this configuration file.

6.1.1. The Home Directory


Before the Console Client can start searching for a Zend_Tool configuration file or a local
storage directory, it must first be able to identify where the "home directory" is located.

On *nix-based machines, PHP will be populated with an environment variable named HOME with
a path to the current users home directory. Typically, this path will be very similar to /home/
myusername.

On Windows-based machines, PHP will typically be populated with an environment variable


named HOMEPATH with the current users home directory. This directory is usually found in either
C:\Documents and Settings\Username\, or in Vista at C:\Users\Username.

If either a home directory cannot be found, or you wish to change the location of where
Zend_Tool_Framework Console Client finds the home directory, you can provide an
environment variable named ZF_HOME to specify where to find the home directory.

6.1.2. Local Storage


Once a home directory can be located, Zend_Tool_Framework's Console Client can either
autodiscover the local storage directory, or it can be told where to expect the local storage
directory.

Assuming the home directory has been found (here noted as $HOME), the Console Client will
then look for the local storage directory in $HOME/.zf/. If found, it will set the local storage
directory to this location.

If the directory cannot be found, or the developer wishes to override this location, that can be
done by setting an environment variable. Regardless if $HOME has been previously set or not,
the developer may supply the environment variable ZF_STORAGE_DIR.

Once the path to a local storage directory is found, the directory must exist for it to be passed
into the Zend_Tool_Framework runtime, as it will not be created for you.

6.1.3. User Configuration


Like local storage, once a home directory can be located, Zend_Tool_Framework's Console
Client can then either attempt to autodiscover the path to a configuration file, or it can be told
specifically where to find the configuration file.

Assuming the home directory has been found (here noted as $HOME), the Console Client will
then attempt to look for the existence of a configuration file located at $HOME/.zf.ini. This
file, if found, will be used as the configuration file for Zend_Tool_Framework.

1448
Zend_Tool_Framework

If that location does not exist, but a local storage directory does, then the Console Client will
then attempt to locate the configuration file within the local storage directory. Assuming the local
storage directory exists in $LOCAL_STORAGE, then if a file exists as $LOCAL_STORAGE/zf.ini,
it will be found by the Console Client and utilized as the Zend_Tool_Framework configuration
file.

If the file cannot be autodiscovered or the developer wishes to specify the location of location
of the configuration file, the developer can do so by setting an environment variable. If the
environment variable ZF_CONFIG_FILE is set, then its value will be used as the location of
the configuration file to use with the Console Client. The ZF_CONFIG_FILE can point to any
Zend_Config readable INI, XML or PHP File.

If the file does not exist in either the autodiscovered or the provided location, it will not be used
as Zend_Tool_Framework does not attempt to create the file automatically.

6.1.4. User Configuration File Content


The configuration file should be structured as a Zend_Config configuration file, in ini format,
and without any sections being defined. First level keys should be used by the provider searching
for a specific value. For example, if the "Project" provider is expecting a "profiles" directory, then
it should typically be understood that it will search for the following ini key value pair:

project.profile = some/path/to/some-directory

The only reserved ini prefix is the value "php". The "php" prefix to values will be reserved to store
names and values of runtime settable php values, such as include_path or error_reporting. To
override the include_path and error_reporting with an ini value, a developer would set:

php.include_path = "/path/to/includes1:/path/to/includes2"
php.error_reporting = 1

The reserved prefix "php" only works with INI files. You can't set PHP INI values
with PHP or XML config.

1449
Zend_Tool_Project
1. Introduction
Zend_Tool_Project est construit à partir de Zend_Tool_Framework permettant ainsi
d'étendre ses capacités et de gérer un projet. En général, un projet est un effort prévu ou
une initiative. Dans le monde de l'informatique, les projets sont généralement une collection de
ressources. Ces ressources peuvent être des fichiers, des répertoires, des bases de données,
des schémas, des images, des styles, et parfois plus.

Ce même concept s'applique aux projets Zend Framework. Dans les projets Zend Framework,
vous avez des contrôleurs, des actions, des vues, des modèles, des bases de données et ainsi de
suite. En terme de Zend_Tool, nous avons besoin d'un moyen de pister ce type de ressources -
c'est-à-dire Zend_Tool_Project.

Zend_Tool_Project est capable de pister les ressources de projet au cours du


développement d'un projet. Ainsi, par exemple, si lors de la première commande vous créez
un contrôleur et que lors de la commande suivante vous souhaitez créer une action à l'intérieur
de ce contrôleur, Zend_Tool_Project doit connaitre ce fichier de contrôleur qui a été créé
ainsi vous pouvez (dans l'action suivante), être capable de lui ajouter une action. C'est ce qui
maintient nos projets à jour et complets.

Un autre point important à comprendre concernant les projets est que typiquement, les
ressources sont organisées de manière hiérarchique. Avec cela à l'esprit, Zend_Tool_Project
est capable de construire le projet en cours dans une représentation interne qui lui permet de
maintenir non seulement quelles ressources de font partie d'un projet à un moment donné, mais
également où elles sont les unes par rapport aux autres.

2. Créer un projet

Les exemples suivants considéreront que l'inferface en ligne de commande de


Zend_Tool_Framework est disponible.

Pour exécuter l'une des commandes de Zend_Tool_Project en mode CLI,


vous devez être dans le répertoire dans lequel le projet a été initialement créé.

Pour démarrer avec Zend_Tool_Project, vous devez simplement créer un projet. La création
d'un projet est simple : allez où vous le souhaitez dans votre système de fichiers, créez un
dossier, allez dans le dossier créé, ensuite exécutez les commandes suivantes :

/tmp/project$ zf create project

Optionnellement, vous pouvez créer un projet n'importe où en exéxcutant :

$ zf create project /chemin/vers/dossier-non-existant

La table suivante décrit les fonctionnalités des fournisseurs qui sont disponibles. Comme vous
pouvez le voir, il existe un fournisseur "Project". Le fournisseur "Project" possède deux actions,
et avec ces actions un certain nombre d'options qui peuvent modifier le comportement de l'action
et du fournisseur.

1450
Zend_Tool_Project

Tableau 148. Project Provider Options

Nom du fournisseur Actions disponibles Paramètres Utilisation en CLI


Project Create / Show create - [path=null, zf create project
profile='default'] some/path

3. Fournisseurs de Zend_Tool_Project
Ci-dessous, vous trouverez un tableau de tous les fournisseurs embarqués avec
Zend_Tool_Project.

Tableau 149. Options du fournisseur Project

Nom du fournisseur Actions disponibles Paramètres Utilisation en CLI


Controller Création create - [name, zf create controller
indexActionIncluded=true]
foo
Action Création create - [name, zf create action
controllerName=index, bar foo (ou zf
viewIncluded=true] create action --name
bar --controlller-
name=foo)
Controller Création create - [name, zf create controller
indexActionIncluded=true]
foo
Profile Visualisation show - [] zf show profile
View Création create - zf create view foo bar
[controllerName,actionNameOrSimpleName]
(ou zf create view -c
foo -a bar)
Test Création / Activation / create - zf create test
Désactivation [libraryClassName] My_Foo_Baz / zf
disable test / zf
enable test

4. Rouages internes de Zend_Tool_Project


4.1. Structure xml interne de Zend_Tool_Project

4.2. Etendre les rouages de Zend_Tool_Project

1451
Zend_Translate
1. Introduction
Zend_Translate est la solution de Zend Framework pour des applications multilingues.

Dans des applications multilingues, le contenu doit être traduit en plusieurs langues et l'affichage
du contenu dépend de la langue de l'utilisateur. PHP offre déjà plusieurs manières de manipuler
de tels problèmes, toutefois la solution PHP a quelques problèmes :

• API contradictoire : Il n'y a pas d'API unique pour les différents formats de source. L'utilisation
du gettext par exemple est très compliquée.

• PHP supporte seulement gettext et les tableaux natifs : PHP lui-même offre seulement
le support des tableaux ou du gettext. Tous autres formats de source doivent être codés
manuellement, parce qu'il n'y a aucun support native.

• Pas de détection de la langue par défaut : La langue par défaut de l'utilisateur ne peut pas
être détectée sans une connaissance plus approfondie des différents navigateurs Web.

• Gettext n'est pas "thread-safe" : La bibliothèque gettext de PHP n'est pas "thread safe", et
elle ne devrait pas être employée dans un environnement multi-threading. C'est dû à des
problèmes de gettext lui-même, pas de PHP, mais c'est un problème existant.

Zend_Translate n'a pas les problèmes ci-dessus. C'est pourquoi nous recommandons
d'employer Zend_Translate au lieu des fonctions natives de PHP. Les avantages de
Zend_Translate sont :

• Support des formats multiples de source : Zend_Translate supporte plusieurs formats de


source, y compris ceux supportés par PHP, et d'autres formats comprenant les fichiers de
type TMX et CSV.

• Thread-safe gettext : Le lecteur de gettext de Zend_Translate est "thread-safe". Il n'y a


aucun problème en utilisant le dans les environnements multi-threadés.

• API générique et facile : L'API de Zend_Translate est très simple et exige seulement une
poignée de fonctions. Ainsi il est facile d'apprendre et facile à maintenir. Tous les formats de
source sont manipulés la même manière, ainsi si le format de vos fichiers source changent de
Gettext en TMX, vous devez seulement changer une ligne de code pour indiquer l'adaptateur
de stockage.

• Détection de la langue de l'utilisateur : Zend_Translate peut détecter et se servir de la


langue préférée de l'utilisateur accédant à l'application.

• Détection automatique de la source : Zend_Translate est capable de détecter et d'intégrer


des fichiers source multiples et de détecter de plus la localisation à utiliser selon les répertoires
ou les noms de fichier.

1.1. Démarrer avec le multi-linguisme


Ce que nous voulons faire c'est traduire les chaînes de caractère générées afin que la vue
produise un contenu traduit. Autrement nous devrions écrire une vue pour chaque langue, et
personne ne voudraient faire ceci. Généralement, les sites multilingues sont très simples dans
leur conception. Il y a seulement quatre étapes que vous devrez faire :

1452
Zend_Translate

1. Décider quel adaptateur vous voulez utiliser

2. Créer votre vue et intégrer Zend_Translate à votre code

3. Créer le fichier source de votre code

4. Traduire votre fichier source dans les langues désirées.

Les sections suivantes vous guident par chacune des quatre étapes. Lisez les pages suivantes
pour créer votre propre application Web multilingue.

2. Adaptateurs pour Zend_Translate


Zend_Translate peut manipuler différents adaptateurs pour la traduction. Chaque adaptateur
a ses propres avantages et inconvénients. Ci-dessous vous trouverez la liste complète de tous
les adaptateurs supportés pour la traduction des fichiers sources.

Tableau 150. Liste des adaptateurs pour Zend_Translate


Adaptateur Description Utilisation
Tableau (array) Utilise les tableaux PHP Petites pages ; l'utilisation la
plus simple ; seulement pour
les programmeurs
Csv Utilise les fichiers à séparation Format simple de fichier texte ;
par virgule (*.csv/*.txt) rapide ; problèmes possibles
avec les caractères Unicode
Gettext Utilise les fichiers binaires Norme GNU pour Linux ;
gettext (*.mo) thread-safe ; besoin d'outils
pour la traduction
Ini Utilise de simples fichiers ini Format simple de fichier texte ;
(*.ini) rapide ; problèmes possibles
avec les caractères Unicode
Tbx Utilise les fichiers d'échange Standard industriel pour des
termbase (*.tbx/*.XML) chaînes partagées entre les
applications ; format XML
Tmx Utilise les fichiers tmx (*.tmx/ Industriellement compatible
*.XML) avec la traduction partagée
d'application ; format XML ;
lisible par l'homme
Qt Utilise les fichiers qt linguist Framework pour les
(*.ts) applications mutualisées ;
format XML ; lisible par
l'homme
Xliff Utilise les fichiers xliff (*.xliff/ Un format plus simple que TMX
*.XML) mais lié à lui ; format XML ;
lisible par l'homme
XmlTm Use xmltm (*.XML) files Standard industriel pour la
traduction de type XML ; format
XML ; lisible par l'homme
Autres *.sql Différents adaptateurs
pourront être implémentés
dans l'avenir.

1453
Zend_Translate

2.1. Comment décider quel adaptateur de traduction utiliser ?


Vous devrez décider quel adaptateur vous voulez utiliser avec Zend_Translate.
Fréquemment, des critères externes tels qu'une condition du projet ou une exigence du client
détermine ceci pour vous, mais si vous êtes en position de le faire vous-même, les conseils
suivants peuvent simplifier votre décision.

En choisissant votre adaptateur vous devriez également prendre en compte


l'encodage utilisé. Même si Zend Framework déclare UTF-8 comme encodage
par défaut, il vous sera parfois nécessaire d'utiliser un autre encodage.
Zend_Translate ne changera pas l'encodage défini dans votre fichier source
ce qui veut dire que si votre source Gettext est construite en ISO-8859-1, il
retournera les chaînes dans cet encodage sans les convertir. Il existe une seule
restriction :

Quand vous utilisez des sources basées sur le format XML comme TMX ou XLIFF
vous devez définir l'encodage dans l'en-tête des fichiers XML, car tout fichier
XML sans définition d'encodage sera traité par défaut en UTF-8 par un analyseur
XML. Vous devez aussi prendre en compte que les encodages des fichiers XML
sont limités aux encodages supportés par PHP, c'est-à-dire UTF-8, ISO-8859-1
and US-ASCII.

2.1.1. Zend_Translate_Adapter_Array
L'adaptateur de type tableau est l'adaptateur qui est le plus simple à utiliser pour les
programmeurs. Mais quand vous avez de nombreuses chaînes de traduction ou beaucoup de
langues vous devriez penser à un autre adaptateur. Par exemple, si vous avez 5000 chaînes de
traduction, l'adaptateur tableau n'est probablement pas le choix le plus approprié pour vous.

Vous devriez seulement utiliser cet adaptateur pour de petits sites avec quelques langues, et si
vous (ou votre équipe de programmeur) créez les traductions vous-même.

2.1.2. Zend_Translate_Adapter_Csv
L'adaptateur Csv est l'adaptateur qui est le plus simple à utiliser pour les clients. Les fichiers CSV
sont lisibles par les éditeurs de texte standard, mais souvent les éditeurs de texte ne supportent
pas les jeux de caractères utf8.

Vous devriez utiliser cet adaptateur seulement si votre client veut faire les traductions lui-même.

Prenez garde que l'adaptateur Csv a des problèmes quand vos fichiers Csv ont
un encodage différent que celui de votre environnement. Ceci est du à un bug
de PHP lui-même qui ne sera pas corrigé avant la PHP 6.0 (http://bugs.php.net/
bug.php?id=38471). Vous devez donc faire attention que l'adaptateur Csv ne
gère pas la locale à cause d'une restrictions PHP.

2.1.3. Zend_Translate_Adapter_Gettext
L'adaptateur Gettext est l'adaptateur qui est utilisé le plus souvent. Gettext est un format de
source de traduction qui a été présenté par GNU, et est maintenant employé dans le monde
entier. Il n'est pas lisible pour l'homme, mais il y a plusieurs outils gratuiciels (par exemple,
POEdit), qui sont très utiles. L'adaptateur Zend_Translate_Gettext n'est pas implémenté
en utilisant l'extension gettext de PHP. Vous pouvez utiliser l'adaptateur Gettext même si vous

1454
Zend_Translate

n'avez pas installer l'extension gettext de PHP. En outre l'adaptateur est "thread-safe" alors que
l'extension gettext de PHP ne l'est pas actuellement.

La plupart des personnes utiliseront cet adaptateur. Avec les outils disponibles, la traduction
professionnelle est très simple. Mais les données de gettext sont stockées dans un format
compréhensible par une machine, qui n'est pas lisible sans outils.

2.1.4. Zend_Translate_Adapter_Ini
L'adaptateur Ini est un adaptateur qui peut être directement utiliser par les clients. Les fichiers INI
sont lisibles par les éditeurs de texte standard, mais souvent les éditeurs de texte ne supportent
pas les jeux de caractères utf8.

Vous devriez utiliser cet adaptateur seulement si votre client veut faire les traductions lui-même.
N'utilisez pas cet adaptateur comme source de traduction générique.

Regression in PHP 5.3


Prior to PHP 5.3, parse_ini_file() and parse_ini_string() handled
non-ASCII characters within INI option keys worked without an issue. However,
starting with PHP 5.3, any such keys will now be silently dropped in the returned
array from either function. If you had keys utilizing UTF-8 or Latin-1 characters,
you may find your translations no longer work when using the INI adapter. If this
is the case, we recommend utilizing a different adapter.

2.1.5. Zend_Translate_Adapter_Tbx
L'adaptateur Tbx est un adaptateur qui sera utilisé par les clients qui utilisent déjà le format
TBX pour leur système de traduction interne. Tbx n'est pas un format de traduction standard,
mais plus une collection de chaînes de caractère sources déjà traduites et pré-traduites. Quand
vous utilisez cet adaptateur vous devez être sûrs que toute votre chaîne de caractère source
nécessaire est traduite. TBX est un fichier basé sur le format XML et un format complètement
nouveau. XML des fichiers sont lisibles par l'homme, mais l'analyse syntaxique n'est pas aussi
rapide qu'avec des fichiers gettext.

Cet adaptateur est parfait pour les sociétés dont les fichiers source pré-traduits existent déjà.
Les fichiers sont lisibles par l'homme et sont indépendants de système.

2.1.6. Zend_Translate_Adapter_Tmx
L'adaptateur Tmx est l'adaptateur qui sera employé par la plupart des clients qui ont des
systèmes multiples qui emploient la même source de traduction, ou quand la source de traduction
doit être indépendante du système. TMX est un format basé sur le format XML, qui est annoncé
pour être le prochain standard industriel. Les fichiers de XML sont lisibles par l'homme, mais
l'analyse n'est pas aussi rapide qu'avec des fichiers gettext.

La plupart des moyennes à grandes entreprises utilisent cet adaptateur. Les fichiers sont lisibles
par l'homme et sont indépendants du système.

2.1.7. Zend_Translate_Adapter_Qt
L'adaptateur Qt est destiné à tous les clients qui ont des fichiers TS faits par QtLinguist
comme source de traduction. QT est un fichier basé sur le format XML. Les fichiers XML sont
humainement lisible, mais l'analyse syntaxique n'est pas si rapide qu'avec des fichiers gettext.

Plusieurs grands acteurs ont construit leur logiciel sur le framework QT. Les fichiers sont lisibles
par l'homme et indépendants du système.

1455
Zend_Translate

2.1.8. Zend_Translate_Adapter_Xliff
L'adaptateur Xliff est l'adaptateur qui sera employé par la plupart des clients qui veulent avoir
des fichiers XML mais n'ont pas d'outils pour TMX. XLIFF est basé sur le format XML et est lié
à TMX mais est plus simple car il ne supporte pas toutes ses possibilités. Les fichiers XML sont
lisibles par l'homme, mais l'analyse n'est pas aussi rapide qu'avec des fichiers gettext.

La plupart des moyennes entreprises utilisent cet adaptateur. Les fichiers sont lisibles par
l'homme et sont indépendants du système.

2.1.9. Zend_Translate_Adapter_XmlTm
L'adaptateur XmlTm est l'adaptateur qui sera utilisé par les clients qui font leur mise en page
eux-mêmes. XmlTm est un format qui permet à la source HTML complète d'être incluse dans la
source de traduction, donc la traduction est couplée avec la mise en page. XmlTm est un fichier
basé sur le format XML, qui est proche de XLIFF, mais qui n'est pas aussi simple à lire.

Cet adaptateur devrait être seulement utilisé quand des fichiers source existent déjà. Les fichiers
sont lisibles par l'homme et sont indépendants du système.

2.2. Intégrer ses propres adaptateurs


Zend_Translate vous permet d'intégrer et d'utiliser vos propres classes d'adaptateurs.
Elles peuvent être utilisées commes les classes standards qui sont déjà incluses dans
Zend_Translate.

Toute classe d'adaptateur que vous voulez utiliser avec Zend_Translate doit être une sous-
classe de Zend_Translate_Adapter. Zend_Translate_Adapter est une classe abstraite
qui définit déjà tout ce qui est nécessaire pour la traduction. Ce qui doit être fait par vous, est
la définition du lecteur des données traduites.

L'usage du préfixe "Zend" devrait être limité à Zend Framework. Si vous


étendez Zend_Translate avec votre propre adaptateur, vous devriez le nommer
"MonEntreprise_Translate_Adapter_MonFormat". Le code suivant montre un exemple de la
manière dont une classe d'adaptateur personnalisée peut être implémentée :

try {
$translate = new Zend_Translate(
'MonEntreprise_Translate_Adapter_MonFormat',
'/chemin/vers/translate.xx',
'fr',
array('monoption' => 'mavaleur'));
} catch (Exception $e) {
// Fichier non trouvé, pas de classe d'adaptateur...
// Echec de l'application
}

2.3. Améliorer les performances de tous les adaptateurs


Zend_Translate vous permet d'utiliser en interne Zend_Cache pour accélérer le chargement
des sources de traduction. Cela devient très pratique si vous utilisez beaucoup de sources de
traduction ou des formats source vastes comme des fichiers au format XML.

Pour utiliser le cache, vous devez juste fournir un objet de cache à la méthode
Zend_Translate::setCache(). Elle prend une instance de Zend_Cache comme seul
paramètre. En outre si vous utilisez n'importe quel adaptateur direct, vous pouvez employer

1456
Zend_Translate

la méthode setCache(). Par commodité, il existe des méthodes statiques getCache(),


hasCache(), clearCache() et removeCache().

$cache = Zend_Cache::factory('Core',
'File',
$frontendOptions,
$backendOptions);
Zend_Translate::setCache($cache);
$translate = new Zend_Translate('gettext',
'/chemin/vers/traduction.mo',
'en');

Vous devez paramétrer le cache avant d'utiliser ou d'initialiser tout adaptateur


ou instance de Zend_Translate. Sinon votre source de traduction ne sera pas
mise en cache tant que vous n'aurez pas ajouté une nouvelle source avec la
méthode addTranslation().

3. Utiliser les adaptateurs de traduction


L'étape suivante est d'utiliser l'adaptateur dans votre code.

Exemple 878. Exemple de code PHP monolingue

print "Exemple\n";
print "=======\n";
print "Ceci la ligne une\n";
print "Aujourd'hui nous sommes le " . date("d/m/Y") . "\n";
print "\n";
print "Correction de la langue ceci est la ligne deux\n";

L'exemple ci-dessus montre l'affichage sans le support de traduction. Vous écrivez probablement
votre code dans votre langue maternelle. Généralement vous devez traduire non seulement
l'affichage, mais également les messages d'erreur et les messages de log.

La prochaine étape est d'inclure Zend_Translate dans votre code existant. Naturellement il
est beaucoup plus facile si vous écrivez dès le début votre code en utilisant Zend_Translate
au lieu de modifier votre code après.

Exemple 879. Exemple de code PHP multilingue

$translate = new Zend_Translate('gettext',


'/mon/chemin/source-de.mo',
'de');
$translate->addTranslation('//mon/chemin/fr-source.mo', 'fr');

print $translate->_("Exemple")."\n";
print "=======\n";
print $translate->_("Ceci la ligne une")."\n";
printf($translate->_("Aujourd'hui nous sommes le %1\$s") . "\n",
date("d/m/Y"));
print "\n";

$translate->setLocale('fr');
print $translate->_("Correction de la langue ceci est la ligne deux") . "\n";

Maintenant regardons plus attentivement ce qui a été fait et la façon d'intégrer Zend_Translate
dans votre code.

1457
Zend_Translate

Créer un nouvel objet de traduction et définir l'adaptateur de base :

$translate = new Zend_Translate('gettext',


'/chemin/vers/source-de.mo',
'de');

Dans cet exemple nous avons décidé d'utiliser l'adaptateur Gettext. Nous plaçons notre
fichier source-de.mo dans le dossier /chemin/vers. Le fichier gettext inclura la traduction
allemande. Et nous avons également ajouté un autre fichier de langue pour le français.

L'étape suivante est d'envelopper toutes les chaînes qui doivent être traduites. L'approche la
plus simple est d'avoir seulement des chaînes simples ou des phrases comme celle-ci :

print $translate->_("Exemple")."\n";
print "=======\n";
print $translate->_("Ceci la ligne une")."\n";

Certaines chaînes ne sont pas nécessairement traduites. La ligne séparatrice est toujours la
même, même dans d'autres langues.

Avoir des valeurs de données intégrées dans une chaîne de traduction est également supporté
par l'utilisation des paramètres inclus.

printf($translate->_("Aujourd'hui nous sommes le %1\$s") . "\n",


date("d/m/Y"));

Au lieu de print(), utiliser la fonction printf() et remplacer tous les paramètres avec des
éléments de type %1\$s. Le premier est %1\$s, le second %2\$s, et ainsi de suite. De cette
façon une traduction peut être faite sans savoir la valeur exacte. Dans notre exemple, la date
est toujours le jour actuel, mais la chaîne peut être traduite sans connaissance du jour actuel.

Chaque chaîne est identifiée dans le stockage de traduction par un identificateur de message.
Vous pouvez employer l'identificateur de message au lieu des chaînes dans votre code, comme
ceci :

print $translate->_(1)."\n";
print "=======\n";
print $translate->_(2)."\n";

faire ceci a plusieurs inconvénients :

Vous ne pouvez pas voir ce que votre code devrait afficher juste en lisant celui-ci.

En outre vous obtiendrez des problèmes si certaines chaînes ne sont pas traduites. Vous devez
toujours imaginer comment la traduction fonctionne. Premièrement Zend_Translate vérifie
si la langue choisie a une traduction pour l'identificateur de message ou la chaîne fournie. Si
aucune chaîne de traduction n'a été trouvée, elle se reporte sur la langue suivante comme
définie dans Zend_Locale. Ainsi le "de_AT" devient seulement "de". Si aucune traduction n'est
trouvée pour le "de", alors le message original est retourné. De cette façon vous avez toujours
un affichage, au cas où la traduction de message n'existerait pas dans votre stockage des
messages. Zend_Translate ne lève jamais d'erreur ou d'exception en traduisant les chaînes.

3.1. Structures des sources de traduction


L'étape suivante est la création des sources de traduction pour les multiples langues vers
lesquelles vous traduisez. Chaque adaptateur est créé de sa propre manière comme décrit ici.
Mais il y a quelques dispositifs généraux qui sont valables pour tous les adaptateurs.

1458
Zend_Translate

Vous devrez savoir où stocker vos fichiers sources de traduction. Avec Zend_Translate vous
n'avez aucune restriction. Les structures suivantes sont préférables :

• Structure de source unique

/application
/languages
lang.en
lang.de
/library

Positif : Tous les fichiers sources pour chacune des langues peuvent être trouvés dans un
dossier. Aucun fractionnement des fichiers.

• Source structurée par langue

/application
/languages
/en
lang.en
other.en
/de
lang.de
other.de
/library

Positif : chaque langue est située dans un dossier. La traduction est facilitée car un seul
dossier doit être traduit par une équipe de langue. En outre l'utilisation de dossiers multiples
est transparente.

• Source structurée par application

/application
/languages
lang.en
lang.de
other.en
other.de

Positif : tous les fichiers sources pour chacune des langues peuvent être trouvés dans un seul
dossier. Aucun fractionnement des fichiers.

Négatif : avoir des dossiers multiples pour la même langue est problématique.

• Source structurée par Gettext

/languages
/de
/LC_MESSAGES
lang.mo
other.mo
/en
/LC_MESSAGES
lang.mo
other.mo

Positif : de vieilles sources de gettext peuvent être utilisées sans changer la structure.

1459
Zend_Translate

Négatif : avoir des dossiers de dossiers peut être embrouillant pour les personnes qui n'ont
pas utilisé gettext avant.

• Source structurée par fichier

/application
/models
mymodel.php
mymodel.de
mymodel.en
/views
/controllers
mycontroller.de
/document_root
/images
/styles
.htaccess
index.php
index.de
/library
/Zend

Positif : chaque fichier est lié à sa propre source de traduction.

Négatif : de multiples petits fichiers sources de traduction rendent plus difficile la traduction.
En outre chaque fichier doit être ajouté comme source de traduction.

Les fichiers source uniques et structurés par langue sont les plus utilisés pour
Zend_Translate.

Maintenant, que nous connaissons la structure que nous voulons avoir, nous devons créer nos
fichiers sources de traduction.

3.2. Créer des fichiers sources de type tableau


Les fichiers sources de type tableau sont simplement des tableaux. Mais vous devez les définir
manuellement parce qu'il n'y a aucun outil pour automatiser cela. Mais parce qu'ils sont très
simples, ils représentent la manière la plus rapide de rechercher des messages si votre code
fonctionne comme prévu. C'est généralement le meilleur adaptateur pour démarrer avec des
systèmes multilingues.

$english = array('message1' => 'message1',


'message2' => 'message2',
'message3' => 'message3');
$german = array('message1' => 'Nachricht1',
'message2' => 'Nachricht2',
'message3' => 'Nachricht3');

$translate = new Zend_Translate('array', $english, 'en');


$translate->addTranslation($deutsch, 'de');

Depuis la version 1.5 il est également possible d'avoir des tableaux inclus dans un fichier externe.
Vous devez simplement fournir le nom de fichier, Zend_Translate l'inclura automatiquement
et recherchera le tableau. Voir l'exemple suivant pour les détails :

// montableau.php

1460
Zend_Translate

return array(
'message1' => 'Nachricht1',
'message2' => 'Nachricht2',
'message3' => 'Nachricht3');

// contrôleur
$translate = new Zend_Translate('array',
'chemin/vers/montableau.php',
'de');

Les fichiers qui ne renvoient pas un tableau ne seront pas inclus. N'importe quel
rendu issu de ce fichier sera ignoré et également supprimé.

3.3. Créer des fichiers sources Gettext


Des fichiers source Gettext sont créés par la bibliothèque GNU gettext. Il y a plusieurs outils libres
disponibles qui peuvent analyser vos fichiers de code et créer les fichiers sources nécessaires à
gettext. Ces fichiers se terminent par *.mo et ce sont des fichiers binaires. Un gratuiciel pour créer
ces fichiers est poEdit. Cet outil vous aide également pour le processus de traduction lui-même.

// Les fichiers mo sont créés et déjà traduits


$translate = new Zend_Translate('gettext',
'chemin/vers/english.mo',
'en');
$translate->addTranslation('chemin/vers/german.mo', 'de');

Comme vous pouvez le voir, les adaptateurs sont utilisés exactement de la même manière,
avec juste une petite différence : changer "array" en "gettext". Toutes autres utilisations
sont exactement les mêmes qu'avec tous autres adaptateurs. Avec l'adaptateur de gettext vous
ne devez plus vous occuper de la structure des répertoires, du "bindtextdomain" et du
"textdomain". Fournissez juste le chemin et le nom de fichier à l'adaptateur.

Vous devriez toujours employer UTF-8 comme source d'encodage. Autrement


vous aurez des problèmes si vous employez deux encodages différents. Par
exemple, si un de vos fichiers source est encodé en ISO-8815-1 et un fichier
différent est codé avec CP815. Vous ne pouvez utiliser qu'un seul encodage pour
vos fichiers sources, ainsi une de vos langues ne s'affichera probablement pas
correctement.

UTF-8 est un format portable qui supporte toutes les langues. Si vous employez
l'encodage UTF-8 pour toutes les langues, vous éliminez le problème des
encodages incompatibles.

La plupart des éditeur gettext ajoutent les informations de l'adaptateur comme chaines
de traduction vides. C'est pour cela que traduire des chaines vides ne fonctionne pas
avec l'adaptateur gettext. A la place, elles sont effacées de la table de traduction.
getAdapterInfo() retourne les informations de l'adaptateur gettext, notamment les
informations des fichiers gettext ajoutés.

// Informations sur l'adaptateur


$translate = new Zend_Translate('gettext',
'path/to/english.mo',
'en');
print_r $translate->getAdapterInfo();

1461
Zend_Translate

3.4. Créer des fichiers source TMX


Les fichiers sources TMX sont les nouveaux standards industriels. Ils ont l'avantage d'être des
fichiers XML et ainsi ils sont lisibles par tout éditeur de fichier et naturellement ils sont lisibles
pour l'homme. Vous pouvez soit créer des fichiers TMX manuellement avec un éditeur de texte,
soit utiliser un outil. Mais la plupart des programmes actuellement disponibles pour développer
des fichiers source TMX ne sont pas des gratuiciels.

Exemple 880. Exemple de fichier TMX

<?xml version="1.0" ?>


<!DOCTYPE tmx SYSTEM "tmx14.dtd">
<tmx version="1.4">
<header creationtoolversion="1.0.0" datatype="winres"
segtype="sentence" adminlang="en-us" srclang="de-at"
o-tmf="abc" creationtool="XYZTool" >
</header>
<body>
<tu tuid='message1'>
<tuv xml:lang="de"><seg>Nachricht1</seg></tuv>
<tuv xml:lang="en"><seg>message1</seg></tuv>
</tu>
<tu tuid='message2'>
<tuv xml:lang="en"><seg>message2</seg></tuv>
<tuv xml:lang="de"><seg>Nachricht2</seg></tuv>
</tu>

$translate = new Zend_Translate('tmx',


'chemin/vers/mytranslation.tmx',
'en');
// TMX peut contenir différentes langues dans le même fichier

Les fichiers TMX peuvent avoir plusieurs langues dans le même fichier. Toute autre langue
incluse est ajoutée automatiquement, ainsi vous n'avez pas à appeler addLanguage().

Si vous voulez avoir seulement les langues spécifiées de la source traduite, vous pouvez
régler l'option defined_language à TRUE. Avec cette option vous pouvez ajouter les langues
souhaitées explicitement avec addLanguage(). La valeur par défaut pour cette option est
d'ajouter toutes les langues.

3.5. Créer des fichiers source CSV


Les fichiers sources CSV sont petits et lisibles pour l'homme. Si vos clients veulent eux-mêmes
traduire, vous utiliserez probablement l'adaptateur CSV.

Exemple 881. Exemple avec un fichier CSV

#Exemple de fichier csv


message1;Nachricht1
message2;Nachricht2

$translate = new Zend_Translate('csv',


'chemin/vers/matraduction.csv',
'de');
$translate->addTranslation('chemin/vers/autretraduction.csv',
'fr');

1462
Zend_Translate

Il existe trois options différentes pour l'adaptateur CSV. Vous pouvez paramétrer "delimiter",
"limit" et "enclosure".

Le délimiteur standard des fichiers CSV est le signe ";". Mais celui-ci n'est pas obligatoire. Avec
l'option "delimiter" vous pouvez décider d'utiliser un autre signe de séparation.

La taille limite d'une ligne de fichier CSV est par défaut "0" Ce qui veut dire que la fin de la ligne est
recherchée automatiquement. Si vous paramétrez l'option "limit" avec une valeur quelconque,
alors le fichier CSV sera lu plus rapidement, mais toute ligne dont la longueur excédera la limite
sera tronquée.

"L'échappement" par défaut d'un fichier CSV est le """. Vous pouvez en paramétrer un autre
avec l'option "enclosure".

Exemple 882. Exemple avec un fichier CSV (2)

#Exemple de fichier csv


# original 'message,1'
"message,1",Nachricht1
# traduction 'Nachricht,2'
message2,"Nachricht,2"
# original 'message3,'
"message3,",Nachricht3

$translate = new Zend_Translate('csv',


'chemin/vers/matraduction.csv',
'de',
array('delimiter' => ','));
$translate->addTranslation('chemin/vers/autretraduction.csv',
'fr');

3.6. Créer des fichiers sources INI


Les fichiers sources INI sont lisibles par l'homme mais habituellement pas très petits puisqu'ils
incluent également d'autres données à côté des traductions. Si vous avez des données qui seront
éditables par vos clients, vous pouvez aussi utiliser l'adaptateur INI dans ce cas.

Exemple 883. Exemple avec un fichier INI

[Test]
;Commentaires possibles
Message_1="Nachricht 1 (de)"
Message_2="Nachricht 2 (de)"
Message_3="Nachricht :3 (de)"

$translate = new Zend_Translate('ini',


'path/to/mytranslation.ini',
'de');
$translate->addTranslation('path/to/other.ini',
'it');

Les fichiers INI ont de multiples restrictions. Si une valeur dans le fichier INI contient un caractère
non-alphanumérique, il doit être entouré avec des guillemets doubles ("). Il y a aussi des mots
réservés qui ne doivent pas être utilisés en tant que clés des fichiers INI. Ceci inclut : NULL,
yes, no, TRUE et FALSE. Les valeurs NULL, no et FALSE sont retournées sous la forme "". yes
et TRUE sont retournés en "1". Les caractères {}|&~![()" ne doivent pas être utilisés dans la clé

1463
Zend_Translate

et ont une signification particulière dans la valeur. Ne les utilisez pas ou vous rencontrerez des
comportements inattendus.

3.7. Options pour les adaptateurs


Les options peuvent être utilisées avec tous les adaptateurs. Bien sûr chacun d'eux accepte
des options différentes. Vous pouvez passer des options quand vous créez l'adaptateur. Pour
l'instant il y a qu'une option qui est valable pour tous les adaptateurs. 'clear' décide si des
données de traduction peuvent être ajoutées à l'existant ou non. Le comportement standard
est d'ajouter des nouvelles données de traduction à l'existant. Les données de traduction sont
seulement effacées pour la langue choisie. Donc on ne touchera pas aux autres langues.

Vous pouvez régler des options temporaires en utilisant addTranslation($data, $locale,


array $options = array()) comme troisième paramètre optionnel. Ou vous pouvez utiliser
la fonction setOptions() pour régler une option.

Exemple 884. Utiliser les options de traduction

// définir ':' comme séparateur pour les fichiers sources de traduction


$options = array('delimiter' => ':');
$translate = new Zend_Translate('csv',
'chemin/vers/matraduction.csv',
'fr',
$options);

...

// efface le langage défini et utilise de nouvelles données de traduction


$options = array('clear' => true);
$translate->addTranslation('chemin/vers/nouveau.csv',
'en',
$options);

Ici vous pouvez trouver toutes les options disponibles pour les différents adaptateurs avec une
description de leur utilisation :

Tableau 151. Options des adaptateurs de traduction


Adaptateur Option Valeur standard Description
Tous clear FALSE Si réglé à TRUE, les
traductions déjà lues
seront effacées. Ceci
peut être utilisé au lieu
de créer une nouvelle
instance quand on lit
de nouvelles données
de traduction.
Tous disableNotices FALSE Si réglé à TRUE, toutes
les notices concernant
la non-disponibilité
des traductions seront
désactivées. Vous
devriez mettre cette
option à TRUE dans
votre environnement
de production.

1464
Zend_Translate

Adaptateur Option Valeur standard Description


Tous ignore . Tous les dossiers
et les fichiers
commençant par
ce caractère seront
ignorés dans la
recherche
automatique de
traductions. La valeur
par défaut est '.', ce
qui signifie que tous
les fichiers cachés
(Unix) seront ignorés.
Mettre une valeur par
exemple à 'tmp' aura
pour effet d'ignorer
les dossiers ou
fichiers 'tmpImages' ou
encore 'tmpFiles' (par
exemple), ainsi que
tous les sous-dossiers
all log null An instance of
Zend_Log where
untranslated
messages and notices
will be written to
logMessage all The message which Untranslated message
will be written into the within '%locale%':
log %message%
all logUntranslated false When this option is set
to true, all message
id's which can not
be translated will be
written into a also
attached log
Tous scan NULL Si réglé à NULL, aucun
scan de la structure
de répertoire ne sera
effectué. Si réglé à
Zend_Translate::LOCALE_DIRECTO
la localisation sera
détectée dans le
répertoire. Si réglé à
Zend_Translate::LOCALE_FILENAM
la localisation sera
détectée dans le
nom de fichier.
Voir Section 3.9,
« Détéction
automatique de la

1465
Zend_Translate

Adaptateur Option Valeur standard Description


source » pour de plus
amples détails.
Csv delimiter ; Définit quel signe
est utilisé pour la
séparation de la
source et de la
traduction.
Csv length 0 Définit la longueur
maximum d'une ligne
de fichier. Réglé à
0, la recherche sera
automatique.
Csv enclosure " Définit le caractère
d'échappement.

Si vous souhaitez avoir vos propres définitions d'options, vous pouvez les utiliser avec tous les
adaptateurs. La méthode setOptions() peut être utilisée pour définir vos options. La méthode
setOptions() nécessite un tableau avec les options que vous voulez paramétrer. Si une
option fournie existe déjà, elle sera alors ré-assignée. Vous pouvez définir autant d'options que
nécessaire car elles ne seront pas vérifiées par l'adaptateur. Vérifiez simplement que vous ne
créez pas une option qui existe déjà dans l'adaptateur, vous affecteriez alors une nouvelle valeur.

Pour récupérer l'ensemble des options, vous pouvez utiliser la méthode getOptions(). Quand
getOptions() est appelée sans paramètre, elle retourne l'ensemble des options. Si un
paramètre est fourni, seule l'option particulière sera retournée.

3.8. Gérer les langues


En travaillant avec différentes langues il y a quelques méthodes qui seront utiles.

La méthode getLocale() peut être utilisée pour récupérer la langue actuellement réglée. Elle
peut retourner soit une instance de Zend_Locale, soit un identifiant de localisation.

La méthode setLocale() règle une nouvelle langue standard pour la traduction. Ceci évite
de placer le paramètre facultatif de langue plus d'une fois lors de l'appel de la méthode
translate(). Si la langue donnée n'existe pas, ou si aucune donnée de traduction n'est
disponible pour la langue, setLocale() essaye de remonter à la langue sans région si elle
est indiquée. Une langue fr_FR serait remontée à fr. Si la remontée n'est pas possible, une
exception sera levée.

La méthode isAvailable() vérifie si une langue donnée est déjà disponible. Elle retourne
TRUE si des données existent pour la langue fournie.

Et enfin la méthode getList() peut être utilisée pour récupérer sous la forme d'un tableau
tous les langues paramétrées pour un adaptateur.

1466
Zend_Translate

Exemple 885. Gestion des langues avec des adaptateurs

...
// retourne la langue paramétrée actuelle
$actual = $translate->getLocale();

...
// vous pouvez utiliser le paramètre optionel au moment de la traduction
echo $translate->_("mon_texte", "fr");
// ou paramètrer une langue standard
$translate->setLocale("fr");
echo $translate->_("mon_texte");
// référence à la langue de base... fr_CH sera remonté à fr
$translate->setLocale("fr_CH");
echo $translate->_("mon_texte");
...
// vérifie si la langue existe
if ($translate->isAvailable("fr")) {
// la langue existe
}

3.8.1. Gestion automatique des langues

Notez que tant que vous ajouterez les nouvelles sources de traduction seulement via la méthode
addTranslation(), Zend_Translate cherchera automatiquement la langue correspondant
au mieux à votre environnement quand vous utiliserez une des localisations automatiques
"auto" ou "browser". Donc normalement vous ne devriez pas appeler setLocale(). Ceci ne
doit être utilisé qu'en conjonction avec la détection automatique des sources de traduction.

L'algorithme recherchera la meilleure locale suivant le navigateur des utilisateurs et votre


environnement. Voyez l'exemple suivant pour les détails :

1467
Zend_Translate

Exemple 886. Comment la détection automatique de la langue fonctionne-t-elle ?

// Assumons que le navigateur retourne ces valeurs


// HTTP_ACCEPT_LANGUAGE = "de_AT=1;fr=1;en_US=0.8";

// Exemple 1 :
$translate = new Zend_Translate('gettext',
'\my_it.mo',
'auto',
array('scan' => Zend_Translate::LOCALE_FILENAME);
// pas de langue trouvée, on retourne le messageid

// Exemple 2 :
$translate = new Zend_Translate('gettext',
'\my_fr.mo',
'auto',
array('scan' => Zend_Translate::LOCALE_FILENAME);
// langue correspondante trouvée "en_US"

// Exemple 3 :
$translate = new Zend_Translate('gettext',
'\my_de.mo',
'auto',
array('scan' => Zend_Translate::LOCALE_FILENAME);
// langue correspondante trouvée "de" car "de_AT" est descendue à "de"

// Exemple 4 :
$translate = new Zend_Translate('gettext',
'\my_it.mo',
'auto',
array('scan' => Zend_Translate::LOCALE_FILENAME);
$translate->addTranslation('\my_ru.mo', 'ru');
$translate->setLocale('it_IT');
// retourne "it_IT" comme source de traduction et surcharge le réglage automatique

Si vous utilisez setLocale(), la detection automatique de la langue sera alors annulée, et la


langue à utiliser sera celle spécifiée par l'appel de la méthode.

Si vous voulez réactiver la détection automatique, réappelez setLocale() et passez lui la


valeur auto.

Depuis Zend Framework 1.7.0 Zend_Translate reconnait une locale globale pour l'application.
Vous pouvez ainsi simplement mettre un objet Zend_Locale dans le registre, comme montré
ci-après. Avec cette fonctionnalité, vous pouvez oublier le passage de la locale à votre objet de
traduction.

// En fichier d'amorçage (bootstrap)


$locale = new Zend_Locale('de_AT');
Zend_Registry::set('Zend_Locale', $locale);

// ailleurs dans votre application


$translate = new Zend_Translate('gettext', '\my_de.mo');
$translate->getLocale();

3.9. Détéction automatique de la source


Zend_Translate peut détecter les sources de traduction de manière automatique. Ainsi vous
n'avez pas à déclarer toutes les sources manuellement. Vous laissez Zend_Translate faire ce

1468
Zend_Translate

travail et scanner complètement tout un répertoire à la recherche de fichiers de langue de


traduction.

La détection automatique des sources de traduction est disponible depuis Zend


Framework version 1.5.

L'utilisation est assez semblable à celle qui permet de spécifier une source de langue. Vous
devez simplement donner un dossier, et non plus un fichier, à l'adaptateur. Ce dossier sera alors
scanné

Exemple 887. Scanner un dossier à la recherche de sources de traduction

// Soit la structure suivante :


// /language
// /language/login/login.tmx
// /language/logout/logout.tmx
// /language/error/loginerror.tmx
// /language/error/logouterror.tmx

$translate = new Zend_Translate('tmx', '/language');

Notez que Zend_Translate cherche dans tous les sous-repertoires. L'utilisation devient alors
relativement simple. Aussi, Zend_Translate ignorera tout fichier qui ne l'interresse pas : des
fichiers non représentatifs de traductions ou encore des fichiers illisibles. Vérifiez donc que le
dossier principal ne contienne que des fichiers de traductions, car Zend_Translate ne renverra
aucune erreur dans le cas contraire, il ignorera simplement de tels fichiers.

Selon la compléxité de la récursivité, la traversée du répertoire principal peut


devenir longue et couteuse.

Dans notre exemple, nous utilisons l'adaptateur TMX qui inclut la langue à utiliser dans le fichier
en question. D'autres adaptateurs n'agissent pas comme cela, ainsi les noms de fichiers devront
comporter les noms des langues à considérer pour de tels adaptateurs.

3.9.1. La langue se trouve dans le nom des dossiers

One way to include automatic language detection is to name the directories related to the
language which is used for the sources within this directory. This is the easiest way and is used
for example within standard gettext implementations.

Zend_Translate needs the 'scan' option to know that it should search the names of all directories
for languages. See the following example for details:

1469
Zend_Translate

Exemple 888. Directory scanning for languages

// expect we have the following structure


// /language
// /language/de/login/login.mo
// /language/de/error/loginerror.mo
// /language/en/login/login.mo
// /language/en/error/loginerror.mo

$translate = new Zend_Translate('gettext',


'/language',
null,
array('scan' =>
Zend_Translate::LOCALE_DIRECTORY));

This works only for adapters which do not include the language within the source
file. Using this option for example with TMX will be ignored. Also language
definitions within the filename will be ignored when using this option.

You should be aware if you have several subdirectories under the same structure.
Expect we have a structure like /language/module/de/en/file.mo. The
path contains in this case multiple strings which would be detected as locale. It
could be eigther de or en. As the behaviour is, in this case, not declared it is
recommended that you use file detection in such situations.

3.9.2. Language through filenames

Another way to detect the langage automatically is to use special filenames. You can either name
the complete file or parts of a file with the used language. To use this way of detection you will
have to set the 'scan' option at initiation. There are several ways of naming the sourcefiles which
are described below:

Exemple 889. Filename scanning for languages

// expect we have the following structure


// /language
// /language/login/login_en.mo
// /language/login/login_de.mo
// /language/error/loginerror_en.mo
// /language/error/loginerror_de.mo

$translate = new Zend_Translate('gettext',


'/language',
null,
array('scan' =>
Zend_Translate::LOCALE_FILENAME));

3.9.2.1. Complete Filename

Having the whole file named after the language is the simplest way but only usable if you have
only one file per directory.

/languages

1470
Zend_Translate

en.mo
de.mo
es.mo

3.9.2.2. Extension of the file

Another very simple way if to use the extension of the file for the language detection. But this
may be confusing because you will no longer know which file extension the file originally was.

/languages
view.en
view.de
view.es

3.9.2.3. Filename tokens

Zend_Translate is also captable of detecting the language if it is included within the filename.
But if you use this way you will have to seperate the language with a token. There are three
supported tokens which can be used: A point '.', a underline '_', or a hyphen '-'.

/languages
view_en.mo -> detects english
view_de.mo -> detects german
view_it.mo -> detects italian

The first found token which can be detected as locale will be used. See the following example
for details.

/languages
view_en_de.mo -> detects english
view_en_es.mo -> detects english and overwrites the first file
because the same messageids are used
view_it_it.mo -> detects italian

All three tokens are used to detect the locale. The first one is the point '.', the second is the
underline '_' and the third the hyphen '-'. If you have several tokens within the filename the first
found depending on the order of the tokens will be used. See the following example for details.

/languages
view_en-it.mo -> detects english because '_' will be used before '-'
view-en_it.mo -> detects italian because '_' will be used before '-'
view_en.it.mo -> detects italian because '.' will be used before '_'

3.10. Vérifier les traductions


Normalement le texte sera traduit sans aucun calcul. Mais il est quelquefois nécessaire si un
texte est traduit ou non dans la source. Dans ce cas la méthode isTranslated() peut être
utilisé.

isTranslated($messageId, $original = false, $locale = null) prend comme


premier paramètre le texte dont vous voulez vérifier que la traduction est possible. Et comme
troisième paramètre optionnel la langue dont vous voulez connaître la traduction. Le second
paramètre optionnel détermine si la traduction est fixée à la langue déclarée ou si une autre
langue peut être utilisée. Si vous avez un texte qui peut être traduit en "fr" mais pas en "fr_fr" vous

1471
Zend_Translate

obtiendriez normalement la traduction fournie, mais avec $original réglé à TRUE, la méthode
isTranslated() retournera FALSE dans ce cas.

Exemple 890. Vérifier si une texte est traduisible

$english = array('message1' => 'Nachricht 1',


'message2' => 'Nachricht 2',
'message3' => 'Nachricht 3');
$translate = new Zend_Translate('array', $english, 'de_AT');

if ($translate->isTranslated('message1')) {
print "'message1' peut être traduit";
}
if (!($translate->isTranslated('message1', true, 'de'))) {
print "'message1' ne peut pas être traduit en 'de', "
. "il est seulement disponible en 'de_AT'";
}
if ($translate->isTranslated('message1', false, 'de')) {
print "'message1' peut être traduit en 'de_AT' "
. "et par conséquent en 'de'";}

3.11. How to log not found translations


When you have a bigger site or you are creating the translation files manually, you often have
the problem that some messages are not translated. But there is a easy solution for you when
you are using Zend_Translate.

You have to follow two or three simple steps. First, you have to create a instance of Zend_Log.
And then you have to attach this instance to Zend_Translate. See the following example:

Exemple 891. Log translations

$translate = new Zend_Translate('gettext', $path, 'de');

// Create a log instance


$writer = new Zend_Log_Writer_Stream('/path/file.log');
$log = new Zend_Log($writer);

// Attach it to the translation instance


$translate->setOptions(array(
'log' => $log,
'logUntranslated' => true));

$translate->translate('unknown string');

Now you will have in the log a new notice: Untranslated message within 'de': unknown
string.

You should note that any translation which can not be found will be logged. This
means all translations when a user requests a not supported language. But also
every request to a message which can not be translated will be logged. Be aware
that when 100 people request the same translation you will have 100 notices
logged.

This feature can not only be used to log messages but also to attach this not translated messages
into a empty translation file. To archive this you will have to write your own log writer which writes
the format you want to have and strips the prepending "Untranslated message" for you.

1472
Zend_Translate

You can also set the 'logMessage' option when you want to have your own log message. Use
the '%message%' token for placing the messageId within your log message, and the '%locale%'
token for the requested locale. See the following example for a self defined log message:

Exemple 892. Self defined log messages

$translate = new Zend_Translate('gettext', $path, 'de');

// Create a log instance


$writer = new Zend_Log_Writer_Stream('/path/to/file.log');
$log = new Zend_Log($writer);

// Attach it to the translation instance


$translate->setOptions(array(
'log' => $log,
'logMessage' => "Missing '%message%' within locale '%locale%'",
'logUntranslated' => true));

$translate->translate('unknown string');

3.12. Access to the source data


Of course sometimes it is useful to have access to the translation source data. Therefor two
functions exist.

The getMessageIds($locale = null) method returns all known message ids as array.

And the getMessages($locale = null) method returns the complete translation source as
array. The message id is used as key and the translation data as value.

Both methods accept an optional parameter $locale which, when set, returns the translation
data for the specified language. If this parameter is not given, the actual set language will be
used. Keep in mind that normally all translations should be available in all languages. Which
means that in a normal situation you will not have to set this parameter.

Additionally the getMessages() method is able to return the complete translation dictionary
with the pseudo-locale 'all'. This will return all available translation data for each added locale.

Attention: The returned array can be very big, depending on the count of added
locales and the amount of translation data.

Exemple 893. Handling languages with adapters

...
// returns all known message ids
$messageids = $translate->getMessageIds();
print_r($messageids);

...
// or just for the specified language
$messageids = $translate->getMessageIds('en_US');
print_r($messageids);

...
// returns all the complete translation data
$source = $translate->getMessages();
print_r($source);

1473
Zend_Translate

4. Creating source files


Below you will find a description of the different source formats which can be used with
Zend_Translate.

Note that most of the described formats should be created by using a tool or a
generation process. These Tools and processes are not part of Zend Framework
and for most of the described formats free tools are available.

4.1. Creating Array source files


Array source files are plain arrays. But you have to define them manually since there is no tool
to aid this. But because they are so simple, it's the fastest way to look up messages if your code
works as expected. It's generally the best adapter to get started with translation business.

$english = array(
'message1' => 'message1',
'message2' => 'message2',
'message3' => 'message3');

$german = array(
'message1' => 'Nachricht1',
'message2' => 'Nachricht2',
'message3' => 'Nachricht3');

$translate = new Zend_Translate('array', $english, 'en');


$translate->addTranslation($deutsch, 'de');

Since release 1.5 it is also supported to have arrays included within an external file. You just
have to provide the filename and Zend_Translate will automatically include it and look for the
array. See the following example for details:

// myarray.php
return array(
'message1' => 'Nachricht1',
'message2' => 'Nachricht2',
'message3' => 'Nachricht3');

// controller
$translate = new Zend_Translate('array', '/path/to/myarray.php', 'de');

Files which do not return an array will fail to be included. Also any output within
this file will be ignored and suppressed.

4.2. Creating Gettext source files


Gettext source files are created by GNU's gettext library. There are several free tools available
that can parse your code files and create the needed gettext source files. These have the
extension *.mo and they are binary files. An open source tool for creating the files is poEdit. This
tool also supports you during the translation process itself.

// We accume that we have created the mo files and translated them

1474
Zend_Translate

$translate = new Zend_Translate('gettext', '/path/to/english.mo', 'en');


$translate->addTranslation('/path/to/german.mo', 'de');

As you can see the adapters are used exactly the same way, with one small difference: change
array to gettext. All other usages are exactly the same as with all other adapters. With the gettext
adapter you no longer have to be aware of gettext's standard directory structure, bindtextdomain
and textdomain. Just give the path and filename to the adapter.

You should always use UTF-8 as source encoding. Otherwise you will have
problems when using two different source encodings. E.g. one of your source
files is encoded with ISO-8815-11 and another one with CP815. You can set only
one encoding for your source file, so one of your languages probably will not
display correctly.

UTF-8 is a portable format which supports all languages. When using UTF-8 for
all languages, you will eliminate the problem of incompatible encodings.

Many gettext editors add adapter informations as empty translation string. This is the reason why
empty strings are not translated when using the gettext adapter. Instead they are erased from
the translation table and provided by the getAdapterInfo() method. It will return the adapter
informations for all added gettext files as array using the filename as key.

// Getting the adapter informations


$translate = new Zend_Translate('gettext', '/path/to/english.mo', 'en');
print_r($translate->getAdapterInfo());

4.3. Creating TMX source files


TMX source files are a new industry standard. They have the advantage of being XML files and
so they are readable by every editor and of course by humans. You can either create TMX files
manually with a text editor, or you can use a special tool. But most tools currently available for
creating TMX source files are not freely available.

Exemple 894. Example TMX file

<?xml version="1.0" ?>


<!DOCTYPE tmx SYSTEM "tmx14.dtd">
<tmx version="1.4">
<header creationtoolversion="1.0.0" datatype="winres" segtype="sentence"
adminlang="en-us" srclang="de-at" o-tmf="abc"
creationtool="XYZTool" >
</header>
<body>
<tu tuid='message1'>
<tuv xml:lang="de"><seg>Nachricht1</seg></tuv>
<tuv xml:lang="en"><seg>message1</seg></tuv>
</tu>
<tu tuid='message2'>
<tuv xml:lang="en"><seg>message2</seg></tuv>
<tuv xml:lang="de"><seg>Nachricht2</seg></tuv>
</tu>

$translate = new Zend_Translate('tmx', 'path/to/mytranslation.tmx', 'en');

TMX files can have several languages within the same file. All other included languages are
added automatically, so you do not have to call addLanguage().

1475
Zend_Translate

If you want to have only specified languages from the source translated you can set the option
'defined_language' to TRUE. With this option you can add the wished languages explicitly
with addLanguage(). The default value for this option is to add all languages.

4.4. Creating CSV source files


CSV source files are small and human readable. If your customers want to translate their own,
you will probably use the CSV adapter.

Exemple 895. Example CSV file

#Example csv file


message1;Nachricht1
message2;Nachricht2

$translate = new Zend_Translate('csv', '/path/to/mytranslation.csv', 'de');


$translate->addTranslation('path/to/other.csv', 'fr');

There are three different options for the CSV adapter. You can set 'delimiter', 'limit' and
'enclosure'.

The default delimiter for CSV string is ';', but with the option 'delimiter' you can decide to
use another one.

The default limit for a line within a CSV file is '0'. This means that the end of a CSV line is searched
automatically. If you set 'limit' to any value, then the CSV file will be read faster, but any line
exceeding this limit will be truncated.

The default enclosure to use for CSV files is '"'. You can set a different one using the option
'enclosure'.

Exemple 896. Second CSV file example

# Example CSV file


"message,1",Nachricht1
message2,"Nachricht,2"
"message3,",Nachricht3

$translate = new Zend_Translate(


'csv',
'/path/to/mytranslation.csv',
'de',
array('delimiter' => ','));

$translate->addTranslation('/path/to/other.csv', 'fr');

When you are using non-ASCII characters within your CSV file, like umlauts or
UTF-8 chars, then you should always use enclosure. Omitting the enclosure can
lead to missing characters in your translation.

4.5. Creating INI source files


INI source files are human readable but normally not very small as they also include other data
beside translations. If you have data which shall be editable by your customers you can use the
INI adapter.

1476
Zend_Translate

Exemple 897. Example INI file

[Test]
;TestPage Comment
Message_1="Nachricht 1 (de)"
Message_2="Nachricht 2 (de)"
Message_3="Nachricht :3 (de)"

$translate = new Zend_Translate('ini', '/path/to/mytranslation.ini', 'de');


$translate->addTranslation('/path/to/other.ini', 'it');

INI files have several restrictions. If a value in the ini file contains any non-alphanumeric
characters it needs to be enclosed in double-quotes ("). There are also reserved words which
must not be used as keys for ini files. These include: NULL, yes, no, TRUE, and FALSE. Values
NULL, no and FALSE results in "", yes and TRUE results in 1. Characters {}|&~![()" must
not be used anywhere in the key and have a special meaning in the value. Do not use them as
it will produce unexpected behaviour.

5. Additional features for translation


There are several additional features which are supported by Zend_Translate. Read here for
these additional informations.

5.1. Options for adapters


Options can be used with all adapters. Of course the options are different for all adapters. You
can set options when you create the adapter. Actually there is one option which is available to
all adapters: 'clear' sets if translation data should be added to existing one or not. Standard
behaviour is to add new translation data to existing one. But the translation data is only cleared
for the selected language. So other languages remain untouched.

You can set options temporarily when using addTranslation($data, $locale, array
$options = array()) as third and optional parameter. And you can use the method
setOptions() to set the options permanently.

Exemple 898. Using translation options

// define ':' as separator for the translation source files


$options = array('delimiter' => ':');
$translate = new Zend_Translate(
'csv',
'/path/to/mytranslation.csv',
'de',
$options);

...

// clear the defined language and use new translation data


$options = array('clear' => true);
$translate->addTranslation('/path/to/new.csv', 'fr', $options);

Here you can find all available options for the different adapters with a description of their usage:

1477
Zend_Translate

Tableau 152. Options for translation adapters

Option Adapter Description Default value


clear all If set to TRUE, FALSE
the already read
translations will be
cleared. This can
be used instead
of creating a new
instance when reading
new translation data
disableNotices all If set to TRUE, all FALSE
notices regarding not
available translations
will be disabled. You
should set this option
to TRUE in production
environment
ignore all All directories and files .
beginning with this
prefix will be ignored
when searching for
files. This value
defaults to '.' which
leads to the behavior
that all hidden files
will be ignored. Setting
this value to 'tmp'
would mean that
directories and files
like 'tmpImages'
and 'tmpFiles'
would be ignored as
well as all subsequent
directories
log all An instance of NULL
Zend_Log where
untranslated
messages and notices
will be written to
logMessage all The message which Untranslated message
will be written into the within '%locale%':
log %message%
logUntranslated all When this option is FALSE
set to TRUE, all
message IDs which
can not be translated
will be written into the
attached log
reload all When this option is FALSE
set to TRUE, then files

1478
Zend_Translate

Option Adapter Description Default value


are reloaded into the
cache. This option can
be used to recreate
the cache, or to add
translations to already
cached data after the
cache has already
been created.
scan all If set to NULL, NULL
no scanning of the
directory structure will
be done. If set to
Zend_Translate::LOCALE_DIRECTORY
the locale will be
detected within the
directory. If set to
Zend_Translate::LOCALE_FILENAME
the locale will
be detected within
the filename. See
Section 5.3,
« Automatic source
detection » for details
delimiter Csv Defines which sign is ;
used as delimiter for
separating source and
translation
enclosure Csv Defines the enclosure "
character to be
used. Defaults to a
doublequote
length Csv Defines the maximum 0
length of a csv line.
When set to 0 it will be
detected automatically
useId Xliff If you set this option TRUE
to FALSE, then the
source string will be
used as message Id.
The default for this
option is TRUE, which
means that the Id
from the trans-unit
element will be used as
message Id

When you want to have self defined options, you are also able to use them within all adapters.
The setOptions() method can be used to define your option. setOptions() needs an array
with the options you want to set. If an given option exists it will be signed over. You can define

1479
Zend_Translate

as much options as needed as they will not be checked by the adapter. Just make sure not to
overwrite any existing option which is used by an adapter.

To return the option you can use the getOptions() method. When getOptions() is called
without a parameter it will return all options set. When the optional parameter is given you will
only get the specified option.

5.2. Handling languages


When working with different languages there are a few methods which will be useful.

The getLocale() method can be used to get the currently set language. It can either hold an
instance of Zend_Locale or the identifier of a locale.

The setLocale() method sets a new standard language for translation. This prevents the need
of setting the optional language parameter more than once to the translate() method. If the
given language does not exist, or no translation data is available for the language, setLocale()
tries to downgrade to the language without the region if any was given. A language of en_US
would be downgraded to en. When even the downgraded language can not be found an
exception will be thrown.

The isAvailable() method checks if a given language is already available. It returns TRUE
if data for the given language exist.

And finally the getList() method can be used to get all currently set languages for an adapter
returned as array.

Exemple 899. Handling languages with adapters

// returns the currently set language


$actual = $translate->getLocale();

// you can use the optional parameter while translating


echo $translate->_("my_text", "fr");
// or set a new language
$translate->setLocale("fr");
echo $translate->_("my_text");
// refer to the base language
// fr_CH will be downgraded to fr
$translate->setLocale("fr_CH");
echo $translate->_("my_text");

// check if this language exist


if ($translate->isAvailable("fr")) {
// language exists
}

5.2.1. Automatical handling of languages


Note that as long as you only add new translation sources with the addTranslation() method
Zend_Translate will automatically set the best fitting language for your environment when you
use one of the automatic locales which are 'auto' or 'browser'. So normally you will not need
to call setLocale(). This should only be used in conjunction with automatic source detection.

The algorithm will search for the best fitting locale depending on the user's browser and your
environment. See the following example for details:

1480
Zend_Translate

Exemple 900. Automatically language detection

// Let's expect the browser returns these language settings:


// HTTP_ACCEPT_LANGUAGE = "de_AT=1;fr=1;en_US=0.8";

// Example 1:
// When no fitting language is found, the message ID is returned
$translate = new Zend_Translate(
'gettext',
'my_it.mo',
'auto',
array('scan' => Zend_Translate::LOCALE_FILENAME));

// Example 2:
// Best found fitting language is 'fr'
$translate = new Zend_Translate(
'gettext',
'my_fr.mo',
'auto',
array('scan' => Zend_Translate::LOCALE_FILENAME));

// Example 3:
// Best found fitting language is 'de' ('de_AT' will be degraded)
$translate = new Zend_Translate(
'gettext',
'my_de.mo',
'auto',
array('scan' => Zend_Translate::LOCALE_FILENAME));

// Example 4:
// Returns 'it' as translation source and overrides the automatic settings
$translate = new Zend_Translate(
'gettext',
'my_it.mo',
'auto',
array('scan' => Zend_Translate::LOCALE_FILENAME));

$translate->addTranslation('my_ru.mo', 'ru');
$translate->setLocale('it_IT');

After setting a language manually with the setLocale() method the automatic detection will
be switched off and overridden.

If you want to use it again, you can set the language auto with setLocale() which will reactivate
the automatic detection for Zend_Translate.

Since Zend Framework 1.7.0 Zend_Translate also recognises an application wide locale. You
can simply set a Zend_Locale instance to the registry like shown below. With this notation you
can forget about setting the locale manually with each instance when you want to use the same
locale multiple times.

// in your bootstrap file


$locale = new Zend_Locale();
Zend_Registry::set('Zend_Locale', $locale);

// default language when requested language is not available


$defaultlanguage = 'en';

1481
Zend_Translate

// somewhere in your application


$translate = new Zend_Translate('gettext', 'my_de.mo');

if (!$translate->isAvailable($locale->getLanguage())) {
// not available languages are rerouted to another language
$translate->setLocale($defaultlanguage);
}

$translate->getLocale();

5.3. Automatic source detection


Zend_Translate can detect translation sources automatically. So you don't have to declare
each source file manually. You can let Zend_Translate do this job and scan the complete
directory structure for source files.

Automatic source detection is available since Zend Framework version 1.5 .

The usage is quite the same as initiating a single translation source with one difference. You
must give a directory which has to be scanned instead a file.

Exemple 901. Scanning a directory structure for sources

// assuming we have the following structure


// /language/
// /language/login/login.tmx
// /language/logout/logout.tmx
// /language/error/loginerror.tmx
// /language/error/logouterror.tmx

$translate = new Zend_Translate('tmx', '/language');

So Zend_Translate does not only search the given directory, but also all subdirectories for
translation source files. This makes the usage quite simple. But Zend_Translate will ignore
all files which are not sources or which produce failures while reading the translation data. So
you have to make sure that all of your translation sources are correct and readable because you
will not get any failure if a file is bogus or can not be read.

Depending on how deep your directory structure is and how much files are within
this structure it can take a long time for Zend_Translate to complete.

In our example we have used the TMX format which includes the language to be used within
the source. But many of the other source formats are not able to include the language within
the file. Even this sources can be used with automatic scanning if you do some pre-requisits as
described below:

5.3.1. Language through naming directories

One way to include automatic language detection is to name the directories related to the
language which is used for the sources within this directory. This is the easiest way and is used
for example within standard gettext implementations.

1482
Zend_Translate

Zend_Translate needs the 'scan' option to know that it should search the names of all
directories for languages. See the following example for details:

Exemple 902. Directory scanning for languages

// assuming we have the following structure


// /language/
// /language/de/login/login.mo
// /language/de/error/loginerror.mo
// /language/en/login/login.mo
// /language/en/error/loginerror.mo

$translate = new Zend_Translate(


'gettext',
'/language',
null,
array('scan' => Zend_Translate::LOCALE_DIRECTORY));

This works only for adapters which do not include the language within the source
file. Using this option for example with TMX will be ignored. Also language
definitions within the filename will be ignored when using this option.

You should be aware if you have several subdirectories under the same structure.
Assuming we have a structure like /language/module/de/en/file.mo. In
this case the path contains multiple strings which would be detected as locale.
It could be either de or en. In such a case the behaviour is undefined and it is
recommended to use file detection in such situations.

5.3.2. Language through filenames


Another way to detect the language automatically is to use special filenames. You can either
name the complete file or parts of a file after the used language. To use this way of detection you
will have to set the 'scan' option at initiation. There are several ways of naming the sourcefiles
which are described below:

Exemple 903. Filename scanning for languages

// assuming we have the following structure


// /language/
// /language/login/login_en.mo
// /language/login/login_de.mo
// /language/error/loginerror_en.mo
// /language/error/loginerror_de.mo

$translate = new Zend_Translate(


'gettext',
'/language',
null,
array('scan' => Zend_Translate::LOCALE_FILENAME));

5.3.2.1. Complete filename

Having the whole file named after the language is the simplest way but only viable if you have
only one file per language.

1483
Zend_Translate

/languages/
/languages/en.mo
/languages/de.mo
/languages/es.mo

5.3.2.2. Extension of the file

Another simple way to use the extension of the file for language detection. But this may be
confusing since you will no longer have an idea which extension the file originally had.

/languages/
/languages/view.en
/languages/view.de
/languages/view.es

5.3.2.3. Filename tokens

Zend_Translate is also capable of detecting the language if it is included within the filename.
But if you go this way you will have to separate the language with a token. There are three
supported tokens which can be used: a dot '.', an underscore '_', or a hyphen '-'.

/languages/
/languages/view_en.mo -> detects english
/languages/view_de.mo -> detects german
/languages/view_it.mo -> detects italian

The first found string delimited by a token which can be interpreted as a locale will be used. See
the following example for details.

/languages/
/languages/view_en_de.mo -> detects english
/languages/view_en_es.mo -> detects english and overwrites the first file
/languages/view_it_it.mo -> detects italian

All three tokens are used to detect the locale. When the filename contains multiple tokens, the
first found token depends on the order of the tokens which are used. See the following example
for details.

/languages/
/languages/view_en-it.mo -> detects english because '_' will be used before '-'
/languages/view-en_it.mo -> detects italian because '_' will be used before '-'
/languages/view_en.it.mo -> detects italian because '.' will be used before '_'

5.4. Checking for translations


Normally text will be translated without any computation. But sometimes it is necessary to know
if a text is translated or not, therefor the isTranslated() method can be used.

isTranslated($messageId, $original = false, $locale = null) takes the text


you want to check as its first parameter, and as optional third parameter the locale for which you
want to do the check. The optional second parameter declares whether translation is fixed to the
declared language or a lower set of translations can be used. If you have a text which can be
returned for 'en' but not for 'en_US' you will normally get the translation returned, but by setting
$original to TRUE, isTranslated() will return FALSE.

1484
Zend_Translate

Exemple 904. Checking if a text is translatable

$english = array(
'message1' => 'Nachricht 1',
'message2' => 'Nachricht 2',
'message3' => 'Nachricht 3');

$translate = new Zend_Translate('array', $english, 'de_AT');

if ($translate->isTranslated('message1')) {
print "'message1' can be translated";
}

if (!($translate->isTranslated('message1', true, 'de'))) {


print "'message1' can not be translated to 'de'"
. " as it's available only in 'de_AT'";
}

if ($translate->isTranslated('message1', false, 'de')) {


print "'message1' can be translated in 'de_AT' as it falls back to 'de'";
}

5.5. How to log not found translations


When you have a bigger site or you are creating the translation files manually, you often have
the problem that some messages are not translated. But there is an easy solution for you when
you are using Zend_Translate.

You have to follow two or three simple steps. First, you have to create an instance of Zend_Log.
Then you have to attach this instance to Zend_Translate. See the following example:

Exemple 905. Log translations

$translate = new Zend_Translate('gettext', $path, 'de');

// Create a log instance


$writer = new Zend_Log_Writer_Stream('/path/to/file.log');
$log = new Zend_Log($writer);

// Attach it to the translation instance


$translate->setOptions(array(
'log' => $log,
'logUntranslated' => true));

$translate->translate('unknown string');

Now you will have a new notice in the log: Untranslated message within 'de': unknown
string.

You should note that any translation which can not be found will be logged. This
means all translations when a user requests a language which is not supported.
Also every request for a message which can not be translated will be logged. Be
aware, that 100 people requesting the same translation, will result 100 logged
notices.

1485
Zend_Translate

This feature can not only be used to log messages but also to attach this untranslated messages
into an empty translation file. To do so you will have to write your own log writer which writes the
format you want to have and strips the prepending "Untranslated message".

You can also set the 'logMessage' option when you want to have your own log message. Use
the '%message%' token for placing the messageId within your log message, and the '%locale%'
token for the requested locale. See the following example for a self defined log message:

Exemple 906. Self defined log messages

$translate = new Zend_Translate('gettext', $path, 'de');

// Create a log instance


$writer = new Zend_Log_Writer_Stream('/path/to/file.log');
$log = new Zend_Log($writer);

// Attach it to the translation instance


$translate->setOptions(array(
'log' => $log,
'logMessage' => "Missing '%message%' within locale '%locale%'",
'logUntranslated' => true));

$translate->translate('unknown string');

5.6. Accessing source data


Sometimes it is useful to have access to the translation source data. Therefor the following two
functions are provided.

The getMessageIds($locale = null) method returns all known message IDs as array.

The getMessages($locale = null) method returns the complete translation source as an


array. The message ID is used as key and the translation data as value.

Both methods accept an optional parameter $locale which, if set, returns the translation data
for the specified language. If this parameter is not given, the actual set language will be used.
Keep in mind that normally all translations should be available in all languages. Which means
that in a normal situation you will not have to set this parameter.

Additionally the getMessages() method can be used to return the complete translation
dictionary using the pseudo-locale 'all'. This will return all available translation data for each
added locale.

Attention: the returned array can be very big, depending on the number of added
locales and the amount of translation data.

1486
Zend_Translate

Exemple 907. Handling languages with adapters

// returns all known message IDs


$messageIds = $translate->getMessageIds();
print_r($messageIds);

// or just for the specified language


$messageIds = $translate->getMessageIds('en_US');
print_r($messageIds);

// returns all the complete translation data


$source = $translate->getMessages();
print_r($source);

6. Notation des pluriels pour Translation


Depuis Zend Framework 1.9, Zend_Translate gère les pluriels. Comme presque tous les
langages utilisent des pluriels, la traduction doit gérer celà.

Qu'est ce qu'un pluriel? En général, les pluriels sont des mots qui prennent en compte une
contenance numérique. Cependant chaque langue a sa propre définition du pluriel. En anglais,
par exemple, un seul pluriel par mot existe donc par exemple "car" donnera "cars" au pluriel.
D'autres langages comme le russe proposent plusieurs pluriels et plusieurs règles de pluriels.

Lorsque vous voulez utiliser les pluriels avec Zend_Translate vous n'avez pas besoin de
savoir comment ceux-ci sont définis, seul le traducteur sait. Vous devez juste savoir la langue
dans laquelle traduire.

Il existe 2 manières d'utiliser les pluriels. La traditionnelle qui vous fait utiliser une méthode, la
moderne, qui permet d'utiliser la même méthode pour plusieurs pluriels.

6.1. Méthode traditionnelle


Les personnes connaissant gettext vont reconnaitre cette méthodologie. Il existe une seule
méthode plural() qui rend le pluriel.

Exemple 908. Exemple avec la méthode traditionnelle

La méthode plural() accepte 4 paramètres. Le premier est le messageId au singulier, le


second est le messageId du pluriel, le troisième est le nombre ou la quantité.

La quantité va être utilisée pour détecter le pluriel à retourner. Le 4ème paramètre optionnel
peut être utilisé pour spécifier une locale concernant la traduction.

$translate = new Zend_Translate('gettext', '/path/to/german.mo', 'de');


$translate->plural('Car', 'Cars', $number);

6.2. Méthode moderne de traduction du pluriel


Utilisez la méthode translate() pour la traduction des pluriels.

Pour utiliser la traduction de pluriels avec translate(), passez un tableau comme messageId
plutôt qu'une chaine. Ce tableau doit contenir le messageId original, celui du pluriel, une quantité
et optionnellement une locale.

1487
Zend_Translate

Exemple 909. Exemple de la méthode moderne de traduction du pluriel

Pour traduire un pluriel avec la méthode moderne, agissez comme suit:

$translate = new Zend_Translate('gettext', '/path/to/german.mo', 'de');


$translate->translate(array('Car', 'Cars', $number));

Avec cette méthode, vous pouvez utiliser n'importe quelle langue comme messageId original.

Exemple 910. Exemple de la méthode moderne de traduction du pluriel utilisant


un langage source différent

Imaginons que nous voulions utiliser du russe et que le messageId est russe et non anglais.

$translate = new Zend_Translate('gettext', '/path/to/german.mo', 'de');


$translate->translate(array('Car',
'Cars first plural',
'Cars second plural',
$number,
'ru'));

Comme vous le voyez, vous pouvez donner plus d'un pluriel, mais il faut alors spécifier la langue
pour que Zend_Translate puisse trouver les règles de pluriel appropriées.

Si vous omettez la langue, l'anglais sera utilisé et tout pluriel superflu sera ignoré.

6.3. Fichiers sources de pluriels


Toutes les sources ne supportent pas les pluriels. Voyez la liste ci-après pour les détails:

Tableau 153. Support du pluriel


Adaptateur Pluriels supportés
Array oui
Csv oui
Gettext oui
Ini non
Qt non
Tbx non
Tmx non
Xliff non
XmlTm non

Lisez la suite pour des exemples.

6.3.1. Source tableau contenant des pluriels


Un tableau de traduction contenant des pluriels devrait ressembler à ceci:

array(
'plural_0' => array(
'plural_0 (ru)',
'plural_1 (ru)',

1488
Zend_Translate

'plural_2 (ru)',
'plural_3 (ru)'
),
'plural_1' => ''
);

Dans cet exemple, plural_0 et plural_1 sont les définitions du pluriel depuis le code source.
Le tableau à l'index plural_0 possède les pluriels traduits. Regardez l'exemple suivant avec
du vrai contenu et une traduction anglais - allemand.

array(
'Car' => array(
'Auto',
'Autos'
),
'Cars' => ''
);

Si votre langue supporte plusieurs pluriels, ajoutez les simplement dans le tableau à la suite du
premier pluriel.

6.3.2. Csv et pluriels


Un fichier csv gérant des pluriels ressemble à ceci:

"plural_0";"plural_0 (ru)";"plural_1 (ru)";"plural_2 (ru)";"plural_3 (ru)"


"plural_1";

Toutes les traductions des pluriels doivent être ajoutées après le premier pluriel et tout les pluriels
suivants doivent être ajoutés après, mais sans traduction. Notez que le délimiteur est nécessaire
pour les pluriels vides.

6.3.3. Gettext et pluriels


Gettext supporte nativement les pluriels, les fichiers *.mo contiennent tout ce qui est nécessaire.

Notez que gettext ne gère pas les langues à plusieurs pluriels, utilisez un autre
adaptateur dans ce cas là.

6.4. Custom plural rules


In rare cases it could be useful to be able to define own plural rules. See chinese for example.
This language defines two plural rules. Per default it does not use plurals. But in rare cases it
uses a rule like (number == 1) ? 0 : 1.

Also when you want to use a language which has no known plural rules, and would want to
define your own rules.

This can be done by using Zend_Translate_Plural::setRule(). The method expects two


parameters which must be given. A rule, which is simply a callback to a self defined method. And
a locale for which the rule will be used.

Your rule could look like this:

public function MyRule($number) {

1489
Zend_Translate

return ($number == 10) ? 0 : 1;


}

As you see, your rule must accept one parameter. It is the number which you will use to return
which plural the translation has to use. In our example we defined that when we get a '10' the
plural definition 0 has to be used, in all other cases we're using 1.

Your rules can be as simple or as complicated as you want. You must only return an integer
value. The plural definition 0 stands for singular translation, and 1 stands for the first plural rule.

To activate your rule, and to link it to the wished locale, you have to call it like this:

Zend_Translate_Plural::setPlural('MyPlural', 'zh');

Now we linked our plural definition to the chinese language.

You can define one plural rule for every language. But you should be aware that you set the
plural rules before you are doing translations.

Define custom plurals only when needed


Zend_Translate defines plurals for most known languages. You should not
define own plurals when you are not in need. The default rules work most of time.

1490
Zend_Uri
1. Zend_Uri
1.1. Aperçu
Zend_Uri est un composant destiné à aider à la manipulation et à la validation des Uniform
Resource Identifiers (URIs). Zend_Uri existe dans le but d'aider les autres composants de
Zend Framework tels que Zend_Http_Client mais peut aussi être utilisé comme composant
individuel.

Les URIs commence toujours avec la définition de leur schéma, suivie d'un double-points. La
construction des différents schémas variant beaucoup, une fabrique est à votre disposition.
Zend_Uri possède une fabrique qui retourne des instances sous-classes d'elle même. Chaque
sous classe possède le nom du schéma dans son nom, comme Zend_Uri_<scheme>, où
<scheme> est le nom du schéma utilisé, tout en minuscule, sauf la première lettre. Une exception
à cette règle est HTTPS, qui est aussi géré par Zend_Uri_Http.

1.2. Créer un nouvel URI


Zend_Uri fabriquera un URI vierge, si seul son schéma est passé à Zend_Uri::factory().

Exemple 911. Créer un URI avec Zend_Uri::factory()

// Création d'un URI vierge


$uri = Zend_Uri::factory('http');

// $uri instanceof Zend_Uri_Http

1
Pour créer un URI à partir de rien, passez simplement le schéma à Zend_Uri::factory() .
Si un schéma non supporté lui est passé, une Zend_Uri_Exception sera levée.

Si un schéma ou URI fourni est supporté, Zend_Uri::factory() retournera une sous-classe


d'elle-même spécialisée pour le schéma à créer.

1.3. Manipuler un URI existant


Pour manipuler un URI existant, passez le entièrement à Zend_Uri::factory().

Exemple 912. Manipuler un URI existant avec Zend_Uri::factory()

// Passez l'URI complet à la fabrique


$uri = Zend_Uri::factory('http://www.zend.com');

// $uri instanceof Zend_Uri_Http

L'URI sera alors analysé et validé. S'il s'avère être invalide, une Zend_Uri_Exception sera
envoyée immédiatement. Sinon, Zend_Uri::factory() retournera une sous classe d'elle-
même qui spécialisera le schéma manipulé.
1
Actuellement, Zend_Uri ne supporte que les schémas HTTP et HTTPS

1491
Zend_Uri

1.4. Validation d'URI


La méthode Zend_Uri::check() peut être utilisée pour valider un URI.

Exemple 913. Validation d'URI avec Zend_Uri::check()

// Valide si l'URI passé est bien formé


$valid = Zend_Uri::check('http://uri.en.question');

// $valid est TRUE ou FALSE

Zend_Uri::check() retourne un simple booléen, ce qui est plus pratique que de passer par
Zend_Uri::factory() et de capturer les exceptions.

1.4.1. Autoriser les caractères "imprudents" dans les URIs


Par défaut, Zend_Uri n'acceptera pas les caractères suivants, définis par la RFC comme
"imprudents" et invalide : "{", "}", "|", "\", "^", "`". Cependant, de nombreuses
implémentations acceptent ces caractères comme valides.

Zend_Uri peut être paramètré pour accepter ces caractères "imprudents" en réglant l'option
"allow_unwise" à TRUE en utilisant la méthode Zend_Uri::setConfig() :

Exemple 914. Autoriser les caractères spéciaux dans les URIs

// Normalement, ceci devrait retourner false :


$valid = Zend_Uri::check('http://example.com/?q=this|that'); // Contient le symbole '|'

// Cependant, vous pouvez autorise les caractères "imprudents"


Zend_Uri::setConfig(array('allow_unwise' => true));
$valid = Zend_Uri::check('http://example.com/?q=this|that'); // Retournera 'true'

// Initialiser 'allow_unwise' à sa valeur par défaut FALSE


Zend_Uri::setConfig(array('allow_unwise' => false));

Zend_Uri::setConfig() paramètre les options de configuration de manière


globale. Il est recommandé de réinitialiser l'option allow_unwise à FALSE
comme dans l'exemple ci-dessus, à moins d'être certain de vouloir utiliser les
caractères "imprudents" de manière globale.

1.5. Méthodes communes


Toute instance sous-classe de Zend_Uri (par exemple Zend_Uri_Http) possède plusieurs
méthodes utiles :

1.5.1. Retrouver le schéma d'un URI


Le schéma d'un URI est la partie précédent les double-points (:). Par exemple, le schéma de
http://www.zend.com est http.

Exemple 915. Récupérer le schéma d'un objet Zend_Uri_*

$uri = Zend_Uri::factory('http://www.zend.com');

$scheme = $uri->getScheme(); // "http"

1492
Zend_Uri

La méthode getScheme() retourne une chaîne de caractères.

1.5.2. Récupérer l'URI entier


Exemple 916. Récupérer l'URI entier depuis un objet Zend_Uri_*

$uri = Zend_Uri::factory('http://www.zend.com');

echo $uri->getUri(); // "http://www.zend.com"

La méthode getUri() retourne une chaîne de caractères représentant l'URI entier.

1.5.3. Valider l'URI


Zend_Uri::factory() validera de toute façon systématiquement l'URI qui lui est passé en
paramètre. Par contre, l'URI peut devenir invalide après, s'il est modifié.

Exemple 917. Valider un objet Zend_Uri_*

$uri = Zend_Uri::factory('http://www.zend.com');

$isValid = $uri->valid(); // TRUE

La méthode valid() propose une façon de vérifier si l'URI est toujours valide.

1493
Zend_Validate
1. Introduction
Le composant Zend_Validate fournit un ensemble de validateurs usuels. Il fournit également
un mécanisme simple de chaînage permettant d'appliquer de multiples validateurs à une donnée
dans un ordre défini par l'utilisateur.

1.1. Qu'est-ce qu'un validateur ?


Un validateur examine ce qui lui est soumis suivant certaines règles et retourne un résultat
booléen, si la donnée est conforme aux exigences. Si ce n'est pas le cas, un validateur peut de
manière optionnelle fournir des informations concernant la (ou les) règle(s) non remplie(s).

Par exemple, une application Web peut réclamer qu'un identifiant comprennent entre six et douze
caractères et ne contiennent que des caractères alphanumériques. Un validateur peut être utilisé
pour s'assurer que les identifiants remplissent ces règles. Si un identifiant donné ne respecte
pas l'une ou plusieurs de ces règles, il sera utile de savoir laquelle ou lesquelles en particulier.

1.2. Utilisation basique des validateurs


Avoir défini la validation de cette manière fournit la fondation de Zend_Validate_Interface,
qui définit deux méthodes, isValid() et getMessages(). La méthode isValid() réalise
la validation sur la valeur fournie, en retournant TRUE si et seulement si la valeur respecte les
critères de validation.

Si isValid() retourne FALSE, getMessages() retourne un tableau de messages expliquant


la(es) raison(s) de l'échec de la validation. Les clés du tableau sont des chaînes courtes qui
identifient les raisons de l'échec de la validation, et les valeurs du tableau sont les chaînes de
messages humainement lisibles correspondantes. Les clés et les valeurs sont dépendantes de
la classe ; chaque classe de validation définit son propre jeu de messages d'échec de validation
et les clés uniques qui les identifient. Chaque classe possède aussi une définition de constantes
("const") qui rattachent tout identificateur à une cause d'échec de validation.

La méthode getErrors() retourne un tableau d'informations courtes qui identifient la(es)


raison(s) de l'échec de la validation. Ces chaînes sont fournies pour identifier les erreurs. Elles
sont destinées à votre code d'application, et non à être affichées pour l'utilisateur. Ces chaînes
sont dépendantes de la classe ; chaque classe de validation définit ces propres chaînes pour
identifier la cause des erreurs. Chaque classe fournit de plus des constantes (const) qui
correspondent aux identificateurs d'erreur.

La méthode getMessages() retourne des informations sur l'échec de validation


seulement pour l'appel le plus récent de isValid(). Chaque appel de
isValid() efface les messages et les erreurs déclenchées par l'appel
précédent, car il est probable que chaque appel de isValid() est réalisé pour
des données d'entrée différentes.

L'exemple suivant illustre la validation d'une adresse émail :

$validator = new Zend_Validate_EmailAddress();

if ($validator->isValid($email)) {

1494
Zend_Validate

// l'email est valide


} else {
// l'email est invalide ; affichons pourquoi
foreach ($validator->getMessages() as $messageId => $message) {
echo "Echec de validation '$messageId' : $message\n";
}
}

1.3. Messages personnalisés


Les classes de validation fournissent une méthode setMessage() avec laquelle vous pouvez
spécifier le format du message retourné par getMessages() dans le cas d'un échec de
validation. Le premier argument de cette méthode est une chaîne contenant le message d'erreur.
Vous pouvez inclure des balises dans cette chaîne qui seront substituées avec les données
appropriées du validateur. La balise %value% est supportée par tous les validateurs ; elle est
substituée par la valeur fournie à isValid(). D'autres balises peuvent être supportées aux
cas par cas par chaque classe de validation. Par exemple, %max% est une balise supportée
par Zend_Validate_LessThan. La méthode getMessageVariables() retourne un tableau
des balises de variables supportées par le validateur.

Le second paramètre optionnel est une chaîne qui identifie le modèle de message d'échec de
validation qui doit être paramètré, ce qui est pratique quand une classe de validation définit
plus d'une cause d'échec. Si vous omettez ce second argument, setMessage() considère
que le message, que vous spécifiez, s'applique au premier message déclaré dans la classe de
validation. La plupart des classes de validation n'ayant qu'un seul message d'erreur, il n'est pas
nécessaire de spécifier distinctement dans ce cas quel message vous affectez.

$validator = new Zend_Validate_StringLength(8);

$validator->setMessage(
'La chaîne \'%value%\' est trop courte ; '
. 'elle doit être au moins de %min% caractères',
Zend_Validate_StringLength::TOO_SHORT);

if (!$validator->isValid('word')) {
$messages = $validator->getMessages();
echo current($messages);

// affiche "La chaîne 'word' est trop courte ;


// elle doit être au moins de 8 caractères"
}

Vous pouvez régler des messages multiples en utilisant la méthode setMessages(). Son
argument dans ce cas est un tableau de paires clé/message.

$validator = new Zend_Validate_StringLength(array('min' => 8, 'max' => 12));

$validator->setMessages( array(
Zend_Validate_StringLength::TOO_SHORT =>
'La chaîne \'%value%\' est trop courte',
Zend_Validate_StringLength::TOO_LONG =>
'La chaîne \'%value%\' est trop longue'
));

Si votre application exige une flexibilité encore plus grande avec laquelle elle rapporte les échecs
de validation, vous pouvez accéder aux propriétés par le même nom que les balises de message
supportées par une classe de validation donnée. La propriété value est toujours accessible

1495
Zend_Validate

dans un validateur ; il s'agit de la valeur fournie comme argument à isValid(). D'autres


propriétés peuvent être supportées au cas par cas par chaque classe de validation.

$validator = new Zend_Validate_StringLength(array('min' => 8, 'max' => 12));

if (!validator->isValid('word')) {
echo 'Echec du mot : '
. $validator->value
. ' ; sa longueur n\'est pas compris entre '
. $validator->min
. ' et '
. $validator->max
. "\n";
}

1.4. Utilisation de la méthode statique is()


S'il est peu pratique de charger une classe de validation donnée et créer une instance de
validateur, vous pouvez utiliser la méthode statique Zend_Validate::is() comme appel
alternatif. Le premier argument de cette méthode est la donnée d'entrée, que vous passeriez à la
méthode isValid(). Le deuxième argument est une chaîne, qui correspond au nom de base
de la classe de validation, relativement dans l'espace de noms Zend_Validate. La méthode
is() charge automatiquement la classe, crée une instance et applique la méthode isValid()
à la donnée d'entrée.

if (Zend_Validate::is($email, 'EmailAddress')) {
// l'email est valide
}

Vous pouvez aussi fournir un tableau de paramètres destinés au constructeur de la classe, s'ils
sont nécessaires pour votre classe de validation.

if (Zend_Validate::is($value, 'Between', array(array('min' => 1, 'max' => 12)))) {


// $value est compris entre 1 et 12
}

La méthode is() retourne une valeur booléenne, la même que la méthode isValid(). Lors
de l'utilisation de la méthode statique is(), les messages d'échec de validation ne sont pas
disponibles.

L'utilisation statique peut être pratique pour invoquer un validateur ad hoc, mais si vous avez
besoin d'exécuter un validateur pour des données multiples, il est plus efficace de suivre le
premier exemple ci-dessus, créant une instance de l'objet de validation et appelant sa méthode
isValid().

De plus, la classe Zend_Filter_Input vous permet d'instancier et d'exécuter des filtres


multiples et des classes de validateurs sur demande pour traiter l'ensemble de données saisies.
Voir Section 5, « Zend_Filter_Input ».

1.4.1. Espaces de noms


When working with self defined validators you can give a forth parameter to
Zend_Validate::is() which is the namespace where your validator can be found.

if (Zend_Validate::is($value, 'MyValidator', array(array('min' => 1, 'max' => 12)),


array('FirstNamespace', 'SecondNamespace')) {

1496
Zend_Validate

// Yes, $value is ok
}

Zend_Validate allows also to set namespaces as default. This means that you can set them
once in your bootstrap and have not to give them again for each call of Zend_Validate::is().
The following code snippet is identical to the above one.

Zend_Validate::setDefaultNamespaces(array('FirstNamespace', 'SecondNamespace'));
if (Zend_Validate::is($value, 'MyValidator', array(array('min' => 1, 'max' => 12))) {
// Yes, $value is ok
}

if (Zend_Validate::is($value, 'OtherValidator', array(array('min' => 1, 'max' => 12))) {


// Yes, $value is ok
}

For your convinience there are following methods which allow the handling of namespaces:

• Zend_Validator::getDefaultNamespaces(): Returns all set default namespaces as


array.

• Zend_Validator::setDefaultNamespaces(): Sets new default namespaces and


overrides any previous set. It accepts eighter a string for a single namespace of an array for
multiple namespaces.

• Zend_Validator::addDefaultNamespaces(): Adds additional namespaces to already


set ones. It accepts eighter a string for a single namespace of an array for multiple
namespaces.

• Zend_Validator::hasDefaultNamespaces(): Returns true when one or more default


namespaces are set, and false when no default namespaces are set.

1.5. Translating messages


Validate classes provide a setTranslator() method with which you can specify a instance
of Zend_Translate which will translate the messages in case of a validation failure. The
getTranslator() method returns the set translator instance.

$validator = new Zend_Validate_StringLength(array('min' => 8, 'max' => 12));


$translate = new Zend_Translate(
'array',
array(Zend_Validate_StringLength::TOO_SHORT => 'Translated \'%value%\''),
'en'
);

$validator->setTranslator($translate);

With the static setDefaultTranslator() method you can set a instance of


Zend_Translate which will be used for all validation classes, and can be retrieved with
getDefaultTranslator(). This prevents you from setting a translator manually for all
validator classes, and simplifies your code.

$translate = new Zend_Translate(


'array',
array(Zend_Validate_StringLength::TOO_SHORT => 'Translated \'%value%\''),
'en'
);
Zend_Validate::setDefaultTranslator($translate);

1497
Zend_Validate

When you have set an application wide locale within your registry, then this locale
will be used as default translator.

Sometimes it is necessary to disable the translator within a validator. To archive this you
can use the setDisableTranslator() method, which accepts a boolean parameter, and
translatorIsDisabled() to get the set value.

$validator = new Zend_Validate_StringLength(array('min' => 8, 'max' => 12));


if (!$validator->isTranslatorDisabled()) {
$validator->setDisableTranslator();
}

It is also possible to use a translator instead of setting own messages with setMessage(). But
doing so, you should keep in mind, that the translator works also on messages you set your own.

2. Classes de validation standard


Zend Framework est fourni avec un jeu de classes de validation standard, qui sont directement
utilisables par votre application.

2.1. Alnum
Retourne TRUE si et seulement si $value contient seulement des caractères alphabétiques et
numériques. Ce validateur inclue une option permettant la validation possible des caractères
espace.

2.2. Alpha
Retourne TRUE si et seulement si $value contient seulement des caractères alphabétiques. Ce
validateur inclue une option permettant la validation possible des caractères espace.

Les caractères alphabétiques comprennent les caractères destinés à constituer


des mots dans chaque langue. Cependant l'alphabet anglais est aussi utilisé pour
les langues suivantes : chinois, japonais et coréen. La langue est spécifiée par
Zend_Locale.

2.3. Barcode
Ce validateur est instancié avec le type de code-barres suivant lequel vous souhaitez valider une
valeur. Il supporte actuellement les types de code-barres "UPC-A" (Universal Product Code) et
"EAN-13" (European Article Number), et la méthode isValid() retourne TRUE si et seulement
si la valeur fournie est validée par l'algorithme de validation du code-barres. Vous devez retirer
tous les caractères exceptés les nombres compris entre zéro et neuf (0-9) de la valeur à tester
avant de la fournir au validateur.

2.4. Between
Retourne TRUE si et seulement si $value est compris entre les valeurs minimum et maximum
définies. La comparaison inclue par défaut les bornes ($value peut égaler le minimum ou le
maximum), bien que ceci puisse être surchargé pour avoir une comparaison stricte, où $value
doit être strictement supérieur au minimum et strictement inférieur au maximum.

1498
Zend_Validate

2.5. Ccnum
Retourne TRUE si et seulement si $value respecte l'algorithme de Luhn ("module 10") pour les
numéros de cartes de crédits.

2.6. Date
Retourne TRUE si $value est une date valide au format YYYY-MM-DD. Si l'option locale est
fournie alors la date sera validé suivant le paramètre local. Enfin si l'option format est fournie
ce format est utilisé pour la validation. Pour plus de détails concernant les paramètres optionnel,
referez vous à Zend_Date::isDate().

2.7. Db_RecordExists et Db_NoRecordExists


Zend_Validate_Db_RecordExists et Zend_Validate_Db_NoRecordExists
permettent de vérifier si un enregistrement existe (ou pas) dans une table de base de données.

2.7.1. Utilisation de base


Voici un exemple basique:

//Vérifie que l'email existe bien dans la base de données


$validator = new Zend_Validate_Db_RecordExists('users', 'emailaddress');
if ($validator->isValid($emailaddress)) {
// l'adresse email existe
} else {
// l'adresse email n'existe pas, affichons les messages d'erreur
foreach ($validator->getMessages() as $message) {
echo "$message\n";
}
}

Le code ci-dessus vérifie la présence d'une adresse email $emailaddress vis à vis d'un champ
d'une table de base de données.

//Vérifie que le nom d'utilisateur n'est pas présent dans la table


$validator = new Zend_Validate_Db_NoRecordExists('users', 'username');
if ($validator->isValid($username)) {
// Le nom d'utilisateur semble absent de la table
} else {
// invalide : l'utilisateur est probablement présent dans la table
$messages = $validator->getMessages();
foreach ($messages as $message) {
echo "$message\n";
}
}

Le code ci-dessus vérifie l'absence d'un nom d'utilisateur $username vis à vis d'un champ d'une
table de base de données.

2.7.2. Exclure des enregistrement


Zend_Validate_Db_RecordExists et Zend_Validate_Db_NoRecordExists proposent
aussi un moyen de tester la base de données en excluant certaines parties de table, en passant
une clause where ou un tableau de paires "champs" "valeur".

1499
Zend_Validate

Lorsqu'un tableau est passé, l'opérateur != est utilisé et vous pouvez ainsi tester le reste de
la table.

//Vérifie qu'aucun autre utilisateur que celui dont l'id est spécifié, ne possède ce nom
$user_id = $user->getId();
$validator = new Zend_Validate_Db_NoRecordExists(
'users',
'username',
array(
'field' => 'id',
'value' => $user_id
)
);

if ($validator->isValid($username)) {
// OK
} else {
// KO
$messages = $validator->getMessages();
foreach ($messages as $message) {
echo "$message\n";
}
}

L'exemple ci dessus va vérifier qu'aucun utilisateur dont l'id n'est pas celui spécifié, possède ce
nom là $username.

La clause d'exclusion peut aussi être renseignée avec une chaine afin de pouvoir utiliser un
opérateur autre que !=.

$post_id = $post->getId();
$clause = $db->quoteInto('post_id = ?', $category_id);
$validator = new Zend_Validate_Db_RecordExists(
'posts_categories',
'post_id',
$clause
);

if ($validator->isValid($username)) {
// OK
} else {
// KO
$messages = $validator->getMessages();
foreach ($messages as $message) {
echo "$message\n";
}
}

L'exemple ci-dessus vérifie la table posts_categories pour s'assurer qu'un enregistrement


avec post_id corresponde à $category_id

2.7.3. Adaptateurs de base de données


Un adaptateur spécifique peut être passé au validateur. Dans le cas contraire, il utilisera
l'adaptateur déclaré comme étant celui par défaut:

$validator = new Zend_Validate_Db_RecordExists('users', 'id', null, $dbAdapter);

1500
Zend_Validate

2.7.4. Nom des bases de données


Vous pouvez spécifier un nom de base de données (schéma) pour l'adaptateur PostgreSQL et
DB/2 simplement grâce à un tableau possédant les clés table et schema. Voici un exemple:

$validator = new Zend_Validate_Db_RecordExists(array('table' => 'users',


'schema' => 'my'), 'id');

2.8. Digits
Retourne TRUE si et seulement si $value contient seulement des caractères numériques.

2.9. EmailAddress
Zend_Validate_EmailAddress permet de valider une adresse émail. Ce validateur éclate
d'abord l'adresse émail entre partie locale et domaine et essaie de valider ces deux parties
conformément aux spécifications des adresses émail et des noms de domaine.

Utilisation de base

Exemple basique :

$validateur = new Zend_Validate_EmailAddress();


if ($validateur->isValid($email)) {
// l'email est valide
} else {
// l'email est invalide ; afficher pourquoi
foreach ($validateur->getMessages() as $message) {
echo "$message\n";
}
}

Ceci validera l'adresse émail $email et, en cas d'échec, fournira des messages d'erreur
informatifs via $validator->getMessages().

Parties locales complexes

Zend_Validate_EmailAddress validera toute adresse émail conforme à la


RFC2822. Comme par exemple bob@domaine.com, bob+jones@domaine.fr,
"bob@jones"@domaine.com et "bob jones"@domaine.com. Quelques formats d'émail
obsolètes ne seront pas validés (comme tout émail contenant un retour chariot ou un caractère
"\").

Validation de différents types de noms de domaine

La partie domaine d'une adresse émail est validée via Zend_Validate_Hostname. Par défaut,
seules les domaines qualifiés sous la forme domaine.com sont acceptés, même si, il vous est
possible d'accepter les adresses IP et les domaines locaux également.

Afin de réaliser cette opération, il vous faut instancier Zend_Validate_EmailAddress en


lui passant un paramètre indiquant le type de nom de domaine à accepter. Les détails
sont disponibles dans Zend_Validate_EmailAddress mais vous trouverez ci-dessous un
exemple illustrant comment accepter les noms de domaines qualifiés et les hôtes locaux :

$validateur = new Zend_Validate_EmailAddress(Zend_Validate_Hostname::ALLOW_DNS | Zend_Valida


if ($validateur->isValid($email)) {

1501
Zend_Validate

// l'email est valide


} else {
// l'email est invalide ; afficher pourquoi
foreach ($validateur->getMessages() as $message) {
echo "$message\n";
}
}

Vérification que le nom de domaine accepte réellement l'émail

Le fait qu'une adresse électronique est dans un format correct, ne signifie pas nécessairement
que l'adresse électronique existe en réalité. Pour aider résoudre ce problème, vous pouvez
utiliser la validation MX pour vérifier si une entrée MX (l'émail) existe dans le l'enregistrement du
DNS pour le nom de domaine de l'émail. Cela vous dit que le nom de domaine accepte l'émail,
mais ne vous dit pas que l'adresse électronique elle-même est valable.

La vérification MX n'est pas active par défaut et est seulement supporté par des plates-formes
UNIX pour l'instant. Pour activer la vérification MX vous pouvez passer un deuxième paramètre
au constructeur Zend_Validate_EmailAddress.

$validator =
new Zend_Validate_EmailAddress(Zend_Validate_Hostname::ALLOW_DNS,
true);

Alternativement vous pouvez passer soit TRUE soit FALSE à $validator-


>setValidateMx() pour activer ou désactiver la validation MX.

En activant ce paramètre, les fonctions de réseau seront utilisés pour vérifier la présence d'un
enregistrement MX sur le nom de domaine de l'adresse électronique que vous voulez valider.
Faîtes cependant attention, cela ralentira probablement votre scénario.

Valider les noms de domaines internationaux

Zend_Validate_EmailAddress peut aussi vérifier les caractères internationaux qui existent


dans quelques domaines. Ceci est connu comme le support de Nom de Domaine International
(IDN). Celui-ci est activé par défaut, quoique vous puissiez le mettre hors service en
changeant le paramètre via l'objet interne Zend_Validate_Hostname qui existe dans
Zend_Validate_EmailAddress.

$validator->hostnameValidator->setValidateIdn(false);

De plus amples informations concernant l'utilisation de setValidateIdn() sont présentes


dans la documentation de Zend_Validate_Hostname.

Notez cependant que les IDNs sont seulement validés si vous autorisez la validation des nom
de domaines.

Validation des "Top Level Domains"

Par défaut un nom de domaine sera vérifié grâce à une liste de TLDs connus. Ceci est activé
par défaut, quoique vous puissiez le mettre hors service en changeant le paramètre via l'objet
Zend_Validate_Hostname interne qui existe dans Zend_Validate_EmailAddress.

$validator->hostnameValidator->setValidateTld(false);

De plus amples informations concernant l'utilisation de setValidateTld() sont présentes


dans la documentation de Zend_Validate_Hostname.

1502
Zend_Validate

Notez cependant que les TLDs sont seulement validés si vous autorisez la validation des nom
de domaines.

2.10. Float
Retourne TRUE si et seulement si $value est une valeur en virgule flottante. A partir de Zend
Framework 1.8 ce validateur prend en considération la locale courante issue du navigateur,
de l'environnement ou de l'application. Vous pouvez bien sûr utiliser les accesseurs get/
setLocale pour changer ou la fournir au moment de la création de l'instance de ce validateur.

2.11. GreaterThan
Retourne TRUE si et seulement si $value est supérieure à une valeur minimum fournie.

2.12. Hex
Retourne TRUE si et seulement si $value contient seulement des caractères numériques
hexadécimaux.

2.13. Hostname
Zend_Validate_Hostname vous permet de valider un nom de domaine sur la base d'un
ensemble de spécifications connues. Il est ainsi possible de valider trois types différents de noms
de domaine : un nom de domaine qualifié (ex : domaine.com), une adresse IP (ex : 1.2.3.4) ou
un nom de domaine local (ex : localhost). Par défaut, seul les noms de domaine qualifiés sont
acceptés.

Utilisation basique

Exemple simple :

$validateur = new Zend_Validate_Hostname();


if ($validateur->isValid($domaine)) {
// le nom de domaine est valide
} else {
// le nom de domaine est invalide ; afficher pourquoi
foreach ($validateur->getMessages() as $message) {
echo "$message\n";
}
}

Ceci validera le domaine $domaine et, en cas d'échec, fournira des messages d'erreur
informatifs via $validator->getMessages().

Validation de différents types de noms de domaine

Il peut se trouver que vous souhaitez valider des adresses IP, des noms de domaine locaux ou
toute combinaison de tous les types disponibles. Cette opération peut être effectuée en passant
un paramètre à Zend_Validate_Hostname au moment de l'instanciation. Le paramètre doit
être un entier qui détermine quels types de noms de domaine sont admis. Il est recommandé
d'utiliser les constantes de la classe Zend_Validate_Hostname.

Les constantes de Zend_Validate_Hostname sont : ALLOW_DNS qui autorise uniquement


les noms de domaine qualifiés, ALLOW_IP qui autorise les adresses IP, ALLOW_LOCAL qui

1503
Zend_Validate

autorise les domaines locaux et ALLOW_ALL qui autorise les trois types précédents. Pour vérifier
uniquement les adresses IP, vous pouvez utiliser l'exemple suivant :

$validateur = new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_IP);


if ($validateur->isValid($hostname)) {
// le nom de domaine est valide
} else {
// le nom de domaine est invalide ; afficher pourquoi
foreach ($validateur->getMessages() as $message) {
echo "$message\n";
}
}

Vous pouvez utiliser ALLOW_ALL pour accepter tous les types de domaines. De même, vous
pouvez créer des configurations combinant ces différents types. Par exemple, pour accepter les
domaines qualifiés et les domaines locaux, instanciez votre objet Zend_Validate_Hostname
de la manière suivante :

$validateur = new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_DNS |


Zend_Validate_Hostname::ALLOW_IP);

Validation de Nom de Domaine International (IDN)

Certains noms de domaines nationaux (Country Code Top Level Domains ou ccTLD), comme .de
(Allemagne), supporte les caractères internationaux dans leurs noms de domaine. Ceci est
connu sous le nom de Nom de Domaine International (IDN). Ces domaines peuvent être
vérifiés par Zend_Validate_Hostname grâce aux caractères étendus qui sont utilisés dans
le processus de validation.

Jusqu'à maintenant plus de 50 ccTLDs supportent les domaines IDN.

Pour vérifier un domaine IDN c'est aussi simple que d'utiliser le validateur standard de nom
de domaine puisque la validation IDN est activé par défaut. Si vous voulez mettre hors
service la validation IDN, cela peut être fait par le passage d'un paramètre au constructeur
Zend_Validate_Hostname ou via la méthode $validator->setValidateIdn().

Vous pouvez aussi désactiver la validation IDN en passant un second paramètre au constructeur
du Zend_Validate_Hostname comme ceci :

$validator =
new Zend_Validate_Hostname(
array(
'allow' => Zend_Validate_Hostname::ALLOW_DNS,
'idn' => false
)
);

Alternativement vous pouvez passer soit TRUE soit FALSE à $validator-


>setValidateIdn() pour activer ou désactiver la validation IDN. Si vous essayez de vérifier
un nom de domaine IDN qui n'est pas actuellement soutenu il est probable qu'il retournera
une erreur s'il y a des caractères internationaux. Quand un fichier de ccTLD spécifiant les
caractères supplémentaires n'existe pas dans "Zend/Validate/Hostname",une validation de nom
de domaine normale est réalisée.

Notez cependant que les IDNs sont seulement validés si vous autorisez la validation des noms
de domaine.

1504
Zend_Validate

Validation des "Top Level Domains"

Par défaut un nom de domaine sera vérifié grâce à une liste de TLDs connus. Si cette
fonctionnalité n'est pas nécessaire, elle peut être désactivée de la même façon que la
désactivation du support des IDNs. Vous pouvez désactiver la validation TLD en passant
un troisième paramètre au constructeur de Zend_Validate_Hostname. Dans l'exemple ci-
dessous, la validation IDN est supportée via le second paramètre.

$validator =
new Zend_Validate_Hostname(
array(
'allow' => Zend_Validate_Hostname::ALLOW_DNS,
'idn' => true,
'tld' => false
)
);

Alternativement vous pouvez passer soit TRUE soit FALSE à $validator-


>setValidateTld() pour activer ou désactiver la validation TLD.

Notez cependant que les TLDs sont seulement validés si vous autorisez la validation des noms
de domaine.

2.14. Iban
Retourne TRUE si et seulement si $value contient un IBAN valide (International Bank Account
Number = Numéro de compte bancaire international). Les numéros IBAN sont validés suivant le
pays dans lequel ils sont utilisés et par un somme de contrôle.

Il existe deux manières de valider les numéros IBAN. En premier lieu, vous pouvez fournir une
locale qui représente un pays. Tout numéro IBAN fourni sera donc validé suivant ce pays.

$validator = new Zend_Validate_Iban('de_AT');


$iban = 'AT611904300234573201';
if ($validator->isValid($iban)) {
// IBAN paraît être valide
} else {
// IBAN est invalide
foreach ($validator->getMessages() as $message) {
echo "$message\n";
}
}

Vous pouvez aussi vouloir valider les numéros IBAN pour des pays uniques. La manière la plus
simple est donc de ne pas fournir de locale comme dans l'exemple suivant.

$validator = new Zend_Validate_Iban();


$iban = 'AT611904300234573201';
if ($validator->isValid($iban)) {
// IBAN paraît être valide
} else {
// IBAN est invalide
}

Mais ceci montre un gros problème : si vous ne devez accepter que les numéros IBAN que pour
un pays en particulier, par exemple l'Allemagne, alors les numéros IBAN des autres pays seront

1505
Zend_Validate

aussi valides. Dans ce cas, souvenez vous d'une chose : quand vous devez valider un numéro
IBAN pour un pays donné, vous avez juste à fournir la locale correspondante. Et quand vous
acceptez tous les numéros IBAN sans restriction de pays, enlevez simplement cette locale.

2.15. InArray
Retourne TRUE si et seulement si $value est contenue dans un tableau. Si l'option stricte est
à TRUE, alors le type de $value est aussi vérifié.

2.16. Int
Retourne TRUE si et seulement si $value est une valeur entière. A partir de Zend Framework 1.8
ce validateur prend en considération la locale courante issue du navigateur, de l'environnement
ou de l'application. Vous pouvez bien sûr utiliser les accesseurs get/setLocale pour changer
ou la fournir au moment de la création de l'instance de ce validateur.

2.17. Ip
Retourne TRUE si et seulement si $value est une adresse IP valide.

2.18. LessThan
Retourne TRUE si et seulement si $value est inférieure à une valeur maximum fournie.

2.19. NotEmpty
Retourne TRUE si et seulement si $value est une valeur non vide.

2.20. Regex
Retourne TRUE si et seulement si $value respecte une expression régulière fournie.

2.21. Validateurs de Sitemap


Les validateurs suivant sont conformes au protocole XML Sitemap.

2.21.1. Sitemap_Changefreq
Valide si oui ou non une chaîne utilisable en tant qu'élément "changefreq" dans un document
XML Sitemap. Les valeurs valides sont : "always", "hourly", "daily", "weekly", "monthly", "yearly",
or "never".

Retourne TRUE si et seulement si la valeur est une chaîne et qu'elle vaut une dès fréquences
ci-dessus.

2.21.2. Sitemap_Lastmod
Valide si oui ou non une chaîne utilisable en tant qu'élément "lastmod" dans un document XML
Sitemap. L'élément "lasmod" doit contenir une date sous la forme W3C, optionnellement en
omettant les informations concernant l'heure.

Retourne TRUE si et seulement si la valeur est une chaîne et qu'elle est valide suivant le
protocole.

1506
Zend_Validate

Exemple 918. Validateur de "lastmod" Sitemap

$validator = new Zend_Validate_Sitemap_Lastmod();


$validator->isValid('1999-11-11T22:23:52-02:00'); // true
$validator->isValid('2008-05-12T00:42:52+02:00'); // true
$validator->isValid('1999-11-11'); // true
$validator->isValid('2008-05-12'); // true
$validator->isValid('1999-11-11t22:23:52-02:00'); // false
$validator->isValid('2008-05-12T00:42:60+02:00'); // false
$validator->isValid('1999-13-11'); // false
$validator->isValid('2008-05-32'); // false
$validator->isValid('yesterday'); // false

2.21.3. Sitemap_Loc
Valide si oui ou non une chaîne utilisable en tant qu'élément "loc" dans un document XML
Sitemap. Ceci utilise en interne la méthode Zend_Form::check(). Vous pouvez en lire
davantage avec la validation d'URI.

2.21.4. Sitemap_Priority
Valide si oui ou non une valeur est utilisable en tant qu'élément "priority" dans un document XML
Sitemap. La valeur doit être un nombre compris entre 0.0 et 1.0. Ce validateur accepte à la fois
des valeurs numériques ou textuelles.

Exemple 919. Validateur de "priority" Sitemap

$validator = new Zend_Validate_Sitemap_Priority();


$validator->isValid('0.1'); // true
$validator->isValid('0.789'); // true
$validator->isValid(0.8); // true
$validator->isValid(1.0); // true
$validator->isValid('1.1'); // false
$validator->isValid('-0.4'); // false
$validator->isValid(1.00001); // false
$validator->isValid(0xFF); // false
$validator->isValid('foo'); // false

2.22. StringLength
Retourne TRUE si et seulement si la longueur de la chaîne $value est supérieure à une valeur
minimum et inférieure à une valeur maximum (quand l'option max n'est pas à NULL). La méthode
setMin() lève une exception si la valeur fournie pour la longueur minimum est supérieure à
celle fournie pour la longueur maximum, et la méthode setMax() lève une exception si la valeur
fournie pour la longueur maximum est supérieure à celle fournie pour la longueur minimum.
Cette classe supporte l'UTF-8 et les autres encodages, en se basant sur la valeur courante de
iconv.internal_encoding . Si vous avez besoin de régler un autre encodage, vous pouvez
le faire avec les accesseurs getEncoding() et setEncoding().

3. Chaînes de validation
Souvent, de multiples validations doivent être appliquées à une valeur dans un ordre particulier.
Le code suivant décrit une méthode permettant de solutionner l'exemple de l'introduction, dans
lequel un identifiant doit contenir précisément entre 6 et 12 caractères alphanumériques.

// Creation d'une chaine de validateurs et ajout de validateurs

1507
Zend_Validate

$validateurChaine = new Zend_Validate();


$validateurChaine->addValidator(
new Zend_Validate_StringLength(array('min' => 6,
'max' => 12)))
->addValidator(new Zend_Validate_Alnum());

// Validation de l'identifiant
if ($validateurChaine->isValid($identifiant)) {
// l'identifiant est testé avec succès
} else {
// l'identifiant échoue aux tests, afficher pourquoi
foreach ($validateurChaine->getMessages() as $message) {
echo "$message\n";
}
}

Les validateurs sont exécutés dans leur ordre d'ajout à Zend_Validate. Dans l'exemple ci-
dessus, l'identifiant est d'abord testé pour vérifier que sa longueur est bien comprise entre
6 et 12 caractères, puis ensuite testé pour vérifier qu'il ne contient bien que des caractères
alphanumériques. Le second test est exécuté quelque soit le résultat du précédent. Ainsi, dans le
cas où les deux tests échouent, getMessages() retournera un message d'échec pour chacun
des validateurs.

Dans certains cas, il peut être utile d'interrompre le processus si l'un des tests échoue.
Zend_Validate permet ce cas de figure via l'usage du deuxième paramètre de la méthode
addValidator(). En positionnant $breakChainOnFailure à TRUE, le validateur ajouté
interrompra la procédure de test s'il échoue, ce qui permet d'éviter de lancer tout autre test qui
serait inutile ou inapproprié dans ce cas de figure. Si l'exemple précédent était écrit comme suit,
la validation alphanumérique ne serait pas lancé si la vérification de la longueur de la valeur
échouait :

$validateurChaine->addValidator(
new Zend_Validate_StringLength(array('min' => 6,
'max' => 12)),
true)
->addValidator(new Zend_Validate_Alnum());

Tout objet qui implémente Zend_Validate_Interface peut être utilisé dans une chaîne de
validation.

4. Écrire des validateurs


Zend_Validate fournit un ensemble de validateurs habituellement nécessaires, mais
inévitablement, les développeurs souhaiteront écrire des validateurs sur mesure pour leurs
besoins particuliers. La méthode d'écriture d'un validateur personnalisé est décrit dans cette
section.

Zend_Validate_Interface définit trois méthodes, isValid(), getMessages(), et


getErrors(), qui peuvent être implémentées par des classes d'utilisateur afin de
créer les objets de validation sur mesure. Un objet qui implémente l'interface
Zend_Validate_Interface peut être ajouté à une chaîne de validateur avec
Zend_Validate::addValidator(). De tels objets peuvent également être employés avec
Zend_Filter_Input.

Comme vous avez déjà pu déduire de la description ci-dessus de


Zend_Validate_Interface, les classes de validation fournie avec Zend Framework retourne

1508
Zend_Validate

une valeur booléenne pour savoir si une valeur est validée ou non. Elles fournissent également
des informations sur la raison pour laquelle la validation a échoué sur une valeur. La mise
à disposition de ces raisons d'échec de validation peut être utilisée par une application dans
différents buts, tels que fournir des statistiques pour l'analyse de la facilité d'utilisation.

La fonctionnalité de base de message d'échec de validation est implémentée dans


Zend_Validate_Abstract. Pour inclure cette fonctionnalité en créant une classe de
validation, étendez simplement Zend_Validate_Abstract. Dans la classe étendue vous
implémenteriez la logique de la méthode isValid() et définiriez les variables de message et
les modèles de message qui correspondent aux types d'échecs de validation qui peuvent se
produire. Si une valeur ne passe pas vos essais de validation, alors isValid() devrait renvoyer
FALSE. Si la valeur passe vos essais de validation, alors isValid() devrait renvoyer TRUE.

En général, la méthode isValid() ne devrait lever aucune exception, excepté où il est


impossible de déterminer si la valeur d'entrée est valide. Quelques exemples de cas raisonnables
pour lever une exception pourraient être si un fichier ne peut pas être ouvert, un serveur de LDAP
ne pourraient pas être contacté, ou une connexion de base de données est indisponible, où
quand une telle chose peut être exigée pour que le succès ou l'échec de validation soit déterminé.

Exemple 920. Création d'une simple classe de validation

L'exemple suivant démontre comment un validateur personnalisé très simple pourrait être
écrit. Dans ce cas-ci les règles de validation sont simplement que la valeur d'entrée doit être
une valeur en virgule flottante.

class MonValidateur_Float extends Zend_Validate_Abstract


{
const FLOAT = 'float';

protected $_messageTemplates = array(


self::FLOAT => "'%value%' n'est pas une valeur en virgule flottante"
);

public function isValid($value)


{
$this->_setValue($value);

if (!is_float($value)) {
$this->_error();
return false;
}

return true;
}
}

La classe définit un modèle pour son message unique d'échec de validation, qui inclut le
paramètre magique intégré, %value%. L'appel à _setValue() prépare l'objet pour insérer
automatiquement la valeur examinée dans le message d'échec, si la validation de la valeur
échoue. L'appel à _error() trace la raison d'échec de validation. Puisque cette classe
définit seulement un message d'échec, il n'est pas nécessaire de fournir à _error() le
nom du modèle de message d'échec.

1509
Zend_Validate

Exemple 921. Écriture d'une classe de validation ayant des conditions de


dépendances
L'exemple suivant démontre un ensemble plus complexe de règles de validation, où on
l'exige que la valeur d'entrée doit être numérique et dans la plage des valeurs limites
minimum et maximum. Une valeur d'entrée ferait échouer la validation pour exactement une
des
••Ces
Laraisons
valeur suivantes
d'entrée : inférieure
n'est pas numérique.
• La valeur
valeur d'entrée
Laraisons d'entrée est
est validation
d'échec de supérieure que
quela
sont lavaleur
valeur
alors permise
permise
traduites minimum.
maximum.
dans les définitions de la classe :
class MonValidateur_NumericBetween extends Zend_Validate_Abstract
{
const MSG_NUMERIC = 'msgNumeric';
const MSG_MINIMUM = 'msgMinimum';
const MSG_MAXIMUM = 'msgMaximum';

public $minimum = 0;
public $maximum = 100;

protected $_messageVariables = array(


'min' => 'minimum',
'max' => 'maximum'
);

protected $_messageTemplates = array(


self::MSG_NUMERIC => "'%value%' n'est pas numérique",
self::MSG_MINIMUM => "'%value%' doit être supérieure à '%min%'",
self::MSG_MAXIMUM => "'%value%' doit être inférieure à '%max%'"
);

public function isValid($value)


{
$this->_setValue($value);

if (!is_numeric($value)) {
$this->_error(self::MSG_NUMERIC);
return false;
}

if ($value < $this->minimum) {


$this->_error(self::MSG_MINIMUM);
return false;
}

if ($value > $this->maximum) {


$this->_error(self::MSG_MAXIMUM);
return false;
}

return true;
}
}
Les propriétés publiques $minimum et $maximum ont été établies pour fournir les frontières
minimum et maximum d'une valeur pour qu'elle soit validée avec succès. La classe définit
également deux variables de message qui correspondent aux propriétés publiques et
permettent que min et max soient employés dans des modèles de message en tant que
paramètres
Noter que simagiques,
n'importe comme avec value.
quel élément de la validation vérifié dans isValid() échoue, un
message approprié d'échec est préparé, et la méthode renvoie immédiatement FALSE. Ces
règles de validation sont donc séquentiellement dépendantes. C'est-à-dire, que si un essai
échoue, il n'y a aucun besoin d'examiner les règles suivantes de validation. Ce besoin peut
exister, cependant. L'exemple suivant illustre comment écrire une classe ayant des règles
indépendantes de validation, où l'objet de validation peut renvoyer des raisons multiples
pour lesquelles une tentative particulière de validation a échoué.

1510
Zend_Validate

Exemple 922. Validation avec des conditions indépendantes, avec raisons


multiples
Considérons d'échecd'une classe de validation pour le contrôle de résistance d'un mot de
l'écriture
passe - quand un utilisateur est requis afin de choisir un mot de passe qui respecte certains
critères pour aider à la sécurisation des comptes d'utilisateur. Supposons que les critères
de
•• estsécurité de mot
au moins unede passe imposent
longueur de que le mot de passe :
8 caractères,
contient au moins une lettre majuscule,
••Laet
contient auau
contient moins
moinsuneunlettre minuscule,
caractère de
classe suivante implémente ces critères chiffre.
de validation :
class MonValidateur_PasswordStrength extends Zend_Validate_Abstract
{
const LENGTH = 'length';
const UPPER = 'upper';
const LOWER = 'lower';
const DIGIT = 'digit';

protected $_messageTemplates = array(


self::LENGTH =>
"'%value%' doit avoir une longueur d'au moins 8 caractères",
self::UPPER =>
"'%value%' doit contenir au moins une lettre majuscule",
self::LOWER =>
"'%value%' doit contenir au moins une lettre minuscule",
self::DIGIT =>
"'%value%' doit contenir au moins un chiffre"
);

public function isValid($value)


{
$this->_setValue($value);

$isValid = true;

if (strlen($value) < 8) {
$this->_error(self::LENGTH);
$isValid = false;
}

if (!preg_match('/[A-Z]/', $value)) {
$this->_error(self::UPPER);
$isValid = false;
}

if (!preg_match('/[a-z]/', $value)) {
$this->_error(self::LOWER);
$isValid = false;
}

if (!preg_match('/\d/', $value)) {
$this->_error(self::DIGIT);
$isValid = false;
}

return $isValid;
}
}
Noter que les quatre critères d'essais dans isValid() ne renvoient pas immédiatement
FALSE. Ceci permet à la classe de validation de fournir toutes les raisons pour lesquelles
le mot de passe d'entrée n'a pas réussi à remplir les conditions de validation. Si, par
exemple, un utilisateur entre la chaîne "#$%" comme mot de passe, isValid() entraînera
que les quatre messages d'échec de validation seront retournés lors de l'appel suivant à
getMessages().

1511
Zend_Validate

5. Messages de validation
Chaque validateur basé sur Zend_Validate propose un ou plusieurs messages dans le cas
d'un echec. Vous pouvez utiliser ces informations pour créer vos propres messages ou pour
traduire les messages présents. La table suivante liste tous les messages retournés par tous
les validateurs.

Tableau 154. Messages de validation disponibles

Validator Constant Message


NOT_ALNUM '%value%' has not only
Alnum alphabetic and digit characters
STRING_EMPTY '%value%' is an empty string
NOT_ALPHA '%value%' has not only
Alpha alphabetic characters
STRING_EMPTY '%value%' is an empty string
Barcode --- messages are thrown by a
subclass
INVALID '%value%' is an invalid EAN-13
barcode
INVALID_LENGTH '%value%' should be 13
Barcode_Ean13
characters
NOT_NUMERIC '%value%' should contain only
numeric characters
INVALID '%value%' is an invalid UPC-A
barcode
Barcode_UpcA
INVALID_LENGTH '%value%' should be 12
characters
NOT_BETWEEN '%value%' is not between
'%min%' and '%max%',
inclusively
Between
NOT_BETWEEN_STRICT '%value%' is not strictly
between '%min%' and '%max
%'
LENGTH '%value%' must contain
between 13 and 19 digits
Ccnum
CHECKSUM Luhn algorithm (mod-10
checksum) failed on '%value%'
FALSEFORMAT '%value%' does not fit given
date format
Date
INVALID '%value%' does not appear to
be a valid date
ERROR_NO_RECORD_FOUND No record matching %value%
was found
Db_Abstract
ERROR_RECORD_FOUND A record matching %value%
was found

1512
Zend_Validate

Validator Constant Message


NOT_DIGITS '%value%' contains not only
Digits digit characters
STRING_EMPTY '%value%' is an empty string
INVALID '%value%' is not a valid email
address in the basic format
local-part@hostname
INVALID_FORMAT '%value%' is not a valid email
address in the basic format
local-part@hostname
INVALID_HOSTNAME '%hostname%' is not a valid
hostname for email address
'%value%'
INVALID_MX_RECORD '%hostname%' does not
appear to have a valid MX
EmailAddress record for the email address
'%value%'
DOT_ATOM '%localPart%' not matched
against dot-atom format
QUOTED_STRING '%localPart%' not matched
against quoted-string format
INVALID_LOCAL_PART '%localPart%' is not a valid
local part for email address
'%value%'
LENGTH_EXCEEDED '%value%' exceeds the
allowed length
TOO_MUCH Too much files, maximum
'%max%' are allowed but
'%count%' are given
File_Count
TOO_LESS Too less files, minimum '%min
%' are expected but '%count%'
are given
DOES_NOT_MATCH The file '%value%' does not
match the given crc32 hashes
NOT_DETECTED There was no crc32 hash
File_Crc32
detected for the given file
NOT_FOUND The file '%value%' could not be
found
FALSE_EXTENSION The file '%value%' has a false
extension
File_ExcludeExtension
NOT_FOUND The file '%value%' was not
found
FALSE_TYPE The file '%value%' has a false
mimetype of '%type%'
File_ExcludeMimeType
NOT_DETECTED The mimetype of file '%value%'
could not been detected

1513
Zend_Validate

Validator Constant Message


NOT_READABLE The file '%value%' can not be
read
File_Exists DOES_NOT_EXIST The file '%value%' does not
exist
FALSE_EXTENSION The file '%value%' has a false
extension
File_Extension
NOT_FOUND The file '%value%' was not
found
TOO_BIG All files in sum should have a
maximum size of '%max%' but
'%size%' were detected
TOO_SMALL All files in sum should have a
File_FilesSize
minimum size of '%min%' but
'%size%' were detected
NOT_READABLE One or more files can not be
read
DOES_NOT_MATCH The file '%value%' does not
match the given hashes
NOT_DETECTED There was no hash detected
File_Hash
for the given file
NOT_FOUND The file '%value%' could not be
found
WIDTH_TOO_BIG Maximum allowed width for
image '%value%' should be
'%maxwidth%' but '%width%'
detected
WIDTH_TOO_SMALL Minimum expected width for
image '%value%' should be
'%minwidth%' but '%width%'
detected
HEIGHT_TOO_BIG Maximum allowed height for
image '%value%' should be
File_ImageSize '%maxheight%' but '%height%'
detected
HEIGHT_TOO_SMALL Minimum expected height for
image '%value%' should be
'%minheight%' but '%height%'
detected
NOT_DETECTED The size of image '%value%'
could not be detected
NOT_READABLE The image '%value%' can not
be read
FALSE_TYPE The file '%value%' is
File_IsCompressed not compressed, '%type%'
detected

1514
Zend_Validate

Validator Constant Message


NOT_DETECTED The mimetype of file '%value%'
could not been detected
NOT_READABLE The file '%value%' can not be
read
FALSE_TYPE The file '%value%' is no image,
'%type%' detected
NOT_DETECTED The mimetype of file '%value%'
File_IsImage
could not been detected
NOT_READABLE The file '%value%' can not be
read
DOES_NOT_MATCH The file '%value%' does not
match the given md5 hashes
NOT_DETECTED There was no md5 hash
File_Md5
detected for the given file
NOT_FOUND The file '%value%' could not be
found
FALSE_TYPE The file '%value%' has a false
mimetype of '%type%'
NOT_DETECTED The mimetype of file '%value%'
File_MimeType
could not been detected
NOT_READABLE The file '%value%' can not be
read
File_NotExists DOES_EXIST The file '%value%' does exist
DOES_NOT_MATCH The file '%value%' does not
match the given sha1 hashes
NOT_DETECTED There was no sha1 hash
File_Sha1
detected for the given file
NOT_FOUND The file '%value%' could not be
found
TOO_BIG Maximum allowed size for file
'%value%' is '%max%' but
'%size%' detected
TOO_SMALL Minimum expected size for
File_Size
file '%value%' is '%min%' but
'%size%' detected
NOT_FOUND The file '%value%' could not be
found
INI_SIZE The file '%value%' exceeds the
defined ini size
FORM_SIZE The file '%value%' exceeds the
File_Upload defined form size
PARTIAL The file '%value%' was only
partially uploaded

1515
Zend_Validate

Validator Constant Message


NO_FILE The file '%value%' was not
uploaded
NO_TMP_DIR No temporary directory was
found for the file '%value%'
CANT_WRITE The file '%value%' can't be
written
EXTENSION The extension returned an
error while uploading the file
'%value%'
ATTACK The file '%value%' was illegal
uploaded, possible attack
FILE_NOT_FOUND The file '%value%' was not
found
UNKNOWN Unknown error while uploading
the file '%value%'
TOO_MUCH Too much words, maximum
'%max%' are allowed but
'%count%' were counted
TOO_LESS Too less words, minimum
File_WordCount
'%min%' are expected but
'%count%' were counted
NOT_FOUND The file '%value%' could not be
found
Float NOT_FLOAT '%value%' does not appear to
be a float
GreaterThan NOT_GREATER '%value%' is not greater than
'%min%'
Hex NOT_HEX '%value%' has not only
hexadecimal digit characters
IP_ADDRESS_NOT_ALLOWED '%value%' appears to be an IP
address, but IP addresses are
not allowed
UNKNOWN_TLD '%value%' appears to be a
DNS hostname but cannot
match TLD against known list
INVALID_DASH '%value%' appears to be a
DNS hostname but contains a
Hostname dash (-) in an invalid position
INVALID_HOSTNAME_SCHEMA '%value%' appears to be a
DNS hostname but cannot
match against hostname
schema for TLD '%tld%'
UNDECIPHERABLE_TLD '%value%' appears to be a
DNS hostname but cannot
extract TLD part

1516
Zend_Validate

Validator Constant Message


INVALID_HOSTNAME '%value%' does not match the
expected structure for a DNS
hostname
INVALID_LOCAL_NAME '%value%' does not appear to
be a valid local network name
LOCAL_NAME_NOT_ALLOWED '%value%' appears to be a
local network name but local
network names are not allowed
NOTSUPPORTED '%value%' does not have IBAN
FALSEFORMAT '%value%' has a false format
Iban
CHECKFAILED '%value%' has failed the IBAN
check
NOT_SAME The token '%token%' does not
match the given token '%value
Identical %'
MISSING_TOKEN No token was provided to
match against
InArray NOT_IN_ARRAY '%value%' was not found in the
haystack
Int NOT_INT '%value%' does not appear to
be an integer
Ip NOT_IP_ADDRESS '%value%' does not appear to
be a valid IP address
LessThan NOT_LESS '%value%' is not less than
'%max%'
NotEmpty IS_EMPTY Value is required and can't be
empty
Regex NOT_MATCH '%value%' does not match
against pattern '%pattern%'
TOO_SHORT '%value%' is less than %min%
characters long
StringLength
TOO_LONG '%value%' is greater than
%max% characters long

Il est possible de récupérer tous les messages d'erreurs d'un validator grâce à sa méthode
getMessageTemplates(). Celle-ci retourne un tableau.

$validator = new Zend_Validate_Alnum();


$messages = $validator->getMessageTemplates();

5.1. Limiter la taille d'un message de validation


Il peut être nécessaire parfois de limiter la taille en caractères des messages d'erreur retournés.
par exemple si une vue n'autorise que 100 caractères par ligne. Zend_Validate propose une
telle option.

1517
Zend_Validate

La taille actuelle est Zend_Validate::getMessageLength(). -1 signifie que le message ne


sera pas tronqué et entièrement retourné, c'est le comportement par défaut.

Pour limiter la taille, utilisez Zend_Validate::setMessageLength(). Lorsque la taille


excède cette valeur, le message sera alors tronqué et suivi de '...'.

Zend_Validate::setMessageLength(100);

Notez que la taille des messages affecte aussi les messages personnalisés
enregistrés, si le validateur considéré étend Zend_Validate_Abstract.

1518
Zend_Version
1. Lire la version de Zend Framework
Zend_Version fournit la constante de classe Zend_Version::VERSION qui contient une
chaîne identifiant la version courante de Zend Framework. Zend_Version::VERSION contient
"1.7.2", par exemple.

La méthode statique Zend_Version::compareVersion($version) est basée sur la


fonction PHP version_compare(). La méthode retourne -1 si la $version fournie est plus
ancienne que la version courante de Zend Framework, 0 si c'est la même, et +1 si la $version
fournie est plus récente que la version courante de Zend Framework.

Exemple 923. Exemple avec la méthode compareVersion()

// retourne -1, 0 or 1
$cmp = Zend_Version::compareVersion('2.0.0');

1519
Zend_View
1. Introduction
Zend_View est une classe qui permet de travailler avec la partie "Vue" du motif de conception
Modèle-Vue-Contrôleur. Elle existe pour aider à garder la vue séparée du modèle et des
scripts du contrôleur. Elle fournie un système d'aide, de filtres d'affichage, et d'échappement de
variables.

Zend_View est un système de template agnostique ; vous pouvez utiliser PHP comme langage
de template, ou créer des instances d'autres systèmes de templates, et les manipuler à travers
les scripts de vue.

L'utilisation de Zend_View se déroule en deux étapes principales : 1. Votre script de contrôleur


crée une instance de Zend_View et assigne des variables à cette instance. 2. Le contrôleur dit
à Zend_View d'effectuer le rendu d'une vue particulière, et de ce fait va donner le contrôle au
script de vue, qui va générer l'affichage.

1.1. Script du Contrôleur


Comme exemple simple, imaginons que votre contrôleur aie une liste de données sur des livres
qu'il veut afficher en passant par une vue. Le contrôleur pourrait alors ressembler à ceci :

// utilise un modèle pour obtenir les données sur les livres :


// auteurs et titres
$data = array(
array(
'auteur' => 'Hernando de Soto',
'titre' => 'Le mystère du capitalisme'
),
array(
'auteur' => 'Henry Hazlitt',
'titre' => 'Les sciences économique en un cours'
),
array(
'auteur' => 'Milton Friedman',
'titre' => 'Libre de choisir'
)
);

// assigniation des données du livre à une instance Zend_View


Zend_Loader::loadClass('Zend_View');
$view = new Zend_View();
$view->books = $data;

// et appel du script de rendu d'affichage appelé "booklist.php"


echo $view->render('booklist.php');

1.2. Script de vue


Maintenant, nous avons besoin d'associer le script de vue "booklist.php". C'est un script PHP
comme les autres, à une exception près : il s'exécute dans la portée de l'instance Zend_View,
ce qui veut dire que les référence à $this pointent vers les attributs et les méthodes de
Zend_View. (Les variables assignées à l'instance par le contrôleur sont des propriétés publiques
de l'instance Zend_View). Ainsi un script de vue de base pourrait ressembler à ceci :

1520
Zend_View

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


<!-- La table des livres -->
<table>
<tr>
<th>Auteur</th>
<th>Titre</th>
</tr>

<?php foreach ($this->books as $key => $val): ?>


<tr>
<td><?php echo $this->escape($val['auteur']) ?></td>
<td><?php echo $this->escape($val['titre']) ?></td>
</tr>
<?php endforeach; ?>
</table>

<?php else: ?>


<p>Aucun livre à afficher</p>

<?php endif; ?>

Notez l'utilisation de la méthode escape pour échapper les variables à afficher.

1.3. Options
Zend_View possède plusieurs options qui peuvent être réglées pour changer le comportement
de vos scripts de vues.

• basePath : indique le chemin de base où peuvent être trouvés les dossiers de scripts, d'aides
et de filtres. Il considère une structure de dossiers de ce type :

chemin/vers/
helpers/
filters/
scripts/

Ceci peut être paramétré via les méthodes setBasePath(), addBasePath(), ou l'option
basePath du constructeur.

• encoding : indique l'encodage de caractère à utiliser avec htmlentities(),


htmlspecialchars(), et tout autre opération. La valeur par défaut est ISO-8859-1 (latin1). Il
peut être paramétré avec la méthode setEncoding() ou l'option encoding du constructeur.

• escape : indique le callback que doit utiliser escape(). Ceci pet être paramétré avec la
méthode setEscape() ou l'option escape du constructeur.

• filter : indique un filtre à utiliser avant d'effectuer le rendu d'un script de vue. Ceci peut
être paramétré avec les méthodes setFilter(), addFilter(), ou l'option filter du
constructeur.

• strictVars : force Zend_View à émettre des "notices" et des "warnings" quand des
variables non initialisées sont lues. Ceci peut être activé en appelant strictVars(true) ou
en passant l'option strictVars au constructeur.

1.4. Balises courtes dans les scripts de vue


Dans nos exemples et notre documentation, nous utilisons les balises longues PHP : <?php.
De plus, nous utilisons parfois la syntaxe alternative des structures de contrôle. Ce sont des

1521
Zend_View

éléments pratiques à utiliser lors de la rédaction de vos scripts de vue, car elles rendent les
constructions plus laconiques, maintiennent les instructions sur des lignes uniques et éliminent
la chasse aux accolades à l'intérieur de l'HTML.

Dans les versions précédentes, nous recommandions souvent l'utilisation des balises courtes (<?
et <?=), car elles rendent les scripts de vues moins verbeux. Cependant, la valeur par défaut du
fichier php.ini pour le réglage short_open_tag est désactivé par défaut en production ou en
hébergement mutualisé ; rendant ainsi vos scripts peu portables. De plus, si vous modélisez du
XML dans vos scripts, la présence des balises courtes entrainera l'échec de la validation. Enfin,
si vous utilisez les balises courtes et que short_open_tag est désactivé, le script retournera
soit des erreurs, soit votre code PHP à l'utilisateur.

Ceci étant dit, de nombreux développeurs préfère utiliser la forme complète pour des
questions de validation ou de portabilité. Par exemple, short_open_tag est désactivé dans le
php.ini.recommended, et si vous avez du XML dans vos scripts de vue, alors les balises courtes
entraîneront un échec de validation du modèle.

De plus, si vous utilisez les balises courtes avec un réglage du paramètre à "off", alors les scripts
de vue vont soit entraîner des erreurs, soit simplement afficher le code à l'utilisateur.

Si malgré ces avertissements, vous souhaitez utiliser les balises courtes mais qu'elles sont
désactivées, vous avez deux options :

• Activer les dans votre fichier .htaccess :

php_value "short_open_tag" "on"

Ceci est seulement possible si vous êtes autorisé à créer et utiliser les fichiers .htaccess.
Cette directive peut aussi être ajoutée à votre fichier httpd.conf.

• Activer une enveloppe de flux ("stream wrapper") optionnelle pour convertir les balises courtes
en balises longues à la volée :

$view->setUseStreamWrapper(true);

Ceci enregistre Zend_View_Stream en tant que enveloppe de flux pour les scripts de vue,
et permet de s'assurer que votre code continue à fonctionner comme si les balises courtes
étaient activées.

Les enveloppes de flux de vue dégradent les performances


L'utilisation d'enveloppe de flux dégradera les performances de votre application,
bien que les tests de performance réels sont indisponibles pour quantifier le
niveau de dégradation. Nous recommandons donc soit d'activer les balises
courtes, soit de convertir vos scripts pour utiliser la forme longue, ou d'avoir une
bonne stratégie de mise en cache partielle ou totale du contenu de vos pages.

1.5. Accesseurs utiles


Typiquement, vous ne devriez seulement avoir besoin d'appeler les méthodes assign(),
render(), ou une des méthodes pour le paramétrage/l'ajout de chemins de filtre, d'aide et de
script de vues. Cependant, si vous souhaitez étendre Zend_View vous-même, ou avez besoin
d'accéder à quelques unes de ces méthodes internes, un certain nombre d'accesseurs existent :

• getVars() retournera toutes les variables assignées.

1522
Zend_View

• clearVars() effacera toutes les variables assignées ; utile si vous souhaitez ré-utiliser un
objet de vue, ou contrôler les variables qui sont disponibles.

• getScriptPath($script) récupérera le chemin résolu vers un script donné..

• getScriptPaths() récupérera tous les chemins vers les scripts de vues enregistrés.

• getHelperPath($helper) récupérera le chemin résolu vers une classe d'aide nommée.

• getHelperPaths() récupérera tous les chemins vers les aides enregistrés.

• getFilterPath($filter) récupérera le chemin résolu vers une classe de filtre nommée.

• getFilterPaths() récupérera tous les chemins vers les filtres enregistrés.

2. Scripts de contrôleur
Le contrôleur est l'endroit où vous instanciez et configurez Zend_View. Vous assignez ensuite
des variables à la vue, et lui dites comment effectuer le rendu en utilisant un script particulier.

2.1. Assigner des variables


Votre script de contrôleur devrait assigner les variables nécessaires à la vue avant de passer
le contrôle au script de vue. Normalement vous pouvez faire les assignations une par une en
assignant les noms des propriétés de l'instance de la vue :

$view = new Zend_View();


$view->a = "Ha";
$view->b = "Bé";
$view->c = "Cé";

Cependant, ceci peut être pénible quand vous avez déjà collecté (dans un tableau ou dans un
objet) les valeurs à assigner.

La méthode assign() vous laisse assigner "en vrac" depuis un tableau ou un objet. Les
exemples suivants ont le même effet que celui ci-dessus.

$view = new Zend_View();

// assigne un tableau de paires clés/valeurs, où la clé


// est le nom de la variable, et la valeur, sa valeur assignée
$array = array(
'a' => "Ha",
'b' => "Bé",
'c' => "Cé",
);
$view->assign($array);

// fait pareil avec les propriétés publiques d'un objet


// notez le transtypage lors de l'assignation
$obj = new StdClass;
$obj->a = "Ha";
$obj->b = "Bé";
$obj->c = "Cé";
$view->assign((array) $obj);

Alternativement, vous pouvez utiliser la méthode assign() pour assigner les variables une par
une, en passant le nom de la variable, et sa valeur.

1523
Zend_View

$view = new Zend_View();


$view->assign('a', "Ha");
$view->assign('b', "Bé");
$view->assign('c', "Cé");

2.2. Effectuer le rendu d'un script de vue


Une fois que vous avez assigné toutes les variables dont vous avez besoin, le contrôleur devrait
demander à Zend_View de rendre un script de vue particulier. Faites cela en appelant la
méthode render(). Notez que la méthode va retourner la vue rendue, mais ne va pas l'afficher,
vous devez donc l'afficher vous même avec print ou echo, au moment voulu.

$view = new Zend_View();


$view->a = "Ha";
$view->b = "Bé";
$view->c = "Cé";
echo $view->render('uneVue.php');

2.3. Chemin des scripts de vue


Par défaut, Zend_View s'attend à ce que vos scripts de vues soient dans le même dossier que
celui du contrôleur. Par exemple, si le script du contrôleur est dans "/chemin/des/controleurs"
et qu'il appelle $view->render('uneVue.php'), Zend_View va rechercher "/chemin/des/
controleurs/uneVue.php".

Évidemment, vos scripts sont peut-être localisés ailleurs. Pour dire à Zend_View ou il doit
chercher, utilisez la méthode setScriptPath().

$view = new Zend_View();


$view->setScriptPath('/chemin/des/vues');

Maintenant, vous appelez $view->render('uneVue.php'), il va rechercher dans "/


chemin/des/vues/uneVue.php".

En fait, vous pouvez "empiler" les chemins en utilisant la méthode setScriptPath(). Comme
vous ajoutez des chemins dans la pile, Zend_View va rechercher le script de vue dans le chemin
le plus récemment ajouté. Cela vous permet de passer outre les vues par défaut, pour des
vues personnalisées. Ainsi vous pouvez créer des "thèmes" ou des "skins" pour certaines vues,
pendant que vous laissez les autres intactes.

$view = new Zend_View();


$view->addScriptPath('/chemin/des/vues');
$view->addScriptPath('/chemin/des/vues-personnalisees');

// maintenant, lorsque vous appelerez $view->render('listelivre.php'),


// Zend_View va rechercher en premier dans
// "/chemin/des/vues-personnalisees/listelivre.php", puis
// dans "/chemin/des/vues/listelivre.php", et ensuite dans le répertoire
// courant pour trouver le fichier "listelivre.php".

Ne jamais utiliser une entrée utilisateur pour spécifier les


chemins vers les scripts de vues
Zend_View utilise des chemins dans lesquels elle cherche et effectue le rendu
des scripts de vues. En soi, ces dossiers devraient être connus à l'avance, et sous
votre contrôle. Ne jamais spécifier des dossiers de scripts de vues sur la base

1524
Zend_View

d'une entrée utilisateur, car vous pourriez ainsi avoir une vulnérabilité d'inclusion
de fichier non voulu si les chemins spécifiés par l'utilisateur sont traversant. Par
exemple, le code suivant peut générer un problème :

// $_GET['foo'] == '../../../etc'
$view->addScriptPath($_GET['foo']);
$view->render('passwd');

De la manière dont cet exemple est conçu, il montre clairement le problème


potentiel. Si vous devez compter sur l'entrée d'utilisateur pour placer votre
chemin de scripts, filtrez correctement l'entrée et contrôlez pour vous assurer
que ces chemins sont contrôlés par votre application.

3. Scripts de vue
Une fois que le contrôleur a assigné les variables et appelé render(), Zend_View inclue le
script de vue requis et l'exécute "à l'intérieur" de la portée de l'instance Zend_View. Donc dans
vos scripts de vue, les références à $this pointent en fait sur l'instance Zend_View elle-même.

Les variables assignées à la vue depuis le contrôleur lui sont référées comme des propriétés
de l'instance. Par exemple, si le contrôleur a assigné une variable "quelquechose", vous vous
référerez à cette variable par $this->quelquechose dans le script de vue. (Cela vous permet
de garder une trace pour savoir quelles valeurs ont été assignées au script, et lesquelles sont
internes au script lui même.)

Pour rappel, voici l'exemple de script issu de l'introduction de ce chapitre sur Zend_View.

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


<!-- La table des livres -->
<table>
<tr>
<th>Auteur</th>
<th>Titre</th>
</tr>

<?php foreach ($this->livres as $cle => $livre): ?>


<tr>
<td><?php echo $this->escape($livre['auteur']) ?></td>
<td><?php echo $this->escape($livre['titre']) ?></td>
</tr>
<?php endforeach; ?>
</table>

<?php else: ?>


<p>Aucun livre à afficher</p>

<?php endif; ?>

3.1. Échapper la sortie


Une des tâches les plus importantes à effectuer dans un script de vue est de s'assurer que la
sortie est correctement échappée ; de plus ceci permet d'éviter les attaques de type cross-site
scripting (XSS). A moins que vous n'utilisiez une fonction, une méthode, ou une aide qui gère
l'échappement, vous devriez toujours échapper les variables lors de l'affichage.

Zend_View a une méthode appelée escape() qui se charge de l'échappement.

1525
Zend_View

// mauvaise pratique d'affichage


echo $this->variable;

// bonne pratique d'affichage


echo $this->escape($this->variable);

Par défaut, la méthode escape() utilise la fonction PHP htmlspecialchar() pour


l'échappement. Cependant, en fonction de votre environnement, vous souhaitez peut-être un
échappement différent. Utilisez la méthode setEscape() au niveau du contrôleur pour dire à
Zend_View quelle méthode de rappel ("callback") elle doit utiliser.

// crée une instance Zend_View


$view = new Zend_View();

// spécifie qu'il faut utiliser htmlentities


// comme rappel d'échappement
$view->setEscape('htmlentities');

// ou spécifie qu'il faut utiliser une méthode statique


// comme rappel d'échappement
$view->setEscape(array('UneClasse', 'nomDeMethode'));

// ou alors une méthode d'instance


$obj = new UneClasse();
$view->setEscape(array($obj, 'nomDeMethode'));

// et ensuite effectue le rendu de la vue


echo $view->render(...);

La fonction ou méthode de rappel doit prendre la valeur à échapper dans le premier paramètre,
et tous les autres paramètres devraient être optionnels.

3.2. Utiliser des systèmes de gabarit (template) alternatifs


Bien que PHP lui-même un moteur de gabarit puissant, beaucoup de développeurs pensent que
c'est beaucoup trop puissant ou complexe pour les graphistes/intégrateurs et veulent utiliser un
moteur de template alternatif. Zend_View fournit deux mécanismes pour faire cela, le premier
à travers les scripts de vues, le second en implémentant Zend_View_Interface.

3.2.1. Système de gabarit utilisant les scripts de vues


Un script de vue peut être utilisé pour instancier et manipuler un objet de gabarit séparé, comme
un gabarit de type PHPLIB. Le script de vue pour ce type d'activité pourrait ressembler à ceci :

include_once 'template.inc';
$tpl = new Template();

if ($this->livres) {
$tpl->setFile(array(
"listelivre" => "listelivre.tpl",
"chaquelivre" => "chaquelivre.tpl",
));

foreach ($this->livres as $cle => $livre) {


$tpl->set_var('auteur', $this->escape($livre['auteur']);
$tpl->set_var('titre', $this->escape($livre['titre']);
$tpl->parse("livre", "chaquelivre", true);

1526
Zend_View

$tpl->pparse("output", "listelivre");
} else {
$tpl->setFile("nobooks", "pasdelivres.tpl")
$tpl->pparse("output", "pasdelivres");
}

Et ceci pourrait être les fichiers de gabarits correspondants :

<!-- listelivre.tpl -->


<table>
<tr>
<th>Auteur</th>
<th>Titre</th>
</tr>
{livres}
</table>

<!-- chaquelivre.tpl -->


<tr>
<td>{auteur}</td>
<td>{title}</td>
</tr>

<!-- pasdelivres.tpl -->


<p>Aucun livre à afficher</p>

3.2.2. Système de gabarit utilisant Zend_View_Interface


Certains peuvent trouver plus facile de simplement fournir un moteur de gabarit compatible avec
Zend_View. Zend_View_Interface définit l'interface de compatibilité minimale nécessaire :

/**
* Retourne l'objet moteur de gabarit actuel
*/
public function getEngine();

/**
* Affecte le dossier des scripts de gabarits
*/
public function setScriptPath($path);

/**
* Règle un chemin de base pour toutes les ressources de vue
*/
public function setBasePath($path, $prefix = 'Zend_View');

/**
* Ajoute un chemin de base supplémentaire pour les ressources de vue
*/
public function addBasePath($path, $prefix = 'Zend_View');

/**
* Récupère les chemins actuels vers les ressources de vue
*/
public function getScriptPaths();

/**

1527
Zend_View

* Méthode à surcharger pour affecter les variables des gabarits


* en tant que propriétés de l'objet
*/
public function __set($key, $value);
public function __isset($key);
public function __unset($key);

/**
* Affectation manuelle de variable de gabarit, ou possibilité
* d'affecter des variables en masse.
*/
public function assign($spec, $value = null);

/**
* Efface toutes les variables du gabarit déjà affectées
*/
public function clearVars();

/**
* Effectue le rendu du gabarit nommé $name
*/
public function render($name);

En utilisant cette interface, il devient relativement facile d'encapsuler un moteur de gabarit tiers
comme une classe compatible Zend_View. Comme par exemple, le code suivant est une
encapsulation potentielle de Smarty :

class Zend_View_Smarty implements Zend_View_Interface


{
/**
* Objet Smarty
* @var Smarty
*/
protected $_smarty;

/**
* Constructeur
*
* @param string $tmplPath
* @param array $extraParams
* @return void
*/
public function __construct($tmplPath = null,
$extraParams = array())
{
$this->_smarty = new Smarty;

if (null !== $tmplPath) {


$this->setScriptPath($tmplPath);
}

foreach ($extraParams as $key => $value) {


$this->_smarty->$key = $value;
}
}

/**
* Retourne l'objet moteur de gabarit
*

1528
Zend_View

* @return Smarty
*/
public function getEngine()
{
return $this->_smarty;
}

/**
* Affecte le dossier des scripts de gabarits
*
* @param string $path Le répertoire à affecter au path
* @return void
*/
public function setScriptPath($path)
{
if (is_readable($path)) {
$this->_smarty->template_dir = $path;
return;
}

throw new Exception('Répertoire fourni invalide');


}

/**
* Récupère le dossier courant des gabarits
*
* @return string
*/
public function getScriptPaths()
{
return array($this->_smarty->template_dir);
}

/**
* Alias pour setScriptPath
*
* @param string $path
* @param string $prefix Unused
* @return void
*/
public function setBasePath($path, $prefix = 'Zend_View')
{
return $this->setScriptPath($path);
}

/**
* Alias pour setScriptPath
*
* @param string $path
* @param string $prefix Unused
* @return void
*/
public function addBasePath($path, $prefix = 'Zend_View')
{
return $this->setScriptPath($path);
}

/**
* Affectation une variable au gabarit
*

1529
Zend_View

* @param string $key Le nom de la variable


* @param mixed $val La valeur de la variable
* @return void
*/
public function __set($key, $val)
{
$this->_smarty->assign($key, $val);
}

/**
* Autorise le fonctionnement du test avec empty() and isset()
*
* @param string $key
* @return boolean
*/
public function __isset($key)
{
return (null !== $this->_smarty->get_template_vars($key));
}

/**
* Autorise l'effacement de toutes les variables du gabarit
*
* @param string $key
* @return void
*/
public function __unset($key)
{
$this->_smarty->clear_assign($key);
}

/**
* Affectation de variables au gabarit
*
* Autorise une affectation simple (une clé => une valeur)
* OU
* le passage d'un tableau (paire de clé => valeur)
* à affecter en masse
*
* @see __set()
* @param string|array $spec Le type d'affectation à utiliser
(clé ou tableau de paires clé => valeur)
* @param mixed $value (Optionel) Si vous assignez une variable nommée,
utilisé ceci comme valeur
* @return void
*/
public function assign($spec, $value = null)
{
if (is_array($spec)) {
$this->_smarty->assign($spec);
return;
}

$this->_smarty->assign($spec, $value);
}

/**
* Effacement de toutes les variables affectées
*
* Efface toutes les variables affectées à Zend_View

1530
Zend_View

* via {@link assign()} ou surcharge de propriété


* ({@link __get()}/{@link __set()}).
*
* @return void
*/
public function clearVars()
{
$this->_smarty->clear_all_assign();
}

/**
* Exécute le gabarit et retourne l'affichage
*
* @param string $name Le gabarit à exécuter
* @return string L'affichage
*/
public function render($name)
{
return $this->_smarty->fetch($name);
}
}

Dans cet exemple, vous instanciez la classe Zend_View_Smarty au lieu de Zend_View, et


vous l'utilisez de la même façon :

//Exemple 1a. Dans l'initView() de l'initializer.


$view = new Zend_View_Smarty('/chemin/vers/les/templates');
$viewRenderer =
Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
$viewRenderer->setView($view)
->setViewBasePathSpec($view->_smarty->template_dir)
->setViewScriptPathSpec(':controller/:action.:suffix')
->setViewScriptPathNoControllerSpec(':action.:suffix')
->setViewSuffix('tpl');

//Exemple 1b. L'utilisation dans le contrôleur d'action reste la même


class FooController extends Zend_Controller_Action
{
public function barAction()
{
$this->view->book = 'Zend PHP 5 Certification Study Guide';
$this->view->author = 'Davey Shafik and Ben Ramsey'
}
}

//Example 2. Initialisation de la vue dans le contrôleur d'action


class FooController extends Zend_Controller_Action
{
public function init()
{
$this->view = new Zend_View_Smarty('/path/to/templates');
$viewRenderer = $this->_helper->getHelper('viewRenderer');
$viewRenderer->setView($this->view)
->setViewBasePathSpec($view->_smarty->template_dir)
->setViewScriptPathSpec(':controller/:action.:suffix')
->setViewScriptPathNoControllerSpec(':action.:suffix')
->setViewSuffix('tpl');
}
}

1531
Zend_View

4. Aides de vue
Dans vos scripts de vue, il est souvent nécessaire d'effectuer certaines actions complexes
encore et encore : par exemple, formater une date, générer des éléments de formulaire, afficher
des liens d'action. Vous pouvez utiliser des classes d'aide pour effectuer ce genre de tâches.

Une aide est simplement une classe. Par exemple, nous voulons une aide nommée "foobar". Par
défaut, la classe est préfixée avec "Zend_View_Helper_" (vous pouvez spécifier un préfixe
personnalisé en paramétrant votre chemin d'aide), et le dernier segment du nom de classe est
le nom de l'aide ; ce segment peut être avec des CaracteresMajuscules ; le nom complet de
la classe est alors : Zend_View_Helper_FooBar. Cette classe doit contenir au moins une
méthode, nommée comme l'aide avec la notationCamel : fooBar().

Surveillez la casse
Les noms des aides sont toujours en notationCamel, c'est-à-dire qu'ils ne
commencent pas avec un caractère majuscule. Le nom de classe elle-même peut
être en casseMélangée, mais la méthode qui est exécutée est en notationCamel.

Pour utiliser une aide dans votre script de vue, appelez la en utilisant $this->nomAide().
Dans les coulisses, Zend_View va charger la classe Zend_View_Helper_NomAide, créer
une instance de cet objet, et appeler sa méthode nomAide(). L'instance de l'objet est
persistante dans l'instance de Zend_View, et est réutilisée pour tous les appels futurs à $this-
>nomAide().

4.1. Aides initiales


Zend_View fournit avec un jeu initial de classes d'aides, la plupart est liée à la génération
d'éléments de formulaire. Chacune affiche et échappe l'élément automatiquement. De plus, il
existe des aides pour créer des URLs sur la base de routes et des listes HTML, de la même
manière que l'on déclarerait des variables. Les aides actuellement incluses sont :

• declareVars() : initialement prévu pour être utilisé avec strictVars(), cette aide peut
être utilisée pour déclarer les variables de modèle ("template") qui sont (ou pas) déjà déclarées
dans l'objet de vue, ou pour gérer des valeurs par défaut. Les tableaux passés comme
arguments à la méthode seront utilisés pour paramétrer des valeurs par défaut ; sinon, si la
variable n'existe pas, on lui affecte une chaîne vide.

• fieldset($name, $content, $attribs) : crée un ensemble de champs XHTML. Si


$attribs contient une clé "legend", cette valeur sera utilisée comme légende du fieldset. Le
fieldset entourera le contenu $content tel qu'il aura été fourni à l'aide.

• form($name, $attribs, $content) : génère un formulaire XHTML. Tous les éléments


$attribs sont échappés et rendus sous la forme d'attributs de la balise "form". Si $content
est présent et n'est pas un booléen valant FALSE, alors ce contenu est rendu à l'intérieur des
balises "form" ; si $content est un booléen valant FALSE (par défaut), seul la balise ouvrante
"form" est générée.

• formButton($name, $value, $attribs) : crée un élément <button />.

• formCheckbox($name, $value, $attribs, $options): crée un élément <input


type="checkbox" />.

Par défaut, quand aucune $value n'est fournie et qu'aucune $options n'est présente, alors
"0" est considéré comme la valeur non cochée et "1" comme la valeur cochée. Si une $value

1532
Zend_View

est fournie, mais qu'aucune $options n'est présente, l'état coché est considéré égal à la
$value fournie.

$options devrait être un tableau. Si ce tableau est indexé, la première valeur est la valeur
cochée, la seconde est la valeur non cochée ; et tout autre valeur est ignorée. Vous pouvez
aussi passer un tableau associatif avec les clés "checked" et "unChecked".

Si $options est fourni, et que $value correspond à la valeur cochée, alors l'élément sera
marqué comme coché. Vous pouvez aussi marquer l'élément comme coché ou décoché en
passant une valeur booléenne à l'attribut "checked".

Ceci pourra sûrement être plus explicite avec quelques exemples :

// "1" et "0" en tant qu'options cochée/décochée ; cochée


echo $this->formCheckbox('foo');

// "1" et "0" en tant qu'options cochée/décochée ; cochée


echo $this->formCheckbox('foo', null, array('checked' => true));

// "bar" et "0" en tant qu'options cochée/décochée ; décochée


echo $this->formCheckbox('foo', 'bar');

// "bar" et "0" en tant qu'options cochée/décochée ; cochée


echo $this->formCheckbox('foo', 'bar', array('checked' => true));

// "bar" et "baz" en tant qu'options cochée/décochée ; décochée


echo $this->formCheckbox('foo', null, null, array('bar', 'baz'));

// "bar" et "baz" en tant qu'options cochée/décochée ; décochée


echo $this->formCheckbox('foo', null, null, array(
'checked' => 'bar',
'unChecked' => 'baz'
));

// "bar" et "baz" en tant qu'options cochée/décochée ; cochée


echo $this->formCheckbox('foo', 'bar', null, array('bar', 'baz'));
echo $this->formCheckbox('foo',
null,
array('checked' => true),
array('bar', 'baz'));

// "bar" et "baz" en tant qu'options cochée/décochée ; décochée


echo $this->formCheckbox('foo', 'baz', null, array('bar', 'baz'));
echo $this->formCheckbox('foo',
null,
array('checked' => false),
array('bar', 'baz'));

Dans tous les cas, la balise est précédée d'un élément masqué ("hidden") avec la valeur de
l'état décoché ; ainsi, si la valeur est décochée, vous aurez toujours une valeur valide retournée
par votre formulaire.

• formErrors($errors, $options) : génère une liste non ordonnée XHTML pour montrer
des erreurs. $errors peut être une chaîne de caractères ou un tableau de chaînes ;
$options peut être tout attribut que vous pourriez vouloir placer dans la balise ouvrante de
la liste.

1533
Zend_View

Vous pouvez spécifier des éléments ouvrants, fermants et des séparateurs de contenu
alternatifs lors du rendu des erreurs en appelant les différentes méthodes suivantes de l'aide :

• setElementStart($string) ; par défaut vaut "<ul class="errors"%s"><li>", où %s est


remplacé avec les attributs spécifiés dans $options.

• setElementSeparator($string) ; par défaut vaut "</li><li>".

• setElementEnd($string) ; par défaut vaut "</li></ul>".

• formFile($name, $attribs): crée un élément <input type="file" />.

• formHidden($name, $value, $attribs) : crée un élément <input type="hidden" />.

• formLabel($name, $value, $attribs) : crée un élément <label>, en réglant l'attribut


for avec $name, et le texte du label avec $value. Si disable est fourni via attribs, rien
n'est retourné.

• formMultiCheckbox($name, $value, $attribs, $options, $listsep) : crée


une liste de cases à cocher. $options devrait être un tableau associatif, avec une profondeur
arbitraire. $value peut être une valeur unique ou un tableau de valeurs sélectionnées qui
correspondent aux clés du tableau $options. $listsep est un séparateur HTML ("<br />")
par défaut. Par défaut, cet élément est traité comme un tableau ; toutes les cases à cocher
partagent le même nom, et sont soumises sous la forme d'un tableau.

• formPassword($name, $value, $attribs) : crée un élément <input type="password" /


>.

• formRadio($name, $value, $attribs, $options) : crée une série d'éléments <input


type="button" />, un pour chaque élément $options. Dans le tableau $options, la clé de
l'élément est la valeur du radio, et la valeur de l'élément est l'étiquette du radio. La radio
$value sera précochée pour vous.

• formReset($name, $value, $attribs) : crée un élément <input type="reset" />.

• formSelect($name, $value, $attribs, $options) : crée un bloc <select>...</


select>, avec une <option> pour chaque élément $options. Dans le tableau $options, la
clé de l'élément est la valeur de l'option, et la valeur de l'élément est son étiquette optionnelle.
L'option (ou les options) $value sera (ou seront) présélectionnée(s) pour vous.

• formSubmit($name, $value, $attribs) : crée un élément <input type="submit" />.

• formText($name, $value, $attribs) : crée un élément <input type="text" />.

• formTextarea($name, $value, $attribs) : crée un bloc <textarea>...</textarea>.

• url($urlOptions, $name, $reset) : crée un URL basé sur une route nommée.
$urlOptions doit être un tableau associatif avec des paires de clés/valeurs utilisées par une
route particulière.

• htmlList($items, $ordered, $attribs, $escape) : génère des listes ordonnées ou


non basées sur les $items qui lui sont fournis. Si $items est un tableau multidimensionnel,
une liste imbriquée sera construite. Si le paramètre $escape vaut TRUE (valeur par défaut),
chaque élément sera échappé en utilisant le mécanisme d'échappement enregistré dans les
objets de vue ; fournissez une valeur FALSE si vous voulez autoriser du balisage dans vos
listes.

1534
Zend_View

Les utiliser dans vos script de vue est très simple, voici un exemple. Notez que tout ce dont vous
avez besoin, c'est de les appeler; elles vont se charger et s'instancier elle-même si besoin est.

<!--
Dans votre script de vue, $this se réfère à l'instance de Zend_View.
Partons du principe que vous avez déjà assigné une série d'options
de sélection dans un tableau $pays =
array('us' => 'Etats-Unis', 'fr' => 'France', 'de' => 'Allemagne').
-->
<form action="action.php" method="post">
<p><label>Votre email :
<?php echo $this->formText('email',
'vous@exemple.fr',
array('size' => 32)) ?>
</label></p>
<p><label>Votre pays :
<?php echo $this->formSelect('country',
'us',
null,
$this->pays) ?>
</label></p>
<p><label>??? Would you like to opt in ???
<?php echo $this->formCheckbox('opt_in',
'oui',
null,
array('oui', 'non')) ?>
</label></p>
</form>

La sortie résultante du script de vue ressemblera à ceci :

<form action="action.php" method="post">


<p><label>Votre email :
<input type="text" name="email"
value="vous@exemple.fr" size="32" />
</label></p>
<p><label>Votre pays :
<select name="country">
<option value="us" selected="selected">Etats-Unis</option>
<option value="fr">France</option>
<option value="de">Allemagne</option>
</select>
</label></p>
<p><label>??? Would you like to opt in ???
<input type="hidden" name="opt_in" value="non" />
<input type="checkbox" name="opt_in"
value="oui" checked="checked" />
</label></p>
</form>

4.1.1. L'aide de vue Action


L'aide de vue Action permet à des scripts de vue de distribuer une action donnée d'un
contrôleur ; le résultat de l'objet de réponse suivant la distribution est alors retourné. Ceux-ci
peuvent être employés quand une action particulière peut produire du contenu réutilisable ou
du contenu de type "gadget".

Les actions qui ont comme conséquence un _forward() ou une redirection sont considérées
invalide, et retourneront une chaîne vide.

1535
Zend_View

L'API pour l'aide de vue Action respecte le même schéma que la plupart les composants MVC
qui appellent des actions de contrôleur : action($action, $controller, $module =
null, array $params = array()). $action et $controller sont exigés ; si aucun
module n'est spécifié, le module par défaut est implicite.

Exemple 924. Utilisation de base de l'aide de vue Action

Par exemple, vous pouvez avoir un CommentController avec une méthode


listAction() que vous souhaitez appeler afin de récupérer une liste de commentaires
pour la requête courante :

<div id="sidebar right">


<div class="item">
<?php echo $this->action('list', 'comment', null, array('count' => 10)); ?>
</div>
</div>

4.1.2. Aide BaseUrl


La plupart des URLs générées par le framework possèdent l' URL de base préfixée
automatiquement. Les développeurs ont besoin de la rajouter à la main à leurs propres URLs
afin de garder une correspondance chemins - ressources correcte.

L'utilisation de l'aide de vue BaseUrl est très simple:

/*
* Imaginons une URL de base dans page/application de "/mypage".
*/

/*
* affiche:
* <base href="/mypage/" />
*/
<base href="<?php echo $this->baseUrl(); ?>" />

/*
* affiche:
* <link rel="stylesheet" type="text/css" href="/mypage/css/base.css" />
*/
<link rel="stylesheet" type="text/css"
href="<?php echo $this->baseUrl('css/base.css'); ?>" />

Pour plus de simplicité, le fichier PHP (par exemple "index.php") est


enelevé de l'URL de base gérée par Zend_Controller. Cependant, si ceci
vous gène, utilisez $this->getHelper('BaseUrl')->setBaseUrl() pour
affecter votre propre BaseUrl.

4.1.3. Aide Currency


Afficher des informations de monnaie localisées est très courant; l'aide de vue de
Zend_Currency est dédiée à cela. Voyez le chapitre sur Zend Currency pour les détails sur la
localisation. Dans cette section, nous apprendrons à manipuler l'aide de vue uniquement.

Il existe plusieurs manières d'initialiser l'aide de vue Currency:

• Enrigistrée dans une instance de Zend_Registry.

1536
Zend_View

• Grâce à une interface fluide.

• En instanciant directement la classe.

L'enregistrement en registre de Zend_Currency est la manière recommandée. Grâce à cela


vous pouvez selectionner la monnaie à utiliser puis ajouter son adaptateur au registre.

Pour séléctionner la valeur de la monnaie à utiliser, passez une chaine ou encore une locale
ce qui est recommandé car les informations provenant du client HTTP seront alors utilisées par
défaut.

Nous parlons bien de "locales" et non de "langues" car la langue peut varier
en fonction de la position géorgraphique au sein d'un même pays.Par exemple,
l'anglais est parlé dans différents dialectes : Anglais ou Américain. Une monnaie
est liée directement à une région, vous devrez donc utiliser une locale complète
c'est à dire représentant le pays et la région. Nous parlons donc de "locale" plutôt
que de "langue."

Exemple 925. Instance en registre

Pour utiliser une instance en registre, créez une instance de Zend_Currency et enregistrez
la dans Zend_Registry en utilisant la clé Zend_Currency.

// notre monnaie d'exemple


$currency = new Zend_Currency('de_AT');
Zend_Registry::set('Zend_Currency', $currency);

// Dans votre vue


echo $this->currency(1234.56);
// Ceci affiche '€ 1.234,56'

Si vous préférez utiliser l'interface fluide, vous pouvez alors créer une instance dans votre vue
et la configurer après cela.

Exemple 926. Instance dans la vue

Pour utiliser l'interface fluide, créez une instance de Zend_Currency, appelez l'aide de
vue sans paramètre et appelez ensuite la méthode setCurrency().

// Dans votre vue


$currency = new Zend_Currency('de_AT');
$this->currency()->setCurrency($currency)->currency(1234.56);
// Ceci affiche '€ 1.234,56'

Si vous utilisez l'aide sans Zend_View alors vous pouvez aussi l'utiliser de manière directe, via
instanciation manuelle.

Exemple 927. Utilisation directe via instanciation

// Notre monnaie d'exemple


$currency = new Zend_Currency('de_AT');

// Initialisation de l'aide de vue


$helper = new Zend_View_Helper_Currency($currency);
echo $helper->currency(1234.56); // Ceci affiche '€ 1.234,56'

1537
Zend_View

Comme déja vu, la méthode currency() est utilisée pour retourner la chaine représentant la
monnaie. Appelez la simplement avec la valeur que vous voulez voir affichée. Des options sont
aussi disponibles, elles servent à changer le comportement interne de l'aide.

Exemple 928. Utilisation directe

// Notre monnaie d'exemple


$currency = new Zend_Currency('de_AT');

// Initialisation de l'aide de vue


$helper = new Zend_View_Helper_Currency($currency);
echo $helper->currency(1234.56); // Ceci affiche '€ 1.234,56'
echo $helper->currency(1234.56, array('precision' => 1));
// Ceci affiche '€ 1.234,6'

Concernant les options disponibles, voyez la méthode toCurrency() de Zend_Currency.

4.1.4. Aide Cycle


L'aide Cycle est utilisée pour alterner des valeurs.

Exemple 929. Aide Cycle : utilisation de base

Pour ajouter des éléments dans le cycle, spécifiez le simplement dans le constructeur ou
utilisez assign(array $data)

<?php foreach ($this->books as $book):?>


<tr style="background-color:<?php echo $this->cycle(array("#F0F0F0",
"#FFFFFF"))
->next()?>">
<td><?php echo $this->escape($book['author']) ?></td>
</tr>
<?php endforeach;?>
// Mouvement dans le sens inverse
$this->cycle()->assign(array("#F0F0F0","#FFFFFF"));
$this->cycle()->prev();
?>

La sortie:

<tr style="background-color:'#F0F0F0'">
<td>First</td>
</tr>
<tr style="background-color:'#FFFFFF'">
<td>Second</td>
</tr>

Exemple 930. Travailler avec 2 cycles ou plus

Pour utiliser 2 cycles, il faut renseigner leurs noms. Ca se passe


au niveau du second paramètre de la méthode cycle. $this-
>cycle(array("#F0F0F0","#FFFFFF"),'cycle2'). setName($name) peut aussi
être utilisée.

<?php foreach ($this->books as $book):?>


<tr style="background-color:<?php echo $this->cycle(array("#F0F0F0",
"#FFFFFF"))
->next()?>">
<td><?php echo $this->cycle(array(1,2,3),'number')->next()?></td>

1538
Zend_View

<td><?php echo $this->escape($book['author'])?></td>


</tr>
<?php endforeach;?>

4.1.5. L'aide de vue Partial


L'aide de vue Partial est utilisée pour effectuer le rendu d'un modèle ("template") spécifique
dans sa propre portée de variable. L'utilisation principale est pour les fragments réutilisables de
modèle avec lesquels vous n'avez pas besoin de vous inquiéter des conflits de noms de variable.
De plus, ils vous permettent de spécifier les scripts de vue partiels dans des modules spécifiques.

Une soeur de l'aide Partial, l'aide de vue de PartialLoop vous permet de passer des
données itératives, et effectue un rendu partiel pour chaque élément.

Compteur de PartialLoop
L'aide de vue PartialLoop assigne une variable à la vue nommée
partialCounter qui fournit la position courante du tableau au script de vue.
Ce qui permet simplement d'avoir des couleurs alternatives dans les lignes d'un
tableau par exemple.

Exemple 931. Utilisation de base des Partials

L'utilisation de base des Partials est d'effectuer le rendu d'un fragment de modèle dans
sa propre portée de vue. Examinez le script partiel suivant :

<!--partiel.phtml-->
<ul>
<li>De : <?php echo $this->escape($this->de) ?></li>
<li>Sujet : <?php echo $this->escape($this->sujet) ?></li>
</ul>

Vous l'appelleriez alors dans votre script de vue en utilisant ce qui suit :

<?php echo $this->partial('partiel.phtml', array(


'de' => 'Equipe Framework',
'sujet' => 'vues partielles')); ?>

Qui vous retournerait :

<ul>
<li>De : Equipe Framework</li>
<li>Sujet : vues partielles</li>
</ul>

Qu'est qu'un modèle ?


Un modèle utilisé avec l'aide de vue Partial peut être un des suivants :

• Tableaux ("array") : si un tableau est fourni, il devrait être associatif, car ses
paires de clé/valeur sont assignées à la vue avec les clés comme variables
de vue.

• Objet implémentant la méthode toArray() : si un objet est fourni et qu'il possède


une méthode toArray(), le résultat de toArray() sera assigné à la vue
comme variable de vue.

1539
Zend_View

• Objet standard : tout autre objet assignera le résultat de


object_get_vars() (essentiellement toutes les propriétés publiques de
l'objet) à l'objet de vue.

Si votre modèle est un objet, vous pouvez vouloir le fournir en tant qu'objet au
script partiel, plutôt que de le sérialiser en un tableau de variables. Vous pouvez
faire ceci en paramétrant la propriété "objectKey" de l'aide de vue approprié :

// Tell partial to pass objects as 'model' variable


$view->partial()->setObjectKey('model');

// Tell partial to pass objects from partialLoop as 'model' variable in final


// partial view script:
$view->partialLoop()->setObjectKey('model');

Cette technique est particulièrement utile quand vous fournissez un


Zend_Db_Table_Rowsets à partialLoop(), ainsi vous avez un accès
complet à vos objets Row à l'intérieur de vos scripts de vue, permettant d'appeler
des méthodes sur ceux-ci (comme récupérer des valeurs d'un Row parent ou
dépendant).

1540
Zend_View

Exemple 932. Utiliser PartialLoop pour effectuer le rendu d'éléments itératifs

Typiquement, vous voudrez employer des Partials dans une boucle, pour rendre le même
fragment de contenu plusieurs fois ; de cette façon vous pouvez mettre de grands blocs de
contenu répété ou de logique complexe d'affichage dans un endroit unique. Toutefois ceci
a un impact d'exécution, car l'aide Partial doit être appelée une fois par itération.

L'aide de vue PartialLoop résout ce problème. Elle vous permet de fournir un élément
itérable (tableau ou objet implémentant Iterator) comme modèle. Elle réitère alors au-
dessus de celui-ci en fournissant les éléments au script partiel. Les éléments dans l'itérateur
peuvent être n'importe quel modèle que l'aide de vue Partial permet (cf. ci-dessus).

Considérons le script partiel suivant :

<!--partialLoop.phtml-->
<dt><?php echo $this->key ?></dt>
<dd><?php echo $this->value ?></dd>

Et le "modèle" suivant :

$model = array(
array('key' => 'Mammifère', 'value' => 'Chameau'),
array('key' => 'Oiseau', 'value' => 'Pingouin'),
array('key' => 'Reptile', 'value' => 'Asp'),
array('key' => 'Poisson', 'value' => 'Flounder')
);

Dans votre script de vue, vous pouvez maintenant appeler l'aide PartialLoop :

<dl>
<?php echo $this->partialLoop('partialLoop.phtml', $model) ?>
</dl>

<dl>
<dt>Mammifère</dt>
<dd>Chameau</dd>

<dt>Oiseau</dt>
<dd>Pingouin</dd>

<dt>Reptile</dt>
<dd>Asp</dd>

<dt>Poisson</dt>
<dd>Flounder</dd>

</dl>

1541
Zend_View

Exemple 933. Effectuer le rendu partiel dans des modules différents

Parfois un partiel existera dans un module différent. Si vous connaissez le nom du module,
vous pouvez le fournir comme deuxième argument à partial() ou à partialLoop(),
en déplaçant l'argument $model à la troisième position.

Par exemple, s'il y a un gestionnaire de page partiel que vous souhaitez utiliser et qui est
dans le module "liste", vous pourriez le saisir comme suit :

<?php echo $this->partial('pager.phtml', 'liste', $pagerData) ?>

De cette façon, vous pouvez réutiliser des partiels créés spécifiquement pour d'autre
modules. Ceci dit, il est probablement une meilleure pratique de mettre des partiels
réutilisables dans des dossiers partagés de script de vue.

4.1.6. L'aide de vue Placeholder

NDT. : Le terme "placeholder est conservé car sa signification varie en fonction


du contexte : conteneur générique ou emplacement réservé.

L'aide de vue Placeholder est utilisé pour faire persister le contenu entre les scripts de vues
et les instances de vues. Il offre aussi des fonctionnalités utiles comme l'agrégation de contenu,
la capture de contenu de scripts de vues pour une utilisation ultérieure, et l'ajout de texte pré ou
post contenu (et la personnalisation des séparateurs de contenu).

Exemple 934. Utilisation basique des Placeholders

L'utilisation basique des placeholders est la persistance des données de vue. Chaque appel
de l'aide Placeholder attend un nom de placeholder ; l'aide retourne un objet conteneur
que vous pouvez soit manipuler ou simplement envoyé à l'affichage.

<?php $this->placeholder('foo')->set("Du texte pour plus tard") ?>


<?php
echo $this->placeholder('foo');
// outputs "Du texte pour plus tard"
?>

1542
Zend_View

Exemple 935. Utilisation des Placeholders pour agréger du contenu

L'agrégation du contenu via les placeholders peut être aussi utile parfois. Par exemple,
votre script de vue peut avoir une variable sous forme de tableau à partir de laquelle vous
souhaitez récupérer des messages à afficher plus tard ; un autre script de vue peut ensuite
déterminer de la manière suivant laquelle ils seront affichés.

L'aide de vue Placeholder utilise des conteneurs qui étendent ArrayObject, fournissant
de riches fonctionnalités de manipulations des tableaux. De plus, il offre une variété de
méthodes pour le formatage du contenu stockée dans le conteneur :

• setPrefix($prefix) paramètre le texte qui sera placé préalablement à tout le


contenu. Utilisez getPrefix() à tout moment pour déterminer le réglage courant.

• setPostfix($prefix) paramètre le texte qui sera placé après tout le contenu. Utilisez
getPostfix() à tout moment pour déterminer le réglage courant.

• setSeparator($prefix) paramètre le texte qui sera placé entre chaque élément de


contenu. Utilisez getSeparator() à tout moment pour déterminer le réglage courant.

• setIndent($prefix) peut être utilisé pour paramétrer une indentation pour chaque
élément du contenu. Si un entier est fourni, il s'agira du nombre d'espaces à utiliser ;
si une chaîne est fournie, elle sera utilisée. Utilisez getIndent() à tout moment pour
déterminer le réglage courant.

<!-- premier script de vue -->


<?php $this->placeholder('foo')->exchangeArray($this->data) ?>

<!-- autre script (plus tard) -->


<?php
$this->placeholder('foo')->setPrefix("<ul>\n <li>")
->setSeparator("</li><li>\n")
->setIndent(4)
->setPostfix("</li></ul>\n");
?>
<?php
echo $this->placeholder('foo');
// affiche une liste non-ordonnée avec une belle indentation
?>

Puisque l'objet conteneur Placeholder étend ArrayObject, vous pouvez ainsi


facilement assigner du contenu à une clé du conteneur en particulier, plutôt que de
simplement de les envoyer les unes après les autres ("push"). Les clés peuvent être
accédées soit en utilisant les propriétés d'objet ou comme les clés d'un tableau.

<?php $this->placeholder('foo')->bar = $this->data ?>


<?php echo $this->placeholder('foo')->bar ?>
<?php
$foo = $this->placeholder('foo');
echo $foo['bar'];
?>

1543
Zend_View

Exemple 936. Utilisation des Placeholders pour capturer le contenu

Occasionnellement vous pouvez avoir du contenu pour un placeholder dans un script de


vue qui est simple à mettre sous forme de modèle ("template") ; l'aide de vue Placeholder
vous permet de capturer tout contenu arbitraire pour un rendu ultérieur en utilisant l'API
suivante.

• captureStart($type, $key) commence la capture de contenu.

$type doit être une des constantes de Placeholder : APPEND ou SET. Si c'est
APPEND, le contenu capturé est ajouté à la liste de contenu courant dans le placeholder ;
si c'est SET, le contenu capturé remplace toute valeur existante dans le placeholder
(potentiellement permet de remplacer tout contenu préalable). Par défaut, $type vaut
APPEND.

$key peut être utilisé pour spécifier une clé en particulier dans le conteneur placeholder
dans laquelle vous souhaitez capturer le contenu.

captureStart() verrouille la capture jusqu'à l'appel de captureEnd() ; vous ne


pouvez pas imbriquer des captures avec le même conteneur placeholder. Le faire
entraînera la levée d'une exception.

• captureEnd() stoppe la capture de contenu, et le place dans l'objet conteneur suivant


la manière utilisée pour appeler captureStart().

<!-- Default capture: append -->


<?php $this->placeholder('foo')->captureStart();
foreach ($this->data as $datum): ?>
<div class="foo">
<h2><?php echo $datum->title ?></h2>
<p><?php echo $datum->content ?></p>
</div>
<?php endforeach; ?>
<?php $this->placeholder('foo')->captureEnd() ?>
<?php echo $this->placeholder('foo') ?>

<!-- Capture to key -->


<?php $this->placeholder('foo')->captureStart('SET', 'data');
foreach ($this->data as $datum): ?>
<div class="foo">
<h2><?php echo $datum->title ?></h2>
<p><?php echo $datum->content ?></p>
</div>
<?php endforeach; ?>
<?php $this->placeholder('foo')->captureEnd() ?>
<?php echo $this->placeholder('foo')->data ?>

4.1.6.1. Implémentation concrète des Placeholder

Zend Framework embarque certaines implémentations concrètes de placeholders. Celles-ci sont


destinées à des placeholders communément utilisés : doctype, titre de page, et les différents
éléments <head>. Dans tous les cas, appeler le placeholder sans arguments retournera l'élément
lui-même.

La documentation pour chacun des éléments existe séparément, suivez les liens ci-dessous :

• Doctype

1544
Zend_View

• HeadLink

• HeadMeta

• HeadScript

• HeadStyle

• HeadTitle

• InlineScript

4.1.7. L'aide de vue Doctype


Les documents HTML et XHTML valides doivent inclure une déclaration DOCTYPE. Sans compter
qu'ils sont difficiles à garder en mémoire, ceux-ci peuvent aussi affecter la façon dont certains
éléments du document peuvent être rendus (par exemple, les échappements CDATA dans
<script> et les éléments <style>.

L'aide Doctype vous permet de spécifier un des types suivants :

• XHTML11

• XHTML1_STRICT

• XHTML1_TRANSITIONAL

• XHTML1_FRAMESET

• XHTML_BASIC1

• HTML4_STRICT

• HTML4_LOOSE

• HTML4_FRAMESET

• HTML5

Vous pouvez aussi spécifier un doctype personnalisé du moment que celui-ci soit correctement
formé.

L'aide Doctype est une implémentation concrète de l'aide Conteneur.

Exemple 937. Utilisation basique de l'aide Doctype

Vous pouvez spécifier le doctype à n'importe quel moment. Cependant, les aides de vues
qui utilisent pour leur affichage ne le reconnaissent qu'une fois qu'il a été paramètré, donc
la manière la plus simple est de le spécifier dans votre fichier d'amorçage :

$doctypeHelper = new Zend_View_Helper_Doctype();


$doctypeHelper->doctype('XHTML1_STRICT');

Ensuite vous l'affichez en début de votre layout :

<?php echo $this->doctype() ?>

1545
Zend_View

Exemple 938. Récupérer le Doctype

Si vous avez besoin du doctype, vous pouvez le récupérer par l'appel de getDoctype()
sur l'objet.

$doctype = $view->doctype()->getDoctype();

Typiquement, vous pouvez simplement vouloir savoir si le doctype est XHTML ou non ; pour
ceci, la méthode isXhtml() vous suffira :

if ($view->doctype()->isXhtml()) {
// faire qqch de différent
}

Vous pouvez aussi vérifier si le doctype représente un document HTML5 :

if ($view->doctype()->isHtml5()) {
// faire qqch de différent
}

4.1.8. L'aide de vue HeadLink


L'élément HTML <link> est de plus en plus employé pour lier différents types de ressources à
votre site : feuilles de styles, syndication, icônes, trackbacks et d'autres. L'aide HeadLink fournit
une interface simple pour créer et agréger ces éléments pour la récupération postérieure et le
rendement dans votre script d'affichage.

L'aide HeadLink possède des méthodes pour ajouter des liens de feuilles de style dans sa pile :

• appendStylesheet($href, $media, $conditionalStylesheet, $extras)

• offsetSetStylesheet($index, $href, $media, $conditionalStylesheet,


$extras)

• prependStylesheet($href, $media, $conditionalStylesheet, $extras)

• setStylesheet($href, $media, $conditionalStylesheet, $extras)

La valeur par défaut de $media vaut screen, mais peut être n'importe quelle valeur de média
valide. $conditionalStylesheet est une chaîne ou le booléen FALSE, et sera utilisé au
moment du rendu pour déterminer si des commentaires spéciaux doivent être inclus pour
empêcher le chargement de la feuille de style sur certaines plate-formes. $extras est un tableau
de valeurs supplémentaires que vous voulez ajouter à la balise.

De plus, l'aide HeadLink possède des méthodes pour ajouter des liens alternatifs dans sa pile :

• appendAlternate($href, $type, $title, $extras)

• offsetSetAlternate($index, $href, $type, $title, $extras)

• prependAlternate($href, $type, $title, $extras)

• setAlternate($href, $type, $title, $extras)

La méthode headLink() de l'aide permet de spécifier tous les attributs nécessaires à un


élément <link>, et vous permet aussi de préciser l'emplacement - le nouvel élément peut
remplacer tous les autres, s'ajouter au début ou à la fin de la liste.

1546
Zend_View

L'aide HeadLink est une implémentation concrète de l'aide Placeholder.

Exemple 939. Utilisation basique de l'aide HeadLink

Vous pouvez spécifier un headLink à n'importe quel moment. Typiquement, vous pouvez
spécifier des liens globaux dans votre script de disposition, et des liens spécifiques à
l'application dans vos scripts de vue. Dans votre script de disposition, dans la section
<head>, vous pourrez ensuite afficher le résultat de l'aide.

<?php // régler les liens dans votre script de vue :


$this->headLink()->appendStylesheet('/styles/basic.css')
->headLink(array('rel' => 'favicon',
'href' => '/img/favicon.ico'),
'PREPEND')
->prependStylesheet('/styles/moz.css',
'screen',
true,
array('id' => 'my_stylesheet'));
?>
<!-- effectuer le rendu -->
<?php echo $this->headLink() ?>

4.1.9. L'aide de vue HeadMeta


L'élément HTML <meta> est utilisé pour fournir des métadonnées concernant votre document
HTML - typiquement, les mots-clés, l'encodage du document, les directives de mise en cache,
etc. Les balises de métadonnées peuvent être soit de type "http-equiv" ou "name", doivent
contenir un attribut "content" et peuvent avoir aussi un attribut modificateur "lang" ou "scheme".

L'aide de vue HeadMeta supporte les méthodes suivantes pour le paramétrage et l'ajout de
métadonnées :

• appendName($keyValue, $content, $conditionalName)

• offsetSetName($index, $keyValue, $content, $conditionalName)

• prependName($keyValue, $content, $conditionalName)

• setName($keyValue, $content, $modifiers)

• appendHttpEquiv($keyValue, $content, $conditionalHttpEquiv)

• offsetSetHttpEquiv($index, $keyValue, $content,


$conditionalHttpEquiv)

• prependHttpEquiv($keyValue, $content, $conditionalHttpEquiv)

• setHttpEquiv($keyValue, $content, $modifiers)

Le paramètre $keyValue est utilisé pour définir une valeur pour la clé "name" ou "http-equiv" ;
$content est la valeur pour la clé "content", et $modifiers est un tableau associatif optionel
qui peut contenir les clés "lang" et/ou "scheme".

Vous pouvez aussi spécifier les métadonnées en utilisant la méthode headMeta() qui a
la signature suivante : headMeta($content, $keyValue, $keyType = 'name',
$modifiers = array(), $placement = 'APPEND'). $keyValue est le contenu de la
clé spécifiée dans $keyType, qui peut être "name" ou "http-equiv". $placement peut être soit
"SET" (efface toutes les valeurs sauvegardées précédentes), soit "APPEND" (ajout en fin de
pile), soit "PREPEND" (ajout en début de pile).

1547
Zend_View

HeadMeta surcharge chacune des méthodes append(), offsetSet(), prepend(), et


set(), pour imposer l'utilisation des méthodes spéciales énumérées ci-dessus. En interne, il
stocke chaque élément sous la forme d'un stdClass, qui peut ensuite être sérialiser grâce à la
méthode itemToString(). Ceci vous permet de réaliser des contrôles sur les éléments de la
pile, et optionnellement de modifier ces éléments simplement en modifiant l'objet retourné.

L'aide de vue HeadMeta est une implémentation concrète de l'aide Placeholder.

Exemple 940. Utilisation basique de l'aide HeadMeta

Vous pouvez spécifier une nouvelle métadonnée à n'importe quel moment. Typiquement,
vous pouvez spécifier les règles de mise en cache côté client ou les mots clés SEO (Search
Engine Optimization : pour l'optimisation des moteurs de recherche).

Par exemple, si vous souhaitez spécifier des mots clés SEO, vous devez créer une
métadonnée de type "name" ayant pour nom "keywords" et pour contenu les mots clés que
vous souhaitez associer à votre page :

// paramètrage des mots clés


$this->headMeta()->appendName('keywords', 'framework, PHP, productivité');

Si vous souhaitez paramètrer des règles de mise en cache côté client, vous devez créer
une métadonnée de type "http-equiv" avec les règles que vous souhaitez imposer :

// désactiver la mise en cache côté client


$this->headMeta()->appendHttpEquiv('expires',
'Wed, 26 Feb 1997 08:21:57 GMT')
->appendHttpEquiv('pragma', 'no-cache')
->appendHttpEquiv('Cache-Control', 'no-cache');

Une autre utilisation habituelle des métadonnées est le réglage du type de contenu ("content
type"), de l'encodage, et le langage :

// régler le type de contenu et l'encodage


$this->headMeta()->appendHttpEquiv('Content-Type', 'text/html; charset=UTF-8')
->appendHttpEquiv('Content-Language', 'fr-FR');

Si vous proposez un document HTML5, vous pouvez fournir l'encodage de cette manière :

// régler l'encodage en HTML5


$this->headMeta()->setCharset('UTF-8');
// donnera <meta charset="UTF-8">

Et comme exemple final, une manière simple d'afficher un message de transition avant une
redirection est d'utiliser une métadonnée "refresh" :

// paramètrer une métadonnée refresh pour 3 secondes


// avant une nouvel URL :
$this->headMeta()->appendHttpEquiv('Refresh',
'3;URL=http://www.some.org/some.html');

Quand vous êtes prêts à placer vos métadonnées dans votre script de disposition, réalisez
un "echo" de l'aide :

<?php echo $this->headMeta() ?>

1548
Zend_View

4.1.10. L'aide de vue HeadScript

L'élément HTML <script> est utilisé pour à la fois pour fournir des éléments de scripts côté-
client dans le code HTML et aussi pour lier une ressource distante contenant du script côté-
client. L'aide de vue HeadScript vous permet de gérer ces deux cas.

L'aide de vue HeadScript supportent les méthodes suivantes pour paramétrer ou ajouter des
scripts :

• appendFile($src, $type = 'text/javascript', $attrs = array())

• offsetSetFile($index, $src, $type = 'text/javascript', $attrs =


array())

• prependFile($src, $type = 'text/javascript', $attrs = array())

• setFile($src, $type = 'text/javascript', $attrs = array())

• appendScript($script, $type = 'text/javascript', $attrs = array())

• offsetSetScript($index, $script, $type = 'text/javascript', $attrs =


array())

• prependScript($script, $type = 'text/javascript', $attrs = array())

• setScript($script, $type = 'text/javascript', $attrs = array())

Dans le cas des méthodes de type *File(), $src est l'emplacement distant du script à charger ;
c'est généralement sous la forme d'une URL ou d'un chemin de fichier. Pour les méthode de
type *Script(), $script sont les directives de script côté-client que vous souhaitez utiliser
dans l'élément.

Paramétrez des commentaires conditionnels

HeadScript vous permet d'englober vos balises de script avec des


commentaires conditionnels, ce qui permet de les masquer pour des navigateurs
spécifiques. Pour ajouter les balises conditionnelles, fournissez le paramètre
conditional en tant que partie du paramètre $attrs lors de l'appel de la
méthode.

Exemple 941. Headscript avec des commentaires conditionnels

// adding scripts
$this->headScript()->appendFile('/js/prototype.js',
'text/javascript',
array('conditional' => 'lt IE 7');

HeadScript vous permet aussi de capturer des scripts ; ceci peut être utile si vous voulez créer
du script côté-client par programmation, et ensuite le placer n'importe où. Une utilisation de ceci
est montré dans un exemple ci-dessous.

Enfin, vous pouvez aussi utiliser la méthode headScript() pour rapidement ajouter des
éléments de script ; le prototype dans ce cas est headScript($mode = 'FILE', $spec,

1549
Zend_View

$placement = 'APPEND'). Le $mode est soit "FILE", soit "SCRIPT", suivant si vous liez un
script ou que vous en définissiez un. $spec est soit le script à lier ou la source du script elle-
même. $placement est "APPEND", "PREPEND", ou "SET".

HeadScript surcharge chacun des append(), offsetSet(), prepend(), et set() pour


imposer l'utilisation des méthodes spéciales énumérées ci-dessus. En interne, il stocke chaque
élément sous la forme d'un stdClass, qui peut être ensuite sérialisé grâce à la méthode
itemToString(). Ceci vous permet de réaliser des vérifications sur les éléments dans la pile,
et optionnellement de les modifier en modifiant simplement l'objet retourné.

L'aide HeadScript est une implémentation concrète de l'aide Conteneur.

Utilisez InlineScript pour les scripts dans le corps ("body") du


HTML

L'aide de vue, InlineScript, similaire à HeadScript devrait être utilisée quand


vous souhaitez inclure des scripts dans le corps ("body") du HTML. Placer ces
scripts en fin du document est une bonne pratique pour accélérer l'envoi de votre
page, particulièrement pour les scripts tiers d'analyse.

Les attributs arbitraires sont désactivées par défaut

Par défaut, HeadScript affichera seulement les attributs de <script>


approuvés par le W3C. Ceux-ci inclus "type", "charset", "defer",
"language", et "src". Cependant, certaines bibliothèques javascript,
notamment Dojo, utilise des attributs personnalisés dans le but de modifier le
comportement. Pour autoriser ce type d'attribut, vous pouvez les activer grâce à
la méthode setAllowArbitraryAttributes() :

$this->headScript()->setAllowArbitraryAttributes(true);

1550
Zend_View

Exemple 942. Utilisation basique de l'aide HeadScript

Vous devriez ajouter une nouvelle balise de script à chaque fois. Comme noté ci-dessus,
ceux-ci peuvent être des liens vers des ressources externes ou vers les scripts eux-mêmes.

// ajout de scripts
$this->headScript()->appendFile('/js/prototype.js')
->appendScript($onloadScript);

L'ordre est souvent important avec les scripts côté-client ; vous devez vous assurer de
charger les librairies dans un ordre spécifique en fonction de leurs dépendances ; utilisez à
la fois les directives append, prepend, et offsetSet pour vous aider dans cette tâche :

// mettre les scripts dans l'ordre

// placer celui-ci à un offset particulier pour s'assurer


// de le charger en dernier
$this->headScript()->offsetSetFile(100, '/js/myfuncs.js');

// utiliser les effets de scriptaculous (append utilise


// l'index suivant, c-à-d. 101)
$this->headScript()->appendFile('/js/scriptaculous.js');

// mais dans tous les cas, le script de base prototype


// doit être chargé en premier :
$this->headScript()->prependFile('/js/prototype.js');

Quand vous êtes finalement prêt à afficher tous les scripts dans votre layout, faîtes
simplement un echo de l'aide :

<?php echo $this->headScript() ?>

Exemple 943. Capturer les scripts en utilisant l'aide HeadScript

Parfois vous devez générer des scripts côté-client par programme. Même si vous pouvez
employer la concaténation de chaînes, les "heredocs", ou tout autre équivalent, il est souvent
plus facile de faire juste la création des scripts et de les entourer par des balises PHP.
HeadScript vous permet de le faire, et capture ainsi l'élément dans la pile :

<?php $this->headScript()->captureStart() ?>


var action = '<?php echo $this->baseUrl ?>';
$('foo_form').action = action;
<?php $this->headScript()->captureEnd() ?>

Les suppositions suivantes sont considérées :

• Les déclarations de scripts sont ajoutées à la pile. Si vous souhaitez qu'elles remplacent la
pile ou qu'elles soient ajoutées en début de pile, vous devez fournir "SET" ou "PREPEND",
en tant que premier argument de captureStart().

• Le type MIME est considéré comme étant "text/javascript" ; si vous souhaitez


spécifier un type différent, vous devez le fournir en tant que deuxième argument de
captureStart().

• Si vous souhaitez spécifier un quelconque attribut additionnel pour la balise <script>,


fournissez-le sous la forme d'un tableau en troisième argument de captureStart().

1551
Zend_View

4.1.11. L'aide de vue HeadStyle


L'élément HTML <style> est utilisé pour inclure des feuilles de styles CSS à l'intérieur de
l'élément HTML <head>.

Utilisez HeadLink pour lier des fichiers CSS externes

HeadLink devrait être utilisé pour inclure des feuilles de styles externes.
HeadStyle ne devrait être utilisé que si vous souhaitez définir des feuilles de
styles internes.

L'aide de vue HeadStyle supporte les méthodes suivantes pour l'ajout et le paramétrage des
déclarations de feuilles de styles :

• appendStyle($content, $attributes = array())

• offsetSetStyle($index, $content, $attributes = array())

• prependStyle($content, $attributes = array())

• setStyle($content, $attributes = array())

Dans tous les cas, $content est le contenu des déclarations CSS. $attributes sont les
attributs additionnels que vous pouvez fournir à la balise style : "lang", "title", "media", ou "dir"
sont autorisés.

Paramétrez des commentaires conditionnels

HeadStyle vous permet d'englober vos balises de style avec des commentaires
conditionnels, ce qui permet de les masquer pour des navigateurs spécifiques.
Pour ajouter les balises conditionnelles, fournissez le paramètre conditional
en tant que partie du paramètre $attrs lors de l'appel de la méthode.

Exemple 944. HeadStyle avec des commentaires conditionnels

// adding scripts
$this->headStyle()->appendStyle($styles, array('conditional' => 'lt IE 7'));

HeadStyle permet aussi la capture des déclarations de style ; ceci peut être utile si vous voulez
créer des déclarations par programme, et ensuite les placer à un autre endroit. L'utilisation de
cette fonctionnalité est montrée dans un exemple ci-dessous.

Enfin, vous pouvez utiliser la méthode headStyle() pour ajouter rapidement des éléments
de déclarations ; la signature de la méthode est headStyle($content$placement =
'APPEND', $attributes = array()). $placement peut être "APPEND", "PREPEND",
ou "SET".

HeadStyle surcharge chacune des méthodes append(), offsetSet(), prepend(), et


set() pour imposer l'utilisation des méthodes spéciales listées ci-dessus. En interne, il stocke
chaque élément sous la forme d'un stdClass, qui est ensuite sérialisé en utilisant la méthode
itemToString(). Ceci vous permet de réaliser des vérifications sur les éléments de la pile, et
optionnellement modifier ces éléments en modifiant simplement l'objet retourné.

L'aide HeadStyle est une implémentation concrète de l'aide Placeholder.

1552
Zend_View

UTF-8 encoding used by default

By default, Zend Framework uses UTF-8 as its default encoding, and, specific to
this case, Zend_View does as well. Character encoding can be set differently on
the view object itself using the setEncoding() method (or the the encoding
instantiation parameter). However, since Zend_View_Interface does not
define accessors for encoding, it's possible that if you are using a custom view
implementation with this view helper, you will not have a getEncoding()
method, which is what the view helper uses internally for determining the
character set in which to encode.

If you do not want to utilize UTF-8 in such a situation, you will need to implement
a getEncoding() method in your custom view implementation.

Exemple 945. Utilisation basique de l'aide HeadStyle

Vous pouvez spécifier une nouvelle balise de style à n'importe quel moment :

// ajout de styles
$this->headStyle()->appendStyle($styles);

L'ordre est très important avec les CSS ; vous pouvez devoir assurer que les déclarations
soient chargées dans un ordre spécifique dû à l'ordre de la cascade ; employez les diverses
directives "append", "prepend", et "offsetSet" pour faciliter cette tâche :

// Mettre les styles dans le bon ordre

// - placer à un offset particulier


$this->headStyle()->offsetSetStyle(100, $stylesPerso);

// - placer à la fin
$this->headStyle()->appendStyle($stylesFinaux);

// - placer au début
$this->headStyle()->prependStyle($stylesInitiaux);

Quand vous êtes finalement prêt à afficher toutes les déclarations de styles dans votre script
de layout, faîtes un simple echo de l'aide :

<?php echo $this->headStyle() ?>

1553
Zend_View

Exemple 946. Capturer les déclarations de style en utilisant l'aide HeadStyle

Parfois vous devez produire des déclarations de styles CSS par programme. Même si vous
pouvez employer la concaténation de chaînes, les "heredocs", ou tout autre équivalent, il
est souvent plus facile de faire juste la création des styles et de les entourer par des balises
PHP. HeadStyle vous permet de le faire, et capture ainsi l'élément dans la pile :

<?php $this->headStyle()->captureStart() ?>


body {
background-color: <?php echo $this->bgColor ?>;
}
<?php $this->headStyle()->captureEnd() ?>

Les suppositions suivantes sont considérées :

• Les déclarations de styles sont ajoutées à la pile. Si vous souhaitez qu'elles remplacent la
pile ou qu'elles soient ajoutées en début de pile, vous devez fournir "SET" ou "PREPEND",
en tant que premier argument de captureStart().

• Si vous souhaitez spécifier un quelconque attribut additionnel pour la balise <style>,


fournissez-le sous la forme d'un tableau en deuxième argument de captureStart().

4.1.12. L'aide de vue HeadTitle

L'élément HTML <title> est utilisé pour fournir un titre à un document HTML. L'aide
HeadTitle vous permet par programme de créer et de stocker le titre afin de le récupérer plus
tard et de l'afficher.

L'aide HeadTitle est une implémentation concrète de l'aide Placeholder. Elle surcharge la
méthode toString() pour forcer la génération d'un élément <title>, et ajoute une méthode
headTitle() pour des réglages faciles et rapides et pour l'aggrégation des éléments du titre.
La signature de la méthode est headTitle($title, $setType = 'APPEND') ; par défaut,
la valeur est ajoutée en fin de pile (pour aggréger les segments du titre), mais vous pouvez aussi
spécifier "PREPEND" (pour l'ajouter en début de pile) ou "SET" (pour remplacer la pile existante).

1554
Zend_View

Exemple 947. Utilisation basique de l'aide HeadTitle

Vous pouvez spécifier la balise de titre à n'importe quel moment. Un usage typique serait
de paramètrer les différents segments du titre à chaque niveau de profondeur de votre
application : site, module, contrôleur, action et ressources potentielles.

// Paramétrage des noms de contrôleurs et d'action


// en tant que segment de titre :
$request = Zend_Controller_Front::getInstance()->getRequest();
$this->headTitle($request->getActionName())
->headTitle($request->getControllerName());

// Réglage du nom de site, par exemple dans votre script


// de disposition :
$this->headTitle('Zend Framework');

// Réglage de la haîne de séparation des segments :


$this->headTitle()->setSeparator(' / ');

Quand vous êtes finalement prêt à afficher le titre dans votre script de disposition, faîtes
simplement un echo de l'aide :

<!-- Affiche <action> / <controller> / Zend Framework -->


<?php echo $this->headTitle() ?>

4.1.13. L'aide de vue HTML Object


L'élément HTML <object> est utilisé pour inclure un média comme Flash ou QuickTime dans
les pages Web. L'aide de vue Object vous aide à réaliser ceci avec un minimum d'effort.

Il existe quatre aides de vue Object initiaux :

• htmlFlash : génère le balisage pour l'inclusion de fichiers Flash.

• htmlObject : génère le balisage pour l'inclusion d'objets personnalisés.

• htmlPage : génère le balisage pour l'inclusion d'autres pages (X)HTML.

• htmlQuicktime : génère le balisage pour l'inclusion de fichiers QuickTime.

Toutes ces aides partagent une interface similaire. Pour cette raison, cette documentation ne
présentera des exemples que pour deux de ces aides.

Exemple 948. Aide de vue Flash

Inclure du Flash dans votre page est assez simple. Le seul argument requis est l'URI de
la ressource.

<?php echo $this->htmlFlash('/path/to/flash.swf'); ?>

Ceci affichera le code HTML suivant :

<object data="/path/to/flash.swf" type="application/x-shockwave-flash"


classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
</object>

1555
Zend_View

Cependant vous pouvez aussi spécifier des attributs, des paramètres et du contenu qui peuvent
être affichés avec la balise <object>. Ceci peut être montré avec l'aide de vue htmlObject.

Exemple 949. Personnalisation d'un objet en fournissant des arguments


additionnels

Le premier argument de l'aide Object est toujours requis. Il s'agit de l'URI de la ressource
à inclure. Le second argument est seulement requis par l'aide htmlObject. Les autres
aides contiennent déjà la bonne valeur pour cet argument. Le troisième argument est
utilisé pour fournir des attributs à l'élément object. Seul un tableau de paires clé/valeur
est accepté. classid ou codebase sont des exemples de tels attributs. Le quatrième
paramètre ne prend aussi qu'un tableau de paires clé/valeur est les utilise pour créer des
éléments <param>. Enfin, vous avez la possibilité de fournir un contenu additionnel à l'objet
en cinquième paramètre. Voici donc un exemple qui utilise tous le paramètres :

<?php echo $this->htmlObject(


'/path/to/file.ext',
'mime/type',
array(
'attr1' => 'aval1',
'attr2' => 'aval2'
),
array(
'param1' => 'pval1',
'param2' => 'pval2'
),
'some content'
); ?>

Ceci affichera le code HTML suivant :

<object data="/path/to/file.ext" type="mime/type"


attr1="aval1" attr2="aval2">
<param name="param1" value="pval1" />
<param name="param2" value="pval2" />
some content
</object>

4.1.14. L'aide de vue InlineScript


L'élément HTML <script> est utilisé pour fournir des éléments de script côté client ou pour
lier des ressources distantes contenant des scripts s'exécutant côté client. L'aide de vue
InlineScript vous permet de gérer ces deux cas. Elle est dérivée de l'aide HeadScript, et
chaque méthode de cette aide est donc disponible ; cependant, vous devez utiliser la méthode
inlineScript() au lieu de headScript().

Utiliser InlineScript pour des scripts dans le corps ("body") HTML

InlineScript, peut être utilisé quand vous souhaitez inclure des scripts dans
votre body HTML. Placer ces scripts en fin de votre document est une bonne
pratique pour améliorer la vitesse de distribution de votre page, particulièrement
quand vous utilisez des scripts d'analyses fournis par des tiers.

Certaines librairies JS doivent être incluses dans la partie head du HTML ; utilisez
l'aide vue HeadScript pour ces scripts.

1556
Zend_View

4.1.15. L'aide de vue JSON


Quand vous créez des vues qui retournent du JSON, il est important de paramétrer aussi les
en-têtes de réponse appropriés. L'aide vue JSON réalise exactement cela. De plus, par défaut,
elle désactive l'éventuel layout (s'il est activé), puisque les layouts sont rarement utilisés dans
les réponses JSON.

L'aide de vue JSON ajoute l'en-tête suivant :

Content-Type: application/json

Beaucoup de librairies AJAX recherche cet en-tête quand elles analysent les réponses pour
déterminer comment le contenu doit être géré.

L'utilisation de l'aide de vue JSON est très simple :

<?php echo $this->json($this->data) ?>

Keeping layouts and enabling encoding using Zend_Json_Expr

Each method in the JSON helper accepts a second, optional argument. This
second argument can be a boolean flag to enable or disable layouts, or an array
of options that will be passed to Zend_Json::encode() and used internally to
encode data.

To keep layouts, the second parameter needs to be boolean TRUE. When the
second parameter is an array, keeping layouts can be achieved by including a
keepLayouts key with a value of a boolean TRUE.

// Boolean true as second argument enables layouts:


echo $this->json($this->data, true);

// Or boolean true as "keepLayouts" key:


echo $this->json($this->data, array('keepLayouts' => true));

Zend_Json::encode allows the encoding of native JSON expressions using


Zend_Json_Expr objects. This option is disabled by default. To enable this
option, pass a boolean TRUE to the enableJsonExprFinder key of the options
array:

<?php echo $this->json($this->data, array(


'enableJsonExprFinder' => true,
'keepLayouts' => true,
)) ?>

4.1.16. Navigation Helpers


The navigation helpers are used for rendering navigational elements from
Zend_Navigation_Container instances.

There are 5 built-in helpers:

• Breadcrumbs, used for rendering the path to the currently active page.

1557
Zend_View

• Links, used for rendering navigational head links (e.g. <link rel="next" href="..." />)

• Menu, used for rendering menus.

• Sitemap, used for rendering sitemaps conforming to the Sitemaps XML format.

• Navigation, used for proxying calls to other navigational helpers.

All built-in helpers extend Zend_View_Helper_Navigation_HelperAbstract, which


adds integration with ACL and translation. The abstract class implements the interface
Zend_View_Helper_Navigation_Helper, which defines the following methods:

• getContainer() and setContainer() gets and sets the navigation container the helper
should operate on by default, and hasContainer() checks if the helper has container
registered.

• getTranslator() and setTranslator() gets and sets the translator used for translating
labels and titles. getUseTranslator() and setUseTranslator() controls whether the
translator should be enabled. The method hasTranslator() checks if the helper has a
translator registered.

• getAcl(), setAcl(), getRole() and setRole(), gets and sets ACL (Zend_Acl)
instance and role (String or Zend_Acl_Role_Interface) used for filtering out pages when
rendering. getUseAcl() and setUseAcl() controls whether ACL should be enabled. The
methods hasAcl() and hasRole() checks if the helper has an ACL instance or a role
registered.

• __toString(), magic method to ensure that helpers can be rendered by echoing the helper
instance directly.

• render(), must be implemented by concrete helpers to do the actual rendering.

In addition to the method stubs from the interface, the abstract class also implements the
following methods:

• getIndent() and setIndent() gets and sets indentation. The setter accepts a String or an
Integer. In the case of an Integer, the helper will use the given number of spaces for indentation.
I.e., setIndent(4) means 4 initial spaces of indentation. Indentation can be specified for all
helpers except the Sitemap helper.

• getMinDepth() and setMinDepth() gets and sets the minimum depth a page must have
to be included by the helper. Setting NULL means no minimum depth.

• getMaxDepth() and setMaxDepth() gets and sets the maximum depth a page can have
to be included by the helper. Setting NULL means no maximum depth.

• getRenderInvisible() and setRenderInvisible() gets and sets whether to render


items that have been marked as invisible or not.

• __call() is used for proxying calls to the container registered in the helper, which means
you can call methods on a helper as if it was a container. See example below.

• findActive($container, $minDepth, $maxDepth) is used for finding the deepest


active page in the given container. If depths are not given, the method will use the values

1558
Zend_View

retrieved from getMinDepth() and getMaxDepth(). The deepest active page must be
between $minDepth and $maxDepth inclusively. Returns an array containing a reference to
the found page instance and the depth at which the page was found.

• htmlify() renders an 'a' HTML element from a Zend_Navigation_Page instance.

• accept() is used for determining if a page should be accepted when iterating containers.
This method checks for page visibility and verifies that the helper's role is allowed access to
the page's resource and privilege.

• The static method setDefaultAcl() is used for setting a default ACL object that will be
used by helpers.

• The static method setDefaultRole() is used for setting a default ACL that will be used
by helpers

If a navigation container is not explicitly set in a helper using $helper->setContainer($nav),


the helper will look for a container instance with the key Zend_Navigation in the registry.
If a container is not explicitly set or found in the registry, the helper will create an empty
Zend_Navigation container when calling $helper->getContainer().

Exemple 950. Proxying calls to the navigation container

Navigation view helpers use the magic method __call() to proxy method calls to the
navigation container that is registered in the view helper.

$this->navigation()->addPage(array(
'type' => 'uri',
'label' => 'New page'));

The call above will add a page to the container in the Navigation helper.

4.1.16.1. Translation of labels and titles

The navigation helpers support translation of page labels and titles. You can set a translator
of type Zend_Translate or Zend_Translate_Adapter in the helper using $helper-
>setTranslator($translator), or like with other I18n-enabled components; by adding the
translator to the registry by using the key Zend_Translate.

If you want to disable translation, use $helper->setUseTranslator(false).

The proxy helper will inject its own translator to the helper it proxies to if the proxied helper doesn't
already have a translator.

There is no translation in the sitemap helper, since there are no page labels or
titles involved in an XML sitemap.

4.1.16.2. Integration with ACL

All navigational view helpers support ACL inherently from the class
Zend_View_Helper_Navigation_HelperAbstract. A Zend_Acl object can be assigned
to a helper instance with $helper->setAcl($acl), and role with $helper-
>setRole('member') or $helper->setRole(new Zend_Acl_Role('member')) . If

1559
Zend_View

ACL is used in the helper, the role in the helper must be allowed by the ACL to access a page's
resource and/or have the page's privilege for the page to be included when rendering.

If a page is not accepted by ACL, any descendant page will also be excluded from rendering.

The proxy helper will inject its own ACL and role to the helper it proxies to if the proxied helper
doesn't already have any.

The examples below all show how ACL affects rendering.

4.1.16.3. Navigation setup used in examples

This example shows the setup of a navigation container for a fictional software company.

Notes on the setup:

• The domain for the site is www.example.com.

• Interesting page properties are marked with a comment.

• Unless otherwise is stated in other examples, the user is requesting the URL http://
www.example.com/products/server/faq/, which translates to the page labeled FAQ
under Foo Server.

• The assumed ACL and router setup is shown below the container setup.

/*
* Navigation container (config/array)

* Each element in the array will be passed to


* Zend_Navigation_Page::factory() when constructing
* the navigation container below.
*/
$pages = array(
array(
'label' => 'Home',
'title' => 'Go Home',
'module' => 'default',
'controller' => 'index',
'action' => 'index',
'order' => -100 // make sure home is the first page
),
array(
'label' => 'Special offer this week only!',
'module' => 'store',
'controller' => 'offer',
'action' => 'amazing',
'visible' => false // not visible
),
array(
'label' => 'Products',
'module' => 'products',
'controller' => 'index',
'action' => 'index',
'pages' => array(
array(
'label' => 'Foo Server',
'module' => 'products',
'controller' => 'server',

1560
Zend_View

'action' => 'index',


'pages' => array(
array(
'label' => 'FAQ',
'module' => 'products',
'controller' => 'server',
'action' => 'faq',
'rel' => array(
'canonical' => 'http://www.example.com/?page=faq',
'alternate' => array(
'module' => 'products',
'controller' => 'server',
'action' => 'faq',
'params' => array('format' => 'xml')
)
)
),
array(
'label' => 'Editions',
'module' => 'products',
'controller' => 'server',
'action' => 'editions'
),
array(
'label' => 'System Requirements',
'module' => 'products',
'controller' => 'server',
'action' => 'requirements'
)
)
),
array(
'label' => 'Foo Studio',
'module' => 'products',
'controller' => 'studio',
'action' => 'index',
'pages' => array(
array(
'label' => 'Customer Stories',
'module' => 'products',
'controller' => 'studio',
'action' => 'customers'
),
array(
'label' => 'Support',
'module' => 'prodcts',
'controller' => 'studio',
'action' => 'support'
)
)
)
)
),
array(
'label' => 'Company',
'title' => 'About us',
'module' => 'company',
'controller' => 'about',
'action' => 'index',
'pages' => array(

1561
Zend_View

array(
'label' => 'Investor Relations',
'module' => 'company',
'controller' => 'about',
'action' => 'investors'
),
array(
'label' => 'News',
'class' => 'rss', // class
'module' => 'company',
'controller' => 'news',
'action' => 'index',
'pages' => array(
array(
'label' => 'Press Releases',
'module' => 'company',
'controller' => 'news',
'action' => 'press'
),
array(
'label' => 'Archive',
'route' => 'archive', // route
'module' => 'company',
'controller' => 'news',
'action' => 'archive'
)
)
)
)
),
array(
'label' => 'Community',
'module' => 'community',
'controller' => 'index',
'action' => 'index',
'pages' => array(
array(
'label' => 'My Account',
'module' => 'community',
'controller' => 'account',
'action' => 'index',
'resource' => 'mvc:community.account' // resource
),
array(
'label' => 'Forums',
'uri' => 'http://forums.example.com/',
'class' => 'external' // class
)
)
),
array(
'label' => 'Administration',
'module' => 'admin',
'controller' => 'index',
'action' => 'index',
'resource' => 'mvc:admin', // resource
'pages' => array(
array(
'label' => 'Write new article',
'module' => 'admin',

1562
Zend_View

'controller' => 'post',


'aciton' => 'write'
)
)
)
);

// Create container from array


$container = new Zend_Navigation($pages);

// Store the container in the proxy helper:


$view->getHelper('navigation')->setContainer($container);

// ...or simply:
$view->navigation($container);

// ...or store it in the reigstry:


Zend_Registry::set('Zend_Navigation', $container);

In addition to the container above, the following setup is assumed:

// Setup router (default routes and 'archive' route):


$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
$router->addDefaultRoutes();
$router->addRoute(
'archive',
new Zend_Controller_Router_Route(
'/archive/:year',
array(
'module' => 'company',
'controller' => 'news',
'action' => 'archive',
'year' => (int) date('Y') - 1
),
array('year' => '\d+')
)
);

// Setup ACL:
$acl = new Zend_Acl();
$acl->addRole(new Zend_Acl_Role('member'));
$acl->addRole(new Zend_Acl_Role('admin'));
$acl->add(new Zend_Acl_Resource('mvc:admin'));
$acl->add(new Zend_Acl_Resource('mvc:community.account'));
$acl->allow('member', 'mvc:community.account');
$acl->allow('admin', null);

// Store ACL and role in the proxy helper:


$view->navigation()->setAcl($acl)->setRole('member');

// ...or set default ACL and role statically:


Zend_View_Helper_Navigation_HelperAbstract::setDefaultAcl($acl);
Zend_View_Helper_Navigation_HelperAbstract::setDefaultRole('member');

4.1.16.4. Breadcrumbs Helper

Breadcrumbs are used for indicating where in a sitemap a user is currently browsing, and
are typically rendered like this: "You are here: Home > Products > FantasticProduct 1.0". The

1563
Zend_View

breadcrumbs helper follows the guidelines from Breadcrumbs Pattern - Yahoo! Design Pattern
Library, and allows simple customization (minimum/maximum depth, indentation, separator, and
whether the last element should be linked), or rendering using a partial view script.

The Breadcrumbs helper works like this; it finds the deepest active page in a navigation
container, and renders an upwards path to the root. For MVC pages, the "activeness"
of a page is determined by inspecting the request object, as stated in the section on
Zend_Navigation_Page_Mvc.

The helper sets the minDepth property to 1 by default, meaning breadcrumbs will not be
rendered if the deepest active page is a root page. If maxDepth is specified, the helper will stop
rendering when at the specified depth (e.g. stop at level 2 even if the deepest active page is
on level 3).

Methods in the breadcrumbs helper:

• {get|set}Separator() gets/sets separator string that is used between breadcrumbs.


Defualt is ' &gt; '.

• {get|set}LinkLast() gets/sets whether the last breadcrumb should be rendered as an


anchor or not. Default is FALSE.

• {get|set}Partial() gets/sets a partial view script that should be used for rendering
breadcrumbs. If a partial view script is set, the helper's render() method will use the
renderPartial() method. If no partial is set, the renderStraight() method is used.
The helper expects the partial to be a String or an Array with two elements. If the partial is a
String, it denotes the name of the partial script to use. If it is an Array, the first element will
be used as the name of the partial view script, and the second element is the module where
the script is found.

• renderStraight() is the default render method.

• renderPartial() is used for rendering using a partial view script.

Exemple 951. Rendering breadcrumbs

This example shows how to render breadcrumbs with default settings.

In a view script or layout:


<?php echo $this->navigation()->breadcrumbs(); ?>
The two calls above take advantage of the magic __toString() method,
and are equivalent to:
<?php echo $this->navigation()->breadcrumbs()->render(); ?>
Output:
<a href="/products">Products</a> <a href="/products/server">Foo Server</a> FAQ

Exemple 952. Specifying indentation

This example shows how to render breadcrumbs with initial indentation.

Rendering with 8 spaces indentation:


<?php echo $this->navigation()->breadcrumbs()->setIndent(8);?>
Output:
<a href="/products">Products</a> <a href="/products/server">Foo Server</a> FAQ

1564
Zend_View

Exemple 953. Customize breadcrumbs output

This example shows how to customze breadcrumbs output by specifying various options.

In a view script or layout:

<?php
echo $this->navigation()
->breadcrumbs()
->setLinkLast(true) // link last page
->setMaxDepth(1) // stop at level 1
->setSeparator(' &#9654;' . PHP_EOL); // cool separator with newline
?>
Output:
<a href="/products">Products</a> &amp;#9654;
<a href="/products/server">Foo Server</a>

/////////////////////////////////////////////////////

Setting minimum depth required to render breadcrumbs:

<?php
$this->navigation()->breadcrumbs()->setMinDepth(10);
echo $this->navigation()->breadcrumbs();
?>
Output:
Nothing, because the deepest active page is not at level 10 or deeper.

Exemple 954. Rendering breadcrumbs using a partial view script

This example shows how to render customized breadcrumbs using a partial vew script. By
calling setPartial(), you can specify a partial view script that will be used when calling
render(). When a partial is specified, the renderPartial() method will be called. This
method will find the deepest active page and pass an array of pages that leads to the active
page to the partial view script.

In a layout:

$partial = ;
echo $this->navigation()->breadcrumbs()
->setPartial(array('breadcrumbs.phtml', 'default'));

Contents of application/modules/default/views/breadcrumbs.phtml:

echo implode(', ', array_map(


create_function('$a', 'return $a->getLabel();'),
$this->pages));

Output:

Products, Foo Server, FAQ

4.1.16.5. Links Helper

The links helper is used for rendering HTML LINK elements. Links are used for describing
document relationships of the currently active page. Read more about links and link types at

1565
Zend_View

Document relationships: the LINK element (HTML4 W3C Rec.) and Link types (HTML4 W3C
Rec.) in the HTML4 W3C Recommendation.

There are two types of relations; forward and reverse, indicated by the keyords 'rel' and
'rev'. Most methods in the helper will take a $rel param, which must be either 'rel' or
'rev'. Most methods also take a $type param, which is used for specifying the link type (e.g.
alternate, start, next, prev, chapter, etc).

Relationships can be added to page objects manually, or found by traversing the container
registered in the helper. The method findRelation($page, $rel, $type) will first try to
find the given $rel of $type from the $page by calling $page->findRel($type) or $page-
>findRel($type). If the $page has a relation that can be converted to a page instance,
that relation will be used. If the $page instance doesn't have the specified $type, the helper
will look for a method in the helper named search$rel$type (e.g. searchRelNext() or
searchRevAlternate()). If such a method exists, it will be used for determining the $page's
relation by traversing the container.

Not all relations can be determined by traversing the container. These are the relations that will
be found by searching:

• searchRelStart(), forward 'start' relation: the first page in the container.

• searchRelNext(), forward 'next' relation; finds the next page in the container, i.e. the page
after the active page.

• searchRelPrev(), forward 'prev' relation; finds the previous page, i.e. the page before the
active page.

• searchRelChapter(), forward 'chapter' relations; finds all pages on level 0 except the 'start'
relation or the active page if it's on level 0.

• searchRelSection(), forward 'section' relations; finds all child pages of the active page if
the active page is on level 0 (a 'chapter').

• searchRelSubsection(), forward 'subsection' relations; finds all child pages of the active
page if the active pages is on level 1 (a 'section').

• searchRevSection(), reverse 'section' relation; finds the parent of the active page if the
active page is on level 1 (a 'section').

• searchRevSubsection(), reverse 'subsection' relation; finds the parent of the active page
if the active page is on level 2 (a 'subsection').

When looking for relations in the page instance ($page->getRel($type)


or $page->getRev($type)), the helper accepts the values of type String,
Array, Zend_Config, or Zend_Navigation_Page. If a string is found, it will
be converted to a Zend_Navigation_Page_Uri. If an array or a config is
found, it will be converted to one or several page instances. If the first key of
the array/config is numeric, it will be considered to contain several pages, and
each element will be passed to the page factory. If the first key is not numeric,
the array/config will be passed to the page factory directly, and a single page will
be returned.

The helper also supports magic methods for finding relations. E.g. to find forward
alternate relations, call $helper->findRelAlternate($page), and to find reverse

1566
Zend_View

section relations, call $helper->findRevSection($page). Those calls correspond


to $helper->findRelation($page, 'rel', 'alternate'); and $helper-
>findRelation($page, 'rev', 'section'); respectively.

To customize which relations should be rendered, the helper uses a render flag. The render flag
is an integer value, and will be used in a bitwse and (&) operation against the helper's render
constants to determine if the relation that belongs to the render constant should be rendered.

See the example below for more information.

• Zend_View_Helper_Navigation_Link::RENDER_ALTERNATE

• Zend_View_Helper_Navigation_Link::RENDER_STYLESHEET

• Zend_View_Helper_Navigation_Link::RENDER_START

• Zend_View_Helper_Navigation_Link::RENDER_NEXT

• Zend_View_Helper_Navigation_Link::RENDER_PREV

• Zend_View_Helper_Navigation_Link::RENDER_CONTENTS

• Zend_View_Helper_Navigation_Link::RENDER_INDEX

• Zend_View_Helper_Navigation_Link::RENDER_GLOSSARY

• Zend_View_Helper_Navigation_Link::RENDER_COPYRIGHT

• Zend_View_Helper_Navigation_Link::RENDER_CHAPTER

• Zend_View_Helper_Navigation_Link::RENDER_SECTION

• Zend_View_Helper_Navigation_Link::RENDER_SUBSECTION

• Zend_View_Helper_Navigation_Link::RENDER_APPENDIX

• Zend_View_Helper_Navigation_Link::RENDER_HELP

• Zend_View_Helper_Navigation_Link::RENDER_BOOKMARK

• Zend_View_Helper_Navigation_Link::RENDER_CUSTOM

• Zend_View_Helper_Navigation_Link::RENDER_ALL

The constants from RENDER_ALTERNATE to RENDER_BOOKMARK denote standard HTML link


types. RENDER_CUSTOM denotes non-standard relations that specified in pages. RENDER_ALL
denotes standard and non-standard relations.

Methods in the links helper:

• {get|set}RenderFlag() gets/sets the render flag. Default is RENDER_ALL. See examples


below on how to set the render flag.

• findAllRelations() finds all relations of all types for a given page.

1567
Zend_View

• findRelation() finds all relations of a given type from a given page.

• searchRel{Start|Next|Prev|Chapter|Section|Subsection}() traverses a
container to find forward relations to the start page, the next page, the previous page, chapters,
sections, and subsections.

• searchRev{Section|Subsection}() traverses a container to find reverse relations to


sections or subsections.

• renderLink() renders a single link element.

Exemple 955. Specify relations in pages

This example shows how to specify relations in pages.

$container = new Zend_Navigation(array(


array(
'label' => 'Relations using strings',
'rel' => array(
'alternate' => 'http://www.example.org/'
),
'rev' => array(
'alternate' => 'http://www.example.net/'
)
),
array(
'label' => 'Relations using arrays',
'rel' => array(
'alternate' => array(
'label' => 'Example.org',
'uri' => 'http://www.example.org/'
)
)
),
array(
'label' => 'Relations using configs',
'rel' => array(
'alternate' => new Zend_Config(array(
'label' => 'Example.org',
'uri' => 'http://www.example.org/'
))
)
),
array(
'label' => 'Relations using pages instance',
'rel' => array(
'alternate' => Zend_Navigation_Page::factory(array(
'label' => 'Example.org',
'uri' => 'http://www.example.org/'
))
)
)
));

1568
Zend_View

Exemple 956. Default rendering of links

This example shows how to render a menu from a container registered/found in the view
helper.

In a view script or layout:


<?php echo $this->view->navigation()->links(); ?>
Output:
<link rel="alternate" href="/products/server/faq/format/xml">
<link rel="start" href="/" title="Home">
<link rel="next" href="/products/server/editions" title="Editions">
<link rel="prev" href="/products/server" title="Foo Server">
<link rel="chapter" href="/products" title="Products">
<link rel="chapter" href="/company/about" title="Company">
<link rel="chapter" href="/community" title="Community">
<link rel="canonical" href="http://www.example.com/?page=server-faq">
<link rev="subsection" href="/products/server" title="Foo Server">

Exemple 957. Specify which relations to render

This example shows how to specify which relations to find and render.

Render only start, next, and prev:


$helper->setRenderFlag(Zend_View_Helper_Navigation_Links::RENDER_START |
Zend_View_Helper_Navigation_Links::RENDER_NEXT |
Zend_View_Helper_Navigation_Links::RENDER_PREV);

Output:
<link rel="start" href="/" title="Home">
<link rel="next" href="/products/server/editions" title="Editions">
<link rel="prev" href="/products/server" title="Foo Server">

Render only native link types:


$helper->setRenderFlag(Zend_View_Helper_Navigation_Links::RENDER_ALL ^
Zend_View_Helper_Navigation_Links::RENDER_CUSTOM);

Output:
<link rel="alternate" href="/products/server/faq/format/xml">
<link rel="start" href="/" title="Home">
<link rel="next" href="/products/server/editions" title="Editions">
<link rel="prev" href="/products/server" title="Foo Server">
<link rel="chapter" href="/products" title="Products">
<link rel="chapter" href="/company/about" title="Company">
<link rel="chapter" href="/community" title="Community">
<link rev="subsection" href="/products/server" title="Foo Server">

Render all but chapter:


$helper->setRenderFlag(Zend_View_Helper_Navigation_Links::RENDER_ALL ^
Zend_View_Helper_Navigation_Links::RENDER_CHAPTER);

Output:
<link rel="alternate" href="/products/server/faq/format/xml">
<link rel="start" href="/" title="Home">
<link rel="next" href="/products/server/editions" title="Editions">
<link rel="prev" href="/products/server" title="Foo Server">
<link rel="canonical" href="http://www.example.com/?page=server-faq">
<link rev="subsection" href="/products/server" title="Foo Server">

1569
Zend_View

4.1.16.6. Menu Helper

The Menu helper is used for rendering menus from navigation containers. By default, the menu
will be rendered using HTML UL and LI tags, but the helper also allows using a partial view script.

Methods in the Menu helper:

• {get|set}UlClass() gets/sets the CSS class used in renderMenu().

• {get|set}OnlyActiveBranch() gets/sets a flag specifying whether only the active branch


of a container should be rendered.

• {get|set}RenderParents() gets/sets a flag specifying whether parents should be


rendered when only rendering active branch of a container. If set to FALSE, only the deepest
active menu will be rendered.

• {get|set}Partial() gets/sets a partial view script that should be used for rendering menu.
If a partial view script is set, the helper's render() method will use the renderPartial()
method. If no partial is set, the renderMenu() method is used. The helper expects the partial
to be a String or an Array with two elements. If the partial is a String, it denotes the name of
the partial script to use. If it is an Array, the first element will be used as the name of the partial
view script, and the second element is the module where the script is found.

• htmlify() overrides the method from the abstract class to return span elements if the page
has no href.

• renderMenu($container = null, $options = array()) is the default render method,


and will render a container as a HTML UL list.

If $container is not given, the container registered in the helper will be rendered.

$options is used for overriding options specified temporarily without rsetting the values in
the helper instance. It is an associative array where each key corresponds to an option in the
helper.

Recognized options:

• indent; indentation. Expects a String or an int value.

• minDepth; minimum depth. Expcects an int or NULL (no minimum depth).

• maxDepth; maximum depth. Expcects an int or NULL (no maximum depth).

• ulClass; CSS class for ul element. Expects a String.

• onlyActiveBranch; whether only active branch should be rendered. Expects a Boolean


value.

• renderParents; whether parents should be rendered if only rendering active branch.


Expects a Boolean value.

If an option is not given, the value set in the helper will be used.

• renderPartial() is used for rendering the menu using a partial view script.

• renderSubMenu() renders the deepest menu level of a container's active branch.

1570
<?php echo $this->navigation()->menu() ?>
Output:
This example shows how to render a menu from a container registered/found in the view
<ul class="navigation">
helper. Notice how pages are filtered out based on visibility and ACL.
<li>
<a title="Go Home" Zend_View
href="/">Home</a>
</li>
<li class="active">
<a href="/products">Products</a>
Exemple 958. Rendering a menu
<ul>
<li class="active">
<a href="/products/server">Foo Server</a>
<ul>
<li class="active">
<a href="/products/server/faq">FAQ</a>
</li>
<li>
<a href="/products/server/editions">Editions</a>
</li>
<li>
<a href="/products/server/requirements">System Requirements</a>
</li>
</ul>
</li>
<li>
<a href="/products/studio">Foo Studio</a>
<ul>
<li>
<a href="/products/studio/customers">Customer Stories</a>
</li>
<li>
<a href="/prodcts/studio/support">Support</a>
</li>
</ul>
</li>
</ul>
</li>
<li>
<a title="About us" href="/company/about">Company</a>
<ul>
<li>
<a href="/company/about/investors">Investor Relations</a>
</li>
<li>
<a class="rss" href="/company/news">News</a>
<ul>
<li>
<a href="/company/news/press">Press Releases</a>
</li>
<li>
<a href="/archive">Archive</a>
</li>
</ul>
</li>
</ul>
</li>
<li>
<a href="/community">Community</a>
<ul>
<li>
<a href="/community/account">My Account</a>
</li>
<li>
<a class="external" href="http://forums.example.com/">Forums</a>
</li>
</ul>
</li>
</ul>

1571
Zend_View

Exemple 959. Calling renderMenu() directly

This example shows how to render a menu that is not registered in the view helper by calling
the renderMenu() directly and specifying a few options.

<?php
// render only the 'Community' menu
$community = $this->navigation()->findOneByLabel('Community');
$options = array(
'indent' => 16,
'ulClass' => 'community'
);
echo $this->navigation()
->menu()
->renderMenu($community, $options);
?>
Output:
<ul class="community">
<li>
<a href="/community/account">My Account</a>
</li>
<li>
<a class="external" href="http://forums.example.com/">Forums</a>
</li>
</ul>

1572
Zend_View

Exemple 960. Rendering the deepest active menu

This example shows how the renderSubMenu() will render the deepest sub menu of the
active branch.

Calling renderSubMenu($container, $ulClass, $indent) is equivalent to calling


renderMenu($container, $options) with the following options:

array(
'ulClass' => $ulClass,
'indent' => $indent,
'minDepth' => null,
'maxDepth' => null,
'onlyActiveBranch' => true,
'renderParents' => false
);

<?php
echo $this->navigation()
->menu()
->renderSubMenu(null, 'sidebar', 4);
?>
The output will be the same if 'FAQ' or 'Foo Server' is active:
<ul class="sidebar">
<li class="active">
<a href="/products/server/faq">FAQ</a>
</li>
<li>
<a href="/products/server/editions">Editions</a>
</li>
<li>
<a href="/products/server/requirements">System Requirements</a>
</li>
</ul>

1573
Zend_View

Exemple 961. Rendering a menu with maximum depth

<?php
echo $this->navigation()
->menu()
->setMaxDepth(1);
?>
Output:
<ul class="navigation">
<li>
<a title="Go Home" href="/">Home</a>
</li>
<li class="active">
<a href="/products">Products</a>
<ul>
<li class="active">
<a href="/products/server">Foo Server</a>
</li>
<li>
<a href="/products/studio">Foo Studio</a>
</li>
</ul>
</li>
<li>
<a title="About us" href="/company/about">Company</a>
<ul>
<li>
<a href="/company/about/investors">Investor Relations</a>
</li>
<li>
<a class="rss" href="/company/news">News</a>
</li>
</ul>
</li>
<li>
<a href="/community">Community</a>
<ul>
<li>
<a href="/community/account">My Account</a>
</li>
<li>
<a class="external" href="http://forums.example.com/">Forums</a>
</li>
</ul>
</li>
</ul>

1574
Zend_View

Exemple 962. Rendering a menu with minimum depth

<?php
echo $this->navigation()
->menu()
->setMinDepth(1);
?>
Output:
<ul class="navigation">
<li class="active">
<a href="/products/server">Foo Server</a>
<ul>
<li class="active">
<a href="/products/server/faq">FAQ</a>
</li>
<li>
<a href="/products/server/editions">Editions</a>
</li>
<li>
<a href="/products/server/requirements">System Requirements</a>
</li>
</ul>
</li>
<li>
<a href="/products/studio">Foo Studio</a>
<ul>
<li>
<a href="/products/studio/customers">Customer Stories</a>
</li>
<li>
<a href="/prodcts/studio/support">Support</a>
</li>
</ul>
</li>
<li>
<a href="/company/about/investors">Investor Relations</a>
</li>
<li>
<a class="rss" href="/company/news">News</a>
<ul>
<li>
<a href="/company/news/press">Press Releases</a>
</li>
<li>
<a href="/archive">Archive</a>
</li>
</ul>
</li>
<li>
<a href="/community/account">My Account</a>
</li>
<li>
<a class="external" href="http://forums.example.com/">Forums</a>
</li>
</ul>

1575
Zend_View

Exemple 963. Rendering only the active branch of a menu

<?php
echo $this->navigation()
->menu()
->setOnlyActiveBranch(true);
?>
Output:
<ul class="navigation">
<li class="active">
<a href="/products">Products</a>
<ul>
<li class="active">
<a href="/products/server">Foo Server</a>
<ul>
<li class="active">
<a href="/products/server/faq">FAQ</a>
</li>
<li>
<a href="/products/server/editions">Editions</a>
</li>
<li>
<a href="/products/server/requirements">System Requirements</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>

Exemple 964. Rendering only the active branch of a menu with minimum depth

<?php
echo $this->navigation()
->menu()
->setOnlyActiveBranch(true)
->setMinDepth(1);
?>
Output:
<ul class="navigation">
<li class="active">
<a href="/products/server">Foo Server</a>
<ul>
<li class="active">
<a href="/products/server/faq">FAQ</a>
</li>
<li>
<a href="/products/server/editions">Editions</a>
</li>
<li>
<a href="/products/server/requirements">System Requirements</a>
</li>
</ul>
</li>
</ul>

1576
Zend_View

Exemple 965. Rendering only the active branch of a menu with maximum depth

<?php
echo $this->navigation()
->menu()
->setOnlyActiveBranch(true)
->setMaxDepth(1);
?>
Output:
<ul class="navigation">
<li class="active">
<a href="/products">Products</a>
<ul>
<li class="active">
<a href="/products/server">Foo Server</a>
</li>
<li>
<a href="/products/studio">Foo Studio</a>
</li>
</ul>
</li>
</ul>

Exemple 966. Rendering only the active branch of a menu with maximum depth
and no parents

<?php
echo $this->navigation()
->menu()
->setOnlyActiveBranch(true)
->setRenderParents(false)
->setMaxDepth(1);
?>
Output:
<ul class="navigation">
<li class="active">
<a href="/products/server">Foo Server</a>
</li>
<li>
<a href="/products/studio">Foo Studio</a>
</li>
</ul>

1577
Zend_View

Exemple 967. Rendering a custom menu using a partial view script

This example shows how to render a custom menu using a partial vew script. By calling
setPartial(), you can specify a partial view script that will be used when calling
render(). When a partial is specified, the renderPartial() method will be called. This
method will assign the container to the view with the key container.

In a layout:

$partial = array('menu.phtml', 'default');


$this->navigation()->menu()->setPartial($partial);
echo $this->navigation()->menu()->render();

In application/modules/default/views/menu.phtml:

foreach ($this->container as $page) {


echo $this->navigation()->menu()->htmlify($page), PHP_EOL;
}

Output:

<a title="Go Home" href="/">Home</a>


<a href="/products">Products</a>
<a title="About us" href="/company/about">Company</a>
<a href="/community">Community</a>

4.1.16.7. Sitemap Helper

The Sitemap helper is used for generating XML sitemaps, as defined by the Sitemaps XML
format. Read more about Sitemaps on Wikpedia.

By default, the sitemap helper uses sitemap validators to validate each element that is rendered.
This can be disabled by calling $helper->setUseSitemapValidators(false).

If you disable sitemap validators, the custom properties (see table) are not
validated at all.

The sitemap helper also supports Sitemap XSD Schema validation of the generated sitemap.
This is disabled by default, since it will require a request to the Schema file. It can be enabled
with $helper->setUseSchemaValidation(true).

Tableau 155. Sitemap XML elements

Element Description
loc Absolute URL to page. An absolute URL will be
generated by the helper.
lastmod The date of last modification of the file, in
W3C Datetime format. This time portion can be
omitted if desired, and only use YYYY-MM-DD.

The helper will try to retrieve the lastmod


value from the page's custom property
lastmod if it is set in the page. If the value is
not a valid date, it is ignored.

1578
Zend_View

Element Description
changefreq How frequently the page is likely to change.
This value provides general information to
search engines and may not correlate exactly
to how often they crawl the page. Valid values
are:

• always

• hourly

• daily

• weekly

• monthly

• yearly

• never

The helper will try to retrieve the changefreq


value from the page's custom property
changefreq if it is set in the page. If the value
is not valid, it is ignored.
priority The priority of this URL relative to other URLs
on your site. Valid values range from 0.0 to 1.0.

The helper will try to retrieve the priority


value from the page's custom property
priority if it is set in the page. If the value is
not valid, it is ignored.

Methods in the sitemap helper:

• {get|set}FormatOutput() gets/sets a flag indicating whether XML output should be


formatted. This corresponds to the formatOutput property of the native DOMDocument
class. Read more at PHP: DOMDocument - Manual. Default is FALSE.

• {get|set}UseXmlDeclaration() gets/sets a flag indicating whether the XML declaration


should be included when rendering. Default is TRUE.

• {get|set}UseSitemapValidators() gets/sets a flag indicating whether sitemap


validators should be used when generating the DOM sitemap. Default is TRUE.

• {get|set}UseSchemaValidation() gets/sets a flag indicating whether the helper should


use XML Schema validation when generating the DOM sitemap. Default is FALSE. If TRUE.

• {get|set}ServerUrl() gets/sets server URL that will be prepended to non-absolute URLs


in the url() method. If no server URL is specified, it will be determined by the helper.

• url() is used to generate absolute URLs to pages.

• getDomSitemap() generates a DOMDocument from a given container.

1579
<loc>http://www.example.com/products/server/requirements</loc>
echo $this->navigation()->sitemap();
</url>
<url>
<loc>http://www.example.com/products/studio</loc>
</url> Zend_View
<url>
<loc>http://www.example.com/products/studio/customers</loc>
</url>
Exemple 968. Rendering an XML sitemap
<url>
<loc>http://www.example.com/prodcts/studio/support</loc>
<?xml version="1.0" encoding="UTF-8"?>
</url>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<url>
<loc>http://www.example.com/company/about</loc>
<loc>http://www.example.com/</loc>
</url>
</url>
<url>
<url>
echo<loc>http://www.example.com/company/about/investors</loc>
$this->navigation()
<loc>http://www.example.com/products</loc>
</url> ->sitemap()
</url>
<url> ->setFormatOutput(true)
<url>
<loc>http://www.example.com/company/news</loc>
->setRole();
<loc>http://www.example.com/products/server</loc>
</url>
</url>
<url>
<url>
<loc>http://www.example.com/company/news/press</loc>
<loc>http://www.example.com/products/server/faq</loc>
</url>
</url>
<url>
<url>
<loc>http://www.example.com/archive</loc>
<loc>http://www.example.com/products/server/editions</loc>
Render the sitemap using no ACL role (should filter out /community/account):
</url>
</url>
<url>
<url>
<loc>http://www.example.com/community</loc>
<loc>http://www.example.com/products/server/requirements</loc>
</url>
</url>
<url>
<url>
<loc>http://www.example.com/community/account</loc>
<loc>http://www.example.com/products/studio</loc>
</url>
</url>
<url>
<url>
<loc>http://forums.example.com/</loc>
<loc>http://www.example.com/products/studio/customers</loc>
<?xml version="1.0" encoding="UTF-8"?>
</url>
</url>
<urlset
</urlset>xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<url>
<loc>http://www.example.com/prodcts/studio/support</loc>
<loc>http://www.example.com/</loc>
</url>
</url>
<url>
<url>
echo<loc>http://www.example.com/company/about</loc>
$this->navigation()
<loc>http://www.example.com/products</loc>
</url> ->sitemap()
</url>
<url> ->setFormatOutput(true)
<url>
<loc>http://www.example.com/company/about/investors</loc>
->setMaxDepth(1);
<loc>http://www.example.com/products/server</loc>
</url>
</url>
<url>
<url>
<loc>http://www.example.com/company/news</loc>
<loc>http://www.example.com/products/studio</loc>
</url>
</url>
<url>
<url>
<loc>http://www.example.com/company/news/press</loc>
<loc>http://www.example.com/company/about</loc>
Render the sitemap using a maximum depth of 1.
</url>
</url>
<url>
<url>
<loc>http://www.example.com/archive</loc>
<loc>http://www.example.com/company/about/investors</loc>
</url>
</url>
<url>
<url>
<loc>http://www.example.com/community</loc>
<loc>http://www.example.com/company/news</loc>
</url>
</url>
<url>
<url>
<loc>http://forums.example.com/</loc>
<loc>http://www.example.com/community</loc>
</url>
</url>
</urlset>
<url>
<loc>http://www.example.com/community/account</loc>
</url>
<url>
<loc>http://forums.example.com/</loc>
</url>
</urlset>

1580
Zend_View

UTF-8 encoding used by default


By default, Zend Framework uses UTF-8 as its default encoding, and, specific to
this case, Zend_View does as well. Character encoding can be set differently on
the view object itself using the setEncoding() method (or the the encoding
instantiation parameter). However, since Zend_View_Interface does not
define accessors for encoding, it's possible that if you are using a custom view
implementation with the Dojo view helper, you will not have a getEncoding()
method, which is what the view helper uses internally for determining the
character set in which to encode.

If you do not want to utilize UTF-8 in such a situation, you will need to implement
a getEncoding() method in your custom view implementation.

4.1.16.8. Navigation Helper

The Navigation helper is a proxy helper that relays calls to other navigational helpers. It can be
considered an entry point to all navigation-related view tasks. The aforementioned navigational
helpers are in the namespace Zend_View_Helper_Navigation, and would thus require the
path Zend/View/Helper/Navigation to be added as a helper path to the view. With the
proxy helper residing in the Zend_View_Helper namespace, it will always be available, without
the need to add any helper paths to the view.

The Navigation helper finds other helpers that implement the


Zend_View_Helper_Navigation_Helper interface, which means custom view helpers can
also be proxied. This would, however, require that the custom helper path is added to the view.

When proxying to other helpers, the Navigation helper can inject its container, ACL/role, and
translator. This means that you won't have to explicitly set all three in all navigational helpers,
nor resort to injecting by means of Zend_Registry or static methods.

• findHelper() finds the given helper, verifies that it is a navigational helper, and injects
container, ACL/role and translator.

• {get|set}InjectContainer() gets/sets a flag indicating whether the container should


be injected to proxied helpers. Default is TRUE.

• {get|set}InjectAcl() gets/sets a flag indicating whether the ACL/role should be injected


to proxied helpers. Default is TRUE.

• {get|set}InjectTranslator() gets/sets a flag indicating whether the translator should


be injected to proxied helpers. Default is TRUE.

• {get|set}DefaultProxy() gets/sets the default proxy. Default is 'menu'.

• render() proxies to the render method of the default proxy.

4.1.17. L'aide de vue Translate


Souvent le sites Web sont disponibles en plusieurs langues. Pour traduire le contenu d'un site,
vous pouvez simplement utiliser Zend Translate et pour intégrer Zend Translate à l'intérieur
de vos vues, vous devriez utiliser l'aide de vue Translate.

Dans tous les exemples suivants nous allons utiliser l'adaptateur de traduction Array. Bien sûr
vous pouvez aussi utiliser toute instance de Zend_Translate ainsi que toutes sous-classes de
Zend_Translate_Adapter. Il y a plusieurs manières d'initialiser l'aide de vue Translate :

1581
Zend_View

• enregistré préalablement dans Zend_Registry

• après, par l'interface fluide

• directement en initialisant la classe

Une instance préalablement enregistré de Zend_Translate est l'utilisation préférée pour cette
aide. Vous pouvez ainsi sélectionner la locale à utiliser avant d'ajouter l'adaptateur dans le
registre.

Nous parlons de locales et non de langues car une langue peut aussi contenir
une région. Par exemple l'anglais est parlé en différents dialectes. Il peut y avoir
une traduction pour l'anglais et une pour l'américain. Ainsi, nous disons "locale"
plutôt que "langues".

Exemple 969. Instance enregistrée

Pour utiliser une instance enregistrée, créez une instance de Zend_Translate ou


Zend_Translate_Adapter et enregistrez la dans Zend_Registry en utilisant la clé
Zend_Translate.

// notre adaptateur d'exemple


$adapter = new Zend_Translate('array', array('simple' => 'einfach'), 'de');
Zend_Registry::set('Zend_Translate', $adapter);

// à l'intérieur de votre vue


echo $this->translate('simple');
// ceci retourne 'einfach'

Si vous êtes plus familier avec l'interface fluide, alors vous pouvez aussi créer une instance à
l'intérieur de votre vue et initialiser l'aide ensuite.

Exemple 970. A l'intérieur de la vue

Pour utiliser l'interface fluide, créez une instance de Zend_Translate ou


Zend_Translate_Adapter, appelez l'aide sans paramètres, et appelez la méthode
setTranslator().

// à l'intérieur de votre vue


$adapter = new Zend_Translate('array', array('simple' => 'einfach'), 'de');
$this->translate()->setTranslator($adapter)->translate('simple');
// ceci retourne 'einfach'

Si vous utilisez votre aide sans Zend_View, alors vous pouvez aussi l'utiliser directement.

Exemple 971. Utilisation directe

// notre adaptateur d'exemple


$adapter = new Zend_Translate('array', array('simple' => 'einfach'), 'de');

// initialiser l'adaptateur
$translate = new Zend_View_Helper_Translate($adapter);
print $translate->translate('simple');
// ceci retourne 'einfach'

Vous devriez utiliser cette façon de faire si vous ne travaillez pas avec Zend_View et que
vous avez besoin de créer des affichages traduits.

1582
Zend_View

Comme vu auparavant, la méthode translate() est utilisé pour retourner la traduction.


Appelez la simplement avec l'identifiant de message de votre adaptateur de traduction. Mais il
peut aussi avoir à remplacer des paramètres dans la chaîne de traduction. Donc, il accepte des
paramètres de deux manières : soit comme une liste de paramètres, soit comme un tableau de
paramètres. Par exemple :

Exemple 972. Paramètres unique

Pour utiliser un paramètre unique, ajoutez le en fin de méthode :

// à l'intérieur de votre vue


$date = "Monday";
$this->translate("Today is %1\$s", $date);
// ceci retourne 'Heute ist Monday'

Gardez à l'esprit que si vous utilisez des paramètres qui sont aussi des textes,
vous pouvez aussi avoir à traduire ces paramètres.

Exemple 973. Liste de paramètres

Ou utiliser une liste de paramètres et ajoutez les en fin de méthode :

// à l'intérieur de votre vue


$date = "Monday";
$month = "April";
$time = "11:20:55";
$this->translate("Today is %1\$s in %2\$s. Actual time: %3\$s",
$date,
$month,
$time);
// ceci retourne 'Heute ist Monday in April. Aktuelle Zeit: 11:20:55'

Exemple 974. Tableau de paramètres

Ou utiliser un tableau de paramètres et ajoutez le en fin de méthode :

// à l'intérieur de votre vue


$date = array("Monday", "April", "11:20:55");
$this->translate("Today is %1\$s in %2\$s. Actual time: %3\$s", $date);
// Could return 'Heute ist Monday in April. Aktuelle Zeit: 11:20:55'

Parfois il est nécessaire de changer la locale pour une traduction. Ceci peut être fait soit
dynamiquement par traduction ou statiquement pour toutes les traductions suivantes. Et vous
pouvez utiliser ceci avec une liste de paramètres ou un tableau de paramètres. Dans les deux
cas la locale doit être fournie comme un paramètre unique final.

Exemple 975. Changement dynamique de la locale

// à l'intérieur de votre vue


$date = array("Monday", "April", "11:20:55");
$this->translate("Today is %1\$s in %2\$s. Actual time: %3\$s", $date, 'it');

Cet exemple retourne la traduction italienne pour l'identifiant de message. Mais la locale ne sera
utilisée qu'une seule fois. La traduction suivante utilisera la locale de l'adaptateur. Normalement

1583
Zend_View

vous réglerez la locale au niveau de votre adaptateur avant de le mettre dans le registre. Mais
vous pouvez aussi paramétrer la locale avec l'aide de vue :

Exemple 976. Changement statique de la locale

// à l'intérieur de votre vue


$date = array("Monday", "April", "11:20:55");
$this->translate()->setLocale('it');
$this->translate("Today is %1\$s in %2\$s. Actual time: %3\$s", $date);

L'exemple ci-dessus paramètre 'it' comme nouvelle locale par défaut, elle sera utilisée pour
toutes les traductions ultérieures.

Bien sûr il existe aussi la méthode getLocale() pour récupérer le réglage courant de la locale.

Exemple 977. Récupération de la locale courante

// à l'intérieur de votre vue


$date = array("Monday", "April", "11:20:55");

// retourne 'de' comme réglé dans les exemples précédents


$this->translate()->getLocale();

$this->translate()->setLocale('it');
$this->translate("Today is %1\$s in %2\$s. Actual time: %3\$s", $date);

// retourne 'it' comme nouvelle locale par défaut


$this->translate()->getLocale();

4.2. Chemin des aides


Comme pour les scripts de vue, votre contrôleur peut spécifier une pile de chemins dans lesquels
Zend_View cherchera les classes d'aides. Par défaut, Zend_View cherche dans "Zend/View/
Helper/*". Vous pouvez dire à Zend_View de regarder dans d'autres chemins en utilisant les
méthodes setHelperPath() et addHelperPath(). De plus, vous pouvez indiquer un préfixe
de classe pour utiliser les aides dans le répertoire fourni, et permettre de donner des espaces
de noms à vos classes d'aide. Par défaut, si aucun préfixe n'est fourni, "Zend_View_Helper_"
est utilisé.

$view = new Zend_View();


$view->setHelperPath('/chemin/vers/plus/de/classes/d-aides',
'Ma_View_Helper');

En fait, vous pouvez "empiler" les chemins en utilisant la méthode addHelperPath(). Comme
vous ajoutez des chemins dans la pile, Zend_View va regarder dans le chemin le plus
récemment ajouté, pour inclure la classe d'aide. Cela vous permet d'ajouter (ou bien de redéfinir)
la distribution initiale des aides, avec vos propres aides personnalisées.

$view = new Zend_View();

// Ajoute /chemin/vers/des/aides avec le préfixe


// de classe 'Ma_View_Helper'
$view->addHelperPath('/chemin/vers/des/aides',
'Ma_View_Helper');
// Ajoute /autre/chemin/vers/des/aides avec le préfixe
// de classe 'Votre_View_Helper'

1584
Zend_View

$view->addHelperPath('/autre/chemin/vers/des/aides',
'Votre_View_Helper');

// maintenant, lorsque vous appelerez $this->helperName(), Zend_View


// va rechercher en premier /autre/chemin/vers/des/aides/HelperName.php
// en utilisant la classe "Votre_View_Helper_HelperName", et ensuite
// dans /chemin/vers/des/aides/HelperName.php en utilisant la classe
// "Ma_View_Helper_HelperName", et finalement dans
// Zend/View/Helpers/HelperName.php en utilisant la classe
// "Zend_View_Helper_HelperName"

4.3. Écrire des aides personnalisées


Écrire des aides personnalisées est facile, vous devez juste suivre ces règles :

• Bien qu'il ne soit pas strictement nécessaire, il est recommandé soit d'implémenter
Zend_View_Helper_Interface ou d'étendre Zend_View_Helper_Abstract quand
vous créez vos aides. Introduit en 1.6.0, ceux-ci définissent la méthode setView() ;
cependant, dans les prochaines releases, nous prévoyons d'implémenter un motif de
conception Stratégie qui permettra de simplifier en grande partie le schéma de nomination
détaillé ci-dessous. Contruire sur ces bases à partir de maintenant vous aidera pour vos codes
futurs.

• Le nom de la classe doit, au minimum, se terminer avec le nom de l'aide en utilisant une
notation en casseMélangée. Par exemple, si vous écrivez une aide appelée "actionSpeciale",
le nom de la classe doit être au minimum "ActionSpeciale". Vous devriez donner au nom de
la classe un préfixe, et il est recommandé d'utiliser "Ma_View_Helper" comme partie de ce
préfixe : "Ma_View_Helper_ActionSpeciale". (Vous devez alors fournir le préfixe, avec ou sans
le tiret bas, à addHelperPath() ou à setHelperPath()).

• La classe doit avoir une méthode publique dont le nom correspond au nom de l'aide ; c'est
la méthode qui sera appelée quand votre template appellera $this->actionSpeciale().
Dans notre exemple $this->actionSpeciale(), la déclaration de méthode requise serait
public function actionSpeciale().

• En général, la classe ne devrait pas afficher directement les données (via echo ou print).
Elle devrait retourner les valeurs pour être ensuite affichées. Les valeurs retournées devrait
être échappées de façon appropriées.

• La classe doit être dans un fichier ayant le même nom que la méthode d'aide. Si on utilise la
méthode actionSpeciale(), le fichier devra être nommé "ActionSpeciale.php"

Placez le fichier de classe d'aide quelque part dans la pile des chemins d'aide, et Zend_View
le chargera, l'instanciera, le rendra persistant, et l'exécutera automatiquement pour vous.

Voici un exemple de fichier "ActionSpeciale.php" :

class Ma_View_Helper_ActionSpeciale
{
protected $_count = 0;
public function actionSpeciale()
{
$this->_count++;
$output = "J'ai vu 'The Big Lebowsky' {$this->_count} fois.";
return htmlspecialchars($output);
}

1585
Zend_View

Ensuite, dans un script de vue, vous pouvez appeler l'aide ActionSpeciale autant de fois que
vous le souhaitez ; elle sera instanciée une fois, et rendue persistante pendant toute la vie de
l'instance de Zend_View.

// rappelez vous, $this se réfère à l'instance de Zend_View


echo $this->actionSpeciale();
echo $this->actionSpeciale();
echo $this->actionSpeciale();

La sortie pourrait alors ressembler à ceci :

J'ai vu 'The Big Lebowsky' 1 fois.


J'ai vu 'The Big Lebowsky' 2 fois.
J'ai vu 'The Big Lebowsky' 3 fois.

Quelquefois vous devez accéder à l'objet Zend_View appelant - par exemple, si vous devez
utiliser l'encodage enregistré ou voulez effectuer le rendu d'un autre script de vue comme une
sous partie de votre aide. Pour avoir accès à votre objet de vue, votre classe d'aide doit avoir
une méthode setView($view), comme ceci :

class Ma_View_Helper_ScriptPath
{
public $view;

public function setView(Zend_View_Interface $view)


{
$this->view = $view;
}

public function scriptPath($script)


{
return $this->view->getScriptPath($script);
}
}

Si votre classe d'aide a une méthode setView(), elle sera appelée quand votre classe sera
instanciée la première fois et fournira l'objet de la vue courante. Il est de votre responsabilité
de maintenir la persistance de l'objet dans votre classe, de même que de déterminer la façon
dont il peut être accéder.

4.4. Registering Concrete Helpers


Sometimes it is convenient to instantiate a view helper, and then register it with the view. As of
version 1.10.0, this is now possible using the registerHelper() method, which expects two
arguments: the helper object, and the name by which it will be registered.

$helper = new My_Helper_Foo();


// ...do some configuration or dependency injection...

$view->registerHelper($helper, 'foo');

If the helper has a setView() method, the view object will call this and inject itself into the
helper on registration.

1586
Zend_View

Helper name should match a method


The second argument to registerHelper() is the name of the helper. A
corresponding method name should exist in the helper; otherwise, Zend_View
will call a non-existent method when invoking the helper, raising a fatal PHP error.

5. Zend_View_Abstract
Zend_View_Abstract est la classe de base à partir de laquelle Zend_View est construite ;
Zend_View elle-même l'étend simplement et déclare une implémentation concrète de la
méthode _run() (qui est invoquée par render()).

De nombreux développeurs constatent qu'ils veulent étendre Zend_View_Abstract afin


d'ajouter des fonctionnalités supplémentaires, et inévitablement se trouvent confrontés face à
des problèmes avec ce design, qui inclut un certain nombre de membres privés. Ce document
a pour but d'expliquer les décisions qui ont poussé à ce design.

Zend_View est une sorte de moteur anti-template dans lequel on utilise nativement PHP pour
la réalisation du template. Avec comme résultat, tout le PHP est disponible, et les scripts de vue
héritent de la portée des objets appelants.

C'est ce dernier point qui est important dans le choix de la décision de ce design. En interne,
Zend_View::_run() réalise simplement ceci :

protected function _run()


{
include func_get_arg(0);
}

Ainsi, les scripts de vue ont accès à l'objet courant($this), et toute méthode ou membres et
cet objet. Puisque beaucoup d'opérations dépendent de membres ayant une portée limitée, ceci
pose un problème : les scrips de vue peuvent potentiellement faire des appels à ces méthodes ou
modifier des propriétés critiques directement. Imaginer un script surchargeant par inadvertance
$_path ou $_file - tout appel suivant à render() ou aux aides de vue sera cassé !

Heureusement, PHP 5 a une réponse à ceci avec ses déclarations de visibilité : les membres
privés se sont pas accessibles par un objet étendant une classe donnée. Ceci a permis la
conception actuelle : Zend_View étend Zend_View_Abstract, les scripts de vues sont ainsi
limités aux seuls méthodes et membres public ou protected de Zend_View_Abstract
- limitant effectivement les actions qu'il peut exécuter, et nous permettant de sécuriser des
secteurs critiques d'un risque de modification par les scripts de vue.

1587
Zend_Wildfire
1. Zend_Wildfire
Zend_Wildfire est un composant qui facilite la communication entre le code PHP et les
composants clients Wildfire.

Le but du projet Wildfire est de développer un canal de communication standardisé entre une
large variété de composants ainsi qu'une architecture de plugins dynamiques. Pour l'instant,
l'attention première est de fournir un système permettant au code PHP côté serveur d'injecter
des messages de logs vers la console Firebug.

En ce qui concerne le log vers Firebug le composant Zend_Log_Writer_Firebug est fourni


et un protocole de communication a été développé, celui-ci utilise les requêtes HTTP et les
en-têtes de réponse pour envoyer des données entre le serveur et les composants clients.
C'est intéressant pour journaliser des données, générées durant l'exécution du script, vers le
navigateur sans interférer avec le contenu de la page. Déboguer les requêtes AJAX qui requière
du JSON "propre" ou un réponse XML est possible avec cette approche.

Il existe aussi un composant Zend_Db_Profiler_Firebug pour journaliser les informations


de profiling de bases de données vers Firebug.

1588
Zend_XmlRpc
1. Introduction
Sur sa page d'accueil, XML-RPC est décrit comme "un appel de procédure à distance utilisant
HTTP comme transport et XML comme encodage. XML-RPC est conçu pour être aussi simple
que possible, en permettant aux structures de données complexes d'être transmises, traitées
et rendues."

Zend Framework propose le support à la fois pour la consommation de services XMP-RPC


distants et pour la construction de nouveaux serveurs XML-RPC.

2. Zend_XmlRpc_Client
2.1. Introduction
Zend Framework possède la capacité de consommer des services distants XML-RPC, via la
classe Zend_XmlRpc_Client. Ses caractéristiques principales sont la conversion automatique
des types entre PHP et XML-RPC, un objet proxy de serveur, et des possibilités d'introspection
du serveur.

2.2. Appels de méthodes


Le constructeur de Zend_XmlRpc_Client reçoit en premier paramètre l'URL du serveur
XML-RPC distant. L'instance retournée pourra alors être utilisée pour appeler n'importe quelle
méthode distante.

Pour appeler une méthode distante, utilisez la méthode call() de votre instance. Le code
suivant montre un exemple avec le serveur XML-RPC du site de Zend Framework. Vous pouvez
l'utiliser pour tester ou explorer les possibilités des composants Zend_XmlRpc.

Exemple 978. XML-RPC appel de méthode

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

echo $client->call('test.sayHello');

// hello

Le type de la valeur XML-RPC retournée sera automatiquement casté en un type compatible


PHP. Dans l'exemple ci-dessus, une string PHP est retournée et immédiatement utilisable.

Le premier paramètre de call() est le nom de la méthode distante à appeler. Si celle-ci


demande des paramètres, ceux-ci doivent alors être passés via le deuxième paramètre de
call(), sous forme de tableau PHP (array) :

1589
Zend_XmlRpc

Exemple 979. XML-RPC appel de méthode avec des paramètres

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

$arg1 = 1.1;
$arg2 = 'foo';

$result = $client->call('test.sayHello', array($arg1, $arg2));

// $result est un type PHP natif

Le tableau de paramètres peut contenir des types PHP natifs, des objets Zend_XmlRpc_Value,
ou bien les deux à la fois.

La méthode call() convertira automatiquement la réponse XML-RPC et retournera un type


PHP natif valide. Un objet Zend_XmlRpc_Response pour la valeur de retour sera de même
disponible, via un appel à getLastResponse().

2.3. Types et conversions


Certaines méthodes distantes requièrent des paramètres. Ceux-ci sont donnés sous forme
de tableau PHP à call(). Chaque paramètre est supposé être un type PHP natif qui sera
alors lui-même converti, ou alors un objet représentant un type XML-RPC (un objet parmi les
Zend_XmlRpc_Value).

2.3.1. Types PHP natifs comme paramètres


Les paramètres passés à call() peuvent être d'un type PHP natif, à savoir string, integer,
float, boolean, array, ou object. Dans ce cas, chacun des types sera converti de manière
automatique en son type compatible XML-RPC, suivant la table suivante :

Tableau 156. PHP et XML-RPC, conversions de types


Type PHP natif XML-RPC type
integer int
double double
boolean boolean
string string
array array
associative array struct
object array

Comment est casté un tableau vide ?


Fournir un tableau vide à une méthode XML-RPC est problématique, car il peut
être représenté sous la forme soit d'un tableau, soit d'une structure ("struct").
Zend_XmlRpc_Client détecte ce genre de conditions et fait une requête vers
la méthode system.methodSignature du serveur pour déterminer le type
XML-RPC approprié vers le quel casté.

Cependant, ceci peut mener malgré tout à des soucis. Premièrement, les
serveurs qui ne supportent system.methodSignature vont retourner une
requête de type échec, et Zend_XmlRpc_Client résultera en un cast de la
valeur de type tableau XML-RPC ("array"). De plus, ceci sous-entend que tout

1590
Zend_XmlRpc

appel avec des arguments de type tableau entraîneront un appel additionnel au


serveur distant.

Pour désactiver entièrement la recherche, vous pouvez appeler la méthode


setSkipSystemLookup() avant de réaliser votre appel XML-RPC :

$client->setSkipSystemLookup(true);
$result = $client->call('foo.bar', array(array()));

2.3.2. Objets Zend_XmlRpc_Value en tant que paramètres

Les paramètres peuvent aussi être des objets Zend_XmlRpc_Value qui spécifient alors
exactement un type XML-RPC. Les raisons principales d'utiliser un tel procédé sont :

• Lorsque vous voulez être certain du type de paramètre (la méthode attend un entier et vous
le récupérez sous forme de chaîne de caractères depuis une base de données).

• Lorsque la méthode attend un type base64 ou dateTime.iso8601 (ceux-ci n'existant pas


nativement dans le langage PHP).

• Lorsque la conversion de types (cast) peut échouer (vous voulez passer une valeur XML-
RPC vide comme paramètre. Mais les valeurs vides en PHP sont représentés sous forme de
tableaux vides, or si vous passez un tableau vide à votre méthode call, il va être converti en
un tableau XML-RPC, comme ce n'est pas un tableau associatif).

Deux manières existent pour créer des objets Zend_XmlRpc_Value : instanciez une sous-
classe Zend_XmlRpc_Value directement, ou utilisez une fabrique ("factory method") telle que
Zend_XmlRpc_Value::getXmlRpcValue().

Tableau 157. Objets Zend_XmlRpc_Value comme types XML-RPC

XML-RPC Type Zend_XmlRpc_Value Zend_XmlRpc_Value Objet


Constante
int Zend_XmlRpc_Value::XMLRPC_TYPE_INTEGER
Zend_XmlRpc_Value_Integer
double Zend_XmlRpc_Value::XMLRPC_TYPE_DOUBLE
Zend_XmlRpc_Value_Double
boolean Zend_XmlRpc_Value::XMLRPC_TYPE_BOOLEAN
Zend_XmlRpc_Value_Boolean
string Zend_XmlRpc_Value::XMLRPC_TYPE_STRING
Zend_XmlRpc_Value_String
base64 Zend_XmlRpc_Value::XMLRPC_TYPE_BASE64
Zend_XmlRpc_Value_Base64
dateTime.iso8601 Zend_XmlRpc_Value::XMLRPC_TYPE_DATETIME
Zend_XmlRpc_Value_DateTime
array Zend_XmlRpc_Value::XMLRPC_TYPE_ARRAY
Zend_XmlRpc_Value_Array
struct Zend_XmlRpc_Value::XMLRPC_TYPE_STRUCT
Zend_XmlRpc_Value_Struct

Conversion automatique

Lorsque vous créez un objet Zend_XmlRpc_Value, sa valeur est déterminée


par un type PHP. Celui-ci va être converti vers le type désiré en utilisant le cast
PHP. Par exemple si une chaîne de caractères est donnée comme valeur à un
objet Zend_XmlRpc_Value_Integer, elle sera alors convertie suivant la règle
(int)$value.

1591
Zend_XmlRpc

2.4. Objet proxy du serveur


Un autre moyen d'appeler des méthodes avec un client XML-RPC est d'utiliser le proxy du
serveur. C'est un objet PHP qui proxie un espace de nom XML-RPC, en fonctionnant autant que
possible comme les objets PHP.

Pour instancier un proxy serveur, appelez getProxy() de Zend_XmlRpc_Client. Elle


retourne un objet Zend_XmlRpc_Client_ServerProxy. Tout appel de méthode sur l'objet
proxy sera proxié vers le serveur XML-RPC, et les paramètres seront utilisés comme pour une
méthode PHP banale.

Exemple 980. Proxy espace de nom par défaut

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

$server = $client->getProxy();
// Proxy l'espace de nom par défaut

$hello = $server->test->sayHello(1, 2);


// test.Hello(1, 2) retourne "hello"

La méthode getProxy() reçoit un argument optionnel désignant l'espace de nom à utiliser par
le proxy. Par défaut, il s'agit de l'espace général, voici un exemple utilisant un espace de nom
test :

Exemple 981. Proxy un espace de nom

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

$test = $client->getProxy('test');
// Proxy l'espace de nommage "test"

$hello = $test->sayHello(1, 2);


// test.Hello(1,2) retourne "hello"

Si le serveur distant supporte les espaces de noms imbriqués, alors le proxy les supportera. Par
exemple, si le serveur dans l'exemple ci-dessus acceptait les espaces de noms imbriqués, alors
sa méthode test.foo.bar() aurait pu être appelée via $test->foo->bar().

2.5. Gestion des erreurs


Deux types d'erreurs peuvent être distingués : erreurs HTTP, ou erreurs XML-RPC. L'objet
Zend_XmlRpc_Client reconnaît ces erreurs et fournit les moyens de les repérer et de les
gérer.

2.5.1. Erreurs HTTP

Si une erreur HTTP survient, par exemple le serveur renvoie un 404 Not Found, alors une
Zend_XmlRpc_Client_HttpException sera levée.

1592
Zend_XmlRpc

Exemple 982. Gérer les erreurs HTTP

$client = new Zend_XmlRpc_Client('http://foo/404');

try {

$client->call('bar', array($arg1, $arg2));

} catch (Zend_XmlRpc_Client_HttpException $e) {

// $e->getCode() retourne 404


// $e->getMessage() retourne "Not Found"

Quelque soit l'utilisation du client XML-RPC, une Zend_XmlRpc_Client_HttpException


sera systématiquement levée lorsqu'une erreur HTTP de quelque type que ce soit est rencontrée.

2.5.2. Erreurs XML-RPC (Faults)


Une erreur XML-RPC peut être assimilée à une exception en PHP. C'est un type spécial retourné
par une des méthodes du client XML-RPC, et ce type contient un message, et un code d'erreur.
Les erreurs XML-RPC seront gérées différemment en fonction du contexte d'utilisation de l'objet
Zend_XmlRpc_Client.

Lors de l'utilisation de la méthode call(), ou de l'objet proxy serveur, une erreur XML-RPC aura
pour effet de lancer une Zend_XmlRpc_Client_FaultException. Le code et le message
de l'exception seront rendus dans leurs valeurs respectives de la réponse XML-RPC.

Exemple 983. Gérer les erreurs XML-RPC

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

try {

$client->call('badMethod');

} catch (Zend_XmlRpc_Client_FaultException $e) {

// $e->getCode() retourne 1
// $e->getMessage() retourne "Unknown method"

En utilisant call(), une exception Zend_XmlRpc_Client_FaultException sera donc


lancée si une erreur survient. Un objet Zend_XmlRpc_Response contenant l'erreur sera de
même disponible via la méthode getLastResponse().

Lors de l'utilisation de la méthode doRequest(), aucune exception ne sera levée si une erreur
XML-RPC survient. Simplement, l'objet Zend_XmlRpc_Response retourné contiendra l'erreur.
Vérifiez-en l'état avec isFault().

2.6. Introspection du serveur


Certains serveurs XML-RPC supportent l'introspection de leurs méthodes au travers de l'espace
de noms system. Zend_XmlRpc_Client fournit un support d'un tel procédé.

1593
Zend_XmlRpc

Une instance de Zend_XmlRpc_Client_ServerIntrospection sera retournée si vous


appelez la méthode getIntrospector() sur l'objet Zend_XmlRpcClient.

2.7. De la requête à la réponse


Dans les faits, la méthode call() de Zend_XmlRpc_Client fabrique un objet
Zend_XmlRpc_Request et l'envoie à une méthode doRequest(), qui retourne un objet de
réponse Zend_XmlRpc_Response.

La méthode doRequest() est disponible directement si besoin :

Exemple 984. Effectuer une requête et récupérer une réponse manuellement

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

$request = new Zend_XmlRpc_Request();


$request->setMethod('test.sayHello');
$request->setParams(array('foo', 'bar'));

$client->doRequest($request);

// $server->getLastRequest() retoure instanceof Zend_XmlRpc_Request


// $server->getLastResponse() retourne instanceof Zend_XmlRpc_Response

Lorsqu'une méthode XML-RPC est appelée, quel qu'en soit le moyen, (call(), doRequest()
ou proxy serveur), le dernier objet de requête, et son homologue de réponse, seront toujours
disponibles, au travers des appels à getLastRequest() et getLastResponse().

2.8. Client HTTP et tests


Dans tous les exemples utilisés sur cette page, nous ne parlons jamais du client HTTP. Lorsque
c'est nécessaire, une instance de Zend_Http_Client sera créée par défaut et injectée dans
Zend_XmlRpc_Client de manière automatique.

L'objet client HTTP peut être récupéré à tout moment grâce à la méthode getHttpClient().
setHttpClient() permet d'injecter un objet Zend_Http_Client.

setHttpClient() est particulièrement utilisée pour les tests unitaires. Lorsque combinée avec
Zend_Http_Client_Adapter_Test, les services Web peuvent être déguisés (émulés) pour
les tests. Voyez les tests unitaires de Zend_XmlRpc_Client pour des exemples concrets.

3. Zend_XmlRpc_Server
3.1. Introduction
Zend_XmlRpc_Server fournit un serveur XML-RPC qui suit les spécifications dictées par
www.xmlrpc.com. Il fournit aussi la méthode system.multicall(), permettant le traitement
de requêtes multiples.

3.2. Usage de base


Voici un exemple d'utilisation basique :

$server = new Zend_XmlRpc_Server();


$server->setClass('My_Service_Class');

1594
Zend_XmlRpc

echo $server->handle();

3.3. Structures du serveur


Zend_XmlRpc_Server se décompose en un objet serveur (lui-même), un objet requête,
réponse, et des objets d'erreurs.

Pour démarrer un serveur Zend_XmlRpc_Server, vous devez attacher une ou plusieurs


classes ou fonctions au serveur, grâce à setClass() et addFunction().

Lorsque c'est fait, vous pouvez passer un objet Zend_XmlRpc_Request


à Zend_XmlRpc_Server::handle(), sinon par défaut il utilisera un objet
Zend_XmlRpc_Request_Http qui récupérera la requête depuis php://input.

Zend_XmlRpc_Server::handle() va alors essayer de traiter la requête. Cette méthode


retournera un objet Zend_XmlRpc_Response ou Zend_XmlRpc_Server_Fault. Tous deux
possèdent une méthode __toString() qui crée une réponse XML valide XML-RPC.

3.4. Conventions
Zend_XmlRpc_Server permet d'attacher des classes et/ou des fonctions au serveur
XML-RPC. Grâce à Zend_Server_Reflection, l'introspection va utiliser les blocs de
commentaires pour déterminer les types d'arguments et de réponse de la fonction/classe.

Les types XML-RPC n'ont pas forcément de correspondance native vers un type PHP. Le code
fera de son mieux pour deviner le type de données approprié, en se basant sur les valeurs listées
dans les balises @param et @return. Certains types XML-RPC n'ont par contre pas d'équivalent
PHP direct, ils devront alors être spécifiés manuellement sous forme de balises phpdoc :

• dateTime.iso8601, une chaîne formatée comme YYYYMMDDTHH:mm:ss

• base64, données encodées en base64

• struct, tableau associatif

Voici un exemple d'utilisation de type particulier:

/**
* This is a sample function
*
* @param base64 $val1 Base64-encoded data
* @param dateTime.iso8601 $val2 An ISO date
* @param struct $val3 An associative array
* @return struct
*/
function myFunc($val1, $val2, $val3)
{}

PhpDocumentor ne vérifie (valide) pas les types des paramètres, mais les types sont obligatoires
pour que le serveur puisse lui, valider les paramètres passés aux appels des méthodes.

Il est parfaitement valide de spécifier plusieurs types pour les paramètres et les retours de
méthodes. La spécification XML-RPC suggère que system.methodSignature retourne un tableau
des possibilités au regard des paramètres d'entrée de la méthode, et de son type de sortie. Ceci
ce fait grâce au caractère '|' de PhpDocumentor

/**

1595
Zend_XmlRpc

* This is a sample function


*
* @param string|base64 $val1 String or base64-encoded data
* @param string|dateTime.iso8601 $val2 String or an ISO date
* @param array|struct $val3 Normal indexed array or an associative array
* @return boolean|struct
*/
function myFunc($val1, $val2, $val3)
{}

Attention toutefois, une signature multiple peut prêter à confusion au regard des personnes
utilisant votre service. En général une fonction ne devrait posséder qu'une seule signature.

3.5. Utiliser des espaces de noms (Namespaces)


XML-RPC accepte le concept d'espace de noms, ce qui permet de grouper les méthodes
XML-RPC. Ceci aide à prévenir les collisions de noms (deux fonctions avec le même nom),
de différentes classes. Par exemple le serveur XML-RPC sert des méthodes dans l'espace
"system" :

• system.listMethods

• system.methodHelp

• system.methodSignature

En interne la correspondance est faite avec les méthodes du même nom, de


Zend_XmlRpc_Server.

Si vous voulez ajouter un espace de noms aux méthodes que vous servez, procédez alors
comme suit :

// Toutes les méthodes publiques de My_Service_Class seront accessibles


// via myservice.METHODNAME
$server->setClass('My_Service_Class', 'myservice');

// la fonction 'somefunc' sera accessible via funcs.somefunc


$server->addFunction('somefunc', 'funcs');

3.6. Requêtes personnalisées


La plupart du temps, vous utiliserez l'objet de requête par défaut
Zend_XmlRpc_Request_Http, sans vous en occuper. En revanche si vous avez un besoin
spécifique, comme par exemple journaliser la requête, traiter une requête CLI, GUI, ou
autre environnement, vous devrez alors créer un objet étendant Zend_XmlRpc_Request.
Implémentez les méthodes getMethod() et getParams() afin que le serveur puisse analyser
ces informations pour traiter la requête.

3.7. Réponses personnalisées


Comme avec les objets de requête, Zend_XmlRpc_Server peut retourner des objets de
réponse personnalisés. Par défaut il s'agit d'objets Zend_XmlRpc_Response_Http qui
envoient un en-tête HTTP Content-Type HTTP pour XML-RPC. Vous pourriez utiliser des objets
de réponse personnalisés pour par exemple renvoyer les réponses vers STDOUT, ou les
journaliser.

1596
Zend_XmlRpc

Pour utiliser une classe de réponse personnalisée, utilisez


Zend_XmlRpc_Server::setResponseClass() avant d'appeler handle().

3.8. Gérer les exceptions grâce aux erreurs (Faults)


Zend_XmlRpc_Server attrape les Exceptions générées par vos classes/fonctions, et génère
une réponse XML-RPC "fault" lorsqu'une exception a été rencontrée. Par défaut, les message
et code des exceptions ne sont pas attachés dans la réponse XML-RPC. Ceci est du au fait que
de telles exceptions peuvent en dire trop, au regard de la sécurité de votre application.

Des classes d'exception peuvent cependant être mises en liste blanche,


et donc utilisées pour les réponses d'erreur ("fault"). Utilisez simplement
Zend_XmlRpc_Server_Fault::attachFaultException() en lui passant une classe
d'exception :

Zend_XmlRpc_Server_Fault::attachFaultException('My_Project_Exception');

Si vous héritez correctement vos exceptions, vous pouvez alors passer en liste blanche
l'exception de plus bas niveau, et ainsi accepter plusieurs types d'exceptions qui en hériteront.
Évidemment, les Zend_XmlRpc_Server_Exceptions sont elles automatiquement mises en liste
blanche, afin de pouvoir traiter les requêtes vers des méthodes inexistantes, ou toute autre erreur
"générique".

Toute exception rencontrée, mais non mise en liste blanche, donnera naissance à une réponse
d'erreur avec le code "404" et le message "Unknown error".

3.9. Cacher la définition du serveur entre les requêtes


Attacher beaucoup de classes au serveur XML-RPC peut consommer beaucoup de ressources,
car l'introspection de chaque classe/fonction est mise en place.

Pour améliorer les performances, Zend_XmlRpc_Server_Cache peut être utilisé pour mettre
en cache la définition d'un serveur. Combiné à __autoload(), ceci améliore grandement les
performances.

Un exemple d'utilisation :

function __autoload($class)
{
Zend_Loader::loadClass($class);
}

$cacheFile = dirname(__FILE__) . '/xmlrpc.cache';


$server = new Zend_XmlRpc_Server();

if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
require_once 'My/Services/Glue.php';
require_once 'My/Services/Paste.php';
require_once 'My/Services/Tape.php';

$server->setClass('My_Services_Glue', 'glue');
// espace de noms glue
$server->setClass('My_Services_Paste', 'paste');
// espace de noms paste
$server->setClass('My_Services_Tape', 'tape');
// espace de noms tape

1597
Zend_XmlRpc

Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
}

echo $server->handle();

L'exemple ci dessus essaye de récupérer la définition du serveur via le fichier xmlrpc.cache.


Si ceci échoue, alors les classes nécessaires au service sont chargées, attachées au serveur,
et une tentative de création de cache est lancée.

3.10. Exemples d'utilisation


Voici quelques exemples qui démontrent les diverses options disponibles pour un serveur XML-
RPC.

3.10.1. Utilisation basique


L'exemple ci dessous attache une fonction au service XML-RPC.

/**
* Retourne le hash MD5 d'une valeur
*
* @param string $value Valeur à hasher
* @return string Hash MD5 de la valeur
*/
function md5Value($value)
{
return md5($value);
}

$server = new Zend_XmlRpc_Server();


$server->addFunction('md5Value');
echo $server->handle();

3.10.2. Attacher une classe


L'exemple ci dessous montre comment attacher les méthodes publiques d'une classe en tant
que méthodes XML-RPC.

$server = new Zend_XmlRpc_Server();


$server->setClass('Services_Comb');
echo $server->handle();

3.10.3. Attacher plusieurs classes grâce aux espaces de noms


L'exemple ci dessous montre comment attacher plusieurs classes grâce aux espaces de noms.

require_once 'Services/Comb.php';
require_once 'Services/Brush.php';
require_once 'Services/Pick.php';

$server = new Zend_XmlRpc_Server();


$server->setClass('Services_Comb', 'comb');
// méthodes appelées sous la forme comb.*
$server->setClass('Services_Brush', 'brush');
// méthodes appelées sous la forme brush.*
$server->setClass('Services_Pick', 'pick');

1598
Zend_XmlRpc

// méthodes appelées sous la forme pick.*


echo $server->handle();

3.10.4. Spécifier les exceptions à utiliser en cas d'erreurs dans les


réponses XML-RPC
L'exemple ci dessous montre comment spécifier les exceptions à utiliser en cas d'erreurs dans
les réponses XML-RPC.

require_once 'Services/Exception.php';
require_once 'Services/Comb.php';
require_once 'Services/Brush.php';
require_once 'Services/Pick.php';

// Utilise les Services_Exception pour les erreurs


Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');

$server = new Zend_XmlRpc_Server();


$server->setClass('Services_Comb', 'comb');
// méthodes appelées sous la forme comb.*
$server->setClass('Services_Brush', 'brush');
// méthodes appelées sous la forme brush.*
$server->setClass('Services_Pick', 'pick');
// méthodes appelées sous la forme pick.*
echo $server->handle();

3.10.5. Utiliser un objet de requête personnalisé


L'exemple suivant montre comment utiliser un objet de requête personnalisé.

require_once 'Services/Request.php';
require_once 'Services/Exception.php';
require_once 'Services/Comb.php';
require_once 'Services/Brush.php';
require_once 'Services/Pick.php';

// Utilise les Services_Exception pour les erreurs


Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');

$server = new Zend_XmlRpc_Server();


$server->setClass('Services_Comb', 'comb');
// méthodes appelées sous la forme comb.*
$server->setClass('Services_Brush', 'brush');
// méthodes appelées sous la forme brush.*
$server->setClass('Services_Pick', 'pick');
// méthodes appelées sous la forme pick.*

// Crée un objet de requête


$request = new Services_Request();

echo $server->handle($request);

3.10.6. Utiliser un objet de réponse personnalisé


L'exemple suivant montre comment utiliser un objet de réponse personnalisé.

require_once 'Services/Request.php';

1599
Zend_XmlRpc

require_once 'Services/Response.php';
require_once 'Services/Exception.php';
require_once 'Services/Comb.php';
require_once 'Services/Brush.php';
require_once 'Services/Pick.php';

// Utilise les Services_Exception pour les erreurs


Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');

$server = new Zend_XmlRpc_Server();


$server->setClass('Services_Comb', 'comb');
// méthodes appelées sous la forme comb.*
$server->setClass('Services_Brush', 'brush');
// méthodes appelées sous la forme brush.*
$server->setClass('Services_Pick', 'pick');
// méthodes appelées sous la forme pick.*

// Crée un objet de requête


$request = new Services_Request();

// Utilise une réponse personnalisée


$server->setResponseClass('Services_Response');

echo $server->handle($request);

3.10.7. Cache entre les requêtes


Les exemples suivants montrent comment gérer une politique de cache inter-requêtes.

require_once 'Services/Request.php';
require_once 'Services/Response.php';
require_once 'Services/Exception.php';
require_once 'Services/Comb.php';
require_once 'Services/Brush.php';
require_once 'Services/Pick.php';

// Specifier un fichier de cache


$cacheFile = dirname(__FILE__) . '/xmlrpc.cache';

// Utilise les Services_Exception pour les erreurs


Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');

$server = new Zend_XmlRpc_Server();

// Essaye de récupérer la définition du serveur via le cache


if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
$server->setClass('Services_Comb', 'comb');
// méthodes appelées sous la forme comb.*
$server->setClass('Services_Brush', 'brush');
// méthodes appelées sous la forme brush.*
$server->setClass('Services_Pick', 'pick');
// méthodes appelées sous la forme pick.*

// Sauve le cache
Zend_XmlRpc_Server_Cache::save($cacheFile, $server));
}

// Crée un objet de requête


$request = new Services_Request();

1600
Zend_XmlRpc

// Utilise une réponse personnalisée


$server->setResponseClass('Services_Response');

echo $server->handle($request);

1601
ZendX_Console_Process_Unix
1. ZendX_Console_Process_Unix
1.1. Introduction
ZendX_Console_Process_Unix allows developers to spawn an object as a new process,
and so do multiple tasks in parallel on console environments. Through its specific nature, it is
only working on *nix based systems like Linux, Solaris, Mac/OSx and such. Additionally, the
shmop_*, pcntl_* and posix_* modules are required for this component to run. If one of the
requirements is not met, it will throw an exception after instantiating the component.

1.2. Basic usage of ZendX_Console_Process_Unix


ZendX_Console_Process_Unix is an abstract class, which requires the user to extend it. It
has a single abstract method called _run() which has to be implemented to create a working
process. It also comes with multiple methods for checking the alive status and share variables
between the parent and the child process.

The _run() method and every method which is called by it is executed by the child process.
Every other method which is called directly by the parent is executed by the parent process.

setVariable() and getVariable() can be used from both the parent- and the child process
to share variables. To observe the alive status, the child process should call _setAlive() in a
frequent interval, so that the parent process can check the last alive time via getLastAlive().
To get the PID of the child process, the parent can call getPid().

1602
ZendX_Console_Process_Unix

Exemple 985. Basic example for processing

This example illustrates a basic child process

class MyProcess extends ZendX_Console_Process_Unix


{
protected function _run()
{
for ($i = 0; $i < 10; $i++) {
// Doing something really important which can't wait: sleeping
sleep(1);
}
}
}

// This part should last about 10 seconds, not 20.


$process1 = new MyProcess();
$process1->start();

$process2 = new MyProcess();


$process2->start();

while ($process1->isRunning() && $process2->isRunning()) {


sleep(1);
}

echo 'All processes completed';

In this example a process is forked twice and executed. As every process runs 10 seconds,
the parent process will be finished after 10 seconds (and not 20).

1603
ZendX_JQuery
1. Introduction
As of version 1.7, Zend Framework integrates jQuery view and form helpers through its extras
library. The jQuery support is meant as an alternative to the already existing Dojo library
integration. Currently jQuery can be integrated into your Zend Framework applications in the
following ways:

• View helper to help setup the jQuery (Core and UI) environment

• jQuery UI specific Zend_View helpers

• jQuery UI specific Zend_Form elements and decorators

By default the jQuery javascript dependencies are loaded from the Google Ajax Library Content
Distribution Network. The CDN offers both jQuery Core and jQuery UI access points and the
view helpers therefore can already offer you most the dependencies out of the box. Currently the
Google CDN offers jQuery UI support up to version 1.5.2, but the jQuery view and form helpers
already make use of the UI library 1.6 version (AutoComplete, ColorPicker, Spinner, Slider). To
make use of these great additions you have to download the release candidate version of the
jQuery UI library from its website.

2. ZendX_JQuery View Helpers


Zend Framework provides jQuery related View Helpers through its Extras Library. These can be
enabled in two ways, adding jQuery to the view helper path:

$view->addHelperPath("ZendX/JQuery/View/Helper", "ZendX_JQuery_View_Helper");

Or using the ZendX_JQuery::enableView(Zend_View_Interface $view) method that


does the same for you.

2.1. jQuery() View Helper


The jQuery() view helper simplifies setup of your jQuery environment in your application. It
takes care of loading the core and ui library dependencies if necessary and acts as a stack for
all the registered onLoad javascript statements. All jQuery view helpers put their javascript code
onto this stack. It acts as a collector for everything jQuery in your application with the following
responsibilities:

• Handling deployment of CDN or a local path jQuery Core and UI libraries.

• Handling $(document).onLoad() events.

• Specifying additional stylesheet themes to use.

The jQuery() view helper implementation, like its dojo() pendant, follows the placeholder
architecture implementation; the data set in it persists between view objects, and may be directly
echo'd from your layout script. Since views specified in a Zend_Layout script file are rendered
before the layout itself, the jQuery() helper can act as a stack for jQuery statements and render
them into the head segment of the html page.

1604
ZendX_JQuery

Contrary to Dojo, themes cannot be loaded from a CDN for the jQuery UI widgets and have to
be implemented in your pages stylesheet file or loaded from an extra stylesheet file. A default
theme called Flora can be obtained from the jQuery UI downloadable file.

1605
ZendX_JQuery

Exemple 986. jQuery() View Helper Example


In this example a jQuery environment using the core and UI libraries will be needed.
UI Widgets should be rendered with the Flora thema that is installed in 'public/styles/
flora.all.css'. The jQuery libraries are both loaded from local paths.
To register the jQuery functionality inside the view object, you have to add the appropriate
helpers to the view helper path. There are many ways of accomplishing this, based on the
requirements that the jQuery helpers have. If you need them in one specific view only, you
can use the addHelperPath method on initialization of this view, or right before rendering:
$view->addHelperPath('ZendX/JQuery/View/Helper/', 'ZendX_JQuery_View_Helper');

If you need them throughout your application, you can register them in your bootstrap file
using access to the Controller Plugin ViewRenderer:
$view = new Zend_View();
$view->addHelperPath('ZendX/JQuery/View/Helper/', 'ZendX_JQuery_View_Helper');

$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer();


$viewRenderer->setView($view);
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);

Now in the view script we want to display a Date Picker and an Ajax based Link.
<?php echo $this->ajaxLink("Show me something",
"/hello/world",
array('update' => '#content'));?>
<div id="content"></div>

<form method="post" action="/hello/world">


Pick your Date: <?php echo $this->datePicker("dp1",
'',
array(
'defaultDate' =>
date('Y/m/d', time())));?>
<input type="submit" value="Submit" />
</form>

Both helpers now stacked some javascript statements on the jQuery helper and printed a
link and a form element respectively. To access the javascript we have to utilize the jQuery()
functionality. Both helpers already activated their dependencies that is they have called
jQuery()->enable() and jQuery()->uiEnable(). We only have to print the jQuery()
environment, and we choose to do so in the layout script's head segment:
<html>
<head>
<title>A jQuery View Helper Example</title>
<?php echo $this->jQuery(); ?>
</head>

<body>
<?php echo $this->layout()->content; ?>
</body>
</html>

Although $this->layout()->content; is printed behind the $this->jQuery()


statement, the content of the view script is rendered before. This way all the javascript
onLoad code has already been put on the onLoad stack and can be printed within the head
segment of the html document.

1606
ZendX_JQuery

2.1.1. jQuery NoConflict Mode


jQuery offers a noConflict mode that allows the library to be run side by side
with other javascript libraries that operate in the global namespace, Prototype for
example. The Zend Framework jQuery View Helper makes usage of the noConflict
mode very easy. If you want to run Prototype and jQuery side by side you can
call ZendX_JQuery_View_Helper_JQuery::enableNoConflictMode(); and all jQuery
helpers will operate in the No Conflict Mode.

Exemple 987. Building your own Helper with No Conflict Mode

To make use of the NoConflict Mode in your own jQuery helper, you only have to use
the static method ZendX_JQuery_View_Helper_JQuery::getJQueryHandler()
method. It returns the variable jQuery is operating in at the moment, either $ or $j

class MyHelper_SomeHelper extends Zend_View_Helper_Abstract


{
public function someHelper()
{
$jquery = $this->view->jQuery();
$jquery->enable(); // enable jQuery Core Library

// get current jQuery handler based on noConflict settings


$jqHandler = ZendX_JQuery_View_Helper_JQuery::getJQueryHandler();

$function = '("#element").click(function() '


. '{ alert("noConflict Mode Save Helper!"); }'
. ')';
$jquery->addOnload($jqHandler . $function);
return '';
}
}

2.1.2. jQuery UI Themes


Since there are no online available themes to use out of the box, the implementation of the UI
library themes is a bit more complex than with the Dojo helper. The jQuery UI documentation
describes for each component what stylesheet information is needed and the Default and Flora
Themes from the downloadable archive give hints on the usage of stylesheets. The jQuery helper
offers the function jQuery()->addStylesheet($path); function to include the dependant
stylesheets whenever the helper is enabled and rendered. You can optionally merge the required
stylesheet information in your main stylesheet file.

2.1.3. Methods Available


The jQuery() view helper always returns an instance of the jQuery placeholder container. That
container object has the following methods available:

2.1.3.1. jQuery Core Library methods

• enable(): explicitly enable jQuery integration.

• disable(): disable jQuery integration.

• isEnabled(): determine whether or not jQuery integration is enabled.

• setVersion(): set the jQuery version that is used. This also decides on the library loaded
from the Google Ajax Library CDN

1607
ZendX_JQuery

• getVersion(): get the current jQuery that is used. This also decides on the library loaded
from the Google Ajax Library CDN

• useCdn(): Return true, if CDN usage is currently enabled

• useLocalPath(): Return true, if local usage is currently enabled

• setLocalPath(): Set the local path to the jQuery Core library

• getLocalPath(): If set, return the local path to the jQuery Core library

2.1.3.2. jQuery UI Library methods

• uiEnable(): explicitly enable jQuery UI integration.

• uiDisable(): disable jQuery UI integration.

• uiIsEnabled(): determine whether or not jQuery UI integration is enabled.

• setUiVersion(): set the jQuery UI version that is used. This also decides on the library
loaded from the Google Ajax Library CDN

• getUiVersion(): get the current jQuery UI that is used. This also decides on the library
loaded from the Google Ajax Library CDN

• useUiCdn(): Return true, if CDN usage is currently enabled for jQuery UI

• useUiLocal(): Return true, if local usage is currently enabled for jQuery UI

• setUiLocalPath(): Set the local path to the jQuery UI library

• getUiLocalPath(): If set, get the local path to the jQuery UI library

2.1.3.3. jQuery Helper Utility methods

• setView(Zend_View_Interface $view): set a view instance in the container.

• onLoadCaptureStart(): Start capturing javascript code for jQuery onLoad execution.

• onLoadCaptureEnd(): Stop capturing

• javascriptCaptureStart(): Start capturing javascript code that has to be rendered after


the inclusion of either jQuery Core or UI libraries.

• javascriptCaptureEnd(): Stop capturing.

• addJavascriptFile($path): Add javascript file to be included after jQuery Core or UI


library.

• getJavascriptFiles(): Return all currently registered additional javascript files.

• clearJavascriptFiles(): Clear the javascript files

• addJavascript($statement): Add javascript statement to be included after jQuery Core


or UI library.

• getJavascript(): Return all currently registered additional javascript statements.

1608
ZendX_JQuery

• clearJavascript(): Clear the javascript statements.

• addStylesheet($path): Add a stylesheet file that is needed for a jQuery view helper to
display correctly.

• getStylesheets(): Get all currently registered additional stylesheets.

• addOnLoad($statement): Add javascript statement that should be executed on document


loading.

• getOnLoadActions(): Return all currently registered onLoad statements.

• setRenderMode($mask): Render only a specific subset of the jQuery environment via


ZendX_JQuery::RENDER_ constants. Rendering all elements is the default behaviour.

• getRenderMode(): Return the current jQuery environment rendering mode.

• setCdnSsl($bool): Set if the CDN Google Ajax Library should be loaded from an SSL or
a Non-SSL location.

These are quite a number of methods, but many of them are used for internally by all the
additional view helpers and during the printing of the jQuery environment. Unless you want to
build your own jQuery helper or have a complex use-case, you will probably only get in contact
with a few methods of these.

2.1.4. Refactoring jQuery environment with setRenderMode()


Using the current setup that was described, each page of your website would show a different
subset of jQuery code that would be needed to keep the current jQuery related items running.
Also different files or stylesheets may be included depending on which helpers you implemented
in your application. In production stage you might want to centralize all the javascript your
application generated into a single file, or disable stylesheet rendering because you have merged
all the stylesheets into a single file and include it statically in your layout. To allow a smooth
refactoring you can enable or disable the rendering of certain jQuery environment blocks with
help of the following constants and the jQuery()->setRenderMode($bitmask) function.

• ZendX_JQuery::RENDER_LIBRARY: Renders jQuery Core and UI library

• ZendX_JQuery::RENDER_SOURCES: Renders additional javascript files

• ZendX_JQuery::RENDER_STYLESHEETS: Renders jQuery related stylesheets

• ZendX_JQuery::RENDER_JAVASCRIPT: Render additional javascript statements

• ZendX_JQuery::RENDER_JQUERY_ON_LOAD: Render jQuery onLoad statements

• ZendX_JQuery::RENDER_ALL: Render all previously mentioned blocks, this is default


behaviour.

For an example, if you would have merged jQuery Core and UI libraries as well as other files into
a single large file as well as merged stylesheets to keep HTTP requests low on your production
application. You could disallow the jQuery helper to render those parts, but render all the other
stuff with the following statement in your view:

$view->jQuery()

1609
ZendX_JQuery

->setRenderMode(ZendX_JQuery::RENDER_JAVASCRIPT |
ZendX_JQuery::RENDER_JQUERY_ON_LOAD);

This statement makes sure only the required javascript statements and onLoad blocks of the
current page are rendered by the jQuery helper.

2.1.5. Migrations
Prior to 1.8 the methods setCdnVersion(), setLocalPath() setUiCdnVersion() and
setUiLocalPath() all enabled the view helper upon calling, which is considered a bug from
the following perspective: If you want to use the any non-default library option, you would have to
manually disable the jQuery helper aftwards if you only require it to be loaded in some scenarios.
With version 1.8 the jQuery helper does only enable itsself, when enable() is called, which all
internal jQuery View helpers do upon being called.

2.2. JQuery Helpers


2.2.1. AjaxLink Helper
The AjaxLink helper uses jQuery's ajax capabilities to offer the creation of links that do ajax
requests and inject the response into a chosen DOM element. It also offers the possibility to
append simple jQuery effects to both the link and the response DOM element. A simple example
introduces its functionality:

<!-- Inside your View Object -->


<div id="container"></div>
<?php echo $this->view->ajaxLink("Link Name",
"url.php",
array('update' => '#container')); ?>

This example creates a link with the label "Link Name" that fires an ajax request to url.php upon
click and renders the response into the div container "#container". The function header for the
ajaxLink is as follows: function ajaxLink($label, $url, $options, $params); The
options array is very powerful and offers you lots of functionality to customize your ajax requests.

Available options are:

Tableau 158. AjaxLink options

Option Data Type Default Value Description


update string false Container to inject
response content into,
use jQuery CSS
Selector syntax, ie.
"#container" or ".box"
method string Implicit GET or Request method, is
POST implicitly chosen as
GET when no
parameters given
and POST when
parameters given.
complete string false Javascript callback
executed, when ajax

1610
ZendX_JQuery

Option Data Type Default Value Description


request is complete.
This option allows for
shortcut effects, see
next section.
beforeSend string false Javascript callback
executed right before
ajax request is started.
This option allows for
shortcut effects, see
next section.
noscript boolean true If true the link
generated will contain
a href attribute to
the given link for
non-javascript enabled
browsers. If false href
will resolve to "#".
dataType string html What type of data
is the Ajax Response
of? Possible are Html,
Text, Json. Processing
Json responses has to
be done with custom
"complete" callback
functions.
attribs array null Additional HTML
attributes the ajaxable
link should have.
title, id, class string false Convenience
shortcuts for HTML
Attributes.
inline boolean false Although far from
best practice, you can
set javascript for this
link inline in "onclick"
attribute.

To enlighten the usage of this helper it is best to show another bunch of more complex examples.
This example assumes that you have only one view object that you want to display and don't
care a lot about html best practices, since we have to output the jQuery environment just before
the closing body tag.

<html>
<head>
<title>Zend Framework jQuery AjaxLink Example</title>
<script language="javascript"
type="text/javascript"
src="myCallbackFuncs.js"></script>
</head>

<body>

1611
ZendX_JQuery

<!-- without echoing jQuery this following -->


<!-- list only prints a list of for links -->
<ul>
<li>
<?php echo $this->ajaxLink("Example 1",
"/ctrl/action1",
array('update' => '#content',
'noscript' => false,
'method' => 'POST')); ?>
</li>
<li>
<?php echo $this->ajaxLink("Example 2",
"/ctrl/action2",
array('update' => '#content',
'class' => 'someLink'),
array('param1' => 'value1',
'param2' => 'value2')); ?>
</li>
<li><?php echo $this->ajaxLink("Example 3",
"/ctrl/action3",
array('dataType' => 'json',
'complete' =>
'alert(data)')); ?>
</li>
<li><?php echo $this->ajaxLink("Example 4",
"/ctrl/action4",
array('beforeSend' => 'hide',
'complete' => 'show')); ?>
</li>
<li>
<?php echo $this->ajaxLink("Example 5",
"/ctrl/action5",
array(
'beforeSend' =>
'myBeforeSendCallbackJsFunc();',
'complete' =>
'myCompleteCallbackJsFunc(data);')
); ?>
</li>
</ul>

<!-- only at this point the javascript is printed to sreen -->


<?php echo $this->jQuery(); ?>
</body>
</html>

You might have already seen that the 'update', 'complete', and 'beforeSend' options have to be
executed in specific order and syntax so that you cannot use those callbacks and override their
behaviour completely when you are using ajaxLink(). For larger use cases you will probably
want to write the request via jQuery on your own. The primary use case for the callbacks is effect
usage, other uses may very well become hard to maintain. As shown in Example Link 5, you can
also forward the beforeSend/complete Callbacks to your own javascript functions.

2.2.1.1. Shortcut Effects

You can use shortcut effect names to make your links actions more fancy. For example the
Container that will contain the ajax response may very well be invisible in the first place.
Additionally you can use shortcut effects on the link to hide it after clicking. The following effects
can be used for callbacks:

1612
ZendX_JQuery

• complete callback: 'show', 'showslow', 'shownormal', 'showfast', 'fadein', 'fadeinslow',


'fadeinfast', 'slidedown', 'slidedownslow', 'slidedownfast'. These all correspond to the jQuery
effects fadeIn(), show() and slideDown() and will be executed on the container specified in
update.

• beforeSend callback: 'fadeout', 'fadeoutslow', 'fadeoutfast', 'hide', 'hideslow', 'hidefast',


'slideup'. These correspond to the jQuery effects fadeOut(), hide(), slideUp() and are executed
on the clicked link.

<?php echo $this->ajaxLink("Example 6",


"/ctrl/action6",
array('beforeSend' => 'hide',
'complete' => 'show')); ?>

2.2.2. jQuery UI Library Helpers


The jQuery UI Library offers a range of layout and form specific widgets that are integrated into the
Zend Framework via View Helpers. The form-elements are easy to handle and will be described
first, whereas the layout specific widgets are a bit more complex to use.

2.2.2.1. jQuery UI Form Helpers

The method signature for all form view helpers closely resembles the Dojo View helpers
signature, helper($id, $value, $params, $attribs). A description of the parameters
follows:

• $id: Will act as the identifier name for the helper element inside a form. If in the attributes no
id element is given, this will also become the form element id, that has to be unique across
the DOM.

• $value: Default value of the element.

• $params: Widget specific parameters that customize the look and feel of the widget. These
options are unique to each widget and described in the jQuery UI documentation. The data
is casted to JSON, so make sure to use the Zend_Json_Expr class to mark executable
javascript as safe.

• $attribs: HTML Attributes of the Form Helper

The following UI widgets are available as form view helpers. Make sure you use the correct
version of jQuery UI library to be able to use them. The Google CDN only offers jQuery UI up to
version 1.5.2. Some other components are only available from jQuery UI SVN, since they have
been removed from the announced 1.6 release.

• autoComplete($id, $value, $params, $attribs): The AutoComplete View helper


will be included in a future jQuery UI version (currently only via jQuery SVN) and creates a text
field and registeres it to have auto complete functionality. The completion data source has to
be given as jQuery related parameters 'url' or 'data' as described in the jQuery UI manual.

• colorPicker($id, $value, $params, $attribs): ColorPicker is currently available


in jQuery UI only from SVN and creates a text field that opens up a color picking tool when
activated.

• datePicker($id, $value, $params, $attribs): Create a DatePicker inside a text


field. This widget is available since jQuery UI 1.5 and can therefore currently be used with the
Google CDN. Using the 'handles' option to create multiple handles overwrites the default set
value and the jQuery parameter 'startValue' internally inside the view helper.

1613
ZendX_JQuery

• slider($id, $value, $params, $attribs): Create a Sliding element that updates its
value into a hidden form field. Available since jQuery UI 1.5.

• spinner($id, $value, $params, $attribs): Create a Spinner element that can spin
through numeric values in a specified range. This is set on top of a form text field and is
available only from jQuery UI SVN

Exemple 988. Showing jQuery Form View Helper Usage

In this example we want to simulate a fictional web application that offers auctions on travel
locations. A user may specify a city to travel, a start and end date, and a maximum amount
of money he is willing to pay. Therefore we need an autoComplete field for all the currently
known travel locations, a date picker for start and end dates and a spinner to specify the
amount.

<form method="post" action="bid.php">


<label for="locaction">Where do you want to travel?</label>
<?php echo $this->autoComplete("location",
"",
array('data' => array('New York',
'Mexico City',
'Sydney',
'Ruegen',
'Baden Baden'),
'multiple' => true)); ?>
<br />

<label for="startDate">Travel Start Date:</label>


<?php echo $this->datePicker("startDate", '',
array(
'defaultDate' => '+7',
'minDate' => '+7',
'onClose' => new Zend_Json_Expr('myJsonFuncCechkingValidity'))); ?>
<br />

<label for="startDate">Travel End Date:</label>


<?php echo $this->datePicker("endDate", '',
array(
'defaultDate' => '+14',
'minDate' => '+7',
'onClose' => new Zend_Json_Expr('myJsonFuncCechkingValidity'))); ?>
<br />

<label for="bid">Your Bid:</label>


<?php echo $this->spinner("bid",
"",
array('min' => 1205.50,
'max' => 10000,
'start' => 1205.50,
'currency' => '€')); ?>
<br />

<input type="submit" value="Bid!" />


</form>

You can see the use of jQuery UI Widget specific parameters. These all correspond to those
given in the jQuery UI docs and are converted to JSON and handed through to the view
script.

1614
ZendX_JQuery

2.2.2.2. Using an Action Helper to Send Data to AutoComplete

The jQuery UI Autocomplete Widget can load data from a remote location rather than from an
javascript array, making its usage really useful. Zend Framework currently providers a bunch of
server-side AutoComplete Helpers and there is one for jQuery too. You register the helper to
the controller helper broker and it takes care of disabling layouts and renders an array of data
correctly to be read by the AutoComplete field. To use the Action Helper you have to put this
rather long statement into your bootstrap or Controller initialization function:

Zend_Controller_Action_HelperBroker::addHelper(
new ZendX_JQuery_Controller_Action_Helper_AutoComplete()
);

You can then directly call the helper to render AutoComplete Output in your Controller

class MyIndexController extends Zend_Controller_Action


{
public function autocompleteAction()
{
// The data sent via the ajax call is inside $_GET['q']
$filter = $_GET['q'];

// Disable Layout and stuff, just displaying AutoComplete Information.


$this->_helper->autoComplete(array("New York", "Bonn", "Tokio"));
}
}

2.2.2.3. jQuery UI Layout Helpers

There is a wide range of Layout helpers that the UI library offers. The ones covered by Zend
Framework view helpers are Accordion, Dialog, Tabs. Dialog is the most simple one, whereas
Accordion and Tab extend a common abstract class and offer a secondary view helper for pane
generation. The following view helpers exist in the jQuery view helpers collection, an example
accompanies them to show their usage.

• dialogContainer($id, $content, $params, $attribs): Create a Dialog Box that


is rendered with the given content.on startup. If the option 'autoOpen' set to false is specified
the box will not be displayed on load but can be shown with the additional dialog("open")
javascript function. See UI docs for details.

• tabPane($id, $content, $options): Add a new pane to a tab container with


the given $id. The given $content is shown in this tab pane. To set the title use
$options['title']. If $options['contentUrl'] is set, the content of the tab is
requested via ajax on tab activation.

• tabContainer($id, $params, $attribs): Render a tab container with all the currently
registered panes. This view helper also offers to add panes with the following syntax: $this-
>tabContainer()->addPane($id, $label, $content, $options).

• accordionPane($id, $content, $options): Add a new pane to the accordion


container with the given $id. The given $content is shown in this tab pane. To set the title
use $options['title'].

• accordionContainer($id, $params, $attribs): Render an accordion container with


all the currently registered panes. This view helper also offers to add panes with the following

1615
ZendX_JQuery

syntax: $this->accordionContainer()->addPane($id, $label, $content,


$options).

Exemple 989. Showing the latest news in a Tab Container

For this example we assume the developer already wrote the controller and model side of
the script and assigned an array of news items to the view script. This array contains at most
5 news elements, so we don't have to care about the tab container getting to many tabs.

<?php foreach($this->news AS $article): ?>


<?php $this->tabPane("newstab",
$article->body,
array('title' => $article->title)); ?>
<?php endforeach; ?>
<h2>Latest News</h2>
<?php echo $this->tabContainer("newstab",
array(),
array('class' => 'flora')); ?>

3. ZendX_JQuery Form Elements and Decorators


All View Helpers are pressed into Zend_Form elements or decorators also. They can even be
easily integrated into your already existing forms. To enable a Form for Zend_JQuery support
you can use two ways: Init your form as $form = new ZendX_JQuery_Form(); or use the
static method ZendX_JQuery::enableForm($form) to enable jQuery element support.

3.1. General Elements and Decorator Usage


Both elements and decorators of the Zend jQuery Form set can be initialized with the option
key jQueryParams to set certain jQuery object related parameters. This jQueryParams array
of options matches to the $params variable of the corresponding view helpers. For example:

$element = new ZendX_JQuery_Form_Element_DatePicker(


'dp1',
array('jQueryParams' => array('defaultDate' => '2007/10/10'))
);
// would internally call to:
$view->datePicker("dp1", "", array('defaultDate' => '2007/10/10'), array());

Additionally elements jQuery options can be customized by the following methods:

• setJQueryParam($name, $value): Set the jQuery option $name to the given value.

• setJQueryParams($params): Set key value pairs of jQuery options and merge them with
the already set options.

• getJQueryParam($name): Return the jQuery option with the given name.

• getJQueryParams(): Return an array of all currently set jQuery options.

Each jQuery related Decorator also owns a getJQueryParams() method, to set options you
have to use the setDecorators(), addDecorator() or addDecorators() functionality of
a form element and set the jQueryParams key as option:

$form->setDecorators(array(

1616
ZendX_JQuery

'FormElements',
array('AccordionContainer', array(
'id' => 'tabContainer',
'style' => 'width: 600px;',
'jQueryParams' => array(
'alwaysOpen' => false,
'animated' => "easeslide"
),
)),
'Form'
));

3.2. Form Elements


The Zend Framework jQuery Extras Extension comes with the following Form Elements:

• ZendX_JQuery_Form_Element_AutoComplete: Proxy to AutoComplete View Helper

• ZendX_JQuery_Form_Element_ColorPicker: Proxy to ColorPicker View Helper

• ZendX_JQuery_Form_Element_DatePicker: Proxy to DatePicker View Helper

• ZendX_JQuery_Form_Element_Slider: Proxy to Slider View Helper

• ZendX_JQuery_Form_Element_Spinner: Proxy to Spinner View Helper

jQuery Decorators: Beware the Marker Interface for


UiWidgetElements

By default all the jQuery Form elements use the


ZendX_JQuery_Form_Decorator_UiWidgetElement decorator for
rendering the jQuery element with its specific view helper. This decorator
is inheritly different from the ViewHelper decorator that is used for most of
the default form elements in Zend_Form. To ensure that rendering works
correctly for jQuery form elements at least one decorator has to implement the
ZendX_JQuery_Form_Decorator_UiWidgetElementMarker interface,
which the default decorator does. If no marker interface is found an exception is
thrown. Use the marker interface if you want to implement your own decorator
for the jQuery form element specific rendering.

3.3. Form Decorators


The following Decorators come with the Zend Framework jQuery Extension:

• ZendX_JQuery_Form_Decorator_AccordionContainer: Proxy to AccordionContainer


View Helper

• ZendX_JQuery_Form_Decorator_AccordionPane: Proxy to AccordionPane View


Helper

• ZendX_JQuery_Form_Decorator_DialogContainer: Proxy to DialogContainer View


Helper

• ZendX_JQuery_Form_Decorator_TabContainer: Proxy to TabContainer View Helper

1617
ZendX_JQuery

• ZendX_JQuery_Form_Decorator_TabPane: Proxy to TabPane View Helper

• ZendX_JQuery_Form_Decorator_UiWidgetElement: Decorator to Display jQuery Form


Elements

Utilizing the Container elements is a bit more complicated, the following example builds a Form
with 2 SubForms in a TabContainer:

1618
ZendX_JQuery
$form = new ZendX_JQuery_Form();
The following example makes use of all Form elements and wraps them into 2 subforms
$form->setAction('formdemo.php');
that are decorated with a tab'mainForm');
$form->setAttrib('id', container. First we build the basic ZendX_JQuery_Form:
$form->setAttrib('class', with
Exemple 990. SubForms TabContainer Decorator
'flora');

$form->setDecorators(array(
'FormElements',
array('TabContainer', array(
'id' => 'tabContainer',
'style' => 'width: 600px;',
)),the Form Id (in this case to 'mainForm') is an important step for the TabContainer. It
Setting
$subForm1
'Form', = new ZendX_JQuery_Form();
is needed that the subforms can relate to the Container Id in a later form building stage. We
$subForm1->setDecorators(array(
));
now initialize two SubForms that will be decorated with the TabPane decorators:
'FormElements',
array('HtmlTag',
array('tag' => 'dl')),
array('TabPane',
array('jQueryParams' => array('containerId' => 'mainForm',
'title' => 'DatePicker and Slider')))
));

$subForm2 = new ZendX_JQuery_Form();


$subForm2->setDecorators(array(
'FormElements',
array('HtmlTag',
array('tag' => 'dl')),
array('TabPane',
array('jQueryParams'
In this stage it is important that the=> 'containerId'
array('containerId'
option => 'mainForm',
is set in each SubForm
TabPane, or the subforms cannot relate back'title' => Container
to the tab 'AutoComplete and Spinner')))
and would not be
//
)); Add Element Date Picker
displayed. To enforce this setting, an exception of the type ZendX_JQuery_Exception is
$elem = new ZendX_JQuery_Form_Element_DatePicker(
thrown if the option "datePicker1",
is not set. We can array("label"
now add all the desired elements
=> "Date to the subforms:
Picker:")
);
$elem->setJQueryParam('dateFormat', 'dd.mm.yy');
$subForm1->addElement($elem);

// Add Element Spinner


$elem = new ZendX_JQuery_Form_Element_Spinner(
"spinner1", array('label' => 'Spinner:')
);
$elem->setJQueryParams(array('min' => 0, 'max' => 1000, 'start' => 100));
$subForm1->addElement($elem);

// Add Slider Element


$elem = new ZendX_JQuery_Form_Element_Slider(
"slider1", array('label' => 'Slider:')
);
$elem->setJQueryParams(array('defaultValue' => '75'));
$subForm2->addElement($elem);

// Add Autocomplete Element


$elem = new ZendX_JQuery_Form_Element_AutoComplete(
"ac1", array('label' => 'Autocomplete:')
);
$elem->setJQueryParams(array('data' => array('New York',
'Berlin',
'Bern',
'Boston')));
$subForm2->addElement($elem);
$form->addSubForm($subForm1, 'subform1');
$form->addSubForm($subForm2, 'subform2');
// Submit
Three Button
additional lines are missing to put it all together and we have a jQuery animated form:
$elem = new Zend_Form_Element_Submit("btn1", array('value' => 'Submit'));
$formString = $form->render($view);
$subForm1->addElement($elem);

1619
Annexe A. Configuration système
requise par Zend Framework

Table des matières


A.1. Introduction ......................................................................................................... 1620
A.1.1. Version de PHP requise ........................................................................... 1620
A.1.2. Extensions PHP ....................................................................................... 1620
A.1.3. Les composants de Zend Framework ........................................................ 1624
A.1.4. Dépendances internes de Zend Framework ............................................... 1628

A.1. Introduction
Zend Framework requière un interpréteur PHP5 avec un serveur Web configuré pour gérer
correctement les scripts PHP. Certaines fonctionnalités requièrent des extensions additionnelles
ou des fonctionnalités du serveur Web ; dans la plupart des cas le framework peut être utilisé
sans celle-ci, bien que l'exécution puisse perdre en performance ou les fonctionnalités auxiliaires
peuvent ne pas être entièrement fonctionnelles. Un exemple d'un telle dépendance est le
mod_rewrite d'un environnement Apache, qui peut être utilisé pour implémenter les "jolies
URL" ("pretty URL") comme "http://www.exemple.com/utilisateur/edition". Si le mod_rewrite
n'est pas activé, Zend Framework peut être configuré pour supporter les URL de type
"http://www.exemple.com?controller=utilisateur&action=edition". Les jolies
URL peuvent être utilisées pour réduire la longueur des URLs avec une représentation textuelle
ou pour l'optimisation des moteurs de recherche (SEO), mais il n'affectent pas directement le
fonctionnement de l'application.

A.1.1. Version de PHP requise


Zend recommande la version la plus récente de PHP pour des questions de sécurité et de
performances, et supporte actuellement la version 5.2.4 de PHP (ou plus récent).

Zend Framework possède une collection étendue de tests automatisés, que vous pouvez lancer
avec PHPUnit 3.3.0 ou plus.

A.1.2. Extensions PHP


Ci-dessous, la table recense toutes les extensions typiquement trouvées dans PHP et comment
elles sont utilisées dans Zend Framework. Cela peut aider à vous guider pour savoir quelles
extensions sont exigées pour votre application. Cependant toutes les extensions utilisées par
Zend Framework ne sont pas exigées pour chaque application.

Une dépendance de type "forte" indique que le composant ou la classe ne pourra pas fonctionner
correctement si l'extension respective n'est pas disponible, tandis qu'une dépendance de type
"faible" indique que le composant peut utiliser l'extension si elle est disponible mais fonctionnera
malgré tout si elle ne l'est pas. Certains composants utiliseront automatiquement les extensions
si elles sont disponibles afin d'optimiser les performances mais pourront exécuter du code
similaire dans le propre code du composant si elles ne le sont pas.

1620
Configuration système
requise par Zend Framework

Tableau A.1. Extensions PHP utilisées par composant dans Zend Framework

Extension PHP Type de dépendance Utilisé par le composant


de Zend Framework
Forte Zend_Cache_Backend_Apc
apc
Faible Zend_File_Transfer
bcmath Faible Zend_Locale
bitset Faible Zend_Search_Lucene
bz2 --- ---
calendar --- ---
com_dotnet --- ---
Zend_Auth_Adapter_Http
Zend_Gdata
Zend_Http_Client
Zend_Pdf
ctype Forte Zend_Rest_Client
Zend_Rest_Server
Zend_Search_Lucene
Zend_Uri
Zend_Validate
curl Forte Zend_Http_Client_Adapter_Curl
date Faible Zend_Amf
dba --- ---
dbase --- ---
Zend_Amf
Zend_Dom
Zend_Feed
Zend_Gdata
Zend_Log_Formatter_Xml
Zend_Rest_Server
Zend_Soap
dom Forte
Zend_Search_Lucene
Zend_Service_Amazon
Zend_Service_Delicious
Zend_Service_Flickr
Zend_Service_Simpy
Zend_Service_Yahoo
Zend_XmlRpc
exif --- ---
fbsql --- ---

1621
Configuration système
requise par Zend Framework

Extension PHP Type de dépendance Utilisé par le composant


de Zend Framework
fdf --- ---
filter --- ---
ftp --- ---
Zend_Captcha
gd Forte
Zend_Pdf
gettext --- ---
gmp --- ---
hash Forte Zend_Auth_Adapter_Http
ibm_db2 Forte Zend_Db_Adapter_Db2
Zend_Currency
Zend_Locale_Format
Zend_Mime
Zend_Pdf
iconv Forte
Zend_Search_Lucene
Zend_Service_Audioscrobbler
Zend_Service_Flickr
Zend_XmlRpc_Client
igbinary Forte Zend_Serializer_Adapter_Igbinary
imap --- ---
informix --- ---
interbase Forte Zend_Db_Adapter_Firebird
Zend_Json
json Faible
Zend_Serializer_Adapter_Json
ldap Forte Zend_Ldap
libxml --- ---
mbstring Forte Zend_Feed
mcrypt Forte Zend_Service_ReCaptcha
memcache Forte Zend_Cache_Backend_Memcached
mhash --- ---
mime_magic Forte Zend_Http_Client
ming --- ---
msql --- ---
mssql --- ---
mysql --- ---
mysqli Forte Zend_Db_Adapter_Mysqli
ncurses --- ---
oci8 Forte Zend_Db_Adapter_Oracle

1622
Configuration système
requise par Zend Framework

Extension PHP Type de dépendance Utilisé par le composant


de Zend Framework
odbc --- ---
openssl --- ---
pcntl --- ---
pcre Forte Virtuellement tous les
composants
pdo Forte Tous les adaptateurs de bases
de données PDO
pdo_dblib --- ---
pdo_firebird --- ---
pdo_mssql Forte Zend_Db_Adapter_Pdo_Mssql
pdo_mysql Forte Zend_Db_Adapter_Pdo_Mysql
pdo_oci Forte Zend_Db_Adapter_Pdo_Oci
pdo_pgsql Forte Zend_Db_Adapter_Pdo_Pgsql
pdo_sqlite Forte Zend_Db_Adapter_Pdo_Sqlite
pgsql --- ---
posix Faible Zend_Mail
pspell --- ---
readline --- ---
recode --- ---
Zend_Controller
Zend_Filter
Zend_Filter_Input
Zend_Json
Zend_Log
Reflection Forte
Zend_Rest_Server
Zend_Server_Reflection
Zend_Validate
Zend_View
Zend_XmlRpc_Server
Zend_Controller_Action_Helper_Redir
session Forte
Zend_Session
shmop --- ---
Zend_Config_Xml
Zend_Feed
Zend_Rest_Client
SimpleXML Forte
Zend_Serializer_Adapter_Wddx
Zend_Service_Audioscrobbler
Zend_Soap

1623
Configuration système
requise par Zend Framework

Extension PHP Type de dépendance Utilisé par le composant


de Zend Framework
Zend_XmlRpc
Faible Zend_Amf
Zend_Service_StrikeIron
soap Forte
Zend_Soap
sockets --- ---
SPL Forte Virtuellement tous les
composants
SQLite Forte Zend_Cache_Backend_Sqlite
standard Forte Virtuellement tous les
composants
sybase --- ---
sysvmsg --- ---
sysvsem --- --
sysvshm --- ---
tidy --- ---
tokenizer --- ---
wddx Forte Zend_Serializer_Adapter_Wddx
Zend_Translate_Adapter_Qt
xml Forte Zend_Translate_Adapter_Tmx
Zend_Translate_Adapter_Xliff
XMLReader --- ---
xmlrpc --- ---
XMLWriter --- ---
xsl --- ---
zip --- ---
Zend_Pdf
zlib Forte
Zend_Filter_Compress

A.1.3. Les composants de Zend Framework


Ci-dessous vous trouverez un tableau qui liste tous les composants disponibles de Zend
Framework ainsi que les extensions PHP dont ils ont besoin. Ceci peut vous aider pour connaître
les extensions requises pour votre application. Les extensions par Zend Framework ne sont pas
utiles pour toutes les applications.

Une dépendance de type "forte" indique que le composant ou la classe ne pourra pas fonctionner
correctement si l'extension respective n'est pas disponible, tandis qu'une dépendance de type
"faible" indique que le composant peut utiliser l'extension si elle est disponible mais fonctionnera
malgré tout si elle ne l'est pas. Certains composants utiliseront automatiquement les extensions
si elles sont disponibles afin d'optimiser les performances mais pourront exécuter du code
similaire dans le propre code du composant si elles ne le sont pas.

1624
Configuration système
requise par Zend Framework

Tableau A.2. Zend Framework Components and the PHP Extensions they use

Zend Framework Type de dépendance Extension PHP


Components and the
PHP Extensions they use
pcre
All Components Forte SPL
standard
Zend_Acl --- ---
Forte date
Zend_Amf dom
Faible
SimpleXML
ctype
Zend_Auth Forte
hash
apc
memcache
Zend_Cache Forte
sqlite
zlib
Zend_Captcha Forte gd
libxml
Zend_Config Forte
SimpleXML
Zend_Console_Getopt --- ---
Reflection
Zend_Controller Forte
session
Zend_Currency Forte iconv
Zend_Date --- ---
ibm_db2
mysqli
oci8
pdo
Zend_Db Forte pdo_mssql
pdo_mysql
pdo_oci
pdo_pgsql
pdo_sqlite
Zend_Debug --- ---
Zend_Dojo --- ---
Zend_Dom Forte dom
Zend_Exception --- ---
Zend_Feed Forte dom

1625
Configuration système
requise par Zend Framework

Zend Framework Type de dépendance Extension PHP


Components and the
PHP Extensions they use
libxml
mbstring
SimpleXML
apc
Zend_File_Transfer Faible
upload_extension
Forte Reflection
Zend_Filter
Faible zlib
Zend_Form --- ---
ctype
Zend_Gdata Forte dom
libxml
ctype
Zend_Http Forte curl
mime_magic
Zend_InfoCard --- ---
Faible json
Zend_Json
Forte Reflection
Zend_Layout --- ---
Zend_Ldap --- ldap
Zend_Loader --- ---
Faible bcmath
Zend_Locale
Forte iconv
dom
Zend_Log Forte libxml
Reflection
Zend_Mail Faible posix
Zend_Measure --- ---
Zend_Memory --- ---
Zend_Mime Forte iconv
Zend_OpenId --- ---
Zend_Paginator --- ---
ctype
gd
Zend_Pdf Forte
iconv
zlib
Zend_ProgressBar --- ---

1626
Configuration système
requise par Zend Framework

Zend Framework Type de dépendance Extension PHP


Components and the
PHP Extensions they use
Zend_Registry --- ---
Zend_Request --- ---
ctype
dom
Zend_Rest Forte libxml
Reflection
SimpleXML
Faible bitset
ctype
Zend_Search_Lucene dom
Forte
iconv
libxml
wddx
Forte SimpleXml
Zend_Serializer
igbinary
Faible json
Zend_Server_Reflection Forte Reflection
Zend_Service_Akismet --- ---
dom
Zend_Service_Amazon Forte
libxml
iconv
Forte
Zend_Service_Audioscrobbler libxml
SimpleXML
dom
Zend_Service_Delicious Forte
libxml
dom
Zend_Service_Flickr Forte iconv
libxml
Zend_Service_Nirvanix --- ---
Zend_Service_ReCaptcha Forte mcrypt
dom
Zend_Service_Simpy Forte
libxml
Zend_Service_SlideShare --- ---
Zend_Service_StrikeIron Forte soap
Zend_Service_Technorati --- ---
Zend_Service_Twitter --- ---

1627
Configuration système
requise par Zend Framework

Zend Framework Type de dépendance Extension PHP


Components and the
PHP Extensions they use
dom
Zend_Service_Yahoo Forte
libxml
Zend_Session Forte session
dom
Zend_Soap Forte SimpleXML
soap
Zend_Test --- ---
Zend_Text --- ---
Zend_TimeSync --- ---
Zend_Translate Forte xml
Zend_Uri Forte ctype
ctype
Zend_Validate Forte
Reflection
Zend_Version --- ---
Zend_Validate Forte Reflection
Zend_Wildfire --- ---
dom
iconv
Zend_XmlRpc Forte libxml
Reflection
SimpleXML

A.1.4. Dépendances internes de Zend Framework


Ci-dessous vous trouverez un tableau listant les composants de Zend Framework ainsi que leurs
dépendances envers les autres composants de Zend Framework. Ceci peut vous aider si vous
utilisez un composant seul au lieu de la bibliothèque complète.

Une dépendance de type "forte" indique que le composant ou la classe ne pourra pas fonctionner
correctement si le composant respectif n'est pas disponible, tandis qu'une dépendance de type
"faible" indique que le composant peut avoir besoin du composant dans certains cas.

Bien qu'il soit possible d'utiliser uniquement certains composants au lieu de Zend
Framework complet, vous devriez avoir à l'esprit que ceci peut entraîner des
problèmes quand des fichiers sont manquants ou que des composants sont
utilisés dynamiquement.

1628
Configuration système
requise par Zend Framework

Tableau A.3. Composants de Zend Framework et leurs dépendances envers les autres
composants de Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Acl Forte Zend_Exception
Zend_Exception
Forte
Zend_Server
Zend_Date
Zend_Amf Faible
Zend_Loader
Zend_Locale
Sub
Zend_Registry
Forte Zend_Exception
Zend_Db
Zend_InfoCard
Faible Zend_Ldap
Zend_OpenId
Zend_Session
Zend_Controller
Zend_Http
Zend_Loader
Fix
Zend_Locale
Zend_Uri
Zend_View
Zend_Captcha
Zend_Auth
Zend_Config
Zend_Date
Zend_Dojo
Zend_Filter
Zend_Form
Zend_Json
Sub
Zend_Layout
Zend_Registry
Zend_Server
Zend_Service_ReCaptcha
Zend_Text
Zend_Validate
Zend_Wildfire
Forte Zend_Exception
Zend_Cache
Faible Zend_Log

1629
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Captcha
Zend_Config
Zend_Controller
Zend_Date
Zend_Db
Zend_Dojo
Zend_Filter
Zend_Form
Zend_Http
Zend_Json
Zend_Layout
Sub
Zend_Loader
Zend_Locale
Zend_Registry
Zend_Server
Zend_Service_ReCaptcha
Zend_Session
Zend_Text
Zend_Uri
Zend_Validate
Zend_View
Zend_Wildfire
Zend_Exception
Zend_Service_ReCaptcha
Forte
Zend_Text
Zend_Validate
Zend_Http
Zend_Json
Zend_Captcha Zend_Loader
Fix
Zend_Locale
Zend_Server
Zend_Uri
Zend_Date
Sub Zend_Filter
Zend_ReLoader
Zend_Config Forte Zend_Exception
Zend_Console_Getopt Forte Zend_Exception

1630
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Faible Zend_Json
Zend_Loader
Sub
Zend_Server
Zend_Config
Zend_Exception
Zend_Loader
Forte
Zend_Registry
Zend_Uri
Zend_View
Zend_Dojo
Zend_Filter
Faible
Zend_Json
Zend_Layout
Zend_Locale
Zend_Controller Fix
Zend_Validate
Zend_Captcha
Zend_Date
Zend_Db
Zend_Form
Zend_Http
Sub
Zend_Server
Zend_Service_ReCaptcha
Zend_Session
Zend_Text
Zend_Wildfire
Zend_Exception
Forte
Zend_Locale
Zend_Currency
Zend_Loader
Sub
Zend_Registry
Zend_Exception
Forte
Zend_Locale
Zend_Date
Zend_Loader
Sub
Zend_Registry
Zend_Exception
Forte
Zend_Loader
Zend_Db
Zend_Registry
Faible
Zend_Wildfire

1631
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Captcha
Zend_Config
Zend_Controller
Zend_Date
Zend_Db
Zend_Dojo
Zend_Filter
Zend_Form
Zend_Http
Sub
Zend_Json
Zend_Layout
Zend_Server
Zend_Service_ReCaptcha
Zend_Session
Zend_Text
Zend_Uri
Zend_Validate
Zend_View
Zend_Debug --- ---
Zend_Exception
Zend_Form
Forte Zend_Json
Zend_Registry
Zend_View
Faible Zend_Filter
Zend_Config
Zend_Loader
Fix Zend_Locale
Zend_Dojo
Zend_Uri
Zend_Validate
Zend_Captcha
Zend_Controller
Zend_Date
Sub Zend_Db
Zend_Dojo
Zend_Http
Zend_Layout

1632
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Server
Zend_Service_ReCaptcha
Zend_Session
Zend_Text
Zend_Wildfire
Zend_Dom Forte Zend_Exception
Zend_Exception --- ---
Zend_Exception
Forte Zend_Loader
Zend_Uri
Zend_Locale
Fix
Zend_Feed Zend_Validate
Zend_Date
Zend_Filter
Sub
Zend_Http
Zend_Registry
Forte Zend_Exception
Zend_File_Transfer
Faible Zend_Loader
Zend_Exception
Forte Zend_Loader
Zend_Validate
Zend_Filter
Faible Zend_Locale
Zend_Date
Sub
Zend_Registry
Zend_Exception
Forte Zend_Filter
Zend_Validate
Zend_Captcha
Zend_Controller
Zend_Json
Faible
Zend_Form Zend_Loader
Zend_Registry
Zend_Session
Zend_Config
Zend_Http
Fix
Zend_Locale
Zend_Server

1633
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Service_ReCaptcha
Zend_Text
Zend_Uri
Zend_View
Zend_Date
Zend_Db
Zend_Dojo
Sub
Zend_Form
Zend_Layout
Zend_Wildfire
Zend_Exception
Zend_Http
Forte
Zend_Mime
Zend_Version
Faible Zend_Loader
Zend_Gdata Zend_Locale
Fix Zend_Uri
Zend_Validate
Zend_Date
Sub Zend_Filter
Zend_Registry
Zend_Exception
Forte Zend_Loader
Zend_Uri
Zend_Locale
Zend_Http Fix
Zend_Validate
Zend_Date
Sub Zend_Filter
Zend_Registry
Zend_Exception
Zend_InfoCard Forte
Zend_Loader
Zend_Exception
Zend_Json Forte Zend_Loader
Zend_Server
Forte Zend_Exception
Zend_Layout Zend_Controller
Faible
Zend_Filter

1634
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Loader
Zend_View
Zend_Config
Zend_Layout
Fix Zend_Registry
Zend_Uri
Zend_Validate
Zend_Captcha
Zend_Date
Zend_Db
Zend_Dojo
Zend_Form
Zend_Http
Sub Zend_Json
Zend_Locale
Zend_Server
Zend_Service_ReCaptcha
Zend_Session
Zend_Text
Zend_Wildfire
Zend_Ldap Forte Zend_Exception
Zend_Loader Forte Zend_Exception
Forte Zend_Exception
Zend_Locale Faible Zend_Registry
Sub Zend_Loader
Forte Zend_Exception
Faible Zend_Wildfire
Zend_Captcha
Zend_Config
Zend_Controller
Zend_Date
Zend_Log
Zend_Db
Sub
Zend_Dojo
Zend_Filter
Zend_Form
Zend_Http
Zend_Json

1635
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Layout
Zend_Loader
Zend_Registry
Zend_Server
Zend_Service_ReCaptcha
Zend_Session
Zend_Text
Zend_Uri
Zend_Validate
Zend_View
Zend_Exception
Zend_Loader
Forte
Zend_Mime
Zend_Validate
Zend_Mail
Fix Zend_Locale
Zend_Date
Sub Zend_Filter
Zend_Registry
Zend_Exception
Forte Zend_Locale
Zend_Measure
Zend_Registry
Sub Zend_Loader
Zend_Cache
Forte
Zend_Exception
Zend_Captcha
Zend_Config
Zend_Controller
Zend_Date
Zend_Db
Zend_Memory Zend_Dojo
Sub Zend_Filter
Zend_Form
Zend_Http
Zend_Json
Zend_Layout
Zend_Loader
Zend_Locale

1636
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Log
Zend_Registry
Zend_Server
Zend_Service_ReCaptcha
Zend_Session
Zend_Text
Zend_Uri
Zend_Validate
Zend_View
Zend_Wildfire
Zend_Mime Forte Zend_Exception
Zend_Controller
Zend_Exception
Forte
Zend_Http
Zend_Session
Zend_Config
Zend_Dojo
Zend_Loader
Zend_Locale
Fix
Zend_Registry
Zend_Uri
Zend_Validate
Zend_OpenId Zend_View
Zend_Captcha
Zend_Date
Zend_Db
Zend_Filter
Zend_Form
Sub Zend_Json
Zend_Layout
Zend_Server
Zend_Service_ReCaptcha
Zend_Text
Zend_Wildfire
Zend_Exception
Zend_Paginator Forte Zend_Json
Zend_Loader

1637
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Controller
Faible Zend_Db
Zend_View
Fix Zend_Server
Zend_Captcha
Zend_Config
Zend_Date
Zend_Dojo
Zend_Filter
Zend_Form
Zend_Http
Zend_Layout
Sub
Zend_Locale
Zend_Registry
Zend_Service_ReCaptcha
Zend_Session
Zend_Text
Zend_Uri
Zend_Validate
Zend_Wildfire
Zend_Exception
Forte Zend_Log
Zend_Memory
Fix Zend_Cache
Zend_Captcha
Zend_Config
Zend_Controller
Zend_Date
Zend_Pdf Zend_Db
Zend_Dojo
Sub Zend_Filter
Zend_Form
Zend_Http
Zend_Json
Zend_Layout
Zend_Loader
Zend_Locale

1638
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Registry
Zend_Server
Zend_Service_ReCaptcha
Zend_Session
Zend_Text
Zend_Uri
Zend_Validate
Zend_View
Zend_Wildfire
Zend_Config
Forte Zend_Exception
Zend_Json
Faible Zend_Session
Zend_Db
Fix Zend_Loader
Zend_Server
Zend_Captcha
Zend_Date
Zend_Dojo
Zend_Progressbar Zend_Filter
Zend_Form
Zend_Http
Zend_Layout
Sub
Zend_Registry
Zend_Service_ReCaptcha
Zend_Text
Zend_Uri
Zend_Validate
Zend_View
Zend_Wildfire
Forte Zend_Exception
Zend_Registry
Faible Zend_Loader
Zend_Request --- ---
Zend_Exception
Zend_Server
Zend_Rest Forte
Zend_Service
Zend_Uri

1639
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Http
Zend_Loader
Fix
Zend_Locale
Zend_Validate
Zend_Date
Sub Zend_Filter
Zend_Registry
Zend_Search_Lucene Forte Zend_Exception
Zend_Exception
Forte
Zend_Loader
Zend_Serializer
Zend_Json
Faible
Zend_Amf
Zend_Server Forte Zend_Exception
Zend_Exception
Zend_Http
Forte
Zend_Uri
Zend_Version
Zend_Loader
Zend_Service_Akismet
Fix Zend_Locale
Zend_Validate
Zend_Date
Sub Zend_Filter
Zend_Registry
Zend_Exception
Forte Zend_Http
Zend_Rest
Zend_Loader
Zend_Locale
Zend_Server
Zend_Service_Amazon Fix
Zend_Service
Zend_Uri
Zend_Validate
Zend_Date
Sub Zend_Filter
Zend_Registry
Zend_Exception
Forte
Zend_Service_Audioscrobbler
Zend_Http

1640
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Loader
Zend_Locale
Fix
Zend_Uri
Zend_Validate
Zend_Date
Sub Zend_Filter
Zend_Registry
Zend_Date
Zend_Exception
Forte Zend_Http
Zend_Json
Zend_Rest
Zend_Loader
Zend_Service_Delicious Zend_Locale
Zend_Server
Fix
Zend_Service
Zend_Uri
Zend_Validate
Zend_Filter
Sub
Zend_Registry
Zend_Exception
Forte
Zend_Http
Zend_Rest
Faible
Zend_Validate
Zend_Loader
Zend_Locale
Zend_Service_Flickr
Fix Zend_Server
Zend_Service
Zend_Uri
Zend_Date
Sub Zend_Filter
Zend_Registry
Zend_Exception
Forte Zend_Http
Zend_Service_Nirvanix Zend_Loader
Zend_Locale
Fix
Zend_Uri

1641
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Validate
Zend_Date
Sub Zend_Filter
Zend_Registry
Zend_Exception
Forte Zend_Http
Zend_Json
Zend_Loader
Zend_Locale
Zend_Service_ReCaptcha Fix Zend_Server
Zend_Uri
Zend_Validate
Zend_Date
Sub Zend_Filter
Zend_Registry
Zend_Exception
Forte Zend_Http
Zend_Rest
Zend_Loader
Zend_Locale
Zend_Server
Zend_Service_Simpy Fix
Zend_Service
Zend_Uri
Zend_Validate
Zend_Date
Sub Zend_Filter
Zend_Registry
Zend_Cache
Forte Zend_Exception
Zend_Http
Zend_Loader
Zend_Locale
Zend_Service_SlideShare Fix
Zend_Uri
Zend_Validate
Zend_Captcha
Sub Zend_Config
Zend_Controller

1642
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Date
Zend_Db
Zend_Dojo
Zend_Filter
Zend_Form
Zend_Json
Zend_Layout
Zend_Log
Zend_Registry
Zend_Server
Zend_Service_ReCaptcha
Zend_Session
Zend_Text
Zend_View
Zend_Wildfire
Zend_Exception
Forte Zend_Http
Zend_Loader
Zend_Locale
Zend_Service_StrikeIron Fix Zend_Uri
Zend_Validate
Zend_Date
Fix Zend_Filter
Zend_Registry
Zend_Date
Zend_Exception
Forte Zend_Http
Zend_Uri
Zend_Locale
Faible Zend_Rest
Zend_Service_Technorati
Zend_Loader
Zend_Server
Fix
Zend_Service
Zend_Validate
Zend_Filter
Sub
Zend_Registry
Zend_Service_Twitter Forte Zend_Exception

1643
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Feed
Zend_Http
Zend_Json
Zend_Rest
Zend_Uri
Zend_Loader
Zend_Locale
Fix Zend_Server
Zend_Service
Zend_Validate
Zend_Date
Fix Zend_Filter
Zend_Registry
Zend_Exception
Forte Zend_Http
Zend_Rest
Faible Zend_Validate
Zend_Loader
Zend_Locale
Zend_Service_Yahoo
Fix Zend_Server
Zend_Service
Zend_Uri
Zend_Date
Sub Zend_Filter
Zend_Registry
Forte Zend_Exception
Zend_Config
Faible Zend_Db
Zend_Loader
Zend_Captcha
Zend_Date
Zend_Session
Zend_Dojo
Zend_Filter
Sub
Zend_Form
Zend_Http
Zend_Json
Zend_Layout

1644
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Registry
Zend_Server
Zend_Service_ReCaptcha
Zend_Session
Zend_Text
Zend_Uri
Zend_Validate
Zend_View
Zend_Wildfire
Zend_Exception
Forte Zend_Server
Zend_Uri
Zend_Loader
Zend_Soap Fix Zend_Locale
Zend_Validate
Zend_Date
Sub Zend_Filter
Zend_Registry
Zend_Controller
Zend_Dom
Zend_Exception
Forte
Zend_Layout
Zend_Registry
Zend_Session
Faible Zend_Loader
Zend_Config
Zend_Locale
Zend_Test Fix Zend_Uri
Zend_Validate
Zend_View
Zend_Captcha
Zend_Date
Zend_Db
Sub Zend_Dojo
Zend_Filter
Zend_Form
Zend_Http

1645
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Json
Zend_Server
Zend_Service_ReCaptcha
Zend_Text
Zend_Wildfire
Forte Zend_Exception
Zend_Text
Faible Zend_Loader
Zend_Date
Forte Zend_Exception
Zend_TimeSync Zend_Loader
Fix Zend_Locale
Sub Zend_Registry
Zend_Exception
Forte Zend_Loader
Zend_Translate
Zend_Locale
Sub Zend_Registry
Zend_Exception
Zend_Loader
Forte
Zend_Locale
Zend_Uri Zend_Validate
Zend_Date
Faible Zend_Filter
Zend_Registry
Zend_Exception
Forte Zend_Loader
Zend_Locale
Zend_Validate
Zend_Date
Faible Zend_Filter
Zend_Registry
Zend_Version --- ---
Zend_Controller
Zend_Exception
Forte Zend_Loader
Zend_View Zend_Locale
Zend_Registry
Zend_Json
Faible
Zend_Layout

1646
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Config
Fix Zend_Uri
Zend_Validate
Zend_Captcha
Zend_Date
Zend_Db
Zend_Dojo
Zend_Filter
Zend_Form
Sub
Zend_Http
Zend_Server
Zend_Service_ReCaptcha
Zend_Session
Zend_Text
Zend_Wildfire
Zend_Controller
Zend_Exception
Forte
Zend_Json
Zend_Loader
Zend_Config
Zend_Layout
Zend_Registry
Fix Zend_Server
Zend_Uri
Zend_Validate
Zend_View
Zend_Wildfire
Zend_Captcha
Zend_Date
Zend_Db
Zend_Dojo
Zend_Filter
Sub Zend_Form
Zend_Http
Zend_Layout
Zend_Service_ReCaptcha
Zend_Session
Zend_Text

1647
Configuration système
requise par Zend Framework

Composant de Type de Dépend du composant de Zend Framework


Zend Framework dépendance
Zend_Exception
Forte Zend_Http
Zend_Server
Zend_Loader
Zend_Uri
Zend_XmlRpc Fix
Zend_Validate
Zend_Locale
Zend_Date
Sub Zend_Filter
Zend_Registry

1648
Annexe B. Notes de migration de Zend
Framework

Table des matières


B.1. Zend Framework 1.10 ......................................................................................... 1649
B.1.1. Zend_Feed_Reader .................................................................................. 1650
B.1.2. Zend_File_Transfer ................................................................................... 1650
B.1.3. Zend_Filter_HtmlEntities ........................................................................... 1651
B.1.4. Zend_Filter_StripTags ............................................................................... 1651
B.1.5. Zend_Translate ........................................................................................ 1651
B.1.6. Zend_Validate .......................................................................................... 1652
B.2. Zend Framework 1.9 ........................................................................................... 1653
B.2.1. Zend_File_Transfer ................................................................................... 1653
B.2.2. Zend_Filter ............................................................................................... 1653
B.2.3. Zend_Http_Client ...................................................................................... 1653
B.2.4. Zend_Locale ............................................................................................ 1654
B.2.5. Zend_View_Helper_Navigation .................................................................. 1655
B.2.6. Security fixes as with 1.9.7 ....................................................................... 1656
B.3. Zend Framework 1.8 ........................................................................................... 1657
B.3.1. Zend_Controller ........................................................................................ 1657
B.3.2. Zend_Locale ............................................................................................ 1657
B.4. Zend Framework 1.7 ........................................................................................... 1657
B.4.1. Zend_Controller ........................................................................................ 1657
B.4.2. Zend_File_Transfer ................................................................................... 1657
B.4.3. Zend_Locale ............................................................................................ 1661
B.4.4. Zend_Translate ........................................................................................ 1663
B.4.5. Zend_View ............................................................................................... 1664
B.5. Zend Framework 1.6 ........................................................................................... 1664
B.5.1. Zend_Controller ........................................................................................ 1665
B.5.2. Zend_File_Transfer ................................................................................... 1665
B.6. Zend Framework 1.5 ........................................................................................... 1665
B.6.1. Zend_Controller ........................................................................................ 1665
B.7. Zend Framework 1.0 ........................................................................................... 1667
B.7.1. Zend_Controller ........................................................................................ 1667
B.7.2. Zend_Currency ......................................................................................... 1669
B.8. Zend Framework 0.9 ........................................................................................... 1669
B.8.1. Zend_Controller ........................................................................................ 1669
B.9. Zend Framework 0.8 ........................................................................................... 1670
B.9.1. Zend_Controller ........................................................................................ 1670
B.10. Zend Framework 0.6 ......................................................................................... 1671
B.10.1. Zend_Controller ...................................................................................... 1671

B.1. Zend Framework 1.10


Lors de la migration d'un version précédente vers Zend Framework 1.10 ou plus récent vous
devriez prendre note de ce qui suit.

1649
Notes de migration
de Zend Framework

B.1.1. Zend_Feed_Reader
With the introduction of Zend Framework 1.10, Zend_Feed_Reader's handling of retrieving
Authors and Contributors was changed, introducing a break in backwards compatibility. This
change was an effort to harmonise the treatment of such data across the RSS and Atom classes
of the component and enable the return of Author and Contributor data in more accessible, usable
and detailed form. It also rectifies an error in that it was assumed any author element referred to
a name. In RSS this is incorrect as an author element is actually only required to provide an email
address. In addition, the original implementation applied its RSS limits to Atom feeds significantly
reducing the usefulness of the parser with that format.

The change means that methods like getAuthors() and getContributors no longer return
a simple array of strings parsed from the relevant RSS and Atom elements. Instead, the return
value is an ArrayObject subclass called Zend_Feed_Reader_Collection_Author which
simulates an iterable multidimensional array of Authors. Each member of this object will be a
simple array with three potential keys (as the source data permits). These include: name, email
and uri.

The original behaviour of such methods would have returned a simple array of strings, each
string attempting to present a single name, but in reality this was unreliable since there is no rule
governing the format of RSS Author strings.

The simplest method of simulating the original behaviour of these methods is to use the
Zend_Feed_Reader_Collection_Author's getValues() which also returns a simple
array of strings representing the "most relevant data", for authors presumed to be their name.
Each value in the resulting array is derived from the "name" value attached to each Author (if
present). In most cases this simple change is easy to apply as demonstrated below.

/**
* Before 1.10
*/

$feed = Zend_Feed_Reader::import('http://example.com/feed');
$authors = $feed->getAuthors();

/**
* With 1.10
*/
$feed = Zend_Feed_Reader::import('http://example.com/feed');
$authors = $feed->getAuthors()->getValues();

B.1.2. Zend_File_Transfer
B.1.2.1. Security change
For security reasons Zend_File_Transfer does no longer store the original mimetype and
filesize which is given from the requesting client into its internal storage. Instead the real values
will be detected at initiation.

Additionally the original values within $_FILES will be overridden within the real values at
initiation. This makes also $_FILES secure.

When you are in need of the original values you can eighter store them before initiating
Zend_File_Transfer or use the disableInfos option at initiation. Note that this option is
useless when its given after initiation.

1650
Notes de migration
de Zend Framework

B.1.2.2. Count validation


Before release 1.10 the MimeType validator used a wrong naming. For consistency the following
constants have been changed:

Tableau B.1. Changed Validation Messages

Old New Value


TOO_MUCH TOO_MANY Too many files,
maximum '%max%'
are allowed but
'%count%' are given
TOO_LESS TOO_FEW Too few files, minimum
'%min%' are expected
but '%count%' are
given

When you are translating these messages within your code then use the new constants. As
benefit you don't need to translate the original string anymore to get a correct spelling.

B.1.3. Zend_Filter_HtmlEntities
In order to default to a more secure character encoding, Zend_Filter_HtmlEntities now
defaults to UTF-8 instead of ISO-8859-1.

Additionally, because the actual mechanism is dealing with character encodings and not
character sets, two new methods have been added, setEncoding() and getEncoding().
The previous methods setCharSet() and setCharSet() are now deprecated and proxy to
the new methods. Finally, instead of using the protected members directly within the filter()
method, these members are retrieved by their explicit accessors. If you were extending the filter
in the past, please check your code and unit tests to ensure everything still continues to work.

B.1.4. Zend_Filter_StripTags
Zend_Filter_StripTags contains a flag, commentsAllowed, that, in previous versions,
allowed you to optionally whitelist HTML comments in HTML text filtered by the class. However,
this opens code enabling the flag to XSS attacks, particularly in Internet Explorer (which
allows specifying conditional functionality via HTML comments). Starting in version 1.9.7 (and
backported to versions 1.8.5 and 1.7.9), the commentsAllowed flag no longer has any meaning,
and all HTML comments, including those containing other HTML tags or nested commments,
will be stripped from the final output of the filter.

B.1.5. Zend_Translate
B.1.5.1. Xliff adapter
In past the Xliff adapter used the source string as message Id. According to the Xliff standard
the trans-unit Id should be used. This behaviour was corrected with Zend Framework 1.10. Now
the trans-unit Id is used as message Id per default.

But you can still get the incorrect and old behaviour by setting the useId option to FALSE.

$trans = new Zend_Translate('xliff', '/path/to/source', $locale, array('useId' => false));

1651
Notes de migration
de Zend Framework

B.1.6. Zend_Validate
B.1.6.1. Adaptateurs personnels
Lorsqu'une erreur apparait dans un adaptateur crée de toute pièce, _error() doit être appelée.
Avant Zend Framework 1.10, il était possible d'appeler cette méthode sans aucun paramètre.
Le premier template de message d'erreur était alors utilisé.

Ce comportement est problématique lorsque vous avez des validateurs retournant plusieurs
messages. Aussi, étendre un validateur peut mener à des comportements inattendus dans une
telle situation, comme par exemple l'apparition du mauvais message d'erreur.

My_Validator extends Zend_Validate_Abstract


{
public isValid($value)
{
...
$this->_error(); // Résultat inattendu
...
}
}

Pour éviter ces problèmes _error() doit desormais prendre obligatoirement un paramètre.

My_Validator extends Zend_Validate_Abstract


{
public isValid($value)
{
...
$this->_error(self::MY_ERROR); // Ok, erreur définie
...
}
}

B.1.6.2. Simplification dans le validateur des dates


Avant Zend Framework 1.10, 2 messages identiques étaient envoyés dans le validateur des
dates. NOT_YYYY_MM_DD et FALSEFORMAT. Depuis Zend Framework 1.10, seul FALSEFORMAT
sera retourné lorsque la date passée ne correspond pas au format demandé.

B.1.6.3. Corrections dans Alpha, Alnum et Barcode


Avant Zend Framework 1.10, les messages dans les 2 validateurs barcode, le Alpha et le
Alnum étaient identiques. Des problèmes pouvaient alors faire surface avec des messages
personnalisés, des traducteurs ou des instances multiples des validateurs.

Depuis Zend Framework 1.10, les valeurs des constantes ont changé pour être uniques. Si vous
utilisiez les constantes comme le manuel le recommande, aucun changement n'est nécessaire.
Mais si vous utilisiez les messages d'erreurs, alors il faudra les changer. Voici les changements
opérés:

Tableau B.2. Messages de validation disponibles


Validateur Constante Valeur
Alnum STRING_EMPTY alnumStringEmpty
Alpha STRING_EMPTY alphaStringEmpty

1652
Notes de migration
de Zend Framework

Validateur Constante Valeur


Barcode_Ean13 INVALID ean13Invalid
Barcode_Ean13 INVALID_LENGTH ean13InvalidLength
Barcode_UpcA INVALID upcaInvalid
Barcode_UpcA INVALID_LENGTH upcaInvalidLength
Digits STRING_EMPTY digitsStringEmpty

B.2. Zend Framework 1.9


Lors de la migration d'une version précédente à Zend Framework 1.9.0 vers une version 1.9,
vous devriez prendre note de ce qui suit.

B.2.1. Zend_File_Transfer
B.2.1.1. MimeType validation
For security reasons we had to turn off the default fallback mechanism of the MimeType,
ExcludeMimeType, IsCompressed and IsImage validators. This means, that if the fileInfo
or magicMime extensions can not be found, the validation will always fail.

If you are in need of validation by using the HTTP fields which are provided by the user then you
can turn on this feature by using the enableHeaderCheck() method.

Security hint
You should note that relying on the HTTP fields, which are provided by your user,
is a security risk. They can easily be changed and could allow your user to provide
a malcious file.

Exemple B.1. Allow the usage of the HTTP fields

// at initiation
$valid = new Zend_File_Transfer_Adapter_Http(array('headerCheck' => true);

// or afterwards
$valid->enableHeaderCheck();

B.2.2. Zend_Filter
Avant la version 1.9, Zend_Filter permettait l'utilisation de la méthode statique get(). Avec
la version 1.9 cette méthode a été renommée en filterStatic() afin d'être plus descriptive.
L'ancienne méthode get() est marquée comme dépréciée.

B.2.3. Zend_Http_Client
B.2.3.1. Changement dans le stockage interne des fichiers d'upload
Dans la version 1.9 de Zend Framework, il y a eu un changement dans la manière dont
Zend_Http_Client stocke en interne les informations concernant les fichiers ayant été
uploadés, affectés grâce à Zend_Http_Client::setFileUpload()

Ce changement a été mis en place de manière à permettre l'envoi de plusieurs fichiers avec le
même nom dans le formulaire, en tant que tableau de fichiers. Plus d'informations à ce sujet
peuvent être trouvées dans ce rapport de bug.

1653
Notes de migration
de Zend Framework

Exemple B.2. Stockage interne des informations sur les fichiers uploadés

// Uploade 2 fichiers avec le même nom d'élément de formulaire, en tant que tableau
$client = new Zend_Http_Client();
$client->setFileUpload('file1.txt', 'userfile[]', 'some raw data', 'text/plain');
$client->setFileUpload('file2.txt', 'userfile[]', 'some other data', 'application/octet-

// Dans Zend Framework <=1.8, la valeur de l'attribut protégé $client->files est:


// $client->files = array(
// 'userfile[]' => array('file2.txt', 'application/octet-stream', 'some other data')
// );

// Dans Zend Framework >=1.9, la valeur de $client->files est:


// $client->files = array(
// array(
// 'formname' => 'userfile[]',
// 'filename' => 'file1.txt,
// 'ctype' => 'text/plain',
// 'data' => 'some raw data'
// ),
// array(
// 'formname' => 'userfile[]',
// 'filename' => 'file2.txt',
// 'formname' => 'application/octet-stream',
// 'formname' => 'some other data'
// )
// );

Comme vous le voyez, ce changement permet l'utilisation du même élément de formulaire avec
plusieurs fichiers. Cependant ceci introduit un changement subtile dans l'API interne, il est donc
signalé ici.

B.2.3.2. Deprecation of Zend_Http_Client::_getParametersRecursive()


Starting from version 1.9, the protected method _getParametersRecursive() is no longer
used by Zend_Http_Client and is deprecated. Using it will cause an E_NOTICE message
to be emitted by PHP.

If you subclass Zend_Http_Client and call this method, you should look into using the
Zend_Http_Client::_flattenParametersArray() static method instead.

Again, since this _getParametersRecursive is a protected method, this change will only
affect users who subclass Zend_Http_Client.

B.2.4. Zend_Locale
B.2.4.1. Méthodes dépréciées
Quelques méthodes de traductions spéciales ont été dépréciées car elles dupliquaient un
comportement existant. Notez cependant que les anciens appels vont toujours fonctionner, mais
une notice utilisateur, qui décrira le nouvel appel, sera émise. Ces méthodes seront effacées en
2.0. Ci-dessous la liste des anciens et nouveaux appels :

Tableau B.3. Liste des types de mesures


Ancien appel Nouvel appel
getLanguageTranslationList($locale) getTranslationList('language', $locale)

1654
Notes de migration
de Zend Framework

Ancien appel Nouvel appel


getScriptTranslationList($locale) getTranslationList('script', $locale)
getCountryTranslationList($locale) getTranslationList('territory', $locale, 2)
getTerritoryTranslationList($locale) getTranslationList('territory', $locale, 1)
getLanguageTranslation($value, $locale) getTranslation($value, 'language', $locale)
getScriptTranslation($value, $locale) getTranslation($value, 'script', $locale)
getCountryTranslation($value, $locale) getTranslation($value, 'country', $locale)
getTerritoryTranslation($value, $locale) getTranslation($value, 'territory', $locale)

B.2.5. Zend_View_Helper_Navigation
Prior to the 1.9 release, the menu helper (Zend_View_Helper_Navigation_Menu) did
not render sub menus correctly. When the onlyActiveBranch was TRUE and the option
renderParents FALSE, nothing would be rendered if the deepest active page was at a depth
lower than the minDepth option.

In simpler words; if minDepth was set to 1 and the active page was at one of the first level
pages, nothing would be rendered, as the following example shows.

Consider the following container setup:

$container = new Zend_Navigation(array(


array(
'label' => 'Home',
'uri' => '#'
),
array(
'label' => 'Products',
'uri' => '#',
'active' => true,
'pages' => array(
array(
'label' => 'Server',
'uri' => '#'
),
array(
'label' => 'Studio',
'uri' => '#'
)
)
),
array(
'label' => 'Solutions',
'uri' => '#'
)
));

The following code is used in a view script:

echo $this->navigation()->menu()->renderMenu($container, array(


'minDepth' => 1,
'onlyActiveBranch' => true,
'renderParents' => false
));

1655
Notes de migration
de Zend Framework

Before release 1.9, the code snippet above would output nothing.

Since release 1.9, the _renderDeepestMenu() method in


Zend_View_Helper_Navigation_Menu will accept active pages at one level below
minDepth, as long as the page has children.

The same code snippet will now output the following:

<ul class="navigation">
<li>
<a href="#">Server</a>
</li>
<li>
<a href="#">Studio</a>
</li>
</ul>

B.2.6. Security fixes as with 1.9.7


Additionally, users of the 1.9 series may be affected by other changes starting in version 1.9.7.
These are all security fixes that also have potential backwards compatibility implications.

B.2.6.1. Zend_Dojo_View_Helper_Editor
A slight change was made in the 1.9 series to modify the default usage of the Editor dijit to use
div tags instead of a textarea tag; the latter usage has security implications, and usage of div
tags is recommended by the Dojo project.

In order to still allow graceful degradation, a new degrade option was added to the view helper;
this would allow developers to optionally use a textarea instead. However, this opens applications
developed with that usage to XSS vectors. In 1.9.7, we have removed this option. Graceful
degradation is still supported, however, via a noscript tag that embeds a textarea. This solution
addressess all security concerns.

The takeaway is that if you were using the degrade flag, it will simply be ignored at this time.

B.2.6.2. Zend_Filter_HtmlEntities
In order to default to a more secure character encoding, Zend_Filter_HtmlEntities now
defaults to UTF-8 instead of ISO-8859-1.

Additionally, because the actual mechanism is dealing with character encodings and not
character sets, two new methods have been added, setEncoding() and getEncoding().
The previous methods setCharSet() and setCharSet() are now deprecated and proxy to
the new methods. Finally, instead of using the protected members directly within the filter()
method, these members are retrieved by their explicit accessors. If you were extending the filter
in the past, please check your code and unit tests to ensure everything still continues to work.

B.2.6.3. Zend_Filter_StripTags
Zend_Filter_StripTags contains a flag, commentsAllowed, that, in previous versions,
allowed you to optionally whitelist HTML comments in HTML text filtered by the class. However,
this opens code enabling the flag to XSS attacks, particularly in Internet Explorer (which
allows specifying conditional functionality via HTML comments). Starting in version 1.9.7 (and
backported to versions 1.8.5 and 1.7.9), the commentsAllowed flag no longer has any meaning,
and all HTML comments, including those containing other HTML tags or nested commments,
will be stripped from the final output of the filter.

1656
Notes de migration
de Zend Framework

B.3. Zend Framework 1.8


Lors de la migration d'un version précédente vers Zend Framework 1.8 ou plus récent vous
devriez prendre note de ce qui suit.

B.3.1. Zend_Controller
B.3.1.1. Changement de la route standard
Comme les segments traduits ont été ajoutés dans la nouvelle route standard, le caractère @ est
maintenant un caractère spécial au début d'un segment de route. Pour être capable de l'utiliser
dans un segment statique, vous devez l'échapper en le préfixant avec un second @. La même
règle s'applique aussi au caractère :.

B.3.2. Zend_Locale
B.3.2.1. Default caching
As with Zend Framework 1.8 a default caching was added. The reason behind this change was,
that most users had performance problems but did not add caching at all. As the I18n core is
a bottleneck when no caching is used we decided to add a default caching when no cache has
been set to Zend_Locale.

Sometimes it is still wanted to prevent caching at all even if this decreases performance. To do
so you can simply disable caching by using the disableCache() method.

Exemple B.3. Disabling default caching

Zend_Locale::disableCache(true);

B.4. Zend Framework 1.7


Lors de la migration d'un version précédente vers Zend Framework 1.7 ou plus récent vous
devriez prendre note de ce qui suit.

B.4.1. Zend_Controller
B.4.1.1. Changement dans l'interface Dispatcher
Les utilisateurs ont portés l'attention sur le fait que
Zend_Controller_Action_Helper_ViewRenderer utilisait une méthode de la classe
abstraite du distributeur standard qui n'était pas présente dans l'interface Dispatcher.La méthode
suivante a donc été ajoutée pour s'assurer que les distributeurs personnalisés continueront à
fonctionner avec les implémentations embarquées :

• formatModuleName() : devrait être utilisé pour prendre un nom de contrôleur brut, comme
un qui aurait été embarqué dans un objet requête, et pour le formater en un nom de classe
approprié qu'une classe étendant Zend_Controller_Action pourra utiliser.

B.4.2. Zend_File_Transfer
B.4.2.1. Changements quand vous utilisez des filtres ou des validateurs
Certaines remarques des utilisateurs indiquaient que les validateurs de Zend_File_Transfer
ne fonctionnaient pas correctement avec Zend_Config dû au fait qu'ils n'utilisait pas de
tableaux nommés.

1657
Notes de migration
de Zend Framework

De plus, tous les filtres et validateurs de Zend_File_Transfer ont été réécrits. Même si les
anciennes signatures continuent à fonctionner, elles ont été marqués comme dépréciées et
émettent une notice PHP vous informant de faire le changement.

La liste suivante vous montre les changements à réaliser pour une utilisation appropriée des
paramètres.

B.4.2.1.1. Filtre Rename

• Ancienne API : Zend_Filter_File_Rename($oldfile, $newfile, $overwrite)

• Nouvelle API : Zend_Filter_File_Rename($options) où $options accepte un tableau


avec les clés suivantes : source est équivalent à $oldfile, target est équivalent à $newfile,
overwrite est équivalent à $overwrite.

Exemple B.4. Changer le filtre rename entre 1.6 et 1.7

// Exemple pour 1.6


$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addFilter('Rename',
array('/path/to/oldfile', '/path/to/newfile', true));

// Même exemple pour 1.7


$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addFilter('Rename',
array('source' => '/path/to/oldfile',
'target' => '/path/to/newfile',
'overwrite' => true));

B.4.2.1.2. Validateur Count

• Ancienne API : Zend_Validate_File_Count($min, $max)

• Nouvelle API : Zend_Validate_File_Count($options) où $options accepte un


tableau avec les clés suivantes : min est équivalent à $min, max est équivalent à $max.

Exemple B.5. Changer le validateur count entre 1.6 et 1.7

// Exemple pour 1.6


$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addValidator('Count',
array(2, 3));

// Même exemple pour 1.7


$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addValidator('Count',
false,
array('min' => 2,
'max' => 3));

B.4.2.1.3. Validateur Extension

• Ancienne API : Zend_Validate_File_Extension($extension, $case)

• Nouvelle API : Zend_Validate_File_Extension($options) où $options accepte un


tableau avec les clés suivantes : * est équivalent à $extension et peut avoir tout autre clé,
case est équivalent à $case.

1658
Notes de migration
de Zend Framework

Exemple B.6. Changer le validateur extension entre 1.6 et 1.7

// Exemple pour 1.6


$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addValidator('Extension',
array('jpg,gif,bmp', true));

// Même exemple pour 1.7


$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addValidator('Extension',
false,
array('extension1' => 'jpg,gif,bmp',
'case' => true));

B.4.2.1.4. Validateur FilesSize

• Ancienne API : Zend_Validate_File_FilesSize($min, $max, $bytestring)

• Nouvelle API : Zend_Validate_File_FilesSize($options) où $options accepte un


tableau avec les clés suivantes : min est équivalent à $min, max est équivalent à $max,
bytestring est équivalent à $bytestring.

De plus la signature de la méthode useByteString() a changé. Elle peut être seulement


utilisée pour tester si le validateur prévoie d'utiliser les chaînes lisibles ou la valeur brute
dans les messages générées. Pour paramétrer la valeur de cette option, utilisez la méthode
setUseByteString().

Exemple B.7. Changer le validateur filessize entre 1.6 et 1.7

// Exemple pour 1.6


$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addValidator('FilesSize',
array(100, 10000, true));

// Même exemple pour 1.7


$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addValidator('FilesSize',
false,
array('min' => 100,
'max' => 10000,
'bytestring' => true));

// Exemple pour 1.6


$upload->useByteString(true); // set flag

// Même exemple pour 1.7


$upload->setUseByteSting(true); // set flag

B.4.2.1.5. Validateur Hash

• Ancienne API : Zend_Validate_File_Hash($hash, $algorithm)

• Nouvelle API : Zend_Validate_File_Hash($options) où $options accepte un tableau


avec les clés suivantes : * est équivalent à $hash et peut avoir tout autre clé, algorithm est
équivalent à $algorithm.

1659
Notes de migration
de Zend Framework

Exemple B.8. Changer le validateur hash entre 1.6 et 1.7

// Exemple pour 1.6


$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addValidator('Hash',
array('12345', 'md5'));

// Même exemple pour 1.7


$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addValidator('Hash',
false,
array('hash1' => '12345',
'algorithm' => 'md5'));

B.4.2.1.6. Validateur ImageSize

• Ancienne API : Zend_Validate_File_ImageSize($minwidth, $minheight,


$maxwidth, $maxheight)

• Nouvelle API : Zend_Validate_File_FilesSize($options) où $options accepte


un tableau avec les clés suivantes : minwidth est équivalent à $minwidth, maxwidth est
équivalent à $maxwidth, minheight est équivalent à $minheight, maxheight est équivalent
à $maxheight.

Exemple B.9. Changer le validateur imagesize entre 1.6 et 1.7

// Exemple pour 1.6


$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addValidator('ImageSize',
array(10, 10, 100, 100));

// Même exemple pour 1.7


$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addValidator('ImageSize',
false,
array('minwidth' => 10,
'minheight' => 10,
'maxwidth' => 100,
'maxheight' => 100));

B.4.2.1.7. Validateur Size

• Ancienne API : Zend_Validate_File_Size($min, $max, $bytestring)

• Nouvelle API : Zend_Validate_File_Size($options) où $options accepte un tableau


avec les clés suivantes : min est équivalent à $min, max est équivalent à $max, bytestring
est équivalent à $bytestring

1660
Notes de migration
de Zend Framework

Exemple B.10. Changer le validateur size entre 1.6 et 1.7

// Exemple pour 1.6


$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addValidator('Size',
array(100, 10000, true));

// Même exemple pour 1.7


$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addValidator('Size',
false,
array('min' => 100,
'max' => 10000,
'bytestring' => true));

B.4.3. Zend_Locale
B.4.3.1. Changement dans l'utilisation de isLocale()

Conformément aux standards de codage isLocale() a été changé pour retourner un booléen.
Dans les versions précédentes une chaîne était retournée lors du succès. Pour la version 1.7 un
mode de compatibilité a été ajouté qui vous permet d'utiliser l'ancien comportement (avec une
chaîne retournée), mais ceci émet un warning pour vous informer de changer vers le nouveau
comportement. Le reroutage que l'ancien comportement de isLocale() pouvait avoir à faire
n'est plus nécessaire car tous les composants de l'I18N traiteront maintenant eux-mêmes le
reroutage.

Pour migrer vos scripts vers la nouvelle API, utilisez simplement la méthode décrite ci-dessous.

1661
Notes de migration
de Zend Framework

Exemple B.11. Comment changer l'appel de isLocale() de 1.6 vers 1.7 ?

// Exemple pour ZF 1.6


if ($locale = Zend_Locale::isLocale($locale)) {
// faire qqch
}

// Même exemple pour ZF 1.7

// Vous devez changer le mode de compatibilité pour empêcher l'émission de warning


// Mais ceci peut être fait dans votre bootstrap
Zend_Locale::$compatibilityMode = false;

if (Zend_Locale::isLocale($locale)) {
}

Notez que vous pouvez utiliser le second paramètre pour voir si la locale est correcte sans
nécessiter de reroutage.

// Exemple pour ZF 1.6


if ($locale = Zend_Locale::isLocale($locale, false)) {
// do something
}

// Même exemple pour ZF 1.7

// Vous devez changer le mode de compatibilité pour empêcher l'émission de warning


// Mais ceci peut être fait dans votre bootstrap
Zend_Locale::$compatibilityMode = false;

if (Zend_Locale::isLocale($locale, false)) {
if (Zend_Locale::isLocale($locale, true)) {
// pas de locale du tout
}

// original string is no locale but can be rerouted


}

B.4.3.2. Changement dans l'utilisation de getDefault()

La signification de la méthode getDefault() a été changé étant donné que nous avons intégré
une locale de framework qui peut être paramétrée avec setDefault(). Ceci ne renvoie plus
la chaîne de la locale mais seulement la locale du framework.

Pour migrer vos scripts vers la nouvelle API, utilisez simplement la méthode décrite ci-dessous.

1662
Notes de migration
de Zend Framework

Exemple B.12. Comment changer l'appel de getDefaut() de 1.6 vers 1.7 ?

// Exemple pour ZF 1.6


$locales = $locale->getDefault(Zend_Locale::BROWSER);

// Même exemple pour ZF 1.7

// Vous devez changer le mode de compatibilité pour empêcher l'émission de warning


// Mais ceci peut être fait dans votre bootstrap
Zend_Locale::$compatibilityMode = false;

$locale = Zend_Locale::getOrder(Zend_Locale::BROWSER);

Notez que le second paramètre de l'ancienne implémentation de getDefault() n'est plus


disponible non plus, mais les valeurs retournées sont les mêmes.

Par défaut l'ancien comportement est toujours actif, mais émet un warning.
Quand vous avez changé votre code vers le nouveau comportement, vous
devriez aussi changer le mode de compatibilité à FALSE ainsi aucun nouveau
warning ne sera émis.

B.4.4. Zend_Translate
B.4.4.1. Paramétrer les langues

Lors de l'utilisation de la détection automatique des langues, ou du réglage manuel des langues
de Zend_Translate, vous avez peut-être remarqué que de temps en temps une notice est
envoyée concernant le non-ajout de traductions vides. Dans certaines versions précédentes,
une exception était levée dans certains cas.

Ceci intervient quand un utilisateur requête une langue non existante, vous n'avez alors aucun
moyen simple de détecter ce qui ne va pas. Nous avons donc ajouté ces notices qui apparaîtront
dans votre historisation et qui vous diront qu'un utilisateur a requêté une langue que vous ne
supportez pas. Notez bien que votre code, même si une notice est déclenchée, fonctionnera
sans problèmes.

Mais quand vous utilisez votre propre gestionnaire d'erreur ou d'exception, comme xDebug,
toutes les notices vous seront retournées, même si ce n'est pas votre intention initiale. Ceci est
du au fait, que ces gestionnaires surchargent tous les réglages internes de PHP.

Pour vous affranchir de ces notices, vous pouvez simplement paramétrer la nouvelle option
disableNotices à TRUE, sa valeur par défaut étant FALSE.

1663
Notes de migration
de Zend Framework

Exemple B.13. Paramétrer les langues sans avoir de notices

Assumons que "fr" soit disponible et qu'un utilisateur requête pour "de" qui ne fait pas
partie de votre portefeuille de traductions.

$language = new Zend_Translate('gettext',


'/chemin/vers/les/traductions',
'auto');

Dans ce cas nous aurons une notice indiquant la non-disponibilité de la langue "de". Ajoutez
simplement l'option et les notices seront désactivées.

$language = new Zend_Translate('gettext',


'/chemin/vers/les/traductions',
'auto',
array('disableNotices' => true));

B.4.5. Zend_View

Les changements de l'API de Zend_View sont seulement notables pour vous si


vous mettez à jour vers les version 1.7.5 ou plus récent.

Avant la version 1.7.5, l'équipe de Zend Framework a été avertie d'une faille
potentielle d'inclusion de fichier local ("Local File Inclusion" (LFI)) dans la méthode
Zend_View::render(). Avant 1.7.5, la méthode acceptait par défaut la possibilité de spécifier
des scripts de vue comportant des indications de dossier parent (comme, "../" ou "..\"). Ceci ouvre
la possibilité à une attaque LFI si des données utilisateurs non filtrées sont passées directement
à la méthode render():

// Ici, $_GET['foobar'] = '../../../../etc/passwd'


echo $view->render($_GET['foobar']); // inclusion LFI

Zend_View émet maintenant une exception dans un tel cas.

B.4.5.1. Désactiver la protection LFI de render()


Comme des développeurs utilisaient de telles notations, mais qui n'étaient pas des données en
provenance de l'extérieur, un drapeau spécial a été crée, il permet de désactiver la protection.
Pour manipuler ce drapeau, il existe 2 moyens : le paramètre 'lfiProtectionOn' du constructeur
de votre vue, ou encore la méthode setLfiProtection().

// Désactivation de la protection par le constructeur


$view = new Zend_View(array('lfiProtectionOn' => false));

// Désactivation de la protection par la méthode dédiée


$view = new Zend_View();
$view->setLfiProtection(false);

B.5. Zend Framework 1.6


Lors de la migration d'un version précédente vers Zend Framework 1.6 ou plus récent vous
devriez prendre note de ce qui suit.

1664
Notes de migration
de Zend Framework

B.5.1. Zend_Controller
B.5.1.1. Changement dans l'interface Dispatcher
Les utilisateurs ont porté à notre connaissance le fait que Zend_Controller_Front
et Zend_Controller_Router_Route_Module utilisent tous les deux des méthodes du
distributeur qui ne sont pas dans l'interface associée. Nous avons donc ajouté les trois méthodes
suivantes pour s'assurer que les distributeurs personnalisés continueront à fonctionner avec les
implémentations embarquées :

• getDefaultModule() : retourne le nom du module par défaut.

• getDefaultControllerName() : retourne le nom du contrôleur par défaut.

• getDefaultAction() : retourne le nom de l'action par défaut.

B.5.2. Zend_File_Transfer
B.5.2.1. Changements quand vous utilisez des validateurs
Certaines remarques des utilisateurs indiquaient que les validateurs de Zend_File_Transfer
ne fonctionnaient pas comme ceux par défaut fournis avec Zend_Form. Zend_Form permet par
exemple l'utilisation du paramètre breakChainOnFailure qui stoppe la validation de tous les
validateurs suivants dès qu'une erreur de validation apparaît.

Nous avons donc ajouter ce paramètre à tous les validateurs existants pour
Zend_File_Transfer.

• Ancienne API : addValidator($validator, $options, $files).

• Nouvelle API : addValidator($validator, $breakChainOnFailure, $options,


$files).

Pour migrer vos scripts vers la nouvelle API, ajoutez simplement un a FALSE après voir défini
le validateur souhaité.

Exemple B.14. Changer les validateurs de fichiers de 1.6.1 vers 1.6.2

// Exemple pour 1.6.1


$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addValidator('FilesSize', array('1B', '100kB'));

// Même exemple pour 1.6.2 et plus récent


// Notez l'ajout du booléen false
$upload = new Zend_File_Transfer_Adapter_Http();
$upload->addValidator('FilesSize', false, array('1B', '100kB'));

B.6. Zend Framework 1.5


Lors de la migration d'un version précédente vers Zend Framework 1.5 ou plus récent vous
devriez prendre note de ce qui suit.

B.6.1. Zend_Controller
Bien que la plupart des fonctionnalités de base demeurent les mêmes, et que toutes les
fonctionnalités documentées restent les mêmes, il existe une "fonctionnalité" particulière non
documentée qui a changé.

1665
Notes de migration
de Zend Framework

Quand vous écrivez des URLs, la manière documentée d'écrire les noms d'action en
notationCamel est d'utiliser un séparateur de mot ; ceux ci sont "." ou "-" par défaut, mais ils
peuvent être configurés dans le distributeur. Le distributeur en interne transforme les noms
d'action en minuscules, et utilise ces séparateurs de mots pour ré-assembler la méthode d'action
en utilisant la notationCamel. Cependant, comme les fonctions PHP ne sont pas sensibles à la
casse, vous pouvez toujours écrire les URLs en utilisant la notationCamel, et le distributeur les
résoudra de la même manière. Par exemple, "notation-camel" deviendra "notationCamelAction"
dans le distributeur, tandis que "notationCamel" deviendra "notationcamelAction" ; cependant, à
cause de l'insensibilité à la casse de PHP, dans les deux cas cela exécutera la même méthode.

Ceci pose des problèmes avec le ViewRenderer lors de la résolution des scripts de vue. La
manière canonique et documentée est que tous les séparateurs de mot sont convertis en tirets,
et les mots en minuscules. Ceci crée un lien sémantique entre les actions et les scripts de
vue, et la normalisation s'assure que les scripts peuvent être trouvés. Cependant, si l'action
"notationCamel" est appelée et est résolue, le séparateur de mot n'est pas pour autant présent,
et le ViewRenderer tente de résoudre un emplacement différent - "notationcamel.phtml" au
lieu de "notation-camel.phtml".

Quelques développeurs se sont fondés sur ce "dispositif", qui n'a jamais été prévu. Plusieurs
changements de l'arbre 1.5.0, cependant, l'ont fait de sorte que le ViewRenderer ne résout plus
ces chemins ; le lien sémantique est maintenant imposé. A partir de maintenant, le distributeur
impose la sensibilité à la casse dans les noms d'action. Ceci veut dire que la référence vers
vos actions dans l'URL en utilisant la notationCamel ne résoudra plus les mêmes méthodes
qu'en utilisant les séparateurs de mots (par ex., "notation-camel"). Ceci entraîne qu'à partir de
maintenant le ViewRenderer honorera seulement les actions en "mots-séparés" lors de la
résolution des scripts de vue.

Si vous constatez que vous comptiez sur ce "dispositif", vous avez plusieurs options :

• Meilleure option : renommez vos scripts de vue. Pour : compatibilité ascendante. Contre : si
vous avez beaucoup de scripts de vue basés sur l'ancien, comportement fortuit, vous aurez
beaucoup de renommage à faire.

• Seconde meilleure option : le ViewRenderer délégue maintenant la résolution des scripts


de vue à Zend_Filter_Inflector ; vous pouvez modifier les règles de l'inflecteur pour ne
plus séparer les mots d'une action avec un tiret :

$viewRenderer =
Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$inflector = $viewRenderer->getInflector();
$inflector->setFilterRule(':action', array(
new Zend_Filter_PregReplace(
'#[^a-z0-9' . preg_quote(DIRECTORY_SEPARATOR, '#') . ']+#i',
''
),
'StringToLower'
));

Le code ci-dessus modifiera l'inflecteur pour ne plus séparer les mots avec un tiret ; vous
pouvez aussi vouloir supprimer le filtre StringToLower si vous voulez que vos scripts de
vues utilisent aussi la notationCamel.

Si le renommage de vos scripts de vue est trop fastidieux ou nécessite trop de temps, ceci est
la meilleure option avant de trouver le temps de le faire.

1666
Notes de migration
de Zend Framework

• Option la moins souhaitable : vous pouvez forcer le distributeur à distribuer les


noms d'action écrits en notationCamel avec un nouveau drapeau du contrôleur frontal,
useCaseSensitiveActions :

$front->setParam('useCaseSensitiveActions', true);

Ceci vous permettra d'utiliser la notationCamel dans l'URL et de toujours faire résoudre la
même action que si vous utilisez les séparateurs de mots. Cependant, ceci signifiera que les
problèmes décrits ci-dessus interviendront tôt ou tard ; vous devrez probablement utiliser la
deuxième option ci-dessus en plus de celle-ci pour que tout fonctionne correctement.

Notez, de plus, que l'utilisation de ce drapeau déclenchera une notice indiquant que cette
utilisation est dépréciée.

B.7. Zend Framework 1.0


Lors de la migration d'un version précédente vers Zend Framework 0.8 ou plus récent vous
devriez prendre note de ce qui suit.

B.7.1. Zend_Controller
Les principaux changements introduits dans la version 1.0.0RC1 sont l'ajout et l'activation par
défaut du plugin ErrorHandleret de l'aide d'action ViewRenderer. Veuillez lire la documentation
de chacun des éléments directement pour apprendre leur fonctionnement et quels effets, ils
peuvent avoir sur vos applications.

Le plugin ErrorHandler est exécuté pendant postDispatch() vérifiant la présence


d'exceptions, et redirigeant vers le contrôleur de gestion d'erreur spécifié. Vous pouvez le
désactiver en réglant le paramètre noErrorHandler du contrôleur frontal :

$front->setParam('noErrorHandler', true);

L'aide d'action ViewRenderer automatise l'injection de vues dans les contrôleurs d'action en
tant qu'autogénération des scripts de vues suivant l'action courante. Le principal problème que
vous pourriez rencontrer intervient quand vous avez des actions qui ne rendent pas de scripts
de vues ni ne font suivre ou redirige, alors ViewRenderer va tenter de rendre un script de vue
basé sur le nom de l'action.

Il existe plusieurs possibilités pour mettre à jour votre code. Dans un premier temps, vous
pouvez globalement désactiver ViewRenderer dans votre fichier d'amorçage du contrôleur
frontal avant toute distribution :

// En considérant que $front est une instance de Zend_Controller_Front


$front->setParam('noViewRenderer', true);

Cependant, ceci n'est pas une bonne stratégie à long terme, car il apparaît aisément que vous
devrez écrire plus de code.

Quand vous serez prêt à utiliser la fonctionnalité ViewRenderer, il y a plusieurs choses à vérifier
dans votre code de contrôleur. Premièrement, regardez vos méthodes d'actions (les méthodes
se terminant par "Action"), et déterminez ce que chacune d'elle réalise. Si rien de ce qui suit
n'est réalisé, vous devrez réaliser des changements :

• Appel de $this->render()

1667
Notes de migration
de Zend Framework

• Appel de $this->_forward()

• Appel de $this->_redirect()

• Appel de l'aide d'action Redirector

Le changement le plus simple est la désactivation de l'auto-rendu pour cette méthode :

$this->_helper->viewRenderer->setNoRender();

Si vous trouvez qu'aucune de vos méthodes d'actions n'effectue de rendu, ne font suivre, ou
redirige, vous pouvez préférer mettre la ligne suivante dans la méthode preDispatch() ou
init() :

public function preDispatch()


{
// désactive l'auto-rendu des scripts de vues
$this->_helper->viewRenderer->setNoRender()
// ... faire autre chose ...
}

Si vous appelez render(), et que vous utilisez la structure de dossier modulaire


conventionnelle, vous voudrez modifier votre code pour utiliser l'auto-rendu :

• Si vous rendez de multiples scripts de vues dans une seule action, vous n'avez rien à modifier.

• Si vous appelez simplement render() sans aucun argument, vous pouvez effacer ces lignes.

• Si vous appelez render() avec des arguments, et que vous ne réalisez pas ensuite
d'exécution de code ou effectuez le rendu de scripts de vues multiples, vous pouvez changer
ces appels par $this->_helper->viewRenderer().

Si vous n'utilisez pas la structure de dossier modulaire conventionnelle, il existe une variété
de méthodes pour paramétrer le chemin de base des vues et les spécifications du chemin
vers les scripts ainsi vous pourrez utiliser ViewRenderer. Veuillez lire la documentation de
ViewRendererpour plus d'informations sur ces méthodes.

Si vous utilisez un objet de vue issu du registre, ou que vous personnalisez votre objet
vue, ou que vous utilisez une implémentation de vue différente, vous pouvez vouloir injecter
ViewRenderer dans cet objet. Ceci peut être réalisé facilement à tout moment.

• Avant la distribution d'une instance de contrôleur frontal :

// En considérant que $view a déjà été définie


$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view);
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);

• A tout moment durant le processus d'amorçage :

$viewRenderer =
Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$viewRenderer->setView($view);

Il existe plusieurs manières de modifier ViewRenderer, incluant le réglage d'un script de vue
différent à rendre, la spécification d'un remplaçant pour tous les éléments remplaçables d'un
chemin de script de vues (incluant le suffixe), le choix d'un segment nommé de la réponse à

1668
Notes de migration
de Zend Framework

utiliser, et plus encore. Si vous n'utilisez pas la structure de dossier modulaire conventionnelle,
vous pouvez tout de même associer différentes spécifications de chemin à ViewRenderer.

Nous vous encourageons à adapter votre code pour utiliser ErrorHandler et ViewRenderer
puisqu'il s'agit maintenant de fonctionnalités natives.

B.7.2. Zend_Currency
Créer un objet Zend_Currency est devenu plus simple. Vous n'avez plus besoin de passer
un script ou de le mettre à NULL, le paramètre script est optionnel et peut être spécifié par la
méthode setFormat().

$currency = new Zend_Currency($currency, $locale);

La méthode setFormat() prend maintenant en paramètre un tableau d'options. Ces options


sont permanentes et écrasent les précédentes déjà présentes. La nouvelle option "precision"
a été intégrée :

• position : Remplacement de l'ancien paramètre "rules"

• script : Remplacement de l'ancien paramètre "script"

• format : Remplacement de l'ancien paramètre "locale" qui n'affecte plus de nouvelle monnaie,
mais seulement un format de nombre.

• display : Remplacement de l'ancien paramètre "rules"

• precision : Nouveau paramètre

• name : Remplacement de l'ancien paramètre "rules". Affecte le nom complet de la monnaie.

• currency : Nouveau paramètre

• symbol : Nouveau paramètre

$currency->setFormat(array $options);

La méthode toCurrency() ne supporte plus les paramètres optionnels "script" et "locale".


A la place, elle accepte un tableau d'options qui sera de la même forme que celui utilisé par
setFormat.

$currency->toCurrency($value, array $options);

Les méthodes getSymbol(), getShortName(), getName(), getRegionList() et


getCurrencyList() ne sont plus statiques. Elles retournent les valeurs affectées dans l'objet,
si on ne leur passe pas de paramètre.

B.8. Zend Framework 0.9


Lors de la migration d'un version précédente vers Zend Framework 0.9 ou plus récent vous
devriez prendre note de ce qui suit.

B.8.1. Zend_Controller
0.9.3 introduit les aides d'actions. En lien avec ce changement, les méthodes suivantes ont été
effacées puisqu'elles sont maintenant encapsulées dans l'aide d'action redirector :

1669
Notes de migration
de Zend Framework

• setRedirectCode() à remplacer par


Zend_Controller_Action_Helper_Redirector::setCode().

• setRedirectPrependBase() à remplacer par


Zend_Controller_Action_Helper_Redirector::setPrependBase().

• setRedirectExit() à remplacer par


Zend_Controller_Action_Helper_Redirector::setExit().

Lisez la documentation des aides d'actionspour plus d'informations sur la récupération


ou la manipulation des objets "helper", et la documentation du helper redirectorpour plus
d'informations sur le réglage des options de redirection (de même que pour les méthodes
alternatives de redirection).

B.9. Zend Framework 0.8


Lors de la migration d'un version précédente vers Zend Framework 0.8 ou plus récent vous
devriez prendre note de ce qui suit.

B.9.1. Zend_Controller
Pour les versions précédentes, l'utilisation basique des composants MVC reste la même :

Zend_Controller_Front::run('/chemin/vers/controleurs');

Cependant, la structure des dossiers a subi une réorganisation, certains composants ont été
effacés, et d'autres ont été soit renommés soit ajoutés. Les changements incluent :

• Zend_Controller_Router a été effacé en faveur du routeur de réécriture ("rewrite router").

• Zend_Controller_RewriteRouter a été renommé en


Zend_Controller_Router_Rewrite, et promu en tant que routeur standard fourni avec le
framework ; Zend_Controller_Front l'utilise par défaut si aucun autre routeur n'est fourni.

• Une nouvelle classe de route à utiliser avec le routeur de réécriture a été introduite,
Zend_Controller_Router_Route_Module ; elle couvre la route par défaut utilisée par le
MVC, et supporte les modules de contrôleurs.

• Zend_Controller_Router_StaticRoute a été renommé en


Zend_Controller_Router_Route_Static.

• Zend_Controller_Dispatcher a été renommé en


Zend_Controller_Dispatcher_Standard.

• Les arguments de Zend_Controller_Action::_forward() ont changés. La signature


est maintenant :

final protected function _forward($action,


$controller = null,
$module = null,
array $params = null);

$action est toujours obligatoire ; si aucun contrôleur n'est spécifié, une action dans le
contrôleur courant est considérée. $module est toujours ignoré à moins que $controller ne
soit spécifié. Pour finir, tout $params fourni sera ajouté à l'objet requête. Si aucun contrôleur

1670
Notes de migration
de Zend Framework

ou module n'est nécessaire, mais que des paramètres le sont, passez simplement NULL pour
ces valeurs.

B.10. Zend Framework 0.6


Lors de la migration d'un version précédente vers Zend Framework 0.6 ou plus récent vous
devriez prendre note de ce qui suit.

B.10.1. Zend_Controller
L'utilisation de base des composants MVC n'a pas changé ; vous pouvez toujours faire comme
suit :

Zend_Controller_Front::run('/chemin/vers/controleurs');

/* -- créer un routeur -- */
$router = new Zend_Controller_RewriteRouter();
$router->addRoute('user', 'user/:username', array('controller' => 'user',
'action' => 'info'));

/* -- l'affecter à un contrôleur -- */
$ctrl = Zend_Controller_Front::getInstance();
$ctrl->setRouter($router);

/* -- régler le répertoire des contrôleurs et distribuer -- */


$ctrl->setControllerDirectory('/chemin/vers/controleurs');
$ctrl->dispatch();

Nous encourageons l'utilisation de l'objet Réponse pour agréger le contenu et les en-têtes. Ceci
permet un basculement plus flexible entre les formats d'affichage (par exemple, JSON ou XML
au lieu de XHTML) dans vos applications. Par défaut, dispatch() va effectuer le rendu de la
réponse, envoyant à la fois les en-têtes et tout contenu. Vous pouvez aussi avoir le contrôleur
frontal qui retourne la réponse en utilisant returnResponse(), et qui ensuite effectue le rendu
de la réponse suivant votre propre logique. Une version future du contrôleur frontal peut mettre
en application l'utilisation de l'objet Réponse via la bufferisation de sortie.

Il existe beaucoup d'autres fonctionnalités qui étendent l'API existante, et celles-ci sont décrites
dans la documentation.

Le changement le plus important auquel vous devrez faire attention apparaîtra quand vous
tenterez de sous-classer les différents composants. La clé se trouve ci-dessous :

• Zend_Controller_Front::dispatch() intercepte par défaut les exceptions dans l'objet


réponse, et ne les affiche pas, afin d'éviter l'affichage d'information sensible du système. Vous
pouvez surcharger ceci de différentes manières :

• Régler throwExceptions() dans le contrôleur frontal :

$front->throwExceptions(true);

• Régler renderExceptions() dans l'objet Réponse :

$response->renderExceptions(true);
$front->setResponse($response);
$front->dispatch();

1671
Notes de migration
de Zend Framework

// ou :
$front->returnResponse(true);
$response = $front->dispatch();
$response->renderExceptions(true);
echo $response;

• Zend_Controller_Dispatcher_Interface::dispatch() accepte maintenant et


retourne un objet Section 4, « L'objet Requête » au lieu d'un élément du distributeur.

• Zend_Controller_Router_Interface::route() accepte maintenant et retourne un


objet Section 4, « L'objet Requête » au lieu d'un élément du distributeur.

• Les changements de Zend_Controller_Action incluent :

• Le constructeur accepte maintenant exactement trois arguments,


Zend_Controller_Request_Abstract $request,
Zend_Controller_Response_Abstract $response, et le tableau facultatif $params.
Zend_Controller_Action::__construct() les utilise pour affecter la requête, la
réponse, et les propriétés invokeArgs de l'objet, et si vous devez surcharger le
constructeur, vous devez faire de même. La meilleure solution est d'utiliser la méthode
init() pour réaliser toute configuration de l'instance, puisque cette méthode est appelée
en tant que action finale du constructeur.

• run() n'est plus défini en tant qu'élément final, mais n'est pas non plus
utilisé par le contrôleur frontal ; son seul but apparaît lors de l'utilisation
de la classe en tant que contrôleur de page. Il prend maintenant deux
arguments facultatifs, un Zend_Controller_Request_Abstract $request et un
Zend_Controller_Response_Abstract $response.

• indexAction() ne nécessite plus d'être défini, mais est recommandé en tant qu'action
par défaut. Ceci permet lors de l'utilisation de RewriteRouter et des contrôleurs d'action
de spécifier différentes méthodes d'action par défaut.

• __call() peut être surchargé pour gérer automatiquement les actions non définies.

• _redirect() prend maintenant un second paramètre facultatif, le code HTTP à retourner


avec la redirection, et un troisième paramètre optionnel, $prependBase, qui peut indiquer
que l'URL de base enregistré avec l'objet requête peut être ajouté en tant que suffixe à
l'URL spécifié.

• La propriété _action n'existe plus. Cette propriété était un


Zend_Controller_Dispatcher_Token, qui n'existe plus maintenant. Le seul but de cet
élément est de fournir l'information concernant le contrôleur, l'action et les paramètres d'URL
de la requête. Cette information est maintenant disponible dans l'objet requête, et peut être
interrogé comme ceci :

// Récupère le nom de controleur de la requête


// L'accès se fait via : $this->_action->getControllerName().
// L'exemple ci-dessous utilise getRequest(), bien que vous pourriez
// accéder directement à la propriété $_request ;
// l'utilisation de getRequest() est recommandée puisque la classe
// parente peut surcharger l'accès à l'objet requête.
$controller = $this->getRequest()->getControllerName();

// Recupere le nom de l'action de la requete


// L'acces se fait via : $this->_action->getActionName().
$action = $this->getRequest()->getActionName();

1672
Notes de migration
de Zend Framework

// Recupere les parametres de la requete


// Ceci n'a pas changé ; les méthodes _getParams() et _getParam()
// relaient simplement l'objet requete maintenant.
$params = $this->_getParams();
$foo = $this->_getParam('foo', 'default');
// parametre de la requete 'foo', en utilisant 'default'
// en tant que valeur par défaut si aucune valeur n'est trouvée

• noRouteAction() a été effacée. La manière appropriée de gérer les méthodes d'actions


non-existantes est de les router vers une action par défaut en utilisant __call() :

public function __call($method, $args)


{
// Si la méthode requetee ne correspond a aucune methode 'Action',
// on renvoie vers la méthode d'action par défaut :
if ('Action' == substr($method, -6)) {
return $this->defaultAction();
}

throw new Zend_Controller_Exception('Appel de methode invalide');


}

• Zend_Controller_RewriteRouter::setRewriteBase() a été effacée. Utilisez plutôt


Zend_Controller_Front::setBaseUrl() (ou
Zend_Controller_Request_Http::setBaseUrl(), si vous utilisez cette classe de requête).

• Zend_Controller_Plugin_Interface a été remplacée par


Zend_Controller_Plugin_Abstract. Toutes les méthodes acceptent et retournent
maintenant un objet Section 4, « L'objet Requête » au lieu d'un élément du distributeur.

1673
Annexe C. Convention de codage PHP
de Zend Framework
Table des matières
C.1. Vue d'ensemble .................................................................................................. 1674
C.1.1. Portée ..................................................................................................... 1674
C.1.2. Buts ......................................................................................................... 1675
C.2. Formatage des fichiers PHP ................................................................................ 1675
C.2.1. Général ................................................................................................... 1675
C.2.2. Indentation ............................................................................................... 1675
C.2.3. Longueur maximum d'une ligne ................................................................. 1675
C.2.4. Terminaison de lignes .............................................................................. 1675
C.3. Conventions de nommage ................................................................................... 1675
C.3.1. Classes ................................................................................................... 1675
C.3.2. Abstract Classes ...................................................................................... 1676
C.3.3. Interfaces ................................................................................................. 1676
C.3.4. Noms de fichiers ...................................................................................... 1676
C.3.5. Fonctions et méthodes ............................................................................. 1677
C.3.6. Variables ................................................................................................. 1677
C.3.7. Constantes .............................................................................................. 1678
C.4. Style de codage .................................................................................................. 1678
C.4.1. Démarcation du code PHP ....................................................................... 1678
C.4.2. Chaînes de caractères ............................................................................. 1678
C.4.3. Tableaux .................................................................................................. 1679
C.4.4. Classes ................................................................................................... 1680
C.4.5. Fonctions et méthodes ............................................................................. 1681
C.4.6. Structure de contrôle ................................................................................ 1684
C.4.7. Documentation intégrée ............................................................................ 1685

C.1. Vue d'ensemble


C.1.1. Portée
Ce document fournit les lignes directrices pour le formatage de code et la documentation pour les
contributeurs individuels et les équipes contributrices à Zend Framework. Un certain nombre de
développeurs utilisant Zend Framework ont trouvé ces conventions de codage pratique car leurs
styles de codage sont cohérents avec l'ensemble du code de Zend Framework. Il est également
à noter qu'il exige un effort significatif pour spécifier entièrement des normes de codage. Note:
parfois les développeurs considèrent l'établissement d'une norme plus important que ce que
cette norme suggère réellement en tout cas au niveau de l'analyse détaillée de la conception.
Les lignes directrices dans les conventions de codage de Zend Framework effectuent un cliché
des pratiques qui ont bien fonctionnées dans le projet Zend Framework. Vous pouvez modifier
ces règles ou les utiliser comme telles en accord avec les termes de votre licence.

Les sujets traités dans les conventions de codage de Zend Framework sont :

• Formatage des fichiers PHP

• Conventions de nommage

1674
Convention de codage
PHP de Zend Framework

• Style de code

• Documentation en ligne

C.1.2. Buts
De bonnes conventions de codage sont importantes dans tout projet de développement, et plus
particulièrement lorsque plusieurs développeurs travaillent en même temps sur le projet. Avoir
ces conventions permet de s'assurer que le code est de haute qualité, peu buggé et facilement
maintenu.

C.2. Formatage des fichiers PHP


C.2.1. Général
Pour les fichiers contenant uniquement du code PHP, la balise de fermeture ("?>") n'est jamais
permise. Il n'est pas requis par PHP. Ne pas l'inclure permet de se prémunir les problèmes liés
à l'injection accidentelle d'espaces blancs dans la sortie.

IMPORTANT : L'inclusion de données binaires arbitraires comme il est permis par


__HALT_COMPILER() est prohibé dans tout fichier PHP de Zend Framework, ainsi que dans
tout fichier dérivé. L'utilisation de cette possibilité est uniquement permise pour des scripts
spéciaux d'installation.

C.2.2. Indentation
Utilisez une indentation de 4 espaces, sans tabulations.

C.2.3. Longueur maximum d'une ligne


La longueur souhaitée d'une ligne est de 80 caractères, c'est-à-dire que les développeurs
devraient avoir pour but de ne pas dépasser les 80 caractères pour des raisons pratiques.
Cependant, des lignes plus longues sont acceptables. La longueur maximum de toute ligne de
code PHP est de 120 caractères.

C.2.4. Terminaison de lignes


La terminaison de ligne est la terminaison standard pour les fichier textes UNIX. Les lignes doit
finir seulement avec un "linefeed" (LF). Les linefeeds sont représentés comme 10 en ordinal,
ou 0x0A en hexadécimal.

Note : N'utilisez pas de retour chariots (CR) comme le font les Macintosh (0x0D) ou de
combinaison retour chariot/linefeed (CRLF) comme le font les ordinateurs sous Windows (0x0D,
0x0A).

C.3. Conventions de nommage


C.3.1. Classes
Zend Framework emploie une convention de nommage des classes où les noms des classes
mènent directement dans les répertoires dans lesquels elles sont stockées. Le répertoire racine
de Zend Framework est le répertoire "Zend/", tandis que le répertoire racine de la librairie extras

1675
Convention de codage
PHP de Zend Framework

de Zend Framework est "ZendX/". Toutes les classes sont stockées de façon hiérarchique sous
ces dossiers racines.

Les noms de classes ne peuvent contenir que des caractères alphanumériques. Les nombres
sont autorisés, mais déconseillés. Les tirets bas ("_") ne sont autorisés que pour être utilisés
comme séparateur de chemin ; le nom de fichier "Zend/Db/Table.php" doit mener à la classe
appelée "Zend_Db_Table".

Si un nom de classe comprend plus d'un mot, la première lettre de chaque nouveau mot doit
être mis en majuscule. La mise en majuscule de lettres successives n'est pas autorisée, c'est-
à-dire qu'une classe "Zend_PDF" est interdit alors que "Zend_Pdf" est autorisé.

Ces conventions définissent un pseudo mécanisme d'espace de noms pour Zend Framework.
Zend Framework adoptera la fonctionnalité des espaces de noms de PHP quand celle-ci sera
disponible et qu'il sera possible pour les développeurs de l'utiliser dans leurs applications.

Regardez les noms de classes dans les librairies standard et extras pour avoir des exemples
de cette convention de nommage. IMPORTANT : le code qui opère avec le Framework mais qui
n'en fait par partie, c'est-à-dire le code écrit par un utilisateur et pas Zend ou une des entreprises
partenaires, ne doivent jamais commencer par "Zend_".

C.3.2. Abstract Classes


In general, abstract classes follow the same conventions as classes, with one additional
rule: abstract class names must end in the term, "Abstract", and that term must not
be preceded by an underscore. As an example, Zend_Controller_Plugin_Abstract
is considered an invalid name, but Zend_Controller_PluginAbstract or
Zend_Controller_Plugin_PluginAbstract would be valid names.

This naming convention is new with version 1.9.0 of Zend Framework. Classes
that pre-date that version may not follow this rule, but will be renamed in the
future in order to comply.

C.3.3. Interfaces
In general, interfaces follow the same conventions as classes, with one additional rule:
interface names may optionally end in the term, "Interface", but that term must not be
preceded by an underscore. As an example, Zend_Controller_Plugin_Interface
is considered an invalid name, but Zend_Controller_PluginInterface or
Zend_Controller_Plugin_PluginInterface would be valid names.

While this rule is not required, it is strongly recommended, as it provides a good visual cue to
developers as to which files contain interfaces rather than classes.

This naming convention is new with version 1.9.0 of Zend Framework. Classes
that pre-date that version may not follow this rule, but will be renamed in the
future in order to comply.

C.3.4. Noms de fichiers


Pour tous les autres fichiers, seuls des caractères alphanumériques, tirets bas et tirets demi-
cadratin ("-") sont autorisés. Les espaces et les caractères spéciaux sont interdits.

1676
Convention de codage
PHP de Zend Framework

Tout fichier contenant du code PHP doit se terminer par l'extension ".php". Ces exemples
montrent des noms de fichiers acceptables pour contenir les noms de classes issus des
exemples ci-dessus :

Zend/Db.php

Zend/Controller/Front.php

Zend/View/Helper/FormRadio.php

Les noms de fichiers doivent correspondre aux noms des classes décris ci-dessus.

C.3.5. Fonctions et méthodes


Les noms de fonctions ne peuvent contenir que des caractères alphanumériques. Les tirets bas
("_") ne sont pas permis. Les nombres sont autorisés mais déconseillés.

Les noms de fonctions doivent toujours commencer avec une lettre en minuscule. Quand un
nom de fonction est composé de plus d'un seul mot, la première lettre de chaque mot doit être
mise en majuscule. C'est ce que l'on appelle communément la "notationCamel".

La clarté est conseillée. Le nom des fonctions devrait être aussi explicite que possible, c'est un
gage de compréhension du code.

Voici des exemples de noms acceptables pour des fonctions :

filterInput()

getElementById()

widgetFactory()

Pour la programmation orientée objet, les accesseurs aux objets doivent toujours être préfixés
par soit "get" soit "set". Lorsque vous utilisez des motifs de conception, comme le Singleton ou la
Fabrique, le nom de la méthode doit contenir le nom du motif pour permettre une reconnaissance
plus simple et plus rapide du motif.

Pour des méthodes d'objet qui sont déclarées avec la construction "private" ou "protected", le
premier caractère du nom variable doit être un tiret bas simple ("_"). C'est la seule utilisation
autorisé d'un tiret bas dans un nom de méthode. Les méthodes déclarées "public" ne devraient
jamais commencer par un tiret bas.

Les fonctions à portée globale ("les fonctions flottantes") sont autorisées mais déconseillées. Il
est recommandé de mettre ces fonctions dans des classes statiques.

C.3.6. Variables
Les noms de variables ne peuvent contenir que des caractères alphanumériques. Les tirets bas
ne sont pas permis. Les nombres sont autorisés mais déconseillés.

Pour les variables membres de classe qui sont déclarées comme "private" ou "protected", le
premier caractère du nom de la variable doit être un tiret bas simple ("_"). C'est la seule utilisation
autorisé d'un tiret bas dans un nom de variable. Les variables membres "public" ne devraient
jamais commencer par un tiret bas.

1677
Convention de codage
PHP de Zend Framework

Tout comme les noms de fonction (cf la section 3.3 ci-dessus), les noms de variables doivent
toujours commencer par un caractère en minuscule et suivre la convention de capitalisation de
la "notationCamel".

La clarté est conseillée. Les variables devraient toujours être aussi claires que pratiques. Des
noms de variables comme "$i" et "$n" sont déconseillé pour tout autre usage que les petites
boucles. Si une boucle contient plus de 20 lignes de code, les variables pour les indices doivent
avoir des noms descriptifs.

C.3.7. Constantes
Les constantes peuvent contenir des caractères alphanumériques et des tirets bas. Les nombres
sont autorisés.

Les constantes doivent toujours être en majuscule, cependant les mots pouvant les composer
doivent être séparés par des tiret-bats ("_").

Par exemple, EMBED_SUPPRESS_EMBED_EXCEPTION est permis mais


EMBED_SUPPRESSEMBEDEXCEPTION ne l'est pas.

Les constantes doivent toujours être définies comme des membres d'une classe, en utilisant la
construction "const". Définir des constantes globales avec "define" est permis mais déconseillé.

C.4. Style de codage


C.4.1. Démarcation du code PHP
Les codes PHP doivent toujours être délimités dans la forme complète, par les balises PHP
standards :

<?php

?>

Les balises courtes d'ouvertures ("<?")ne sont pas autorisées. Pour les fichiers ne contenant que
du code PHP, la balise de fermeture doit toujours être omise (Voir Section C.2.1, « Général »).

C.4.2. Chaînes de caractères


C.4.2.1. Chaînes littérales
Lorsqu'une chaîne est littérale (c'est-à-dire qu'elle ne contient pas de substitution de variables),
l'apostrophe ou guillemet simple doit être utilisé pour démarquer la chaîne :

$a = 'Exemple de chaîne de caractères';

C.4.2.2. Chaînes de caractères littérales avec apostrophes


Lorsque qu'une chaîne littérale contient des apostrophes, il est permis de les démarquer en
utilisant les guillemets doubles. Ceci est particulièrement conseillé pour les requêtes SQL :

$sql = "SELECT `id`, `name` from `people` "


. "WHERE `name`='Eric' OR `name`='Caroline'";

1678
Convention de codage
PHP de Zend Framework

La syntaxe ci-dessus est préférée à l'échappement des apostrophes car elle est plus facile à lire.

C.4.2.3. Substitution de variables


La substitution des variables est permise en utilisant une de ces deux formes :

$greeting = "Bonjour $name, bienvenue !";

$greeting = "Bonjour {$name}, bienvenue !";

Pour des raisons d'uniformité, cette forme n'est pas permise :

$greeting = "Bonjour ${name}, bienvenue !";

C.4.2.4. Concaténation de chaînes


Les chaînes peuvent êtres concaténées en utilisant l'opérateur ".". Un espace doit toujours être
ajouté avant, et après cet opérateur, cela permet d'améliorer la lisibilité :

$company = 'Zend' . ' ' . 'Technologies';

Lors de la concaténation de chaînes avec l'opérateur ".", il est permis de couper le segment en
plusieurs lignes pour améliorer la lisibilité. Dans ces cas, chaque nouvelle ligne doit être remplie
avec des espaces, de façon à aligner le "." sous l'opérateur "=" :

$sql = "SELECT `id`, `name` FROM `people` "


. "WHERE `name` = 'Caroline' "
. "ORDER BY `name` ASC ";

C.4.3. Tableaux
C.4.3.1. Tableaux indexés numériquement
L'utilisation d'indices négatifs n'est pas permise.

Un tableau indexé peut commencer avec n'importe quel nombre positif, cependant cette méthode
est déconseillée. Il est conseillé de commencer l'indexation à 0.

Lors de la déclaration de tableaux indexés avec la construction array, un espace doit être ajouté
après chaque virgule délimitante, pour améliorer la lisibilité :

$sampleArray = array(1, 2, 3, 'Zend', 'Studio');

Il est aussi permis de déclarer des tableaux indexés sur plusieurs lignes en utilisant la
construction array. Dans ce cas, chaque nouvelle ligne doit être remplie par des espaces
jusqu'à ce que cette ligne s'aligne, comme il est montré dans l'exemple suivant :

$sampleArray = array(1, 2, 3, 'Zend', 'Studio',


$a, $b, $c,
56.44, $d, 500);

Alternately, the initial array item may begin on the following line. If so, it should be padded at one
indentation level greater than the line containing the array declaration, and all successive lines

1679
Convention de codage
PHP de Zend Framework

should have the same indentation; the closing paren should be on a line by itself at the same
indentation level as the line containing the array declaration:

$sampleArray = array(
1, 2, 3, 'Zend', 'Studio',
$a, $b, $c,
56.44, $d, 500,
);

When using this latter declaration, we encourage using a trailing comma for the last item in the
array; this minimizes the impact of adding new items on successive lines, and helps to ensure
no parse errors occur due to a missing comma.

C.4.3.2. Tableaux associatifs


Lorsque de la déclaration de tableaux associatifs avec la construction array, il est conseillé de
séparer la définition sur plusieurs lignes. Dans ce cas, chaque ligne successive doit être remplie
par des espaces pour que les clés et les valeurs soient alignées :

$sampleArray = array('firstKey' => 'firstValue',


'secondKey' => 'secondValue');

Alternately, the initial array item may begin on the following line. If so, it should be padded at
one indentation level greater than the line containing the array declaration, and all successive
lines should have the same indentation; the closing paren should be on a line by itself at the
same indentation level as the line containing the array declaration. For readability, the various
"=>" assignment operators should be padded such that they align.

$sampleArray = array(
'firstKey' => 'firstValue',
'secondKey' => 'secondValue',
);

When using this latter declaration, we encourage using a trailing comma for the last item in the
array; this minimizes the impact of adding new items on successive lines, and helps to ensure
no parse errors occur due to a missing comma.

C.4.4. Classes
C.4.4.1. Déclaration de classes
Les classes doivent être nommées conformément aux conventions de nommage de Zend
Framework.

L'accolade est toujours écrite dans la ligne sous le nom de la classe.

Toutes les classes doivent avoir un bloc de documentation conforme aux standards
PHPDocumentor.

Tout code d'une classe doit être indenté avec 4 espaces.

Une seule classe est permise par fichier PHP.

Le placement de code additionnel dans un fichier de classe est permis, mais déconseillé. Dans
ces fichiers, deux lignes vides doivent séparer la classe du code PHP additionnel.

1680
Convention de codage
PHP de Zend Framework

Voici un exemple d'une déclaration de classe autorisée :

/**
* Bloc de documentation
*/
class SampleClass
{
// contenu de la classe
// qui doit être indenté avec 4 espaces
}

Classes that extend other classes or which implement interfaces should declare their
dependencies on the same line when possible.

class SampleClass extends FooAbstract implements BarInterface


{
}

If as a result of such declarations, the line length exceeds the maximum line length, break the line
before the "extends" and/or "implements" keywords, and pad those lines by one indentation level.

class SampleClass
extends FooAbstract
implements BarInterface
{
}

If the class implements multiple interfaces and the declaration exceeds the maximum line length,
break after each comma separating the interfaces, and indent the interface names such that
they align.

class SampleClass
implements BarInterface,
BazInterface
{
}

C.4.4.2. Variables membres de la classe


Les variables membres doivent être nommées en respectant les conventions de nommage de
Zend Framework.

Toute variable déclarée dans une classe doit être listée en haut de cette classe, avant toute
déclaration de méthode.

La construction var n'est pas permise. Les variables membres déclarent toujours leur visibilité
en utilisant la construction private, protected, ou public. L'accès direct à ces variables
membres en les rendant publiques est permis mais déconseillé. Il est préférable d'utiliser des
accesseurs (set/get).

C.4.5. Fonctions et méthodes


C.4.5.1. Déclaration de fonctions et de méthodes
Les fonctions doivent être nommées en respectant les conventions de nommage de Zend
Framework.

1681
Convention de codage
PHP de Zend Framework

Les fonctions internes aux classes doivent toujours déclarer leur visibilité en utilisant la
construction private, protected, ou public.

Tout comme les classes, l'accolade ouvrante est toujours écrite sous le nom de la fonction. Il
n'y a pas d'espace entre le nom de la fonction et les parenthèses des arguments. Il n'y a pas
d'espace entre la parenthèse fermante et l'accolade.

Les fonctions globales sont fortement déconseillées.

Voici un exemple d'une déclaration permise d'une fonction de classe :

/*
* Bloc de documentation
*/
class Foo
{
/**
* Bloc de documentation
*/
public function bar()
{
// contenu de la fonction
// qui doit être indenté avec 4 espaces
}
}

In cases where the argument list exceeds the maximum line length, you may introduce line
breaks. Additional arguments to the function or method must be indented one additional level
beyond the function or method declaration. A line break should then occur before the closing
argument paren, which should then be placed on the same line as the opening brace of the
function or method with one space separating the two, and at the same indentation level as the
function or method declaration. The following is an example of one such situation:

/**
* Documentation Block Here
*/
class Foo
{
/**
* Documentation Block Here
*/
public function bar($arg1, $arg2, $arg3,
$arg4, $arg5, $arg6
) {
// all contents of function
// must be indented four spaces
}
}

NOTE : Le passage par référence est permis uniquement dans la déclaration de la fonction :

/**
* Bloc de documentation
*/
class Foo
{
/**
* Bloc de documentation

1682
Convention de codage
PHP de Zend Framework

*/
public function bar(&$baz)
{}
}

L'appel par référence est interdit.

La valeur de retour ne doit pas être entourée de parenthèses. Ceci peut gêner à la lecture et
peut aussi casser le code si une méthode est modifiée plus tard pour retourner par référence.

/**
* Bloc de documentation
*/
class Foo
{
/**
* INCORRECT
*/
public function bar()
{
return($this->bar);
}

/**
* CORRECT
*/
public function bar()
{
return $this->bar;
}
}

C.4.5.2. Usage de fonctions et méthodes


Les arguments d'une fonction sont séparés par un espace après la virgule de délimitation. Voici
un exemple d'un appel de fonction qui prend trois arguments :

threeArguments(1, 2, 3);

L'appel par référence est interdit. Référez vous à la section sur la déclaration de fonctions pour
la méthode correcte de passage des argument par référence.

Pour les fonctions dont les arguments peuvent être des tableaux, l'appel à la fonction doit inclure
la construction "array" et peut être divisé en plusieurs ligne pour améliorer la lecture. Dans ces
cas, les standards d'écriture de tableaux s'appliquent aussi :

threeArguments(array(1, 2, 3), 2, 3);

threeArguments(array(1, 2, 3, 'Zend', 'Studio',


$a, $b, $c,
56.44, $d, 500), 2, 3);

threeArguments(array(
1, 2, 3, 'Zend', 'Studio',
$a, $b, $c,
56.44, $d, 500
), 2, 3);

1683
Convention de codage
PHP de Zend Framework

C.4.6. Structure de contrôle


C.4.6.1. If / Else / Elseif
Les structure de contrôles basées sur les constructions if et elseif doivent avoir un seul
espace avant la parenthèse ouvrante de la condition, et un seul espace après la parenthèse
fermante.

Pour la condition entre les parenthèses, les opérateurs doivent être séparés par des espaces
pour une meilleure lisibilité. Les parenthèses internes sont conseillées pour améliorer le
regroupement logique de longues conditions.

L'accolade ouvrante est écrite sur la même ligne que la condition. L'accolade fermante est
toujours écrite sur sa propre ligne. Tout contenu présent à l'intérieur des accolades doit être
indenté par 4 espaces.

if ($a != 2) {
$a = 2;
}

If the conditional statement causes the line length to exceed the maximum line length and has
several clauses, you may break the conditional into multiple lines. In such a case, break the
line prior to a logic operator, and pad the line such that it aligns under the first character of
the conditional clause. The closing paren in the conditional will then be placed on a line with
the opening brace, with one space separating the two, at an indentation level equivalent to the
opening control statement.

if (($a == $b)
&& ($b == $c)
|| (Foo::CONST == $d)
) {
$a = $d;
}

The intention of this latter declaration format is to prevent issues when adding or removing
clauses from the conditional during later revisions.

Pour les instruction "if" qui incluent "elseif" ou "else", les conventions de formatage sont similaires
à celles de la construction "if". Les exemples suivants montrent le formatage approprié pour les
structures "if" avec "else" et/ou les constructions "elseif" :

if ($a != 2) {
$a = 2;
} else {
$a = 7;
}

if ($a != 2) {
$a = 2;
} elseif ($a == 3) {
$a = 4;
} else {
$a = 7;
}

if (($a == $b)
&& ($b == $c)

1684
Convention de codage
PHP de Zend Framework

|| (Foo::CONST == $d)
) {
$a = $d;
} elseif (($a != $b)
|| ($b != $c)
) {
$a = $c;
} else {
$a = $b;
}

PHP permet que ces instructions soient écrites sans accolades dans certaines circonstances.
La convention de codage ne fait pas de différentiation et toutes les instructions "if", "elseif" et
"else" doivent utiliser des accolades.

C.4.6.2. Switch
Les instructions de contrôle avec "switch" ne doivent avoir qu'un seul espace avant la parenthèse
ouvrante de l'instruction conditionnelle, et aussi un seul espace après la parenthèse fermante.

Tout le contenu à l'intérieur de l'instruction "switch" doit être indenté avec 4 espaces. Le contenu
sous chaque "case" doit être indenté avec encore 4 espaces supplémentaires.

switch ($numPeople) {
case 1:
break;

case 2:
break;

default:
break;
}

La construction default ne doit jamais être oubliée dans une instruction switch.

NOTE : Il est parfois pratique d'écrire une clause case qui passe à travers le case suivant en
omettant l'inclusion de break ou return. Pour distinguer ce cas d'un bug, toute clause case
ne contenant pas break ou return doit contenir le commentaire "// break intentionally omitted".

C.4.7. Documentation intégrée


C.4.7.1. Format de la documentation
Tous les blocs de documentation ("docblocks") doivent être compatible avec le format
phpDocumentor. La description du format phpDocumentor n'est pas du ressort de ce document.
Pour plus d'information, visitez http://phpdoc.org/

Tous les fichiers de code source écrits pour Zend Framework ou qui opèrent avec ce framework
doivent contenir un docblock du fichier, en haut de chaque fichier, et un docblock de classe
immédiatement au dessus de chaque classe. Ci-dessous vous trouverez des exemples de tels
docblocs.

C.4.7.2. Fichiers
Chaque fichier qui contient du code PHP doit avoir un bloc d'entête en haut du fichier qui contient
au minimum ces balises phpDocumentor :

1685
Convention de codage
PHP de Zend Framework

/**
* Description courte du fichier
*
* Description longue du fichier s'il y en a une
*
* LICENSE: Informations sur la licence
*
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license BSD License
* @version $Id:$
* @link http://framework.zend.com/package/PackageName
* @since File available since Release 1.5.0
*/

C.4.7.3. Classes
Chaque classe doit avoir un docblock qui contient au minimum ces balises phpDocumentor :

/**
* Description courte de la classe
*
* Description longue de la classe, s'il y en a une
*
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license BSD License
* @version Release: @package_version@
* @link http://framework.zend.com/package/PackageName
* @since Class available since Release 1.5.0
* @deprecated Class deprecated in Release 2.0.0
*/

C.4.7.4. Fonctions
Chaque fonction, méthode, doit avoir un docblock contenant au minimum :

• Une description de la fonction

• Tous les arguments

• Toutes les valeurs de retour possibles

Il n'est pas nécessaire d'utiliser la balise "@access" parce que le niveau d'accès est déjà connu
avec les constructions "public", "private", "protected" utilisée pour déclarer la fonction.

Si une fonction/méthode peut lancer une exception, utilisez "@throws" :

@throws exceptionclass [description]

1686
Annexe D. Zend Framework
Documentation Standard

Table des matières


D.1. Overview ............................................................................................................ 1687
D.1.1. Scope ...................................................................................................... 1687
D.2. Documentation File Formatting ............................................................................ 1687
D.2.1. XML Tags ................................................................................................ 1687
D.2.2. Maximum Line Length .............................................................................. 1688
D.2.3. Indentation ............................................................................................... 1688
D.2.4. Line Termination ...................................................................................... 1688
D.2.5. Empty tags .............................................................................................. 1688
D.2.6. Usage of whitespace within documents ..................................................... 1689
D.2.7. Program Listings ...................................................................................... 1691
D.2.8. Notes on specific inline tags ..................................................................... 1692
D.2.9. Notes on specific block tags ..................................................................... 1693
D.3. Recommendations .............................................................................................. 1694
D.3.1. Use editors without autoformatting ............................................................. 1694
D.3.2. Use Images ............................................................................................. 1694
D.3.3. Use Case Examples ................................................................................. 1694
D.3.4. Avoid Replicating phpdoc Contents ........................................................... 1694
D.3.5. Use Links ................................................................................................ 1694

D.1. Overview
D.1.1. Scope
This document provides guidelines for creation of the end-user documentation found within
Zend Framework. It is intended as a guide to Zend Framework contributors, who must write
documentation as part of component contributions, as well as to documentation translators. The
standards contained herein are intended to ease translation of documentation, minimize visual
and stylistic differences between different documentation files, and make finding changes in
documentation easier with diff tools.

You may adopt and/or modify these standards in accordance with the terms of our license.

Topics covered in Zend Framework's documentation standards include documentation file


formatting and recommendations for documentation quality.

D.2. Documentation File Formatting


D.2.1. XML Tags
Each manual file must include the following XML declarations at the top of the file:

<?xml version="1.0" encoding="UTF-8"?>


<!-- Reviewed: no -->

1687
Zend Framework
Documentation Standard

XML files from translated languages must also include a revision tag containing the revision of
the corresponding English-language file the translation was based on.

<?xml version="1.0" encoding="UTF-8"?>


<!-- EN-Revision: 14978 -->
<!-- Reviewed: no -->

D.2.2. Maximum Line Length


The maximum line length, including tags, attributes, and indentation, is not to exceed 100
characters. There is only one exception to this rule: attribute and value pairs are allowed to
exceed the 100 chars as they are not allowed to be separated.

D.2.3. Indentation
Indentation should consist of 4 spaces. Tabs are not allowed.

Tags which are at the same level must have the same indentation.

<sect1>
</sect1>

<sect1>
</sect1>

Tags which are one level under the previous tag must be indented with 4 additional spaces.

<sect1>
<sect2>
</sect2>
</sect1>

Multiple block tags within the same line are not allowed; multiple inline tags are allowed, however.

<!-- NOT ALLOWED: -->


<sect1><sect2>
</sect2></sect1>

<!-- ALLOWED -->


<para>
<classname>Zend_Magic</classname> does not exist. <classname>Zend_Acl</classname> does.
</para>

D.2.4. Line Termination


Line termination follows the Unix text file convention. Lines must end with a single linefeed (LF)
character. Linefeed characters are represented as ordinal 10, or hexadecimal 0x0A.

Note: Do not use carriage returns (CR) as is the convention in Apple OS's (0x0D) or the carriage
return - linefeed combination (CRLF) as is standard for the Windows OS (0x0D, 0x0A).

D.2.5. Empty tags


Empty tags are not allowed; all tags must contain text or child tags.

1688
Zend Framework
Documentation Standard

<!-- NOT ALLOWED -->


<para>
Some text. <link></link>
</para>

<para>
</para>

D.2.6. Usage of whitespace within documents


D.2.6.1. Whitespace within tags
Opening block tags should have no whitespace immediately following them other than line breaks
(and indentation on the following line).

<!-- NOT ALLOWED -->


<sect1>WHITESPACE
</sect1>

Opening inline tags should have no whitespace immediately following them.

<!-- NOT ALLOWED -->


This is the class <classname> Zend_Class</classname>.

<!-- OK -->
This is the class <classname>Zend_Class</classname>.

Closing block tags may be preceded by whitespace equivalent to the current indentation level,
but no more than that amount.

<!-- NOT ALLOWED -->


<sect1>
</sect1>

<!-- OK -->
<sect1>
</sect1>

Closing inline tags must not be preceded by any whitespace.

<!-- NOT ALLOWED -->


This is the class <classname>Zend_Class </classname>

<!-- OK -->
This is the class <classname>Zend_Class</classname>

D.2.6.2. Multiple line breaks


Multiple line breaks within or between tags are not allowed.

<!-- NOT ALLOWED -->


<para>
Some text...

... and more text


</para>

1689
Zend Framework
Documentation Standard

<para>
Another paragraph.
</para>

<!-- OK -->
<para>
Some text...
... and more text
</para>

<para>
Another paragraph.
</para>

D.2.6.3. Separation between tags


Tags at the same level must be separated by an empty line to improve readability.

<!-- NOT ALLOWED -->


<para>
Some text...
</para>
<para>
More text...
</para>

<!-- OK -->
<para>
Some text...
</para>

<para>
More text...
</para>

The first child tag should open directly below its parent, with no empty line between them; the
last child tag should close directly before the closing tag of its parent.

<!-- NOT ALLOWED -->


<sect1>

<sect2>
</sect2>

<sect2>
</sect2>

<sect2>
</sect2>

</sect1>

<!-- OK -->
<sect1>
<sect2>
</sect2>

<sect2>

1690
Zend Framework
Documentation Standard

</sect2>

<sect2>
</sect2>
</sect1>

D.2.7. Program Listings


The opening <programlisting> tag must indicate the appropriate "language" attribute and be
indented at the same level as its sibling blocks.

<para>Sibling paragraph.</para>

<programlisting language="php"><![CDATA[

CDATA should be used around all program listings.

<programlisting> sections must not add linebreaks or whitespace at the beginning or end of the
section, as these are then represented in the final output.

<!-- NOT ALLOWED -->


<programlisting language="php"><![CDATA[

$render = "xxx";

]]></programlisting>

<!-- OK -->
<programlisting language="php"><![CDATA[
$render = "xxx";
]]></programlisting>

Ending CDATA and <programlisting> tags should be on the same line, without any indentation.

<!-- NOT ALLOWED -->


<programlisting language="php"><![CDATA[
$render = "xxx";
]]>
</programlisting>

<!-- NOT ALLOWED -->


<programlisting language="php"><![CDATA[
$render = "xxx";
]]></programlisting>

<!-- OK -->
<programlisting language="php"><![CDATA[
$render = "xxx";
]]></programlisting>

The <programlisting> tag should contain the "language" attribute with a value appropriate to
the contents of the program listing. Typical values include "css", "html", "ini", "javascript", "php",
"text", and "xml".

<!-- PHP -->


<programlisting language="php"><![CDATA[

1691
Zend Framework
Documentation Standard

<!-- Javascript -->


<programlisting language="javascript"><![CDATA[

<!-- XML -->


<programlisting language="xml"><![CDATA[

For program listings containing only PHP code, PHP tags (e.g., "<?php", "?>") are not required,
and should not be used. They simply clutter the narrative, and are implied by the use of the
<programlisting> tag.

<!-- NOT ALLOWED -->


<programlisting language="php"<![CDATA[<?php
// ...
?>]]></programlisting>

<programlisting language="php"<![CDATA[
<?php
// ...
?>
]]></programlisting>

Line lengths within program listings should follow the coding standards recommendations.

Refrain from using require_once(), require(), include_once(), and include() calls


within PHP listings. They simply clutter the narrative, and are largely obviated when using an
autoloader. Use them only when they are essential to the example.

Never use short tags

Short tags (e.g., "<?", "<?=") should never be used within programlisting or the
narrative of a document.

D.2.8. Notes on specific inline tags


D.2.8.1. classname
The tag <classname> must be used each time a class name is represented by itself; it should not
be used when combined with a method name, variable name, or constant, and no other content
is allowed within the tag.

<para>
The class <classname>Zend_Class</classname>.
</para>

D.2.8.2. varname
Variables must be wrapped in the <varname> tag. Variables must be written using the "$" sigil.
No other content is allowed within this tag, unless a class name is used, which indicates a class
variable.

<para>
The variable <varname>$var</varname> and the class variable
<varname>Zend_Class::$var</varname>.
</para>

1692
Zend Framework
Documentation Standard

D.2.8.3. methodname
Methods must be wrapped in the <methodname> tag. Methods must either include the full
method signature or at the least a pair of closing parentheses (e.g., "()"). No other content is
allowed within this tag, unless a class name is used, which indicates a class method.

<para>
The method <methodname>foo()</methodname> and the class method
<methodname>Zend_Class::foo()</methodname>. A method with a full signature:
<methodname>foo($bar, $baz)</methodname>
</para>

D.2.8.4. constant
Use the <constant> tag when denoting constants. Constants must be written in UPPERCASE.
No other content is allowed within this tag, unless a class name is used, which indicates a class
constant.

<para>
The constant <constant>FOO</constant> and the class constant
<constant>Zend_Class::FOO</constant>.
</para>

D.2.8.5. filename
Filenames and paths must be wrapped in the <filename> tag. No other content is allowed in
this tag.

<para>
The filename <filename>application/Bootstrap.php</filename>.
</para>

D.2.8.6. command
Commands, shell scripts, and program calls must be wrapped in the <command> tag. If the
command includes arguments, these should also be included within the tag.

<para>
Execute <command>zf.sh create project</command>.
</para>

D.2.8.7. code
Usage of the <code> tag is discouraged, in favor of the other inline tasks discussed previously.

D.2.9. Notes on specific block tags


D.2.9.1. title
The <title> tag is not allowed to hold other tags.

<!-- NOT ALLOWED -->


<title>Using <classname>Zend_Class</classname></title>

<!-- OK -->

1693
Zend Framework
Documentation Standard

<title>Using Zend_Class</title>

D.3. Recommendations
D.3.1. Use editors without autoformatting
For editing the documentation, typically you should not use formal XML editors. Such editors
normally autoformat existing documents to fit their own standards and/or do not strictly follow the
docbook standard. As examples, we have seen them erase the CDATA tags, change 4 space
separation to tabs or 2 spaces, etc.

The style guidelines were written in large part to assist translators in recognizing the lines that
have changed using normal diff tools. Autoformatting makes this process more difficult.

D.3.2. Use Images


Good images and diagrams can improve readability and comprehension. Use them whenever
they will assist in these goals. Images should be placed in the documentation/manual/en/
figures/ directory, and be named after the section identifier in which they occur.

D.3.3. Use Case Examples


Look for good use cases submitted by the community, especially those posted in proposal
comments or on one of the mailing lists. Examples often illustrate usage far better than the
narrative does.

When writing your examples for inclusion in the manual, follow all coding standards and
documentation standards.

D.3.4. Avoid Replicating phpdoc Contents


The manual is intended to be a reference guide for end-user usage. Replicating the phpdoc
documentation for internal-use components and classes is not wanted, and the narrative should
be focussed on usage, not the internal workings. In any case, at this time, we would like the
documentation teams to focus on translating the English manual, not the phpdoc comments.

D.3.5. Use Links


Link to other sections of the manual or to external sources instead of recreating documentation.

Linking to other sections of the manual may be done using either the <xref> tag (which will
substitute the section title for the link text) or the <link> tag (to which you must provide link text).

<para>
"Xref" links to a section: <xref
linkend="doc-standard.recommendations.links" />.
</para>

<para>
"Link" links to a section, using descriptive text: <link
linkend="doc-standard.recommendations.links">documentation on
links</link>.
</para>

To link to an external resource, use <ulink>:

1694
Zend Framework
Documentation Standard

<para>
The <ulink url="http://framework.zend.com/">Zend Framework site</ulink>.
</para>

1695
Annexe E. Recommended Project
Structure for Zend Framework MVC
Applications

Table des matières


E.1. Overview ............................................................................................................ 1696
E.2. Recommended Project Directory Structure ............................................................ 1696
E.3. Module Structure ................................................................................................. 1698
E.4. Rewrite Configuration Guide ................................................................................ 1699
E.4.1. Apache HTTP Server ............................................................................... 1699
E.4.2. Microsoft Internet Information Server ......................................................... 1699

E.1. Overview
Many developers seek guidance on the best project structure for a Zend Framework project
in a relatively flexible environment. A "flexible" environment is one in which the developer can
manipulate their file systems and web server configurations as needed to achieve the most ideal
project structure to run and secure their application. The default project structure will assume
that the developer has such flexibility at their disposal.

The following directory structure is designed to be maximally extensible for complex projects,
while providing a simple subset of folder and files for project with simpler requirements. This
structure also works without alteration for both modular and non-modular Zend Framework
applications. The .htaccess files require URL rewrite functionality in the web server as
described in the Rewrite Configuration Guide, also included in this appendix.

It is not the intention that this project structure will support all possible Zend Framework project
requirements. The default project profile used by Zend_Tool reflect this project structure, but
applications with requirements not supported by this structure should use a custom project profile.

E.2. Recommended Project Directory Structure


<project name>/
application/
configs/
application.ini
controllers/
helpers/
forms/
layouts/
filters/
helpers/
scripts/
models/
modules/
services/
views/
filters/

1696
Recommended Project Structure for
Zend Framework MVC Applications

helpers/
scripts/
Bootstrap.php
data/
cache/
indexes/
locales/
logs/
sessions/
uploads/
docs/
library/
public/
css/
images/
js/
.htaccess
index.php
scripts/
jobs/
build/
temp/
tests/

The following describes the use cases for each directory as listed.

• application/: This directory contains your application. It will house the MVC system, as
well as configurations, services used, and your bootstrap file.

• configs/: The application-wide configuration directory.

• controllers/, models/, and views/: These directories serve as the default controller,
model or view directories. Having these three directories inside the application directory
provides the best layout for starting a simple project as well as starting a modular project
that has global controllers/models/views.

• controllers/helpers/: These directories will contain action helpers. Action helpers


will be namespaced either as "Controller_Helper_" for the default module or
"<Module>_Controller_Helper" in other modules.

• layouts/: This layout directory is for MVC-based layouts. Since Zend_Layout is capable
of MVC- and non-MVC-based layouts, the location of this directory reflects that layouts are
not on a 1-to-1 relationship with controllers and are independent of templates within views/.

• modules/: Modules allow a developer to group a set of related controllers into a logically
organized group. The structure under the modules directory would resemble the structure
under the application directory.

• services/: This directory is for your application specific web-service files that are provided
by your application, or for implementing a Service Layer for your models.

• Bootstrap.php: This file is the entry point for your application, and should implement
Zend_Application_Bootstrap_Bootstrapper. The purpose for this file is to
bootstrap the application and make components available to the application by initializing
them.

• data/: This directory provides a place to store application data that is volatile and possibly
temporary. The disturbance of data in this directory might cause the application to fail. Also, the

1697
Recommended Project Structure for
Zend Framework MVC Applications

information in this directory may or may not be committed to a subversion repository. Examples
of things in this directory are session files, cache files, sqlite databases, logs and indexes.

• docs/: This directory contains documentation, either generated or directly authored.

• library/: This directory is for common libraries on which the application depends, and
should be on the PHP include_path. Developers should place their application's library code
under this directory in a unique namespace, following the guidelines established in the PHP
manual's Userland Naming Guide, as well as those established by Zend itself. This directory
may also include Zend Framework itself; if so, you would house it in library/Zend/.

• public/: This directory contains all public files for your application. index.php sets up and
invokes Zend_Application, which in turn invokes the application/Bootstrap.php
file, resulting in dispatching the front controller. The web root of your web server would typically
be set to this directory.

• scripts/: This directory contains maintenance and/or build scripts. Such scripts might
include command line, cron, or phing build scripts that are not executed at runtime but are part
of the correct functioning of the application.

• temp/: The temp/ folder is set aside for transient application data. This information would
not typically be committed to the applications svn repository. If data under the temp/ directory
were deleted, the application should be able to continue running with a possible decrease in
performance until data is once again restored or recached.

• tests/: This directory contains application tests. These could be hand-written, PHPUnit tests,
Selenium-RC based tests or based on some other testing framework. By default, library code
can be tested by mimicing the directory structure of your library/ directory. Additionally,
functional tests for your application could be written mimicing the application/ directory
structure (including the application subdirectory).

E.3. Module Structure


The directory structure for modules should mimic that of the application/ directory in the
recommended project structure:

<modulename>
configs/
application.ini
controllers/
helpers/
forms/
layouts/
filters/
helpers/
scripts/
models/
services/
views/
filters/
helpers/
scripts/
Bootstrap.php

The purpose of these directories remains exactly the same as for the recommended project
directory structure.

1698
Recommended Project Structure for
Zend Framework MVC Applications

E.4. Rewrite Configuration Guide


URL rewriting is a common function of HTTP servers. However, the rules and configuration differ
widely between them. Below are some common approaches across a variety of popular web
servers available at the time of writing.

E.4.1. Apache HTTP Server


All examples that follow use mod_rewrite, an official module that comes bundled with Apache.
To use it, mod_rewrite must either be included at compile time or enabled as a Dynamic Shared
Object (DSO). Please consult the Apache documentation for your version for more information.

E.4.1.1. Rewriting inside a VirtualHost


Here is a very basic virtual host definition. These rules direct all requests to index.php, except
when a matching file is found under the document_root.

<VirtualHost my.domain.com:80>
ServerName my.domain.com
DocumentRoot /path/to/server/root/my.domain.com/public

RewriteEngine off

<Location />
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ /index.php [NC,L]
</Location>
</VirtualHost>

Note the slash ("/") prefixing index.php; the rules for .htaccess differ in this regard.

E.4.1.2. Rewriting within a .htaccess file


Below is a sample .htaccess file that utilizes mod_rewrite. It is similar to the virtual host
configuration, except that it specifies only the rewrite rules, and the leading slash is omitted from
index.php.

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

There are many ways to configure mod_rewrite; if you would like more information, see Jayson
Minard's Blueprint for PHP Applications: Bootstrapping.

E.4.2. Microsoft Internet Information Server


As of version 7.0, IIS now ships with a standard rewrite engine. You may use the following
configuration to create the appropriate rewrite rules.

1699
Recommended Project Structure for
Zend Framework MVC Applications

<?xml version="1.0" encoding="UTF-8"?>


<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Imported Rule 1" stopProcessing="true">
<match url="^.*$" />
<conditions logicalGrouping="MatchAny">
<add input="{REQUEST_FILENAME}"
matchType="IsFile" pattern=""
ignoreCase="false" />
<add input="{REQUEST_FILENAME}"
matchType="IsDirectory"
pattern=""
ignoreCase="false" />
</conditions>
<action type="None" />
</rule>
<rule name="Imported Rule 2" stopProcessing="true">
<match url="^.*$" />
<action type="Rewrite" url="index.php" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

1700
Annexe F. Guide de performance Zend
Framework

Table des matières


F.1. Introduction ......................................................................................................... 1701
F.2. Chargement des classes ..................................................................................... 1701
F.2.1. Comment optimiser mon include_path ? ..................................................... 1701
F.2.2. Comment éliminer les déclarations require_once non nécessaires ? ............. 1703
F.2.3. Comment accélérer le chargement des plugins ? ........................................ 1704
F.3. Performance de Zend_Db .................................................................................... 1705
F.3.1. Comment réduire la surcharge introduite par Zend_Db_Table lors de la
récupération des métadonnées de table ? .......................................................... 1705
F.3.2. Le SQL généré avec Zend_Db_Select n'utilise pas mes index ; comment
améliorer ceci ? ................................................................................................ 1706
F.4. Internationalisation (i18n) and Localisation (l10n) .................................................. 1706
F.4.1. Quel adaptateur de traduction dois-je utiliser ? ........................................... 1706
F.4.2. Comment peut-on améliorer les performances de la traduction et de la
localisation ? ..................................................................................................... 1707
F.5. View Rendering ................................................................................................... 1707
F.5.1. How can I speed up resolution of view helpers? ......................................... 1707
F.5.2. How can I speed up view partials? ............................................................ 1709
F.5.3. How can I speed up calls to the action() view helper? ................................. 1709

F.1. Introduction
Le but de cette annexe est de fournir des stratégies concrètes afin d'améliorer les performances
de vos applications Zend Framework. Ce guide est présenté sous le format "Question &
Réponse" et est divisé en différents sujets de préoccupation.

F.2. Chargement des classes


Tous ceux qui ont déjà réalisé le profilage d'une application Zend Framework reconnaîtront
immédiatement que le chargement des classes y est relativement coûteux. Entre le nombre
important de fichier de classe qui doivent être chargées pour un grand nombre de composants
et l'utilisation des plugins qui n'impliquent pas une relation 1:1 entre leur nom de classe et le
système de fichier, les différents appels de include_once et require_once peuvent être
problématique. Ce chapitre a pour but de fournir des solutions concrètes pour solutionner ces
problèmes.

F.2.1. Comment optimiser mon include_path ?


Une optimisation triviale pour accélérer la vitesse de chargement des classes est de faire
attention à votre include_path. En particulier, vous devriez faire quatre choses : utilisez
des chemins absolus (ou des chemins relatifs à des chemins absolus), réduire le nombre
des chemins à inclure, définir le dossier de Zend Framework le plus tôt possible dans
l'include_path et inclure le dossier courant en dernier dans votre include_path.

1701
Guide de performance
Zend Framework

F.2.1.1. Utiliser des chemins absolus


Tandis que ceci peut sembler une micro-optimisation, le fait est que si vous ne le faites pas,
vous n'obtiendrez qu'un très petit avantage de la mise en cache du realpath de PHP, et en
conséquence, le cache d'opcode ne fonctionnera pas tout à fait comme vous pourriez l'imaginer.

Il y a deux manières simples de s'assurer de ceci. Premièrement, vous pouvez le mettre en


dur dans votre php.ini, httpd.conf, ou .htaccess. Deuxièmement, vous pouvez utiliser la
fonction realpath() de PHP au moment du paramétrage de votre include_path :

$paths = array(
realpath(dirname(__FILE__) . '/../library'),
'.',
);
set_include_path(implode(PATH_SEPARATOR, $paths);

Vous pouvez utiliser des chemins relatifs - du moment qu'ils sont relatifs à un chemin absolu :

define('APPLICATION_PATH', realpath(dirname(__FILE__)));
$paths = array(
APPLICATION_PATH . '/../library'),
'.',
);
set_include_path(implode(PATH_SEPARATOR, $paths);

Néanmoins, c'est typiquement une tâche insignifiante de fournir simplement le chemin à


realpath().

F.2.1.2. Réduire le nombre de dossier défini dans l'include_path


Les chemins d'inclusion sont scannés dans l'ordre dans lequel ils apparaissent dans
l'include_path. Évidemment, ceci veut dire que vous aurez un résultat plus rapide si le fichier
est trouvé dans le premier chemin scanné que si vous le trouvez dans le dernier chemin scanné.
De plus, une amélioration plutôt évidente est de diminuer tout simplement le nombre de chemins
dans votre include_path à seulement de ce que vous avez réellement besoin. Regardez
chaque chemin que vous avez défini dans votre include_path pour déterminer si vous avez
réellement besoin d'une fonctionnalité dans votre application ; si ce n'est pas le cas, enlevez le.

Une autre optimisation consiste en la combinaison de chemins. Par exemple, Zend Framework
suit la convention de nommage PEAR ; ainsi , si vous utilisez des librairies PEAR (ou d'autres
framework ou librairies de composants qui respectent la convention de nommage PEAR),
essayez de mettre toutes ces librairies dans le même chemin de l'include_path. Ceci peut
souvent être réalisé par quelque chose d'assez simple comme de créer des liens symboliques
vers une ou plusieurs bibliothèques dans un dossier commun.

F.2.1.3. Définir le dossier de Zend Framework le plus tôt possible dans


l'include_path
Pour continuer avec les suggestions précédentes, une autre optimisation évidente est de définir
le dossier de Zend Framework le plus tôt possible dans votre include_path. Dans la plupart
des cas, il devrait être le premier de la liste. Ceci permet de s'assurer les fichiers de Zend
Framework à inclure le sont dès le premier scan.

F.2.1.4. Définir le dossier courant le plus tard possible ou pas du tout


La plupart des exemples d'include_path montre l'utilisation du répertoire courant ("."). Ceci
est pratique pour s'assurer que les scripts dans le même dossier que le fichier courant peuvent

1702
Guide de performance
Zend Framework

aussi être chargés. Cependant ces mêmes exemples montrent souvent ce dossier comme étant
le premier de la liste des include_path - ce qui veut dire l'arbre de dossiers courant est toujours
scanné en premier. La plupart du temps, avec Zend Framework, ce n'est pas nécessaire, et ce
dossier peut tout naturellement être mis en dernière position de la liste.

Exemple F.1. Exemple : optimisation de l'include_path

Essayons de mettre ensemble toutes ces suggestions. Considérons que nous utilisons une
ou plusieurs composants PEAR en conjonction avec Zend Framework - par exemple les
composants PHPUnit et Archive_Tar - et qu'il est occasionnellement nécessaire d'inclure
les fichiers relativement au fichier courant.

Premièrement, nous allons créer un dossier pour les librairies dans notre projet. Dans ce
même dossier, nous allons créer un lien symbolique vers notre dossier Zend Framework
"library/Zend", ainsi que les dossiers nécessaires dans notre installation PEAR :

library
Archive/
PEAR/
PHPUnit/
Zend/

Ceci nous permet d'ajouter notre propre librairie si nécessaire, tout en laissant intact les
librairies partagées.

Ensuite, nous optons pur la création de notre include_path par programme à l'intérieur
de notre fichier public/index.php. Ceci nous permet de déplacer notre code dans le
système de fichiers, sans devoir éditer l'include_path à chaque fois.

Nous emprunterons des idées à chacune des suggestions ci-dessus : nous utiliserons
les chemins absolus, déterminé en utilisant le realpath() ; nous positionnerons Zend
Framework au plus tôt dans l'include_path ; nous avons déjà vérifié les chemins
d'inclusions nécessaires ; et nous mettrons le dossier courant comme dernier chemin. En
fait, nous faisons tout bien ici - nous allons donc terminer avec seulement deux chemins.

$paths = array(
realpath(dirname(__FILE__) . '/../library'),
'.'
);
set_include_path(implode(PATH_SEPARATOR, $paths));

F.2.2. Comment éliminer les déclarations require_once non


nécessaires ?
Le chargement tardif ("lazy loading") est une technique d'optimisation conçue pour repousser
l'opération coûteuse de chargement d'une classe jusqu'au dernier moment possible - c'est-à-
dire lors de l'instanciation d'un objet de cette classe, ou lors de l'utilisation d'une constante de
classe ou d'une propriété statique. PHP supporte tout ceci via l'autoloading (ou "chargement
automatique"), ce qui vous permet de définir un ou plusieurs callbacks à exécuter dans le but
de faire correspondre un nom de classe à un fichier.

Cependant, la plupart des avantages que vous pourrez retirer de l'autoloading sont diminués si
le code de votre librairie exécute toujours des appels à require_once - ce qui est précisément
le cas de Zend Framework. La question est donc : comment éliminer ces déclarations
require_once dans le but de maximiser les performances de l'autoloader.

1703
Guide de performance
Zend Framework

F.2.2.1. Effacer les appels de require_once avec find et sed


Une manière simple d'effacer les appels require_once est d'utiliser les utilitaires Unix "find" en
conjonction avec "sed" pour passe en commentaires tous les appels. Essayez d'exécuter les
commandes suivantes (où "%" indique le prompteur shell) :

% cd chemin/vers/la/librarie/ZendFramework
% find . -name '*.php' -not -wholename '*/Loader/Autoloader.php' \
-not -wholename '*/Application.php' -print0 | \
xargs -0 sed --regexp-extended --in-place 's/(require_once)/\/\/ \1/g'

Cette ligne unique (coupée en deux pour la lisibilité) itère parmi les fichiers PHP et y remplace
toute les instances de require_once par //require_once, c'est-à-dire en commentant
toutes ces lignes (tout en maintenant les appels à require_once dans Zend_Application
et Zend_Loader_Autoloader, puisque ces classes tomberont en erreur sans ceux-ci).

Cette commande peut être simplement ajoutée à un script de construction automatique ou à


un processus de mise en production, permettent ainsi d'augmenter les performances de votre
application en production. Il est à noter, cependant, que si vous utilisez cette technique, vous
devez utiliser l'autoloading ; vous pouvez l'activer dans votre fichier public/index.php en
ajoutant le code suivant :

require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();

F.2.3. Comment accélérer le chargement des plugins ?


Certains composants utilisent les plugins, ce qui vous permet de créer vos propres classes afin
de les utiliser avec le composant, de même que de surcharger les plugins standard existants
embarqués dans Zend Framework. Ceci fournit une importante flexibilité au framework, mais a
un prix : le chargement des plugins est une tâche assez coûteuse.

Le chargeur de plugins vous permet de définir des paires préfixe de classe / chemin, vous
autorisant ainsi à spécifier des fichiers de classe dans des chemins de dossiers non standard.
Chaque préfixe peut avoir de multiples chemins associés. En interne, le chargeur de plugins
boucle à travers chaque préfixe, et ensuite à travers chaque chemin lui étant associé, en testant
l'existence du fichier et s'il est accessible dans ce chemin. Il le charge ensuite, et teste pour voir
si la classe recherchée est bien disponible. Comme vous pouvez l'imaginer, tout ceci entraîne
des appels aux stats du système de fichiers.

Multipliez ceci par le nombre de composants qui utilisent le PluginLoader, et vous aurez une
idée de l'importance de ce problème. Au moment de l'écriture de ce document, les composants
suivants utilisent le PluginLoader :

• Zend_Controller_Action_HelperBroker : aides d'action

• Zend_Dojo : aides de vues, éléments de formulaires et décorateurs

• Zend_File_Transfer : adaptateurs

• Zend_Filter_Inflector : filtres (utilisé par l'aide d'action ViewRenderer et


Zend_Layout)

• Zend_Filter_Input : filtres et validateurs

1704
Guide de performance
Zend Framework

• Zend_Form : éléments, validateurs, filtres, décorateurs, captcha et adaptateur pour les


transferts de fichiers

• Zend_Paginator : adaptateurs

• Zend_View : aides de vues, filtres

Comment réduire le nombre des appels réalisés ?

F.2.3.1. Utiliser le fichier de cache des inclusions du PluginLoader


Zend Framework 1.7.0 ajoute un fichier de cache des inclusions au PluginLoader. Cette
fonctionnalité écrit dans un fichier les appels "include_once", que vous pouvez ensuite inclure
dans votre fichier d'amorçage. Même si ceci introduit de nouveaux appels include_once dans
votre code, cela permet de s'assurer que le PluginLoader les retournera au plus vite.

La documentation du PluginLoader inclue un exemple complet de son utilisation.

F.3. Performance de Zend_Db


Zend_Db est une couche d'abstraction pour les bases de données, et a pour but de fournir une
API commune pour les opérations SQL. Zend_Db_Table est un Table Data Gateway, dont le
but est d'abstraire les opérations communes de niveau table. A cause de cette nature abstraite et
de la manière suivant laquelle sont réalisées ces opérations, ces composants peuvent introduire
des pertes de performances.

F.3.1. Comment réduire la surcharge introduite par


Zend_Db_Table lors de la récupération des métadonnées de
table ?
Dans le but de maintenir une utilisation la plus simple possible, et aussi de supporter un
changement de schéma permanent au cours du développement, Zend_Db_Table réalise une
série d'action en arrière-plan à la première utilisation, il analyse le schéma de la table et le stocke
dans les propriétés de l'objet. Cette opération est typiquement coûteuse, indépendamment de
la base de données -- ce qui peut contribuer à des goulots en production.

Toutefois, ils existent des techniques permettant d'améliorer ceci.

F.3.1.1. Utiliser le cache des métadonnées


Zend_Db_Table peut optionnellement utiliser Zend_Cache pour mettre en cahce les
métadonnées de la table. C'est typiquement plus rapide d'accès et moins coûteux que d'accéder
à ces métadonnées directement dans la base de données.

La documentation de Zend_Db_Table inclue des informations concernant la mise en cache


des métadonnées.

F.3.1.2. Mettre en dur les métadonnées dans votre définition de table


A partir de la version 1.7.0, Zend_Db_Table fournit aussi le support permettant de stocker les
métadonnées en dur dans la définition de la table. Ceci est un cas d'utilisation très avancé,
et ne devrait être utilisé que lorsque vous êtes que votre schéma de base de données évolue
rarement, ou que vous êtes certain de pouvoir maintenir à jour ces définitions.

1705
Guide de performance
Zend Framework

F.3.2. Le SQL généré avec Zend_Db_Select n'utilise pas mes


index ; comment améliorer ceci ?
Zend_Db_Select est plutôt bon dans son trvail. Cependant si vous avez des requêtes
complexes requiérant des jointures ou des sous-sélections, il est souvent assez naïf.

F.3.2.1. Ecrire votre SQL amélioré


La seule véritable réponse est d'écrire vous même votre propre SQL ; Zend_Db n'oblige pas
l'utilisation de Zend_Db_Select, donc fournir votre propre instruction SQL de sélection est une
approche parfaitement légitime.

Effectuez un EXPLAIN sur vos requêtes, et testez plusieurs approches jusqu'à obtenir un indice
le plus performant, ensuite écrivez en dur votre SQL en tant que propriété de la classe ou comme
constante.

Si votre SQL requiert des arguments variables, fournissez des emplacements réservés dans
votre SQL, et utilisez une combinaison de vsprintf() et array_walk() pour injecter les
valeurs dans votre SQL :

// $adapter est l'adaptateur de base de données. Dans Zend_Db_Table,


// vous le récupérez en appelant $this->getAdapter().
$sql = vsprintf(
self::SELECT_FOO,
array_walk($values, array($adapter, 'quoteInto'))
);

F.4. Internationalisation (i18n) and Localisation (l10n)


Internationaliser et localiser un site sont des manières fantastiques d'étendre votre audience
et de s'assurer que tous les visiteurs peuvent trouver l'information dont ils ont besoin.
Cependant, ceci entraîne souvent une dégradation de performance. Ci-dessous vous trouverez
des stratégies à utiliser pour réduire la surcharge due à l'I18N et à la L10N.

F.4.1. Quel adaptateur de traduction dois-je utiliser ?


Tous les adaptateurs de traduction ne sont pas conçus de la même façon. Certains ont plus
de fonctionnalités que d'autres, et certains sont plus performants que d'autres. De plus, vous
pouvez avoir des contraintes qui vous forcent à utiliser un adaptateur en particulier. Cependant
si vous avez le choix, quels adaptateurs sont les plus rapides ?

F.4.1.1. Utiliser les adaptateurs de traduction non-XML pour plus de


rapidité
Zend Framework embarque toute une variété d'adaptateurs de traduction. Une moitié de ceux-
ci utilisent un format XML, entraînant une surcharge mémoire et des pertes de performance.
Heureusement, il existe plusieurs adaptateurs basés sur d'autres formats qui peuvent être
analysés beaucoup plus rapidement. Par ordre de vitesse, du plus rapide au plus lent, ils sont :

• Array : celui-ci est le plus rapide, puisqu'il est, par définition, analysé dans un format natif de
PHP immédiatement lors de son inclusion.

• CSV : utilises fgetcsv() pour analyser un fichier CSV file et le transforme en un format PHP
natif.

1706
Guide de performance
Zend Framework

• INI : utilises parse_ini_file() pour analyser un fichier INI file et le transforme en un format
PHP natif. Celui-ci et l'adaptateur CSV sont équivalent en terme de performance.

• Gettext : l'adaptateur Gettext de Zend Framework n'utilise pas l'extension gettext puisqu'elle
n'est pas thread safe et ne permet pas de spécifier plus d'une locale par serveur. En
conséquence, il est plus lent que d'utiliser l'extension Gettext directement, mais comme le
format Gettext est binaire, il reste plus rapide à analyser qu'un format XML.

Si l'un de vos besoins principaux est la performance, nous vous conseillons d'utiliser l'un des
adaptateurs ci-dessus.

F.4.2. Comment peut-on améliorer les performances de la


traduction et de la localisation ?
Peut-être, pour certaines raisons, vous êtes limité à un adaptateur de traduction de type XML.
Ou peut-être vous voudriez accélérer des choses encore plus. Ou peut-être vous voulez rendre
des opérations de localisation plus rapides. Comment pouvez-vous faire ceci ?

F.4.2.1. Utiliser les caches de traductions et de localisation


A la fois Zend_Translate et Zend_Locale implémente une fonctionnalité de mise en cache
qui peuvent considérablement améliorer les performances. Dans chacun des cas, le goulot
principal est typiquement la lecture des fichiers, pas la réelle consultation ; la mise en cache
élimine la nécessité de relire de nouveau les fichiers de traduction ou de localisation.

Vous pouvez lire plus d'informations concernant la mise en cache d'informations de traduction
ou de localisation dans les paragraphes suivants :

• Mise en cache pour Zend_Translate

• Mise en cache pour Zend_Locale

F.5. View Rendering


When using Zend Framework's MVC layer, chances are you will be using Zend_View.
Zend_View is performs well compared to other view or templating engines; since view scripts
are written in PHP, you do not incur the overhead of compiling custom markup to PHP, nor do
you need to worry that the compiled PHP is not optimized. However, Zend_View presents its
own issues: extension is done via overloading (view helpers), and a number of view helpers,
while carrying out key functionality do so with a performance cost.

F.5.1. How can I speed up resolution of view helpers?


Most Zend_View "methods" are actually provided via overloading to the helper system. This
provides important flexibility to Zend_View; instead of needing to extend Zend_View and
provide all the helper methods you may utilize in your application, you can define your helper
methods in separate classes and consume them at will as if they were direct methods of
Zend_View. This keeps the view object itself relatively thin, and ensures that objects are created
only when needed.

Internally, Zend_View uses the PluginLoader to look up helper classes. This means that for
each helper you call, Zend_View needs to pass the helper name to the PluginLoader, which
then needs to determine the class name, load the class file if necessary, and then return the class
name so it may be instantiated. Subsequent uses of the helper are much faster, as Zend_View
keeps an internal registry of loaded helpers, but if you use many helpers, the calls add up.

1707
Guide de performance
Zend Framework

The question, then, is: how can you speed up helper resolution?

F.5.1.1. Use the PluginLoader include file cache


The simplest, cheapest solution is the same as for general PluginLoader performance: use the
PluginLoader include file cache. Anecdotal evidence has shown this technique to provide a
25-30% performance gain on systems without an opcode cache, and a 40-65% gain on systems
with an opcode cache.

F.5.1.2. Extend Zend_View to provide often used helper methods


Another solution for those seeking to tune performance even further is to extend Zend_View to
manually add the helper methods they most use in their application. Such helper methods may
simply manually instantiate the appropriate helper class and proxy to it, or stuff the full helper
implementation into the method.

class My_View extends Zend_View


{
/**
* @var array Registry of helper classes used
*/
protected $_localHelperObjects = array();

/**
* Proxy to url view helper
*
* @param array $urlOptions Options passed to the assemble method
* of the Route object.
* @param mixed $name The name of a Route to use. If null it will
* use the current Route
* @param bool $reset Whether or not to reset the route defaults
* with those provided
* @return string Url for the link href attribute.
*/
public function url(array $urlOptions = array(), $name = null,
$reset = false, $encode = true
) {
if (!array_key_exists('url', $this->_localHelperObjects)) {
$this->_localHelperObjects['url'] = new Zend_View_Helper_Url();
$this->_localHelperObjects['url']->setView($this);
}
$helper = $this->_localHelperObjects['url'];
return $helper->url($urlOptions, $name, $reset, $encode);
}

/**
* Echo a message
*
* Direct implementation.
*
* @param string $string
* @return string
*/
public function message($string)
{
return "<h1>" . $this->escape($message) . "</h1>\n";
}
}

1708
Guide de performance
Zend Framework

Either way, this technique will substantially reduce the overhead of the helper system by
avoiding calls to the PluginLoader entirely, and either benefiting from autoloading or bypassing
it altogether.

F.5.2. How can I speed up view partials?


Those who use partials heavily and who profile their applications will often immediately notice
that the partial() view helper incurs a lot of overhead, due to the need to clone the view
object. Is it possible to speed this up?

F.5.2.1. Use partial() only when really necessary


The partial() view helper accepts three arguments:

• $name: the name of the view script to render

• $module: the name of the module in which the view script resides; or, if no third argument is
provided and this is an array or object, it will be the $model argument.

• $model: an array or object to pass to the partial representing the clean data to assign to the
view.

The power and use of partial() come from the second and third arguments. The $module
argument allows partial() to temporarily add a script path for the given module so that the
partial view script will resolve to that module; the $model argument allows you to explicitly pass
variables for use with the partial view. If you're not passing either argument, use render()
instead!

Basically, unless you are actually passing variables to the partial and need the clean variable
scope, or rendering a view script from another MVC module, there is no reason to incur the
overhead of partial(); instead, use Zend_View's built-in render() method to render the
view script.

F.5.3. How can I speed up calls to the action() view helper?


Version 1.5.0 introduced the action() view helper, which allows you to dispatch an MVC action
and capture its rendered content. This provides an important step towards the DRY principle,
and promotes code reuse. However, as those who profile their applications will quickly realize, it,
too, is an expensive operation. Internally, the action() view helper needs to clone new request
and response objects, invoke the dispatcher, invoke the requested controller and action, etc.

How can you speed it up?

F.5.3.1. Use the ActionStack when possible


Introduced at the same time as the action() view helper, the ActionStack consists of an
action helper and a front controller plugin. Together, they allow you to push additional actions
to invoke during the dispatch cycle onto a stack. If you are calling action() from your layout
view scripts, you may want to instead use the ActionStack, and render your views to discrete
response segments. As an example, you could write a dispatchLoopStartup() plugin like
the following to add a login form box to each page:

class LoginPlugin extends Zend_Controller_Plugin_Abstract


{
protected $_stack;

1709
Guide de performance
Zend Framework

public function dispatchLoopStartup(


Zend_Controller_Request_Abstract $request
) {
$stack = $this->getStack();
$loginRequest = new Zend_Controller_Request_Simple();
$loginRequest->setControllerName('user')
->setActionName('index')
->setParam('responseSegment', 'login');
$stack->pushStack($loginRequest);
}

public function getStack()


{
if (null === $this->_stack) {
$front = Zend_Controller_Front::getInstance();
if (!$front->hasPlugin('Zend_Controller_Plugin_ActionStack')) {
$stack = new Zend_Controller_Plugin_ActionStack();
$front->registerPlugin($stack);
} else {
$stack = $front->getPlugin('ActionStack')
}
$this->_stack = $stack;
}
return $this->_stack;
}
}

The UserController::indexAction() method might then use the $responseSegment


parameter to indicate which response segment to render to. In the layout script, you would then
simply render that response segment:

<?php $this->layout()->login ?>

While the ActionStack still requires a dispatch cycle, this is still cheaper than the action() view
helper as it does not need to clone objects and reset internal state. Additionally, it ensures that
all pre and post dispatch plugins are invoked, which may be of particular concern if you are using
front controller plugins for handling ACL's to particular actions.

F.5.3.2. Favor helpers that query the model over action()


In most cases, using action() is simply overkill. If you have most business logic nested in
your models and are simply querying the model and passing the results to a view script, it will
typically be faster and cleaner to simply write a view helper that pulls the model, queries it, and
does something with that information.

As an example, consider the following controller action and view script:

class BugController extends Zend_Controller_Action


{
public function listAction()
{
$model = new Bug();
$this->view->bugs = $model->fetchActive();
}
}

// bug/list.phtml:

1710
Guide de performance
Zend Framework

echo "<ul>\n";
foreach ($this->bugs as $bug) {
printf("<li><b>%s</b>: %s</li>\n",
$this->escape($bug->id),
$this->escape($bug->summary)
);
}
echo "</ul>\n";

Using action(), you would then invoke it with the following:

<?php $this->action('list', 'bug') ?>

This could be refactored to a view helper that looks like the following:

class My_View_Helper_BugList extends Zend_View_Helper_Abstract


{
public function bugList()
{
$model = new Bug();
$html = "<ul>\n";
foreach ($model->fetchActive() as $bug) {
$html .= sprintf(
"<li><b>%s</b>: %s</li>\n",
$this->view->escape($bug->id),
$this->view->escape($bug->summary)
);
}
$html .= "</ul>\n";
return $html;
}
}

You would then invoke the helper as follows:

<?php $this->bugList() ?>

This has two benefits: it no longer incurs the overhead of the action() view helper, and also
presents a more semantically understandable API.

1711
Annexe G. Informations de copyright
Les droits ci-dessous sont applicables aux éléments de Zend Framework.

Copyright © 2005-2010 Zend Technologies Inc. (http://www.zend.com)

1712

Das könnte Ihnen auch gefallen