Bonjour, je suis Vincent. Un développeur PHP.

Je développe sur Symfony2, Zend Framework, Magento. Je travaille actuellement chez Ekino.

FeedBundle : un bundle Symfony pour générer des flux RSS/Atom

05/08 2012
Je n'avais pas blogué depuis un petit moment, il était temps de vous tenir informé de mes actualités de développement.

J'ai récemment développé un bundle pour Symfony que j'ai nommé FeedBundle. Ce bundle va vous permettre de générer des flux RSS et/ou Atom à partir des données de vos entités et le tout de façon très simple.

Imaginons, par exemple, une entité Article qui regroupe les articles de votre blog. Il vous suffit d'implémenter une interface sur cette entité selon si vous souhaitez le composant Routing de Symfony pour générer les URLs de vos articles ou non.

ItemInterface : générer une URL via le composant Routing


namespace Bundle\BlogBundle\Entity;

use Eko\FeedBundle\Item\RoutedItemInterface;

/**
 * Bundle\BlogBundle\Entity\Article
 */
class Article implements RoutedItemInterface
{
    /**
     * Returns article route name
     * 
     * @return string
     */
    public function getFeedItemRouteName()
    {
        return 'blog_article_view';
    }

    /**
     * Returns article route parameters
     * 
     * @return array
     */
    public function getFeedItemRouteParameters()
    {
        return array('id' => $this->id);
    }
}

Dans ce cas, le bundle utilisera la route disposant de l'identifiant "blog_article_view" et lui passera l'identifiant de l'article.

Vous devez biensûr également implémenter les autres méthodes de l'interface, à savoir :

  • public function getItemFeedTitle() { . . . }
  • public function getItemFeedDescription() { . . . }
  • public function getItemFeedPubDate() { . . . }

RoutedItemInterface : générer une URL manuellement


namespace Bundle\BlogBundle\Entity;

use Eko\FeedBundle\Item\ItemInterface;

/**
 * Bundle\BlogBundle\Entity\Article
 */
class Article implements ItemInterface
{
    /**
     * Returns article URL link
     * 
     * @return array
     */
    public function getFeedItemLink()
    {
        return 'http://www.myblog.fr/article/' . $this->slug;
    }
}

Ajoutez la configuration de votre flux

Il vous faudra également fournir quelques informations sur votre flux dans votre fichier "app/config.yml" de la façon suivante :

eko_feed:
    feeds:
        article:
            title:       'Articles'
            description: 'Derniers articles du blog'
            link:        'http://vincent.composieux.fr'
            encoding:    'utf-8'
            author:      'Vincent Composieux' # Seulement requis pour les flux de type Atom

Le tour est joué, il ne nous reste plus qu'à ajouter nos entités à notre flux puis à l'afficher, depuis notre controlleur.

Générer le flux depuis le controller

Nous arrivons maintenant à l'étape crutialle : générer notre flux de type Atom ou RSS depuis un controlleur :

namespace Bundle\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class BlogController extends Controller
{
    /**
     * Generate the article feed
     *
     * @return Response XML Feed
     */
    public function feedAction()
    {
        $articles = $this->getDoctrine()->getRepository('BundleBlogBundle:Article')->findAll();

        $feed = $this->get('eko_feed.feed.manager')->get('article');
        $feed->addFromArray($articles);

        return new Response($feed->render('rss')); // ou 'atom'
    }
}

Il vous suffit donc d'appeler le service et d'y ajouter vos articles (entités) précédemment récupérés. Le bundle s'occupe ensuite de faire opérer la magie et d'afficher votre flux. Vous pouvez également ajouter des noeuds personnalisés supplémentaires à votre XML si vous le souhaitez.

Pour aller plus loin ?

Je vous invite à vous rendre sur le repository Github du bundle : http://www.github.com/eko/FeedBundle.

N'hésitez également pas à participer si vous souhaitez faire évoluer ce bundle et à m'envoyer des pull requests.

Découverte de Backbone.JS et Underscore.JS

02/05 2012
Parcequ'il est bon de se faire un peu la main sur toutes les différentes technologies web, j'ai décidé de m'entraîner un peu ce week-end à deux librairies : Backbone.JS et Underscore.JS.

J'ai ainsi développé une petite web-app (basée également sur jQuery Mobile pour l'interface mobile) du nom de Spoticheck (disponible sur mon compte Github) qui utilise ces deux librairies.

Backbone.JS se décrit ainsi :
Backbone.js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface.

En bref, Backbone.JS vous apporte une réelle structure quasiment comparable à l'architecture MVC, le tout en JavaScript.

Nous pouvons ainsi créer des modèles de données, ici, un exemple avec une classe "app.models.song" et 2 méthodes custom qui me permettent d'obtenir la liste des artistes sous forme de chaîne de caractères ainsi qu'une méthode getPopularity() qui me retourne la largeur de la barre de progression qui est affichée sur l'interface :


