Je me concentrerai sur trois fichiers:

  • le .htaccess
  • le index.php
  • le bootstrap.php

et j’introduirai l’utilisation des plugins.

.htaccess

Une application web MVC et plus précisément ZF utilise la réécriture d’url car elle a besoin de savoir quelle action effectuer et non quel fichier charger. Il ne peut donc y avoir qu’un seul et unique point d’entrée (cf le contrôleur frontal) et ce fichier donnera le “top départ” pour notre application.

Nous utiliserons un fichier nommer .htaccess, qui nous permettra de réécrire la requête et de renvoyer le tout vers le index.php. Pour que ce .htaccess fonctionne correctement il faut au préalable vérifier certaines informations dans la configuration du serveur apache.
Vérifiez si le module rewrite est bien installé et activé:

Sous linux

/etc/apache2/mods-available contient les modules installés /etc/apache2/mods-enabled contient les modules activés.( liens symboliques vers les fichiers du répertoire mods-available)
Dans le fichier /etc/apache2/httpd.conf, vérifiez maintenant que la directive AllowOverride est bien à all pour le répertoire /var/www.

Sous Windows

Il faut que le module Rewrite soit activé dans le fichier PATH\TO\wamp\bin\apache\Apache2.2.11\conf\httpd.conf.
Il suffira (si le module est installé) de dé-commenter la ligne suivante:
LoadModule rewrite_module modules/mod_rewrite.so Vérifiez maintenant que la directive AllowOverride pour le répertoire ./www a bien la valeur all.
Maintenant nous pouvons utiliser le .htaccess suivant:

#activation la réécriture d'URL
RewriteEngine On
 
##CONDITIONS##
 
#si fichier non vide
RewriteCond %{REQUEST_FILENAME} -s [OR]
#si lien symbolique
RewriteCond %{REQUEST_FILENAME} -l [OR]
#si répertoire
RewriteCond %{REQUEST_FILENAME} -d
 
##REECRITURE##
 
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
 
##CONFIGURATION PHP##
 
#PAS d'échappement des caractères spéciaux des chaînes provenant de Get, Post ou Cookie.
php_flag magic_quotes_gpc off
 
#variables EGPCS non globales
php_flag register_globals off
 
#balises courtes d'ouverture de PHP (<? <?= )
php_flag short_open_tag on

plus de détail sur la réécriture d’URL

index.php

Toutes nos requêtes sont maintenant redirigées vers le index.php.
Mais que contient-il donc de si intéressant pour que tout le monde veuille y aller ?!

<?php
 
set_include_path('.'
. PATH_SEPARATOR . './library'
. PATH_SEPARATOR . './application/models/'
. PATH_SEPARATOR . get_include_path());
 
// Définit le chemin du repértoire de l'application
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . './application'));
// Définit l'environnement de l'application
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'test'));
 
require_once 'Zend/Application.php';
 
// Création de l'application
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
 
$application->bootstrap()
           ->run();

Hum hum… Pas grand chose en effet…

Détrompez-vous, tout ceci à une importance capitale car c’est ici qu’est lancée et configurée la base de votre application!

En détail:

set_include_path modifie la valeur de la directive de configuration include_path en ajoutant les chemins par défaut qu’utiliseront les fonctions du type require, include, etc...

Nous pointerons bien sur sur notre répertoire library contenant celle de Zend (et bientôt la notre) puis sur le répertoire de nos modèles. Cela nous permettra dans un futur proche d’appeler plus facilement nos classes.

