Formation CakePHP 1.3.8 - Exercices

13
 T utoriel CakePHP Créez rapidement vos applications avec CakePHP Auteur Date de dernière version Numéro de version Christian Buffin 18/04/11 1.2 Formation CakePHP 1.3.8 Page 1 / 13

Transcript of Formation CakePHP 1.3.8 - Exercices

Page 1: Formation CakePHP 1.3.8 - Exercices

5/11/2018 Formation CakePHP 1.3.8 - Exercices - slidepdf.com

http://slidepdf.com/reader/full/formation-cakephp-138-exercices 1/13

 

Tutoriel CakePHP

Créez rapidement vos applications avec CakePHP

Auteur Date de dernière version Numéro de version

Christian Buffin 18/04/11 1.2

Formation CakePHP 1.3.8 Page 1 / 13

Page 2: Formation CakePHP 1.3.8 - Exercices

5/11/2018 Formation CakePHP 1.3.8 - Exercices - slidepdf.com

http://slidepdf.com/reader/full/formation-cakephp-138-exercices 2/13

 

Révisions

SQL1.Trouver tous les posts qui sont visibles

SELECT * FROM posts WHERE visible = true;

2.Trouver tous les posts qui sont visibles et trier le jeu de résultats par date de création en ordredescendant.

SELECT * FROM posts WHERE visible = true ORDER BY created DESC;

3.Ajouter l'utilisateur lié au jeu de résultats.

SELECT * FROM posts INNER JOIN users ON ( posts.user_id = users.id ) WHEREposts.visible = true ORDER BY posts.created DESC;

4.a. PostgreSQL - Trouver l'id et le title de 2 posts, aliaser le nom de la table (par Post) et préfixerle nom de chaque colonne par Post__ 

SELECT "Post"."id" AS "Post__id", "Post"."title" AS "Post__title"FROM "posts" AS "Post"

LEFT JOIN "users" AS "User" ON ("Post"."user_id" = "User"."id")LIMIT 2

4.b. MySQL - Trouver l'id et le title de 2 posts

SELECT posts.id, posts.titleFROM posts

LEFT JOIN users ON (posts.user_id = users.id)LIMIT 2

Programmation orientée objet1. Créez une classe Animal qui possède un attribut publique nom (dont la valeur par défaut est« Animal ») et une méthode publique manger qui affiche « <nom> mange ».

class Animal{

public $nom = 'Animal';

public function manger() {echo "{$this->nom} mange";

}

Formation CakePHP 1.3.8 Page 2 / 13

Page 3: Formation CakePHP 1.3.8 - Exercices

5/11/2018 Formation CakePHP 1.3.8 - Exercices - slidepdf.com

http://slidepdf.com/reader/full/formation-cakephp-138-exercices 3/13

 

}

2. Créez une classe Chien qui hérite de la classe Animal et qui surcharge l'attribut name en luidonnant la valeur par défaut « Médor ».

class Chien extends Animal{

public $nom = 'Médor';}

3. Complétez la classe précédente en surchargeant la méthode manger pour qu'elle affiche cequ'affiche la classe Animal, plus une ligne qui affiche « <nom> est un bon chien ».

class Chien extends Animal{

public $nom = 'Médor';

public function manger() {parent::manger();echo "{$this->nom} est un bon chien";

}}

4. Modifiez la classe précédente pour ne pas afficher le résultat de la méthode manger de laclasse Animal. À la place, affichez « <nom> est un bon chien qui mange ».

class Chien extends Animal{public $nom = 'Médor';

public function manger() {echo "{$this->nom} est un bon chien qui mange";

}}

Formation CakePHP 1.3.8 Page 3 / 13

Page 4: Formation CakePHP 1.3.8 - Exercices

5/11/2018 Formation CakePHP 1.3.8 - Exercices - slidepdf.com

http://slidepdf.com/reader/full/formation-cakephp-138-exercices 4/13

 

Code généré par la console

Localisation

Créez et remplissez le fichier de traduction en français pour le code généré par la console(seulement pour la partie posts/edit.ctp). Testez dans votre navigateur.

