Table des matières
- 1. Introduction
- 2. Installation de Catalyst
- 3. Création d'une application
- 4. Ajout d'une vue
- 5. Exemples d'utilisation des TT
- 6. Création d'un controleur
- 7. Création d'un Model
- 8. Catalyst::Enzyme pour plus de simplicité
- 9. Authentification
- 10. Intégration d'une barre de navigation
- 11. Authentification (Suite)
- 12. V0.0X
- 13. Model et Mysql
- 14. Mise en place d'un cache
- 15. Des modules Catalyst
- 16. Divers
Perl est un language de programmation avec lequel je me débrouille tout juste alors pardonnez les erreurs qui apparaitront certainement au cours de l'écriture de ce document. N'hésitez pas à m'informer de toute remarque qui vous semblerai judicieuse.
Catalyst est un nouveau framework MVC en Perl destiné à faciliter considérablement la construction d'application Web. Il est aujourdhui en constante évolution.
Il utilise de nombreux modules Perl issu du CPAN ( search.cpan.org) et est au fait des dernières technos.
MVC signifie Model View Controler.
Les Models sont les définitions des espaces de stockages et elurs méthodes d'accès.
Les Views serviront dans la représentation des données.
Le rôle des controleurs est de gérer le flux de l'application.
Controller -> Prend les données dans Model
Controller -> Fourni les données à la View ou passe a un autre controleur, ...
Par exemple http://localhost:3000/Users/list est une action permettant de lister les utilisateurs de l'application. Dans le Controler 'Users' serai défini une méthode 'list' qui pourrai accéder aux données du Model 'Utilisateurs'. Les données retournées par les methodes du Model seraient stockées par le Controller qui les fournirai ensuite à la View.
Nous débuterons notre exploration à partir d'une installation vierge indépendante du système installé.
Prérequis:
Une Debian installée.
Accès au Net
Pour permettre l'utilisation de la dernière version de Catalyst nous allons créer une mini Debian qui contiendra tous les packages necessaires. Ainsi le système de base se sera pas affecté.
# 1 - Création du système Debian minimum # Retrieve minimum packages for Debian Sid debootstrap sid chroot_catalyst # 2 - On prend pour racine ce nouveau système chroot chroot_catalyst # 3 - Montage du FS /proc mount -t proc proc /proc # 4 - Lecture des derniers packages apt-get update # 5 - Install minimum packages for catalyst apt-get install locales gcc libc6-dev libperl-dev perl-modules dh-make-perl libdbi-perl libclass-dbi-perl libdbd-mysql-perl libclass-dbi-sqlite-perl libsql-abstract-limit-perl libclass-trigger-perl libdbix-contextualfetch-perl libhttp-server-simple-perl libwww-mechanize-perl libhttp-server-simple-perl libsqlite3-dev sqlite3 libtest-pod-perl libtest-pod-coverage-perl libclass-inspector-perl libperl6-slurp-perl subversion-tools libnet-ldap-perl shared-mime-info dnsutils libimage-imlib2-perl libgraphviz-perl librpc-xml-perl libtemplate-perl libgd-perl libclass-dbi-fromform-perl ftp mysql-client-4.1 dpkg-reconfigure locales apt-get clean (=~ 300 Mo) # 6 - Init .cpan perl -MCPAN -e shell # 7 - Install lasted packages for Catalyst perl -MCPAN -e shell << __EOF__ force install Test::WWW::Mechanize::Catalyst install Task::Catalyst install Catalyst::Enzyme install Catalyst::View::GraphViz install Catalyst::View::TT::ControllerLocal install Catalyst::Plugin::Authorization::Roles install Catalyst::Plugin::Authentication::Store::DBIC install Catalyst::Helper::Controller::Scaffold install Catalyst::Plugin::Authentication::CDBI install DBI::Shell __EOF__
Vous avez pu constater que Catalyst est dépendant d'un très grand nombre de modules perl.
Notre espace de travail étant à jour (=~ 330Mo), nous y resterons le reste du document.
Nous crééons tout dabord le répertoire d'acceuil de notre application et nous nous y rendons.
mkdir -p /var/www/catalyst && cd /var/www/catalystEnsuite création de l'application
catalyst.pl MonAppli created "MonAppli" created "MonAppli/script" created "MonAppli/lib" ...
Et enfin exécution de l'application.
localhost:/var/www/catalyst/MonAppli/# cd MonAppli localhost:/var/www/catalyst/MonAppli/# perl script/monappli_server.pl [] [catalyst] [debug] Debug messages enabled [] [catalyst] [debug] Loaded plugins: .------------------------------------------------------------------------------. | Catalyst::Plugin::Static::Simple | '------------------------------------------------------------------------------' [] [catalyst] [debug] Loaded dispatcher "Catalyst::Dispatcher" [] [catalyst] [debug] Loaded engine "Catalyst::Engine::HTTP" [] [catalyst] [debug] Found home "/var/www/catalyst/MonAppli" [] [catalyst] [debug] Loaded Private actions: .----------------------+----------------------------------------+--------------. | Private | Class | Method | +----------------------+----------------------------------------+--------------+ | /default | MonAppli | default | '----------------------+----------------------------------------+--------------' [] [catalyst] [info] MonAppli powered by Catalyst 5.61 You can connect to your server at http://localhost:3000
Et voilà notre première application est maintenant créée, elle est en écoute du port 3000. Pour le vérifier il suffit de se connecter à http://localhost:3000/
Le fonctionnement de l'application MonAppli est définie dans
./lib/MonAppli.pm. On constate que celle-ci hérite de
'-Debug' 'Static::Simple'
use Catalyst qw/-Debug Static::Simple/;
-Debug nous permet d'accéder au mode Débug de Catalyst et Static::Simple gérera pour nous les pages statiques.
On y remarque le code suivant:
sub default : Private {
my ( $self, $c ) = @_;
# Hello World
$c->response->body( $c->welcome_message );
}Il s'agit du code qui sera utilisé si aucune autre action n'est exécutée. Pour plus de détails sur les actions prédéfinies (default, begin, end, auto, index) voir Wiki FlowChart
Au début on s'y pert un peu... Pour débugger on peut ajouter une ligne de code comme ceci:
$c->log->debug("[>> MonAppDeTest.pm sub default: bla bla bla ]") if $c->req->params->{debug};Nous allons modifier l'application de manière a ce qu'elle utilise une vue héritant des templates toolkit. Voir Catalyst::View::TT et www.template-toolkit.org
Pour créer notre vue :
localhost:/var/www/catalyst/MonAppli/# perl script/monappli_create.pl view TT TT exists "/var/www/catalyst/MonAppli/script/../lib/MonAppli/View" exists "/var/www/catalyst/MonAppli/script/../t/View" created "/var/www/catalyst/MonAppli/script/../lib/MonAppli/View/TT.pm" created "/var/www/catalyst/MonAppli/script/../t/View/TT.t"
Nous pouvons maintenant utiliser cette vue.
Dans lib/MonAppli.pm nous modifions :
sub default : Private {
my ( $self, $c ) = @_;
# Hello World
#$c->response->body( $c->welcome_message );
$c->stash->{template}="mavue.tt";
$c->stash->{mavariable}="MAVARIABLE";
}
sub end : Private {
my ( $self, $c ) = @_;
# Forward to View unless response body is already defined
$c->forward('View::TT') unless $c->response->body;
}Et nous créons le fichier root/mavue.tt
Ceci est le fichier mavue.tt mavariable=[% mavariable %]
Nous redémarrons le serveur pour la prise en compte des modifications. Cette fois pour le redémmarrer nous utilsons l'option -r qui permet au serveur de redémarrer automatiquement si un fichier est modifié. Très utile lors du développement de l'application.
On indique à View::TT quel template utiliser en fournissant son nom a travers le stash. Pour plus d'infos sur le stash voir Manual Intro
Ensuite on transfert vers MonAppli::View::TT ($c->forward('MonAppli::View::TT');)
Et voilà on voit apparaitre "Ceci est le fichier mavue.tt" ainsi que [% mavariable %] subsititué.
Comme pour le template les variables seroint fournies a notre vue a travers le hachage $c->stash. Nous allons utiliser concretement les templates toolkit en leurs fournissants des donnes.
Dans 'defaut' de lib/MonAppli.pm ajoutons:
$c->stash->{montableau} = [ 1, 3, 5, 7, 9 ]; # reference a un tableau
Et dans le template root/mavue.tt:
<br><b>Reference a un tableau</b><br>
montableau=[% montableau %]<br>
montableau[1]=[% montableau.1 %]<br>
montableau.first = [% montableau.first %]<br>
montableau.last = [% montableau.last %]<br>
montableau.size = [% montableau.size %]<br>
join(',',montableau) = [% montableau.join(', ') %]<br>
[% FOREACH donnee = montableau %]
[% "Premier tour <br>" IF loop.first -%]
donnee=[% donnee %] loop.count=[% loop.count %]<br>
[% END %]
Dans 'defaut' de lib/MonAppli.pm ajoutons:
$c->stash->{monhach} = {
couleur => 'rouge',
taille => 'petit',
forme => 'rond',
};Et dans le template root/mavue.tt:
<br><b>Reference a un hachage</b><br> monhach=[% monhach %]<br> monhach.couleur = [% monhach.couleur %]<br>
Infos sur les variables TT => Variables TT
Nous souhaitons accéder a notre vue avec une URL spécifique par exemple '/mavue'. Encore une fois (comme pour le vue TT) nous allons utiliser le 'Helper' de Catalyst pour créer le squelette de notre controleur.
perl script/monappli_create.pl controller mavue
Ouvrons le fichier
lib/MonAppli/Controller/mavue.pm. Comme pour
l'application il y a encore une action 'default' commente cette fois ci.
On la dcommente pour quelle devienne:
sub default : Private {
my ( $self, $c ) = @_;
$c->log->debug("[>> MonAppli/Controller/mavue.pm sub defaut ]") if $c->req->params->{debug};
$c->stash->{mavariable}="MAVARIABLE";
$c->stash->{montableau} = [ 1, 3, 5, 7, 9 ]; # reference a un tableau
$c->stash->{monhach} = {
couleur => 'rouge',
taille => 'petit',
forme => 'rond',
};
$c->stash->{template}="mavue.tt";
$c->forward('MonAppli::View::TT');
}Modifions a nouveau 'default' de
lib/MonAppli.pm pour qu'il redevienne:
sub default : Private {
my ( $self, $c ) = @_;
# Hello World
$c->response->body( $c->welcome_message );
}Et voilà notre controler est prêt. http://localhost:3000/mavue
Donc jusqu'a maintenant nous avons:
Conserver la page par defaut (lib/MonAppli.pm sub default)
Ajouter le controleur 'mavue' qui 'forward' vers mavue.tt avec View::TT
Ces deux actions sont indiqués dans le log sous cette forme:
.----------------------+----------------------------------------+--------------. | Private | Class | Method | +----------------------+----------------------------------------+--------------+ | /default | MonAppli | default | | /mavue/default | MonAppli::Controller::mavue | default | '----------------------+----------------------------------------+--------------'
Nous pouvons ajouter des actions a notre controller.Dans notre exemple notre application devra retourne la date lorsque l'on accdera a /mavue/date.
Ajout a lib/MonAppli/Controller/mavue.pm de:
...
use Date::Calc qw(Localtime);
...
sub date : Global{
my ( $self, $c ) = @_;
my ($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = Localtime();
my $date="Nous somme le $day/$month/$year il est $hour:$min:$sec";
$c->stash->{date}=$date;
$c->stash->{template}="date.tt";
$c->forward('MonAppli::View::TT');
}Et creation du template correspondant
root/date.tt
Fichier date.tt<br> [% date %]
Et voila on peut y accéder http://localhost:3000/date nous fourni la date. D'ailleurs on le vérifie dans le log:
.----------------------+----------------------------------------+--------------. | Private | Class | Method | +----------------------+----------------------------------------+--------------+ | /default | MonAppli | default | | /mavue/date | MonAppli::Controller::mavue | date | | /mavue/default | MonAppli::Controller::mavue | default | '----------------------+----------------------------------------+--------------' [Mon Nov 21 13:47:15 2005] [catalyst] [debug] Loaded Path actions: .--------------------------------------+---------------------------------------. | Path | Private | +--------------------------------------+---------------------------------------+ | /date | /mavue/date | '--------------------------------------+---------------------------------------
Pour rendre cette action accessible a partir de /mavue/date l'action ne doit plus etre Global mais Local. Pour les type d'actions possibles voir Manuel::Intro#Actions
[Mon Nov 21 14:34:51 2005] [catalyst] [debug] Loaded Path actions: .--------------------------------------+---------------------------------------. | Path | Private | +--------------------------------------+---------------------------------------+ | /mavue/date | /mavue/date | '--------------------------------------+---------------------------------------'
Le Model défini les moyens d'accéder à une base de donnée. Dans cet exemple nous utiliserons une base sqlite.
Le schéma de notre base étant le suivant:
../exemple.sql
-- exempledb.sql
CREATE TABLE page (
id_page INTEGER PRIMARY KEY,
titre VARCHAR(40)
);
CREATE TABLE article(
id_article INTEGER PRIMARY KEY,
titre VARCHAR(40),
contenu VARCHAR(2000)
);
CREATE TABLE page_article(
id INTEGER PRIMARY KEY,
page INTEGER REFERENCES page,
article INTEGER REFERENCES article
);
INSERT INTO page VALUES(1, 'Titre de la premiere page');
INSERT INTO page values(2, 'Titre de la seconde page');
INSERT INTO article values(1, 'Titre Article 1', 'contenu article 1');
INSERT INTO article values(2, 'Titre Article 2', 'contenu article 2');
INSERT INTO article values(3, 'Titre Article 3', 'contenu article 3');
INSERT INTO article values(4, 'Titre Article 4', 'contenu article 4');
INSERT INTO page_article values(1,'1','1');
INSERT INTO page_article values(2,'1','2');
INSERT INTO page_article values(3,'2','3');
INSERT INTO page_article values(4,'2','4');
Pour créer la base sqlite, on utilise la commande suivante:
localhost:/var/www/catalyst/MonAppli/$ sqlite3 exemple.db < ../exemple.sql
Crééons le Model qui utilisera cette base:
localhost:/var/www/catalyst/MonAppli/$ perl script/monappli_create.pl model MonCDBI CDBI dbi:SQLite:/var/www/catalyst/MonAppli/exemple.db exists "/var/www/catalyst/MonAppli/script/../lib/MonAppli/Model" exists "/var/www/catalyst/MonAppli/script/../t" created "/var/www/catalyst/MonAppli/script/../lib/MonAppli/Model/MonCDBI.pm" created "/var/www/catalyst/MonAppli/script/../lib/MonAppli/Model/MonCDBI" created "/var/www/catalyst/MonAppli/script/../lib/MonAppli/Model/MonCDBI/Article.pm" created "/var/www/catalyst/MonAppli/script/../lib/MonAppli/Model/MonCDBI/Page.pm" created "/var/www/catalyst/MonAppli/script/../lib/MonAppli/Model/MonCDBI/PageArticle.pm" exists "/var/www/catalyst/MonAppli/script/../t" created "/var/www/catalyst/MonAppli/script/../t/model_MonCDBI-Article.t" exists "/var/www/catalyst/MonAppli/script/../t" created "/var/www/catalyst/MonAppli/script/../t/model_MonCDBI-Page.t" exists "/var/www/catalyst/MonAppli/script/../t" created "/var/www/catalyst/MonAppli/script/../t/model_MonCDBI-PageArticle.t"
Cool :) Notre Model 'MonCDBI' à découvert les tables de notre base. Mouai mais encore ...
Nous allons ensuite voir comment accéder aux données de nos tables.
Pour cela nous pouvons utiliser le controleur Scaffold de cette manière:
localhost:/var/www/catalyst/MonAppli/$ perl script/monappli_create.pl controller Page Scaffold MonCDBI::Page
exists "/var/www/catalyst/MonAppli/script/../lib/MonAppli/Model"
created "/var/www/catalyst/MonAppli/script/../lib/MonAppli/Model/MonCDBI.pm"
created "/var/www/catalyst/MonAppli/script/../lib/MonAppli/Model/MonCDBI"
created "/var/www/catalyst/MonAppli/script/../lib/MonAppli/Model/MonCDBI/Article.pm"
created "/var/www/catalyst/MonAppli/script/../lib/MonAppli/Model/MonCDBI/Page.pm"
created "/var/www/catalyst/MonAppli/script/../lib/MonAppli/Model/MonCDBI/PageArticle.pm"
exists "/var/www/catalyst/MonAppli/script/../t/Model"
created "/var/www/catalyst/MonAppli/script/../t/Model/MonCDBI-Article.t"
exists "/var/www/catalyst/MonAppli/script/../t/Model"
created "/var/www/catalyst/MonAppli/script/../t/Model/MonCDBI-Page.t"
exists "/var/www/catalyst/MonAppli/script/../t/Model"
created "/var/www/catalyst/MonAppli/script/../t/Model/MonCDBI-PageArticle.t"Mais il existe depuis peu un module beaucoup plus simple d'utilisation et qui va nous faciliter grandement la tâche :)
Catalyst::Enzyme nous facilite encore plus la tâche :)
Testons le immédiatement. Pour cela nous réutiliserons le schema de
la base SQLite exemple.sql
Lors de la création automatique de vue,controleur ou model nous avons utilisé des 'Helpers'. Ils sont fournis pour nous aider à construire le squelette de scripts. Catalyst::Enzyme fourni aussi ses propres Helpers
Il va nous aider dans la création des scripts d'accès aux données d'une table.
localhost:/var/www/catalyst/$ catalyst.pl TestEnzyme && cd TestEnzyme localhost:/var/www/catalyst/TestEnzyme/$ vi lib/TestEnzyme.pm
On remplace
use Catalyst qw/-Debug Static::Simple/;
par
use Catalyst qw/-Debug Static::Simple DefaultEnd FormValidator/;
et
$c->response->body( $c->welcome_message );
par
$c->res->redirect("/page");
localhost:/var/www/catalyst/TestEnzyme/$ perl script/testenzyme_create.pl view TT Enzyme::TT exists "/var/www/catalyst/TestEnzyme/script/../lib/TestEnzyme/View" exists "/var/www/catalyst/TestEnzyme/script/../t" created "/var/www/catalyst/TestEnzyme/script/../lib/TestEnzyme/View/TT.pm" created "/var/www/catalyst/TestEnzyme/script/../root/base/add.tt" created "/var/www/catalyst/TestEnzyme/script/../root/base/edit.tt" created "/var/www/catalyst/TestEnzyme/script/../root/base/footer.tt" created "/var/www/catalyst/TestEnzyme/script/../root/base/form_macros.tt" created "/var/www/catalyst/TestEnzyme/script/../root/base/header.tt" created "/var/www/catalyst/TestEnzyme/script/../root/base/list.tt" created "/var/www/catalyst/TestEnzyme/script/../root/base/list_macros.tt" created "/var/www/catalyst/TestEnzyme/script/../root/base/pager.tt" created "/var/www/catalyst/TestEnzyme/script/../root/base/pager_macros.tt" created "/var/www/catalyst/TestEnzyme/script/../root/base/view.tt" created "/var/www/catalyst/TestEnzyme/script/../root/static/css/testenzyme.css" created "/var/www/catalyst/TestEnzyme/script/../t/view_TT.t" localhost:/var/www/catalyst/TestEnzyme/$ mkdir db && dbish dbi:SQLite:dbname=db/exemple.db < ../exemple.sql localhost:/var/www/catalyst/TestEnzyme/$ perl script/testenzyme_create.pl model ExempleDB Enzyme::CDBI dbi:SQLite:dbname=db/exemple.db localhost:/var/www/catalyst/TestEnzyme/$ perl script/testenzyme_create.pl controller Page Enzyme::CRUD ExempleDB::Page localhost:/var/www/catalyst/TestEnzyme/$ perl script/testenzyme_create.pl controller Article Enzyme::CRUD ExempleDB::Article

Cool :)
Avec une page de style, un pager ... ça a une autre gueule non ?
En fait pour profiter du 'pager' (permet d'afficher qu'un nombre
limité de données ) il nous faut tout dabord modifier notre Modele Page
lib/TestEnzyme/Model/ExempleDB/Page.pm.
# Remplacer
__PACKAGE__->config(
crud => {
}
);
# par
__PACKAGE__->config(
crud => {
moniker => "Page",
column_monikers => { __PACKAGE__->default_column_monikers, titre => "Le titre" },
rows_per_page => 5,
data_form_validator => {
optional => [ __PACKAGE__->columns ],
required => [ qw/ titre /],
constraint_methods => {
titre => { name => 'contraintetitre', constraint => qr/^[A-Z]/ },
},
missing_optional_valid => 0,
msgs => {
format => '%s',
constraints => {
contraintetitre => "Le titre doit d~buter par une majuscule !",
},
},
},
},
);
column_monikers : permet de renommer une colonne a l'affichage
rows_per_page: comme son nom l'indique, nombre de rangée de données par page (utilisé par le 'pager')
data_form_validator: Nous permet de valider les donnée fourni par l'utilisateur. Dans notre exemple si aucune donnée n'est fournie au champ 'titre' (required) alors les données ne sont pas validées et donc non enregistrées dans par l'action 'do_add'.
constraint_methods: Contrainte sur les données. Notre titre doit commencer par une majuscule

