11
11
12
12
namespace Symfony \Bridge \Doctrine \Form \ChoiceList ;
13
13
14
- use Doctrine \Common \Persistence \Mapping \ClassMetadata ;
15
14
use Doctrine \Common \Persistence \ObjectManager ;
16
15
use Symfony \Component \Form \ChoiceList \ChoiceListInterface ;
17
16
use Symfony \Component \Form \ChoiceList \Factory \ChoiceListFactoryInterface ;
18
17
use Symfony \Component \Form \ChoiceList \Loader \ChoiceLoaderInterface ;
19
- use Symfony \Component \Form \Exception \RuntimeException ;
20
18
21
19
/**
22
20
* Loads choices using a Doctrine object manager.
@@ -41,67 +39,20 @@ class DoctrineChoiceLoader implements ChoiceLoaderInterface
41
39
private $ class ;
42
40
43
41
/**
44
- * @var ClassMetadata
42
+ * @var IdReader
45
43
*/
46
- private $ classMetadata ;
44
+ private $ idReader ;
47
45
48
46
/**
49
47
* @var null|EntityLoaderInterface
50
48
*/
51
49
private $ objectLoader ;
52
50
53
- /**
54
- * The identifier field, unless the identifier is composite
55
- *
56
- * @var null|string
57
- */
58
- private $ idField = null ;
59
-
60
- /**
61
- * Whether to use the identifier for value generation
62
- *
63
- * @var bool
64
- */
65
- private $ compositeId = true ;
66
-
67
51
/**
68
52
* @var ChoiceListInterface
69
53
*/
70
54
private $ choiceList ;
71
55
72
- /**
73
- * Returns the value of the identifier field of an object.
74
- *
75
- * Doctrine must know about this object, that is, the object must already
76
- * be persisted or added to the identity map before. Otherwise an
77
- * exception is thrown.
78
- *
79
- * This method assumes that the object has a single-column identifier and
80
- * will return a single value instead of an array.
81
- *
82
- * @param object $object The object for which to get the identifier
83
- *
84
- * @return int|string The identifier value
85
- *
86
- * @throws RuntimeException If the object does not exist in Doctrine's identity map
87
- *
88
- * @internal Should not be accessed by user-land code. This method is public
89
- * only to be usable as callback.
90
- */
91
- public static function getIdValue (ObjectManager $ om , ClassMetadata $ classMetadata , $ object )
92
- {
93
- if (!$ om ->contains ($ object )) {
94
- throw new RuntimeException (
95
- 'Entities passed to the choice field must be managed. Maybe ' .
96
- 'persist them in the entity manager? '
97
- );
98
- }
99
-
100
- $ om ->initializeObject ($ object );
101
-
102
- return current ($ classMetadata ->getIdentifierValues ($ object ));
103
- }
104
-
105
56
/**
106
57
* Creates a new choice loader.
107
58
*
@@ -114,22 +65,17 @@ public static function getIdValue(ObjectManager $om, ClassMetadata $classMetadat
114
65
* @param ObjectManager $manager The object manager
115
66
* @param string $class The class name of the
116
67
* loaded objects
68
+ * @param IdReader $idReader The reader for the object
69
+ * IDs.
117
70
* @param null|EntityLoaderInterface $objectLoader The objects loader
118
71
*/
119
- public function __construct (ChoiceListFactoryInterface $ factory , ObjectManager $ manager , $ class , EntityLoaderInterface $ objectLoader = null )
72
+ public function __construct (ChoiceListFactoryInterface $ factory , ObjectManager $ manager , $ class , IdReader $ idReader , EntityLoaderInterface $ objectLoader = null )
120
73
{
121
74
$ this ->factory = $ factory ;
122
75
$ this ->manager = $ manager ;
123
- $ this ->classMetadata = $ manager ->getClassMetadata ($ class );
124
- $ this ->class = $ this -> classMetadata -> getName () ;
76
+ $ this ->class = $ manager ->getClassMetadata ($ class)-> getName ( );
77
+ $ this ->idReader = $ idReader ;
125
78
$ this ->objectLoader = $ objectLoader ;
126
-
127
- $ identifier = $ this ->classMetadata ->getIdentifierFieldNames ();
128
-
129
- if (1 === count ($ identifier )) {
130
- $ this ->idField = $ identifier [0 ];
131
- $ this ->compositeId = false ;
132
- }
133
79
}
134
80
135
81
/**
@@ -145,23 +91,7 @@ public function loadChoiceList($value = null)
145
91
? $ this ->objectLoader ->getEntities ()
146
92
: $ this ->manager ->getRepository ($ this ->class )->findAll ();
147
93
148
- // If the class has a multi-column identifier, we cannot index the
149
- // objects by their IDs
150
- if ($ this ->compositeId ) {
151
- $ this ->choiceList = $ this ->factory ->createListFromChoices ($ objects , $ value );
152
-
153
- return $ this ->choiceList ;
154
- }
155
-
156
- // Index the objects by ID
157
- $ objectsById = array ();
158
-
159
- foreach ($ objects as $ object ) {
160
- $ id = self ::getIdValue ($ this ->manager , $ this ->classMetadata , $ object );
161
- $ objectsById [$ id ] = $ object ;
162
- }
163
-
164
- $ this ->choiceList = $ this ->factory ->createListFromChoices ($ objectsById , $ value );
94
+ $ this ->choiceList = $ this ->factory ->createListFromChoices ($ objects , $ value );
165
95
166
96
return $ this ->choiceList ;
167
97
}
@@ -193,14 +123,14 @@ public function loadValuesForChoices(array $objects, $value = null)
193
123
// know that the IDs are used as values
194
124
195
125
// Attention: This optimization does not check choices for existence
196
- if (!$ this ->choiceList && ! $ this ->compositeId ) {
126
+ if (!$ this ->choiceList && $ this ->idReader -> isSingleId () ) {
197
127
$ values = array ();
198
128
199
129
// Maintain order and indices of the given objects
200
130
foreach ($ objects as $ i => $ object ) {
201
131
if ($ object instanceof $ this ->class ) {
202
132
// Make sure to convert to the right format
203
- $ values [$ i ] = (string ) self :: getIdValue ( $ this ->manager , $ this -> classMetadata , $ object );
133
+ $ values [$ i ] = (string ) $ this ->idReader -> getIdValue ( $ object );
204
134
}
205
135
}
206
136
@@ -240,8 +170,8 @@ public function loadChoicesForValues(array $values, $value = null)
240
170
241
171
// Optimize performance in case we have an object loader and
242
172
// a single-field identifier
243
- if (!$ this ->choiceList && ! $ this ->compositeId && $ this ->objectLoader ) {
244
- $ unorderedObjects = $ this ->objectLoader ->getEntitiesByIds ($ this ->idField , $ values );
173
+ if (!$ this ->choiceList && $ this ->objectLoader && $ this ->idReader -> isSingleId () ) {
174
+ $ unorderedObjects = $ this ->objectLoader ->getEntitiesByIds ($ this ->idReader -> getIdField () , $ values );
245
175
$ objectsById = array ();
246
176
$ objects = array ();
247
177
@@ -250,8 +180,7 @@ public function loadChoicesForValues(array $values, $value = null)
250
180
// "INDEX BY" clause to the Doctrine query in the loader,
251
181
// but I'm not sure whether that's doable in a generic fashion.
252
182
foreach ($ unorderedObjects as $ object ) {
253
- $ id = self ::getIdValue ($ this ->manager , $ this ->classMetadata , $ object );
254
- $ objectsById [$ id ] = $ object ;
183
+ $ objectsById [$ this ->idReader ->getIdValue ($ object )] = $ object ;
255
184
}
256
185
257
186
foreach ($ values as $ i => $ id ) {
0 commit comments