Damien Mathieu

Blog d’un développeur web

Mes résolutions pour 2009

janvier6

Alors bon, pour ceux qui auraient pas remarqué, on a changé d’année. Je vous épargnerais le billet “Ruby vs PHP : incrémenter un entier”.
Sinon, ça va partir en troll.
Par contre, on est déjà à 1/50e de l’année (environ). Alors il faut que je note mes résolutions maintenant avant que l’année ne soit finie quand même.

Comme tous les ans, j’en ai beaucoup. Alors je les ai triées en trois catégories.
Celles que je suis sur de tenir.
Celles que j’espère tenir.
Celles que je ne tiendrais de toute façon pas.

Celles que je suis sur de tenir

  • Finir l’API de Refstats ainsi que l’interface utilisateur
  • Obtenir la première place du classement Wikio général

Celles que j’espère tenir

  • Passer moins de temps devant ma machine et socialiser un peu plus
  • Me remettre à la natation
  • Trouver une nouvelle troupe de théâtre

Celles que je ne tiendrais pas

  • Battre mon record de longévité d’une relation amoureuse (1 mois)
  • Apporter la paix dans le monde

Et comme ça, c’est à peu près tout. Et bonne année.

posted under Personnel | 3 Comments »

Rails : send_data et send_file

janvier5

Si vous avez déjà tenté de permettre à vos utilisateurs de télécharger des images, zip ou autres documents binaires via votre application rails, vous vous êtes probablement confronté au problème suivant :

Vous affichez le contenu de votre document assez simplement :
render :file => '/path/vers/le/fichier'
Avec le headers['Content-Type'] approprié.

Cependant dans le cas de gros fichiers (pas si gros que cela d’ailleurs), vous constaterez que celui-ci est rarement rendu en entier.
Dans le cas de fichiers binaires, c’est plutôt génant car celui-ci se retrouve corrompu et donc inutilisable.

Mais c’est là qu’arrive le rendu en streaming, avec send_data et send_file.

send_data 'le contenu', :filename => 'monfichier'
send_file '/path/vers/le/fichier', :type => 'image/png'

Le contenu de votre document est rendu en entier et récupérable par l’utilisateur :)
Vous pouvez également lire la documentation, plus détaillée, de ActionController::Streaming.

posted under Rails, Ruby | No Comments »

Rails vs CakePHP vs Symfony : mettre à jour un attribut d’un uplet

janvier2

Supposons le cas suivant : un utilisateur dans une base de données avec le champ “active” à false. Vous désirez activer l’utilisateur en passant la valeur de ce champ à true.

Comparaisons entre CakePHP, Symfony et Rails.

Rails
User.find(1).update_attribute(:active, true)

CakePHP
$user = $this->User->findById(1);
$user['User']['active'] = true
$this->User->save($user);

Symfony
$user = UserPeer::retrieveByPk(1);
$user->setActive(true);
$user->save();

Encore une fois, peu de commentaires à faire. Le code parle de lui même.

posted under PHP, Rails | 12 Comments »

Ruby vs PHP : récupération d’une date antérieure

décembre26

Second article de la série Ruby vs PHP.
Qui est en fait Rails vs PHP. Oui, je triche en comparant un framework à un langage je sais :)

Comment récupérer une date antérieure à la date actuelle. Nous prendrons pour exemple la récupération de la date il y a de cela 3 jours.

Rails :
puts 3.day.ago

PHP :
echo date('d-m-Y', date('U') - 259200);

Il est, je pense, inutile de faire un quelconque commentaire/conclusion. :-)

Merb et Rails ne feront plus qu’un : Rails 3

décembre23

Il s’agit du cadeau de noël que nous font les équipes de développement de Rails et de Merb : les deux principaux frameworks open source écrits en Ruby ne vont faire plus qu’un bientôt, lors de la sortie de Rails 3.
L’annonce officiel : Merb gets merged into Rails 3 !

