Development

/plugins/nahoPropelOptimizerPlugin/README

You must first sign up to be able to contribute.

root/plugins/nahoPropelOptimizerPlugin/README

Revision 8458, 6.0 kB (checked in by naholyr, 5 months ago)

[nahoPropelOptimizerPlugin]
- Updated README (ready for publishing)
- Added support for returning NULL instead of NULLs-hydrated object (in case of
LEFT JOIN with non-existing related object)

Line 
1 = nahoPropelOptimizerPlugin plugin =
2
3 This `nahoPropelOptimizerPlugin` plugin fixes a few defects (not to say "bugs") in Propel model generation, that are not yet handled by Symfony builder wrapping.
4
5 == Instalation ==
6
7   * Install the plugin
8    
9     {{{
10       symfony plugin-install http://plugins.symfony-project.com/nahoPropelOptimizerPlugin
11     }}}
12    
13     Like any other plugin, you can either extract one of the attached archives, or use Subversion.
14  
15   * Edit `config/propel.ini` and find the following lines :
16    
17     {{{
18       ; builder settings
19       propel.builder.peer.class              = addon.propel.builder.SfPeerBuilder
20       propel.builder.object.class            = addon.propel.builder.SfObjectBuilder
21      
22       propel.builder.objectstub.class        = addon.propel.builder.SfExtensionObjectBuilder
23       propel.builder.peerstub.class          = addon.propel.builder.SfExtensionPeerBuilder
24       propel.builder.objectmultiextend.class = addon.propel.builder.SfMultiExtendObjectBuilder
25       propel.builder.mapbuilder.class        = addon.propel.builder.SfMapBuilderBuilder
26     }}}
27    
28     And replace `addon.propel.builder.Sf` with `plugins.nahoPropelOptimizerPlugin.lib.SfOptimized` :
29    
30     {{{
31       ; builder settings
32       propel.builder.peer.class              = plugins.nahoPropelOptimizerPlugin.lib.SfOptimizedPeerBuilder
33       propel.builder.object.class            = plugins.nahoPropelOptimizerPlugin.lib.SfOptimizedObjectBuilder
34      
35       propel.builder.objectstub.class        = plugins.nahoPropelOptimizerPlugin.lib.SfOptimizedExtensionObjectBuilder
36       propel.builder.peerstub.class          = plugins.nahoPropelOptimizerPlugin.lib.SfOptimizedExtensionPeerBuilder
37       propel.builder.objectmultiextend.class = plugins.nahoPropelOptimizerPlugin.lib.SfOptimizedMultiExtendObjectBuilder
38       propel.builder.mapbuilder.class        = plugins.nahoPropelOptimizerPlugin.lib.SfOptimizedMapBuilderBuilder
39     }}}
40  
41   * Rebuild your model :
42    
43     {{{
44       $ symfony propel-build-model
45       $ symfony cc
46     }}}
47
48 Your model classes have been regenerated with all the supported optimizations. You're ready to go !
49
50 Default behavior is enabling all supported optimizations, see the "Configuration" section to disable some of them if you want.
51
52 == Optimizations ==
53
54 This section lists all the changes made by this custom builder.
55
56 === Includes overhead (defect) ===
57
58 Default behavior does not remove all the useless calls to "include_once" made by Propel (it removes some of them, but not all). They are useless as the autoloader already takes care of this, and they add a little useless overhead.
59
60 `nahoPropelOptimizer` removes all these calls in Peer and MapBuilder classes.
61
62 === Explicit joins (bug) ===
63
64 With the default builder, Peer classes join with an implicit JOIN. PostPeer::doSelectJoinAuthor will execute this query :
65
66 {{{
67   SELECT * FROM post, author WHERE post.author_id = author.id AND ...
68 }}}
69
70 Which is equivalent to :
71
72 {{{
73   SELECT * FROM post INNER JOIN author ON (post.author_id = author.id) WHERE ...
74 }}}
75
76 This behavior makes the `doSelectJoinXXX` methods unreliable if you expected to be sure to have the same results with or without the join (if you had a not required foreign key, this implicit inner join will just drop the lines where this key was `NULL`).
77
78 `nahoPropelOptimizer` forces Propel to use real explicit joins, and checks if the foreign key is `required` or not to make a LEFT JOIN or an INNER JOIN.
79
80 Due to a still partial support of those joins in Propel, the related object is always hydrated, but when the foreign key was `NULL` it's hydrated with `NULL` values... But the next optimization is here to fix that ;)
81
82 === LEFT JOINS and related objects hydrated with NULL values (defect) ===
83
84 When you make a LEFT JOIN, Propel always hydrates the related object, even if there is *no* related object !
85
86 If there is no related object, you will get corrupted results.
87
88 Let's see this schema, where a user can have a group, but it's not required :
89
90 {{{
91   t_group:
92     id: ~
93     name: { type: varchar(128), index: unique }
94   t_user:
95     id: ~
96     login: { type: varchar(128), index: unique }
97     group_id: { type: integer, foreignTable: t_group, foreignReference: id, required: false }
98 }}}
99
100 {{{
101   <?php
102    
103     // Retrieve the user, joined with group, with explicit joins optimization activated
104     // We will retrieve the user with ID = $id, and we know this user has no related group
105    
106     $criteria = new Criteria;
107     $criteria->add(TUser::ID, $id);
108    
109     $users = TUserPeer::doSelectJoinTGroup($criteria);
110     // Executed query : SELECT * FROM t_user JOIN t_group ON (t_user.group_id = t_group.id) WHERE t_user.id = $id
111    
112     $user = $users[0];
113    
114     $group = $user->getGroup();
115     // Default behavior : $group is an instance of TGroup, and all its fields are NULL
116     // Fixed behavior   : $group is NULL
117 }}}
118
119 With this optimization, you will not retreive corrupted objects, when the object does not exist, you get NULL as you would expect it to be.
120
121 === Calls to Propel::import (bug) ===
122
123 This bug makes the overriding of plugins' model totally impossible, and adds a little overhead just like includes.
124
125 If a plugin has a bundled schema with a package attribute different than "lib.model", because of this bug you will not be able to customize the model without touching the files directly located in the plugin's directory.
126
127 This is caused by useless calls to Propel::import(). This optimization just removes all of them : they are fully useless as the autoloader handles the loading of model classes very better.
128
129 == Configuration ==
130
131 All optimizations are activated when you don't specify anything.
132
133 To disable an optimization, just add the corresponding option to your `config/propel.ini` :
134
135 {{{
136   ; Disable optimization "Includes overhead"
137   propel.builder.addIncludes = true
138  
139   ; Disable optimization "Explicit joins"
140   propel.builder.implicitJoins = true
141  
142   ; Disable optimization "LEFT JOINS and related objects hydrated with NULL values"
143   propel.builder.hydrateNULLs = true
144  
145   ; Disable optimization "Calls to Propel::import"
146   propel.builder.addPropelImports = true
147 }}}
Note: See TracBrowser for help on using the browser.