schema-files.txt 10.3 KB
Newer Older
1 2 3 4
++ 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.

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

7 8
++ Example Schema File

9 10 11
Below is an example schema file for generating a set of models.

You will notice in this schema file it is not always necessary to specify the local and foreign parameters on a relationship. If the foreign columns follow the naming patterns, Doctrine can successfully guess each of them.
12 13 14 15

schema.yml
<code type="yml">
---
16 17 18
Group:
# bind this model to connection1
  connection: connection1
19 20 21 22 23 24 25 26
  columns: 
    id: 
      notnull: true
      primary: true
      autoincrement: true
      type: integer
      length: 4
      name: id
27
    name: 
28 29 30
      type: string
      length: 255
  relations:
31 32
    Users:
      class: User
33
      refClass: UserGroup
34 35 36 37 38 39 40 41 42 43 44 45 46
# set attributes on the model
  attributes:
    export: tables
# you can set templates on your schema with the following syntax
# if you do not require any options to be set for the template
# actAs and templates are the same, actAs serves as a convenience method for the Templates/Plugins
# that come bundled with Doctrine
  templates: [Doctrine_Template_NestedSet, Doctrine_Template_Versionable]
# this below syntax can be used for the templates above
  actAs:
    NestedSet:
      hasManyRoots: true
      rootColumnName: root_id
47 48 49 50 51 52 53 54 55 56 57
UserGroup:
  columns:
    user_id:
      type: integer
      length: 4
      primary: true
    group_id:
      type: integer
      length: 4
      primary: true
  relations:
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
    User: -
    Group: -
UserCar:
  columns:
    user_id:
      type: integer
      length: 11
      primary: true
    car_id:
      type: integer
      length: 11
      primary: true
  relations:
    User: -
    Car: -
Adult:
  fields:
    id:
      type: integer
      size: 11
78 79
      primary: true
      autoincrement: true
80 81 82 83
    name:
      type: string
      size: 255
    contact_id:
84
      type: integer
85 86 87 88 89 90 91 92 93 94 95 96
      size: 11
  relations:
    Contact:
      foreignType: one
Car:
  columns:
    id:
      type: integer
      length: 11
      primary: true
      autoincrement: true
    name:
97 98 99 100 101
      type: string
      length: 255
  relations:
    Users:
      class: User
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
      refClass: UserCar
Child:
  fields:
    id:
      type: integer
      size: 11
      primary: true
      autoincrement: true
    name:
      type: string
      size: 255
    adult_id:
      type: integer
      size: 11
  relations:
    Adult:
      foreignAlias: Children
Contact:
  columns:
    id:
      type: integer
      length: 11
      primary: true
      autoincrement: true
    name:
      type: string
      length: 255
Dog:
  columns:
    id:
      type: integer
      length: 11
      primary: true
      autoincrement: true
    name:
      type: string
      length: 255
    user_id:
      type: integer
      length: 11
  relations:
    User:
      foreignType: one
SelfReference:
  fields:
    id:
      type: integer
      size: 11
      primary: true
      autoincrement: true
    name:
      type: string
      size: 255
    user_id1:
      type: integer
      size: 11
    user_id2:
      type: integer
      size: 11
    parent_self_reference_id:
      type: integer
      size: 11
    parent_self_reference_id2:
      type: integer
      size: 11
  relations:
    User1:
      class: User
      local: user_id1
      foreignAlias: SelfReference1
    User2:
      class: User
      local: user_id2
      foreignAlias: SelfReference2
    SelfReference1:
      class: SelfReference
      local: parent_self_reference_id
      foreignAlias: SelfReferences1
    SelfReference2:
      class: SelfReference
      local: parent_self_reference_id2
      foreignAlias: SelfReferences2
User:
  inheritance:
    extends: Entity
  fields:
    id:
      type: integer
      size: 11
      primary: true
      autoincrement: true
    username:
      type: string
      length: 255
    hair_color:
      type: string
      length: 255
    contact_id:
      type: integer
      length: 11
  relations:
    Contact:
      local: contact_id
      foreign: id
      foreignType: one
    Cars:
      class: Car
      refClass: UserCar
    Groups:
      class: Group
212
      refClass: UserGroup
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
  indexes:
    name_x:
      columns:
        username:
          sorting: ASC
          length: 11
          primary: true
      type: unique
Entity:
  columns:
    id:
      type: integer
      size: 11
      primary: true
      autoincrement: true
228 229
</code>

230
And now we want to use some Doctrine code to parse that schema.yml file and generate our models from it.
231 232 233 234 235 236 237

<code type="php">
// This code will generate the models for schema.yml at /path/to/generate/models
$import = new Doctrine_Import_Schema();
$import->importSchema('schema.yml', 'yml', '/path/to/generate/models');
</code>

