How to manage behaviors? #188

willdurand opened this Issue Apr 23, 2012 · 33 comments


None yet
Propel member

@vworldat: behaviors are the incarnation of pure awesomeness


We need to find a way to auto-wire Propel behaviors at buildtime.
Each behavior should have a name like timestampable, geocodable, etc.
In the mapping definition (schema.xml), we just declare it using the following XML tag:

<behavior name="timestampable" />

That's cool for "core" behaviors, but for third-party behaviors like geocodable, we need to wire the behavior's name with the class. In the plain old Propel 1.6, we rely on a file which owns a behaviors section:

// ...
timestampable.class = My\TimestampableBehavior

By reading this file, the generator knows where to find, and how to load the right class for a given behavior.
This file doesn't exist anymore in Propel2, so we are looking for a new, and better solution. That's the aim of this issue.


  • Install Propel
  • Define a mapping (schema.xml)
  • Install a new behavior, let's say "geocodable", not part of the Propel2 core
  • Add this behavior to the mapping by using the <behavior /> tag
  • Generate classes (the generator has to load the right class for "geocodable")

So the question is how to dynamically map a name (string), and a class name?



We still need to figure out how to pass information to the generator.



<register_behavior name="taggable" class="Full\Namespace\Taggable.php" />

The generator has all information to use the behavior.

External file

a declare-beahavior statement in an external file

Back to Propel 1.6.

What's next?

Find the best way to easily register behaviors.


Is there a way to tell Propel 2, like in a configuration file, where to search for behavior?

In this way we just need to tell Propel 2 where to search where a behavior is used in a mapping file.


