Documentation FuelPHP 1.7.3

FuelPHP

Traducteur

Christophe LOUVET

Ce tutoriel est une traduction française de la documentation officielle de FuelPHP. C'est un cours qui vous permettra d'apprendre ce framework pour PHP.

Commentez ♪

- Titre : Documentation FuelPHP 1.7.3

- Auteur : FuelPHP

- Traducteur : Christophe LOUVET

- Parution : 8 décembre 2015

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2015 Equipe PHP. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- 1. Bienvenue dans FuelPHP

- 1-1. Prérequis

- 1-2. Installation rapide

- 1-3. Installation manuelle

- 1-4. Étapes suivantes

- 2. Installation rapide

- 2-1. Installation en ligne de commande

- 3. Installation manuelle

- 3-1. Clonage de la dernière version depuis github

- 3-2. Clonage de la dernière version de la branche de développement depuis github

- 3-3. Téléchargement du fichier zippé

- 4. Composer

- 5. Configuration

- 5-1. Installation dans le dossier DocumentRoot

- 5-2. Qu'en est-il des dossiers à plusieurs niveaux de sous-répertoires ?

- 5-2-1. Apache

- 5-2-2. Nginx

- 5-3. Configurer l'environnement

- 6. Configurez votre nouvelle installation

- 6-1. Introduction

- 6-2. Options de configuration

- 7. Modèle vue contrôleur (MVC)

- 7-1. Qu'est-ce que MVC

- 7-2. Les contrôleurs

- 7-2-1. Qu'est-ce qu'un contrôleur ?

- 7-2-2. Créer un contrôleur

- 7-2-3. Les méthodes HTTP préfixées action

- 7-2-4. Les contrôleurs dans des sous-dossiers

- 7-2-5. Les espaces de noms contrôleur

- 7-2-6. Utilisation de plus de paramètres depuis l'URL

- 7-2-7. Retourner le résultat

- 7-2-8. Méthodes spéciales contrôleur

- 7-2-9. action_index()

- 7-2-10. before()

- 7-2-11. after($reponse)

- 7-2-12. router($methode,$parametres)

- 7-2-13. Extension des autres contrôleurs

- 7-2-14. Créer des contrôleurs de base

- 7-3. Les modèles

- 7-3-1. Que sont les modèles ?

- 7-3-2. Comment sont utilisés les modèles ?

- 7-3-3. Créer un modèle

- 7-3-4. Accéder à un modèle

- 7-3-5. Écrivez vos propres modèles

- 7-3-6. Écrire des requêtes SQL

- 7-3-7. Utiliser le constructeur de requêtes

- 7-3-8. Utiliser le modèle CRUD pour créer des modèles

- 7-3-9. Utiliser ORM pour créer des modèles

- 7-4. Vues

- 7-4-1. Qu'est-ce qu'une vue ?

- 7-4-2. Créer une vue

- 7-4-3. Utiliser des vues

- 7-4-4. Sécurité

- 7-4-5. Rendu « paresseux »

- 7-4-6. Vues de niche

- 7-4-7. Exemple de vues