# app/locale/fre/LC_MESSAGES/default.po

msgid "Invalid post"msgstr "Billet invalide"

msgid "The post has been saved"msgstr "Impossible d'enregistrer le billet"

msgid "The post could not be saved. Please, try again."

msgstr "Impossible d'enregistrer le billet. Veuillez réessayer"

ParamètresEssayez de déboguer les paramètres qui sont passés au contrôleur dans les méthodes index,view et edit du contrôleur PostsController.

debug( $this->params['pass'] ); // Paramètres GET, façon CakePHP

debug( $this->data ); // Paramètres POST, commenter le redirect pour lesvoir.

debug( $this->params['named'] ); // Paramètres nommés

Pages d'erreurModifiez le code de la méthode view de la classe PostsController pour envoyer une page404 lorsque l'enregistrement n'est pas trouvé.

function view($id = null) {$post = $this->Post->read(null, $id);if( empty( $post ) ) {

$this->cakeError( 'error404' );}$this->set('post', $post);

Formation CakePHP 1.3.8 Page 4 / 13

Page 5: Formation CakePHP 1.3.8 - Exercices

5/11/2018 Formation CakePHP 1.3.8 - Exercices - slidepdf.com

http://slidepdf.com/reader/full/formation-cakephp-138-exercices 5/13

 

}

Add / edit

Regroupez les méthodes add et edit de PostsController ainsi que les vues associées, afin depasser par la méthode _add_edit.

PostsController

function add() {$args = func_get_args();call_user_func_array( array( $this, '_add_edit' ), $args );

}

function edit() {$args = func_get_args();call_user_func_array( array( $this, '_add_edit' ), $args );

}