The advantage of the XML Tag approach is that you map the name to the class yourself, meaning you can more easily extend and also resolve conflicts if two behaviors have the same name (though it's unlikely one would use both at the same time, but who knows).


The composer custom installer would be awesome. But you will end up being dependent to composer.

IMO the composer installer should write a file that is writable by hand.

Propel member



In this way when we want to use a behavior we can do like this:

<behavior name="taggable" class="Full\Namespace\Taggable.php" />

Just one place to tell Propel where to find the behavior class.

Propel member

Also, XML should be only one way to define a schema. You should focus on how to make that using the object-oriented model, and then see how an XML mapping could do that.

Propel member

@maxailloud at the moment, there is no more configuration file. It could appear later, but it was a pain to have all these files, so we dropped them.

@GromNaN yep, that's my opinion too.

@fzaninotto thanks to namespaces, it will make names really long:

My\Super\SuperBehavior => my_super_super_behavior // or my_super_super if we use a convention

XML here is just a way to define mapping. We are working on that to make it more XML independent, so we will be able to support other "formats" (yml, php, ...)

Propel member

@couac: non I meant tag style, not attributes. Your example mixes both CamelCase and underscore tags.

Propel member

@maxailloud I like this declaration but we can't declare this statement using a script for instance.

@fzaninotto ah, it doesn't matter. (edited)


I don't really understand. Can you explain why we can't do like this?

Propel member

I don't really know the source code and I can't image the constraints but what about a behavior:register command or something like this ? We pass options to the command like the name and the class and the BehaviorRegisterCommand.php file does the stuff it requires. If it's too hard to implement, why not define behavior in the schema.xml file. It's not really logical but it's a solution.


What about defining a special folder for 3rd party behaviors and let the generator search the behavior within that folder?
IMHO that would really be "auto-wiring" like your tweet says, @willdurand


I agree.
A directory like "Behavior" (such a surprise) wherever we want, like in bundles or even in vendor maybe I don't know.

Propel member

Imho we should use the following convention (over configuration):

  • MyWonderful behavior must be a class called MyWonderfulBehavior
  • this class must be in Propel\Generator\Behavior\MyWonderful namespace

If we use this convention, third-part behaviors already work correctly, without any other effort, and in our schema we can write simply:
<behavior name="mywonderful" />

Propel member

@cristianoc72 makes sense, you're right. But third party bundles should not use the Propel\... namespace I guess.

Propel member

@robin850 a command can't do that, except if it writes sometime in a file, which makes no sens because a script could do that without any problem. The question is, how to do that without relying on a file?

@maxailloud because you don't know anything about your schema at this time. And, a script can't/shouldn't modify your mapping.

Well, I like the idea of this directory. We could do something like Symfony2 does with commands. It browses the whole project to find Command/ directories, and uses reflection to ensure classes are real commands.

What about doing the same? We could define the Behavior/ directory, and a BehaviorInterface? The last thing is to be able to give the root directory of our project to Propel..


I was thinking about the same solution, so I'm agree with that.

Propel member

We could use the autoload feature of composer. It can load a file as bootstrap.

# composer.json
    "autoload": {
        "psr-0": { "MyLibrary": "src/" },
        "files": ["src/bootstrap.php"]

The bootstrap file can register the behavior statically into Propel.

# my_library/src/bootstrap.php
Propel::registerBehavior('timestampable', 'MyLibrary\TimestampableBehavior');
Propel member

We don't use the Propel class at build time, it's part of the runtime. And I'd like to get rid of all these static calls.
I don't think Composer will be an issue there, it's flexible enough.


+1 for schema, I'm unsure Propel should depend on Composer. But, I'd prefer the class name, not class="Full\Namespace\Taggable.php" (.php).


I don't know if there is any progress on that. But why not using the service container ?

You can provide a BehaviorListener with a BehaviorFactory (if you want to use 2 behavior with same configuration without duplicating the same configuration at each model class).

You will have to register with php when only using propel, but for symfony2 you can just provide a tag to register the behavior.

The name in the xml will correspond to the service container id

Propel member

@Brouznouf behaviors have to be registered at buildtime, and the service container is used at runtime.


Hi there,

I like that discussion. It's about finding an interface for behavior authors? I just want to give a different point of view. The view from a behavior author. So what I'd wish to do:

I'd like to have my behavior hosted on github. Writing my behavior on top of composer. So every dependencies I need (like classes that needs to be extended), I can pull in using composer. Travis to run my tests. I would like to distribute my behavior to packagist, maybe as "propel-behavior" type? Would make sense to me. Or distribute it as zip or phar.

On the end-user side (like this is what I need to document then) a composer include may be sufficient or extract the zip rsp. move the phar to your "classpath". Include a line in your schema? config? to point to the new behavior. Use it.

Take it as a user-story. Are you talking about behavior generator and/or runtimes? Sorry, if that drives that discussion in a wrong direction, then just ignore my ignorance.

I have worked a little with ant, they have the <taskdef> tag. Similar to the <behavior> and <behavior_registers> tags here. I like them.

Here are my ideas for that

Idea 1:

If My\Behavior is in "classpath":
<behavior name="mybehavior" class="my\Behavior"/>

If not:
<behavior name="mybehavior" class="my\Behavior" path="path/to/my"/>

Idea 2:

<behavior class="my\Behavior">

// path param from idea 1 applies here, too.


namespace my;
class Behavior extends propel\... {
    const name = "mybehavior"
    // ...

In both cases, I'd use my behavior like that in the schema.xml:

<mybehavior ... >

Hope this gives some more input.

Best regards

Propel member

So, whats the decision now here? The current implementation is:

if (false !== strpos($behavior, '\\')) {
    $class = $behavior;
} else {
    $generator = new PhpNameGenerator();
    $phpName = $generator->generateName(array($behavior, PhpNameGenerator::CONV_METHOD_PHPNAME));
    $class = sprintf('\\Propel\\Generator\\Behavior\\%s\\%sBehavior', $phpName, $phpName);

and I pretty like the way it works now. I don't see a advantage when we can define a 'short name' for external behaviours. One with the name/cass 'Vendor\XyBehavior' is for me actual ok and it's unambiguous.

<behavior class="Vendor\XyBehaviour" />
Propel member

@willdurand, you wrote This file [] doesn't exist anymore in Propel2,so we are looking fora new, and
better solution
. But

$ grep '' * -rin | wc -l

So, I think this sentence is obsolete?

Propel member

Nope, but the file isn't entirely removed yet..

Propel member

Will there be a replacement for all these options?

Propel member

I don't know, but we should probably reduce the list of options.

Propel member

This properties file is quite handy and I've really no idea how to replace all those hundreds of options. In my opinion we should keep this file and use in all commands a call like ModelBuildCommand it has:

$generatorConfig = new GeneratorConfig(array_merge(array(
    'propel.platform.class'                     => $input->getOption('platform'),
), $this->getBuildProperties($input->getOption('input-dir') . '/')));

The current issue without this file in MigrationDiff is that overriten properties like enable-package-object-model (propel.packageObjectModel) are not used and thus the command fails with split schema files.

Propel member

The comment above has been merged into master: #378.

Propel member

this is not really blocking, so I postpone it to beta

Propel member

Ok, let's forget this.

@willdurand willdurand closed this Sep 30, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment