|
0
|
1 |
<?php |
|
|
2 |
|
|
|
3 |
/* |
|
|
4 |
* This file is part of the Symfony package. |
|
|
5 |
* |
|
|
6 |
* (c) Fabien Potencier <fabien@symfony.com> |
|
|
7 |
* |
|
|
8 |
* For the full copyright and license information, please view the LICENSE |
|
|
9 |
* file that was distributed with this source code. |
|
|
10 |
*/ |
|
|
11 |
|
|
|
12 |
namespace Symfony\Bundle\DoctrineBundle\DependencyInjection; |
|
|
13 |
|
|
|
14 |
use Symfony\Component\DependencyInjection\Alias; |
|
|
15 |
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; |
|
|
16 |
use Symfony\Component\DependencyInjection\ContainerBuilder; |
|
|
17 |
use Symfony\Component\DependencyInjection\Definition; |
|
|
18 |
use Symfony\Component\DependencyInjection\DefinitionDecorator; |
|
|
19 |
use Symfony\Component\DependencyInjection\Reference; |
|
|
20 |
use Symfony\Bundle\DoctrineAbstractBundle\DependencyInjection\AbstractDoctrineExtension; |
|
|
21 |
use Symfony\Component\Config\FileLocator; |
|
|
22 |
|
|
|
23 |
/** |
|
|
24 |
* DoctrineExtension is an extension for the Doctrine DBAL and ORM library. |
|
|
25 |
* |
|
|
26 |
* @author Jonathan H. Wage <jonwage@gmail.com> |
|
|
27 |
* @author Fabien Potencier <fabien@symfony.com> |
|
|
28 |
* @author Benjamin Eberlei <kontakt@beberlei.de> |
|
|
29 |
*/ |
|
|
30 |
class DoctrineExtension extends AbstractDoctrineExtension |
|
|
31 |
{ |
|
|
32 |
public function load(array $configs, ContainerBuilder $container) |
|
|
33 |
{ |
|
|
34 |
$configuration = new Configuration($container->getParameter('kernel.debug')); |
|
|
35 |
$config = $this->processConfiguration($configuration, $configs); |
|
|
36 |
|
|
|
37 |
if (!empty($config['dbal'])) { |
|
|
38 |
$this->dbalLoad($config['dbal'], $container); |
|
|
39 |
} |
|
|
40 |
|
|
|
41 |
if (!empty($config['orm'])) { |
|
|
42 |
$this->ormLoad($config['orm'], $container); |
|
|
43 |
} |
|
|
44 |
} |
|
|
45 |
|
|
|
46 |
/** |
|
|
47 |
* Loads the DBAL configuration. |
|
|
48 |
* |
|
|
49 |
* Usage example: |
|
|
50 |
* |
|
|
51 |
* <doctrine:dbal id="myconn" dbname="sfweb" user="root" /> |
|
|
52 |
* |
|
|
53 |
* @param array $config An array of configuration settings |
|
|
54 |
* @param ContainerBuilder $container A ContainerBuilder instance |
|
|
55 |
*/ |
|
|
56 |
protected function dbalLoad(array $config, ContainerBuilder $container) |
|
|
57 |
{ |
|
|
58 |
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); |
|
|
59 |
$loader->load('dbal.xml'); |
|
|
60 |
|
|
|
61 |
if (empty($config['default_connection'])) { |
|
|
62 |
$keys = array_keys($config['connections']); |
|
|
63 |
$config['default_connection'] = reset($keys); |
|
|
64 |
} |
|
|
65 |
$this->defaultConnection = $config['default_connection']; |
|
|
66 |
|
|
|
67 |
$container->setAlias('database_connection', sprintf('doctrine.dbal.%s_connection', $this->defaultConnection)); |
|
|
68 |
$container->setAlias('doctrine.dbal.event_manager', new Alias(sprintf('doctrine.dbal.%s_connection.event_manager', $this->defaultConnection), false)); |
|
|
69 |
|
|
|
70 |
$container->setParameter('doctrine.dbal.connection_factory.types', $config['types']); |
|
|
71 |
|
|
|
72 |
$connections = array(); |
|
|
73 |
foreach (array_keys($config['connections']) as $name) { |
|
|
74 |
$connections[$name] = sprintf('doctrine.dbal.%s_connection', $name); |
|
|
75 |
} |
|
|
76 |
$container->setParameter('doctrine.connections', $connections); |
|
|
77 |
$container->setParameter('doctrine.default_connection', $this->defaultConnection); |
|
|
78 |
|
|
|
79 |
foreach ($config['connections'] as $name => $connection) { |
|
|
80 |
$this->loadDbalConnection($name, $connection, $container); |
|
|
81 |
} |
|
|
82 |
} |
|
|
83 |
|
|
|
84 |
/** |
|
|
85 |
* Loads a configured DBAL connection. |
|
|
86 |
* |
|
|
87 |
* @param string $name The name of the connection |
|
|
88 |
* @param array $connection A dbal connection configuration. |
|
|
89 |
* @param ContainerBuilder $container A ContainerBuilder instance |
|
|
90 |
*/ |
|
|
91 |
protected function loadDbalConnection($name, array $connection, ContainerBuilder $container) |
|
|
92 |
{ |
|
|
93 |
// configuration |
|
|
94 |
$configuration = $container->setDefinition(sprintf('doctrine.dbal.%s_connection.configuration', $name), new DefinitionDecorator('doctrine.dbal.connection.configuration')); |
|
|
95 |
if (isset($connection['logging']) && $connection['logging']) { |
|
|
96 |
$configuration->addMethodCall('setSQLLogger', array(new Reference('doctrine.dbal.logger'))); |
|
|
97 |
unset ($connection['logging']); |
|
|
98 |
} |
|
|
99 |
|
|
|
100 |
// event manager |
|
|
101 |
$def = $container->setDefinition(sprintf('doctrine.dbal.%s_connection.event_manager', $name), new DefinitionDecorator('doctrine.dbal.connection.event_manager')); |
|
|
102 |
|
|
|
103 |
// connection |
|
|
104 |
if (isset($connection['charset'])) { |
|
|
105 |
if ((isset($connection['driver']) && stripos($connection['driver'], 'mysql') !== false) || |
|
|
106 |
(isset($connection['driver_class']) && stripos($connection['driver_class'], 'mysql') !== false)) { |
|
|
107 |
$mysqlSessionInit = new Definition('%doctrine.dbal.events.mysql_session_init.class%'); |
|
|
108 |
$mysqlSessionInit->setArguments(array($connection['charset'])); |
|
|
109 |
$mysqlSessionInit->setPublic(false); |
|
|
110 |
$mysqlSessionInit->addTag('doctrine.event_subscriber', array('connection' => $name)); |
|
|
111 |
|
|
|
112 |
$container->setDefinition( |
|
|
113 |
sprintf('doctrine.dbal.%s_connection.events.mysqlsessioninit', $name), |
|
|
114 |
$mysqlSessionInit |
|
|
115 |
); |
|
|
116 |
unset($connection['charset']); |
|
|
117 |
} |
|
|
118 |
} |
|
|
119 |
|
|
|
120 |
$options = $this->getConnectionOptions($connection); |
|
|
121 |
|
|
|
122 |
$container |
|
|
123 |
->setDefinition(sprintf('doctrine.dbal.%s_connection', $name), new DefinitionDecorator('doctrine.dbal.connection')) |
|
|
124 |
->setArguments(array( |
|
|
125 |
$options, |
|
|
126 |
new Reference(sprintf('doctrine.dbal.%s_connection.configuration', $name)), |
|
|
127 |
new Reference(sprintf('doctrine.dbal.%s_connection.event_manager', $name)), |
|
|
128 |
$connection['mapping_types'], |
|
|
129 |
)) |
|
|
130 |
; |
|
|
131 |
} |
|
|
132 |
|
|
|
133 |
protected function getConnectionOptions($connection) |
|
|
134 |
{ |
|
|
135 |
$options = $connection; |
|
|
136 |
|
|
|
137 |
if (isset($options['platform_service'])) { |
|
|
138 |
$options['platform'] = new Reference($options['platform_service']); |
|
|
139 |
unset($options['platform_service']); |
|
|
140 |
} |
|
|
141 |
unset($options['mapping_types']); |
|
|
142 |
|
|
|
143 |
foreach (array( |
|
|
144 |
'options' => 'driverOptions', |
|
|
145 |
'driver_class' => 'driverClass', |
|
|
146 |
'wrapper_class' => 'wrapperClass', |
|
|
147 |
) as $old => $new) { |
|
|
148 |
if (isset($options[$old])) { |
|
|
149 |
$options[$new] = $options[$old]; |
|
|
150 |
unset($options[$old]); |
|
|
151 |
} |
|
|
152 |
} |
|
|
153 |
|
|
|
154 |
return $options; |
|
|
155 |
} |
|
|
156 |
|
|
|
157 |
/** |
|
|
158 |
* Loads the Doctrine ORM configuration. |
|
|
159 |
* |
|
|
160 |
* Usage example: |
|
|
161 |
* |
|
|
162 |
* <doctrine:orm id="mydm" connection="myconn" /> |
|
|
163 |
* |
|
|
164 |
* @param array $config An array of configuration settings |
|
|
165 |
* @param ContainerBuilder $container A ContainerBuilder instance |
|
|
166 |
*/ |
|
|
167 |
protected function ormLoad(array $config, ContainerBuilder $container) |
|
|
168 |
{ |
|
|
169 |
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); |
|
|
170 |
$loader->load('orm.xml'); |
|
|
171 |
|
|
|
172 |
$this->entityManagers = array(); |
|
|
173 |
foreach (array_keys($config['entity_managers']) as $name) { |
|
|
174 |
$this->entityManagers[$name] = sprintf('doctrine.orm.%s_entity_manager', $name); |
|
|
175 |
} |
|
|
176 |
$container->setParameter('doctrine.entity_managers', $this->entityManagers); |
|
|
177 |
|
|
|
178 |
if (empty($config['default_entity_manager'])) { |
|
|
179 |
$tmp = array_keys($this->entityManagers); |
|
|
180 |
$config['default_entity_manager'] = reset($tmp); |
|
|
181 |
} |
|
|
182 |
$container->setParameter('doctrine.default_entity_manager', $config['default_entity_manager']); |
|
|
183 |
|
|
|
184 |
$options = array('auto_generate_proxy_classes', 'proxy_dir', 'proxy_namespace'); |
|
|
185 |
foreach ($options as $key) { |
|
|
186 |
$container->setParameter('doctrine.orm.'.$key, $config[$key]); |
|
|
187 |
} |
|
|
188 |
|
|
|
189 |
$container->setAlias('doctrine.orm.entity_manager', sprintf('doctrine.orm.%s_entity_manager', $config['default_entity_manager'])); |
|
|
190 |
|
|
|
191 |
foreach ($config['entity_managers'] as $name => $entityManager) { |
|
|
192 |
$entityManager['name'] = $name; |
|
|
193 |
$this->loadOrmEntityManager($entityManager, $container); |
|
|
194 |
} |
|
|
195 |
} |
|
|
196 |
|
|
|
197 |
/** |
|
|
198 |
* Loads a configured ORM entity manager. |
|
|
199 |
* |
|
|
200 |
* @param array $entityManager A configured ORM entity manager. |
|
|
201 |
* @param ContainerBuilder $container A ContainerBuilder instance |
|
|
202 |
*/ |
|
|
203 |
protected function loadOrmEntityManager(array $entityManager, ContainerBuilder $container) |
|
|
204 |
{ |
|
|
205 |
if ($entityManager['auto_mapping'] && count($this->entityManagers) > 1) { |
|
|
206 |
throw new \LogicException('You cannot enable "auto_mapping" when several entity managers are defined.'); |
|
|
207 |
} |
|
|
208 |
|
|
|
209 |
$ormConfigDef = $container->setDefinition(sprintf('doctrine.orm.%s_configuration', $entityManager['name']), new DefinitionDecorator('doctrine.orm.configuration')); |
|
|
210 |
|
|
|
211 |
$this->loadOrmEntityManagerMappingInformation($entityManager, $ormConfigDef, $container); |
|
|
212 |
$this->loadOrmCacheDrivers($entityManager, $container); |
|
|
213 |
|
|
|
214 |
$methods = array( |
|
|
215 |
'setMetadataCacheImpl' => new Reference(sprintf('doctrine.orm.%s_metadata_cache', $entityManager['name'])), |
|
|
216 |
'setQueryCacheImpl' => new Reference(sprintf('doctrine.orm.%s_query_cache', $entityManager['name'])), |
|
|
217 |
'setResultCacheImpl' => new Reference(sprintf('doctrine.orm.%s_result_cache', $entityManager['name'])), |
|
|
218 |
'setMetadataDriverImpl' => new Reference('doctrine.orm.'.$entityManager['name'].'_metadata_driver'), |
|
|
219 |
'setProxyDir' => '%doctrine.orm.proxy_dir%', |
|
|
220 |
'setProxyNamespace' => '%doctrine.orm.proxy_namespace%', |
|
|
221 |
'setAutoGenerateProxyClasses' => '%doctrine.orm.auto_generate_proxy_classes%', |
|
|
222 |
'setClassMetadataFactoryName' => $entityManager['class_metadata_factory_name'], |
|
|
223 |
); |
|
|
224 |
foreach ($methods as $method => $arg) { |
|
|
225 |
$ormConfigDef->addMethodCall($method, array($arg)); |
|
|
226 |
} |
|
|
227 |
|
|
|
228 |
foreach ($entityManager['hydrators'] as $name => $class) { |
|
|
229 |
$ormConfigDef->addMethodCall('addCustomHydrationMode', array($name, $class)); |
|
|
230 |
} |
|
|
231 |
|
|
|
232 |
if (!empty($entityManager['dql'])) { |
|
|
233 |
foreach ($entityManager['dql']['string_functions'] as $name => $function) { |
|
|
234 |
$ormConfigDef->addMethodCall('addCustomStringFunction', array($name, $function)); |
|
|
235 |
} |
|
|
236 |
foreach ($entityManager['dql']['numeric_functions'] as $name => $function) { |
|
|
237 |
$ormConfigDef->addMethodCall('addCustomNumericFunction', array($name, $function)); |
|
|
238 |
} |
|
|
239 |
foreach ($entityManager['dql']['datetime_functions'] as $name => $function) { |
|
|
240 |
$ormConfigDef->addMethodCall('addCustomDatetimeFunction', array($name, $function)); |
|
|
241 |
} |
|
|
242 |
} |
|
|
243 |
|
|
|
244 |
if (!isset($entityManager['connection'])) { |
|
|
245 |
$entityManager['connection'] = $this->defaultConnection; |
|
|
246 |
} |
|
|
247 |
|
|
|
248 |
$container |
|
|
249 |
->setDefinition(sprintf('doctrine.orm.%s_entity_manager', $entityManager['name']), new DefinitionDecorator('doctrine.orm.entity_manager.abstract')) |
|
|
250 |
->setArguments(array( |
|
|
251 |
new Reference(sprintf('doctrine.dbal.%s_connection', $entityManager['connection'])), |
|
|
252 |
new Reference(sprintf('doctrine.orm.%s_configuration', $entityManager['name'])) |
|
|
253 |
)) |
|
|
254 |
; |
|
|
255 |
|
|
|
256 |
$container->setAlias( |
|
|
257 |
sprintf('doctrine.orm.%s_entity_manager.event_manager', $entityManager['name']), |
|
|
258 |
new Alias(sprintf('doctrine.dbal.%s_connection.event_manager', $entityManager['connection']), false) |
|
|
259 |
); |
|
|
260 |
} |
|
|
261 |
|
|
|
262 |
/** |
|
|
263 |
* Loads an ORM entity managers bundle mapping information. |
|
|
264 |
* |
|
|
265 |
* There are two distinct configuration possibilities for mapping information: |
|
|
266 |
* |
|
|
267 |
* 1. Specify a bundle and optionally details where the entity and mapping information reside. |
|
|
268 |
* 2. Specify an arbitrary mapping location. |
|
|
269 |
* |
|
|
270 |
* @example |
|
|
271 |
* |
|
|
272 |
* doctrine.orm: |
|
|
273 |
* mappings: |
|
|
274 |
* MyBundle1: ~ |
|
|
275 |
* MyBundle2: yml |
|
|
276 |
* MyBundle3: { type: annotation, dir: Entities/ } |
|
|
277 |
* MyBundle4: { type: xml, dir: Resources/config/doctrine/mapping } |
|
|
278 |
* MyBundle5: |
|
|
279 |
* type: yml |
|
|
280 |
* dir: [bundle-mappings1/, bundle-mappings2/] |
|
|
281 |
* alias: BundleAlias |
|
|
282 |
* arbitrary_key: |
|
|
283 |
* type: xml |
|
|
284 |
* dir: %kernel.dir%/../src/vendor/DoctrineExtensions/lib/DoctrineExtensions/Entities |
|
|
285 |
* prefix: DoctrineExtensions\Entities\ |
|
|
286 |
* alias: DExt |
|
|
287 |
* |
|
|
288 |
* In the case of bundles everything is really optional (which leads to autodetection for this bundle) but |
|
|
289 |
* in the mappings key everything except alias is a required argument. |
|
|
290 |
* |
|
|
291 |
* @param array $entityManager A configured ORM entity manager. |
|
|
292 |
* @param ContainerBuilder $container A ContainerBuilder instance |
|
|
293 |
*/ |
|
|
294 |
protected function loadOrmEntityManagerMappingInformation(array $entityManager, Definition $ormConfigDef, ContainerBuilder $container) |
|
|
295 |
{ |
|
|
296 |
// reset state of drivers and alias map. They are only used by this methods and children. |
|
|
297 |
$this->drivers = array(); |
|
|
298 |
$this->aliasMap = array(); |
|
|
299 |
|
|
|
300 |
$this->loadMappingInformation($entityManager, $container); |
|
|
301 |
$this->registerMappingDrivers($entityManager, $container); |
|
|
302 |
|
|
|
303 |
$ormConfigDef->addMethodCall('setEntityNamespaces', array($this->aliasMap)); |
|
|
304 |
} |
|
|
305 |
|
|
|
306 |
protected function getObjectManagerElementName($name) |
|
|
307 |
{ |
|
|
308 |
return 'doctrine.orm.'.$name; |
|
|
309 |
} |
|
|
310 |
|
|
|
311 |
protected function getMappingObjectDefaultName() |
|
|
312 |
{ |
|
|
313 |
return 'Entity'; |
|
|
314 |
} |
|
|
315 |
|
|
|
316 |
protected function getMappingResourceConfigDirectory() |
|
|
317 |
{ |
|
|
318 |
return 'Resources/config/doctrine'; |
|
|
319 |
} |
|
|
320 |
|
|
|
321 |
protected function getMappingResourceExtension() |
|
|
322 |
{ |
|
|
323 |
return 'orm'; |
|
|
324 |
} |
|
|
325 |
|
|
|
326 |
/** |
|
|
327 |
* Loads a configured entity managers cache drivers. |
|
|
328 |
* |
|
|
329 |
* @param array $entityManager A configured ORM entity manager. |
|
|
330 |
* @param ContainerBuilder $container A ContainerBuilder instance |
|
|
331 |
*/ |
|
|
332 |
protected function loadOrmCacheDrivers(array $entityManager, ContainerBuilder $container) |
|
|
333 |
{ |
|
|
334 |
$this->loadOrmEntityManagerCacheDriver($entityManager, $container, 'metadata_cache'); |
|
|
335 |
$this->loadOrmEntityManagerCacheDriver($entityManager, $container, 'result_cache'); |
|
|
336 |
$this->loadOrmEntityManagerCacheDriver($entityManager, $container, 'query_cache'); |
|
|
337 |
} |
|
|
338 |
|
|
|
339 |
/** |
|
|
340 |
* Loads a configured entity managers metadata, query or result cache driver. |
|
|
341 |
* |
|
|
342 |
* @param array $entityManager A configured ORM entity manager. |
|
|
343 |
* @param ContainerBuilder $container A ContainerBuilder instance |
|
|
344 |
* @param string $cacheName |
|
|
345 |
*/ |
|
|
346 |
protected function loadOrmEntityManagerCacheDriver(array $entityManager, ContainerBuilder $container, $cacheName) |
|
|
347 |
{ |
|
|
348 |
$cacheDriverService = sprintf('doctrine.orm.%s_%s', $entityManager['name'], $cacheName); |
|
|
349 |
|
|
|
350 |
$driver = $cacheName."_driver"; |
|
|
351 |
$cacheDef = $this->getEntityManagerCacheDefinition($entityManager, $entityManager[$driver], $container); |
|
|
352 |
$container->setDefinition($cacheDriverService, $cacheDef); |
|
|
353 |
} |
|
|
354 |
|
|
|
355 |
/** |
|
|
356 |
* Gets an entity manager cache driver definition for metadata, query and result caches. |
|
|
357 |
* |
|
|
358 |
* @param array $entityManager The array configuring an entity manager. |
|
|
359 |
* @param array $cacheDriver The cache driver configuration. |
|
|
360 |
* @param ContainerBuilder $container |
|
|
361 |
* @return Definition $cacheDef |
|
|
362 |
*/ |
|
|
363 |
protected function getEntityManagerCacheDefinition(array $entityManager, $cacheDriver, ContainerBuilder $container) |
|
|
364 |
{ |
|
|
365 |
switch ($cacheDriver['type']) { |
|
|
366 |
case 'memcache': |
|
|
367 |
$memcacheClass = !empty($cacheDriver['class']) ? $cacheDriver['class'] : '%doctrine.orm.cache.memcache.class%'; |
|
|
368 |
$memcacheInstanceClass = !empty($cacheDriver['instance_class']) ? $cacheDriver['instance_class'] : '%doctrine.orm.cache.memcache_instance.class%'; |
|
|
369 |
$memcacheHost = !empty($cacheDriver['host']) ? $cacheDriver['host'] : '%doctrine.orm.cache.memcache_host%'; |
|
|
370 |
$memcachePort = !empty($cacheDriver['port']) ? $cacheDriver['port'] : '%doctrine.orm.cache.memcache_port%'; |
|
|
371 |
$cacheDef = new Definition($memcacheClass); |
|
|
372 |
$memcacheInstance = new Definition($memcacheInstanceClass); |
|
|
373 |
$memcacheInstance->addMethodCall('connect', array( |
|
|
374 |
$memcacheHost, $memcachePort |
|
|
375 |
)); |
|
|
376 |
$container->setDefinition(sprintf('doctrine.orm.%s_memcache_instance', $entityManager['name']), $memcacheInstance); |
|
|
377 |
$cacheDef->addMethodCall('setMemcache', array(new Reference(sprintf('doctrine.orm.%s_memcache_instance', $entityManager['name'])))); |
|
|
378 |
break; |
|
|
379 |
case 'apc': |
|
|
380 |
case 'array': |
|
|
381 |
case 'xcache': |
|
|
382 |
$cacheDef = new Definition('%'.sprintf('doctrine.orm.cache.%s.class', $cacheDriver['type']).'%'); |
|
|
383 |
break; |
|
|
384 |
default: |
|
|
385 |
throw new \InvalidArgumentException(sprintf('"%s" is an unrecognized Doctrine cache driver.', $cacheDriver['type'])); |
|
|
386 |
} |
|
|
387 |
|
|
|
388 |
$cacheDef->setPublic(false); |
|
|
389 |
// generate a unique namespace for the given application |
|
|
390 |
$namespace = 'sf2orm_'.$entityManager['name'].'_'.md5($container->getParameter('kernel.root_dir').$container->getParameter('kernel.environment')); |
|
|
391 |
$cacheDef->addMethodCall('setNamespace', array($namespace)); |
|
|
392 |
|
|
|
393 |
return $cacheDef; |
|
|
394 |
} |
|
|
395 |
|
|
|
396 |
/** |
|
|
397 |
* Returns the base path for the XSD files. |
|
|
398 |
* |
|
|
399 |
* @return string The XSD base path |
|
|
400 |
*/ |
|
|
401 |
public function getXsdValidationBasePath() |
|
|
402 |
{ |
|
|
403 |
return __DIR__.'/../Resources/config/schema'; |
|
|
404 |
} |
|
|
405 |
|
|
|
406 |
/** |
|
|
407 |
* Returns the namespace to be used for this extension (XML namespace). |
|
|
408 |
* |
|
|
409 |
* @return string The XML namespace |
|
|
410 |
*/ |
|
|
411 |
public function getNamespace() |
|
|
412 |
{ |
|
|
413 |
return 'http://symfony.com/schema/dic/doctrine'; |
|
|
414 |
} |
|
|
415 |
} |