Il nous est aussi possible de modifier les champs/colonnes à
afficher. Pour notre Model 'Article' remarquez que seul les champs
'contenu' et 'titre' sont affichés, 'id_article' ne l'est pas. Pour forcer
son affichage lors du listing ' /list' nous modifions la
ligne suivante du Model 'Article'
( lib/TestEnzyme/Model/ExempleDB/Article.pm):
__PACKAGE__->columns(list_columns => qw/ contenu titre /); par __PACKAGE__->columns(list_columns => qw/ id_article contenu titre /);
Il est aussi possible de modifier les champs à afficher lors de l'ajout et de la vue d'article.
__PACKAGE__->columns(view_columns => qw/ contenu titre /);
Nous n'allons pas laisser n'importe qui accéder en écriture à notre base de données, il nous faut donc un mécanisme d'authentification. Encore une fois Catalyst est là pour nous aider :)
Pour assurer l'authentication des utilisateurs nous utiliserons le module Catalyst::Plugin::Authentication::CDBI. Celui-ci ne se contente pas seulement de gérer les utilisateurs mais aussi le 'role' des utilisateurs. Nous déciderons par exemple que l'utilisateur 'toto' a le 'role' admin.
Les utilisateurs ainsi que les roles seront stockés en base. Une
fois encore nous utiliserons SQLite. ( ../auth.sql
)
-- Users
CREATE TABLE user (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(30) NOT NULL,
password VARCHAR(40) NOT NULL,
firstname VARCHAR(40),
lastname VARCHAR(40)
);
-- Roles
CREATE TABLE role (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(30)
);
-- Mapping
CREATE TABLE user_role (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
user INTEGER REFERENCES user,
role INTEGER REFERENCES role
);
-- Users (pass: 12345)
REPLACE INTO user VALUES (1, 'admin', '12345','Robert','Dupont');
REPLACE INTO user VALUES (2, 'user', '12345','gaston','lagaffe');
REPLACE INTO user VALUES (3, 'toto', '12345','gaston','lagaffe');
-- Roles
REPLACE INTO role VALUES (1, 'admin');
REPLACE INTO role VALUES (2, 'writer');
REPLACE INTO role VALUES (3, 'reader');
-- User Roles
REPLACE INTO user_role VALUES (1, 1, 1);
REPLACE INTO user_role VALUES (2, 1, 2);
REPLACE INTO user_role VALUES (3, 1, 3);
REPLACE INTO user_role VALUES (4, 2, 2);
REPLACE INTO user_role VALUES (5, 2, 3);
REPLACE INTO user_role VALUES (6, 3, 3);
localhost:/var/www/catalyst/TestEnzyme/# dbish dbi:SQLite:dbname=db/auth.db < ../auth.sqlNotre application doit tout dabord hériter du module
'Catalyst::Plugin::Authentication::CDBI' et de 'Session::FastMmap'.
Ajoutons les simplement dans le fichier
lib/TestEnzyme.pm.
use Catalyst qw/-Debug Static::Simple DefaultEnd FormValidator Session::FastMmap Authentication::CDBI/;
...
# Authentication
__PACKAGE__->config->{authentication} = {
user_class => 'TestEnzyme::Model::Auth::User',
user_field => 'username',
role_class => 'TestEnzyme::Model::Auth::Role',
role_field => 'role',
user_role_class => 'TestEnzyme::Model::Auth::UserRole',
user_role_user_field => 'user',
user_role_role_field => 'role'
};
...
sub begin : Private {
my ( $self, $c ) = @_;
$c->res->headers->content_type( 'text/html; charset=iso-8859-1' );
my $result=$c->session_login('admin', '8cb2237d0679ca88db6464eac60da96345513964');
$c->log->debug("result=$result");
}
...
sub end : Private {
my ( $self, $c ) = @_;
die "Debug forc~" if $c->req->params->{die};
}'begin' est la première action exécutée, nous vérifions simplement que le login fonctionne. Dans le log du serveur devrait apparaitre '[catalyst] [debug] result=1'. ( Créer tout dabord le Model 'Auth' ci-dessous). $c->res->headers->content_type nous permet la prise en compte des accents en français.
'end' est la dernière 'action' exécutée. Elle nous permettra le debuguage des scripts, il suffira alors ajouter '?die=1' à l'url pour accéder à la page de debug.
Notre module d'authentification fait appel au Model 'Auth' qui n'a pas encore été créé. Ce que nous faisons tout de suite.
localhost:/var/www/catalyst/TestEnzyme/$ perl script/testenzyme_create.pl model Auth CDBI dbi:SQLite:dbname=db/auth.db
exists "/var/www/catalyst/TestEnzyme/script/../lib/TestEnzyme/Model"
exists "/var/www/catalyst/TestEnzyme/script/../t"
created "/var/www/catalyst/TestEnzyme/script/../lib/TestEnzyme/Model/Auth.pm"
created "/var/www/catalyst/TestEnzyme/script/../lib/TestEnzyme/Model/Auth"
created "/var/www/catalyst/TestEnzyme/script/../lib/TestEnzyme/Model/Auth/Role.pm"
created "/var/www/catalyst/TestEnzyme/script/../lib/TestEnzyme/Model/Auth/User.pm"
created "/var/www/catalyst/TestEnzyme/script/../lib/TestEnzyme/Model/Auth/UserRole.pm"
exists "/var/www/catalyst/TestEnzyme/script/../t"
created "/var/www/catalyst/TestEnzyme/script/../t/model_Auth-Role.t"
exists "/var/www/catalyst/TestEnzyme/script/../t"
created "/var/www/catalyst/TestEnzyme/script/../t/model_Auth-User.t"
exists "/var/www/catalyst/TestEnzyme/script/../t"
created "/var/www/catalyst/TestEnzyme/script/../t/model_Auth-UserRole.t"En redémarrant le serveur nous pouvons vérifier que les tables sont correctement chargées et que result est bien égal à '1' ce qui nous confirmera qur l'authentification s'est correctement déroulée. Un cookie à aussi été créé contenant le numéro de session.
[] [catalyst] [debug] Loaded tables "article page page_article" [] [catalyst] [debug] Loaded tables "role user user_role" ... [] [catalyst] [debug] result=1
Nous allons dans un premier temps imposer une authentification des
utilisateurs quelle que soit la page accédée. Pour celà nous modifions
l'action 'begin' du fichier principal de notre application
lib/TestEnzyme.pm
sub begin : Private {
my ( $self, $c ) = @_;
# Pour les accents
$c->res->headers->content_type( 'text/html; charset=iso-8859-1' );
# force login for all pages
unless ($c->req->{user}) {
$c->req->action(undef);
$c->forward('/login/login');
}
}
'begin' étant éxécuté avant tout autre action, cela oblige les utilisateurs à se loguer.
Nous constatons que l'action 'begin' n'est pas exécutée. Hmmm ... Pourquoi ???. Rappelons nous que nous venons de tester le fonctionnement du 'login' et qu'un cookie a été créé. Supprimons le et là et bien ...
Il nous faut donc créer le controleur 'Login'.
localhost:/var/www/catalyst/TestEnzyme/$ perl script/testenzyme_create.pl controller Login
Et l'action login du controleur 'Login'
( lib/TestEnzyme/Controller/Login.pm
sub default : Private {
my ($self, $c) = @_;
$c->forward('login');
}
sub login : Path('/login') {
my ( $self, $c ) = @_;
if ($c->req->params->{username}) {
my $login=$c->session_login(
$c->req->params->{username},
$c->req->params->{password}
);
if ( $login ){
$c->res->redirect( $c->session->{referer} || '/' );
}
else{
$c->stash->{template} = "login.tt"
}
}
else {
# save the referring page so we can redirect back
$c->session->{referer} = $c->req->path;
$c->stash->{template} = "login.tt"
}
}Si nous ne sommes pas authentifié alors nous sommes redirigé vers la page de login. Le reste se passe de commentaire :)
Il nous faut encore créer le template 'login.tt'
localhost:/var/www/catalyst/TestEnzyme/$ cat root/login.tt
[% INCLUDE base/header.tt %]
<form action="/login" method="post">
<fieldset>
<legend>Connexion.</legend>
<label for="username"><span class="field">Login:</span></label>
<input type="text" name="username" /><br />
<label for="password"><span class="field">Password:</span></label>
<input type="password" name="password" /><br />
<label for="submit"><span class="field"></span></label>
<input type="submit" value="Se connecter" /><br />
</fieldset>
</form>
[% IF ! c.req.user %]
<script language="javascript">
document.forms[0].username.focus();
</script>
[% END %]
<fieldset>
Se connecter en admin password=12345 ou user/12345 ou toto/12345
</fieldset>
Terminé. Notre système d'authentification est en place :)
Nous allons modifier maintenant modifier un peu l'authentification. L'utilisateur pourra voir divers éléments selon son 'role'. S'il n'est pas logué alors il ne dispose d'aucun 'role' et un onglet 'login' apparait en haut de page. S'il est logué un onglet 'logout' apparait en haut de page. Pour y parvenir nous devrons:
Créer une action 'Logout'.
Supprimer l'action 'begin' de l'application qui redirige s'il l'utilisateur n'est pas logué
Modifier nos templates pour qu'ils fasse nt apparaitre une barre de navigation (Login/Logout)
L'ajout de l'action 'Logout' se fait simplement en
modifiant/ajoutant comme suit le code de
lib/TestEnzyme/Controller/Login.pm
sub login : Path('/login') {
my ( $self, $c ) = @_;
if ($c->req->params->{username}) {
my $login=$c->session_login(
$c->req->params->{username},
$c->req->params->{password}
);
if ( $login ){
$c->res->redirect( '/' );
}
else{
$c->stash->{template} = "login.tt"
}
}
else {
# save the referring page so we can redirect back
$c->session->{referer} = $c->req->path;
$c->stash->{template} = "login.tt"
}
}
sub logout : Path('/logout') {
my ($self, $c) = @_;
$c->session_logout if ($c->req->{user});
$c->res->redirect('/login/login');
}On peut dès à présent utiliser l'url 'login/logout' qui après avoir supprimer la session nous redirige vers 'login/login'.

