Tutorial

Introduction

Dans ce petit tutoriel, nous allons créer une application toute simple qui nous permettra de voir un maximum de concept de ce framework.
Pour cela nous allons utiliser le mkbuilder, qui va nous générer une application vierge, puis nous paramétrons sa base de donnée...
Mais d'abord une petite introduction au mkframework et son fonctionnement: lorsque vous appelez une page, le dispatcher en fonction de l'url va
définir quel module vous appelez, et quel action (exple: module article, action lister ou module article, action editer)
Il récupère l'instance unique du module, appelle l'action demandée qui est en fait une de ses méthodes précédées par un underscore "_"
Dans cette méthode, on va faire nos accès aux données, faire nos différents traitements, assigner les variables nécessaires aux vues
par exemple un tableau d'objet article pour notre vue de listage des articles
puis utiliser ces vues (via display() )
pour enfin, au final faire un envoi de notre réponse vers le client (via send() )

On peut entre temps, avant le send() charger différents modules à des "emplacements" par exemple notre menu de gauche, mais nous verrons ca plus tard.

On verra egalement dans ce tutorial comment agencer differentes briques: article et ses commentaires.

L'application qui va être développée

L'application choisi sera un modeste gestionnaire de contenu permettant de créer des articles, de les modifier et pourquoi pas laisser la possibilité d'être commenté
Le fameux blog en 15 minutes dont d'autres framework ont déjà fait la promo.

Installation

Telecharger le mkframework en cliquant sur le lien situé sur le site. Vous recuperez une archive au format zip.
Décompressez la dans le repertoire web de votre serveur apache, (repertoire www/ ou htdocs/ selon votre environnement)
Dans ce tutoriel, on part du principe que vous avez installé le framework à la racine de votre repertoire web, il est donc accessible via l'adresse http://localhost/mkframework_v3_XX_XX/

Creation des tables en base de donnée