- 7-4-8. Méthode 1 (utilisant les vues de l'exemple ci-dessus et le rendu « paresseux »)

- 7-4-9. Méthode 2 ( utilisant les vues de l'exemple ci-dessus et le rendu forcé)

- 7-4-10. Méthode 3 ( utilisant les vues de l'exemple ci-dessus, sans donnée globale, et avec le rendu « paresseux »)

- 7-5. Présentation

- 7-5-1. Qu'est-ce qu'une présentation ?

- 7-5-2. Créer une présentation

- 7-5-3. Passage de fonctions à des vues

- 7-5-4. Sécurité

- 7-5-5. Usage avancé

- 7-5-5-a. Gestion de plusieurs méthodes

- 7-5-5-b. Les méthodes before et after

- 7-5-5-c. Changer la vue

- 7-5-5-d. Utiliser un fichier de vue différent, ou un objet vue existant

- 7-5-5-e. Accès à la vue

- 7-5-5-f. Utilisation des présentations depuis un autre namespace ou sans Presenter_ prefixed

- 8. Requêtes HMVC

- 8-1. Erreur 404 pendant une requête HMVC

- 8-2. Traversée d'une instance de requête

- 9. Génération de code avec Oil

- 9-1. Les contrôleurs

- 9-2. Les modèles

- 9-3. Génération de modèles en utilisant Model_Crud

- 9-4. Génération de modèle sans option TimeStamp

- 9-5. Changer le TimeStamp et les champs de TimeStamp

- 9-6. Générer un modèle en utilisant Model_Soft

- 9-7. Générer un modèle en utilisant Model_Temporal

- 9-8. Générer un modèle en utilisant Model_Nestedset.

- 9-9. Les présentations

- 9-10. Lancer des migrations

- 9-11. Générer des migrations

- 9-12. Magic_Migrations

- 9-13. L'échafaudage

- 9-14. L'échafaudage d'administration

- 9-15. Tâches

- 9-16. Configurations

- 9-17. Générer une configuration depuis COREPATH

- 9-18. Forçage de la mise à jour de la configuration depuis COREPATH et APPPATH

- 9-19. Les packages

- 9-19-1. Générer un package « driver-based »

- 9-19-2. Générer un package avec des fichiers VCS

- 9-19-3. Les modules de package

- 10. Les tâches

- 10-1. Qu'est-ce qu'une tâche ?

- 10-2. Créer une tâche

- 10-3. Fractionner une tâche en plusieurs méthodes

- 11. Les modules

- 11-1. Qu'est-ce qu'un module ?

- 11-2. Configuration des modules

- 11-3. Namespaces de module

- 11-4. La structure d'un dossier module

- 11-5. Chargement de fichiers de module transversal

- 11-6. Routage de module

- 11-7. Les modules et les requêtes HMVC

- 11-8. Utiliser des classes de module en dehors de celui-ci

- 12. Les packages

- 12-1. Installer des packages

- 12-2. Installer des packages avec Oil

- 12-2-1. Installation

- 12-2-2. Désinstallation

- 12-3. Créer des packages

- 13. Le routage

- 13-1. Routes réservées

- 13-2. Routage de base

- 13-3. Routage semi-avancé

- 13-4. Routage avancé

- 13-5. Routage HTTP

- 13-6. Routes nommées et routage inverse

- 13-7. Routes inline

- 13-8. Modules et routage

- 14. Sécurité

- 14-1. Les encodages de sortie

- 14-1-1. Protection CSRF

- 14-1-2. Filtrage XSS

- 14-1-3. Filtrage d'entrée

- 14-1-4. Injection SQL

- 15. La gestion des erreurs

- 15-1. Codes erreur

- 15-2. Les erreurs de logique d'application

- 15-2-1. Erreur 404

- 15-2-2. Lancer un 404

- 15-2-3. Manipulation 404

- 15-2-4. Tout intercepter

- 15-2-5. Lancer une erreur 500

- 15-2-6. Lancer une erreur 403

- 15-2-7. Erreurs en mode CLI

- 16. Tests unitaires

- 16-1. Qu'est-ce qu'un test unitaire ?

- 16-2. PHPUnit

- 16-3. Lancer des tes unitaires

- 16-4. Créer des tests unitaires

- 16-5. Groupes de test

- 16-6. Configuration avancée

- 16-7. Tests unitaires pour modules

- 16-8. Tests dans un dossier Fuel/Directoy renommé

- 17. Profilage

- 17-1. Qu'est-ce que le profilage ?

- 17-2. Profilage d'application

- 17-3. Profilage de base de données

- 17-4. Ajout d'information au profileur

- 18. Remerciements

1 - Bienvenue dans FuelPHP

FuelPHP est un framework web PHP 5 simple, flexible et soutenu par la communauté. Il est né de l'insatisfaction d'utilisateurs de frameworks courants, en vue de pallier des insuffisances. C'est un framework développé par une communauté de développeurs, et elle assure également le support. FuelPHP est extrêmement portable : il fonctionne sur la plupart des serveurs et est doté d'une syntaxe propre dont il est fier.

1-1 - Prérequis

Serveur WEB :

- tout type de serveur Web : FuelPHP a été testé sur Apache, IIS, et Nginx ;

- fonctionne sur tous les systèmes d'exploitation majeurs incluant les *nix et Windows.

Version PHP :

- une version 5.3.3 ou supérieure est requise.

Extensions PHP :

FuelPHP utilise des fonctionnalités que PHP définit comme extensions. Pour éviter tout problème de compatibilité possible, FuelPHP utilise seulement les extensions natives du code PHP, qui sont documentées sur le site officiel de PHP. Si les extensions utilisées font partie d'un dépôt PECL (qui doivent être installées manuellement par un administrateur système), FuelPHP les utilisera quand il les détectera ; sinon il fonctionnera sans.

Voici une liste des extensions utilisées, et des classes qui les utilisent :

Extension

utilisé dans

Commentaires

fileinfo

Upload

Documentation.
Notez que sur un système Windows , une installation manuelle de DLL peut être requise.

mbstring

n/a

Documentation.
Si non présente, le framework n'a pas de support multioctets. Vous pouvez vérifier la constante MBSTRING pour voir si votre installation a le support multioctet activé.

mcrypt

Crypt

Documentation.
Si non présent, PHPSecLib est utilisé pour émuler ces fonctionnalités.

PHPUnit :

- PHPUnit version 3.7 ou supérieure est requis si vous voulez lancer des tests unitaires.

Recommandé :

- serveur Web - Apache 2.4+, fonctionnant sous *nix.

- mod_rewrite - pour retirer index.php de l'URL.

1-2 - Installation rapide

Si votre temps est précieux, et que vous souhaitez des choses fonctionnelles au bout de quelques secondes au lieu de quelques minutes, vous pouvez utiliser notre installateur rapide. En utilisant la bibliothèque curl, vous pouvez installer une version de base de « Oil », à partir de laquelle vous pouvez créer une nouvelle installation complète de FuelPHP.

# installation rapide de Oil depuis le web
curl get.fuelphp.com/oil | sh
# maintenant que Oil est installé, création d'un projet de blog
# dans un dossier nommé Sites
cd Sites/
oil create blog

Pour de plus amples informations, consultez la partie détail installation rapide.

1-3 - Installation manuelle

Si vous ne pouvez pas utiliser la méthode d'installation rapide, vous pouvez aussi installer FuelPHP manuellement, vous trouverez les instructions détaillées sur la partie détail installation manuelle.

1-4 - Étapes suivantes

1. Lecture sur les composants d'une application FuelPHP.

2. Configuration de votre nouvelle installation de FuelPHP.

3. Apprentissage de l'usage des modules et des packages.

4. Lecture sur les contrôleurs.

2 - Installation rapide

2-1 - Installation en ligne de commande

Ceci fonctionne uniquement sur les systèmes *nix (Linux, OS X, Unix,etc.).

Notre installeur rapide est une interface dépouillée pour le package « oil ». Il permet de créer un nouveau projet avec une commande. Vous n'avez plus besoin d'utiliser « php » dans votre commande « oil ». Pour installer l'installeur rapide, ouvrez simplement un terminal et lancez la commande suivante :

curl get.fuelphp.com/oil | sh

Cette commande vous demandera votre mot de passe, car il installe le script dans /usr/bin.

Vous pouvez maintenant utiliser juste « oil » au lieu de « php oil » dans vos projets.

Si vous avez installé le script « oil » avant la version 1.6, vous devez le réinstaller pour qu'il lance aussi Composer.

Pour créer un nouveau projet, lancez simplement :

$ oil create <nom du projet>

Ceci va créer un dossier dans le dossier courant avec le nom de projet donné.Il va ensuite cloner le dépôt et tous les sous-modules dans le dossier.

Ceci va aussi lancer la commande « oil refine install », laquelle donne les droits d'écriture aux dossiers nécessaires, et la commande « php composer.phar », mises à jour pour remonter les dépendances définies dans Composer.

3 - Installation manuelle

Ceci va créer l'installation par défaut à la racine de votre dossier Virtualhost.

3-1 - Clonage de la dernière version depuis github

cd dossier/ou/se/trouve/votre/racine/virtualhost
git clone git://github.com/fuel/fuel.git .
./composer.phar update

N'oubliez-pas le « . » à la fin de la commande git. Sinon, cela vous créera un dossier nommé fuel à la racine de votre dossier virtualhost.

3-2 - Clonage de la dernière version de la branche de développement depuis github

cd dossier/ou/se/trouve/votre/racine/virtualhost
git clone git://github.com/fuel/fuel.git -b 1.8/develop .
./composer.phar update --prefer-source

N'oubliez-pas le « . » à la fin de la commande git. Sinon, cela vous créera un dossier nommé fuel à la racine de votre dossier virtualhost.

Autre solution : vous pouvez utiliser « Composer » pour tout installer en une seule opération :

composer create-project fuel/fuel:dev-1.8/develop --prefer-source .

3-3 - Téléchargement du fichier zippé

Les différentes étapes de téléchargement sont les suivantes :

1. Téléchargez le fichier zip du framework FuelPHP ;

2. Décompressez le fichier téléchargé, pour extraire les sources ;

3. Exécutez la commande « php composer.phar update » pour installer toutes les dépendances ;

4. Déplacez les fichiers sur votre serveur, selon les recommandations suivantes :

- le répertoire « public » du dossier source correspond au contenu du répertoire de votre site ou de votre application tel que défini dans votre serveur Web ; par exemple «  public_html », « public », « htdocs »,etc. Il faut donc déplacer ce contenu à l'emplacement requis, qui peut aussi être un sous-répertoire de votre « webroot » ; pourvu que ce soit la destination de votre utilisation de FuelPHP ;

- il est recommandé que le dossier « public » de votre installation FuelPHP soit différent de celui utilisé, par défaut, par votre serveur Web. Cette recommandation répond à des questions de sécurité ;

- il faudra aussi éditer le fichier index.php pour modifier les chemins d'accès des dossiers app, core, et packages, afin qu'ils pointent sur les chemins propres à votre installation :

/
docs/
fuel/
app/
core/
packages/
public/
.htaccss
assets/
index.php
oil

Après l'installation, assurez-vous que les permissions soient correctes sur les dossiers auxquels le framework doit accéder. Il existe une tâche « oil » qui permet de positionner les droits en écriture sur les dossiers de base :

php oil refine install
Made writable: APPPATH/cache
Made writable: APPPATH/logs
Made writable: APPPATH/tmp
Made writable: APPPATH/config

4 - Composer

Depuis la version 1.6, FuelPHP utilise le manager de packages Composer pour récupérer automatiquement les dépendances, soit de Packagist, soit de Github, soit d'une localisation personnalisée. À partir de la version 1.7.2, tous les composants du framework FuelPHP sont aussi installés via Composer.

Composer est contrôlé via le fichier composer.json, que vous trouverez à la racine de votre installation FuelPHP. Pour votre commodité, il est inclus dans la bibliothèque composer.phar. Vous pouvez donc lancer Composer directement :

php composer.phar self-update
php composer.phar update

Si vous n'exécutez pas cette étape, FuelPHP ne démarrera pas, car tous les composants vitaux du framework sont chargés via Composer.

5 - Configuration

La configuration principale peut être trouvée dans app/config/config.php. Vous pouvez donc éditer ce fichier pour le correspondre à votre installation.

5-1 - Installation dans le dossier DocumentRoot

Comme expliqué au point 3.3, pour des questions de sécurité, il est fortement recommandé de ne pas installer FuelPHP dans le dossier document root de votre serveur Web.

Cependant, il y a des cas où vous voudriez faire cela, par exemple pour un environnement de développement local où le module dynamique Apache mass virtual hosting est utilisé pour configurer rapidement des nouveaux environnements de développement sans la nécessité de redémarrer le serveur Web.

Dans un tel cas, installez FuelPHP dans un dossier que vous avez désigné comme dossier d'installation racine. Une fois cela effectué, allez dans le dossier public, déplacez tout un cran au-dessus, et supprimez-le. La seule utilité de ce dossier est de fournir un point d'ancrage pour les DocumentRoot de votre serveur Web. Vous n'en avez plus besoin puisque vous avez installé FuelPHP dans un dossier qui est DocumentRoot.

Après le déplacement, changez l'emplacement de l'application, des packages, et du cœur du framework dans le fichier index.php.

define('APPPATH', realpath(__DIR__.'/fuel/app/').DIRECTORY_SEPARATOR);
define('PKGPATH', realpath(__DIR__.'/fuel/packages/').DIRECTORY_SEPARATOR);
define('COREPATH', realpath(__DIR__.'/fuel/core/').DIRECTORY_SEPARATOR);

5-2 - Qu'en est-il des dossiers à plusieurs niveaux de sous-répertoires ?

Cela ne fait pas de différence, la procédure reste exactement la même.

Dans ce cas cependant, votre application pourrait être un petit peu plus compliquée en raison de la structure de dossiers impactée. Mais vous ne pouvez pas juste y mettre un simple fichier .htaccess, vous voudrez probablement toujours accéder à d'autres éléments installés dans cette même structure de dossier.

En supposant que vous avez installé FuelPHP dans le dossier « /sous/dossier/profond » dans votre DocumentRoot, vous devriez normalement avoir accès à votre application en utilisant l'URL « http:/exemple.org/sous/dossier/profond ».

5-2-1 - Apache

En plaçant ce fichier .htaccess dans un des dossiers au plus haut dans l'arborescence, vous pouvez avoir une redirection par votre navigateur vers votre application FuelPHP si aucune concordance n'est trouvée avec le nom de fichier ou dossier :

<IfModule mod_rewrite.c>
RewriteEngine on
# envoie la requête au sous-dossier, si ce n'est pas un vrai fichier, un vrai dossier, ou si c'est une requête racine
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d [OR]
RewriteCond $1 ^$
RewriteRule ^(.*)$ /sous/dossier/profond [R=301,L]
</IfModule>

Notez que ceci effectue une redirection, et par conséquent ne cache pas les sous-dossiers dans le chemin de l'utilisateur. Si c'est ce que vous voulez, utilisez plutôt ceci :

<IfModule mod_rewrite.c>
RewriteEngine on
# envoie la requête au sous-dossier, si ce n'est pas un vrai fichier, un vrai dossier, ou si c'est une requête racine
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d [OR]
RewriteCond $1 ^$
RewriteRule ^(.*)$ /sous/dossier/profond [QSA,L]
</IfModule>

Évidemment, si vous le placez dans le sous-dossier, vous pouvez cacher « sous/dossier » à l'URL, mais pas en profondeur.

Notez qu'avoir un fichier .htaccess activé va ralentir considérablement votre serveur Apache. Si vous avez accès à la configuration de celui-ci, envisagez la désactivation de cette fonctionnalité, et ajoutez des règles de rewrite dans la définition du VirtualHost.

5-2-2 - Nginx

Nginx ne comporte pas de fichier de configuration client, vous devez donc ajouter des règles de rewrite dans le fichier de configuration de votre VirtualHost. Vous pouvez utiliser celui-ci comme une ligne directrice :

server {
server_name fuelphp.local;

# on s'assure que Nginx peut écrire dans ces fichiers
access_log /var/www/fuelphp/nginxlogs/access.log;
error_log /var/www/fuelphp/nginxlogs/error.log;
root /var/www/fuelphp/public;

location/{
index index.php;
try_files $uri $uri/ /index.php$is_args$args;
}

location ~ \.php$ {
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param FUEL_ENV "production";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}

5-3 - Configurer l'environnement

Par défaut, l'environnement est configuré en mode développement. FuelPHP utilise l'environnement pour définir quels sont les paramètres de la base de données à utiliser. Mais l'environnement sert aussi à d'autres fins.

Pour configurer l'environnement, insérez la ligne suivante dans votre fichier .htaccess :

SetEnv FUEL_ENV production

Pour Nginx, il faut utiliser la déclaration « fastcgi param » , comme montrée dans l'exemple ci-dessus. Les options disponibles sont détaillées dans la classe Constants de la classe Fuel.

6 - Configurez votre nouvelle installation

6-1 - Introduction

Le framework FuelPHP est conçu avec, à l'esprit, une configuration au-dessus des conventions. Ceci donne en résultat une plateforme hautement personnalisable sur laquelle vous bâtissez votre application.

Les fichiers de configuration sont stockés dans le dossier app/config. La configuration de base de l'application est faite dans app/config/config.php. La configuration chargée peut être spécifique à un environnement, plus d'informations dans la partie 5.

Pour écraser les paramètres d'une fonction spécifique, il suffit de créer soit un nouveau fichier dans app/config, soit copier le fichier correspondant depuis core/config vers app/config.

6-2 - Options de configuration

Ce sont les options qui peuvent être définies dans le fichier de configuration de base, app/config/config.php. Ce fichier est vide après l'installation de FuelPHP. Toutes les options par défaut, comme définies ci-dessous, sont définies dans le fichier correspondant dans le dossier core/config. Quand vous voulez surcharger une option, par défaut, ajoutez une clé au tableau dans votre fichier de configuration, et modifiez la valeur. Sinon, copiez la section depuis le fichier core dans le fichier de l'application, et modifiez-le.

FuelPHP utilise la notation « dot-notation » lors de la gestion des tableaux. C'est un moyen pratique pour accéder à des éléments de tableaux multidimensionnels. Cette notation, utilisée dans la documentation, fournit une référence simple à taper. Par exemple :

// quand vous voyez "always_load.packages = array()", c'est un raccourci pour :
array("always_load" => array("packages" => array(...) ) );

Clé

Type

Par défaut

Description

base_url

chaîne

null

L'URL de base de l'application, elle peut être relative. Elle doit contenir un slash. ('/foo/', 'http://exemple.com/').

url_suffix

chaîne

''

Tout suffixe qui doit être ajouté aux URL générées par Fuel. Si le suffixe est une extension, assurez-vous d'y inclure le point ('.html').

index_file

chaîne

'index.php'

Le nom du fichier de bootstrap principal. Affecter la valeur false, à cette clé, ou retirez-la, si vous utilisez mod rewrite.

controller_prefix

chaîne

'Controller_'

Le préfixe de classe utilisé pour trouver les contrôleurs lors du mapping de l'URI au nom de contrôleur de classe. Vous devez le modifier si vous voulez des contrôleurs avec namespace dans un dossier différent de app/classes/controller.

profiling

booléen

false

Ceci pour activer le profileur.

cache_dir

chaîne

APPPATH.'cache/'

Le dossier où doivent être stockés les fichiers de cache. Ce dossier doit être en écriture pour pour les services FuelPHP.

caching

booléen

false

Ceci pour activer la recherche dans le cache.

cache_lifetime

int

3600

La durée du cache en secondes.

ob_callback

callback

null

Callback fourni à ob_start(), ajusté pour ob_gzhandler pour activer l'encodage gzip en sortie.

errors

tableau

Tableau contenant les clés de configuration pour contrôler le comportement en cas de détection d'erreurs.

errors.continue_on

tableau

array()

Contient les erreurs PHP qui seront prises en compte. Voir aussi : gestion d'erreurs.

errors.throttle

int

10

Combien d'erreurs seront affichées, au même moment. Une fois ce nombre excédé, les autres erreurs ne sont pas affichées, jusqu'à traitement de celles en cours (prévention du manque de mémoire pendant le traitement des erreurs).

errors.notices

booléen

true

Activation de la notification d'erreur.

language

chaîne

'en'

Le langage par défaut de l'application, utilisé par la classe lang.

locale

chaîne

'en_US'

Utilisé par la fonction setlocale(), qui est requise par certaines installations PHP Il faut lui donner la valeur false, si vous voulez vous passer de son utilisation. Sa syntaxe peut différer selon l'OS. Ubuntu, par exemple, exige l'encodage .utf8 (suffixe d'encodage).

encoding

chaîne

'UTF-8'

L'encodage, par défaut, utilisé pour les caractères.

server_gmt_offset

int

0

L'offset en secondes du serveur par rapport au Timestamp GMT quand time() est utilisé. Il permet de corriger une éventuelle mauvaise configuration serveur : time() devrait toujours retourner le nombre de secondes depuis le 01/01/1970 00:00:00 GMT.

default_timezone

chaîne

'UTC'

La Timezone du serveur*.

* Si vous fixez cette valeur, ASSUREZ-VOUS DE FAÇON ABSOLUE que la timezone configurée correspond à celle fixée sur votre serveur, puisque le calcul de timezone se fait par rapport à GMT. Ceci provoquera un affichage d'heure incorrect dans votre application, et des soucis de cookies/sessions dus à un mauvais calcul de délai d'expiration.

Clé

Type

Par défaut

Description

log_threshold

int

Fuel::L_WARNING

Il s'agit du seuil de journalisation. C'est un tableau spécifique des niveaux de messages à loguer. Documentation sur les différentes valeurs possibles.

log_path

chaîne

APPPATH.'logs/'

Le répertoire des logs. Ce dossier DOIT ÊTRE en écriture pour les services FuelPHP.

log_date_format

chaîne

'Y-m-d H:i:s'

Le format date et heure utilisé dans les logs.

security

tableau

Tableau contenant les clés de configuration pour contrôler la sécurité de votre application.

security.csrf_autoload

booléen

false

Positionné pour la vérification automatique du jeton csrf. Plus d'infos sur csrf.

security.csrf_token_key

chaîne

'fuel_csrf_token'

Quelle clé $_POST à chercher pour vérifier le jeton csrf.

security.csrf_expiration

int

0

Fixe le délai d'expiration du cookie csrf. Toute valeur supérieure à 0 correspond au nombre de secondes avant expiration du cookie.

security.token_salt

chaîne

Valeur utilisée dans la génération de votre jeton de sécurité.

Il faut indiquer un niveau de complexité dans la génération des jetons de sécurité, afin de les rendre moins prévisibles.

security.allow_x_headers

booléen

false

Autorise la classe Input à utiliser les headers « X » quand ils sont présents, tels que HTTP_X_FORWARDED_FOR ou HTTP_X_FORWARDED_PROTO.

security.uri_filter

tableau

array('htmlentities')

Définit les fonctions PHP à utiliser pour filtrer les URI.

security.input_filter

tableau

array()

Définit les fonctions PHP à utiliser pour filtrer les tableaux d'entrée ($_GET, $_POST et $_COOKIE).
Peut être positionné sur xxs_clean,
Ceci peut causer une baisse de performance liée à la taille des variables en entrée.

security.output_filter

tableau

array()

Définit les fonctions PHP à utiliser pour filtrer les variables ajustées à la vue.
Peut être fixé à xxs_clean,
Ceci peut causer une baisse de performance liée à la taille des variables.

security.auto_filter_output

booléen

true

Pour encoder automatiquement les données vues (htmlentities) .

security.whitelisted_classes

tableau()

array(
'stdClass',
'Fuel\\Core\\View',
'Fuel\\Core\\Presenter',
'Closure'
)

Avec l'encodage de sortie activé sur tous les objets passés, vont être convertis en chaîne ou levée d'exceptions à moins qu'ils soient de la classe de ce tableau.

cookie

tableau

Tableau contenant les clés de configuration définies dans les réglages globaux de cookies.

cookie.expiration

int

0

Durée de vie, en secondes, d'un cookie.

cookie.path

chaîne

'/'

Limite le périmètre de chemin d'accès où le cookie est actif.

cookie.domain

chaîne

null

Limite le périmètre de domaine où le cookie est actif.

cookie.secure

booléen

false

Ne transmet le cookie que sur une connexion sécurisée.

cookie.http_only

booléen

false

Ne transmet le cookie qu'en HTTP, désactivant l'accès JavaScript.

module_paths

tableau

array()

Chemins d'accès aux dossiers de module. Utilisé quand un module est ajouté sans emplacement spécifié.

always_load

tableau

Tableau contenant les éléments que le framework doit charger lors de son initialisation.

always_load.packages

tableau

array()

Les packages à autocharger. Spécifiés en tant que array('package') ou array('package' => PKGPATH.'chemin/du/package').
Pour que cela fonctionne, le chemin d'accès doit être dans package_paths.

always_load.modules

tableau

array()

Les modules à autocharger spécifiés tels que array('package'). Les modules autochargés sont accessibles via l'URL. Pour que cela fonctionne, un chemin de module doit être dans module_paths.

always_load.classes

tableau

array()

Contient les classes à autocharger et lancer quand vous voulez autocharger une classe depuis un package ou un module, assurez-vous aussi qu'il soit autochargé.

always_load.config

tableau

array()

Contient les fichiers de configuration à autocharger. Les fichiers de configuration sont à charger dans un groupe comme : array('config') ou array('filename' => 'group'). Si vous ne voulez pas charger le fichier dedans, mettez le nom du groupe à null : array('filename' => null).

always_load.language

tableau

array()

Contient les fichiers de langage à autocharger. Les fichiers de configuration sont à charger dans un groupe ainsi : array('lang') ou array('filename' => 'group').
Si vous ne voulez pas charger le fichier dedans, mettez le groupe à null : array('filename' => null).

L'interaction avec les fichiers de configuration s'effectue avec la classe Config. Les fichiers de configuration peuvent aussi être générés via Oil.

7 - Modèle vue contrôleur (MVC)

7-1 - Qu'est-ce que MVC

MVC (Modèle Vue Contrôleur) est une approche pour séparer le code en fonction du rôle qu'il joue dans votre application. Dans un flux d'application, on commence avec un contrôleur qui est chargé. Ce contrôleur exécute une méthode accédant aux données en utilisant des modèles. Une fois ce travail effectué, le contrôleur décide quelle vue charger, laquelle contient la sortie que vos visiteurs vont obtenir.

7-2 - Les contrôleurs

Les classes de contrôleur sont localisées dans « chemin_appli/classes/controller ».

FuelPHP décide quel contrôleur charger en fonction de l'URL demandée et quelle méthode y appliquer. C'est là que votre application commence à travailler. Le contrôleur décide des actions à effectuer, quoi faire des entrées utilisateur, quelles données manipuler et quelle vue à montrer à l'utilisateur. Cependant, le contrôleur ne fait rien de ces actions lui-même, il demande aux modèles et aux classes de faire le travail.

7-2-1 - Qu'est-ce qu'un contrôleur ?

Les contrôleurs sont des classes pouvant être atteintes à travers l'URL et s'occupent de traiter la requête. Un contrôleur appelle les modèles et les classes pour chercher l'information. Enfin il passe tout à la vue de sortie. Si une URL comme www.votresite.com/exemple/index est demandée, le premier segment (« exemple ») sera le contrôleur qui sera appelé et le second segment (« index ») sera la méthode utilisée par ce contrôleur.

7-2-2 - Créer un contrôleur

Dans FuelPHP, les contrôleurs sont dans le dossier fuel/app/classes/controller et sont préfixés avec « Controller ». Optionnellement, ils doivent étendre la classe controller pour l'ensemble complet de fonctionnalités. Ci-dessous, un exemple qui étend le contrôleur :

class Controller_Example extends Controller
{

public function action_index()
{
$data['css'] = Asset::css(array('reset.css','960.css','main.css'));
return Response::forge(View::forge('welcome/index'));
}
}

Les méthodes pouvant être appelées à travers les URL sont préfixées avec « action_ ». Cela signifie que vous n'êtes pas limité par les constructions PHP, ou le nom utilisé (exemple : le nom de méthode « list » est autorisé, « action_list » ne posera pas de problème). Mais cela signifie également que le nom que vous donnez à vos méthodes publiques de contrôleur est utilisable depuis d'autres classes, mais n'est pas routable.

7-2-3 - Les méthodes HTTP préfixées action

Il est possible de router les méthodes préfixées actions. Voici un exemple :

class Controller_Example extends Controller
{
public function get_index()
{
// Ceci sera appelé lors d'une méthode HTTP GET.
}

public function post_index()
{
// Ceci sera appelé lors d'une méthode HTTP POST.
}
}

7-2-4 - Les contrôleurs dans des sous-dossiers

Il vous est également possible de mettre un contrôleur dans un sous-dossier tel que fuel/app/classes/controller/sous_dossier/test.php. Dans ce cas, le contrôleur doit inclure le nom de dossier dans le nom de la classe tel que : controleur_sous_dossier_test.

La profondeur des dossiers n'est pas limitée, ainsi fuel/app/classes/controller/sous_dossier1/sous_dossier2/sous_dossier3/test.php devra avoir un nom de classe tel que Controller_sous_dossier1_sous_dossier2_sous_dossier3_Test.

7-2-5 - Les espaces de noms contrôleur

Regardez la page espace de noms pour voir comment vous pouvez les utiliser dans vos contrôleurs.

7-2-6 - Utilisation de plus de paramètres depuis l'URL

Disons que nous avons la méthode suivante dans notre exemple de contrôleur :

public function action_name_to_upper($name_1, $name_2)
{
$data['name_1'] = strtoupper($name_1);
$data['name_2'] = strtoupper($name_2);
return View::forge('test/name_to_upper', $data);
}

Si nous appelons cette méthode en utilisant : www.votresite.com/exemple/name_to_upper/fuel/php, « FUEL » et « PHP » seront transmis en tant que $name_1 et $name_2 dans le tableau $data.

7-2-7 - Retourner le résultat

Idéalement, une action de contrôleur doit retourner un objet de réponse. Optionnellement, vous pouvez spécifier des headers HTTP spéciaux, comme un code de status HTTP personnel (un code autre que « 200 OK »).Si vous ne retournez pas d'objet de réponse, la méthode par défaut after() va encapsuler la valeur de retour de l'action dans un objet de réponse pour vous.

Si votre contrôleur étend un des contrôleurs de base, votre action peut également retourner toute valeur pouvant être castée en chaîne, par exemple un objet vue. La méthode after() du contrôleur de base sera converti en objet réponse pour vous.

Si votre contrôleur n'étend pas un des contrôleurs de base, et que vous voulez utiliser cette fonctionnalité, votre contrôleur doit intégrer votre propre méthode after() qui accepte les valeurs de retour action, et doit être encapsulé dans un objet réponse devant être retourné.

7-2-8 - Méthodes spéciales contrôleur

N'écrasez pas le constructeur de la classe __construct(), utilisez before() en lieu et place. À moins d'avoir, auparavant, étudié les bases du contrôleur depuis le noyau et avoir compris comment il doit être étendu, pour ne pas casser votre installation FuelPHP.

7-2-9 - action_index()

Cette méthode sera appelée si le contrôleur est appelé sans un second paramètre. Dans l'exemple, au-dessus, www.votresite.com/exemple/index sera identique à www.votresite.com/exemple.

7-2-10 - before()

La méthode before() est utilisée comme une préméthode, pour exécuter le code requis dans chaque méthode de contrôleur appelé. Cette méthode sera exécutée avant la méthode de l'URL appelée de votre contrôleur. Elle ne sera pas appelée, si elle se révèle ne pas exister. Vous ne devriez pas utiliser cette méthode pour router des décisions. Si vous en avez besoin, utilisez la méthode router à la place.

7-2-11 - after($reponse)

Cette méthode sera exécutée après que la méthode de l'URL est aboutie, elle ne sera pas appelée si elle n'existe pas. Le paramètre $reponse est requis. La méthode after() DOIT retourner un objet réponse.

Si la méthode after() doit construire un objet réponse, il peut utiliser la propriété status du contrôleur pour positionner le status HTTP de la réponse. Par défaut, la propriété contient « 200 (OK) ».

7-2-12 - router($methode,$parametres)

Cette méthode va prendre le contrôle du routage interne du contrôleur. Une fois le contrôleur chargé, la méthode router() est appelée et utilise la $methode lui ayant été passée, à la place de la méthode par défaut. Elle lui passe aussi $parametres dans un tableau. Les méthodes before() et after() fonctionneront toujours comme attendu.

7-2-13 - Extension des autres contrôleurs

Grâce à l'autoloader, vous pouvez étendre vos autres contrôleurs sans écrire quoi que ce soit de plus que son nom dans une définition de classe :

class Controller_Exemple extends Controller_Bienvenue
{

// vos méthodes

}

Cela peut paraître étrange de prime à bord, mais étendre les contrôleurs vous permet de partager leurs méthodes et créer des contrôleurs de base très facilement.

7-2-14 - Créer des contrôleurs de base

Un contrôleur de base est un contrôleur partagé, comme les contrôleurs Public ou Admin et sont utilisés pour partager la logique entre les groupes de contrôleurs. Par exemple, le contrôleur Admin pourrait contenir vos actions de login et logout et peut-être un tableau de bord. Mais il peut aussi contenir une méthode before(), qui contrôle si l'utilisateur est logué en tant qu'administrateur. Donc tous les autres contrôleurs dans votre panneau d'administration étendront cela et seront automatiquement sécurisés.

class Controller_Admin extends Controller
{

public function before()
{
// vérifie si administrateur
}

// vos méthodes

public function action_index()
{
// charge le tableau de bord
}

public function action_login()
{
// logue l'utilisateur
}
}

Ce code ira dans fuel/app/classes/controller/admin.php et tous vos autres contrôleurs devraient aller dans fuel/app/classes/controller/admin/ comme ceci :

class Controller_Admin_User extends Controller_Admin
{

public function action_index()
{
// Remplace le tableau de bord avec le listing de l'index utilisateur
}

public function action_edit($id)
{
// édition des utilisateurs
}
}

7-3 - Les modèles

Les classes de modèle sont localisées dans chemin_appli/classes/model

7-3-1 - Que sont les modèles ?

Chaque fois que des données doivent être récupérées, manipulées, supprimées, ceci devrait être fait par un modèle. Un modèle est une représentation d'une sorte de données et possède des méthodes pour les changer. Par exemple, vous ne devez jamais mettre une requête SQL dans un contrôleur, celles-ci sont mises dans un modèle et le contrôleur va inviter le modèle à exécuter les requêtes. Par ce biais, si votre base de données change, vous n'aurez pas à changer tous les contrôleurs, mais juste le modèle qui agit dessus.

7-3-2 - Comment sont utilisés les modèles ?

Dans FuelPHP, un modèle c'est essentiellement juste une classe comme une autre. Ils ne font rien de plus qu'une bibliothèque, mais le préfixe model_ aide à le différencier des autres classes. Pour faire quelque chose d'utile avec un modèle, vous aurez besoin d'utiliser d'autres classes.

7-3-3 - Créer un modèle

namespace Model;

class Bienvenue extends \Model {

public static function get_results()
{
// interactions avec la base de données
}

}

Rappelez-vous de faire précéder d'un antislash les classes utilisées de façon globale, en dehors du namespace, vous êtes dedans. Pour plus de détails, lisez la documentation sur les namespaces sur PHP.net.

7-3-4 - Accéder à un modèle

PHP contient le mot clé « use » pour importer des classes dans le namespace en cours, ceci permet de raccourcir le nom de classe de modèle depuis, par exemple, « Model\Bienvenue » vers « Bienvenue », tout simplement, dans le fichier spécifique à la classe :

use \Model\Bienvenue;

class Controller_ Bienvenue extends Controller
{
public function action_index()
{
$resultat = Bienvenue::get_results();
}
}

7-3-5 - Écrivez vos propres modèles

Bien que les modèles puissent être utilisés avec tout type de structures de données, nous nous focaliserons sur l'usage avec SQL, car c'est l'usage le plus commun. Vos modèles auront presque toujours au moins les méthodes CRUD(Create, Read, Update, Delete : création, lecture, mise à jour, suppression). Dans FuelPHP, vos modèles n'ont besoin de rien étendre par défaut, bien que vous puissiez bien sûr créer votre propre modèle de données ou utiliser le package, FuelPHP, ORM.

7-3-6 - Écrire des requêtes SQL

Vous pouvez utiliser la classe DB pour créer vos requêtes en SQL natif comme ceci :

DB::query('SELECT * FROM users WHERE id = 5');

7-3-7 - Utiliser le constructeur de requêtes

Quand il s'agit de manipuler des données, de travailler avec des données dans un tableau ou de faire une application portable sur de multiples moteurs de bases de données, vous pourriez trouver le SQL natif assez lourd. En utilisant les méthodes de construction de requêtes de la classe DB, vous pouvez faire abstraction du SQL natif :

DB::select('title','content')->from('articles')->execute()->get('title');

Pour plus d'informations sur les requêtes SQL et l'utilisation du constructeur de requêtes, consultez la documentation sur la classe DB.

7-3-8 - Utiliser le modèle CRUD pour créer des modèles

Une possibilité pour créer des modèles est l'utilisation du modèle CRUD, lequel ajoute une fonctionnalité communément utilisée à vos modèles pour interagir avec une table de base de données. Un exemple de cet usage ci-dessous :

// trouve tous les articles
$entry = Model_Article::find_all();

// trouve tous les articles de la catégorie 1 classés par date la plus récente
$entry = Model_Article::find(array(
'where' => array('category_id', 1),
'order_by' => array('date' => 'desc')
));

7-3-9 - Utiliser ORM pour créer des modèles

Pour des modèles avec plus de fonctionnalités, comme le support des relations, vous pouvez utiliser le package ORM. Ce qui ajoute un grand nombre de fonctionnalités, en « boite noire », à vos modèles. Voici un exemple de cet usage ci-dessous :

// recherche de tous les articles
$entry = Model_Article::find('all');

// recherche de tous les articles de la catégorie 1 classés par date descendante
$entry = Model_Article::find('all', array(
'where' => array('category_id', 1),
'order_by' => array('date', 'desc')
));

Le modèle CRUD et le package ORM utilisent une syntaxe similaire. Ce qui permet une migration simple, le modèle CRUD ne peut fournir toutes les fonctionnalités que vous souhaitez.

7-4 - Vues

Les classes de vue sont localisées dans chemin_appli/classes/views.

Les vues contiennent votre code HTML, lequel ne devrait jamais se trouver dans vos contrôleurs ou une autre classe qui n'est pas destinée à créer une sortie. En séparant votre rendu de votre logique, vous garantissez que, quand vous décidez de changer votre disposition, vous avez seulement à changer les vues, et ne pas vous occuper des contrôleurs. Ainsi, les vues ne devraient contenir que les commandes PHP : echo et foreach.

7-4-1 - Qu'est-ce qu'une vue ?

Les vues sont des fichiers qui présentent les données au navigateur. Ces fichiers activent la séparation de la logique et de la présentation pour votre application. Les vues sont typiquement des fichiers html, JavaScript, ou css. Mais ils peuvent contenir des variables, qui leur sont passées par leur contrôleur.

7-4-2 - Créer une vue

Dans FuelPHP, les vues sont localisées dans le dossier app/views. Elles peuvent être rangées dans des sous-dossiers. Les vues sont nommées en fonction de leur chemin de dossier depuis fuel/app/views et les noms de fichiers. Par exemple, un fichier de vue placé dans fuel/app/views/user/join.php sera nommé user/join.

Exemple :

<html>
<head>
<title><?php echo $titre; ?></title>
</head>
<body>
Bienvenue, <?php echo $username; ?>.
</body>
</html>

7-4-3 - Utiliser des vues

Dans le framework FuelPHP, les vues sont très flexibles. Vous pouvez créer une vue simple et des vues de niche dans d'autres vues. Cela peut être fait de multiples façons.

Vue d'exemple (fuel/app/views/home/index.php) :

<html>
<head>
<title><?php echo $titre; ?></title>
</head>
<body>
Bienvenue, <?php echo $username; ?>.
</body>
</html>

Méthode 1 (en utilisant l'exemple au-dessus) :

class Controller_Home extends Controller
{
public function action_index()
{
$data = array(); //stocke les variables qui iront dans les vues

$data['username'] = 'Joe14';
$data['titre'] = 'Home';

//assigne la vue à la sortie du navigateur
return View::forge('home/index', $data);
}
}

Méthode 2 (en utilisant l'exemple au-dessus) :

class Controller_Home extends Controller
{
public function action_index()
{
//création de la vue
$vue = View::forge('home/index');

//assignation des variables pour la vue
$vue->username = 'Joe14';
$vue->titre = 'Home';

// une autre façon d'assigner les variables pour la vue
$vue->set('username', 'Joe14');
$vue->set('titre', 'Home');

//assignation de la vue à la sortie du navigateur
return $vue;
}
}

7-4-4 - Sécurité

Les vues utilisent les encodages de sortie pour assainir tout ce qui passe par elles. Dans une installation par défaut, la méthode de sécurité Security::htmlentities() est définie comme filtre de sortie. Vous pouvez modifier les filtres dans vos applications, dans le fichier config.php. Si vous voulez passer quelque chose de non filtré, vous pouvez utiliser la méthode set($nom,$valeur,false).

class Controller_Exemple extends Controller
{
public function action_index()
{
$vue = \View::forge('exemple');

// ajoute filtré, sorties: &lt;strong&gt; pas du gras car filtrage de &lt;/strong&gt;
$vue->title = '<strong>npas du gras car filtré</strong>';

// ajoute non filtré, sorties: <strong> gras à cause du non filtrage</strong>
$vue->set('titre', '<strong> ras à cause du non filtrage</strong>', false);

// ou utiliser la méthode set_safe(), laquelle est identique à  set() mais est à 'false' par défaut
$vue->set_safe('titre', '<strong> gras à cause du filtrage</strong>');

return $vue;
}
}

Si vous ne voulez pas que votre vue se comporte comme cela, vous pouvez passer false en troisième argument de View::forge(). À partir de là, tout ce qui est ajouté à cet objet view, sera non filtré. Si vous voulez quand même filtrer certaines valeurs, vous pouvez utiliser set($nom, $valeur, true).

Vous pouvezaussi désactiver le filtre de sortie globalement en fixant la valeur de configuration de l'application security.auto_filter_output sur false. Pour des raisons de sécurité, il est hautement recommandé de ne pas le faire.

Note sur les objets : à moins que l'objet passé soit de type vue, présentation ou fermeture, il faut une méthode __toString() et forcer en chaîne de caractères quand le filtrage de sortie est activé. Si vous voulez le passer quand même, vous devez utiliser set($nom, $valeur, false),mais n'oubliez pas de filtrer ce que vous utilisez !

Il est prévu que les vues et présentations contiennent du HTML et s'occupent de leur propre filtrage ce pour quoi elles ne sont pas assainies. Les fermetures ne peuvent pas être assainies, vous devriez vous assurer que c'est traité dedans quand nécessaire.

7-4-5 - Rendu « paresseux »

Quand on instancie un objet de type « vue », seul l'environnement requis pour générer la sortie est installé. Le fichier de vue n'est pas lu, aucune variable n'est interprétée, et aucune sortie ne sera rendue. Cela se passe uniquement quand vous appelez explicitement la méthode render() sur l'objet de type « vue » ou quand vous passez l'objet de type « vue » en chaîne (ce qui se passe automatiquement quand vous y appliquez la commande echo). Ceci signifie qu'aucune vue n'est traitée tant que ce n'est pas absolument nécessaire. Cela signifie également que FuelPHP ne garde pas en mémoire les vues rendues, tant que ce n'est pas le moment de les envoyer au navigateur.

7-4-6 - Vues de niche

Les vues peuvent aussi être « nichées » dans d'autres vues. Ceci peut être fait à de multiples reprises.

7-4-7 - Exemple de vues

fuel/app/views/layout.php

<html>
<head>
<?php echo $head; ?>
</head>
<body>
<?php echo $header; ?>
<?php echo $content; ?>
<?php echo $footer; ?>
</body>
</html>

fuel/app/views/head.php

<title><?php echo $titre; ?></title>

fuel/app/views/header.php

<div class="logo"></div>
<div class="texte de logo"><?php echo $titre_site; ?></div>

fuel/app/views/content.php

<h1><?php echo $titre; ?></h1>
<div class="accueil_utilisateur">Bienvenue <?php echo $username; ?></div>

fuel/app/views/footer.php

<div class="footer">
&copy; Copyright <?php echo date('Y');?> <?php echo $titre_site; ?>
</div>

7-4-8 - Méthode 1 (utilisant les vues de l'exemple ci-dessus et le rendu « paresseux »)

class Controller_Home extends Controller
{
public function action_index()
{
// create the layout view
$vue = View::forge('layout');

// assignation variables globales, toutes les vues y ont donc accès
$vue->set_global('username', 'Joe14');
$vue->set_global('titre', 'Home');
$vue->set_global('titre_site', 'Mon site Web');

//assignation vues comme variables, rendu paresseux
$vue->head = View::forge('head');
$vue->header = View::forge('header');
$vue->content = View::forge('content');
$vue->footer = View::forge('footer');

// returne l'objet vue à la requete
return $vue;
}
}

7-4-9 - Méthode 2 ( utilisant les vues de l'exemple ci-dessus et le rendu forcé)

class Controller_Home extends Controller
{
public function action_index()
{
//assignation variables
$data = array();
$data['titre'] = 'Home';
$data['titre_site'] = 'Mon site Web';
$data['username'] = 'Joe14';

//assignation vues comme variables, rendu forcé
$vues = array();
$vues['head'] = View::forge('head', $data)->render();
$vues['header'] = View::forge('header', $data)->render();
$vues['content'] = View::forge('content', $data)->render();
$vues['footer'] = View::forge('footer', $data)->render();

// retourne le rendu HTML à la requête
return View::forge('layout', $vues)->render();
}
}

7-4-10 - Méthode 3 ( utilisant les vues de l'exemple ci-dessus, sans donnée globale, et avec le rendu « paresseux »)

class Controller_Home extends Controller
{
public function action_index()
{
// creationde la couche vue
$vue = View::forge('layout');

//variables locales de la vue, rendu paresseux
$vue->head = View::forge('head', array('titre' => 'Home'));
$vue->header = View::forge('header', array('titre_site' => 'Mon site Web'));
$vue->content = View::forge('content', array('username' => 'Joe14', 'titre' => 'Home'));
$view->footer = View::forge('footer', array('titre_site' => 'Mon site Web'));

// retourne l'objet vue à la requête
return $vue;
}
}

Consultez la classe vue dans la section classes pour la description des fonctions vue.

7-5 - Présentation

Les classes de présentation sont localisées dans chemin_appli/classes/presenter.

Quand votre application s'enrichit avec de nouveaux objets, elle devient plus complexe. Vous découvrirez, alors, qu'il devient plus difficile de dissocier ce qui appartient au contrôleur, de ce qui appartient à la vue. La logique de votre application peut devenir compliquée à discerner. C'est là qu'intervient la présentation : c'est le lien entre votre contrôleur et vos vues.

7-5-1 - Qu'est-ce qu'une présentation ?

Une présentation est une classe contenant la logique nécessaire pour générer votre vue (ou vos vues). Quand le contrôleur a terminé avec votre entrée utilisateur, et a terminé toute autre action qu'il doit effectuer, il transfère l'exécution à la présentation pour récupérer et traiter les données nécessaires à la vue. Une présentation ne devrait effectuer aucune manipulation de données, mais peut contenir des appels à la base de données et autres opérations de récupération et préparation nécessaires pour générer les données de la vue.

Les présentations sont optionnelles. Si vous n'en avez pas besoin, vous pouvez utiliser les vues directement, et garder la logique de prétraitement dans votre contrôleur.

7-5-2 - Créer une présentation

Tout d'abord, créez une classe présentation vide dans APPPATH/classes/presenter/index.php :

class Presenter_Index extends Presenter
{
}

Vous pouvez ensuite créer la vue associée à la présentation dans app/views/index.php :

<h1><?php echo $titre; ?></h1>

<ul>
<?php
foreach ($articles as $a)
{
echo '<li>'.$a->titre.'</li>';
}
?>
</ul>

À propos des noms de vue

Une présentation et ses vues sont prévues par défaut pour partager le même nom. Ainsi une présentation Presenter_Index attend comme nom de vue app/views/index.php. Et les underscores fonctionnent ici comme avec les classes, ce qui signifie que la vue pour la présentation est attendue dans app/views/quelque/chose.php.

Ce comportement, par défaut, peut être modifié en fixant à non statique la variable $_view property dans votre présentation, avec le nom de la vue (sans son suffixe), ou en passant un nom de vue personnalisé lors du traitement de la présentation.

Nous allons, à présent, créer la présentation depuis le contrôleur :

$presentation = Presenter::forge('index');

Nous avons, maintenant, tout paramétré. Cependant, il n'y a toujours pas de données passées à la vue. Elle a toujours besoin d'obtenir des valeurs $string $title et $articles en tableau. Nous faisons cela en ajoutant une méthode view() à la présentation à laquelle sera assignée cette donnée :

class Presenter_Index extends Presenter
{

public function view()
{
$this->title = 'Test cette présentation';

$this->articles = Model_Articles::find('all');
}
}

Et c'est fait.

Dans votre code, les vues et présentations sont interchangeables. Vous pouvez retourner une présentation depuis vos actions contrôleur. Vous pouvez donc installer une présentation comme un thème partiel, ou l'assigner à une section de votre template. L'API basique de la présentation est compatible avec la vue, il est donc facile de changer une vue en présentation dans votre code sans avoir à effectuer de révision majeure.

7-5-3 - Passage de fonctions à des vues

Pour passer une fonction de vue spécifique depuis votre présentation à votre vue, vous utilisez les Closures (fermetures) :

// Dans la présentation
class Presenter_Index extends Presenter
{

public function view()
{
$this->echo_upper = function($string) { echo strtoupper($string); };
}
}

// Ce que vous pouvez ensuite utiliser dans votre vue:
$echo_upper('this string'); // Outputs: "THIS STRING"

7-5-4 - Sécurité

La sécurité de la présentation est similaire à celle de la vue. Ce qui signifie que ce qui est fixé par la présentation va être sorti encodé aussi longtemps que vous ne le désactivez pas. Vous pouvez utiliser directement la même méthode set ($nom,$valeur,$encodage) dans la présentation comme vous l'utilisez dans la vue. Plus d'informations dans la section sécurité des vues.

7-5-5 - Usage avancé

7-5-5-a - Gestion de plusieurs méthodes

S'il y a plusieurs façons de parser la même vue, vous pouvez ajouter de multiples méthodes à la présentation autres que la méthode par défaut view(). Pour utiliser cela, vous avez besoin d'ajouter les noms de méthode comme un second paramètre à la méthode Presenter::forge() :

// va appeler une autre method() au-dessus de la présentation
$presentation = Presenter::forge('index', 'autre_methode');

7-5-5-b - Les méthodes before et after

Si vous avez besoin d'avoir certaines données ajoutées pour toutes les méthodes de la présentation, vous pouvez ajouter une méthode before() et after(), juste comme vous pouvez le faire avec les contrôleurs.

7-5-5-c - Changer la vue

Par défaut, $this->_view récupère l'objet de type vue lui étant assigné. Vous pouvez remplacer cet objet en faisant votre propre méthode set_view() dans la présentation et régler la $this->_view à un objet de votre choix.

Cependant, cet objet doit vous permettre de paramétrer ses propriétés (lesquelles sont utilisées comme template de données) et doit avoir la méthode magique __toString() qui effectuera le rendu et retournera le contenu parsé. En d'autres mots, il doit être compatible avec le comportement de la classe vue. Le nom de la vue attendue est disponible dans la propriété $this->_view property.

7-5-5-d - Utiliser un fichier de vue différent, ou un objet vue existant

Vous pouvez aussi dire à l'instance de présentation d'utiliser une différente vue, et ne pas utiliser le mécanisme automatique pour déterminer la vue à charger, en utilisant le quatrième paramètre de la méthode forge() :

// utilisation de la vue 'autre/index' au lieu de 'index'
$presentation = Presenter::forge('index', 'autre_methode', null, 'autre/index');

// vous pouvez aussi passer directement un objet vue
$vue = View::forge('autre/index');
$presentation = Presenter::forge('index', 'autre_methode', null, $vue);

7-5-5-e - Accès à la vue

Vous pouvez utiliser la méthode get_view() pour accéder à l'objet vue depuis l'extérieur de la présentation.

7-5-5-f - Utilisation des présentations depuis un autre namespace ou sans Presenter_ prefixed

Si vous voulez utiliser des présentations depuis un autre namespace ou sans Presenter_ prefixed, vous devez utiliser le nom complet de la classe avec forge(), en incluant le namespace. Dans ces cas, le nommage par défaut ne fonctionnera souvent pas comme attendu, donc fixer $_view property ou un nom de vue personnalisé est encouragé.

8 - Requêtes HMVC

Les requêtes HMVC sont un grand moyen de séparer la logique et réutiliser la logique contrôleur à de multiples endroits. Un usage commun des requêtes HMVC, est que quand vous utilisez un thème ou un moteur de templates pour générer vos pages, ou chaque page est divisée en sections, et les sections sont peuplées par des widgets. En utilisant des modules pour produire la sortie widget, vous pouvez créer une application hautement populaire avec des composants faciles à réutiliser.

Vous appelez une méthode de contrôleur de module en utilisant la classe Request :

// récupération de la sortie d'un contrôleur
$widget = Request::forge('mycontroller/mymethod/parms')->execute();
echo $widget;

// ou récupération de la sortie d'un module
$widget = Request::forge('mymodule/mycontroller/mymethod/parms', false)->execute();
echo $widget;

// et si vous avez besoin de passer certaines données
$widget = Request::forge('mymodule/mycontroller/mymethod/parms', false)->execute(array('tree'=>'apple'));
echo $widget;

Par défaut, toutes les demandes effectuées sont traitées par le moteur de routage de FuelPHP. Si vous voulez demander quelque chose qui n'est pas routable (par exemple, dans le cas où vous ne voulez pas qu'un navigateur les demande), vous devriez passer 'false' comme second paramètre à l'appel de forge() , si vous ne voulez pas aboutir à une erreur 404 quand vous exécutez la demande.

Charger des vues en requête HMVC est identique à charger des requêtes normales et contrôleur, accédées par une requête HMVC, et sont également accessibles depuis le navigateur.
Néanmoins, dans certains cas, vous ne voudrez pas le composant (par exemple, un widget) soit accédé via le navigateur. L'exemple suivant vous montre comment le vérifier pour une requête HMVC :

<?php

class Controller_Widget extends Controller
{

public function action_show()
{
if( ! Request::is_hmvc())
{
// requête principale
}
else
{
// requête HMVC
}
}

}

8-1 - Erreur 404 pendant une requête HMVC

Quand une erreur 404 se produit pendant une requête HMVC, une HttpNotFoundException est levée. Si non traitée, elle va déclencher le chargement de la page 404 par défaut du framework. Cependant, vous pouvez prévenir ceci en gérant votre propre page 404 :

try
{
\Request::forge('this_will_fail');
}
catch (HttpNotFoundException $e)
{
// Gestion exception
}

8-2 - Traversée d'une instance de requête

Si vous voulez accéder à d'autres requêtes, vous pouvez les traverser en utilisant deux méthodes : $request->parent() et $request->children(). Le parent est la requête durant laquelle la requête courante a été créée (null pour la requête principale). Les enfants sont toutes les requêtes créées durant la requête courante.

9 - Génération de code avec Oil

La génération de code peut être utilisée pour accélérer le temps de développement en construisant la majorité du code répétitif pour vous. Ceci est entièrement optionnel, comme tout le reste dans oil ; et le code peut être édité comme bon vous semble à la suite. Vous pouvez générer les éléments suivants :

- les contrôleurs ;

- les modèles ;

- les présentations ;

- les migrations ;

- l'échafaudage ;

- l'échafaudage administrateur ;

- les tâches ;

- les configurations ;

- les packages ;

- les modules.

9-1 - Les contrôleurs

Pour générer un squelette de contrôleur avec des actions et des vues prédéfinies, utilisez la commande suivante :

$ php oil g controller posts action1 action2 action3
Created view: APPPATH/views/posts/action1.php
Created view: APPPATH/views/posts/action2.php
Created view: APPPATH/views/posts/action3.php
Created controller: APPPATH/classes/controller/posts.php

Ceci va produire un contrôleur ressemblant à ça :

class Controller_Posts extends Controller_Template
{

public function action_action1()
{
$this->template->title = 'Posts  Action1';
$this->template->content = View::forge('posts/action1');
}

public function action_action2()
{
$this->template->title = 'Posts  Action2';
$this->template->content = View::forge('posts/action2');
}

public function action_action3()
{
$this->template->title = 'Posts  Action3';
$this->template->content = View::forge('posts/action3');
}

}

/* Fin de fichier posts.php */

9-2 - Les modèles

Pour générer un simple modèle en énumérant les champs, et bénéficier de la migration automatique des paramètres, il faut exécuter les commandes suivantes :

$ php oil g model post title:varchar[50] body:text user_id:int
Created model: APPPATH/classes/model/post.php
Created migration: APPPATH/migrations/001_create_posts.php

Ceci va créer un modèle simple qui utilise Orm, donc assurez-vous que le package est activé dans votre fichier de configuration. Il ressemblera à :

class Model_Post extends Orm\Model {

protected static $_properties = array(
'id',
'title',
'body',
'created_at',
'updated_at'
);

protected static $_observers = array(
'Orm\Observer_CreatedAt' => array(
'events' => array('before_insert'),
'mysql_timestamp' => false,
),
'Orm\Observer_UpdatedAt' => array(
'events' => array('before_save'),
'mysql_timestamp' => false,
),
);

}

/* Fin de fichier post.php */

Pas très extraordinaire, mais la migration est la partie utilisée ici :

namespace Fuel\Migrations;

class Create_posts
{
public function up()
{
\DBUtil::create_table('posts', array(
'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true),
'title' => array('constraint' => 50, 'type' => 'varchar'),
'body' => array('type' => 'text'),
'user_id' => array('constraint' => 11, 'type' => 'int'),
'created_at' => array('type' => 'datetime'),

), array('id'));
}

public function down()
{
\DBUtil::drop_table('posts');
}
}

Si vous ne souhaitez pas générer une migration, fournissez simplement -no-migration :

$ php oil g model post title:varchar[50] body:text user_id:int --no-migration
Created model: APPPATH/classes/model/post.php

Par défaut, le nom de classe est généré singulièrement (il représente un post), mais la table correspondante est générée de façon plurielle (contient des posts multiples). Vous pouvez faire utiliser à la table le même nom que le modèle en utilisant -singular.

9-3 - Génération de modèles en utilisant Model_Crud

FuelPHP v1.1 a ajouté un modèle simple basé sur le modèle CRUD lequel offre une fonctionnalité similaire à l'utilisation d'ORM, sans surcharge des données relationnelles. Vous pouvez avoir le modèle généré par l'ajout de --crud.

$ php oil g model post title:varchar[50] body:text user_id:int created_at:datetime --crud
Created model: APPPATH/classes/model/post.php
Created migration: APPPATH/migrations/001_create_posts.php

Ceci va créer un modèle simple qui utilise Fuel\Core\Model_Crud. Il ressemblera à ça :

class Model_Post extends \Model_Crud
{
protected static $_properties = array(
'id',
'title',
'body',
'user_id',
'created_at',
'updated_at'
);

protected static $_table_name = 'posts';

}

9-4 - Génération de modèle sans option TimeStamp

Ajoutez -no-timestamp pour exclure les champs reated/updated et les observateurs.

$ php oil g model post title:varchar[50] body:text user_id:int --no-timestamp

class Model_Post extends \Orm\Model
{
protected static $_properties = array(
'id',
'title',
'body',
'user_id'
);

}
namespace Fuel\Migrations;

class Create_posts
{
public function up()
{
\DBUtil::create_table('posts', array(
'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true),
'title' => array('constraint' => 50, 'type' => 'varchar'),
'body' => array('type' => 'text'),
'user_id' => array('constraint' => 11, 'type' => 'int'),

), array('id'));
}

public function down()
{
\DBUtil::drop_table('posts');
}
}

9-5 - Changer le TimeStamp et les champs de TimeStamp

Quand vous utilisez les champs de TimeStamp dans n'importe quel modèle ORM ou CRUD (\Model_Crud) vous pouvez choisir vos propres noms de champ. Il suffit d'utiliser les options --created-at et -updated-at pour fixer vos propres noms de champ.

Par défaut, quand vous activez les timestamps, ceux-ci sont stockés en temps UNIX, dans un entier. Si vous préférez le format MySQL DATETIME, vous pouvez utiliser l'option -mysql-timestamp.

$ php oil g model post title:varchar[50] body:text user_id:int --mysql-timestamp --created-at=my_created

Ce qui donnera :

<?php

class Model_Post extends \Orm\Model
{
protected static $_properties = array(
'id',
'title',
'body',
'user_id',
'my_created',
'updated_at'
);

protected static $_observers = array(
'Orm\Observer_CreatedAt' => array(
'events' => array('before_insert'),
'mysql_timestamp' => true,
'property' => 'my_created',
),
'Orm\Observer_UpdatedAt' => array(
'events' => array('before_save'),
'mysql_timestamp' => true,
),
);
}
<?php

namespace Fuel\Migrations;

class Create_posts
{
public function up()
{
\DBUtil::create_table('posts', array(
'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true),
'title' => array('constraint' => 50, 'type' => 'varchar'),
'body' => array('type' => 'text'),
'user_id' => array('constraint' => 11, 'type' => 'int'),
'my_created' => array('constraint' => 11, 'type' => 'int'),
'updated_at' => array('constraint' => 11, 'type' => 'int'),

), array('id'));
}

public function down()
{
\DBUtil::drop_table('posts');
}
}

9-6 - Générer un modèle en utilisant Model_Soft

FuelPHP v1.5 a ajouté un modèle Model_Soft, basé sur le modèle ORM. Il suffit d'ajouter -soft-delete pour utiliser Model_Soft.

$ php oil g model post title:varchar[50] body:text user_id:int --soft-delete

Ce qui donnera :

<?php

class Model_Post extends \Orm\Model_Soft
{
protected static $_properties = array(
'id',
'title',
'body',
'user_id',
'created_at',
'updated_at',
'deleted_at',
);

protected static $_observers = array(
'Orm\Observer_CreatedAt' => array(
'events' => array('before_insert'),
'mysql_timestamp' => false,
),
'Orm\Observer_UpdatedAt' => array(
'events' => array('before_update'),
'mysql_timestamp' => false,
),
);

protected static $_soft_delete = array(
'mysql_timestamp' => false,
);
}
<?php

namespace Fuel\Migrations;

class Create_posts
{
public function up()
{
\DBUtil::create_table('posts', array(
'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true, 'unsigned' => true),
'title' => array('constraint' => 50, 'type' => 'varchar'),
'body' => array('type' => 'text'),
'user_id' => array('constraint' => 11, 'type' => 'int'),
'created_at' => array('constraint' => 11, 'type' => 'int', 'null' => true),
'updated_at' => array('constraint' => 11, 'type' => 'int', 'null' => true),
'deleted_at' => array('constraint' => 11, 'type' => 'int', 'null' => true),

), array('id'));
}

public function down()
{
\DBUtil::drop_table('posts');
}
}

Si vous souhaitez changer le nom du champ deleted_at, utilisez l'option -deleted-at pour fixer votre propre nom de champ.

$ php oil g model post title:varchar[50] body:text user_id:int --soft-delete --deleted-at=mydeleted

9-7 - Générer un modèle en utilisant Model_Temporal

Ajoutez -temporal pour utiliser Model_Temporal.

$ php oil g model post title:varchar[50] body:text user_id:int --temporal

Ce qui vous donnera :

<?php

class Model_Post extends \Orm\Model_Temporal
{
protected static $_properties = array(
'id',
'temporal_start',
'temporal_end',
'title',
'body',
'user_id',
);

protected static $_temporal = array(
'mysql_timestamp' => false,
);

protected static $_primary_key = array('id', 'temporal_start', 'temporal_end');
protected static $_table_name = 'posts';

}
<?php

namespace Fuel\Migrations;

class Create_posts
{
public function up()
{
\DBUtil::create_table('posts', array(
'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true, 'unsigned' => true),
'temporal_start' => array('constraint' => 11, 'type' => 'int'),
'temporal_end' => array('constraint' => 11, 'type' => 'int'),
'title' => array('constraint' => 50, 'type' => 'varchar'),
'body' => array('type' => 'text'),
'user_id' => array('constraint' => 11, 'type' => 'int'),

), array('id'));
}

public function down()
{
\DBUtil::drop_table('posts');
}
}

Veuillez noter que temporal_start et temporal_end ne sont pas ajoutés à la clé primaire du tableau de migration. Vous devez les ajouter manuellement. Le paramètre --no-timestamp est fixé à true par défaut. Ce qui signifie que la création de champs created_at and updated_at et les observateurs connexes sont omis. Vous pouvez contourner ce comportement par défaut avec -no-timestamp=0 pour les retrouver.

Si vous souhaitez changer le nom des champs temporal_start ou temporal_end, utilisez les options --temporal-start ou -temporal-end pour fixer vos propres noms de champ.

$ php oil g model post title:varchar[50] body:text user_id:int --temporal --temporal-start=mystart --temporal-end=myend

9-8 - Générer un modèle en utilisant Model_Nestedset.

Pour générer un modèle Model_Nestedset, il faut ajoutez -nestedset.

$ php oil g model post title:varchar[50] body:text user_id:int --nestedset

Ce qui vous donnera :

<?php

class Model_Post extends \Orm\Model_Nestedset
{
protected static $_properties = array(
'id',
'left_id',
'right_id',
'title',
'body',
'user_id',
);

protected static $_table_name = 'posts';
}
<?php

namespace Fuel\Migrations;

class Create_posts
{
public function up()
{
\DBUtil::create_table('posts', array(
'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true, 'unsigned' => true),
'left_id' => array('constraint' => 11, 'type' => 'int', 'unsigned' => true),
'right_id' => array('constraint' => 11, 'type' => 'int', 'unsigned' => true),
'title' => array('constraint' => 50, 'type' => 'varchar'),
'body' => array('type' => 'text'),
'user_id' => array('constraint' => 11, 'type' => 'int'),

), array('id'));
}

public function down()
{
\DBUtil::drop_table('posts');
}
}

--no-timestamp est fixé à true par défaut, ce qui signifie la création des champs created_at et updated_at et leurs observateurs respectifs sont omis. Vous pouvez contourner ce comportement par défaut avec--no-timestamp=0 pour les retrouver.

Si vous souhaitez changer les noms de champ title, tree_id, left_id, right_id, utilisez une des options --title, --tre-id, --left-id, --right-id pour fixer vos propres noms de champ.

$ php oil g model post title:varchar[50] body:text user_id:int --nestedset --title=mytitle --tree-id=mytreeid --left-id=myleftid --right-id=myrightid

9-9 - Les présentations

Optionnellement, vous pouvez avoir à générer une classe présentation pour accompagner la vue.

$ php oil g controller posts action1 action2 action3 --with-presenter

9-10 - Lancer des migrations

Les commandes suivantes illustrent comment utiliser la commande refine pour lancer des tâches de migration utiles, en supposant que le système est actuellement en migration. La tâche de migration peut recevoir en paramètre une version donnée ou up/down pour migration à une version d'écart.

$ php oil refine migrate
Currently on migration: 5.

$ php oil refine migrate --version=4
Migrated to version: 4.

$ php oil refine migrate --version=5
Migrated to version: 5.

$ php oil refine migrate:down
Migrated to version: 4.

$ php oil refine migrate:up
Migrated to version: 5.

Les types de champs suivant sont supportés : string[n], varchar[n], int[n], enum[value1, value2], decimal[n, n], float[n, n], text, blob, datetime, date, timestamp et time.

9-11 - Générer des migrations

Vous pouvez générer des migrations sans créer un modèle. Cela pourrait être utilisé pour renommer une table, ou ajouter des champs à une table d'une façon, qui sera facile à déployer dans d'autres environnements.

$ php oil generate migration rename_table_users_to_accounts
Building magic migration: rename_table
Created migration: APPPATH/migrations/002_rename_table_users_to_accounts.php

9-12 - Magic_Migrations

Les Magic_Migrations sont un certain nombre de migrations « magiques », lesquelles vous construisent automatiquement une migration basée sur un préfixe de votre nom de migration.

$ php oil generate migration create_users name:text email:string[50] password:string[125]
$ php oil generate migration rename_table_users_to_accounts
$ php oil generate migration add_bio_to_accounts bio:text
$ php oil generate migration delete_bio_from_accounts bio:text
$ php oil generate migration rename_field_name_to_username_in_accounts
$ php oil generate migration drop_accounts

Attention à ce que lors du renommage de vos migrations, celles-ci ne commencent pas avec n'importe quel mot clé, par accident.

9-13 - L'échafaudage

L'échafaudage est vraiment la partie la plus passionnante de la génération de code Oil. Cette approche est empruntée à Rails qui y a apporté de nombreuses améliorations. L'idée n'étant pas seulement de créer des squelettes MVC et de migrations, mais de les peupler avec du code CRUD par défaut, le code fonctionne donc après avoir écrit la commande.

$ php oil g scaffold monkey name:string description:text
Created model: APPPATH/classes/model/monkey.php
Created migration: APPPATH/migrations/003_create_monkeys.php
Created controller: APPPATH/classes/controller/monkeys.php
Created view: APPPATH/views/monkeys/index.php
Created view: APPPATH/views/monkeys/view.php
Created view: APPPATH/views/monkeys/create.php
Created view: APPPATH/views/monkeys/edit.php
Created view: APPPATH/views/monkeys/_form.php

$ php oil refine migrate
Migrated to latest version: 3.

Comme vous pouvez le voir, une grande partie du code est générée par cette commande incluant une commande exécutée dans la seconde commande. Le contrôleur ressemble à ceci :

class Controller_Monkey extends Controller_Template
{

public function action_index()
{
$data['monkeys'] = Model_Monkey::find('all');
$this->template->title = "Monkeys";
$this->template->content = View::forge('monkey/index', $data);

}

public function action_view($id = null)
{
$data['monkey'] = Model_Monkey::find($id);

$this->template->title = "Monkey";
$this->template->content = View::forge('monkey/view', $data);

}

public function action_create($id = null)
{
if (Input::method() == 'POST')
{
$monkey = Model_Monkey::forge(array(
'name' => Input::post('name'),
'description' => Input::post('description'),
));

if ($monkey and $monkey->save())
{
Session::set_flash('success', 'Added monkey #'.$monkey->id.'.');

Response::redirect('monkey');
}

else
{
Session::set_flash('error', 'Could not save monkey.');
}
}

$this->template->title = "Monkeys";
$this->template->content = View::forge('monkey/create');

}

public function action_edit($id = null)
{
$monkey = Model_Monkey::find($id);

if (Input::method() == 'POST')
{
$monkey->name = Input::post('name');
$monkey->description = Input::post('description');

if ($monkey->save())
{
Session::set_flash('success', 'Updated monkey #' . $id);

Response::redirect('monkey');
}

else
{
Session::set_flash('error', 'Could not update monkey #' . $id);
}
}

else
{
$this->template->set_global('monkey', $monkey, false);
}

$this->template->title = "Monkeys";
$this->template->content = View::forge('monkey/edit');

}

public function action_delete($id = null)
{
if ($monkey = Model_Monkey::find($id))
{
$monkey->delete();

Session::set_flash('success', 'Deleted monkey #'.$id);
}

else
{
Session::set_flash('error', 'Could not delete monkey #'.$id);
}

Response::redirect('monkey');

}
}

9-14 - L'échafaudage d'administration

Vous pouvez échanger l'échafaudage avec l'administration et générer un contrôleur qui étend Controller_Admin au lieu de Controller_Template. À la première utilisation de cette commande un squelette administration sera généré. Pour étendre ce squelette, utilisez l'argument skip force. Pour générer dans des sous-dossiers nommez le préfixe avec le nom de modèle en conséquence.

$ php oil g admin project_entry title:string abstract:text full_text:text project_id:int is_draft:int order:int -s
Creating migration: APPPATH/migrations/012_create_project_entries.php
Creating model: APPPATH/classes/model/project/entry.php
Creating controller: APPPATH/classes/controller/admin/project/entry.php
Creating view: APPPATH/views/admin/project/entry/index.php
Creating view: APPPATH/views/admin/project/entry/view.php
Creating view: APPPATH/views/admin/project/entry/create.php
Creating view: APPPATH/views/admin/project/entry/edit.php
Creating view: APPPATH/views/admin/project/entry/_form.php

9-15 - Tâches

Vous pouvez aussi utiliser Oil pour générer le squelette d'une nouvelle tâche.

$ php oil g task newtask cmd1 cmd2

Ce qui générera :

<?php

namespace Fuel\Tasks;

class Newtask
{
public static function run($args = NULL)
{
echo "\n===========================================";
echo "\nLancer une tache par DEFAUT [Newtask:Run]";
echo "\n-------------------------------------------\n\n";

/***********************************
Mettez les DÉTAILS DE LA TÂCHE ICI
***********************************/
}

public static function cmd1($args = NULL)
{
echo "\n===========================================";
echo "\nLancement tache [Newtask:Cmd1]";
echo "\n-------------------------------------------\n\n";

/***********************************
Mettez les DÉTAILS DE LA TÂCHE ICI
***********************************/
}

public static function cmd2($args = NULL)
{
echo "\n===========================================";
echo "\nLancement tache [Newtask:Cmd2]";
echo "\n-------------------------------------------\n\n";

/***********************************
Mettez les  DÉTAILS DE LA TÂCHE ICI
***********************************/
}
}
/* End of file tasks/newtask.php */

9-16 - Configurations

Pour générer une configuration, utilisez la commande suivante :

$ php oil g config sample hello:world
Created config: APPPATH/config/sample.php

Ce qui produira une configuration ressemblant à ceci :

return array (
'hello' => 'world',
);

/* Fin de fichier echantillon.php */

9-17 - Générer une configuration depuis COREPATH

Pour combiner une configuration depuis COREPATH/config si COREPATH/config n'en a pas :

$ php oil g config package
Created config: APPPATH/config/package.php

Ceci produira une configuration ressemblant à cela :

return array (
'sources' =>
array (
0 => 'github.com/fuel-packages',
),
);

9-18 - Forçage de la mise à jour de la configuration depuis COREPATH et APPPATH

Pour combiner la configuration depuis COREPATH/config et COREPATH/config vers APPPATH/config, il faut exécuter la commande suivante :

$ php oil g config form --overwrite
Created config: APPPATH/config/form.php

Ceci produira une configuration ressemblant à cela :

return array (
'prep_value' => true,
'auto_id' => true,
'auto_id_prefix' => '',
'form_method' => 'post',
);

/* Fin de fichier formulaire.php */

9-19 - Les packages

Pour générer un package, utilisez la commande suivante :

$ php oil g package sample
Creating file: PKGPATH/sample/classes/sample.php
Creating file: PKGPATH/sample/config/sample.php
Creating file: PKGPATH/sample/bootstrap.php

Le chemin par défaut où est généré le package est PKGPATH, mais il peut être modifié dans la configuration package_paths en passant l'option --path=package_path ou -p=package_path à la commande.

9-19-1 - Générer un package « driver-based »

Si vous souhaitez générer un package driver-based, il suffit de fournir l'option -drivers ou -d.

$ php oil g package sample -d
Creating file: PKGPATH/sample/classes/sample.php
Creating file: PKGPATH/sample/classes/sample/driver.php
Creating file: PKGPATH/sample/config/sample.php
Creating file: PKGPATH/sample/bootstrap.php

Vous pouvez aussi générer vos propres drivers. Pour cela, il faut passez simplement les noms de driver séparés par virgules à l'option -drivers ou -d.

$ php oil g package sample -d=driver1,driver2
Creating file: PKGPATH/sample/classes/sample.php
Creating file: PKGPATH/sample/classes/sample/driver.php
Creating file: PKGPATH/sample/classes/sample/driver1.php
Creating file: PKGPATH/sample/classes/sample/driver2.php
Creating file: PKGPATH/sample/config/sample.php
Creating file: PKGPATH/sample/bootstrap.php

9-19-2 - Générer un package avec des fichiers VCS

Si vous souhaitez générer les fichiers composer.json et README.md pour votre package, fournissez simplement l'option --vcs ou -v :

$ php oil g package sample -v
Creating file: PKGPATH/sample/composer.json
Creating file: PKGPATH/sample/README.md
Creating file: PKGPATH/sample/classes/sample.php
Creating file: PKGPATH/sample/config/sample.php
Creating file: PKGPATH/sample/bootstrap.php

9-19-3 - Les modules de package

Pour générer un module, utilisez la commande suivante :

$ php oil g module blog

Cette commande va créer un dossier nommé blog dans le module de votre application module path dans config.module_paths. Si vous avez des chemins de modules multiples définis, vous aurez une liste de chemins que vous pouvez choisir, par exemple :

$ php oil g module blog

Si votre application a des multiples chemins définis, choisissez le chemin approprié depuis la liste ci-dessous :

1. /var/www/fuel/shared/modules/

2. /var/www/fuel/app/modules/

Pour assurer, plus facilement une génération de modules, vous pouvez fournir l'option -folders avec une liste de dossiers séparés par une virgule à créer. Ceux-ci peuvent être imbriqués presque indéfiniment et vous n'avez pas besoin de fournir chaque dossier parent. Un exemple court utile peut être :

$ php oil g module blog --folders=classes/model,classes/controller,config,lang

10 - Les tâches

10-1 - Qu'est-ce qu'une tâche ?

Les tâches sont des classes qui peuvent être exécutées en ligne de commande, ou planifiées dans un job cron. Elles sont généralement utilisées pour des processus en arrière-plan (background), des tâches chronométrées, et des tâches de maintenance. Les tâches peuvent appeler des modèles ou d'autres classes comme pour les contrôleurs.

10-2 - Créer une tâche

Dans FuelPHP, les contrôleurs sont placés dans le dossier fuel/app/tasks. Ci-dessous, un exemple de tâche « exemple » :

namespace Fuel\Tasks;

class Exemple
{

public function run($message = 'Hello!')
{
echo $message;
}
}

Ceci sera appelé via l'utilitaire refine dans Oil :

$ php oil refine exemple "Bonjour"

Quand le nom de la tâche est utilisé dans la commande, la méthode « run() » est appelée.

10-3 - Fractionner une tâche en plusieurs méthodes

Vous pouvez ajouter plus de méthodes à votre tâche pour fractionner un groupe de tâches en tâches plus spécifiques pouvant être appelées séparément.

public function current_date()
{
echo date('Y-m-d');
}

Nous pouvons appeler cette méthode en utilisant :

$ php oil refine example:current_date

11 - Les modules

11-1 - Qu'est-ce qu'un module ?

Un module est un groupe d'éléments MVC indépendants. L'utilisation de modules permet la réutilisation possible et l'encapsulation de votre code. Un module réside habituellement dans un sous-dossier nommé modules. Il est suggéré de profiter des modules chaque fois que vous travaillez sur un gros projet, quand vous pensez que le code de base fera plus que quelques lignes de code. Cela vous aidera à ranger soigneusement les choses.

Un module peut agir indépendamment, par exemple un module de blog ou d'album. Vous pouvez router directement vers le module controllers, sans avoir à accéder au code global. Les modules peuvent aussi être utilisés dans un réel contexte HMVC, là où les contrôleurs appellent d'autres contrôleurs, lesquels vont produire (une partie) le résultat souhaité pour générer le résultat de la page demandée.

11-2 - Configuration des modules

Pour pouvoir utiliser des modules, vous devez dire à FuelPHP où ceux-ci sont stockés. Par défaut, ils sont dans le dossier modules de votre application. Pour définir le chemin d'accès à vos modules, il vous faut modifier la ligne « modules_path » du fichier config.php de votre application. Vous pouvez aussi définir plusieurs chemins d'accès, si vous le faites, ils seront utilisés pour la recherche des modules dans l'ordre que vous aurez définis.

/**
* Pour vous permettre de découper votre application en modules pouvant                   * être routés par le premier segment URI, vous devez définir leur chemin de *base ici.
**/
'module_paths' => array(
APPPATH.'modules'.DS,               // chemin des modules d'application
APPPATH.'..'.DS.'globalmods'.DS     // chemin global vers vos modules
),

Quand vous définissez vos chemins, assurez-vous qu'ils finissent par « DS », le séparateur de dossier de FuelPHP.

11-3 - Namespaces de module

Un des problèmes souvent rencontrés en travaillant avec du code développé indépendamment, c'est l'éventualité des collisions de noms de classes. Par exemple, beaucoup de modules sont fournis avec un contrôleur admin. Pour éviter les collisions dans FuelPHP, chaque module n'est défini que dans son propre espace de noms, lequel doit être nommé à l'identique du nom du dossier du module.

<?php
/**
* contrôleur du module dans le module Monmodule
*/

namespace Monmodule;

class Controller_Widget
{

// placez le code de votre contrôleur ici, tout comme pour un contrôleur d'application
}

Si vous avez déplacé vos contrôleurs dans un namespace comme expliqué ici, vous devez utiliser le même setup pour vos contrôleurs de module. Dans l'exemple, ci-dessus, le namespace sera Mymodule\Controller, le Widget classname.

11-4 - La structure d'un dossier module

Il faut commencer la création d'un module par la création d'un répertoire pour celui-ci, dans le dossier des modules défini dans la configuration. Les noms de dossiers déterminent les noms de module, et le namespace pour les classes de celui-ci. Ce nom est également utilisé dans l'URI, si vous voulez router les contrôleurs de module, ou comme partie d'une requête en cas d'appel HMVC.

Comme un module peut être vu comme une partie contenue dans votre propre application, vous remarquerez que la structure de dossier d'un module est très familière, c'est la même que la structure d'un dossier application. La structure de dossier suivante est prise en charge pour un module :

- classes

- contrôleur

- modèle

- vue

- configuration

- langue

- tâches

- vues

11-5 - Chargement de fichiers de module transversal

Que ce soit un fichier de configuration ou de vue, un chargement de fichier de module transversal doit avoir le module préfixé du nom de fichier :

// Chargement transversal de configuration
\Config::load('autremodule::myconfig');

// Chargement transversal d'une vue
\View::forge('autremodule::subdir/view');
Lance une tâche depuis le module :
$ php oil refine <nom_du_module>::<nom_tache>:<nom_methode>

11-6 - Routage de module

Quand vous utilisez des modules en mode routé, vous pouvez ajouter des routes personnalisées pour votre module en incluant un fichier routes.php dans votre dossier de configuration modules. Ces routes seront chargées quand FuelPHP détectera que le premier segment URI fera référence à un module, et seules les routes de ce module seront chargées. Ces routes seront ajoutées au début du tableau de routes de sorte qu'une possible route (n'importe laquelle) dans les routes principales de la configuration ne soit pas traitée avant celles du module.

Cela implique que les routes module peuvent être utilisées pour le routage global ou pour les autres modules. En d'autres termes, la partie gauche devrait toujours inclure le module courant comme premier segment d'URI. Pour la partie droite, vous pouvez utiliser tout ce qui est défini dans les sections ci-dessus. C'est très bien d'avoir une route de module dans un contrôleur d'application ou dans un autre module.

11-7 - Les modules et les requêtes HMVC

En plus d'utiliser les modules pour séparer logiquement les parties indépendantes de votre application, vous pouvez utiliser les contrôleurs de module dans un contexte HMVC, là où vos contrôleurs d'application appellent un ou plusieurs contrôleurs de module pour créer le résultat final d'une requête URI.

Lisez la documentation des requêtes HMVC pour en découvrir plus.

11-8 - Utiliser des classes de module en dehors de celui-ci

Il est possible d'utiliser une classe de module en dehors de celui-ci. Pour que cela fonctionne, FuelPHP a besoin d'être configuré pour autocharger la classe quand vous y faites référence, dans votre code. Ceci signifie que vous devez indiquer à FuelPHP où trouver le module. Il y a deux façons de le faire. Vous pouvez précharger le module en spécifiant le module à charger dans le réglage 'always_load', 'modules' du fichier config.php de votre application.

'always_load' => array(

/**
* Ces modules sont toujours chargés au démarrage de Fuel. Vous pouvez          *les spécifier de la manière suivante:
*
* array('module_name');
*
* Un chemin doit être réglé dans les chemins de module pour que ça      * fonctionne.
*/
'modules'   => array('mymodule'),

Vous pouvez également ajouter manuellement le module au démarrage, avant que vous utilisiez une des méthodes statiques :

// rend le module Mymodule accessible
Module::load('mymodule');
Vous appelez ensuite la classe de module comme ceci :
\Mymodule\Myclass::mymethod('params');

12 - Les packages

Quand il s'agit d'organiser, réutiliser et partager votre code, les packages sont un excellent moyen pour le faire. Ils peuvent contenir toute sorte de code comme des modèles, des bibliothèques tierces, des configurations, et bien d'autres éléments.

Les packages vous permettent aussi d'étendre le noyau sans compromettre votre dossier app/classes. Pour clarifier ce qu'est un package, voici en voici quelques avantages :

- une grande façon d'organiser votre code ;

- la fourniture d'une zone pour garder les bibliothèques tierces ;

- un moyen d'étendre d'autres packages sans toucher au code de quelqu'un d'autre ;

- un emplacement pour étendre FuelPHP sans corrompre les fichiers noyau.

Mais :

- les packages ne mappent pas les URL ;

- ils sont inaccessibles via des requêtes HMVC.

12-1 - Installer des packages

Installer des packages peut être fait manuellement ou via Oil. Pour installer un package, il faut télécharger manuellement ses sources, et le copier dans le dossier des packages, qui est par défaut : fuel/packages.

Pour être en mesure d'utiliser un package installé, vous devez l'ajouter à always_load dans votre fichier app/config/config.php ou utiliser Package::load().

12-2 - Installer des packages avec Oil

Les packages peuvent être téléchargés et installés manuellement. Grâce à la commande package, ces opérations peuvent être plus rapides. Cela fonctionne en recherchant les packages dans une liste de sources définies dans fuel/core/config/package.php qui peut être éditée comme tout autre fichier de configuration ou copiée depuis le dossier fuel/app/config.

Oil est intelligent, il va donc vérifier si vous avez Git installé sur votre ordinateur avant de faire quoi que ce soit. Si vous avez Git d'installé, Oil va installer un package comme un dépôt Git au lieu de directement télécharger les fichiers, rendant plus faciles les mises à jour, les nouvelles versions et le suivi de changement personnalisés dans le package.

12-2-1 - Installation

$ php oil package install test-package
Downloading package: git://github.com/philsturgeon/fuel-test-package.git
remote: Counting objects: 13, done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 13 (delta 3), reused 0 (delta 0)
Receiving objects: 100% (13/13), 10.85 KiB, done.
Resolving deltas: 100% (3/3), done.

Cloning into /Users/phil/Sites/fuel/fuel/packages/test-package...

Si Git n'est pas installé, ou que le flag -direct est fourni, alors le fichier .zip du package sera téléchargé et décompressé dans fuel/packages/nom_du_package.

$ php oil package install test-package --direct
Downloading package: http://github.com/philsturgeon/fuel-test-package/zipball/master
DOCROOT/fuel/packages/test-package/LICENSE.txt
DOCROOT/fuel/packages/test-package/README
DOCROOT/fuel/packages/test-package/classes/association.php
DOCROOT/fuel/packages/test-package/classes/belongsto.php
DOCROOT/fuel/packages/test-package/classes/exception.php
DOCROOT/fuel/packages/test-package/classes/hasmany.php
DOCROOT/fuel/packages/test-package/classes/hasone.php
DOCROOT/fuel/packages/test-package/classes/model.php

12-2-2 - Désinstallation

$ php oil package uninstall test-package
Uninstalling package "test-package"

Contrairement à l'installation, il n'y a pas de différence si Git est installé ou non, la procédure de désinstallation est la même.

12-3 - Créer des packages

Pour simplifier la compréhension des sources de votre application, il est mieux de structurer votre package comme ceci :

/packages
/package
/bootstrap.php
/classes
/vos.php
/classes.php
/ici.php
/config
/packageconfig.php
/et cetera

Chaque package devrait avoir un fichier bootstrap.php placé à la base de celui-ci. Il faut utiliser le bootstrap pour ajouter le namespace du package (globalement si vous le voulez), puis y ajouter les classes pour de meilleures performances.

// ajout namespace, nécessaire si vous voulez que l'autoloader puisse trouver les classes
Autoloader::add_namespace('Mypackage', __DIR__.'/classes/');

// Ajout comme namespace de noyau
Autoloader::add_core_namespace('Mypackage');

// Ajout comme namespace de noyau (les classes sont aliasés au global, ainsi utilisables sans préfixe de namespace)
// fixe le second argument à true pour préfixer et pouvoir écraser les classes de noyau
Autoloader::add_core_namespace('Mypackage', true);

// et ajoute les classes, c'est utile pour :
// - optimisation : aucun chemin de recherche nécessaire
// - nécessaire pour pouvoir utiliser comme namespace de noyau
// - si vous voulez casser les règles de recherche de chemin de l'autoloader
Autoloader::add_classes(array(
'Mypackage\\Classname' => __DIR__.'/classes/classname.php',
'Mypackage\\Anotherclass' => __DIR__.'/classes/anotherclass.php',
));

Une fois vos classes en place, vous pouvez commencer à les utiliser.

Si les namespaces de package ne sont pas aliasés au global, vous devez les fournir

// Si aliasé au global utilisez juste :
$instance = new Myclass;

// Quand non aliasé au global
$instance = new Mynamespace\Myclass;

13 - Le routage

Le routage de FuelPHP porte sur de simples routes statiques contrairement aux routes avancées dans le routage verbal HTTP. Les routes sont fixées, dans FuelPHP, dans le fichier /app/config/routes.php.

13-1 - Routes réservées

Dans FuelPHP, il y a quatre routes réservées : _root_, _403_, _404_ et _500_.

- _root_ : La route par défaut quand aucune URI n'est spécifiée ;

- _403_ : la route utilisée quand une application lance une HttpNoAccessException qui n'est pas interceptée ;

- _404_ : la route utilisée quand une application lance une HttpNotFoundException qui n'est pas interceptée ;

- _500_ : la route utilisée quand une application lance une HttpServerErrorException qui n'est pas interceptée.

La classe requête lance une HttpNotFoundException, quand vous demandez une URI (une route) que votre application ne peut pas résoudre.

Si no _404_ route est défini, le framework utilise son propre handler d'erreur pour afficher un message « Page non trouvée ». Si no _403_ ou _500_ route est défini, ces exceptions restent non interceptées, et sont gérées comme toute autre exception que votre application devrait lever.

return array(
'_root_'  => 'welcome/index',
'_404_'   => 'welcome/404',
);

13-2 - Routage de base

La route à gauche est comparée à la requête URI. Si une correspondance est trouvée,la requête est routée à l'URI sur la droite.

Ceci vous permet de faire des choses comme ci-dessous :

return array(
'about'   => 'site/about',
'contact' => 'contact/form',
'admin'   => 'admin/login',
);

13-3 - Routage semi-avancé

Vous pouvez inclure n'importe quel regex dans vos routes. La partie gauche est comparée à la requête URI, et la partie droite est le remplacement pour la gauche. Vous pouvez donc utiliser des références arrière dans la partie droite depuis le regex sur la gauche. Il y a aussi des déclarations spécifiques qui vous permettent de tout faire correspondre, ou seulement un segment :

- :any - cela fait correspondre quelque chose de ce point dans l'URI ;

- :segment - cela fait correspondre seulement un segment dans l'URI, mais ce segment peut être n'importe quoi ;

- :num - ceci fait correspondre n'importe quel nombre ;

- :alpha - ceci fait correspondre n'importe quel caractère alphabétique, incluant l'UTF-8 ;

- :alnum - ceci fait correspondre n'importe quel caractère alphanumérique, incluant l'UTF-8.

Voici quelques exemples :

return array(
'blog/(:any)'      => 'blog/entry/$1', // Routes /blog/entry_name to /blog/entry/entry_name
'(:segment)/about' => 'site/about/$1', // Routes /en/about to /site/about/en
'(\d{2})/about'    => 'site/about/$1', // Routes /12/about to /site/about/12
);

13-4 - Routage avancé

Vous pouvez aussi avoir nommé les paramètres dans vos routes. Ceci vous permet de donner les noms dans vos segments URI, lesquels peuvent être accédés depuis l'intérieur de vos actions.

Exemple :

return array(
'blog/:year/:month/:id' => 'blog/entry', // Routes /blog/2010/11/entry_name to /blog/entry
);

Dans l'exemple ci-dessus, on intercepte le nom blog/2010/11/entry. Il devrait ensuite router cette requête vers votre action 'entry' dans votre contrôleur 'blog'. Les paramètres nommés seront accessibles comme suit :

$this->param('year');
$this->param('month');
$this->param('id');

Notez que comme un paramètre nommé est une expression rationnelle (regex), chaque paramètre nommé est considéré comme une référence arrière. Donc dans une route comme ':name/(\d{2})',la référence arrière pour votre segment à deux chiffres est $2 et pas $1.

13-5 - Routage HTTP

Vous pouvez router vos URL vers des contrôleurs et actions basées sur le mot clé HTTP utilisé pour les appeler. Ceci rend facile et rapide la conception de contrôleur RESTful.

Exemple :

return array(
// Routes GET /blog to /blog/all and POST /blog to /blog/create
'blog' => array(array('GET', new Route('blog/all')), array('POST', new Route('blog/create'))),
);

Vous pouvez utiliser les paramètres nommés et les regex dans vos URL :

return array(
'blog/(:any)' => array(array('GET', new Route('blog/show/$1'))),
);

Vous pouvez aussi spécifier si cette route est prise en charge pour seulement HTTP, ou également HTTPS, en passant false ou true comme troisième paramètre :

// route seulement valide s'il s'agit d'une requête https
return array(
'blog/(:any)' => array(array('GET', new Route('blog/show/$1'), true)),
);

13-6 - Routes nommées et routage inverse

L'idée de route inversée se présente comme ceci : supposez que vous ayez une zone d'administration et que vous avez une route paramétrée pour elle. Dans vos vues, vous voudriez en utilisant une ancre HTML que cette zone d'administration soit accessible via le lien 'admin/start/overview'. Maintenant, vous décidez de déplacer des choses autour et finir par bouger cette page spécifique vers 'admin/overview'. À la suite de cela maintenant, vous devez mettre à jour les liens dans toutes les vues.

Lorsque vous utilisez le routage inverse avec ces noms de route vous pouvez lier une ancre à une route nommée, de sorte que lors de changements de route, les liens dans vos vues suivent automatiquement le changement.

Exemple de route :

return array(
'admin/start/overview' => array('admin/overview', 'name' => 'admin_overview'), // ajoute une route nommée pour la page admin/overview
);

Exemple d'ancre :

// produit <a href="http://your_base_url/admin/start/overview">Overview</a>
echo Html::anchor(Router::get('admin_overview'), 'Overview');

Notez que cela ne fonctionne actuellement que pour les routes qui sont définies dans app/config/routes.php, pas pour les routes de module.

13-7 - Routes inline

Une route n'a pas à se résoudre à une méthode de contrôleur. FuelPHP prend également en charge les routes inline, lesquelles sont définies comme une « closure » qui remplace la méthode du contrôleur. Comme les méthodes de contrôleur, les routes inline doivent retourner un objet de réponse, soit en en fabriquant un manuellement, ou soit suite à l'exécution d'une requête fabriquée.

Exemple de route :

return array(
'secret/mystuff' => function () {
// cette route fonctionne seulement en développement
if (\Fuel::$env == \Fuel::DEVELOPMENT)
{
return \Request::forge('secret/mystuff/keepout', false)->execute();
}
else
{
throw new HttpNotFoundException('Cette page est seulement accessible en développement.');
}
};

13-8 - Modules et routage

Pour en savoir plus sur le routage de modules

14 - Sécurité

Fuel prend la sécurité très au sérieux ; et comme résultat, a implémenté les mesures suivantes pour assurer la sécurité de vos applications Web :

- Les encodages de sortie ;

- Protection CSRF ;

- Filtrage XSS ;

- Filtrage d'entrée ;

- Injection SQL.

Par défaut, FuelPHP ne filtre pas les variables POST et GET à leur entrée, et encode tout vers la sortie. FuelPHP encode aussi les URI pour prévenir les mauvaises surprises lors d'utilisation de segments URI, et échappe tout ce qui va dans une base de données.

Cette partie explique les mesures de sécurité générale qu'offre FuelPHP. La classe sécurité est documentée dans la partie des classes. Vous trouverez également les détails de configuration de la classe sécurité sur cette page.

14-1 - Les encodages de sortie

Par défaut, FuelPHP favorise l'encodage de sortie par le filtrage d'entrée. Il y a deux raisons à cela :

1. Plus de souci sur la provenance de vos données, et filtrage ou non, l'encodage de sortie sera assuré lors de la transmission au client ;

2. Cela veut aussi dire que toute entrée est stockée en brut, sans aucun traitement ; donc en cas de problème, vous avez toujours vos données originales.

Cela signifie aussi que vous n'aurez pas de problèmes quand vous aurez besoin de données en format brut, sans aucune mise en forme. Un exemple commun : les données produites par les éditeurs HTLM tels que TinyCME ou ckeditor, utilisés dans beaucoup d'applications avec édition de contenu par l'utilisateur final. Dans ce cas, vous voudrez peut-être lancer le filtrage XSS sur ces variables d'entrées pour filtrer toute mauvaise surprise qui pourrait être glissée puisque c'est un exemple typique de données non voulues dans la sortie encodée.

Puisque l'encodage de sortie ne peut se passer que sur les chaînes, vous devez prêter attention aux objets que vous voulez passer à vos vues. Assurez-vous que votre objet contient une méthode __toString(), sur laquelle l'encodage peut s'exécuter. Il faut aussi ajouter votre classe d'objet à la classe whitelist dans la configuration de sécurité, sans oublier le namespace. Vous pouvez aussi la passer à la vue avec le flag $encode positionné à false. Il est possible d'utiliser la méthode auto_encode pour désactiver temporairement l'encodage de sortie sur une base par vue.

Vous pouvez consulter la section sur la sécurité des vues pour voir comment mieux sécuriser vos vues.

14-1-1 - Protection CSRF

La falsification « Cross-site », aussi connue sous le nom d'attaque un-clic ou 'session riding" en abrégé CSRF, est un type d'exploit malveillant sur un site Web par lequel des commandes non autorisées sont transmises par un utilisateur que le site Web reconnaît. Contrairement à une attaque Cross-site Scripting (XSS), qui exploite la confiance qu'a un utilisateur en un site en particulier, l'exploit CSRF exploite la confiance d'un site envers un utilisateur. L'attaque fonctionne en incluant un lien ou un script dans une page qui accède au site dans lequel l'utilisateur est connu (ou est supposé être authentifié).

Par exemple, un utilisateur, Bob, pourrait naviguer dans un chat de forum où un autre utilisateur, Mallaury, a posté un message. Supposons que Mallaury a conçu un élément d'image HTML qui référence une action sur le site Web de la banque de Bob (plutôt qu'un fichier image par exemple). Si la banque de Bob garde cette information d'authentification dans un cookie, et que ce cookie n'a pas expiré, la tentative de charger l'image par le navigateur de Bob va soumettre le formulaire de retrait avec son cookie, et ainsi autoriser une transaction sans l'approbation de Bob. Source : Wikipédia.

FuelPHP vous fournit les outils pour protéger vos formulaires contre ce type d'attaques, en incluant un jeton de sécurité dans le formulaire, qui peut être validé lors de la soumission de celui-ci, et assurera qu'une fois validé, le formulaire sera soumis par le client qui a effectué la requête.

La protection CSRF peut être configurée via la section sécurité dans le fichier de configuration config/config.php. Pour activer la protection CSRF, commencez par ajouter le jeton dans le formulaire :

// in plain HTML
<input type="hidden" name="<?php echo \Config::get('security.csrf_token_key');?>" value="<?php echo \Security::fetch_token();?>" />

// utilisation de la classe du formulaire
echo \Form::csrf();

// utilisation d'une instance de formulaire, va aussi rajouter la règle de validation dans le bloc de champs
$form = \Form::forge();
$form->add_csrf();

Pour manuellement vérifier si le formulaire a bien été soumis, par le client ayant traité le formulaire :

// contrôle si le formulaire a été soumis
if ($_POST)
{
// contrôle la validité du jeton CSRF
if ( ! \Security::check_token())
{
// attaque CSRF ou jeton CSRF expiré
}
else
{
// jeton valide, on peut traiter les entrées formulaire
}
}

14-1-2 - Filtrage XSS

FuelPHP fournit le filtrage XSS en utilisant la bibliothèque HTMLawed, une bibliothèque très rapide et hautement configurable. Par défaut, elle fonctionne en mode sécurisé et équilibré.

Le mode sécurisé fait référence au HTML restreint de façon à réduire les vulnérabilités aux attaques par scripts (telles que XSS), basé sur du code HTML, qui reste quand même légal et conforme aux spécifications standards. Quand des éléments tels que des objets ou des scripts, des attributs tels que onmouseover, et des styles sont autorisés dans le texte d'entrée, un saisisseur d'entrée peut introduire du code HTML malveillant.

En mode équilibré, HTMLawed contrôle et corrige les entrées pour avoir des tags équilibrés et du contenu d'élément légal (c'est-à-dire tout élément de niche devrait être valide, et le texte brut peut être présenté uniquement dans le contenu d'élément les autorisant).

Pour des raisons de performance, il est recommandé d'utiliser la méthode xss_clean sur des valeurs d'entrées individuelles, plutôt qu'un filtre d'entrée générique.

14-1-3 - Filtrage d'entrée

Bien que désactivé par défaut, vous pouvez configurer FuelPHP pour filtrer toutes les entrées ($_GET, $_POST et $_COOKIE), pour chaque requête de page. Pour le faire, configurez les méthodes ou fonctions à utiliser pour les filtrer dans vos fichiers config/config.php de vos applications.

/**
* réglages de sécurité
*/
'security' => array(
'input_filter' => array(),
)

Tout peut être appelé en PHP, et n'accepter qu'une seule valeur comme paramètre pouvant être utilisée à des fins de filtrage. Ceci inclut les fonctions telles que 'htmlentities', les méthodes de classe statiques comme '\\Security::xss_clean' , ou encore les méthodes d'objet définies comme array($objet, 'methode'). Si vous utilisez une méthode d'objet, assurez-vous que l'objet est disponible avant que FuelPHP ne soit initialisé, puisque le filtrage d'entrée s'effectue très tôt dans le processus de requête.

14-1-4 - Injection SQL

Une injection SQL est une technique d'injection de code qui exploite une vulnérabilité de sécurité survenant dans la couche base de données d'une application (comme les requêtes). La vulnérabilité est présente quand une entrée utilisateur mal filtrée comporte une chaîne de caractères avec des commandes SQL encapsulées, ou qu'une chaîne mal tapée génère une commande SQL. C'est un des types de vulnérabilités les plus courants, quand un langage ou un script en embarque un autre. Les attaques par injection SQL sont aussi connues sous le nom d'insertions SQL.

Cette forme d'injection SQL se produit quand les caractères d'échappement d'une entrée utilisateur ne sont pas filtrés et sont donc passés comme instruction SQL. Il en résulte une manipulation potentielle des instructions traitées dans la base de données par l'utilisateur final de l'application. Source Wikipédia.

FuelPHP protège contre les injections SQL en encapsulant toutes les valeurs passées à une des méthodes de classe de base de données, comme cela se passe au niveau du créateur de requêtes central, tout le code qui utilise le créateur de requêtes, incluant le package Fuel ORM, sera automatiquement encapsulé.

15 - La gestion des erreurs

Vous savez tous (ou devriez) que la gestion des erreursest une partie très importante dans le processus de développement. Non seulement elle montre à l'utilisateur que la page demandée n'est pas disponible, mais c'est aussi une façon d'informer les machines (telles que les navigateurs) de ce qui se passe en fournissant un statut d'erreur HTTP.

15-1 - Codes erreur

Le système interne de gestion d'erreurs de FuelPHP est basé sur les exceptions. Ceci permet de les intercepter dans votre code. Votre application peut donc gérer les exceptions levées, et l'utilisateur peut continuer à utiliser l'application.

FuelPHP altère également le comportement par défaut de PHP, quand une erreur PHP se présente (qui ne sont pas des exceptions) depuis les anciennes fonctions procédurales. Au lieu de continuer après toutes les erreurs fatales, FuelPHP va envoyer une PhpErrorException sur toutes ces erreurs. Ceci vous forcera à résoudre toutes les erreurs, même une E_NOTICE que vous auriez éventuellement ignorée. Il vous permettra également d'intercepter les erreurs PHP. Par exemple, pour intercepter les erreurs de syntaxe dans les fichiers de vue quand celles-ci ont été créées par des non-programmeurs.

Vous pouvez échanger ce comportement en ajoutant les types d'erreurs PHP (comme E_NOTICE ou E_STRICT) à la clé errors.continue_on dans vos fichiers config/config.php d'application. Les erreurs définies ici autoriseront vos scripts à continuer. Aucune exception ne sera levée pour ces erreurs, vous pouvez donc ne plus les intercepter.

Il est grandement conseillé de ne pas poursuivre votre code sans résoudre les erreurs, car elles pourraient conduire à des bogues, qui seront difficiles à repérer, une fois votre application passée en production !

15-2 - Les erreurs de logique d'application

15-2-1 - Erreur 404

La route 404 est fixée dans app/config/routes.php et doit pointer le contrôleur/la méthode qui gère les pages 404. Plus d'informations sur cela dans la section routage.

15-2-2 - Lancer un 404

Il peut y avoir des moments où on a besoin de lancer une erreur 404, comme gérer le routage soi-même. Cela s'effectue simplement en lançant une HttpNotFoundException. FuelPHP vous cède le contrôle de la page.

throw new HttpNotFoundException;

Cette exception est interceptée et traitée dans les fichiers index.php de vos applications. Quand elle est interceptée, elle va rechercher pour la route 404 définie, et si trouvée, va fabriquer une nouvelle requête en utilisant la route trouvée comme une URI pour la requête. Comme il s'agit d'une requête normale, l'URI va être routée comme toute autre requête.

Si vous ne voulez pas de ce fonctionnement, modifiez le fichier index.php comme suit :

// génère la requête, l'exécute, et envoie la sortie.
try
{
$reponse = Request::forge()->execute()->response();
}
catch (HttpNotFoundException $e)
{
$route = array_key_exists('_404_', Router::$routes) ? Router::$routes['_404_']->translation : Config::get('routes._404_');
if ($route)
{
// ajoute 'false' à la requête fabriquée, désactive le moteur de routage
$reponse = Request::forge($route, false)->execute()->response();
}
else
{
throw $e;
}
}

15-2-3 - Manipulation 404

Quand une demande est faite et après que le routeur aura cherché la correspondance et qu'il n'y en a pas, le gestionnaire 404 rentre en jeu. Par défaut, la _404_route pointe sur la méthode welcome/404, qui se présente comme suit :

// À l'intérieur du contrôleur_Welcome

/**
* l'action 404 pour l'application.
*
* @access  public
* @return  void
*/
public function action_404()
{
$messages = array('Aw, crap!', 'Bloody Hell!', 'Uh Oh!', 'Nope, not here.', 'Huh?');
$data['title'] = $messages[array_rand($messages)];

// fixe un header HTTP 404 sur la sortie
return Response::forge(Presenter::forge('welcome/404', $data), 404);
}

Vous pouvez voir ici ce qui se passe à l'intérieur du handler 404. Comme vous pouvez le voir, c'est un contrôleur d'action normale. Ce qui est intéressant avec cela, c'est qu'elle permet de montrer n'importe quel type de contenu sur la page. Vous pouvez charger vos propres vues avec des données récupérées dans la base de données.

Notez que Fuel ne fixe pas le statut 404, votre réponse doit fixer cela, retournez Response::forge(Presenter::forge('welcome/404'), 404); afin d'envoyer le header de statut correct.

15-2-4 - Tout intercepter

Comme FuelPHP ne fixe pas le statut de réponse 404, vous pouvez l'utiliser comme un intercepteur pour toutes les fonctions. Vous pourriez avoir un modèle de page qui remplit la page depuis une base de données depuis URI. Voici un exemple pour illustrer les possibilités :

// À l'intérieur de votre contrôleur 404

public function action_my404()
{
$original_uri = \Input::uri();
$result = \DB::select()->from('pages')->where('uri', $original_uri)->execute();
if(count($result) === 1)
{
// affiche cette page de quelque manière de votre choix
}
else
{
// affiche votre page générale 404
$messages = array('Aw, crap!', 'Bloody Hell!', 'Uh Oh!', 'Nope, not here.', 'Huh?');
$data['title'] = $messages[array_rand($messages)];
return Response::forge(View::forge('welcome/404', $data), 404);
}
}

15-2-5 - Lancer une erreur 500

Il peut avoir des moments où vos applications doivent impérativement s'arrêter, par exemple, quand il y a un souci majeur sur le serveur. Dans un tel cas, on a une erreur interne au serveur 500. Cette exception peut être interceptée en amont du contrôleur en définissant une _500_route. Cela vous permet de montrer un message d'erreur approprié, de faire du loging d'erreur additionnel, ou envoyer une notification à un administrateur pour gérer la résolution du problème.

Similaire au lancement d'une erreur 404, une exception peut lancer une erreur 500.

throw new HttpServerErrorException;

15-2-6 - Lancer une erreur 403

Si vous voulez une gestion centralisée des violations d'accès, vous pouvez choisir d'en signaler une en lançant une HttpNoAccessException. Cette exception peut être interceptée à l'avant du contrôleur en définissant une _403_ route. Le handler pourrait stocker l'URI courante par exemple, demander un login, et en cas de succès, retourner à l'URI stockée et donc l'utilisateur peut retourner à l'endroit de la violation d'accès.

Similaire au lancement d'une erreur 404, une exception peut lancer une erreur 403.

throw new HttpNoAccessException;

15-2-7 - Erreurs en mode CLI

Quand une erreur arrive en mode CLI, soit interactivement à travers la console Oil ou soit lors du fonctionnement d'une tâche, l'erreur est simplement affichée, et selon le type d'erreur, l'action en cours peut être avortée.

Vous pouvez activer le dump de backtrace quand une erreur fatale se produit en fixant la clé cli_backtrace dans le fichier config.php à true.

16 - Tests unitaires

FuelPHP a intégré, dans sa conception, la gestion des tests unitaires. Il inclut des tests et des classes de test basées sur le Framework de test PHPUnit.

16-1 - Qu'est-ce qu'un test unitaire ?

Les tests unitaires sont des tests automatiques écrits, pour s'assurer qu'une unité de code (typiquement une fonction ou une méthode) fait ce pour quoi elle a été conçue. Ces tests aident également les développeurs à ne pas casser du code qui fonctionnait jusqu'à présent. Les tests unitaires sont également le cœur de métier de la discipline de « Test Driven Development » (TDD).

16-2 - PHPUnit

Vous aurez besoin d'avoir PHPUnit installé en local si vous voulez exécuter les tests fournis avec FuelPHP, et si vous voulez utiliser Oil pour exécuter vos tests. Si vous n'avez pas déjà installé PHPUnit, merci de vous référer à la documentation d'installation de PHPUnit à :https://phpunit.de/manual/current/en/installation.html.

Si vous n'êtes pas intéressé par l'exécution de tests unitaires avec FuelPHP, alors il n'y a aucune nécessité pour vous d'installer PHPUnit.

16-3 - Lancer des tes unitaires

Dans l'utilitaire de ligne de commande inclus dans FuelPHP, Oil est déjà configuré pour exécuter vos tests unitaires. Vous pouvez exécuter tous les tests dans votre projet FuelPHP à partir de la ligne de commande en utilisant Oil comme suit :

$ php oil test

Tests Running...This may take a few moments.
PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /home/user/sites/example/fuel/core/phpunit.xml

...............................................................  63/251 ( 25%)
............................................................... 126/251 ( 50%)
............................................................... 189/251 ( 75%)
..............................................................

Time: 6 seconds, Memory: 22.25Mb

OK (251 tests, 206 assertions)

16-4 - Créer des tests unitaires

Dans FuelPHP, les scripts d'exécution des tests sont situés dans le dossier Fuel/app/tests et ses sous-répertoires. Si ce répertoire est inexistant, il faudra le créer. Par convention, les fichiers de tests sont placés dans le même sous-chemin de Fuel/app/tests tout comme la classe testée se trouve dans Fuel/app/classes, donc un test pour la classe Fuel/app/cours/modèle/login.php serait dans le fichier Fuel/app/tests/modèle/login.php.

Les tests sont des classes qui étendent la classe de TestCase. TestCase est l'extension FuelPHP de la classe PHPUnit_Framework_TestCase de PHPUnit, vous serez donc en mesure d'utiliser toutes les assertions et les méthodes habituelles de PHPUnit dans votre test. Par convention, les classes de test sont nommées après la classe qu'elles testent, préfixées par test_, donc un test pour la classe Model_Login serait nommé Test_Model_Login.

class Test_Model_Login extends TestCase
{
public function test_foo()
{
}
}

Vous pouvez trouver plus d'informations sur l'écriture des tests dans la documentation de PHPUnit :

http://www.phpunit.de/manual/current/en/writing-tests-for-phpunit.html.

16-5 - Groupes de test

Si vous voulez exécuter uniquement un sous-ensemble de tests pendant la programmation, vous pouvez utiliser des groupes de tests. Pour cela, il faut lancer php oil test avec le switch de commande --group=.

$ php oil test --group=App

Cette commande va exécuter uniquement les tests du groupe 'App'. Vous pouvez attribuer une classe de test à un ou plusieurs groupes de tests avec l'attribut @group de docblock.

/**
* @group App
* @group Login
*/
class Test_Model_Login extends TestCase
{
public function test_foo()
{
}
}

16-6 - Configuration avancée

Si vous avez besoin de personnaliser le contenu du fichier phpunit.xml, copiez Fuel/core/phpunit.xml dans le répertoire Fuel/app. FuelPHP va reconnaître votre nouveau fichier de configuration à la place de l'ancien dans Fuel/core.

16-7 - Tests unitaires pour modules

Si vous développez un grand système dans FuelPHP, la pratique recommandée est de développer des modules. Mais comme les chemins de module sont configurables, ceux-ci doivent être configurés dans phpunit.xml pour que les tests soient reconnus et exécutés. Par exemple, si vous développez des modules dans Fuel/app/modules, vous voudrez ajouter cette suite de tests dans votre configuration phpunit :

16-8 - Tests dans un dossier Fuel/Directoy renommé

Si vous avez renommé votre répertoire FuelPHP, les variables système (document root, core path, etc.) définies dans le fichier phpunit.xml deviennent de mauvaises références. Bien que les modifications apportées aux chemins dans le script Oil de votre racine aideront les autres commandes de Oil, PHPUnit charge son propre environnement, donc un répertoire de Fuel renommé brisera les tests. Pour corriger cela, vous éditez la copie de phpunit.xml dans votre app/Directory, puis mettre à jour les chemins des variables du serveur pour tenir compte de votre nouvelle structure de fichier.

17 - Profilage

Le profileur d'application livré avec FuelPHP est basé sur PHP Quick Profiler.

17-1 - Qu'est-ce que le profilage ?

Le profileur fournit des informations relatives de profilage et de débogage sans ajouter beaucoup de lignes à votre code. Vous avez seulement besoin de basculer un paramètre de configuration sur true, qui vous donne accès à un outil automatisé pour aider à créer une expérience d'examen rapide et plus cohérente. Pour simplifier son utilisation, le profileur fournit l'emplacement du code avant l'examen.

Le profileur vous fournit une interface à onglets, dans laquelle vous pouvez trouver les informations suivantes :

- Console : c'est l'onglet par défaut qui donne des informations sur les erreurs, les entrées de log, l'utilisation de la mémoire et les temps d'exécution ;

- Load time : il s'agit du temps de charge. Il permet d'afficher les détails d'exécution dans le corps de l'onglet ;

- Database : cet onglet porte sur le nombre de requêtes exécutées, le temps d'exécution, et si pris en charge, une analyse de la requête ;

- Memory : c'est la crête de mémoire totale utilisée par la requête ;

- Files : il s'agit des noms complets (« full qualified ») des fichiers PHP inclus, et leur taille ;

- Config: c'est le contenu de la configuration stockée, à la fin de la requête ;

- Session : cet onglet indique le contenu de la session stockée, à la fin de la requête ;

- GET : il y est indiqué le contenu du tableau $_GET ;

- POST : il y est indiqué le contenu du tableau $_POST.

Un écran typique de profil ressemble à ceci :

Au bas de l'écran de profileur, vous trouverez trois options :

- Bottom : option, par défaut, dans laquelle le profileur est une surcouche. En cliquant sur cette option, le profileur se positionnera à la fin des sorties. Ce qui vous permet de visualiser toutes les sorties, le profileur va aller après la fin de votre sortie. Cliquez à nouveau et elle se déplacera en arrière ;

- Height : cette option permet de basculer entre un grand panneau (comme dans la capture d'écran) ou un petit panneau de profileur ;

- Details : change les détails de profileur. Si éteint, seule la barre d'onglet sera visible.

17-2 - Profilage d'application

Le profilage de votre application est désactivé par défaut. Vous pouvez configurer FuelPHP pour activer le profileur via le fichier config/config.php de votre application :

'profiling'  => true,

Après l'activation du profileur, vous le verrez apparaître en bas de la fenêtre de votre navigateur.

17-3 - Profilage de base de données

Le profilage de base de données est désactivé par défaut également. Celui-ci est activé par base de données définie, et est activée en réglant l'option «profilage» à true au niveau de la configuration de base de données que vous souhaitez profiler dans votre config /<environnement>/db.php.

'profiling'  => true,

Si vous utilisez plusieurs environnements, veillez à sélectionner le bon fichier de configuration de db.php.

17-4 - Ajout d'information au profileur

Consultez la documentation de la classe Profiler pour voir comment vous pouvez interagir avec le profileur.

18 - Remerciements

Tous nos remerciements à Christophe LOUVET pour cette traduction, à Guillaume SIGUI pour sa relecture technique et à Claude Leloup pour sa relecture orthographique.