Tag: Symfony

Symfony Admin generator: Transformer un filtre en multi filtre

applications-other Petit retour à un billet un peu plus technique le temps de préparer la suite sur twitter. Si il y a bien une chose dont on ne plus se passer une fois qu’on y a goûté dans symfony, c’est bien l’admin generator. Surtout que la doc couvre déjà pas mal de possibilités, mais avec un peu d’imagination on peut vraiment en faire ce qu’on veut.

Et ca tombe bien, parce que niveau idées tordues, nos chefs de projets ou clients sont rarement les derniers, vous serez d’accord avec moi ;)

Lors d’une présentation d’un back office récemment, on m’a demandé s’il était possible de choisir plusieurs valeurs lors du filtrage (en l’occurence des marques de produits). « Certainement » fut ma réponse, même si j’en avais aucune idée. J’ai donc jeté un coup d’oeil sur cette histoire et c’était finalement l’histoire de 2min.

Lire la suite

Mysql, Propel et l’UTF8 sont dans un bateau

edit-cut Un gros souci que j’ai toujours eu lors de mes projets symfony c’est la capacité de dire à Propel que je veux ma base en UTF8, j’ai beau mettre UTF8 un peu partout, database.yml, schema.yml, propel.ini rien n’y fait, mon build-all créé mes tables en ISO. D’ailleurs un peu déçu que Jobeet chapitre 3 n’aborde pas le sujet.

J’ai donc tenté de voir du côté de Mysql, pour mettre ce dernier par défaut en utf8, mais là aussi, on a beau remplir le my.cnf de utf8 dans toutes les options, rien de concret ne se produit.

J’en été donc resté à devoir rajouter à la main, dans mon .sql généré par symfony, le fameux « DEFAUT CHARSET=UTF8″. Mais devoir le rajouter à chaque modification de mon schema, cela peut devenir pénible dans des projets de tests.

Et puis par hasard au détour d’une conversation sur mysql dans une mailing-list (mea culpa j’ai pas noté l’adresse) je suis enfin tombé sur quelque chose qui fonctionne! A la création de la table, écrire:

CREATE DATABASE mydb CHARACTER SET utf8 COLLATE utf8_general_ci

Voilà, toutes les tables créés maintenant dans cette base seront en UTF8 par défaut.

Il y a sans doute mieux, mais pour l’instant je me contente de ça. Mais peut-être que quelqu’un a une meilleur solution? Comment gérez-vous vos tables en UTF8?

How-to Symfony: Gestion d’un arbre en Propel via les NestedSet – Part 2

system-run La dernière fois, on avait vu comment construire l’aspect graphique de notre gestion de catégorie via Symfony et Propel. On va voir maintenant comme lui associer les actions symfony qui vont bien.
Au programme donc dans l’ordre:

  • la remise en état des liens modifier/supprimer
  • l’ajout d’un lien pour ajouter un enfant à une catégorie
  • la sauvegarde de l’ordre de l’arbre

Ya du boulot, alors on se lance.

Lire la suite

How-to Symfony: Gestion d’un arbre en Propel via les NestedSet – Part 1

accessories-text-editor Les arbres en informatique c’est un peu le sujet qui fait rêver mais qui embête souvent, moi le premier. Car qui dit arbre, dit récursivité et là en général on commence à se prendre la tête dans les mains. Bah oui gérer quelque chose dont on ne connait pas la fin, ca fait toujours un peu peur.

Ici, le principe va être justement de gérer un arbre de catégories, un cas qui peut revenir assez régulièrement. A noter que le concept reprend la version doctrine de redotheoffice avec une modification quant au plugin jquery utilisé. En effet, on essaiera ici de gérer l’ordre des catégories également par drag and drop.

Lire la suite

De l’art de bien configurer vos credentials dans Symfony

system-run J’ai été confronté récemment à un problème tout bête dans ma gestion de droits sous Symfony. En effet, je voulais pouvoir configurer dans mes security.yml, une autorisation d’accès pour un certain niveau d’utilisateur ou en étant admin.

Tout naturellement j’ai opté pour l’écriture:

editArticle:
credentials: [ admin, editor ]

Mais l’accès devenait impossible pour les deux, alors que l’un ou l’autre fonctionnait. J’ai donc décidé d’appliquer tous les groupes au groupe admin pour régler le problème, manque de temps pour me documenter. Après coup, le problème m’étant revenu pendant que je naviguais sur le site du framework, j’ai tenté une recherche et la forcément la réponse devant mes yeux.

