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,20 @@ protected function registerMappingDrivers(array $objectManager, ContainerBuilder
203
212
$ mappingDriverDef ->addMethodCall ('setGlobalBasename ' , ['mapping ' ]);
204
213
}
205
214
215
+ // Available since doctrine/persistence >= 4.1
216
+ if (interface_exists (ClassLocator::class) && 'attribute ' === $ driverType ) {
217
+ $ driverClass = $ mappingDriverDef ->getClass ();
218
+
219
+ /** @var string[] $directoryPaths */
220
+ $ directoryPaths = $ mappingDriverDef ->getArgument (0 );
221
+
222
+ $ classLocator = $ this ->registerMappingClassLocatorService ($ driverClass , $ driverName , $ container , $ directoryPaths );
223
+
224
+ if (null !== $ classLocator ) {
225
+ $ mappingDriverDef ->replaceArgument (0 , new Reference ($ classLocator ));
226
+ }
227
+ }
228
+
206
229
$ container ->setDefinition ($ mappingService , $ mappingDriverDef );
207
230
208
231
foreach ($ driverPaths as $ prefix => $ driverPath ) {
@@ -213,6 +236,56 @@ protected function registerMappingDrivers(array $objectManager, ContainerBuilder
213
236
$ container ->setDefinition ($ this ->getObjectManagerElementName ($ objectManager ['name ' ].'_metadata_driver ' ), $ chainDriverDef );
214
237
}
215
238
239
+ /**
240
+ * @param class-string<MappingDriver> $driverClass
241
+ * @param string[] $dirs
242
+ *
243
+ * @return ?string service id, or null if not available
244
+ */
245
+ private function registerMappingClassLocatorService (string $ driverClass , string $ driverName , ContainerBuilder $ container , array $ dirs ): ?string
246
+ {
247
+ $ parameter = new \ReflectionParameter ([$ driverClass , '__construct ' ], 0 );
248
+
249
+ $ parameterType = TypeResolver::create ()->resolve ($ parameter );
250
+
251
+ // It's possible that doctrine/persistence:^4.1 is installed with the older versions of ORM/ODM.
252
+ // In this case it's necessary to check for actual driver support.
253
+ if (!$ parameterType ->isIdentifiedBy (ClassLocator::class)) {
254
+ return null ;
255
+ }
256
+
257
+ $ classLocator = $ this ->getObjectManagerElementName ($ driverName .'_mapping_class_locator ' );
258
+
259
+ $ locatorDefinition = new Definition (
260
+ FileClassLocator::class,
261
+ [new Reference ($ this ->registerMappingClassFinderService ($ driverName , $ container , $ dirs ))],
262
+ );
263
+
264
+ $ container ->setDefinition ($ classLocator , $ locatorDefinition );
265
+
266
+ return $ classLocator ;
267
+ }
268
+
269
+ /** @param string[] $dirs */
270
+ private function registerMappingClassFinderService (string $ driverName , ContainerBuilder $ container , array $ dirs ): string
271
+ {
272
+ $ finderService = $ this ->getObjectManagerElementName ($ driverName .'_mapping_class_finder ' );
273
+
274
+ if ($ container ->hasDefinition ($ finderService )) {
275
+ $ finderDefinition = $ container ->getDefinition ($ finderService );
276
+ } else {
277
+ $ finderDefinition = new Definition (Finder::class, []);
278
+ }
279
+
280
+ $ finderDefinition ->addMethodCall ('files ' );
281
+ $ finderDefinition ->addMethodCall ('name ' , ['*.php ' ]);
282
+ $ finderDefinition ->addMethodCall ('in ' , [$ dirs ]);
283
+
284
+ $ container ->setDefinition ($ finderService , $ finderDefinition );
285
+
286
+ return $ finderService ;
287
+ }
288
+
216
289
/**
217
290
* Assertion if the specified mapping information is valid.
218
291
*
0 commit comments