app.models.song = Backbone.Model.extend({
    barWidth: 200,

    getArtists: function () {
        var artists = Array();

        _(this.get('artists')).each(function (artist) {
            artists.push(artist.name);
        });

        return artists.join(' & ');
    },

    getPopularity: function () {
        return (this.get('popularity') * this.barWidth);
    }
});
Ces données du modèle peuvent ensuite être appelées très simplement. Ici par exemple, on envoie des données du modèlee au template, par l'intermédiaire d'une classe de vue (équivaut à un controller dans l'architecture MVC) :

app.views.entry = Backbone.View.extend({
    render: function () {
        $(this.el).append(
            _.template($('#entry').html(), {
                cid: this.model.cid,
                artists: this.model.getArtists(),
                track: this.model.get('track'),
                link: this.model.get('link'),
                listen: this.model.get('listen'),
                popularity: this.model.getPopularity()
            })
        );
    }
});
On notera également ici l'utilisation du framework Underscore.JS (objet _) sur lequel nous appelons la méthode template(). En effet, Underscore.JS est une librairie qui nous fournit principalement des méthodes qui peuvent s'avérer très utiles. Je vous invite à aller faire un tour sur la documentation de la librairie qui vous permettra d'obtenir la liste complète des méthodes disponibles.

Enfin, j'aimerais apporter une petite précision, si comme moi vous souhaitez utiliser jQuery Mobile et Backbone.JS (qui utilise la navigation via le hash d'URL) dans un même projet, il vous faut désactiver le fait que jQuery Mobile change les hash en URL concrètes en initialisant avant l'appel à la librairie JS de jQuery Mobile :

$(document).bind('mobileinit', function () {
    $.extend($.mobile, {
        pushStateEnabled: false,
        hashListeningEnabled: false
    });
});

PHP 5.4.0 stable est disponible : tour d'horizon des nouveautés !

