Ce blog — désormais archivé — est en lecture seule. Rendez-vous sur mon nouveau site personnel.

Prendre un Café

L'espace d'expression de Nicolas Perriault

Aller au contenu | Aller au menu | Aller à la recherche

mercredi 5 mai 2010

Juste pour rappel

Ahem, pour ceux qui ne l’auraient pas compris, les billets techniques seront désormais publiés sur le blog de ma société, Akei.

Tenez c’est drôle, je viens justement d’en publier un sur l’installation de Django dans un environnement virtuel Python avec pip, virtualenv et virtualenvwrapper, c’est fou ça.

Pour faire valoir ce que de droit, veuillez madame, monsieur…

mardi 20 avril 2010

Faire part de naissance

Ceux qui me suivent sur twitter en ont eu la primeur, mais j’officialise sur ce blog : Akei, ma société, est née.

Akei

Akei met en avant une offre de services axée sur le conseil, la formation et le développement Web, autour de technologies variées comme PHP, Symfony, Python, Django ; mais plus que tout sur la qualité.

Je ne m’étalerai pas sur les longueurs et turpitudes administratives proprement kafkaïennes qu’il m’a fallu affronter pour accoucher du bébé (et qui durent encore, soit dit en passant), mais je veux juste profiter de l’instant pour vous inciter à regarder ce site, à en lire les contenus, et à prendre contact si vous vous reconnaissez dans la vision présentée, pour éventuellement - pourquoi pas ? - travailler ensemble sur vos projets Web.

jeudi 18 février 2010

RMLL 2010 : appel à conférences

D’aucuns ne le sachant peut-être pas, je suis cette année co-responsable - avec Thomas Parisot - de l’organisation des sessions Internet aux Rencontres Mondiales du Logiciel Libre qui se tiendront à Bordeaux du 6 au 11 juillet 2010.

Si vous travaillez sur (ou avec) un projet libre ayant un rapport avec Internet (Web, XMPP, IRC, email, etc.), n’hésitez pas à nous proposer un sujet de conférence technique en rapport. Trois formats d’intervention sont disponibles : 20, 40 ou 60 minutes (incluant la séance aux questions). Les conférences peuvent se tenir en français, en espagnol ou en anglais.

Si vous souhaitez proposer un sujet de conférence, il vous suffit d’envoyer un simple email d’une dizaine de ligne présentant dans les grandes lignes votre thématique, à l’adresse suivante : internet@listes2010.rmll.info.

Par contre, la date limite de dépôt des candidatures est fixée au 1er mars, autant vous dire qu’il vous faut vous dépêcher si vous souhaitez postuler ;)

mercredi 17 février 2010

User Dependent Forms with Symfony

While sadly not being at Symfony Live 2010 with pals, I’m drowning my sorrow into tech tutorials writing.

Sometimes you want to design forms and contextualize them regarding the current user session. For example:

  • Manage the display of some fields regarding the user authentication status and credentials;
  • Filter some queries used to get the values available in a <select/> tag;
  • Allow multiple steps form validation with step state persistence (wizzard);
  • etc.

So how can we achieve this without using an evilish sfContext::getInstance()->getUser() call in the configure() method of the form?

Symfony 1.2 1.3 and 1.4 introduced the generation of a project-wide BaseForm class we can use here to setup some convenient methods to allow user setters and getters:

 php
<?php
class BaseForm extends sfFormSymfony
{
  static protected $user = null;

  static public function getUser()
  { 
    return self::$user;
  }

  static public function getValidUser()
  {
    if (!self::$user instanceof sfBasicSecurityUser)
    {
      throw new RuntimeException('No valid user instance available');
    }
    
    return self::$user;
  }

  static public function setUser(sfBasicSecurityUser $user)
  {
    self::$user = $user;
  }
}

Okay, we now can set a user instance as a static property of all available forms within the project, nice. Wait, how the hell will we set the instance, and when?

Symfony dispatch a very useful context.load_factories event when all the factories - including the user one - are instanciated and available in the context. So we can listen to this event and set the user instance to the forms when it’s ready. We’ll do this in the ProjectConfiguration.class.php:

 php
<?php
class ProjectConfiguration extends sfProjectConfiguration
{
  public function setup()
  {
    // ...
    
    $this->dispatcher->connect('context.load_factories', array($this, 'listenToLoadFactoriesEvent'));
  }

  public function listenToLoadFactoriesEvent(sfEvent $event)
  {
    BaseForm::setUser($event->getSubject()->getUser());
  }
}

So now we’ve set a static user instance in every form at project configuration time, we can use it in any form.

For example, imagine a form where only authenticated users having an admin credential can see, fill and submit an hypothetic is_published field:

 php
