Tristan et moi avons publié il y a quelques temps des comportements Propel sous forme de plugins Symfony, tandis que l'ami NiKo en termine un qui, croyez-moi, n'est pas raté... Cependant, bien qu'ils soient très utiles, la documentation de Symfony demeure assez peu explicite au sujet du rôle des behaviors Propel, et de la manière de les développer.
Symfony propose un mécanisme, appelé "Behavior", qui permet l'extension de l'interface des objets générés par Propel, l'ORM par défaut du framework. En clair, ce mécanisme permet d'ajouter ou de redéfinir certaines méthodes des objets d'accès aux entrées de la base de données. En plus des accesseurs et modificateurs traditionnels, disponibles dans les BasePeer, un behavior permet donc de disposer de nouvelles méthodes, afin de répondre à des besoins fonctionnels précis.
Par exemple, le plugin sfPropelActAsNestedSetBehaviorPlugin (ouf !) ajoute un fonctionnement de Nested Set [1] aux objets Propel. Le plugin sfPropelActAsTaggableBehaviorPlugin (re-ouf !), lui, leur ajoute toutes les fonctionnalités de tagging dont vous aurez besoin si l'application que vous développez est bien Web 2.0-compliant (mais je ne m'engage pas pour le Web 3.0).
Ce qui est très intéressant, évidemment, c'est que ces comportements sont entièrement génériques, et ne dépendent a priori pas de la structure à laquelle on les applique. Ils constituent donc un moyen simple et réutilisable de rendre les éléments de votre modèle de données versionnables, commentables, notables, tagables, etc.
Les behaviors Propel profitent directement des fonctionnalités de réflexion [2] et de surcharge, introduites par PHP5.
Le mécanisme global de fonctionnement d'un behavior est le suivant :

__call du BasePeer;propel.ini, recherche d'un mixin convenableRien de bien magique, finalement, mais le résultat est cependant très pratique, puisqu'en quelques opérations il permet de disposer de nouvelles fonctionnalités au sein d'un développement.
Le développement d'un Behavior Propel au sein de Symfony suit exactement le modèle décrit dans le paragraphe précédent.
La déclaration du behavior, c'est-à-dire des hooks et des méthodes proposés par le behavior, se fait par le biais de la classe sfPropelBehavior, qui propose deux méthodes statiques pour cela : registerHooks, et registerMethods. Pour comprendre leur emploi, on peut prendre pour exemple le plugin sfPropelActAsTaggableBehaviorPlugin :
postSave doit être appelée après l'exécution de la méthode save :
sfPropelBehavior::registerHooks('sfPropelActAsTaggableBehavior', array (
':save:post' => array ('sfPropelActAsTaggableBehavior', 'postSave'),
));
registerMethods, sous la forme d'un simple tableau. Par exemple, ceci ajoutera les méthodes addTag et getTags aux classes qui adopteront le comportement sfPropelActAsTaggableBehavior :
sfPropelBehavior::registerMethods('sfPropelActAsTaggableBehavior', array (
array ('sfPropelActAsTaggableBehavior', 'addTag'),
array ('sfPropelActAsTaggableBehavior', 'getTags')
));
Le behavior proprement dit est constitué d'une classe qui implémente les méthodes enregistrées à l'étape précédente. Si on poursuit l'exemple précédent, la classe sfPropelActAsTaggableBehavior devra donc proposer une implémentation des méthodes addTag et getTags. Chacune de ces méthodes prend en premier paramètre un objet, qui correspond à une instance de la classe utilisant le behavior. Les autres paramètres de chaque méthode sont laissés à la discrétion du concepteur du plugin, et correspondent aux paramètres d'utilisation de chacune des méthodes ajoutées par le behavior. Ainsi, si on observe toujours le même plugin, le prototype de addTag est :
public function addTag(BaseObject $object, $tagname)
Et à l'utilisation, si par exemple "Post" est une classe ayant adopté le comportement :
$post = new Post();
$post->addTag('symfony, plugin, php5');