TODO: Crypter les mots de passe dans db/auth.db
Pour intégrer notre 'barre de navigation' à nos page nous allons l'ajouter à la manière de ce qui est fait dans les templates qui ont été créés automatiquement (root/base/[add,list,edit,view].tt). Ont peut constater qu'il y a un '[% INCLUDE 'header.tt' %]' dans chacun de ceux-ci. C'est donc dans ce template que nous ferons notre modification.
localhost:/var/www/catalyst/TestEnzyme/$ cat root/base/header.tt ... [% INCLUDE "navbar.tt" %]
Le barre de navigation root/base/navbar.tt se
présente sous cette forme
localhost:/var/www/catalyst/TestEnzyme/$ cat root/base/navbar.tt
<div id="navcontainer">
<ul class="navlist">
<li [% IF nav == 'acceuil' %]id="active"[% END %]><a href="/">Acceuil</a></li>
<li [% IF nav == 'search' %]id="active"[% END %]><a href="/page">Page</a></li>
<li [% IF nav == 'report' %]id="active"[% END %]><a href="/article">Article</a></li>
[% IF ! c.req.user %]<li><a href="/login/login">Login</a></li>[% END %]
[% IF c.req.user %]<li><a href="/login/logout">Logout</a></li>[% END %]
</ul>
</div>
On remarque que le paramètre 'nav' permet d'utiliser un 'id active' qui pourra être utilisée par la feuille de style CSS. Nous y reviendrons plus tard. Voyons ce que ça donne ...

