propelorm/Propel2 — pull request #511 by gossi (2014-01-08 03:01:39+00:00)
Title: Install Behaviors with Composer

This let's you install behaviors with composer. I thought it's not that much to do, to implement this. This is all more a proof-of-concept and RFC than a final implementation. However, let me explain.

### What a Behavior Author needs to do
All the dev needs to do is polish his composer.json a little bit.
1. Set type to "propel-behavior"
2. Add propel extra package
3. Set name and class for his behavior

Example:
```json
{
"name" : "gossi/propel-l10n-behavior",
"type" : "propel-behavior",
"extra": {
"propel": {
"name": "l10n",
"class": "\\gossi\\propel\\behavior\\l10n\\L10nBehavior"
}
}
}
```

- The `class` must extend the `Propel\Generator\Model\Behavior` class (oh, btw. there is no check for that).
- The `name` is used in the schema as behavior name (``)

That's it.

### How that works
When composer installs its dependencies, a composer.lock file is created, containing all packages, including their composer.json file contents. This file is scanned, all packages with the `propel-behavior` type are searched and stored in a lookup map. When a behavior is requested, the name is looked up in the map and the class name gets returned.

### Alternative Solution
An alternative solution would be, to create a propel-behavior-installer. It can potentially install behaviors in other locations than the vendor dir, such as the propel behavior folder in the generator namespace and thus loaded from there. This would require a behavior author to mimic a certain folder structure, that the already present behavior loader can find the behavior, which I think is not gonna happen.
Additionally the installer must somehow keep a storage with the installed behaviors (maybe a simple json file). This file must be consumed by propel to read all the available behaviors. Given that propel is installed as package itself, it has no "config" folder itself hence when upgrading it is unsure wether files stay in the propel vendor dir, despite the fact propel can be deleted and reinstalled and loose all its files. The dilemma can be handled with event handlers; even if possible, this is not funny at all (or somehow get some persistent configuration storage).
Last but not least, behavior devs need to include another (require) statement in their composer.json.

composer.lock is a nice and always present storage (even if deleted, the user can easily hinted to run composer update) and the code to handle this is much smaller, which also makes him less error prone plus offers more flexibility to the behavior dev.
(A side note: we use the composer.lock to automatically manage the build path in the eclipse composer plugin and has been proven as a reliable resource).

### Further Considerations
I just had a quick shot at the propel source code, as such I do not know much of its characteristics and for a quick'n'dirty hack a singleton instance for the ComposerFinder sounds ok to me. If propel has a concept for such things, even better. Also I assumed the `extra.propel` path in the composer.json (can also be `extra`). So rethink this location (API) here. I have not implemented any error messages yet (this also includes what happens when no composer.lock is found, maybe requires another cli option to specify the location).

gossi