Lire la suite

Effectuer un pré et/ou post traitement dans vos actions Symfony

dialog-information Dans le genre, méthode symfony dont on ne parle pas qui peuvent être utiles, voici preExecute et son copain postExecute toutes les deux, méthodes de sfAction.

Comme leur nom le laisse à penser, ce sont des méthodes qui seront appeler en amont et en aval de l’exécution d’une action. Je n’ai pas vraiment d’idée d’utilisation à l’heure où j’écris mais dans un souci de factorisation, je trouve le concept intéressant et c’est bien avec ce genre de méthodes que je trouve Symfony si bien pensé.

Quelqu’un s’en est déjà servi? Une utilisation intéressante qui gagne à être connue?

Déployer votre projet Symfony en production via rsync

applications-other Vous venez de boucler votre projet symfony en local et êtes impatients de le tester sur votre hébergement réel. Personnellement cette opération ne m’enchante jamais car les lettres FTP sonnent comme une évidence, or jamais un client FTP ne m’aura convaincu surtout quand un jour on a pu goûter au rsync.

Lire la suite

Symfony: Automatiser la navigation dans votre admin-generator

accessories-text-editor Petite reprise d’activité du blog après quelques journée assez chargées. Et me voilà vous proposer une pré alpha d’un petit snippet pour symfony 1.2 qui vise à automatiser la génération d’un menu pour l’admin générator qui malheureusement ne propose rien de semblable à l’heure actuelle.
Et combien il devient vite barbant de rajouter les liens de vos nouveaux modules à la main dans votre layout.

Voici donc une solution possible et facile à mettre en place en se basant sur le fichier de routing.

Lire la suite

Prenez le contrôle de votre CSS

applications-system Votre projet est en plein sprint, les releases de corrections s’enchainent et vous devez soumettre le résultat à chaque fois à votre client. Et pourtant il y a un mécanisme des navigateurs qu’on adore en tant qu’utilisateur mais qui gène parfois en tant que développeur, la mise en cache des CSS.

Quoi de plus frustrant d’avoir en premier retour de votre client Euh, pourquoi l’image est au milieu de l’écran? alors que vous venez de passer les dernières heures à la mettre au bon endroit en retouchant votre CSS. Bien sûr vous lancez rapidement le cri de guerre adéquat F5! et la magie opère enfin.

Mais ne serait-il pas plus plaisant que d’obtenir dès le premier clic, le bon résultat?
Il y a pour cela une astuce, que bon nombre connaisse, mais qui dans un contexte de développement professionnel, est souvent lourde à mettre en place: changer le nom de votre CSS pour forcer le navigateur à la recharger et ainsi laisser apparaitre vos modifications du premier coup.

Lire la suite

Uploadez en Symfony

accessories-text-editor Quand on utilise un framework PHP aussi propre et bien pensé que symfony, on a souvent envie de continuer ce beau travail en ajoutant notre code de la meilleur des façons pour conserver la logique de l’application, MVC, héritage, composition…

Mais ce n’est pas toujours simple. Voici un petit exemple qui concerne un passage obscur de la documentation officielle des formulaires dans symfony, l’upload de fichier.

Pour commencer, il faut souvent définir dans la définition de notre formulaire le widget et le validator correspondant. Dans notre exemple, on prendra un champ nommé avatar, imaginons un classe Profil:

public function configure()
{
    $this->widgetSchema['avatar'] = new sfWidgetFormInputFile();
    // Un upload étant rarement obligatoire, 
   // le cas de l'avatar est un bon exemple, on le rend facultatif ici
    $this->validatorSchema['avatar'] = new sfValidatorFile(array('required' => false)) ; 
}

Maintenant on a bien notre formulaire qui s’affiche correctement. Le problème, si on n’upload pas de nouvel avatar, à la prochaine sauvegarde, le champ avatar sera remis à sa valeur par défaut, fonctionnement tout à fait normal en l’état.
Pour éviter ceci, voici la fonction à rajouter, toujours dans notre classe de notre formulaire Profil, c’est en fait une surcharge de la méthode save:

public function save($con = null)
{
    // On test si le champ avatar a été renseigné dans le formulaire
    if ($file = $this->getValue('avatar'))
    {
      // Si oui, on sauvegarde le fichier
      $filename = 'nomDuFichier';
      $extension = $file->getExtension($file->getOriginalExtension());
      $file->save(sfConfig::get('sf_upload_dir').$filename.$extension);
    }
    else
    {
      // Si non, on récupère la version actuelle dans l'objet Père (ici profil), 
      // que l'on insère dans le tableau de valeur du formulaire
      $this->values['avatar'] = $this->getObject()->getAvatar();
    }
 
    // Puis on lance la sauvegarde normal de la classe mère
    return parent::save($con);
}

