====== Déboguer le SecurityComponent ====== __CakePHP__ : 1.3.x Le SecurityComponent est un composant bien utile de CakePHP permettant entre autre de sécuriser des formulaires: utilisé avec le FormHelper, il est responsable entre autre de: * ajouter un champ caché servant de ticket de validation lors du POST * comparer les champs affichés dans la page et les champs renvoyés en comparant un hash des noms des champs. En cas d'erreur de ces comparaisons, par défaut le SecurityComponent affiche une page vide avec un code d'erreur HTTP. Lors du développement, il peut alors être difficile de déterminer pour quelle raison un formulaire se bloque lors de l'envoi. Mais la plupart du temps la raison est que la comparaison des champs affichés par le FormHelper et les champs renvoyés (et donc vérifiés par le SecurityComponent) ne correspondent pas. **Comment comparer les champs affichés par le FormHelper et les champs renvoyés ?** __SecurityComponent__ Mettre un point d'arrêt de debug à la fin de la méthode **_validatePost(&$controller)** pour comparer les variables //$token// et //$check// ... $check = Security::hash(serialize($fieldList) . Configure::read('Security.salt')); return ($token === $check); } Si les valeurs de //$token// et //$check// sont différentes, on est bien dans le cas d'une différence entre champs affichés et champs renvoyés Dans ce cas: __FormHelper__ Mettre un point d'arrêt dans la méthode **secure($fields = array())**. Cette méthode est appelée par la méthode **end($options = null)** de FormHelper. Ce point d'arrêt permet de déterminer quels sont les champs affichés du formulaire (variable //$fields// en début de méthode) et le hash qui en découle (variable //$fields// en fin de méthode). function secure($fields = array()) { if (!isset($this->params['_Token']) || empty($this->params['_Token'])) { return; } ... $fields = Security::hash(serialize($fields) . Configure::read('Security.salt')); ... return $out; } Réutiliser le point d'arrêt mis dans SecurityComponent afin de voir le contenu de //$fieldList// qui devrait être différent du contenu de //$fields// dans FormHelper. A partir de là, il ne restera plus qu'à savoir d'où vient cette différence ! __Note__: Une erreur courante empêchant le SecurityComponent de fonctionner est le fait de ne pas fermer les formulaires: La fonction **submit($caption = null, $options = array())** du FormHelper ne fait qu'imprimer un bouton submit, mais ne ferme pas le formulaire ! Ce qui signifie un code HTML invalide, et dans le cas présent le fait de ne pas passer par la méthode **secure($fields = array())** nécessaire au fonctionnement du SecurityComponent. ====== Erreurs de validation non-montrées ====== __CakePHP__ : 1.3.x Alors que j'utilisais la méthode //saveAll()// dans un controller, les erreurs de validations des Models n'étaient pas montrées. J'ai cherché pendant un moment ce qu'il se passait dans la méthode elle-même, avant de comprendre que le problème se trouvait plus loin dans le code. Je faisais un nouveau //read()// depuis le Model principal, ce qui a pour effet de réinitialiser la variables //$validationErrors// !... Le code suivant explique ceci: Ici les erreurs ne sont pas montrées: if (!empty($this->data)) { if ($this->User->saveAll($this->data, array('validate'=>'first'))) { $this->Session->setFlash('User saved'); } else { $this->Session->setFlash('User not saved.'); } } $this->data = $this->User->read(null, $id); Ici les erreurs sont montrées: if (!empty($this->data)) { if ($this->User->saveAll($this->data, array('validate'=>'first'))) { $this->Session->setFlash('User saved'); } else { $this->Session->setFlash('User not saved.'); } } else { $this->data = $this->User->read(null, $id); } ====== Encodage de la base de données ====== __CakePHP__ : 1.3.x (probablement 1.2.x) __Problème__ : En faisant un export depuis une base de données MySQL vers une autre base de données, j'ai réalisé que les textes n'étaient pas encodés correctement dans la première. Une des conséquences dans mon cas particulier était le fait que lors de l'import dans la seconde base de données, l'ensemble des caractères accentués était affiché dans le mauvais encodage une fois dans les pages web. Normal, puisque le script d'export SQL généré par phpMyAdmin contenait déjà ces caractères mal encodés. Les deux bases de données contenaient pourtant des champs encodés en //utf8_unicode_ci//. __Solution__ : Le problème ne venait pas de l'encodage des champs dans MySQL, mais de la communication entre CakePHP et MySQL qui se faisait dans le mauvais encodage. Mais il est possible de spécifier au driver MySQL l'encodage à utiliser dans le fichier de configuration de base de données de CakePHP: class DATABASE_CONFIG { var $default = array( 'driver' => 'mysql', 'encoding' => 'utf8', //-> here the encoding is forced 'persistent' => false, 'host' => 'localhost', 'login' => 'my_login', 'password' => 'my_password', 'database' => 'my_database', 'prefix' => 'db_', ); } __Remarque__ : Dans le cas où vous avez déjà des caractères mal encodés dans votre base de données, le script suivant peut vous permettre de remplacer ces caractères afin de pouvoir néanmoins utiliser le script SQL obtenu lors de l'export: [[tips_informatiques:Linux:Shell:Fichiers_Dossiers:Fichiers_Dossiers#Remplacer des caractères UTF-8 affichés en ISO-8859-1 dans un fichier | Remplacer des caractères UTF-8 affichés en ISO-8859-1 dans un fichier]] ====== Bake des vues avec les vues hors CRUD ====== __Problème__: Un bake lancé avec un simple $ cake bake ne génère que les actions du CRUD. __Solution__: Lancer la commande de la façon suivante: $ cake bake view all De cette manière, bake recherche les templates pour toutes les actions présentes dans les contrôleurs, ce qui est en plus bien plus rapide pour générer toutes les vues :-) __Cake 2__: /path/to/project/app$ ../lib/Cake/Console/cake bake view Format admin_copy ====== Bake rapide d'un contrôleur avec actions publiques et admin ====== __Commande__: Lancer la commande de la façon suivante: $ cake bake controller Comment public admin ====== find avec conditions sur un modèle obtenu par contain ====== __Code__: $this->Structure->contain(array('Document' => array('fields' => array('id', 'pid', 'title', 'year'), 'conditions' => array('year' => $years), 'DocumentSubtype' => array('id', 'name', 'DocumentType' => array('id', 'name')), 'PublicationVector' => array('id', 'name'), 'Author' => array('id', 'firstname', 'lastname', 'cn_individu')) ) );