class myForm extends BaseForm
{
  public function configure()
  {
    // will throw an exception if no user is available
    $user = self::getValidUser();
    
    $this->setWidgets(array(
      'title' => new sfWidgetFormInputText(),
      'body' => new sfWidgetFormTextarea(),
    ));
    
    $this->setValidators(array(
      'title' => new sfValidatorString(array('min_length' => 5)),
      'body' => new sfValidatorString(array('min_length' => 20)),
    ));
    
    if ($user->isAuthenticated() && $user->hasCredential('admin'))
    {
      $this->widgetSchema['is_published'] = new sfWidgetFormInputCheckbox();
      $this->validatorSchema['is_published'] = new sfValidatorBoolean(array(
        'required' => false,
      ));
    }
    
    // ...
  }
}

Here a basic user won’t see and won’t be able to submit any value for the is_published field. Note that all those changes won’t ever affect the controllers or the model, and the forms will still be easily testable because the forms and the user instance are not tightly coupled.

As a side note, you can also use the form options to eventually pass a user instance and fallback on the static instance in case it’s not available:

 php
class myForm extends BaseForm
{
  public function configure()
  {
    // will throw an exception if no user is available
    $user = $this->getOption('user', self::getValidUser());
    
    // ...
  }
}

In a controller, you would use it this way:

 php
<?php 
class fooActions extends sfActions
{
  public function executeBar(sfWebRequest $request)
  {
    $this->form = new myForm(array('user' => $this->getUser()));
    
    // ...
  }
}

A typical unit test suite of the form would be:

 php
$t = new lime_test(2, new lime_output_color());

$user = new sfBasicSecurityUser(new sfEventDispatcher(), new sfSessionTestStorage(array(
  'session_path' => sys_get_temp_dir(),
)));

$form = new myForm(array('user' => $user));
$t->is(count($form->getWidgetSchema(), 2, '->configure() displays 2 fields when user is not authenticated'));
$user->setAuthenticated(true);
$user->addCredential('admin');
$t->is(count($form->getWidgetSchema(), 3, '->configure() displays 3 fields when user is authenticated and is an admin'));
// ... I'll let you complete the suite by yourself

Now imagine we want to filter the choices offered by a one to many relationship field of a Doctrine form regarding user credentials:

 php
class ArticleForm extends BaseArticleForm
{
  public function configure()
  {
    // will throw an exception if no user is available
    $user = $this->getOption('user', self::getValidUser());
    
    // ...
    
    // Category choices
    $categoryQuery = $this->getUserCategoryQuery($user);
    $this->widgetSchema['category_id'] = new sfWidgetFormDoctrineChoice(array(
      'model' => 'Category',
      'query' => $categoryQuery,
    ));
    $this->validatorSchema['community_id'] = new sfValidatorDoctrineChoice(array(
      'model' => 'Category',
      'query' => $categoryQuery,
    ));
  }
  
  /**
   * Please note that this method would naturally better fit in the model, in the 
   * ArticleTable class; We put this here for conciseness
   */
  protected function getUserCategoryQuery(sfBasicSecurityUser $user)
  {
    $query = Doctrine:getTable('Category')->createQuery('c');
    
    // If user is not an admin, only allow choice of published categories
    if (!$user->hasCredential('admin'))
    {
      $query->where('c.is_published = 1');
    }
    
    return $query;
  }
}

There are many more cool things you can achieve by offering user session access to a form, while keeping all the stuff easy to test.

As usual, if you have a better way, feel free to tell us about it in the comments.

lundi 25 janvier 2010

Bye, Flickr

Stop

In some hours, maybe days, my flickr account will be destroyed, and its content will be gone, definitely.

Looks like Flickr doesn’t allow "sales links" within photo description:

Flickr: no sales links allowed

That doesn’t fit my way of thinking my expensive hobby. I know, by putting links to redbubble I’m breaking the terms of service agreement, so I’m the culprit, and Flickr is safe.

Bye Flickr, after 5 years of paying my "pro" account fees, I’m a bit sad to leave the community, but I can’t stand paying for a service which doesn’t allow me to manage my stuff the way I want. Especially when some Interesting photos of the day, highlighted by Flickr itself in its explore RSS feed, are using the same kind of links, but are still there, safe.

Double standards? Not for me, thanks. Bye.

PS: When I’ll have a new dedicated self-hosted website, I’ll keep you informed here. In the meanwhile, feel free to reach me at redbubble.

Edit: Done, flickr account is gone. All the data it contained have been retrieved using the awesome photobackup utility, give it a go, even for backuping your flickr stream: it just works.

jeudi 7 janvier 2010

Polar Beer

Bruno Bord a eu l’excellente idée de proposer une chaîne littéraire autour du concept de ”polar geek”. J’avais une heure à tuer, en voici donc le modeste résultat.

Lire la suite...

vendredi 1 janvier 2010

Je vends mon Canon 450D + 18-55mm f/3.5-5.6 + 55/250mm f/3.5-5.6 + Sigma 30mm f/1.4

Edit : C’est tout vendu, désolé pour ceux qui tomberaient sur ce post après la bataille. J’ai finalement acheté un Canon 5D d’occasion nanti d’un zoom grand angle 20-35mmL de la marque, pour moins de la moitié du prix d’un 5D mark II neuf. Je ne suis qu’un amateur, et je me voyais pas finir à faire mariages ou photos de bébé pour payer le matos. Je reste donc libre de shooter ce que je veux, quand je veux, mais en full-frame ;)

