Symfony: Comment corriger l’erreur “Can’t create table (errno: 150)”?

Après avoir conçu le fichier schema.yml pour une application de jeux en ligne, j’ai été surpris par une erreur mysql 150 au moment quand j’ai exécuté “php symfony doctrine:build –all –and-load –no-confirmation”, l’idée était de pouvoir gérer les permissions par rapport à un concours et donner à un utilisateur X les droits pour le faire, la solution la plus naturel afin de l’intégrer avec sfDoctrineGuard est de créer une table avec une relation “many to many“, voici donc ce que contenait mon fichier schma.yml pour la table concernée :

[code]
################## Questions ##################
Concours:
columns:
id: { type: integer(4), primary: true, autoincrement: true}
name: string(250)
….
############ Gestion des Permissions ############
sfGuardConcoursUser:
columns:
user_id: { type: integer, primary: true}
concours_id: { type: integer, primary: true}
relations:
Concours: { local: concours_id, foreign: id, foreignAlias: sfGuardConcoursUserConcours, onDelete: CASCADE }
sfGuardUser: { local: user_id, foreign: id, foreignAlias: sfGuardConcoursUsersfGuardUser, onDelete: CASCADE }
[/code]

Problème

Après avoir fait un “php symfony doctrine:build –all –and-load –no-confirmation”, j’ai eu droit à cette erreur:

SQLSTATE[HY000]: General error: 1005 Can’t create table ‘test.#sql-529_3dab’ (errno: 150). Failing Query: “ALTER TABLE jeux_concours ADD CONSTRAINT jeux_concours_concours_id_user_id FOREIGN KEY (concours_id) REFERENCES concours

Solution?

Et Oui c’est l’une des erreurs qui m’ont fait chier pendant une heure pour trouver d’où ça provient, pour vous faire gagner du temps, voici la recette magique ;) :

Pour mysql les relations “many to many” doivent avoir toujours le même type et la même longueur des champs clés, vous remarquez bien que le champ Concours[id] est du type integer(4), par-contre dans la table sfGuardConcoursUser il est du type integer, il n’a donc pas la même longueur et c’est à cause de cette différence que l’erreur 150 s’est produite.

La solution est très simple, il suffit de mettre integer comme type pour le champ id de la table Concours au lieu de integer(4) et Bingo!

Happy coding

symfony: Utiliser sfWidgetFormJQueryDate avec sfFormExtraPlugin

Vu le très peu de documentation que j’ai pu trouvé au sujet du plugin sfFormExtraPlugin de symfony, voici un guide rapide qui vous permettra d’installer le plugin sfFormExtraPlugin et pouvoir afficher un calendrier pour les champs de type date grâce au widget sfWidgetFormJQueryDate, voici donc les étapes à suivre:

1 – Installer le plugin sfFormExtraPlugin

En mode console, positionnez vous sur le dossier d’installation du projet et exécuter :

[code lang=’plain’]./symfony plugin:install sfFormExtraPlugin[/code]

2 – Télecharger et mettre en place les librairies jQuery nécessaire

Malheureusement le plugin sfFormExtraPlugin n’inclue pas les librairies externes nécessaire au fonctionnement, il faut le faire à la main!

il faut donc télécharger JQuery et JQuery UI:

  • Allez sur le site de jQuery UI
  • Dans la liste des composants déchochez toutes les cases sauf Core et Datepicker
  • Sélectionner le thème qui vous convient à droite et cliquez Télécharger

3 – Placé les fichiers téléchargés dans le dossier web et modifier le fichier view.yml

Décompresser jquery-ui-1.8custom.zip et copier les fichiers décompresser vers le dossier web ainsi:

  • js/jquery-1.4.2.min.js et js/jquery-ui-1.8.custom.min.js dans le dossier /web/js
  • css/jquery-ui-1.8.custom.css dans le dossier /web/css
  • renommer le dossier css/theme/images/ en jquery-ui-images et mettez le dans /web/images/
  • Ouvrez le fichier /web/css/jquery-ui-1.8.custom.css et remplacer “images/” par “../images/jquery-ui-images/” pour corriger le chemin vers les images
  • calendar.png une petite icône qu’on affiche à coté du champs pour faire joli :p (à mettre dans /web/images/)

Maintenant il faut inclure les fichiers javascript et css dans view.yml de notre application (par exemple /apps/backend/config/view.yml) :

Ajout du fichier javascript
[code lang=’plain’]
javascripts: [jquery-1.4.2.min.js, jquery-ui-1.8.custom.min.js]
[/code]
Ajout du fichier css
[code lang=’plain’]
stylesheets: [jquery-ui-1.8.custom.css]
[/code]

4 – Mise en place du Widget dans la classe du formulaire