Et voilà, nous sommes restés dans la logique métier de symfony, en surchargeant l’existant et surtout en permettant de garder notre action identique, les modifications ayant été apportées dans le modèle.

PHVsPjxsaT48c3Ryb25nPndvb19hZHNfcm90YXRlPC9zdHJvbmc+IC0gdHJ1ZTwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX2ltYWdlXzE8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb20vYWRzL3dvb3RoZW1lcy0xMjV4MTI1LTEuZ2lmPC9saT48bGk+PHN0cm9uZz53b29fYWRfaW1hZ2VfMjwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbS9hZHMvd29vdGhlbWVzLTEyNXgxMjUtMi5naWY8L2xpPjxsaT48c3Ryb25nPndvb19hZF9pbWFnZV8zPC9zdHJvbmc+IC0gaHR0cDovL3d3dy53b290aGVtZXMuY29tL2Fkcy93b290aGVtZXMtMTI1eDEyNS0zLmdpZjwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX2ltYWdlXzQ8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb20vYWRzL3dvb3RoZW1lcy0xMjV4MTI1LTQuZ2lmPC9saT48bGk+PHN0cm9uZz53b29fYWRfdXJsXzE8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb208L2xpPjxsaT48c3Ryb25nPndvb19hZF91cmxfMjwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbTwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX3VybF8zPC9zdHJvbmc+IC0gaHR0cDovL3d3dy53b290aGVtZXMuY29tPC9saT48bGk+PHN0cm9uZz53b29fYWRfdXJsXzQ8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb208L2xpPjxsaT48c3Ryb25nPndvb19hbHRfc3R5bGVzaGVldDwvc3Ryb25nPiAtIGN1c3RvbS5jc3M8L2xpPjxsaT48c3Ryb25nPndvb19hdXRvX2ltZzwvc3Ryb25nPiAtIGZhbHNlPC9saT48bGk+PHN0cm9uZz53b29fY29udGVudF9hcmNoaXZlczwvc3Ryb25nPiAtIGZhbHNlPC9saT48bGk+PHN0cm9uZz53b29fY29udGVudF9ob21lPC9zdHJvbmc+IC0gZmFsc2U8L2xpPjxsaT48c3Ryb25nPndvb19jdXN0b21fZmF2aWNvbjwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2ZlZWRidXJuZXJfdXJsPC9zdHJvbmc+IC0gPC9saT48bGk+PHN0cm9uZz53b29fZ29vZ2xlX2FuYWx5dGljczwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2xvZ288L3N0cm9uZz4gLSBodHRwOi8vd3d3LmFtaWNhbGVtZW50LXdlYi5uZXQvd3AtY29udGVudC93b29fdXBsb2Fkcy8zLWxvZ28ucG5nPC9saT48bGk+PHN0cm9uZz53b29fbWFudWFsPC9zdHJvbmc+IC0gaHR0cDovL3d3dy53b290aGVtZXMuY29tLzwvbGk+PGxpPjxzdHJvbmc+d29vX25hdl9leGNsdWRlPC9zdHJvbmc+IC0gPC9saT48bGk+PHN0cm9uZz53b29fcmVzaXplPC9zdHJvbmc+IC0gdHJ1ZTwvbGk+PGxpPjxzdHJvbmc+d29vX3Nob3J0bmFtZTwvc3Ryb25nPiAtIHdvbzwvbGk+PGxpPjxzdHJvbmc+d29vX3RoZW1lbmFtZTwvc3Ryb25nPiAtIFR5cGViYXNlZDwvbGk+PGxpPjxzdHJvbmc+d29vX3RodW1iX2hlaWdodDwvc3Ryb25nPiAtIDEwMDwvbGk+PGxpPjxzdHJvbmc+d29vX3RodW1iX3dpZHRoPC9zdHJvbmc+IC0gMTAwPC9saT48bGk+PHN0cm9uZz53b29fdXBsb2Fkczwvc3Ryb25nPiAtIGh0dHA6Ly93d3cuYW1pY2FsZW1lbnQtd2ViLm5ldC93cC1jb250ZW50L3dvb191cGxvYWRzLzMtbG9nby5wbmc8L2xpPjwvdWw+