238
This is the directory structure that would be generated at /path/to/generate/models. The base classes contain the actual definitions for the model, and the top level models extend the base and they are only written the first time so you are able to modify them without your additions being overwritten.
239 240

<code>
241 242 243 244 245 246
- Adult.class.php
- Car.class.php
- Child.class.php
- Contact.class.php
- Dog.class.php
- Entity.class.php
247
- Group.class.php
248
- SelfReference.class.php
249
- User.class.php
250
- UserCar.class.php
251 252
- UserGroup.class.php
- generated
253 254 255 256 257 258
  - BaseAdult.class.php
  - BaseCar.class.php
  - BaseChild.class.php
  - BaseContact.class.php
  - BaseDog.class.php
  - BaseEntity.class.php
259
  - BaseGroup.class.php
260
  - BaseSelfReference.class.php
261
  - BaseUser.class.php
262
  - BaseUserCar.class.php
263 264 265
  - BaseUserGroup.class.php
</code>

266 267 268 269 270 271 272 273 274
++ 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:
275 276 277 278 279 280 281 282 283 284 285
    user_id:
      type: integer
      length: 4
      primary: true
      autoincrement: true
    first_name:
      type: string
      length: 20
    last_name:
      type: string
      length: 20
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
  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.

Note: Don't mind the extra trailing commas. This is normal and they should not affect anything negatively.

<code type="php">
<?php

class BaseUserProfile extends Doctrine_Record
{

	public function setTableDefinition()
	{
        // code

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

?>
</code>

318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
++ Additional Schema Options

It isn't necessary to define both sides of a relationship in the schema.yml file as doctrine will attempt to autocomplete the relationships for you. If you choose to define only one side of the relationship, there are two yaml options you can pass to help doctrine decide how to complete the opposite end of the relationship. For example.

schema.yml
<code type="yml">
---
Table1:
  tableName: table_1
  relations: 
    Table2Alias:
      class: Table2
      local: foreign_key
      type: one
      foreignAlias: Table1Alias
      foreignType: one
  columns:
    column_1: { type: string, length: 128 }
    foreign_key: { type: integer, length: 4 }

Table2:
  tableName: table_2
  columns:
    column_1: { type: string, length: 128 }
    foreign_key: { type: integer, length: 4 }
</code>

This schema will define a 1-1 relationship between Table1 and Table2. You'll notice there are two new yaml entries, foreignAlias, and foreignType. ForeignAlias will define the as Alias portion of the opposite relationship, and similarily foreignType defines the reverse relationship of the opposite relationship. Defining foreignType is only necessary when you want a one-to-one relationship, but do not want to define both ends of the relationship manually. The above schema produces the following classes.

<code type="php">
/**
 * This class has been auto-generated by the Doctrine ORM Framework
 */
class Table1 extends Doctrine_Record
{

		public function setTableDefinition()
		{
        $this->setTableName('table_1');
        $this->hasColumn('column_1', 'string', 128);
        $this->hasColumn('foreign_key', 'integer', 4);
		}

		public function setUp()
		{
        $this->hasOne('Table2 as Table2Alias', array('local' => 'foreign_key',
                                                     'foreign' => 'id',
                                                     'onDelete' => 'CASCADE'));
		}
}

/**
 * This class has been auto-generated by the Doctrine ORM Framework
 */
class Table2 extends Doctrine_Record
{

		public function setTableDefinition()
		{
        $this->setTableName('table_2');
        $this->hasColumn('column_1', 'string', 128);
        $this->hasColumn('foreign_key', 'integer', 4);
		}

		public function setUp()
		{
        $this->hasOne('Table1 as Table1Alias', array('local' => 'id',
                                                     'foreign' => 'foreign_key'));
		}
}
</code>

As you can see doctrine fully completes the relationship for both classes. You can also use this shorter format for m-to-m relationships. Using the same User and Groups models defined previously, we create a simplified schema.yml. Whereas in the one-to-many and one-to-one the foreignAlias isn't a required field. If you choose to create many-to-many relationships using the short yaml syntax, the foreignAlias is required for proper generation.

<code type="yml">
---
User:
  columns:
    id: { notnull: true, primary: true, autoincrement: true,  type: integer,  length: 4, name: id }
    username: { type: string, length: 255 }
  relations:
    Groups:
      class: Group
      refClass: UserGroup
      foreignAlias: Users
      local: user_id
      foreign: group_id
      type: many

UserGroup:
  columns:
    user_id: { type: integer, length: 4, primary: true }
    group_id: { type: integer, length: 4, primary: true }

Group:
  columns:
    id: { notnull: true, primary: true, autoincrement: true, type: integer, length: 4, name: id }
    name: { type: string, length: 255 }
</code>

This schema will create identical classes as the fully defined schema.yml above.