[code lang=’php’]
class PrescripteursForm extends BasePrescripteursForm
{
public function configure()
{
$this->widgetSchema[‘date_debut’] = new sfWidgetFormJQueryDate(array(‘image’=>’/images/calendar.png’));
$this->widgetSchema[‘date_fin’] = new sfWidgetFormJQueryDate(array(‘image’=>’/images/calendar.png’));
}
}
[/code]

Et le tour est joué ;) ça devrai ressembler à ça :


Manipuler les paramètres de configuration dans symfony

SymfonyDans symfony, tous les paramètres de configuration sont stockés dans des fichiers .yml (settings.yml, app.yml, module.yml, logging.yml, and i18n.yml), ceux-ci sont accessibles via une classe spéciale sfConfig, certains sont automatiquement utilisés dans le framework!
Lors du développement d’une application/module symfony, on peut définir des paramètres de configuration spécifiques à notre application, l’objectif de ce tutoriel est d’expliquer comment récupérer/modifier les valeurs de ces variables !

Exemple de fichier de configuration

On considère que le nom de l’application est frontend, et le fichier de configuration de l’application /apps/frontend/config/app.yml
[code lang=’plain’]all:
categoryPages:
maxPages: 10
productPages:
maxPages: 5
generalMax: 15[/code]

Récupérer une valeur

[code lang=’php’]
echo sfConfig::get(‘app_categoryPages_maxPages’); // => 10
echo sfConfig::get(‘app_productPages_maxPages’); // => 5
echo sfConfig::get(‘app_generalMax’); // => 15
[/code]

Symfony utilise le format YAML pour tous ses fichiers de configuration grâce à sa syntaxe simple et efficace, les données sont représentées par une combinaison de listes, tableaux (de hachage) et données scalaires.

L’accès à une variable se fait via la méthode get() de la classe sfConfig, il suffit d’indiquer le chemin permettant d’accéder à la variable, on respectant ces petites règles :

  • Le premier paramètre corrépond au nom d’un fichier de configuration sans le .yml (settings, app, module, logging, i18n..), ces fichiers se trouve dans le répertoire /apps/NOMAPPLICATION/config/
  • Il ne faut pas mentionner le “all” ou “default” dans la méthode sfConfig::get()
  • Séparez les paramètres par des “_” en respectant arborescence selon le fichier .yml
  • Il est préférable de ne pas utilisé des “_” dans le nom des paramètres pour éviter un éventuel conflit

Modifier la valeur d’un paramètre “on the fly”

La méthode set de la classe sfConfig permet la modification de la valeur d’un paramètre de configuration, cette modificationn’est pas permanente, et n’affecte pas le fichier de configuration concerné:
Exemple :
[code lang=’php’]sfConfig::set(‘sf_timeout’, 86400);[/code]

Modifier un paramètre dans le fichier yml

Par défaut, symfony ne gère pas l’écriture dans les fichiers de configuration, il n’y a donc pas de méthode save() dans la classe sfConfig, néanmoins il fourni d’autre méthodes permettant la réalisation de cette tache:

Exemple :

Modifier app_categoryPages_maxPages dans /apps/frontend/config/app.yml

[code lang=’plain’]all:
categoryPages:
maxPages: 10
productPages:
maxPages: 5
generalMax: 15[/code]

Dans actions.class.php

[code lang=’php’]$app_config_file = sfConfig::get(‘sf_app_config_dir’).”/app.yml”;
$config_values = sfYaml::load($app_config_file);
$config_values[‘all’][‘categoryPages’][‘imap_maxPages’] = 20; // à titre d’exemple
$content = sfYaml::dump($config_values);
file_put_contents($app_config_file, $content);[/code]

sfYaml::load() retourne un tableau associatif contenant les paramètres de configuration du fichier passé en paramètre, sfYaml::dump() permet de génerer le code YAML à partir d’un tableau sur-lequel on a effectué nos modifications. sans oublier que le chemin du fichier en question doit être inscriptible (+w) pour permettre l’écriture des nouveaux paramètres

Pourquoi symfony ne gère pas l’écriture dans les fichiers YML?

Je vous rassure, ce n’est pas un oubli ;) au début ça m’a fait un peu bizarre mais voilà pourquoi :

  • Dans symfony, les paramètres de configuration ne découlent pas d’un seul fichier mais de plusieurs fichiers yml (en cascade), on saura pas lequel des fichiers modifier
  • Sur un serveur de développement, tous les fichiers YAML sont version-nés, si ceux-ci sont édités, il y aura des conflits au moment de mettre à jour par le biais du SVN/GIT
  • Les fichiers YAML ne sont pas destinés à être modifiés dynamiquement surtout dans un projets collaboratif (sauf cas particulier)

Un grand merci à Charles, Jérôme et François qui m’ont éclairci les idées à ce sujet =)

Voilà, ce billet touche à sa fin, à très bientôt ;)