% -*- mode: latex; -*- mustache tags:  
\ifx\wholebook\relax\else

	\documentclass[10pt,twoside,english]{root/support/latex/sbabook/sbabook}
  \usepackage{import}
  \subimport{root/support/latex/}{common.tex}

  \hypersetup{pdfinfo = {
    Title = {Construire une interface Web avec Teapot pour TinyBlog},
    Author = {},
    Keywords = {pharo, smalltalk}}}
  \begin{document}
\fi

\chapter{Une Interface Web avec Teapot pour TinyBlog}\section{Correction semaine pr\'{e}c\'{e}dente}
Vous pouvez charger la correction de la semaine pr\'{e}c\'{e}dente en ex\'{e}cutant le code suivant:

\begin{displaycode}{smalltalk}
Gofer new 
   smalltalkhubUser: 'PharoMooc' project: 'TinyBlog';
   package: 'ConfigurationOfTinyBlog';
   load. 
#ConfigurationOfTinyBlog asClass loadWeek2Correction
\end{displaycode}

Apr\`{e}s le chargement d'un package, il est recommand\'{e} d'ex\'{e}cuter les tests unitaires qu'il contient afin de v\'{e}rifier le bon fonctionnement du code charg\'{e}.
Pour cela, vous pouvez lancer l'outil TestRunner (World menu \textgreater{} Test Runner), chercher le package TinyBlog-Tests et lancer tous les tests unitaires de la classe \textcode{TBBlogTest} en cliquant sur le bouton \symbol{34}Run Selected\symbol{34}. Tous les tests doivent \^{e}tre verts. Une alternative est de presser l'icone verte qui se situe \`{a} cot\'{e} de la class \textcode{TBBlogTest}. 

Ouvrez maintenant un browser de code pour regarder le code des classes \textcode{TBBlog} et \textcode{TBBlogTest} et compl\'{e}ter votre propre code si n\'{e}cessaire.
Avant de poursuivre, n'oubliez pas de committer une nouvelle version dans votre d\'{e}p\^{o}t sur Smalltalkhub ou SS3 si vous avez modifi\'{e} votre application. 
\section{Une interface web avec Teapot}
Dans la suite, nous allons cr\'{e}er une premi\`{e}re interface web pour TinyBlog en utilisant Teapot (\url{http://smalltalkhub.com/#!/~zeroflag/Teapot}). Nous verrons une solution bien plus compl\`{e}te avec Seaside par la suite.
\subsection{La classe TBTeapotWebApp}
Cr\'{e}er une classe nomm\'{e}e \textcode{TBTeapotWebApp} ainsi:

\begin{displaycode}{smalltalk}
Object subclass: #TBTeapotWebApp
    instanceVariableNames: 'teapot'
    classVariableNames: 'Server'
    package: 'TinyBlog-Teapot'
\end{displaycode}

La variable \textcode{teapot} contiendra un petit server HTTP Teapot.
Ici on utilise une impl\'{e}mentation diff\'{e}rente du Design Pattern Singleton en utilisant une variable de classe nomm\'{e}e \textcode{Server}. Nous faison cela afin de ne pas avoir deux serveurs g\'{e}rant les connexions sur le m\^{e}me port. 

Ajouter la m\'{e}thode d'instance \textcode{initialize} pour initialiser la variable d'instance  \textcode{teapot} :

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> initialize
    super initialize.
    teapot := Teapot configure: {
       #port -> 8081. 
       #debugMode -> true }.
\end{displaycode}
\subsection{La Page d'accueil}
D\'{e}finissons une m\'{e}thode \textcode{homePage} dans le protocol 'html' qui retourne le code HTML de la page d'accueil de notre application web. Commen\c{c}ons par une version simple :

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> homePage
    ^ '<html><body><h1>TinyBlog Web App</h1></body></html>'
\end{displaycode}
\subsection{D\'{e}clarer les URLs (routes)}
Ajouter maintenant une m\'{e}thode \textcode{start} pour que l'objet teapot r\'{e}ponde \`{a} des URLs particuli\`{e}res. Commen\c{c}ons par r\'{e}pondre \`{a} l'URL \textcode{/} lorsqu'elle est acc\'{e}d\'{e}e en GET :

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> start
    "a get / is now returning an html welcome page"
    teapot
        GET: '/' -> [ self homePage ];
        start
\end{displaycode}
\subsection{Stopper l'application}
Ajouter \'{e}galement une m\'{e}thode pour stopper l'application :

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> stop
    teapot stop
\end{displaycode}
\subsection{D\'{e}marrage l'application }
Ajouter deux m\'{e}thodes \textcode{start} et \textcode{stop} c\^{o}t\'{e} classe pour respectivement d\'{e}marrer et arr\^{e}ter l'application dans le protocol 'start/stop'. Ces m\'{e}thodes utilisent la variable de class \textcode{Server} pour implanter un Singleton. 

\begin{displaycode}{smalltalk}
TBTeapotWebApp class >> start
    Server ifNil: [ Server := self new start ]    
\end{displaycode}

\begin{displaycode}{smalltalk}
TBTeapotWebApp class >> stop
    Server ifNotNil: [ Server stop. Server := nil ]
\end{displaycode}


\begin{figure}

\begin{center}
\includegraphics[width=0.6\textwidth]{figures/homepage.png}\caption{Une premi\`{e}re page servie par notre application.\label{fighome}}\end{center}
\end{figure}

\section{Tester votre application}
Maintenant nous pouvons lancer notre application en ex\'{e}cutant le code suivant pour d\'{e}marrer votre application :

\begin{displaycode}{smalltalk}
TBTeapotWebApp start
\end{displaycode}

Avec un navigateur web, vous pouvez acc\'{e}der \`{a} l'application via l'URL \url{http://localhost:8081/}. Vous devriez voir s'afficher le texte \symbol{34}TinyBlog Web App\symbol{34} comme la figure \ref{fighome}.


\begin{figure}

\begin{center}
\includegraphics[width=0.6\textwidth]{figures/withPosts.png}\caption{Afficher la liste des titres de posts.\label{figposts}}\end{center}
\end{figure}

\section{Afficher la liste des posts}
On souhaite maintenant modifier le code de la m\'{e}thode \textcode{homePage} pour que la page d'accueil affiche la liste de tous les posts visibles.
Pour rappel, tous les posts peuvent \^{e}tre obtenus via \textcode{TBBlog current allVisibleBlogPosts}.
Ajoutons une m\'{e}thode d'acc\`{e}s aux posts dans le protocol 'accessing' et modifions la m\'{e}thode \textcode{homePage} ainsi que deux petites m\'{e}thodes auxilliaires.

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> allPosts
   ^ TBBlog current allVisibleBlogPosts 
\end{displaycode}

Comme il faut g\'{e}n\'{e}rer une longue chaine de caract\`{e}res contenant le code HTML de cette page, nous utilisons un fl\^{o}t (stream) dans la m\'{e}thode \textcode{homePage}.
Nous avons \'{e}galement d\'{e}coup\'{e} le code en plusieurs m\'{e}thodes dont \textcode{renderPageHeaderOn:} et \textcode{renderPageFooterOn:} qui permettent de g\'{e}n\'{e}rer l'en-t\^{e}te et le pieds de la page html.

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> homePage
    ^ String streamContents: [ :s | 
            self renderPageHeaderOn: s.
            s << '<h1>TinyBlog Web App</h1>'.
            s << '<ul>'.
            self allPosts do: [ :aPost |
                s << ('<li>', aPost title, '</li>') ].
            s << '</ul>'.
            self renderPageFooterOn: s.
        ]
\end{displaycode}

Notez que le message \textcode{\textless{}\textless{}} est un synonyme du message \textcode{nextPutAll:} qui ajoute une collection d'\'{e}l\'{e}ments dans un fl\^{o}t (stream). 

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> renderPageHeaderOn: aStream
    aStream << '<html><body>' 
\end{displaycode}

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> renderPageFooterOn: aStream
    aStream << '</body></html>' 
\end{displaycode}

Tester l'application dans un navigateur web, vous devez maintenant voir la liste des titres des posts comme dans la figure \ref{figposts}. Si ce n'est pas le cas, assurez vous que votre blog a bien des posts. Vous pouvez utiliser le message \textcode{createDemoPosts} pour ajouter quelques postes g\'{e}n\'{e}riques.

\begin{displaycode}{smalltalk}
TBBlog createDemoPosts
\end{displaycode}
\section{D\'{e}tails d'un Post}\subsection{Ajouter une Nouvelle Page}
Am\'{e}liorons notre application. On souhaite que l'URL \url{http://localhost:8081/post/1} permette de voir le post num\'{e}ro 1. 

Commen\c{c}ons par penser au pire, et d\'{e}finissons une m\'{e}thode pour les erreurs. 
Nous d\'{e}finissons la m\'{e}thode \textcode{errorPage} comme suit : 

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> errorPage 
    ^ String streamContents: [ :s | 
        self renderPageHeaderOn: s. 
        s << '<p>Oups, an error occurred</p>'.
        self renderPageFooterOn: s.
        ]
\end{displaycode}

Teapot permet de d\'{e}finir des routes avec des patterns comme '\textless{}id\textgreater{}' dont la valeur est ensuite accessible dans l'objet requ\^{e}te re\c{c}u en param\`{e}tre du bloc.

Nous modifions donc la m\'{e}thode \textcode{start} pour ajouter une nouvelle route \`{a} notre application permettant d'afficher le contenu d'un post.

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> start
    teapot
       GET: '/' -> [ self homePage ];
       GET: '/post/<id>' -> [ :request | self pageForPostNumber: (request at: #id) asNumber ];
       start
\end{displaycode}

Il faut maintenant d\'{e}finir la m\'{e}thode \textcode{pageForPostNumber:} qui affiche toutes les informations d'un post:

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> pageForPostNumber: aPostNumber
    |currentPost|
    currentPost := self allPosts at: aPostNumber ifAbsent: [ ^ self errorPage ].
    ^ String streamContents: [ :s | 
        self renderPageHeaderOn: s. 
        s << ('<h1>', currentPost title, '</h1>').
        s << ('<h3>', currentPost date mmddyyyy, '</h3>').
        s << ('<p> Category: ', currentPost category, '</p>').
        s << ('<p>', currentPost text, '</p>').
        self renderPageFooterOn: s.
        ]
\end{displaycode}

Dans le code ci-dessus, on peut voir que le nombre pass\'{e} dans l'URL est utilis\'{e} comme la position du post \`{a} afficher dans la collection des posts. 
Cette solution est simple mais fragile puisque si l'ordre des posts dans la collection change, une m\^{e}me URL ne d\'{e}signera plus le m\^{e}me post.
\subsection{Ajouter des liens vers les posts}
Modifions la m\'{e}thode \textcode{homePage} pour que les titres des posts soient des liens vers leur page respective.

\begin{displaycode}{smalltalk}
TBTeapotWebApp >> homePage
    ^ String streamContents: [ :s | 
         self renderPageHeaderOn: s.
         s << '<h1>TinyBlog Web App</h1>'.
         s << '<ul>'.
         self allPosts withIndexDo: [ :index :aPost |
              s << '<li>';
                << ('<a href="/post/', index asString, '">');
                << aPost title ;
                << '</a></li>' ].
            s << '</ul>'.
            self renderPageFooterOn: s
        ]
\end{displaycode}

Maintenant, la page d'accueil de l'application affiche bien une liste de lien vers les posts.
\section{Extensions possibles}
Cette application est un exemple p\'{e}dagogique \`{a} travers lequel vous avez manipul\'{e} des collections, des fl\^{o}ts (Streams), etc. 

Plusieurs \'{e}volutions peuvent \^{e}tre apport\'{e}es telles que: 

\begin{itemize}
\item sur la page de d\'{e}tails d'un post, ajouter un lien pour revenir \`{a} la page d'accueil,
\item ajouter une page affichant la liste cliquable des cat\'{e}gories de posts,
\item ajouter une page affichant tous les posts d'une cat\'{e}gorie donn\'{e}e,
\item ajouter des styles CSS pour avoir un rendu plus agr\'{e}able.
\end{itemize}

 


\ifx\wholebook\relax\else
\end{document}
\fi