Les define vont servir à déclarer des constantes qui seront donc utilisables n’importe où dans l’application. Il ne faut surtout pas en abuser mais, bien utilisées, elles s’avèrent très pratiques. Par exemple ici nous définissons la constante APPLICATION_PATH qui nous permettra d’accéder au répertoire « application » sans devoir « coder en dur » le chemin.
Si par exemple votre application doit migrer de la racine d’un serveur vers un sous-répertoire, avec les constantes définies ci dessus il n’y aura aucune modification du code car realpath(dirname(FILE) renvoi le chemin du fichier index.php et c’est sur celui-ci que sont basées nos constantes.

Maintenant que l’application sait où elle se trouve, elle peut se lancer!

Zend_Application

Parlons maintenant de notre fichier INI. Je vous laisse le soin de vous renseigner sur cette extension, de ses points forts et points faibles, elle n’en reste pas moins celle utilisée par défaut dans la doc.

Ce fichier va regrouper de manière déclarative des informations dont notre application a besoin pour se lancer (ressources), elles seront chargées automatiquement à condition bien sur de respecter leur nommage. Ceci va nous éviter de coder « en dur » la gestion de certaines ressources et donc alléger notre bootstrap.

[production]
 
;definition de la timezone
phpsettings.date.timezone = "Europe/Paris"
 
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"
 
;Espaces de nom
autoloadernamespaces[] = "Zend_"
autoloadernamespaces[] = "Lib_"
 
;initialisation du contrôleur frontal
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
 
[test:production]
;affichage des erreur
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

Nous avons tout d’abord déclaré une section « production » qui regroupe les options utilisées pour la mise en production de l’application. Dans cette section, vous pouvez voir qu’il est précisé le chemin de notre fichier de boot pour qu’il soit automatiquement chargé et les espaces de noms utilisées dans l’application :

  • Zend pour la librairie ZF
  • Lib pour notre librairie personnalisée

Nous allons aussi indiquer où se trouve le répertoire de nos contrôleurs. Voyez l’importance de notre constante APPLICATION_PATH !

Ensuite nous avons déclaré une section « test » (d’où la constante APLICATION_ENV). Elle hérite de « production » et va ajouter l’affichage des erreurs et même celles issues de la séquence de démarrage de php, ce qui est quand même plus pratique pour le débuggage!

Nous ajouterons de nouvelles informations dans ce fichier au fur et à mesure du tuto pour par exemple la base de données ou les plugins.

Le Bootstrap

Le bootstrap est une classe qui permet l’initialisation manuelle de ressources pour compléter celles déjà initialisées automatiquement via Zend_Application et application.ini. Cette classe va nous servir à regrouper les actions bas niveaux et redondantes de l’application telle que l’initialisation de la bdd, du layout, des droits, etc.

Voici à quoi elle ressemble:

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
protected function _initMethod(){}
}

Chaque méthode préfixée par « _init » sera automatiquement appelée par la méthode bootstrap() de la classe Zend_Application_Bootstrap_Bootstrap que nous étendons (plus précisément par la classe abstraite de celle-ci).

En clair on à rien à faire de ce coté là, juste à ajouter nos méthodes!

Pour commencer nous allons configurer l’autoloader pour un chargement global de tous les espaces de noms.

protected function _initAutoLoader() {
            $autoload = Zend_Loader_Autoloader::getInstance();
            $autoload->setFallbackAutoloader(true);</pre>
}

mais il est tout à fait possible de restreindre son étendue pour ne capturer que ceux dont vous avez besoin via la méthode:

/[php]
$autoload->registerNamespace('My_');

La classe Zend_Loader_Autoloader est un Singleton, ce qui nous permettra si besoin d’enregistrer un nouvel autoloader de n’importe quelle classe de notre application, nous ne le ferons pas mais c’est toujours bon à savoir.

Revenons à nos moutons ou plutôt à nos fonctions !
Passons à la configuration de notre base de données.

Les paramètres de connexion seront externalisés dans notre fichier application.ini de la manière suivante:

[test:production]
...
;conf db
resources.db.adapter = PDO_MYSQL
resources.db.params.host = localhost
resources.db.params.username = root
resources.db.params.password =
resources.db.params.dbname = test
resources.db.params.charset = utf-8

Dans les articles suivants, j’utiliserais cette base de données:” database debuter avec zend

Pour retrouver ces informations dans notre bootstrap nous utiliserons la méthode $this->getOptions() qui nous renverra le contenu du fichier.