function _add_edit( $id = null ) {if( $this->action == 'edit' ) {

$post = $this->Post->read( null, $id );if( empty( $post ) ) {$this->cakeError( 'error404' );}

}

if (!empty($this->data)) {

$this->Post->create();if ($this->Post->save($this->data)) {$this->Session->setFlash(__('The Post has been saved',

true));$this->redirect(array('action' => 'index'));

} else {$this->Session->setFlash(__('The Post could not be saved.

Please, try again.', true));}

}

if( $this>action == 'edit' && empty( $this->data ) ) {$this->data = $post;

}

$this->render( null, null, '_add_edit' );}

 _add_edit.ctp

<div class="posts form"><?php echo $this->Form->create('Post');?>

<fieldset><legend><?php

Formation CakePHP 1.3.8 Page 5 / 13

Page 6: Formation CakePHP 1.3.8 - Exercices

5/11/2018 Formation CakePHP 1.3.8 - Exercices - slidepdf.com

http://slidepdf.com/reader/full/formation-cakephp-138-exercices 6/13

 

if( $this->action == 'add' ) {__('Add Post');

}else {__('Edit Post');

}

?></legend><?php

if( $this->action == 'edit' ) {echo $this->Form->input('id');

}echo $this->Form->input('title');echo $this->Form->input('user_id');echo $this->Form->input('visible');echo $this->Form->input('introduction');echo $this->Form->input('content');echo $this->Form->input('Tag');

?></fieldset>

<?php echo $this->Form->end(__('Submit', true));?></div><div class="actions">

<h3><?php __('Actions'); ?></h3><ul>

<?php if( $this->action == 'edit' ):?><li><?php echo $this->Html->link(__('Delete', true),

array('action' => 'delete', $this->Form->value('Post.id')), null,sprintf(__('Are you sure you want to delete # %s?', true), $this->Form->value('Post.id'))); ?></li>

<?php endif;?><li><?php echo $this->Html->link(__('List Posts', true),

array('action' => 'index'));?></li></ul>

</div>

Formation CakePHP 1.3.8 Page 6 / 13

Page 7: Formation CakePHP 1.3.8 - Exercices

5/11/2018 Formation CakePHP 1.3.8 - Exercices - slidepdf.com

http://slidepdf.com/reader/full/formation-cakephp-138-exercices 7/13

 

ModèleDans le modèle Post, arrangez-vous pour que l'on puisse supprimer un billet même si son id estclé étrangère pour d'autres modèles.

public $hasMany = array('Comment' => array(

'dependent' => true)

);

Dans le contrôleur Posts, méthode view, déboguez le nombre d'utilisateurs dont l'id est strictementsupérieur à 2.

$count = $this->Post->User->find( 'count', array( 'conditions' =>array( 'User.id >' => 2 ) ) );

debug( $count );

Formation CakePHP 1.3.8 Page 7 / 13

Page 8: Formation CakePHP 1.3.8 - Exercices

5/11/2018 Formation CakePHP 1.3.8 - Exercices - slidepdf.com

http://slidepdf.com/reader/full/formation-cakephp-138-exercices 8/13

 

Vue1. Dans la vue index liée au contrôleur Posts, changez le colonne user_id en User.username. Aubesoin, modifiez la récursivité dans la méthode du contrôleur. Vérifiez que l'on puisse bien trier letableau de résultats par nom d'utilisateur.

views/posts/index.ctp

<th><?php echo $paginator->sort('title');?></th><th><?php echo $paginator->sort('User.username');?></th><th><?php echo $paginator->sort('introduction');?></th>…

<?php echo $post['Post']['title']; ?></td><td>

<?php echo $post['User']['username']; ?></td>

<td><?php echo $post['Post']['introduction']; ?>

controllers/posts_controller.php

function index() {$this->Post->recursive = 0;$this->set('posts', $this->paginate());

}

2. Recopiez le layout par défaut se trouvant dans cake/libs/views/layout/default.ctp dansapp/views/layouts/default.ctp. Ajoutez des liens (en utilisant la méthode link du helper Html) versles pages d'index de tous vos contrôleurs.

<div id="menu"><?php echo $this->Html->link( 'Billets', array( 'controller' =>

'posts', 'action' => 'index' ) ); ?><?php echo $this->Html->link( 'Utilisateurs', array( 'controller' =>

'users' ) ); ?>// ...

</div>

3. Modifiez la méthode _add_edit du contrôleur Posts, la vue associée et le modèle associé pourobtenir une liste déroulante des utilisateurs pour le champ Post.user_id. Vous utiliserez la méthodefind( 'list' ).

controllers/posts_controller.php

// ...$listUsers = $this->Post->User->find( 'list' );$this->set( 'listUsers', $listUsers );

$this->render( null, null, '_add_edit' );

Formation CakePHP 1.3.8 Page 8 / 13

Page 9: Formation CakePHP 1.3.8 - Exercices

5/11/2018 Formation CakePHP 1.3.8 - Exercices - slidepdf.com

http://slidepdf.com/reader/full/formation-cakephp-138-exercices 9/13

 

}

models/user.php

<?phpclass User extends AppModel {

var $name = 'User';var $displayField = 'username';// ...

views/posts/_add_edit.ctp

echo $this->Form->input( 'user_id', array( 'options' => $listUsers ) );

Remarque: on n'est pas obligés de de spécifier les options à utiliser pour le champ user_id,puisqu'on a utilisé la variable $users (et que notre champ s'appelle user_id) … magie deCakePHP. Je vous conseille donc d'être explicites pour éviter de mauvaises surprises. Néanmoins,voici le code permettant d'utiliser la magie de CakePHP.

controllers/posts_controller.php

// ...$users = $this->Post->User->find( 'list' );$this->set( 'users', $users );

$this->render( null, null, '_add_edit' );}

views/posts/_add_edit.ctp

echo $this->Form->input( 'user_id' );

L'explication de cette magie est que l'on a bien respecté les conventions CakePHP, et que l'on anommé le champ user_id (nom de la table au singulier, underscore id) puisque ce champcorrespond à une clé étrangère.

4. Modifiez le code précédent pour obtenir par défaut une entrée vide dans la liste déroulante.Aidez-vous du CookBook en regardant l'aide pour la méthode input du FormHelper.

echo $this->Form->input( 'user_id', array( 'empty' => true ) );

5. Modifiez la méthode _add_edit du contrôleur Posts et la vue associée pour obtenir des cases àcocher des divers tags que l'on peut associer au billet. Vérifiez que l'enregistrement s'effectuecorrectement.

controllers/posts_controller.php

Formation CakePHP 1.3.8 Page 9 / 13

Page 10: Formation CakePHP 1.3.8 - Exercices

5/11/2018 Formation CakePHP 1.3.8 - Exercices - slidepdf.com

http://slidepdf.com/reader/full/formation-cakephp-138-exercices 10/13

 

// ...$this->set( 'tags', $this->Post->Tag->find( 'list' ) );

$this->render( null, null, '_add_edit' );}

views/posts/_add_edit.ctp

echo $this->Form->input( 'Tag', array( 'multiple' => 'checkbox' ) );

5. Dans l'index des billets, ajoutez une colonne contenant la liste des tags, utilisez la classe Set.N'oubliez pas d'augmenter la récursivité.

controllers/posts_controller.php

$this->Post->recursive = 1;$this->set('posts', $this->paginate());

views/posts/index.ctp

<td><?php echo $post['Post']['visible']; ?>&nbsp;</td><td><?php echo implode( ', ', Set::extract( $post, '/Tag/name' ) ); ?>&nbsp;</td><td><?php echo $post['Post']['introduction']; ?>&nbsp;</td>

6. Dans la vue de la méthode view du contrôleur Posts, présentez les données comme pour unvrai blog (Titre, auteur / date de création, tags, introduction, contenu, commentaires). Préoccupez-vous uniquement du HTML (pas du CSS). Utilisez les fonctions PHP strftime et strtotime pourobtenir la date dans la langue définie par setlocale. Inspirez-vous d'un billet du sitehttp://www.zeldman.com/

views/posts/view.ctp

<div class="posts view"><h1><?php echo $post['Post']['title'];?></h1><p>Crée par <?php echo $post['User']['username'];?> le <?php echo

strftime( '%A %e %B %Y à %H:%M', strtotime( $post['Post']['created'] ) );?

>.</p><?php

$tags = Set::combine( $post, 'Tag.{n}.id', 'Tag.{n}.name' );if( empty( $tags ) ) {

echo $this->Html->tag( 'p', 'Non catégorisé' );}else {

$liens = array();foreach( $tags as $id => $name ) {

$liens[] = $this->Html->link( $name,array( 'controller' => 'tags', 'action' => 'view', $id ) );

}echo $this->Html->tag( 'p', 'Catégorisé dans: '.implode( ',

Formation CakePHP 1.3.8 Page 10 / 13

Page 11: Formation CakePHP 1.3.8 - Exercices

5/11/2018 Formation CakePHP 1.3.8 - Exercices - slidepdf.com

http://slidepdf.com/reader/full/formation-cakephp-138-exercices 11/13

 

', $liens ) );}

?><div class="introduction">

<?php echo $post['Post']['introduction'];?></div>

<div class="content"><?php echo $post['Post']['content'];?>

</div>

<div class="comments"><h2>Commentaires</h2>

<?phpif( empty( $post['Comment'] ) ) {

echo $this->Html->tag( 'p', 'Aucun commentaire' );}else {

foreach( $post['Comment'] as $comment ) {$tmp = '';

$tmp .= $this->Html->tag( 'h3', $comment['name'] );$tmp .= $this->Html->tag( 'p', strftime( 'Crée le %A

%e %B %Y à %H:%M', strtotime( $comment['created'] ) ) );$tmp .= $this->Html->tag( 'div',

$comment['content'] );echo $this->Html->tag( 'div', $tmp, array( 'class' =>

'comment' ) );}

}?></div>

</div>

7. Faites un formulaire de recherche pour la méthode index du contrôleur Posts. Vous afficherez 4champs dans le formulaire: Post.visible , Post.user_id, Post.title et Post.created. Construisez votremoteur champ par champ ( d'abord Post.visible, puis Post.visible et Post.user_id, etc... ). Utilisez(du moins à terme) la méthode postConditions de la classe Controller.

models/post.php

class Post extends AppModel {public $name = 'Post';public $order = array( 'Post.id ASC' );

// ...}

Formation CakePHP 1.3.8 Page 11 / 13

Page 12: Formation CakePHP 1.3.8 - Exercices

5/11/2018 Formation CakePHP 1.3.8 - Exercices - slidepdf.com

http://slidepdf.com/reader/full/formation-cakephp-138-exercices 12/13

 

views/posts/index.ctp (à rajouter avant le tableau de résultats)

<?php/*

Il faut préciser que l'on retourne bien sur la méthode index ducontrôleur Posts.

Par défaut, CakePHP renverra vers la méthode add du contrôleurcourant.

*/echo $this->Form->create( null, array( 'url' => array( 'controller' =>

'posts', 'action' => 'index' ) ) );

echo $this->Form->input( 'Post.user_id', array( 'empty' => true ) );echo $this->Form->input( 'Post.title' );/*

Le champ created est de type timestamp/datetime, on va le forcerà être de type date,

avec un format francophone et une année maximale correspondant àl'année en cours

*/echo $this->Form->input( 'Post.created', array( 'type' => 'date',

'dateFormat' => 'DMY', 'empty' => true, 'maxYear' => date( 'Y' ) ) );echo $this->Form->input( 'Post.visible' );

echo $this->Form->end( __( 'Search', true ) );?>

controllers/posts_controller.php

public function index() {

$conditions = array();$data = $this->data;

if( !empty( $this->data ) ) {// Nettoyage des champs videsforeach( array( 'Post.user_id', 'Post.title' ) as $path ) {

$value = Set::classicExtract( $data, $path );if( empty( $value ) ) {

$data = Set::remove( $data, $path );}

}

// Variable temporaire pour stocker la date de création$created = $data['Post']['created'];$data = Set::remove( $data, 'Post.created' );

// Transformation en conditions$conditions = $this->postConditions( $data, array( 'Post.title'

=> 'LIKE' ) );

// Ajout éventuel du critère sur la date de création (pour letype timestamp/datetime de la BDD)

if( !empty( $created['day'] ) && !empty( $created['month'] ) && !empty( $created['year'] ) ) {

$createdStart = "{$created['year']}-{$created['month']}-

{$created['day']}";

Formation CakePHP 1.3.8 Page 12 / 13

Page 13: Formation CakePHP 1.3.8 - Exercices

5/11/2018 Formation CakePHP 1.3.8 - Exercices - slidepdf.com

http://slidepdf.com/reader/full/formation-cakephp-138-exercices 13/13

 

$createdStop = date( 'Y-m-d', strtotime( $createdStart ) + (24 * 60 * 60 ) );

$conditions[] = "Post.created BETWEEN '{$createdStart}' AND'{$createdStop}'";

}}

$this->Post->recursive = 0;$this->set( 'posts', $this->paginate( null, $conditions ) );$this->set( 'users', $this->Post->User->find( 'list' ) );

}

controllers/posts_controller.php (méthode alternative)

public function index() {$conditions = array();$data = $this->data;

if( !empty( $this->data ) ) {// Variable temporaire pour stocker la date de création$created = $data['Post']['created'];$data = Set::remove( $data, 'Post.created' );

// Transformation en conditions$conditions = $this->postConditions(

$data,array(

'Post.title' => 'LIKE','Post.user_id' => 'LIKE'

)

);

// Ajout éventuel du critère sur la date de création (pour letype timestamp/datetime de la BDD)

if( !empty( $created['day'] ) && !empty( $created['month'] ) && !empty( $created['year'] ) ) {

$createdStart = "{$created['year']}-{$created['month']}-{$created['day']}";

$createdStop = date( 'Y-m-d', strtotime( $createdStart ) + (24 * 60 * 60 ) );

$conditions[] = "Post.created BETWEEN '{$createdStart}' AND'{$createdStop}'";

}}

$this->Post->recursive = 0;$this->set( 'posts', $this->paginate( null, $conditions ) );$this->set( 'users', $this->Post->User->find( 'list' ) );

}

Formation CakePHP 1.3.8 Page 13 / 13