***

Une fois n’est pas coutume, je vais profiter de ce blog pour vous souhaiter une bonne année passer une petite annonce[1]. Suite à une trop grosse acquisition, je vends une grosse partie de mon matériel photo actuel :

Le matériel est en excellent état. Maintenant, voila le prix que j’en demande :

  • Pour 690€, je vous cède le 450D, le 18-55mm, le 55-250mm et le Sigma 30mm ;
  • Pour 490€, je vous cède le 450D + 18-55mm + 55-250mm ;
  • Le Sigma 30mm seul est proposé à 290€.

Je n’ai pas très envie de vendre le 55-250mm hors pack, désolé… mais le pack complet est - je pense - proposé ici à un tarif très intéressant, même pour de l’occasion.

Habitant sur Montpellier, je préfèrerai bien évidemment une remise en main propre ; si je dois expédier le barda, les frais d’expédition seront en sus.

Si vous êtes intéressé, contactez-moi :)

Notes

[1] Bon allez, c’est bien parce que c’est vous : bonne année.

mercredi 16 décembre 2009

Symfony Development using Textmate

When I do consulting, a lot of people are really surprised that I use Texmate, a popular text editor for OS X, to develop on Symfony projects. Indeed, Textmate is a bit rough around the edge compared to bloated full featured IDE like Eclipse PDT or Netbeans, which are both Java based by the way.

So why using Textmate? No intelligent autocompletion, very basic project management, poor VCS native support, limited index search capabilities… First and while it’s mainly a matter of taste, I mainly use Texmate because it’s fast. Compared to PDT with which you often have to wait a bunch of seconds for the UI to respond on some action you make, mate will react quite instantaneously, and that is making big difference to me. Because when I’m concentrated, focused on some complex problem to solve, I demand my text editor to not make me wait [1].

Oppositely, not having full code introspection and autocompletion makes mate making me think about the code I write, instead of just consuming some API passively. I’ve been using phpeclipse and PDT for some years with Symfony, but I think I really began to understand the framework architecture when I switched to mate as my primary editor. Because every time you need to do something with the Symfony API, you have to open the file and read the code: then you learn a lot. And by the time, you end by knowing the core very well, and it’s incredibly efficient. One more time, this is just matter of taste.

Textmate quick tips

So whereas mate can be somewhat limited at first glance, a second look shows it provides some really effective commands to enhance your productivity. Let’s examine some of them.

Searching for a file within the project codebase

Just by pressing ⌘ + t, a snappy filename search window will pop up and allow you to search a file interactively by its name pattern. If you’re using the incredible Quicksilver app for osx, you got the picture.

interactive-filename-search.png

As Symfony names php files against the class name they contain, finding a class file is just easy as typing the class name in the search field!

Browsing the available functions, classes and methods within a php file

When a php file is opened, the ⌘ + shift + t command will show up the available sections of the document, with a search box you can use to filter their names, still interactively.

interactive-method-name-search.png

Note that this will also work for other file types (like CSS for instance).

Obtening help on native php functions

Move the carret onto some php native function and press ctrl + h and you’ll get the php.net related page in a pop up.

Want the function signature definition in a tooltip, like in PDT or Netbeans? Hit ⌥ + F1 and you’re done.

signature-tooltip.png

Using the mate command line utility

Textmate ships with a native command line interface executable called mate you can use from your term:

$ cd /path/to/project
$ mate .

You can also pipe some command to mate to open the output in it:

$ svn diff|mate

diff-mate.png

Taking part of Mate’s url-scheme capabilities with Symfony

I already blogged about this awesome feature available since Symfony 1.3, one more I won’t ever be able to live without.

Improve your productivity using bundles

The Ack in project bundle

One of the most annoying lack of mate is its internal search engine. It’s really damn slow. The best way to get something decent is to install the Ack in project bundle. You’ll then be able to access a fast and convenient fulltext search engine by pressing the ⌘ + shift + a command.

ack-in-project.png

The ProjectPlus bundle

If you’re looking after a better project browser and some VCS support in mate, you’ll love the ProjectPlus bundle. It will replace the default project drawer by a new one with finder label colors support, file sorting options and VCS icons integration. Give it a try, you won’t be able to live without it.

project-plus-drawer.png

The Symfony bundle

How could I write a blog post on Textmate and Symfony without mentioning the Symfony bundle? Denderello and contributors did a really good job taking over the original tool, which provides very convenient and effective shortcuts to write Symfony snippets of code quickly.

The GetBundle bundle

Last, if you didn’t find anything new or useful reading this blog entry, you might then be interested by installing the GetBundle bundle which will allow you to browse all available bundles and install any of them in one click!

GetBundle.png

Conclusion

So these are some of the reasons why I’m using Textmate when developing with Symfony (and other languages too). What are yours?

Notes

[1] You know the don’t make me think mantra? Well, now you got another one ;)

- page 1 de 73