Oui il fallait s'y attendre, notre barre de navigation va devoir
être 'habillée' par la page CSS
root/static/css/testenzyme.css. On y ajoute ce qui
suit
.navlist {
padding: 3px 0;
margin-left: 0;
margin-top: 1em;
border-bottom: 1px solid #778;
# font: bold 12px Verdana, sans-serif;
}
.navlist li {
list-style: none;
margin: 0;
display: inline;
}
.navlist li a {
padding: 3px 0.5em;
margin-left: 3px;
border: 1px solid #778;
border-bottom: none;
background: #b5cadc;
text-decoration: none;
}
.navlist li a:link { color: #448; }
.navlist li a:visited { color: #667; }
.navlist li a:hover {
color: #000;
background: #eef;
border-top: 4px solid #7d95b5;
border-color: #227;
}
.navlist #active a {
background: white;
border-bottom: 1px solid white;
border-top: 4px solid;
}
.loginas{
background-color:#FF0000;
}
Ah oui là c'est mieux :)

Le paramètre 'nav' va permettre le colorier l'onglet relatif à la
page à laquelle on accède. Pour cela modifons l'action 'default' de
lib/TestEnzyme.pm pour qu'il nous transfert vers un
template 'index.tt' et l'action 'end' qui enregistre dans le stash
nav='acceuil'.
sub default : Private {
my ( $self, $c ) = @_;
# Hello World
$c->stash->{template} ||= "index.tt";
}
sub end : Private {
my ( $self, $c ) = @_;
$c->stash->{nav} = "acceuil" unless $c->stash->{nav};
# Forward to View unless response body is already defined
$c->forward('View::TT') unless $c->response->body;
die "Debug forc~" if $c->req->params->{die};
}Au tours du template root/base/index.tt
[% INCLUDE "header.tt" %] [% INCLUDE "navbar.tt" %] Page d'acceuil. ( ~ ~ ~ ~ ~ ) [% INCLUDE "footer.tt" %]

L'onglet de la page par defaut 'acceuil' est maintenant mise en évidence.
Nous allons procéder de manière identique pour les autres onglets.
Les onglets nous transfert vers les controleurs 'Page' et 'Article', c'est
donc dans ces controleurs que nous fixerons le paramètre 'nav' spécifique
et plus extactement dans l'action 'begin' du controleur. Pour le
controleur 'Page' ( ) nous aurons donc
sub begin : Private {
my ( $self, $c ) = @_;
$c->stash->{nav} = "page";
}
Et nous ferons de même pour le controleur 'Article'. Notre barre de navigation fonctionne, elle est facilement maintenable et il est possible d'en ajouter ou supprimer facilemnt des onglets. Nous pourrions sur le même princi


