++ Introduction

The purpose of schema files is to allow you to manage your model definitions directly from a yaml 
file rather then editing php code. The yaml schema file is parsed and used to generate all your 
model definitions/classes. This makes Doctrine model definitions much more portable.

Schema files support all the normal things you would write with manual php code. Component to 
connection binding, relationships, attributes, templates/behaviors, indexes, etc.

++ Short Hand Syntax

Doctrine offers the ability to specify schema in a short hand syntax. A lot of the schema parameters 
have values they default to, this allows us to abbreviate the syntax and let Doctrine just use its 
defaults. Below is an example of schema taking advantage of all the shorthand features.

<code type="yaml">
---
detect_relations: true

User:
  columns:
    username: string
    password: string
    contact_id: integer

Contact:
  columns:
    first_name: string
    last_name: string
    phone: string
    email: string
    address: string
</code>

++ Expanded Syntax

Here is the none short hand form of the above schema.

<code type="yaml">
---
detect_relations: true

User:
  columns:
    username:
      type: string(255)
    password:
      type: string(255)
    contact_id:
      type: integer
  relations:
    Contact:
      class: Contact
      local: contact_id
      foreign: id
      foreignAlias: User
      foreignType: one
      type: one

Contact:
  columns:
    first_name:
      type: string(255)
    last_name:
      type: string(255)
    phone:
      type: string(255)
    email:
      type: string(255)
    address:
      type: string(255)
  relations:
    User:
      class: User
      local: id
      foreign: contact_id
      foreignAlias: Contact
      foreignType: one
      type: one
</code>

++ Relationships

When specifying relationships it is only necessary to specify the relationship on the end where 
the foreign key exists. When the schema file is parsed, it inflects the relationship and builds the 
opposite end automatically. If you specify the other end of the relationship manually, the auto 
generation will have no effect.

Doctrine will also attempt to guess the local and foreign key names based on the class involved in the 
relationship. You will notice that all of our example schemas do not include the specific local and 
foreign keys because it is able to guess them.

+++ Detect Relations

Doctrine offers the ability to specify a detect_relations options. This feature provides automatic 
relationship building based on column names. If you have a User model with a contact_id and a class 
with the name Contact exists, it will automatically create the relationships between the two.

+++ Customizing Relationships

Doctrine only requires that you specify the relationship on the end where the foreign key exists. The 
opposite end of the relationship will be inflected and built on the opposite end. The schema syntax 
offers the ability to customize the relationship alias and type of the opposite end. This is good news 
because it means you can maintain all the relevant relationship information in one place. Below is an 
example of how to customize the alias and type of the opposite end of the relationship. It demonstrates 
the relationships User hasOne Contact and Contact hasOne User as UserModel. Normally it would have 
automatically generated User hasOne Contact and Contact hasMany User. The foreignType and foreignAlias 
keywords allow you to customize the foreign relationship.

<code type="yaml">
---
User:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)
  relations:
    Contact:
      foreignType: one
      foreignAlias: UserModel

Contact:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    name:
      type: string(255)
</code>

Here is an example schema:

<code type="yaml">
---
detect_relations: true

User:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)

Contact:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    name:
      type: string(255)
</code>

The resulting relationships will be User hasOne Contact and Contact hasMany User.

+++ One to One

<code type="yaml">
---
User:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)
  relations:
    Contact:
      foreignType: one
Contact:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    name:
      type: string(255)
</code>

+++ One to Many

<code type="yaml">
---
User:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)
Phonenumber:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    name:
      type: string(255)
    user_id:
      type: integer(4)
  relations:
    User:
      foreignAlias: Phonenumbers
</code>

+++ Many to Many

<code type="yaml">
User:
  columns:
    id:
      type: integer(4)
      autoincrement: true
      primary: true
    username:
      type: string(255)
    password:
      type: string(255)
  attributes:
    export: all
    validate: true
Group:
  tableName: group_table
  columns:
    id:
      type: integer(4)
      autoincrement: true
      primary: true
    name:
      type: string(255)
  relations:
    Users:
      foreignAlias: Groups
      class: User
      refClass: GroupUser
GroupUser:
  columns:
    group_id:
      type: integer(4)
      primary: true
    user_id:
      type: integer(4)
      primary: true
</code>

++ Features & Examples

+++ Connection Binding

<code type="php">
Doctrine::connection('mysql://jwage:pass@localhost/connection1', 'connection1');
</code>

<code type="yaml">
---
User:
  connection: connection1
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)
</code>

+++ Attributes

<code type="yaml">
---
User:
  connection: connection1
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)
  attributes:
    export: none
    validate: false
</code>

+++ Enums

<code type="yaml">
---
TvListing:
 tableName: tv_listing
 actAs: [Timestampable]
 columns:
   notes:
     type: string
   taping:
     type: enum
     length: 4
     values: ['live', 'tape']
   region:
     type: enum
     length: 4
     values: ['US', 'CA']
</code>

+++ Templates

<code type="yaml">
---
User:
  connection: connection1
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)
  templates:
    MyCustomTemplate
      option1: value
      option2: value
</code>

+++ ActAs

<code type="yaml">
---
User:
  connection: connection1
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)
  actAs:
    Sluggable:
      fields: [username]
      name: slug    # defaults to 'slug'
      type: string  # defaults to 'clob'
      length: 255   # defaults to null. clob doesn't require a length
</code>

+++ Options

<code type="yaml">
---
User:
  connection: connection1
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)
  options:
    type: INNODB
    collate: utf8_unicode_ci
    charset: utf8
