Auteur
Page 1 / 13
Rvisions SQL
1.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 rsultats par date de cration en ordre descendant.
SELECT * FROM posts WHERE visible = true ORDER BY created DESC;
4.a. PostgreSQL - Trouver l'id et le title de 2 posts, aliaser le nom de la table (par Post) et prfixer le 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
Page 2 / 13
2. Crez une classe Chien qui hrite de la classe Animal et qui surcharge l'attribut name en lui donnant la valeur par dfaut Mdor .
class Chien extends Animal { public $nom = 'Mdor'; }
3. Compltez la classe prcdente en surchargeant la mthode manger pour qu'elle affiche ce qu'affiche la classe Animal, plus une ligne qui affiche <nom> est un bon chien .
class Chien extends Animal { public $nom = 'Mdor'; public function manger() { parent::manger(); echo "{$this->nom} est un bon chien"; }
4. Modifiez la classe prcdente pour ne pas afficher le rsultat de la mthode manger de la classe Animal. la place, affichez <nom> est un bon chien qui mange .
class Chien extends Animal { public $nom = 'Mdor'; public function manger() { echo "{$this->nom} est un bon chien qui mange"; }
Page 3 / 13
Paramtres
Essayez de dboguer les paramtres qui sont passs au contrleur dans les mthodes index, view et edit du contrleur PostsController.
debug( $this->params['pass'] ); // Paramtres GET, faon CakePHP
Pages d'erreur
Modifiez le code de la mthode view de la classe PostsController pour envoyer une page 404 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);
Page 4 / 13
Add / edit
Regroupez les mthodes add et edit de PostsController ainsi que les vues associes, afin de passer par la mthode _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
Page 5 / 13
<?php
if( $this->action == 'add' ) { __('Add Post'); } else { __('Edit Post'); } ?></legend> 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>
Page 6 / 13
Modle
Dans le modle Post, arrangez-vous pour que l'on puisse supprimer un billet mme si son id est cl trangre pour d'autres modles.
public $hasMany = array( 'Comment' => array( 'dependent' => true ) );
Dans le contrleur Posts, mthode view, dboguez le nombre d'utilisateurs dont l'id est strictement suprieur 2.
$count = $this->Post->User->find( 'count', array( 'conditions' => array( 'User.id >' => 2 ) ) ); debug( $count );
Page 7 / 13
Vue
1. Dans la vue index lie au contrleur Posts, changez le colonne user_id en User.username. Au besoin, modifiez la rcursivit dans la mthode du contrleur. Vrifiez que l'on puisse bien trier le tableau de rsultats 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 dfaut se trouvant dans cake/libs/views/layout/default.ctp dans app/views/layouts/default.ctp. Ajoutez des liens (en utilisant la mthode link du helper Html) vers les pages d'index de tous vos contrleurs.
<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 mthode _add_edit du contrleur Posts, la vue associe et le modle associ pour obtenir une liste droulante des utilisateurs pour le champ Post.user_id. Vous utiliserez la mthode find( 'list' ). controllers/posts_controller.php
// ... $listUsers = $this->Post->User->find( 'list' ); $this->set( 'listUsers', $listUsers ); $this->render( null, null, '_add_edit' );
Page 8 / 13
models/user.php
<?php class 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 obligs de de spcifier les options utiliser pour le champ user_id, puisqu'on a utilis la variable $users (et que notre champ s'appelle user_id) magie de CakePHP. Je vous conseille donc d'tre explicites pour viter de mauvaises surprises. Nanmoins, 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 a nomm le champ user_id (nom de la table au singulier, underscore id) puisque ce champ correspond une cl trangre. 4. Modifiez le code prcdent pour obtenir par dfaut une entre vide dans la liste droulante. Aidez-vous du CookBook en regardant l'aide pour la mthode input du FormHelper.
echo $this->Form->input( 'user_id', array( 'empty' => true ) );
5. Modifiez la mthode _add_edit du contrleur Posts et la vue associe pour obtenir des cases cocher des divers tags que l'on peut associer au billet. Vrifiez que l'enregistrement s'effectue correctement. controllers/posts_controller.php
Page 9 / 13
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 rcursivit. controllers/posts_controller.php $this->Post->recursive = 1; $this->set('posts', $this->paginate()); views/posts/index.ctp
<td><?php echo $post['Post']['visible']; ?> </td> <td><?php echo implode( ', ', Set::extract( $post, '/Tag/name' ) > </td> <td><?php echo $post['Post']['introduction']; ?> </td>
); ?
6. Dans la vue de la mthode view du contrleur Posts, prsentez les donnes comme pour un vrai blog (Titre, auteur / date de cration, tags, introduction, contenu, commentaires). Proccupezvous uniquement du HTML (pas du CSS). Utilisez les fonctions PHP strftime et strtotime pour obtenir la date dans la langue dfinie par setlocale. Inspirez-vous d'un billet du site http://www.zeldman.com/ views/posts/view.ctp
<div class="posts view"> <h1><?php echo $post['Post']['title'];?></h1> <p>Cre 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 catgoris' ); } else { $liens = array(); foreach( $tags as $id => $name ) { $liens[] = $this->Html->link( $name, array( 'controller' => 'tags', 'action' => 'view', $id ) ); } echo $this->Html->tag( 'p', 'Catgoris dans: '.implode( ',
Page 10 / 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> <?php if( 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( 'Cre 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 mthode index du contrleur Posts. Vous afficherez 4 champs dans le formulaire: Post.visible , Post.user_id, Post.title et Post.created. Construisez votre moteur champ par champ ( d'abord Post.visible, puis Post.visible et Post.user_id, etc... ). Utilisez (du moins terme) la mthode postConditions de la classe Controller. models/post.php
class Post extends AppModel { public $name = 'Post'; public $order = array( 'Post.id ASC' ); // ... }
Page 11 / 13
Il faut prciser que l'on retourne bien sur la mthode index du contrleur Posts. Par dfaut, CakePHP renverra vers la mthode add du contrleur courant. */ 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 anne maximale correspondant l'anne 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 vides foreach( 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 cration $created = $data['Post']['created']; $data = Set::remove( $data, 'Post.created' ); // Transformation en conditions $conditions = $this->postConditions( $data, array( 'Post.title' => 'LIKE' ) ); // Ajout ventuel du critre sur la date de cration (pour le type timestamp/datetime de la BDD) if( !empty( $created['day'] ) && !empty( $created['month'] ) && ! empty( $created['year'] ) ) { $createdStart = "{$created['year']}-{$created['month']}{$created['day']}";
Page 12 / 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' ) ); }
Page 13 / 13