= sfPropelAlternativeSchemaPlugin - Extension to the Propel schema syntax = == Overview == This plugin extends the symfony model generator, based on Propel, to allow a schema to override another one. It also provides a new YAML syntax for defining database schemas, more explicit and more readable. This new syntax is completely backward compatible with symfony's current `schema.yml` syntax, so installing this plugin will not break your applications. == Installation == To install the plugin for a symfony project, the usual process is to use the symfony command line: {{{ $ php symfony plugin-install http://plugins.symfony-project.com/sfPropelAlternativeSchemaPlugin }}} Alternatively, if you don't have PEAR installed, you can download the latest package attached to this plugin's wiki page and extract it under your project's `plugins/` directory. Clear the cache to enable the autoloading to find the new classes: {{{ $ php symfony cc }}} That's it, you are ready to write schemas with the new syntax and override existing schemas. == New schema syntax == As an alternative to the current `schema.yml` syntax (which still works), this plugin proposes a new way to define a database schema. Consider the following schema, using the current syntax: {{{ propel: _attributes: { noXsd: false, defaultIdMethod: none, package: lib.model } ab_group: _attributes: { phpName: Group, package: foo.bar.lib.model } id: name: varchar(50) cd_user: _attributes: { phpName: User, isI18N: true, i18nTable: cd_user_i18n } first_name: { type: varchar, size: 255, default: "Anonymous" } last_name: varchar(50) age: { type: integer, required: true, index: true } ab_group_id: created_at: cd_user_i18n: description: longvarchar ef_article: title: { type: longvarchar, required: true, index: unique } stripped_title: { type: longvarchar, required: true, primaryKey: true, sequence: my_custom_sequence_name } user_id: my_group: { type: integer, foreignTable: ab_group, foreignReference: id, onDelete: setnull } created_at: timestamp updated_at: ij_article: _attributes: { phpName: Article } title: varchar(50) user_id: { type: integer } _foreignKeys: - foreignTable: cd_user onDelete: cascade references: - { local: user_id, foreign: id } created_at: _indexes: my_index: [title, user_id] _uniques: my_other_index: [created_at] ab_group_i18n: motto: longvarchar }}} With the new syntax, you can write it as follows: {{{ connection: propel noXsd: false defaultIdMethod: none package: lib.model classes: Group: tableName: ab_group package: foo.bar.lib.model columns: id: name: varchar(50) User: tableName: cd_user isI18N: true i18nTable: cd_user_i18n columns: first_name: { type: varchar, size: 255, default: "Anonymous" } last_name: varchar(50) age: { type: integer, required: true, index: true } ab_group_id: created_at: CdUserI18n: columns: description: longvarchar EfArticle: columns: title: { type: longvarchar, required: true, index: unique } stripped_title: { type: longvarchar, required: true, primaryKey: true, sequence: my_custom_sequence_name } user_id: my_group: { type: integer, foreignTable: ab_group, foreignReference: id, onDelete: setnull } created_at: timestamp updated_at: Article: tableName: ij_article columns: title: varchar(50) user_id: { type: integer } created_at: foreignKeys: - foreignTable: cd_user onDelete: cascade references: - { local: user_id, foreign: id } indexes: my_index: [title, user_id] uniques: my_other_index: [created_at] AbGroupI18n: columns: motto: longvarchar }}} The main difference is that you declare classes, not tables, using the table `phpName` as a key. If you don't define a `tableName`, the plugin will determine one automatically based on the `phpName` using `sfInflector::underscore()`. This syntax is also more explicit, since you must create entries for `classes` and `columns`. But it gets rid of the ugly `_attributes` hack of the current syntax. The `connection` parameter is optional. If it is not set, it will take `propel` as a default value. Last but not least, all the 'magic' of the current syntax is still there (auto definition of primary keys, foreign keys, i18n tables, etc.). Once you have defined such a schema, rebuild the model as usual: {{{ $ php symfony propel-build-model }}} == Customizing an existing schema == Schemas using this new syntax can be customized by other schemas. This is great for plugin schemas, for instance, to allow users to override some of the plugin's schema settings (such as the connection, the table names, etc). When dealing with a schema with the alternative syntax, the symfony builder will look for custom YAML files for this schema, following this rule: Original schema name | Custom schema name -----------------------------------------|------------------------ config/schema.yml | schema.custom.yml config/foobar_schema.yml | foobar_schema.custom.yml plugins/myPlugin/config/schema.yml | myPlugin_schema.custom.yml plugins/myPlugin/config/foo_schema.yml | myPlugin_foo_schema.custom.yml Custom schemas will be looked for in the application's and plugins' `config/` directories, so a plugin can override another plugin's schema. Custom schemas must respect the same alternative syntax. The plugin will simply merge the two schemas, as follows: {{{ # Original schema ################# classes: User: tableName: cd_user columns: first_name: { type: varchar, size: 255, default: "Anonymous" } last_name: varchar(50) age: { type: integer, required: true, index: true } created_at: Article: tableName: ij_article columns: title: varchar(50) user_id: { type: integer } created_at: foreignKeys: - foreignTable: cd_user onDelete: cascade references: - { local: user_id, foreign: id } # Custom schema ############### connection: myConnection classes: Group: tableName: ab_group package: foo.bar.lib.model columns: id: name: varchar(50) User: tableName: ef_user isI18N: true i18nTable: cd_user_i18n columns: ab_group_id: Article: columns: updated_at: # Resulting schema ################## connection: myConnection classes: Group: tableName: ab_group package: foo.bar.lib.model columns: id: name: varchar(50) User: tableName: cd_user isI18N: true i18nTable: cd_user_i18n columns: first_name: { type: varchar, size: 255, default: "Anonymous" } last_name: varchar(50) age: { type: integer, required: true, index: true } ab_group_id: created_at: Article: tableName: ij_article columns: title: varchar(50) user_id: { type: integer } created_at: updated_at: foreignKeys: - foreignTable: cd_user onDelete: cascade references: - { local: user_id, foreign: id } }}} == TODO == * Manage behaviors directly in the schema == Changelog == === 2007-10-05 | 0.9.0 Beta === * francois: initial release