</code>

+++ Indexes

Please see chapter [doc basic-schema-mapping :index :name] for more information about indexes and 
their options.

schema.yml
<code type="yml">
---
UserProfile:
  columns:
    user_id:
      type: integer
      length: 4
      primary: true
      autoincrement: true
    first_name:
      type: string
      length: 20
    last_name:
      type: string
      length: 20
  indexes:
    name_index:
      fields:
        first_name:
          sorting: ASC
          length: 10
          primary: true
        last_name: []
      type: unique
</code>

This is the PHP line of code that is auto-generated inside setTableDefinition() inside your base 
model class.

<code type="php">
$this->index('name_index', array('fields' => array('first_name' => array( 'sorting' => 'ASC', 'length' => '10', 'primary' => true ), 'last_name' => array( ) ), 'type' => 'unique'));
</code>

+++ Inheritance

Simple inheritance. Read about more about [doc relations:inheritance:simple-inheritance :index :name]. Any columns or relations added to the children classes will be moved to the parent.

<code type="yaml">
---
Entity:
  columns:
    name: string(255)
    username: string(255)
    password: string(255)

User:
  inheritance:
    extends: Entity
    type: simple

Group:
  inheritance:
    extends: Entity
    type: simple
</code>

Class table inheritance. Read about more about [doc relations:inheritance:class-table-inheritance :index :name]

<code type="yaml">
---
Entity:
  columns:
    name: string(255)

User:
  inheritance:
    extends: Entity
    type: class_table
  columns:
    username: string(255)
    password: string(255)
    age: integer(2)
</code>

Concrete inheritance. Read about more about [doc relations:inheritance:concrete-inheritance :index :name]

<code type="yaml">
---
TextItem:
  columns:
    topic: string(255)

Comment:
  inheritance:
    extends: TextItem
    type: concrete
  columns:
    content: string(300)
</code>

Column aggregation inheritance. Read about more about [doc relations:inheritance:column-aggregation-inheritance :index :name]. Like simple inheritance, any columns or relationships added to the children will be automatically removed and moved to the parent.

<code type="yaml">
---
Entity:
  columns:
    name: string(255)
    type: string(255)         # Optional, will be automatically added when it is specified in the child class

User:
  inheritance:
    extends: Entity
    type: column_aggregation  # Optional, it is implied if a keyField or keyValue is present
    keyField: type            # Optional, will default to 'type' and add it to the parent class if type is column aggregation
    keyValue: User            # Optional, will default to the name of the child class if type is column aggregation
  columns:
    username: string(255)
    password: string(255)

Group:
  inheritance:
    extends: Entity
    type: column_aggregation
    keyField: type
    keyValue: Group
  columns:
    description: string(255)
</code>

+++ Generate Accessors

When the generate_accessors: true option is present in a schema file, it will generate propel orm style 
get and set accessors in the Base model definition. For example setFieldName() and getFieldName() would 
then be possible in your models.

Example:
<code type="yaml">
---
generate_accessors: true

User:
  columns:
    username:
      type: string(255)
</code>

+++ Column Aliases

If you want the ability alias a column name as something other than the column name in the database 
this is possible with the " as alias_name" string after the column name.

Example:
<code type="yaml">
---
User:
  columns:
    login:
      name: login as username
      type: string(255)
    password:
      type: string(255)
</code>

The above example would allow you to access the login column name from the alias "username".

+++ Packages

Doctrine offers the "package" parameter which will generate the models in to sub folders. With large 
schema files this will allow you to better organize your schemas in to folders.

<code type="yaml">
---
User:
  package: User
  columns:
    username: string(255)
</code>

The model files from this schema file would be put in a folder named User. You can specify more sub 
folders by doing "package: User.Models" and the models would be in User/Models

+++ Global Schema Information

Doctrine schemas allow you to specify certain parameters that will apply to all of the models defined 
in the schema file. Below you can find an example on what global parameters you can set for schema files.

List of global parameters:

connection
attributes
templates
actAs
options
package
inheritance
detect_relations
generate_accessors

<code type="yaml">
---
connection: conn_name1
actAs: [Timestampable]
options:
  type: INNODB
package: User
detect_relations: true
generate_accessors: true

User:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    contact_id:
      type: integer(4)
    username:
      type: string(255)
    password:
      type: string(255)

Contact:
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    name:
      type: string(255)
</code>

All of the settings at the top will be applied to every model which is defined in that yaml file.

++ Using Schema Files

Once you have defined your schema files you need some code to 
<code type="php">
// The options are completely optional. Only use this if you need something beyond the default configuration for model generation
$options = array('packagesPrefix'        =>  'Package',             // What to prefix the middle package models with
                 'packagesPath'          =>  '',                    // this defaults to the "#models_path#/packages"
                 'generateBaseClasses'   =>  true,                  // Whether or not to generate abstract base models containing the definition and a top level class which is empty extends the base
                 'generateTableClasses'  =>  true,                  // Whether or not to generate a table class for each model
                 'baseClassesDirectory'  =>  'generated',           // Name of the folder to generate the base class definitions in
                 'baseClassName'         =>  'Doctrine_Record',     // Name of the base Doctrine_Record class
                 'suffix'                =>  '.php');               // Extension for your generated models

// This code will generate the models for schema.yml at /path/to/generate/models
Doctrine::generateModelsFromYaml('/path/to/directory/with/yaml/schema/files', '/path/to/generate/models', $options);
</code>