Comme dirait Barney, c’est awesome ! Deux frameworks ayant chacun leurs avantages et leurs inconvénients mergant les uns avec les autres afin de s’améliorer encore plus chacun.

Ceci tout en précisant qu’il ne s’agit pas d’une réecriture totale du framework. Cela serait idiot à ce niveau.
Les bases utilisées seront apparemment celles de Rails. Les projets Merb quant à eux, migreront vers ce premier.

Et même une timeline est donnée, malgré le fait qu’il est bien précisé que celle-ci n’est absolument pas sure, il s’agit seulement d’espérances.
Rails 3 devrait donc voir théoriquement sa première version beta pour le RailsConf 2009 à Las Vegas.

Un seul commentaire (en fait, non, deux) : Rails 3 va roxer :)
Le second, c’est : joyeux noël.

posted under Rails, Ruby | 3 Comments »

Ruby vs PHP : compter le nombre de mots dans un texte

décembre19

Ceci est le premier article d’une série de comparaison entre PHP et Ruby.

Compter le nombre de mots dans un texte est plus complexe que cela ne le parait au premier abord. En effet, un espace ne symbolise pas forcément un mot. Cela peut être un point d’exclamation (!); un nombre ou tout autre.

Ici, nous allons donc prendre la définition suivante pour “mot” :
Suite de caractères comprenant au moins un caractère alphabétique.

En d’autres termes : toute suite de caractères qui comprends au moins une letttre de l’alphabet.

Comptons donc maintenant nos mots en Ruby.

class String
def nb_words
self.split(' ').select { |word| word.is_word? }.size
end
def is_word?
self.gsub /([a-z]+)/
end
end

Pour compter le nombre de mots dans une chaine de caractères, il suffit alors de faire :
puts "ma chaine ! super non ?".nb_words

Qui devrait alors retourner 4 et non pas 6 car “!” et “?” ne sont pas des mots.

Faisons maintenant la même chose en PHP, même si je ne vous le conseille pas. En effet, PHP 5.3 implémentera une fonction permettant de faire cela en natif.
function nb_words($string) {
$nb = 0;
$string = explode(' ', $string);
foreach($string as $word) {
if (preg_match('([a-z]+)’, $word)) $nb++;
}
return $nb;
}

A utiliser de la manière suivante :
echo nb_words('ma chaine ! super non ?');

Symfony : identifier les utilisateurs

décembre15

Cet article reprends les principes expliqués dans l’article du Jobeet Symfony du 13 décembre.
Simplement cet article est un petit peu “chatty” et j’ai voulu représenter les fondamentaux de son contenu de manière plus synthétique.

Dans le dossier lib de votre application symfony (apps/<votre application>/lib), vous verrez un fichier myUser.class.php.
Celui-ci est instancié lors de chaque chargement de page et vous permet d’identifier l’utilisateur actif et de gérer sa session.

Ainsi, pour ajouter et lire une variable de session dans le contrôleur :
$this->getUser()->setAttribute('myVar', 'moncontenu');
$this->getUser()->getAttribute('myVar');

Et dans la vue :
$sf_user->setAttribute('myVar', 'moncontenu');
$sf_user->getAttribute('myVar');

Jusque la, aucune difficulté. Mais cet objet va beaucoup plus loin. En effet, vous pouvez forcer quelqu’un à s’identifier pour accéder à un module particulier. Dans le fichier apps/<votre application>/config/security.yml, placez le code suivant :
default:
is_secure: on

Et pour identifier notre utilisateur automatiquement quelque soit le contrôleur, remplissons notre fichier myUser.class.php :
class myUser extends sfBasicSecurityUser {
function __construct($arg, $arg2) {
parent::__construct($arg, $arg2);
if (!$this->isAuthenticated())
$this->setAuthenticated(true);
}
}

Ici, nous identifions l’utilisateur quoi qu’il arrive. Mais bien évidemment, il en revient à vous de ne faire cela que lorsque cela est nécessaire. Dans mon cas, je vérifie l’identité de l’utilisateur avec un appel à l’API JSON de RefStats (en développement). Mais vous pouvez utiliser un modèle pour faire cela.

Pour finir, simplement identifier un utilisateur ne suffit pas toujours. Il peut arriver que vous ayez besoin de gérer divers niveaux d’identification. Symfony permet, pour cela, de gérer des “groupes”, appellés credentials.

Dans votre fichier security.yml, placez :
default:
is_secure: on
credentials: admin

Seuls les utilisateurs ayant le credential admin pourront accéder à la page. Puis pour attribuer ce credential à l’utilisateur courant :
$this->getUser()->addCredential('admin');

Et vous pouvez vérifier directement dans votre application que l’utilisateur a bien le credential demandé :
$this->getUser()->hasCredential('admin');

Pour plusde détails sur tout cela, je ne peux que vous inviter à lire l’article “The User” du Jobeet.
Mais celui-ci peut déjà, je l’espère, vous renseigner sur l’utilité de myUser.class.php et une des manières de l’utiliser.

posted under PHP | 7 Comments »

Configurer Symfony 1.2 pour MySQL

décembre8

Ayant, en ce moment, un peu de temps pour cela, j’en profite pour regarder un petit peu à quoi ressemble Symfony.
Je ferai donc probablement quelques articles à ce propos ici dans les jours à venir.

Si vous lisez cette documentation, vous constaterez qu’ils indiquent de placer le “dsn” suivant dans votre configuration :
mysql://root:pass@localhost/database

Cependant la nouvelle version de Propel force une légère modification de cette configuration. Il nous faut donc modifier le “dsn” en :
mysql:dbname=database;host=localhost

Tous les autres paramètres peuvent être conservé de manière similaire.
Cependant, si vous n’avez pas une application “from scratch”, vous devez, pour mettre à jour depuis la 1.1, suivez les conseils de mise à jour donnés sur cette page.

posted under PHP | 3 Comments »

Rails : tester l’envoi de fichier

novembre27

Rails ça rox ! Mais comme pour tout, il faut correctement l’utiliser.
Et pour cela, il faut faire des test. Pas manuels, mais automatiques. Je vous laisse découvrir cela.

Cependant il y a certaines choses qui ne sont pas forcément pratiques à tester, tel que l’envoi d’un fichier.
Vous avez besoin d’un objet spécial toussa. Pas bien difficile dans l’idée. Mais tellement chiant pour un bon fainéant comme moi ;-)

Si vous avez lu l’article donné plus haut, vous avez vu la page “Testing Files Upload” qui, fonctionne bien.
Ou presque, malheureusement.
En effet l’attribut content_type est, dans “la vraie vie”, modifiable. Et ici, il est disponible uniquement en lecture. C’est bête, ça fait planter votre test alors que l’application fonctionne bien.

Mais il y a une solution heureusement ! La voici :)
En cherchant un peu, j’ai découvert que Rails propose une méthode permettant de tester l’envoi de fichier, méthode qui est disponible en interne.

ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + 'myfile.jpeg', content_type)

Ok, cool. Si vous testez cela déjà, vous constaterez que vous avez correctement votre objet pour tester le fichier envoyé. Super !
Seulement vous ne pouvez toujours pas modifier la valeur de content_type. Alors que l’objet retourné par un vrai fichier envoyé le permet.

Allons donc un petit peu hacker Rails.
Ouvrez le fichier RUBY_PATH/gems/1.8/actionpack-2.0.2/action_controller/test_process.rb

Puis cherchez la déclaration de la class TestUploadedFile
La, vous verrez la ligne suivante :
attr_reader :content_type

Nous avons donc l’attribut content_type en lecture. Passons le en lecture-écriture :
attr_accessor :content_type

Et hop ! Vous pouvez maintenant tester votre envoi de fichier tout en modifiant le content_type :)
Et moi dès que j’aurai trouvé un client GIT potable sous Windows, je pourrais proposer le hack à l’équipe de développement de Rails.