protected function _initDb() {
            //chargement des donées du fichier application.ini
            $config = new Zend_Config($this->getOptions());
 
            //test de la connexion avec l'adapateur créé
            try {
                  $db = Zend_Db::factory($config->resources->db);
                  $db->getConnection();
            }catch (Exception $e) {
                  exit( $e->getMessage() );
            }
            //configuration de l'adaptateur par defaut pour nos tables
            Zend_Db_Table::setDefaultAdapter($db);
 
            //mise en registre de notre adatateur
            Zend_Registry::set( 'db', $db );
            return $db;
      }

Quelques petites précisions sur Zend_Db_Table. Cette classe propose une méthode static utilisant le design pattern « Factory ». Cela va nous permettre d’instancier un adaptateur dont le type n’est pas prédéfini (nous le définissons dans le fichier ini).
Le design pattern « Adapter » est utilisé pour faire la liaison et créer des correspondances entre deux interfaces qui ne peuvent communiquer. Ici nous utiliserons PDO_MYSQL pour communiquer avec notre base de données.

Ce code nous a permis de voir quelques notions intéressantes mais n’est plus à jour depuis la version 1.10 de ZF qui automatise tout ça. Si vous y êtes passé, il faut ajouter cette ligne au fichier application.ini:

resources.db.isDefaultTableAdapter = true

et le code de notre méthode deviendra:

protected function _initDb() {
            $resource = $bootstrap->getPluginResource('db');
            try {
                  $db = $resource->getDbAdapter();
                  $db->getConnection();
            }catch ( Exception $e) {
                  exit( $e -> getMessage() );
            }
            Zend_Registry::set('db',$db);
      }

Ah bah oui, ça change un peu…

Zend_Registry est une classe de type Singleton qui hérite de la classe native php « ArrayObject » donc utilisable aussi comme un tableau. Elle va nous permettre de stocker des données ou objets de manière statique et donc accessibles partout dans l’application. A ne pas confondre avec le stockage en session.

À propos des plugins

Lorsque l’on passe à des applications un peu plus complexes, on se rend vite compte que la classe bootstrap seule devient assez limitée et ne nous permet pas une gestion complète des traitements ou tout du moins pas de manière structurée et facilement maintenable. Ainsi d’autres moyens sont mises à notre disposition pour pouvoir séparer sous forme de classes les ressources et traitements à mettre en place.

Je n’approfondirais pas ces notions ici car elles seront abordées plus précisément dans les prochains articles.

Plugin de ressource : Zend_Application_Resource_ResourceAbstract

C’est une classe abstraite que nous pouvons étendre pour créer nos propre plugins de ressources (exemple: objet View ou Layout personnalisé). Elle consiste principalement en une méthode init() qu’il faut définir pour initialiser et configurer une ressource particulière, elle sera appelée automatiquement à la suite de __construct(). Ainsi dans votre bootstrap, vous pourrez initialiser et récupérer vos plugins de cette façon:

//initialisation
$this->bootstrap('My_Resource');
//récupération de l'objet retourné par la méthode init()
$ressource = $this->getResource('My_Resource');

En résumé notre plugin va créer une ressource plus ou moins dans son coin et va la renvoyer au bootstrap pour qu’il continue sont travail.

Plugin de contrôle : Zend_Controller_Plugin_Abstract

Les plugins du contrôleur frontal permettent d’injecter du code à un moment précis de l’application, ils apportent donc des modifications selon la requête effectuée. Leur fonctionnement est un peu plus complexe que les plugins de ressources (voir la doc).

Typiquement nous les utiliserons pour la gestion des erreurs ou des ACL.

class Lib_Controller_Plugin_Auth extends Zend_Controller_Plugin_Abstract {
      public function preDispatch(Zend_Controller_Request_Abstract $request) {}
}

La méthode qui sera le plus souvent utilisée sera preDispatch(), elle donne accès à la requête entrante $request avant que l’action soit distribuée soit avant tout traitement, elle nous permettra donc d’agir comme filtre de requête, ce qui est très pratique!

Cette article touche à sa fin, si l’on devait comparer notre application à une maison, on pourrait dire que l’on vient d’y installer une porte d’entrée!

Mais à quoi sert une porte sur une maison vide ?! Nous poursuivrons donc le chantier au prochain article!