root/branches/1.1/UPGRADE_TO_1_1

Revision 5522, 16.5 KB (checked in by jwage, 5 months ago)

[1.1] Fixes issue with prefixes causing invalid differences (closes #1854)

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