[Edit : Après avoir récupéré la dernière nightly build de Rails, le bug du attr_accessor a été corrigé. Si vous avez la dernière version de Rails, il n'est donc pas utile de faire cela]

posted under Rails | 3 Comments »

Zend Framework en MVC : charger les modèles proprement

novembre25

Ceux qui me connaissent le savent : je fait beaucoup de critiques sur le Zend Framework n’aimant pas vraiment les mauvaises habitudes de développement qu’il permet de prendre et les répétitions inutiles de code qu’il incite.
Je suis un fort partisan du DNRY (Do Not Repeat Yourself) et je ne m’en cache pas.

Cependant il est plus facile de vendre du Zend Framework qu’un autre framework que je ne nommerais pas mais qui a une équipe de développement non réactive et qui semble se reposer sur ses lauriers.
Alors je m’adapte et je tente de faire des trucs propres avec Zend Framework.
Et c’est faisable !!!

L’un des gros problèmes que je donnais au framework est le fait qu’il n’y a aucun chargeur automatique des modèles lorsque l’on utilise le framework en mode MVC. Il nous fallait donc faire quelque chose comme :

require_once APPLICATION_PATH . '/models/Users.php';
$this->Users = new Users();

Et ce dans chacun de nos contrôleurs qui utilise ce modèle. Pas cool.

Avoir quelque chose comme cela lors de la déclaration du contrôleur serait plus joli :
var $uses = array('Users');

Alors implémentons-le !
Tout d’abord, il nous faut déclarer ce que j’appelle un AppControlleur.
Il s’agit d’un contrôleur qui n’est jamais appellé seul. Il étends Zend_Controller_Action.

Chacun de nos contrôleurs étendra cet AppController. Ainsi, toute méthode présente dans celui-ci le sera dans le notre.

Donc, créons notre fichier dans le répertoire “application” de celle-ci. Nommons le AppController.php

Voici son contenu :
class AppController extends Zend_Controller_Action {
}

Puis il faut que nous inclusions notre AppController dans l’application. Dans bootstrap.php, après avoir défini la constante APPLICATION_PATH, placez :
include(APPLICATION_PATH . '/AppController.php');

Puis déclarez vos contrôleurs habituels de la manière suivante :
class MonController extends AppController

Voila, rechargez votre page. Si vous n’avez pas d’erreur, votre AppController est correctement chargé.
Super me direz-vous ! Mais ou ça m’amène ?

Eh bien maintenant, vous pouvez définir une méthode qui sera exécutée automatiquement à chaque chargement de page et qui chargera tous les modèles dont vous avez besoin.

Soyons fous, mettons à jour notre AppController :
class AppController extends Zend_Controller_Action {
function __construct($param, $param2) {
parent::__construct($param, $param2);
if (isset($this->uses))
foreach($this->uses as $model) {
if (file_exists(APPLICATION_PATH . '/models/'.$model.'.php'))
require_once APPLICATION_PATH . '/models/'.$model.'.php';
else
throw new Exception('Can\'t load model '.$model.' Please create the file \''.APPLICATION_PATH . '/models/'.$model.'.php\'');
if (class_exists($model))
$this->{$model} = new $model();
else
throw new Exception(APPLICATION_PATH . '/models/'.$model.'.php was supposed to declare class \''.$model.'\'');
}
}
}

Et voila ! Que faisons-nous ? Dans la méthode __construct, nous regardons si la variable de classe $uses est définie. Si c’est le cas, nous parcourons le tableau.
Pour chacun des éléments, nous vérifions si le modèle existe et nous le chargeons.

Puis nous vérifions si la class du bon nom existe et nous l’initialisons.

Et vous pouvez maintenant instancier tous les modèles de votre choix en une seule ligne de code dans chacun de vos contrôleurs.

posted under PHP | 12 Comments »
« Older Entries

Rss Feeds

En Français
In English