root/branches/1.1/UPGRADE_TO_1_1

Revision 5339, 15.2 KB (checked in by jwage, 33 hours ago)

[1.1] Reverting r5084 as it introduces some bugs which cannot be fixed until a later version (closes #1692)

Line 
1Update from 1.0 to 1.1
2======================
3
4This document details the changes made to Doctrine 1.1 to make it easier for you
5to upgrade your projects to use this version.
6
7Doctrine Record
8---------------
9
10isValid() & isModified() Optional Deep Parameter
11------------------------------------------------
12
13When you use the `Doctrine_Record::isValid()` and `Doctrine_Record::isModified()`
14methods you can optionally pass a `$deep` argument with a value of true so that
15Doctrine will check any references that exist. So if a reference record is
16invalid or modified then the parent object will return as such.
17
18Here is an example using `isModified()`:
19
20    [php]
21    $user = new TUser();
22    $mail = new Email();
23    $mail->address = 'test';
24    $user->emails[] = $mail;
25
26    // Returns true because the referenced email model is modified
27    $modified = $user->isModified(true);
28
29Here is an example using `isValid()`:
30
31    $user = new User();
32    $mail = new Email();
33
34    $user->name = "floriank";
35    $user->emails[] = $mail;
36
37    // Returns false because the referenced Email object does not have an address set
38    $valid = $user->isValid(true);
39
40[r5098](http://trac.doctrine-project.org/changeset/5098) - Added ability to
41define custom accessors/mutators for a Doctrine record
42
43    [php]
44    public function setTableDefinition()
45    {
46        $this->hasColumn('username', 'string');
47    }
48
49    public function setUp()
50    {
51        $this->hasAccessor('username', 'customUsernameAccessor');
52        $this->hasMutator('username', 'customUsernameMutator');
53    }
54
55    public function customUsernameAccessor()
56    {
57        return $this->_get('username');
58    }
59
60    public function customUsernameMutator($value)
61    {
62        $this->_set('username', $value);
63    }
64
65[r5236](http://trac.doctrine-project.org/changeset/5236) - Added ability to
66alias record listeners
67
68    [php]
69    $this->addListener(new My_Listener_FooListener($this->_options), 'FooListener');
70
71No aliasing and no options usage:
72
73    [yml]
74    Foo:
75      columns:
76        bar: string(50)
77      listeners: [My_Listener_FooListener]
78
79No aliasing and using options
80
81    [yml]
82    Foo:
83      columns:
84        bar: string(50)
85      listeners:
86        My_Listener_FooListener:
87          useOptions: true
88
89Using alias definition
90
91    [yml]
92    Foo:
93      columns:
94        bar: string(50)
95      listeners:
96        FooListener:
97          class: My_Listener_FooListener
98          useOptions: true
99
100[r5236](http://trac.doctrine-project.org/changeset/5236) - Added ability to
101enable/disable record listeners
102
103Possibility to remove all listeners of all record listeners
104
105    [php]
106    Doctrine::getTable('Foo')->getRecordListener()->setOption('disabled', true);
107
108Possibility to remove some listeners of all record listeners
109
110    [php]
111    Doctrine::getTable('Foo')->getRecordListener()->setOption('disabled',
112      array('preSerialize', 'postHydrate'));
113
114Possibility to remove all listeners of a single record listener
115
116    [php]
117    Doctrine::getTable('Foo')->getRecordListener()->get('FooListener')
118      ->setOption('disabled', true);
119
120Possibility to remove some listeners of a single record listener
121
122    [php]
123    Doctrine::getTable('Foo')->getRecordListener()->get('FooListener')
124      ->setOption('disabled', array('preSave', 'postInsert'));
125
126[r5241](http://trac.doctrine-project.org/changeset/5240) - Added ability to
127work with mapped values as if they were part of the record. It is useful to
128store transient data into record (this data is not persisted to database).
129
130    [php]
131    class Foo extends Doctrine_Record {
132        public function setTableDefinition() {
133            $this->mapValue('name');
134        }
135
136        // ...
137    }
138
139    $foo = new Foo();
140
141    $foo->name = 'guilhermeblanco';
142    echo $foo->name; // prints: guilhermeblanco
143
144[r5014](http://trac.doctrine-project.org/changeset/5014) - Added support for
145`FROM User u WHERE u.id IN ?` in the Doctrine_Query api.
146
147    [php]
148    $q = Doctrine_Query::create()
149      ->from('User u')
150      ->where('u.id IN ?', array(1, 2, 3));
151    $users = $q->execute();
152
153[r5019](http://trac.doctrine-project.org/changeset/5019) - `unlink()` and
154`link()` have been changed to not delete references until `save()` is called
155on the object. Also, fixed synchronizeWithArray() to synchronize many to many
156relationships.
157
158    [php]
159    // Does not link until save()
160    $user = Doctrine::getTable('User')->find(1);
161    $user->link('Groups', array(1, 2, 3));
162    $user->save();
163
164    // Third argument will force it to save instantly
165    $user = Doctrine::getTable('User')->find(1);
166    $user->link('Groups', array(1, 2, 3), true);
167
168    $user = Doctrine::getTable('User')->find(1);
169    $userArray = array('Group' => array(1, 2, 3));
170
171    $user->synchronizeWithArray($userArray);
172    $user->save();
173
174You can also use the same structure with the `fromArray()` function:
175
176    [php]
177    $user->fromArray($userArray);
178    $user->save();
179
180[r5034](http://trac.doctrine-project.org/changeset/5034) - You can now retrieve
181the old values of records through the getModified() function. By default it
182returns an array of fieldName => newValue but if you specify getModified(true)
183it will return the old values.
184
185    [php]
186    $users = Doctrine::getTable('User')->findAll();
187    $user = $users->getFirst();
188    $user->name = 'zYne-';
189   
190    $oldValues = $user->getModified(true);
191    /*
192    array(
193      'name' => 'zYne',
194    )
195    */
196   
197    $newValues = $user->getModified(false);
198    /*
199    array(
200      'name' => 'zYne-',
201    )
202    */
203
204[r5035](http://trac.doctrine-project.org/changeset/5035) - Added ability to use
205custom setters with fromArray()
206
207    [php]
208    public function setTableDefinition()
209    {
210        $this->hasColumn('password');
211    }
212
213    public function setEncryptedPassword($password)
214    {
215        return $this->_set('password', md5($password));
216    }
217
218    $user->fromArray(array('encrypted_password' => 'changeme'));
219
220Will invoke the custom setter setEncryptedPassword()
221
222Default Options
223---------------
224
225[r5027](http://trac.doctrine-project.org/changeset/5039) - Added support for
226setting default charset and collate for tables.
227
228Set globally on a Doctrine_Manager instance.
229
230    [php]
231    $manager->setCollate('utf8_unicode_ci');
232    $manager->setCharset('utf8');
233
234The same can be set on the Doctrine_Connection and Doctrine_Record levels.
235
236    [php]
237    $connection->setCollate('utf8_unicode_ci');
238    $connection->setCharset('utf8');
239
240    public function setTableDefinition()
241    {
242      $this->setCollate('utf8_unicode_ci');
243      $this->setCharset('utf8');
244    }
245
246[r5030](http://trac.doctrine-project.org/changeset/5039) - Added support for
247setting default options for columns and auto added identifier columns.
248
249The following is now possible on Doctrine_Manager, Doctrine_Connection and
250Doctrine_Record.
251
252    [php]
253    $manager->setAttribute(Doctrine::ATTR_DEFAULT_COLUMN_OPTIONS,
254      array('type' => 'string', 'length' => 255, 'notnull' => true));
255
256You can also customize the values that make up the auto added identifier column as well.
257
258    [php]
259    // %s in the name is replaced with the table name.
260    $manager->setAttribute(Doctrine::ATTR_DEFAULT_IDENTIFIER_OPTIONS,
261      array('name' => '%s_id', 'type' => 'string', 'length' => 16));
262
263[r5079](http://trac.doctrine-project.org/changeset/5079) - Added ability to
264retrieve the modified properties from the last transaction with the
265Doctrine_Record::getLastModified() method
266
267    [php]
268    $user = new User();
269    $user->username = 'jwage';
270    print_r($user->getModified()); // array('username' => 'jwage')
271    $user->save();
272
273    // getModified() returns the current modified properties and in this case
274    now no propeties are modified.
275    print_r($user->getModified()); // array()
276
277    // you can retrieve the last modified properties like the following
278    print_r($user->getLastModified()); // array('username' => 'jwage')
279
280Doctrine Query
281--------------
282
283[r5031](http://trac.doctrine-project.org/changeset/5031) - A query can now be
284transformed from an update() or delete() to a select() or any combination. Run a
285query once to update a field then turn it to a select and execute it.
286
287    [php]
288    $q = Doctrine_Query::create()
289        ->update('User u')
290        ->set('u.password', '?', 'newpassword')
291        ->where('u.username = ?', 'jwage');
292    $q->execute();
293
294    // Change it to a select query
295    $q->select();
296    $user = $q->fetchOne();
297
298[r5018](http://trac.doctrine-project.org/changeset/5018) - Added
299`Doctrine::ATTR_AUTO_FREE_QUERY_OBJECTS` for auto freeing query objects after
300execution
301
302    [php]
303    $manager->setAttribute('auto_free_query_objects');
304    $q = Doctrine_Query::create()
305      ->from('User u')
306    $users = $q->execute(); // $q->free() is triggered
307
308[r5121](http://trac.doctrine-project.org/changeset/5121) - Added new
309Doctrine_Query_Abstract::getFlattenedParams() to replace
310Doctrine_Query_Abstract::getParams() and Doctrine_Query_Abstract::getParams()
311now returns the raw unmodified array of query parameters.
312
313Doctrine Collection
314-------------------
315
316[r5032](http://trac.doctrine-project.org/changeset/5032) - You can now convert
317a Doctrine_Collection in to a key value array made up of the values from the two
318specified columns.
319
320    [php]
321    $q = Doctrine_Query::create()
322        ->from('User u');
323    $users = $q->execute();
324
325    $array = $users->toKeyValueArray('id', 'name');
326    print_r($array);
327
328    /*
329    array(
330      4 => 'zYne',
331      5 => 'Arnold Schwarzenegger',
332      6 => 'Michael Caine',
333      7 => 'Takeshi Kitano',
334      8 => 'Sylvester Stallone',
335      9 => 'Kurt Russell',
336      10 => 'Jean Reno',
337      11 => 'Edward Furlong',
338    )
339    */
340
341Doctrine Validation
342-------------------
343
344[r5033](http://trac.doctrine-project.org/changeset/5033) - You can now specify a
345unique validator on a set of fields. The argument of the unique() function can
346either be an array of fields or an argument for each field.
347
348    [php]
349    public function setTableDefinition()
350    {
351        $this->hasColumn('username', 'string', 255);
352        $this->hasColumn('email_address', 'string', 255);
353
354        $this->unique('username', 'email_address');
355    }
356
357Registering Validators
358----------------------
359
360In Doctrine 1.1 you now have the ability to register custom validators so that
361Doctrine is aware of them. You can also get the allowed validators.
362
363    [php]
364    // Register a new validator
365    $manager = Doctrine_Manager::getInstance();
366    $manager->registerValidators('MyValidator');
367
368    // Get array of validators
369    $validators = $manager->getValidators();
370
371E-Mail Validator
372----------------
373
374You now have the ability to configure the Email validator to not check the mx
375record of the e-mail address.
376
377    [php]
378    class User extends Doctrine_Record
379    {
380        public function setTableDefinition()
381        {
382            $this->hasColumn('username', 'string', 255);
383            $this->hasColumn('password', 'string', 255);
384            $this->hasColumn('email_address', 'string', 255, array('email' => array('check_mx' => false)));
385        }
386    }
387
388Doctrine Hydration
389------------------
390
391[r5016](http://trac.doctrine-project.org/changeset/5016) - A performance change
392was made to the hydration process which should yield some improvements when
393hydrating large result sets.
394
395Doctrine Schema Files
396---------------------
397
398You are now able to pass extra attributes through the YAML schema parser to
399store any custom column information and you have access to it through the
400Doctrine_Table.
401
402    [yml]
403    User:
404      columns:
405        username:
406          type: string(255)
407          extra:
408            test: 123
409        password:
410          type: string(255)
411
412          $username = Doctrine::getTable('User')->getDefinitionOf('username');
413          echo $username['extra']['test']; // 123
414
415Generated Models
416----------------
417
418Doctrine will now generate phpDoc property tags with the generated base classes.
419
420    [yml]
421    User:
422      columns:
423        username: string(255)
424        password: string(255)
425
426    Phonenumber:
427      columns:
428        user_id: integer
429        phonenumber: string
430      relations:
431        User:
432          foreignAlias: Phonenumbers
433
434Generates the following User and Phonenumber class
435
436    [php]
437    /**
438     * BaseUser
439     *
440     * This class has been auto-generated by the Doctrine ORM Framework
441     *
442     * @property string $username
443     * @property string $password
444     * @property Doctrine_Collection $Phonenumbers
445     *
446     * @package    ##PACKAGE##
447     * @subpackage ##SUBPACKAGE##
448     * @author     ##NAME## <##EMAIL##>
449     * @version    SVN: $Id: Builder.php 5270 2008-12-05 20:47:43Z jwage $
450     */
451    abstract class BaseUser extends Doctrine_Record
452    {
453      public function setTableDefinition()
454      {
455        $this->setTableName('user');
456        $this->hasColumn('username', 'string', 255, array('type' => 'string', 'length' => '255'));
457        $this->hasColumn('password', 'string', 255, array('type' => 'string', 'length' => '255'));
458      }
459
460      public function setUp()
461      {
462        $this->hasMany('Phonenumber as Phonenumbers', array('local' => 'id',
463                                                            'foreign' => 'user_id'));
464      }
465    }
466
467    /**
468     * BasePhonenumber
469     *
470     * This class has been auto-generated by the Doctrine ORM Framework
471     *
472     * @property integer $user_id
473     * @property string $phonenumber
474     * @property User $User
475     *
476     * @package    ##PACKAGE##
477     * @subpackage ##SUBPACKAGE##
478     * @author     ##NAME## <##EMAIL##>
479     * @version    SVN: $Id: Builder.php 5270 2008-12-05 20:47:43Z jwage $
480     */
481    abstract class BasePhonenumber extends Doctrine_Record
482    {
483      public function setTableDefinition()
484      {
485        $this->setTableName('phonenumber');
486        $this->hasColumn('user_id', 'integer', null, array('type' => 'integer'));
487        $this->hasColumn('phonenumber', 'string', null, array('type' => 'string'));
488      }
489
490      public function setUp()
491      {
492        $this->hasOne('User', array('local' => 'user_id',
493                                    'foreign' => 'id'));
494      }
495    }
496
497Versionable Behavior
498--------------------
499
500[r5097](http://trac.doctrine-project.org/changeset/5097) - Added ability to
501disable automatic deleting of versions when a record is deleted
502
503    [php]
504    $this->actAs('Versionable', array('deleteVersions' => false));
505
506And the yaml version:
507
508    [yml]
509    actAs:
510      Versionable:
511        deleteVersions: false
512
513Migrations
514----------
515
516In Doctrine 1.1 we have made a few changes to migrations.
517
518* Generated migration classes are prefixed with a timestamp instead of a
519incremented integer.
520* Added possibility for automation of up/down methods.
521* Re-ordered arguments for addColumn() so that type is first before length.
522* Added `Doctrine_Migration_Diff` tool.
523
524Here is an example of how you can automate the opposite up or down of a migration
525api method.
526
527    [php]
528    public function migrate($direction)
529    {
530      $this->column($direction, 'table_name', 'column_name', 'string', '255');
531    }
532
533The above example will create the column when $direction == up and will remove
534the column when $direction == down.
535
536SoftDelete
537----------
538
539In Doctrine 1.1 the SoftDelete behavior was changed slightly to store a `deleted_at`
540timestamp to indicate a deleted record rather than a `deleted` boolean flag.
541
542You will need to modify your existing database schema and rename the `deleted`
543column to `deleted_at` and modify the type to be a timestamp.
Note: See TracBrowser for help on using the browser.