11
11
12
12
namespace Symfony \Bridge \Doctrine \DependencyInjection ;
13
13
14
+ use Doctrine \Persistence \Mapping \Driver \ClassLocator ;
15
+ use Doctrine \Persistence \Mapping \Driver \FileClassLocator ;
16
+ use Doctrine \Persistence \Mapping \Driver \MappingDriver ;
14
17
use Symfony \Component \DependencyInjection \Alias ;
15
18
use Symfony \Component \DependencyInjection \ContainerBuilder ;
16
19
use Symfony \Component \DependencyInjection \Definition ;
17
20
use Symfony \Component \DependencyInjection \Reference ;
21
+ use Symfony \Component \Finder \Finder ;
18
22
use Symfony \Component \HttpKernel \DependencyInjection \Extension ;
23
+ use Symfony \Component \TypeInfo \Type ;
24
+ use Symfony \Component \TypeInfo \TypeResolver \TypeResolver ;
19
25
20
26
/**
21
27
* This abstract classes groups common code that Doctrine Object Manager extensions (ORM, MongoDB, CouchDB) need.
@@ -30,6 +36,8 @@ abstract class AbstractDoctrineExtension extends Extension
30
36
protected array $ aliasMap = [];
31
37
32
38
/**
39
+ * @var array<string,array<string,string>> An array of directory paths by namespace, indexed by driver type.
40
+ *
33
41
* Used inside metadata driver method to simplify aggregation of data.
34
42
*/
35
43
protected array $ drivers = [];
@@ -185,7 +193,8 @@ protected function registerMappingDrivers(array $objectManager, ContainerBuilder
185
193
}
186
194
187
195
foreach ($ this ->drivers as $ driverType => $ driverPaths ) {
188
- $ mappingService = $ this ->getObjectManagerElementName ($ objectManager ['name ' ].'_ ' .$ driverType .'_metadata_driver ' );
196
+ $ driverName = $ objectManager ['name ' ].'_ ' .$ driverType ;
197
+ $ mappingService = $ this ->getObjectManagerElementName ($ driverName .'_metadata_driver ' );
189
198
if ($ container ->hasDefinition ($ mappingService )) {
190
199
$ mappingDriverDef = $ container ->getDefinition ($ mappingService );
191
200
$ args = $ mappingDriverDef ->getArguments ();
@@ -203,6 +212,19 @@ protected function registerMappingDrivers(array $objectManager, ContainerBuilder
203
212
$ mappingDriverDef ->addMethodCall ('setGlobalBasename ' , ['mapping ' ]);
204
213
}
205
214
215
+ if ('attribute ' === $ driverType ) {
216
+ $ driverClass = $ mappingDriverDef ->getClass ();
217
+
218
+ /** @var string[] $directoryPaths */
219
+ $ directoryPaths = $ mappingDriverDef ->getArgument (0 );
220
+
221
+ $ classLocator = $ this ->registerMappingClassLocatorService ($ driverClass , $ driverName , $ container , $ directoryPaths );
222
+
223
+ if (null !== $ classLocator ) {
224
+ $ mappingDriverDef ->replaceArgument (0 , new Reference ($ classLocator ));
225
+ }
226
+ }
227
+
206
228
$ container ->setDefinition ($ mappingService , $ mappingDriverDef );
207
229
208
230
foreach ($ driverPaths as $ prefix => $ driverPath ) {
@@ -213,6 +235,61 @@ protected function registerMappingDrivers(array $objectManager, ContainerBuilder
213
235
$ container ->setDefinition ($ this ->getObjectManagerElementName ($ objectManager ['name ' ].'_metadata_driver ' ), $ chainDriverDef );
214
236
}
215
237
238
+ /**
239
+ * @param class-string<MappingDriver> $driverClass
240
+ * @param string[] $dirs
241
+ *
242
+ * @return ?string service id, or null if not available
243
+ */
244
+ private function registerMappingClassLocatorService (string $ driverClass , string $ driverName , ContainerBuilder $ container , array $ dirs ): ?string
245
+ {
246
+ // Available since doctrine/persistence >= 4.1
247
+ if (!interface_exists (ClassLocator::class)) {
248
+ return null ;
249
+ }
250
+
251
+ $ parameter = new \ReflectionParameter ([$ driverClass , '__construct ' ], 0 );
252
+
253
+ $ parameterType = TypeResolver::create ()->resolve ($ parameter );
254
+
255
+ // It's possible that doctrine/persistence:^4.1 is installed with the older versions of ORM/ODM.
256
+ // In this case it's necessary to check for actual driver support.
257
+ if (!$ parameterType ->isIdentifiedBy (ClassLocator::class)) {
258
+ return null ;
259
+ }
260
+
261
+ $ classLocator = $ this ->getObjectManagerElementName ($ driverName .'_mapping_class_locator ' );
262
+
263
+ $ locatorDefinition = new Definition (
264
+ FileClassLocator::class,
265
+ [new Reference ($ this ->registerMappingClassFinderService ($ driverName , $ container , $ dirs ))],
266
+ );
267
+
268
+ $ container ->setDefinition ($ classLocator , $ locatorDefinition );
269
+
270
+ return $ classLocator ;
271
+ }
272
+
273
+ /** @param string[] $dirs */
274
+ private function registerMappingClassFinderService (string $ driverName , ContainerBuilder $ container , array $ dirs ): string
275
+ {
276
+ $ finderService = $ this ->getObjectManagerElementName ($ driverName .'_mapping_class_finder ' );
277
+
278
+ if ($ container ->hasDefinition ($ finderService )) {
279
+ $ finderDefinition = $ container ->getDefinition ($ finderService );
280
+ } else {
281
+ $ finderDefinition = new Definition (Finder::class, []);
282
+ }
283
+
284
+ $ finderDefinition ->addMethodCall ('files ' );
285
+ $ finderDefinition ->addMethodCall ('name ' , ['*.php ' ]);
286
+ $ finderDefinition ->addMethodCall ('in ' , [$ dirs ]);
287
+
288
+ $ container ->setDefinition ($ finderService , $ finderDefinition );
289
+
290
+ return $ finderService ;
291
+ }
292
+
216
293
/**
217
294
* Assertion if the specified mapping information is valid.
218
295
*
0 commit comments