13
13
14
14
use Doctrine \Common \Persistence \ManagerRegistry ;
15
15
use Doctrine \Common \Persistence \ObjectManager ;
16
- use Doctrine \ORM \QueryBuilder ;
17
16
use Symfony \Bridge \
8000
Doctrine \Form \ChoiceList \DoctrineChoiceLoader ;
18
17
use Symfony \Bridge \Doctrine \Form \ChoiceList \EntityLoaderInterface ;
19
18
use Symfony \Bridge \Doctrine \Form \ChoiceList \IdReader ;
25
24
use Symfony \Component \Form \ChoiceList \Factory \DefaultChoiceListFactory ;
26
25
use Symfony \Component \Form \ChoiceList \Factory \PropertyAccessDecorator ;
27
26
use Symfony \Component \Form \Exception \RuntimeException ;
28
- use Symfony \Component \Form \Exception \UnexpectedTypeException ;
29
27
use Symfony \Component \Form \FormBuilderInterface ;
30
28
use Symfony \Component \OptionsResolver \Options ;
31
29
use Symfony \Component \OptionsResolver \OptionsResolver ;
@@ -92,6 +90,24 @@ public static function createChoiceName($choice, $key, $value)
92
90
return (string ) $ value ;
93
91
}
94
92
93
+ /**
94
+ * Gets important parts from QueryBuilder that will allow to cache its results.
95
+ * For instance in ORM two query builders with an equal SQL string and
96
+ * equal parameters are considered to be equal.
97
+ *
98
+ * @param object $queryBuilder
99
+ *
100
+ * @return array|false Array with important QueryBuilder parts or false if
101
+ * they can't be determined
102
+ *
103
+ * @internal This method is public to be usable as callback. It should not
104
+ * be used in user code.
105
+ */
106
+ public function getQueryBuilderPartsForCachingHash ($ queryBuilder )
107
+ {
108
+ return false ;
109
+ }
110
+
95
111
public function __construct (ManagerRegistry $ registry , PropertyAccessorInterface $ propertyAccessor = null , ChoiceListFactoryInterface $ choiceListFactory = null )
96
112
{
97
113
$ this ->registry = $ registry ;
@@ -117,29 +133,28 @@ public function configureOptions(OptionsResolver $resolver)
117
133
$ type = $ this ;
118
134
119
135
$ choiceLoader = function (Options $ options ) use ($ choiceListFactory , &$ choiceLoaders , $ type ) {
120
- // This closure and the "query_builder" options should be pushed to
121
- // EntityType in Symfony 3.0 as they are specific to the ORM
122
136
123
137
// Unless the choices are given explicitly, load them on demand
124
138
if (null === $ options ['choices ' ]) {
125
- // We consider two query builders with an equal SQL string and
126
- // equal parameters to be equal
127
- $ qbParts = $ options ['query_builder ' ]
128
- ? array (
129
- $ options ['query_builder ' ]->getQuery ()->getSQL (),
130
- $ options ['query_builder ' ]->getParameters ()->toArray (),
131
- )
132
- : null ;
133
-
134
- $ hash = CachingFactoryDecorator::generateHash (array (
135
- $ options ['em ' ],
136
- $ options ['class ' ],
137
- $ qbParts ,
138
- $ options ['loader ' ],
139
- ));
140
139
141
- if (isset ($ choiceLoaders [$ hash ])) {
142
- return $ choiceLoaders [$ hash ];
140
+ $ hash = null ;
141
+ $ qbParts = null ;
142
+
143
+ // If there is no QueryBuilder we can safely cache DoctrineChoiceLoader,
144
+ // also if concrete Type can return important QueryBuilder parts to generate
145
+ // hash key we go for it as well
146
+ if (!$ options ['query_builder ' ] || false !== ($ qbParts = $ type ->getQueryBuilderPartsForCachingHash ($ options ['query_builder ' ]))) {
147
+
148
+ $ hash = CachingFactoryDecorator::generateHash (array (
149
+ $ options ['em ' ],
150
+ $ options ['class ' ],
151
+ $ qbParts ,
152
+ $ options ['loader ' ],
153
+ ));
154
+
155
+ if (isset ($ choiceLoaders [$ hash ])) {
156
+ return $ choiceLoaders [$ hash ];
157
+ }
143
158
}
144
159
145
160
if ($ options ['loader ' ]) {
@@ -151,15 +166,19 @@ public function configureOptions(OptionsResolver $resolver)
151
166
$ entityLoader = $ type ->getLoader ($ options ['em ' ], $ queryBuilder , $ options ['class ' ]);
152
167
}
153
168
154
- $ choiceLoaders [ $ hash ] = new DoctrineChoiceLoader (
169
+ $ doctrineChoiceLoader = new DoctrineChoiceLoader (
155
170
$ choiceListFactory ,
156
171
$ options ['em ' ],
157
172
$ options ['class ' ],
158
173
$ options ['id_reader ' ],
159
174
$ entityLoader
160
175
);
161
176
162
- return $ choiceLoaders [$ hash ];
177
+ if ($ hash !== null ) {
178
+ $ choiceLoaders [$ hash ] = $ doctrineChoiceLoader ;
179
+ }
180
+
181
+ return $ doctrineChoiceLoader ;
163
182
}
164
183
};
165
184
@@ -240,10 +259,6 @@ public function configureOptions(OptionsResolver $resolver)
240
259
$ queryBuilderNormalizer = function (Options $ options , $ queryBuilder ) {
241
260
if (is_callable ($ queryBuilder )) {
242
261
$ queryBuilder = call_user_func ($ queryBuilder , $ options ['em ' ]->getRepository ($ options ['class ' ]));
243
-
244
- if (!$ queryBuilder instanceof QueryBuilder) {
245
- throw new UnexpectedTypeException ($ queryBuilder , 'Doctrine\ORM\QueryBuilder ' );
246
- }
247
262
}
248
263
249
264
return $ queryBuilder ;
@@ -305,7 +320,6 @@ public function configureOptions(OptionsResolver $resolver)
305
320
306
321
$ resolver ->setAllowedTypes ('em ' , array ('null ' , 'string ' , 'Doctrine\Common\Persistence\ObjectManager ' ));
307
322
$ resolver ->setAllowedTypes ('loader ' , array ('null ' , 'Symfony\Bridge\Doctrine\Form\ChoiceList\EntityLoaderInterface ' ));
308
- $ resolver ->setAllowedTypes ('query_builder ' , array ('null ' , 'callable ' , 'Doctrine\ORM\QueryBuilder ' ));
309
323
}
310
324
311
325
/**
0 commit comments