CREATE TABLE `article` (
`id` int(11) NOT NULL auto_increment,
`titre` varchar(50) NOT NULL,
`resume` text NOT NULL,
`auteur_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
);

CREATE TABLE `auteur` (
`id` int(11) NOT NULL auto_increment,
`nom` varchar(30) NOT NULL,
`prenom` varchar(30) NOT NULL,
PRIMARY KEY (`id`)
);

Première étape la création d'une nouvelle application

Ouvrez votre navigateur à l'adresse http://localhost/mkframework_v3_XX_XX/
Cliquez dans le menu sur "créer un site"
mkbuilder_creersite.png
Entrez le nom de l'application à créer, ici : blog
mkbuilder_creersite_blog.png
Cliquez sur le bouton "créer"
L'application mkbuilder va générer une nouvelle application vierge dans le repertoire mkframework_v3_XX_XX/data/siteGenere/blog

Paramétrer la connexion à la base de donnée

Lors de la création d'une nouvelle application, le mkbuider créer une arborescence complète comprenant des librairies, des fichiers css, de config...
On peut depuis le mkbuilder éditer le fichier de configuration conf/connexion.php de votre application. Ce fichier permet de gérer plusieurs configuration de connexion
aussi bien plusieurs paramètres de connexion (user,base différente) que des bases différentes: mysql/postgresql...
Vous pouvez ainsi stocker vos articles sur mysql et vos user sur postgresql...
Pour paramétrer vos connexions le plus simplement du monde, via le mkbuilder, cliquez sur modifier, sélectionnez votre application, ici blog.
Cliquez sur "modifier les paramètres de connexion"
Et vous verrez la page suivante:
mkbuilder_modifierconnexion.png
Comme vous pouvez le remarquer il y a N config dont l'une d'elle, la première a son nom en constant: defaut
Cette première configuration doit rester (utilisée dans certains scripts de génération), vous pouvez créer autant de paramètres de connexion que vous voulez.
Modifier vos paramètres et valider le formulaire.

Générer la couche modèle

Le framework étant basé sur une architecture MVC, il nous faut créer la couche M: Modèle.
Pour cela rien de plus simple, cliquez sur "générer la couche modèle", sélectionnez dans le menu déroulant la configuration à utiliser et valider.
note: on sélectionne dans le menu déroulant la configuration à utiliser, car on peut avoir N configurations, et il faut utiliser des paramètres différents
pour s'y connecter afin de générer la couche modèle de toutes les tables accessibles via ces paramètres.
Nous choisirons ici defaut, n'ayant pas paramétré de deuxième connexion à une autre base ou a un autre sgbd.

note:vous pouvez gérer la configuration utilisé par table en cliquant sur "gérer la couche modèle"

Enrichissons un peu cette couche modèle

La couche modèle généré automatiquement est brute (elle ne comprend pas ici ni les jointures...)
Nous allons l'enrichir de deux facons: 1. en y ajoutant les jointures adequates, 2. en y inserant une methode permettant de l'utiliser dans un menu deroulant
Ajoutons une jointure en cliquant sur le lien "Ajouter jointure sur un modèle"
Sélectionnez ensuite la table sur laquelle ajouter une relation en cliquant dessus.
mkbuilder_ajoutjointure.png
En cliquant sur "article", un formulaire vous permet de selectionner une jointure de maniere intuitive
mkbuilder_ajoutjointuresurarticle.png
Un Article possède [un/plusieurs] [selection de table etrangere] dont [champ de la table etrangere] egal [champ de la table local]
Pour la table article, un article possède un auteur dont son id est egal au champ auteur_id de notre article
On renseigne donc : Un Article possède [un] [auteur] dont [id] est egal à [auteur_id]
Cela nous génère du code a ajouter dans notre fichier bdd/Article.php au sein de la méthode init()
mkbuilder_ajoutjointuresurarticlegenere.png

Code


<?php 
//Un Article a un Auteur dont id est egal a auteur_id
$this->hasOne('Auteur')->dont('id')->egal('auteur_id');
//pour l'appeler $Article->recupAuteur()->propriete
 
?>

Faisons de meme pour les commentaires: un article possède plusieurs commentaires
restons sur article
Un article possède [plusieurs] [commentaire] dont [article_id] est egal à [id]

Code


<?php 
//Un Article a plusieurs Commentaire dont article_id est egal a id
$this->hasMany('Commentaire')->dont('article_id')->egal('id');
//pour l'appeler $Article->recupCommentaire()->propriete
 
?>

A ajouter sous le code precedent, toujours dans la methode init() de la classe Article
Vous pouvez faire de meme pour auteur si vous souhaitez afficher ses articles...

Maintenant generons la methode getSelect() de l'auteur
Pour utiliser un menu déroulant afin de selectionner un auteur, il faudrait deja avoir un tableau conprenant une clé et un libellé affiché
Pour cela nous allons générer une méthode getSelect() pour la classe auteur
Cliquez sur "Ajouter methode getSelect() sur un modèle (appelé par FORM::getSelect('nomChamp',$tab) )"
mkbuilder_bloggetselect.png
Selectionnez "auteur"
mkbuilder_bloggetselect2.png
Dans le formulaire indiquer
Utiliser comme clé [id] Utiliser comme valeur [nom]
Valider
Vous obtenez
mkbuilder_bloggetselect3.png

Code


<?php 
//recupere un tableau pouvant etre utilise dans un formulaire select
//exple: FORM::getSelect('nomDuChamp', getInstance('Auteur')->getSelect() )
public function getSelect($key=null){
    
    
$tab=$this->find();
    
    
$selectTab=array();
    foreach(
$tab as $item){
        
$selectTab$item->id ] = $item->nom;
    }
    
    if(
$key!=null and isset($selectTab[$key])){
        return 
$selectTab[$key];
    }
    
    return 
$selectTab;

}
 
?>

Ajoutez cette nouvelle methode dans la classe auteur situé dans bdd/Auteur.php

Génération du CRUD qu'est-ce que c'est ?

CRUD Create Read Update Delete, les quatre actions d'une base de donnée.
Et bien le mkframework vous permet de générer facilement le crud pour chaque table.
Pour cela cliquez sur "générer le CRUD", sélectionnez dans le menu déroulant la configuration a utiliser
La une liste des tables disponible dans notre base va s'afficher.
mkbuilder_crud.png
Cliquez sur "article"
mkbuilder_crudgentable.png
Vous allez voir apparaître la liste des champs de cette table ainsi que des informations pour chaque champ: son type ainsi que le fait qu'il soit un champ primaire ou non.
Vous pouvez ici si c'est le cas configurer des menus deroulants s'appuyant sur la methode getSelect() d'une table etrangère
Par exemple dans notre cas, on voudrais bien choisir un auteur dans un menu deroulant plutot que de saisir son id :)
Naturellement le builder aura selectionné dans le menu deroulant en face d'auteur_id "select sur table "Auteur"" qui utilisera la methode précedement ajoutée.
Sélectionnez dans le menu déroulant si vous voulez que le mkbuilder modifie le menu de votre application ou non (laissé a oui)
Cliquez sur "générer le CRUD"
Et voila le crud de votre table article est généré
Recommencer pour commentaire, et auteur
note: pour "commentaire" selectionnez dans le menu deroulant "input" vu que les commentaires seront intégré aux articles on aura pas besoin d'utiliser le menu deroulant...

Visionnez l'application en cours de route

Rendez vous à l'adresse du mkbuilder, et cliquez dans le menu sur "lister les sites" vous voyez ainsi une liste des application que vous avez généré
mkbuilder_listersites.png
Cliquez sur blog
Vous voila sur votre site généré. vous pouvez remarquer en bas a gauche dans votre menu "article", cliquez dessus pour voir le CRUD généré.
mkbuilder_blogcrud.png
mkbuilder_blogcrudajout.png
mkbuilder_blogcrud2.png

Les briques générées, il faut faire l'intégration

On veut lister les articles, et en cliquant sur l'un d'eux voir un article en entier, + voir la liste des commentaires associé
+ un formulaire pour en ajouter.

Toutes briques nous les avons généré lors de la génération du CRUD de chaque table
La liste des articles, nous l'avons
La liste des commentaires, nous l'avons (jointure entre article et commentaire)
Le formulaire d'ajout de commentaire, nous l'avons, il faut le modifier pour forcer l'id de l'article

Pour cela on va utiliser la méthode "moduleInclude" de notre moteur de template, pour charger un module a un emplacement mémoire précis
On va inclure commentaire::list (module=commentaire,action=list) a l'emplacement "list_commentaire" puis, on va charger le formulaire d'ajout de commentaire::new
a l'emplacement "ajout_commentaire"
Comme ça dans la vue "show" de l'article on va pouvoir afficher ces éléments ou bon nous semble en faisant appel a $this->getContent(le_nom_de_l_emplacemnt)

Pour cela dans le fichier article/action.php, on va indiquer

Code


<?php 
//dans la fonction function _show(){

$tpl=getInstanceTpl();
//ajouter ces deux lignes avant le display show
$tpl->moduleInclude('commentaire::list&article_id='.getVar('id'), 'liste_commentaire');
$tpl->moduleInclude('commentaire::new&article_id='.getVar('id'), 'ajout_commentaire');
$tpl->display('show');
$tpl->send('template1');
 
?>


Dans la vue article/tpl/show.php

Code


<?php 
?>
<!--ICI le contenu html d'affichage de notre article-->

<!--en dessous on liste les commentaires-->
<?php echo $this->getContent('liste_commentaire'); ?>
<!--puis le formulaire d'ajout de commentaire-->
<?php echo $this->getContent('ajout_commentaire');?>
<?php
 ?>


Avant
mkbuilder_blogcrudshow.png
Après
mkbuilder_blogcrudshowmodifie.png

note:avec un "moduleInclude", les "send()" seront ignorés permettant d'éviter que les modules appelés exécute leur propre send et vous génère des erreurs

note2: si vous avez besoin d'exécuter un module avec son send (par exemple pour le module secure, si la personne se trompe dans son login/pass
il faut exécuter le "send()" vers le template "login" et pas le "template général", dans ce cas ne pas faire un "moduleInclude", mais un "moduleExec"
pour ne pas ignorer le "send()" du module
Si il n'y avait pas cette distinction "moduleInclude" / "moduleExec" on serait obligé de commenter les send() des méthodes "new" et "list"
et on ne pourrait pas l'appeler tout seul. Alors que la vous pouvez l'inclure dans une autre action, mais aussi l'appeler tout seul

note: comme vous l'avez remarqué on passe &article_id au moment ou l'on appel le module, on va donc modifier notre module pour qu'il utilise ce paramètre

Il faut remplacer les méthodes findLimit() par findByArticleLimit() et count() par countByArticle()
Dans le fichier module/commentaire/action.php

Code


<?php 
function list(){
    
$total=getInstance('Commentaire')->countByArticle$this->article_id );
    (...)
    
$commentaireTab=getInstance('Commentaire')->findByArticleLimit$this->article_id ,$pagination->getLimit());
    (...)
}
 
?>


et dans la couche modèle de commentaire bdd/commentaire.php

on ajoute la méthode findByArticleLimit()

Code


<?php 
function findByArticleLimit($articleId,$pagination){
    return 
$this->findLimit('article_id='.$this->quote($articleId),$pagination);
}    
 
?>


on ajoute la méthode countByArticle()

Code


<?php 
function countByArticle($articleId){
    return 
$this->count('article_id='.$this->quote($articleId));
}    
 
?>

En faisant cela on va bien retourner la liste et le nombre de commentaires attachés a notre article

note: techniquement on etait pas obligé de creer une nouvelle methode, on aurait tres bien pu ajouter le critere dans l'appel de l'action list

Code


<?php 
function list(){
    
$total=getInstance('Commentaire')->count'article_id='.getInstance('Commentaire')->article_id );
    (...)
    
$commentaireTab=getInstance('Commentaire')->findByArticleLimit'article_id='.getInstance('Commentaire')->article_id  ,$pagination->getLimit());
    (...)
}
 
?>

Mais c'est moins propre et il faut bien penser qu'il faut bien separer les couches, ne pas mettre de requete dans les controlleurs et encore moins dans les vues :)
Ceci permettant facilement de retrouver ses requetes dans le repertoire bdd (peut etre pratique pour une optimisation...)

On va ensuite modifier commentaire::new pour forcer le champ article_id
On va simplement ajouter un champ hidden dans le formulaire d'ajout de commentaire

Dans commentaire/tpl/edit.php

On a 3 manières de faire:
2 en récupérant la variable dans le module commentaire:
On peut récupérer une variable dans un module via:
getInstance('module_commentaire')->article_id
ou
getModuleVar('commentaire','article_id')
Et la dernière en récupérant simplement la variable id en GET vu que l'adresse de la page d'un article est ?:nav=article::show&id=N
on peut faire simplement un getVar('id')

Code


<?php 
//on passe en cache l'id de l'article qui est stocké dans le module commentaire (on lui a passé lors du moduleInclude "&article_id=")
$form=FORM::getHidden('article_id',getModuleVar('commentaire','article_id'));
//on passe également une variable "redirect" pour lui indiquer vers quel adresse il redirige après l'enregistrement
$form.=FORM::getHidden('redirect','article::show&id='.getInstance('module_commentaire')->article_id );

$form.=FORM::getInput('pseudo');
$form.=FORM::getTextarea('texte');
echo 
FORM::getForm($form,array('action'=>'commentaire::save'));
 
?>


Un peu de mise en forme

Après un peu de mise en forme: modification du css, ainsi que des vues module/articles/tpl/show.php, module/commentaires/tpl/list.php
On obtient ceci
On peut également modifier le module menu assez facilement en éditant module/menu/action.php
mkbuilder_blogmiseenforme.png

That's all

Voila on a fini c'était pas trop dur grâce au mkbuilder.
De plus la syntaxe générale est assez pratique et facilement assimilable.

Ce qu'on a appris dans ce tutorial

On a appris a utiliser le mkbuilder:
- générer une application vierge,
- administrer sa connexion,
- générer la couche modèle,
- générer le CRUD d'une table
On a appris a utiliser le framework
- comment charger un module a un emplacement mémoire avec moduleInclude (n'oubliez pas de commenter le send() pour éviter qu'il envoi la sortie trop tôt)
- comment ajouter des méthodes dans la couche modèle pour simuler d'autres requêtes
- comment passer des variables a un module, puis les récupérer dans une vue ( getModuleVar('commentaire','article_id') ou getInstance('module_commentaire')->article_id )
- comment forcer la redirection d'une méthode de sauvegarde.