01/03 2012
Et voilà, PHP 5.3.0 et ses namespaces et closures sont maintenant censés être rentrés dans les moeurs (je dis censé car beaucoup de projets, en entreprise notamment, n'osent pas migrer leurs applications ...). Depuis ce soir, la nouvelle version de PHP 5.4.0 est disponible, et au moment ou mon serveur dédié est en train de compiler, j'en profite pour vous faire un petit article sur les nouveautés apportées.  

1. Nouvelle syntaxe courte pour les tableaux (arrays) et deréférencement

Il est maintenant possible d'écrire un tableau PHP de ces deux façons :
$array = array('foo', 'foo' => 'bar');
ou
$array = ['foo', 'foo' => 'bar'];
De plus, dans le cas ou nous avons une méthode method() qui nous renvoie un tableau avec en indice 0 un objet, d'appeler directement une méthode sur l'objet, de la façon suivante : Pour plus d'informations sur ces deux nouveautés, voici les liens vers les RFC sur le wiki de PHP :

2. Petite amélioration des closures par rapport à PHP 5.3

En plus des closures déjà existentes depuis PHP 5.3, il est maintenant possible d'appeler une méthode de callback fournie directement par une autre méthode d'un objet en utilisant un array, de la façon suivante :

$callback = array($object, 'myMethod');
$callback();

3. L'arrivée des Traits va redonner un coup de jeune à votre code !

Je pense que c'est une des nouveautés qui va faire du bien dans la façon de développer. Vous allez en effet pouvoir écrire/définir des "Traits", sortes de structures, et les utiliser dans vos classes. À noter qu'une classe n'implémente pas un Trait, il l'utilise simplement (comme j'ai pu le lire : de façon horizontale, allez savoir pourquoi). Petit exemple illustré :
trait Price {
    public function getPrice() {
        return 20.00;
    }
}

class Vehicle {}

class Car extends Vehicle {
    use Price;
}

$myCar = new Car();
echo $myCar->getPrice(); // 20.00
J'attends d'utiliser cette nouveauté d'avantage pour vous faire un retour plus intéressant !

4. L'avancée des uploads en session via les formulaires

Et non, vous ne rêvez pas ! Il va maintenant être possible, en PHP, de connaître l'état d'avancement des uploads, et ce, de manière plutôt simple. Imaginez un formulaire HTML, avec comme attribut value="myuploadform" et en attribut name, la valeur PHP suivante :
ini_get("session.upload_progress.name");
Vous pourrez récupérer à tout moment la progression en session via cette clé :
$_SESSION["upload_progress_myuploadform"]

5. Un serveur HTTP compilé avec PHP

Vous allez en effet pouvoir lancer à tout moment un serveur HTTP avec PHP afin de tester rapidement vos développements. Pour ce faire, rien de plus simple, pour lancer un serveur web sur le port 8080, il suffit de taper dans votre terminal/console :
php -S localhost:8080
À noter que des options sont disponibles pour définir par exemple un document root personnalisé.

6. Et bien d'autres choses ont été modifiées

  • L'option d'activation des magic quotes a été supprimée,
  • La possibilité de désactiver les requêtes POST,
Bref, un tas de choses qu'il me reste encore à tester !

foREST - Framework léger d'API RESTful écrit en PHP 5.3

22/10 2011
Je vous présente aujourd'hui foREST, un petit framework d'API RESTful développé par mes soins durant quelques moments d'ennuis. Ce framework utilise les composants YAML et Console du framework Symfony2. Le projet est disponible sur Github, donc n'hésitez pas à participer. Il vous permettra de réaliser des requêtes de type REST (GET, POST, PUT, DELETE), de gérer des utilisateurs et des droits d'accès à certaines ressources ainsi que de gérer des paramètres de différents types (string, integer, ...) fournis dans vos requêtes.

Fichiers de configuration

Les fichiers de configuration utilisent le format YAML et j'ai utilisé le composant Symfony2 afin de parser le YAML dans ce projet. Vous pouvez définir des connections à plusieurs bases de données nommées dans le fichier config/databases.yml comme suit pour la base de données nommée "main" :

main:
  dsn: mysql:host=localhost;dbname=forest
  username: root
  password: root
Les utilisateurs et roles d'accès à votre API peuvent être gérés simplement grâce à l'implémentation du composant Console de Symfony2 : Pour ajouter un utilisateur, utilisez la commande :
php console user:add username password role
Pour supprimer un utilisateur :
php console user:del username
Enfin, il ne faut pas oublier de rafraîchir le fichier .htpasswd avec les nouvelles informations en tapant :
php console user:refresh

Créer une nouvelle ressource

Créer une ressource consiste à créer un répertoire du nom de votre ressource dans le répertoire "resources". Par exemple : "resources/Books" et de créer à l'intérieur les 3 fichiers suivants : routing.yml : contient les routes d'accès à vos API pour cette ressource. Elles sont définies sous la forme suivante :

"get:/books":
  description: "List all books by specified filters"
  resource: ForestResourcesBooks
  action: getBooks
  role: user
queries.yml : contient les requêtes en bases de données, identifiées par une clé comme suit dans cet exemple :

"my.book.query":
  database: main
  query: >
         SELECT * FROM books
Vous pouvez ensuite appeller cette requête dans vos différentes ressources avec :

        return $this->query('my.book.query');
Enfin, il ne vous reste plus qu'à créer la classe PHP de la ressource, qui doit comporter le même nom que le répertoire de la ressource, à savoir "Books.php" dans notre exemple. Ce fichier doit prendre la forme suivante :

/**
 * foREST - a simple RESTful PHP API
 * 
 * @version 1.0
 * @author Vincent Composieux - vincent.composieux@gmail.com
 */

namespace ForestResources;

use ForestCoreRequest,
    ForestCoreResource;

/**
 * Books
 */
class Books extends Resource {
    /**
     * List all books
     * 
     * @param Request $request
     * 
     * @return array
     */
    public function getBooks(Request $request) {
        return $this->query('my.book.query');
    }
Vous êtes maintenant prêt à utiliser l'API ! Je vous invite à me contacter si vous souhaitez plus de détails sur l'utilisation de l'API, des remarques ou encore participer sur Github.

Compiler PHP 5.4 sous Linux (Debian / Ubuntu)

09/07 2011
Interessons-nous un peu à la toute dernière release alpha de PHP et testons-la sur nos serveurs, quelle bonne idée ? Voici pour vous la procédure de compilation :

Préparation de l'installation / compilation

wget http://snaps.php.net/php5.4-latest.tar.gz
tar xzvf php5.4-latest.tar.gz
cd php5.4-XXXXXXXXX/
Ensuite, pour le bon déroulement de la compilation, et parce-que j'ai eu quelques surprises, assurez-vous de bien disposer des paquets "apache2-threaded-dev" et "libxml2" d'installés. Sinon :
apt-get install apache2-threaded-dev libxml2
C'est installé ? Ok, on y est, passons à la compilation !

Compilation !

Exécutez désormais les 3 méthodes "classiques" de compilation via ./configure, make et make install :
./configure --with-mysql=/usr/share/mysql  --with-pdo-mysql  --with-apxs2=/usr/bin/apxs2 --enable-xml --with-zlib
make
make install
Vous pouvez également effectuer un "make test" si vous souhaitez exécuter les quelques 8000+ tests unitaires contenus dans PHP.

Installation du module Apache

À ce niveau là, un "php -v" doit vous donner le résultat suivant :
composieux:~# php -v
PHP 5.4.0alpha2-dev (cli) (built: Jul  8 2011 13:10:31) 
Copyright (c) 1997-2011 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2011 Zend Technologies
Oui ? Parfait, copions donc notre extension PHP pour Apache afin de remplacer l'existante (en supposant que vous êtes toujours dans le répertoire) puis redémarrons Apache :
cp libs/libphp5.so /usr/lib/apache2/modules/
/etc/init.d/apache2 restart
Une petite page phpinfo(); sur votre serveur web afin de vérifier la version actuellement installée de PHP et celle-ci devrait être en 5.4.
« Voir les articles précédents