Configuration.php 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. <?php
  2. namespace Doctrine\Bundle\DoctrineBundle\DependencyInjection;
  3. use Doctrine\ORM\EntityManager;
  4. use ReflectionClass;
  5. use Symfony\Component\Config\Definition\BaseNode;
  6. use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
  7. use Symfony\Component\Config\Definition\Builder\NodeDefinition;
  8. use Symfony\Component\Config\Definition\Builder\TreeBuilder;
  9. use Symfony\Component\Config\Definition\ConfigurationInterface;
  10. use Symfony\Component\DependencyInjection\Exception\LogicException;
  11. use function array_key_exists;
  12. use function assert;
  13. use function class_exists;
  14. use function constant;
  15. use function in_array;
  16. use function is_array;
  17. use function is_bool;
  18. use function is_int;
  19. use function is_string;
  20. use function key;
  21. use function method_exists;
  22. use function reset;
  23. use function strlen;
  24. use function strpos;
  25. use function strtoupper;
  26. use function substr;
  27. use function trigger_error;
  28. use const E_USER_DEPRECATED;
  29. /**
  30. * This class contains the configuration information for the bundle
  31. *
  32. * This information is solely responsible for how the different configuration
  33. * sections are normalized, and merged.
  34. */
  35. class Configuration implements ConfigurationInterface
  36. {
  37. /** @var bool */
  38. private $debug;
  39. /**
  40. * @param bool $debug Whether to use the debug mode
  41. */
  42. public function __construct(bool $debug)
  43. {
  44. $this->debug = $debug;
  45. }
  46. public function getConfigTreeBuilder(): TreeBuilder
  47. {
  48. $treeBuilder = new TreeBuilder('doctrine');
  49. $rootNode = $treeBuilder->getRootNode();
  50. $this->addDbalSection($rootNode);
  51. $this->addOrmSection($rootNode);
  52. return $treeBuilder;
  53. }
  54. /**
  55. * Add DBAL section to configuration tree
  56. */
  57. private function addDbalSection(ArrayNodeDefinition $node): void
  58. {
  59. $node
  60. ->children()
  61. ->arrayNode('dbal')
  62. ->beforeNormalization()
  63. ->ifTrue(static function ($v) {
  64. return is_array($v) && ! array_key_exists('connections', $v) && ! array_key_exists('connection', $v);
  65. })
  66. ->then(static function ($v) {
  67. // Key that should not be rewritten to the connection config
  68. $excludedKeys = ['default_connection' => true, 'types' => true, 'type' => true];
  69. $connection = [];
  70. foreach ($v as $key => $value) {
  71. if (isset($excludedKeys[$key])) {
  72. continue;
  73. }
  74. $connection[$key] = $v[$key];
  75. unset($v[$key]);
  76. }
  77. $v['default_connection'] = isset($v['default_connection']) ? (string) $v['default_connection'] : 'default';
  78. $v['connections'] = [$v['default_connection'] => $connection];
  79. return $v;
  80. })
  81. ->end()
  82. ->children()
  83. ->scalarNode('default_connection')->end()
  84. ->end()
  85. ->fixXmlConfig('type')
  86. ->children()
  87. ->arrayNode('types')
  88. ->useAttributeAsKey('name')
  89. ->prototype('array')
  90. ->beforeNormalization()
  91. ->ifString()
  92. ->then(static function ($v) {
  93. return ['class' => $v];
  94. })
  95. ->end()
  96. ->children()
  97. ->scalarNode('class')->isRequired()->end()
  98. ->booleanNode('commented')
  99. ->setDeprecated(
  100. ...$this->getDeprecationMsg('The doctrine-bundle type commenting features were removed; the corresponding config parameter was deprecated in 2.0 and will be dropped in 3.0.', '2.0')
  101. )
  102. ->end()
  103. ->end()
  104. ->end()
  105. ->end()
  106. ->end()
  107. ->fixXmlConfig('connection')
  108. ->append($this->getDbalConnectionsNode())
  109. ->end();
  110. }
  111. /**
  112. * Return the dbal connections node
  113. */
  114. private function getDbalConnectionsNode(): ArrayNodeDefinition
  115. {
  116. $treeBuilder = new TreeBuilder('connections');
  117. $node = $treeBuilder->getRootNode();
  118. $connectionNode = $node
  119. ->requiresAtLeastOneElement()
  120. ->useAttributeAsKey('name')
  121. ->prototype('array');
  122. assert($connectionNode instanceof ArrayNodeDefinition);
  123. $this->configureDbalDriverNode($connectionNode);
  124. $connectionNode
  125. ->fixXmlConfig('option')
  126. ->fixXmlConfig('mapping_type')
  127. ->fixXmlConfig('slave')
  128. ->fixXmlConfig('replica')
  129. ->fixXmlConfig('shard')
  130. ->fixXmlConfig('default_table_option')
  131. ->children()
  132. ->scalarNode('driver')->defaultValue('pdo_mysql')->end()
  133. ->scalarNode('platform_service')->end()
  134. ->booleanNode('auto_commit')->end()
  135. ->scalarNode('schema_filter')->end()
  136. ->booleanNode('logging')->defaultValue($this->debug)->end()
  137. ->booleanNode('profiling')->defaultValue($this->debug)->end()
  138. ->booleanNode('profiling_collect_backtrace')
  139. ->defaultValue(false)
  140. ->info('Enables collecting backtraces when profiling is enabled')
  141. ->end()
  142. ->booleanNode('profiling_collect_schema_errors')
  143. ->defaultValue(true)
  144. ->info('Enables collecting schema errors when profiling is enabled')
  145. ->end()
  146. ->scalarNode('server_version')->end()
  147. ->scalarNode('driver_class')->end()
  148. ->scalarNode('wrapper_class')->end()
  149. ->scalarNode('shard_manager_class')->end()
  150. ->scalarNode('shard_choser')->end()
  151. ->scalarNode('shard_choser_service')->end()
  152. ->booleanNode('keep_slave')
  153. ->setDeprecated(
  154. ...$this->getDeprecationMsg('The "keep_slave" configuration key is deprecated since doctrine-bundle 2.2. Use the "keep_replica" configuration key instead.', '2.2')
  155. )
  156. ->end()
  157. ->booleanNode('keep_replica')->end()
  158. ->arrayNode('options')
  159. ->useAttributeAsKey('key')
  160. ->prototype('variable')->end()
  161. ->end()
  162. ->arrayNode('mapping_types')
  163. ->useAttributeAsKey('name')
  164. ->prototype('scalar')->end()
  165. ->end()
  166. ->arrayNode('default_table_options')
  167. ->info("This option is used by the schema-tool and affects generated SQL. Possible keys include 'charset','collate', and 'engine'.")
  168. ->useAttributeAsKey('name')
  169. ->prototype('scalar')->end()
  170. ->end()
  171. ->end();
  172. // dbal < 2.11
  173. $slaveNode = $connectionNode
  174. ->children()
  175. ->arrayNode('slaves')
  176. ->setDeprecated(
  177. ...$this->getDeprecationMsg('The "slaves" configuration key will be renamed to "replicas" in doctrine-bundle 3.0. "slaves" is deprecated since doctrine-bundle 2.2.', '2.2')
  178. )
  179. ->useAttributeAsKey('name')
  180. ->prototype('array');
  181. $this->configureDbalDriverNode($slaveNode);
  182. // dbal >= 2.11
  183. $replicaNode = $connectionNode
  184. ->children()
  185. ->arrayNode('replicas')
  186. ->useAttributeAsKey('name')
  187. ->prototype('array');
  188. $this->configureDbalDriverNode($replicaNode);
  189. $shardNode = $connectionNode
  190. ->children()
  191. ->arrayNode('shards')
  192. ->prototype('array');
  193. // TODO: Remove when https://github.com/psalm/psalm-plugin-symfony/pull/168 is released
  194. assert($shardNode instanceof ArrayNodeDefinition);
  195. $shardNode
  196. ->children()
  197. ->integerNode('id')
  198. ->min(1)
  199. ->isRequired()
  200. ->end()
  201. ->end();
  202. $this->configureDbalDriverNode($shardNode);
  203. return $node;
  204. }
  205. /**
  206. * Adds config keys related to params processed by the DBAL drivers
  207. *
  208. * These keys are available for replica configurations too.
  209. */
  210. private function configureDbalDriverNode(ArrayNodeDefinition $node): void
  211. {
  212. $node
  213. ->children()
  214. ->scalarNode('url')->info('A URL with connection information; any parameter value parsed from this string will override explicitly set parameters')->end()
  215. ->scalarNode('dbname')->end()
  216. ->scalarNode('host')->info('Defaults to "localhost" at runtime.')->end()
  217. ->scalarNode('port')->info('Defaults to null at runtime.')->end()
  218. ->scalarNode('user')->info('Defaults to "root" at runtime.')->end()
  219. ->scalarNode('password')->info('Defaults to null at runtime.')->end()
  220. ->booleanNode('override_url')->defaultValue(false)->info('Allows overriding parts of the "url" parameter with dbname, host, port, user, and/or password parameters.')->end()
  221. ->scalarNode('application_name')->end()
  222. ->scalarNode('charset')->end()
  223. ->scalarNode('path')->end()
  224. ->booleanNode('memory')->end()
  225. ->scalarNode('unix_socket')->info('The unix socket to use for MySQL')->end()
  226. ->booleanNode('persistent')->info('True to use as persistent connection for the ibm_db2 driver')->end()
  227. ->scalarNode('protocol')->info('The protocol to use for the ibm_db2 driver (default to TCPIP if omitted)')->end()
  228. ->booleanNode('service')
  229. ->info('True to use SERVICE_NAME as connection parameter instead of SID for Oracle')
  230. ->end()
  231. ->scalarNode('servicename')
  232. ->info(
  233. 'Overrules dbname parameter if given and used as SERVICE_NAME or SID connection parameter ' .
  234. 'for Oracle depending on the service parameter.'
  235. )
  236. ->end()
  237. ->scalarNode('sessionMode')
  238. ->info('The session mode to use for the oci8 driver')
  239. ->end()
  240. ->scalarNode('server')
  241. ->info('The name of a running database server to connect to for SQL Anywhere.')
  242. ->end()
  243. ->scalarNode('default_dbname')
  244. ->info(
  245. 'Override the default database (postgres) to connect to for PostgreSQL connexion.'
  246. )
  247. ->end()
  248. ->scalarNode('sslmode')
  249. ->info(
  250. 'Determines whether or with what priority a SSL TCP/IP connection will be negotiated with ' .
  251. 'the server for PostgreSQL.'
  252. )
  253. ->end()
  254. ->scalarNode('sslrootcert')
  255. ->info(
  256. 'The name of a file containing SSL certificate authority (CA) certificate(s). ' .
  257. 'If the file exists, the server\'s certificate will be verified to be signed by one of these authorities.'
  258. )
  259. ->end()
  260. ->scalarNode('sslcert')
  261. ->info(
  262. 'The path to the SSL client certificate file for PostgreSQL.'
  263. )
  264. ->end()
  265. ->scalarNode('sslkey')
  266. ->info(
  267. 'The path to the SSL client key file for PostgreSQL.'
  268. )
  269. ->end()
  270. ->scalarNode('sslcrl')
  271. ->info(
  272. 'The file name of the SSL certificate revocation list for PostgreSQL.'
  273. )
  274. ->end()
  275. ->booleanNode('pooled')->info('True to use a pooled server with the oci8/pdo_oracle driver')->end()
  276. ->booleanNode('MultipleActiveResultSets')->info('Configuring MultipleActiveResultSets for the pdo_sqlsrv driver')->end()
  277. ->booleanNode('use_savepoints')->info('Use savepoints for nested transactions')->end()
  278. ->scalarNode('instancename')
  279. ->info(
  280. 'Optional parameter, complete whether to add the INSTANCE_NAME parameter in the connection.' .
  281. ' It is generally used to connect to an Oracle RAC server to select the name' .
  282. ' of a particular instance.'
  283. )
  284. ->end()
  285. ->scalarNode('connectstring')
  286. ->info(
  287. 'Complete Easy Connect connection descriptor, see https://docs.oracle.com/database/121/NETAG/naming.htm.' .
  288. 'When using this option, you will still need to provide the user and password parameters, but the other ' .
  289. 'parameters will no longer be used. Note that when using this parameter, the getHost and getPort methods' .
  290. ' from Doctrine\DBAL\Connection will no longer function as expected.'
  291. )
  292. ->end()
  293. ->end()
  294. ->beforeNormalization()
  295. ->ifTrue(static function ($v) {
  296. return ! isset($v['sessionMode']) && isset($v['session_mode']);
  297. })
  298. ->then(static function ($v) {
  299. $v['sessionMode'] = $v['session_mode'];
  300. unset($v['session_mode']);
  301. return $v;
  302. })
  303. ->end()
  304. ->beforeNormalization()
  305. ->ifTrue(static function ($v) {
  306. return ! isset($v['MultipleActiveResultSets']) && isset($v['multiple_active_result_sets']);
  307. })
  308. ->then(static function ($v) {
  309. $v['MultipleActiveResultSets'] = $v['multiple_active_result_sets'];
  310. unset($v['multiple_active_result_sets']);
  311. return $v;
  312. })
  313. ->end()
  314. ->beforeNormalization()
  315. ->ifTrue(static function ($v) {
  316. return empty($v['override_url']) && isset($v['url']);
  317. })
  318. ->then(static function ($v) {
  319. @trigger_error('Not setting doctrine.dbal.override_url to true is deprecated. True is the only value that will be supported in doctrine-bundle 3.0.', E_USER_DEPRECATED);
  320. return $v;
  321. })
  322. ->end();
  323. }
  324. /**
  325. * Add the ORM section to configuration tree
  326. */
  327. private function addOrmSection(ArrayNodeDefinition $node): void
  328. {
  329. $node
  330. ->children()
  331. ->arrayNode('orm')
  332. ->beforeNormalization()
  333. ->ifTrue(static function ($v) {
  334. if (! empty($v) && ! class_exists(EntityManager::class)) {
  335. throw new LogicException('The doctrine/orm package is required when the doctrine.orm config is set.');
  336. }
  337. return $v === null || (is_array($v) && ! array_key_exists('entity_managers', $v) && ! array_key_exists('entity_manager', $v));
  338. })
  339. ->then(static function ($v) {
  340. $v = (array) $v;
  341. // Key that should not be rewritten to the connection config
  342. $excludedKeys = [
  343. 'default_entity_manager' => true,
  344. 'auto_generate_proxy_classes' => true,
  345. 'proxy_dir' => true,
  346. 'proxy_namespace' => true,
  347. 'resolve_target_entities' => true,
  348. 'resolve_target_entity' => true,
  349. ];
  350. $entityManager = [];
  351. foreach ($v as $key => $value) {
  352. if (isset($excludedKeys[$key])) {
  353. continue;
  354. }
  355. $entityManager[$key] = $v[$key];
  356. unset($v[$key]);
  357. }
  358. $v['default_entity_manager'] = isset($v['default_entity_manager']) ? (string) $v['default_entity_manager'] : 'default';
  359. $v['entity_managers'] = [$v['default_entity_manager'] => $entityManager];
  360. return $v;
  361. })
  362. ->end()
  363. ->children()
  364. ->scalarNode('default_entity_manager')->end()
  365. ->scalarNode('auto_generate_proxy_classes')->defaultValue(false)
  366. ->info('Auto generate mode possible values are: "NEVER", "ALWAYS", "FILE_NOT_EXISTS", "EVAL"')
  367. ->validate()
  368. ->ifTrue(function ($v) {
  369. $generationModes = $this->getAutoGenerateModes();
  370. if (is_int($v) && in_array($v, $generationModes['values']/*array(0, 1, 2, 3)*/)) {
  371. return false;
  372. }
  373. if (is_bool($v)) {
  374. return false;
  375. }
  376. if (is_string($v)) {
  377. if (in_array(strtoupper($v), $generationModes['names']/*array('NEVER', 'ALWAYS', 'FILE_NOT_EXISTS', 'EVAL')*/)) {
  378. return false;
  379. }
  380. }
  381. return true;
  382. })
  383. ->thenInvalid('Invalid auto generate mode value %s')
  384. ->end()
  385. ->validate()
  386. ->ifString()
  387. ->then(static function ($v) {
  388. return constant('Doctrine\Common\Proxy\AbstractProxyFactory::AUTOGENERATE_' . strtoupper($v));
  389. })
  390. ->end()
  391. ->end()
  392. ->scalarNode('proxy_dir')->defaultValue('%kernel.cache_dir%/doctrine/orm/Proxies')->end()
  393. ->scalarNode('proxy_namespace')->defaultValue('Proxies')->end()
  394. ->end()
  395. ->fixXmlConfig('entity_manager')
  396. ->append($this->getOrmEntityManagersNode())
  397. ->fixXmlConfig('resolve_target_entity', 'resolve_target_entities')
  398. ->append($this->getOrmTargetEntityResolverNode())
  399. ->end()
  400. ->end();
  401. }
  402. /**
  403. * Return ORM target entity resolver node
  404. */
  405. private function getOrmTargetEntityResolverNode(): NodeDefinition
  406. {
  407. $treeBuilder = new TreeBuilder('resolve_target_entities');
  408. $node = $treeBuilder->getRootNode();
  409. $node
  410. ->useAttributeAsKey('interface')
  411. ->prototype('scalar')
  412. ->cannotBeEmpty()
  413. ->end();
  414. return $node;
  415. }
  416. /**
  417. * Return ORM entity listener node
  418. */
  419. private function getOrmEntityListenersNode(): NodeDefinition
  420. {
  421. $treeBuilder = new TreeBuilder('entity_listeners');
  422. $node = $treeBuilder->getRootNode();
  423. $normalizer = static function ($mappings) {
  424. $entities = [];
  425. foreach ($mappings as $entityClass => $mapping) {
  426. $listeners = [];
  427. foreach ($mapping as $listenerClass => $listenerEvent) {
  428. $events = [];
  429. foreach ($listenerEvent as $eventType => $eventMapping) {
  430. if ($eventMapping === null) {
  431. $eventMapping = [null];
  432. }
  433. foreach ($eventMapping as $method) {
  434. $events[] = [
  435. 'type' => $eventType,
  436. 'method' => $method,
  437. ];
  438. }
  439. }
  440. $listeners[] = [
  441. 'class' => $listenerClass,
  442. 'event' => $events,
  443. ];
  444. }
  445. $entities[] = [
  446. 'class' => $entityClass,
  447. 'listener' => $listeners,
  448. ];
  449. }
  450. return ['entities' => $entities];
  451. };
  452. $node
  453. ->beforeNormalization()
  454. // Yaml normalization
  455. ->ifTrue(static function ($v) {
  456. return is_array(reset($v)) && is_string(key(reset($v)));
  457. })
  458. ->then($normalizer)
  459. ->end()
  460. ->fixXmlConfig('entity', 'entities')
  461. ->children()
  462. ->arrayNode('entities')
  463. ->useAttributeAsKey('class')
  464. ->prototype('array')
  465. ->fixXmlConfig('listener')
  466. ->children()
  467. ->arrayNode('listeners')
  468. ->useAttributeAsKey('class')
  469. ->prototype('array')
  470. ->fixXmlConfig('event')
  471. ->children()
  472. ->arrayNode('events')
  473. ->prototype('array')
  474. ->children()
  475. ->scalarNode('type')->end()
  476. ->scalarNode('method')->defaultNull()->end()
  477. ->end()
  478. ->end()
  479. ->end()
  480. ->end()
  481. ->end()
  482. ->end()
  483. ->end()
  484. ->end()
  485. ->end()
  486. ->end();
  487. return $node;
  488. }
  489. /**
  490. * Return ORM entity manager node
  491. */
  492. private function getOrmEntityManagersNode(): ArrayNodeDefinition
  493. {
  494. $treeBuilder = new TreeBuilder('entity_managers');
  495. $node = $treeBuilder->getRootNode();
  496. $node
  497. ->requiresAtLeastOneElement()
  498. ->useAttributeAsKey('name')
  499. ->prototype('array')
  500. ->addDefaultsIfNotSet()
  501. ->append($this->getOrmCacheDriverNode('query_cache_driver'))
  502. ->append($this->getOrmCacheDriverNode('metadata_cache_driver'))
  503. ->append($this->getOrmCacheDriverNode('result_cache_driver'))
  504. ->append($this->getOrmEntityListenersNode())
  505. ->children()
  506. ->scalarNode('connection')->end()
  507. ->scalarNode('class_metadata_factory_name')->defaultValue('Doctrine\ORM\Mapping\ClassMetadataFactory')->end()
  508. ->scalarNode('default_repository_class')->defaultValue('Doctrine\ORM\EntityRepository')->end()
  509. ->scalarNode('auto_mapping')->defaultFalse()->end()
  510. ->scalarNode('naming_strategy')->defaultValue('doctrine.orm.naming_strategy.default')->end()
  511. ->scalarNode('quote_strategy')->defaultValue('doctrine.orm.quote_strategy.default')->end()
  512. ->scalarNode('entity_listener_resolver')->defaultNull()->end()
  513. ->scalarNode('repository_factory')->defaultValue('doctrine.orm.container_repository_factory')->end()
  514. ->end()
  515. ->children()
  516. ->arrayNode('second_level_cache')
  517. ->children()
  518. ->append($this->getOrmCacheDriverNode('region_cache_driver'))
  519. ->scalarNode('region_lock_lifetime')->defaultValue(60)->end()
  520. ->booleanNode('log_enabled')->defaultValue($this->debug)->end()
  521. ->scalarNode('region_lifetime')->defaultValue(3600)->end()
  522. ->booleanNode('enabled')->defaultValue(true)->end()
  523. ->scalarNode('factory')->end()
  524. ->end()
  525. ->fixXmlConfig('region')
  526. ->children()
  527. ->arrayNode('regions')
  528. ->useAttributeAsKey('name')
  529. ->prototype('array')
  530. ->children()
  531. ->append($this->getOrmCacheDriverNode('cache_driver'))
  532. ->scalarNode('lock_path')->defaultValue('%kernel.cache_dir%/doctrine/orm/slc/filelock')->end()
  533. ->scalarNode('lock_lifetime')->defaultValue(60)->end()
  534. ->scalarNode('type')->defaultValue('default')->end()
  535. ->scalarNode('lifetime')->defaultValue(0)->end()
  536. ->scalarNode('service')->end()
  537. ->scalarNode('name')->end()
  538. ->end()
  539. ->end()
  540. ->end()
  541. ->end()
  542. ->fixXmlConfig('logger')
  543. ->children()
  544. ->arrayNode('loggers')
  545. ->useAttributeAsKey('name')
  546. ->prototype('array')
  547. ->children()
  548. ->scalarNode('name')->end()
  549. ->scalarNode('service')->end()
  550. ->end()
  551. ->end()
  552. ->end()
  553. ->end()
  554. ->end()
  555. ->end()
  556. ->fixXmlConfig('hydrator')
  557. ->children()
  558. ->arrayNode('hydrators')
  559. ->useAttributeAsKey('name')
  560. ->prototype('scalar')->end()
  561. ->end()
  562. ->end()
  563. ->fixXmlConfig('mapping')
  564. ->children()
  565. ->arrayNode('mappings')
  566. ->useAttributeAsKey('name')
  567. ->prototype('array')
  568. ->beforeNormalization()
  569. ->ifString()
  570. ->then(static function ($v) {
  571. return ['type' => $v];
  572. })
  573. ->end()
  574. ->treatNullLike([])
  575. ->treatFalseLike(['mapping' => false])
  576. ->performNoDeepMerging()
  577. ->children()
  578. ->scalarNode('mapping')->defaultValue(true)->end()
  579. ->scalarNode('type')->end()
  580. ->scalarNode('dir')->end()
  581. ->scalarNode('alias')->end()
  582. ->scalarNode('prefix')->end()
  583. ->booleanNode('is_bundle')->end()
  584. ->end()
  585. ->end()
  586. ->end()
  587. ->arrayNode('dql')
  588. ->fixXmlConfig('string_function')
  589. ->fixXmlConfig('numeric_function')
  590. ->fixXmlConfig('datetime_function')
  591. ->children()
  592. ->arrayNode('string_functions')
  593. ->useAttributeAsKey('name')
  594. ->prototype('scalar')->end()
  595. ->end()
  596. ->arrayNode('numeric_functions')
  597. ->useAttributeAsKey('name')
  598. ->prototype('scalar')->end()
  599. ->end()
  600. ->arrayNode('datetime_functions')
  601. ->useAttributeAsKey('name')
  602. ->prototype('scalar')->end()
  603. ->end()
  604. ->end()
  605. ->end()
  606. ->end()
  607. ->fixXmlConfig('filter')
  608. ->children()
  609. ->arrayNode('filters')
  610. ->info('Register SQL Filters in the entity manager')
  611. ->useAttributeAsKey('name')
  612. ->prototype('array')
  613. ->beforeNormalization()
  614. ->ifString()
  615. ->then(static function ($v) {
  616. return ['class' => $v];
  617. })
  618. ->end()
  619. ->beforeNormalization()
  620. // The content of the XML node is returned as the "value" key so we need to rename it
  621. ->ifTrue(static function ($v) {
  622. return is_array($v) && isset($v['value']);
  623. })
  624. ->then(static function ($v) {
  625. $v['class'] = $v['value'];
  626. unset($v['value']);
  627. return $v;
  628. })
  629. ->end()
  630. ->fixXmlConfig('parameter')
  631. ->children()
  632. ->scalarNode('class')->isRequired()->end()
  633. ->booleanNode('enabled')->defaultFalse()->end()
  634. ->arrayNode('parameters')
  635. ->useAttributeAsKey('name')
  636. ->prototype('variable')->end()
  637. ->end()
  638. ->end()
  639. ->end()
  640. ->end()
  641. ->end()
  642. ->end();
  643. return $node;
  644. }
  645. /**
  646. * Return a ORM cache driver node for an given entity manager
  647. */
  648. private function getOrmCacheDriverNode(string $name): ArrayNodeDefinition
  649. {
  650. $treeBuilder = new TreeBuilder($name);
  651. $node = $treeBuilder->getRootNode();
  652. $node
  653. ->addDefaultsIfNotSet()
  654. ->beforeNormalization()
  655. ->ifString()
  656. ->then(static function ($v): array {
  657. return ['type' => $v];
  658. })
  659. ->end()
  660. ->children()
  661. ->scalarNode('type')->defaultNull()->end()
  662. ->scalarNode('id')->end()
  663. ->scalarNode('pool')->end()
  664. ->end();
  665. if ($name === 'metadata_cache_driver') {
  666. $node->setDeprecated(...$this->getDeprecationMsg(
  667. 'The "metadata_cache_driver" configuration key is deprecated. PHP Array cache is now automatically registered when %kernel.debug% is false.',
  668. '2.3'
  669. ));
  670. }
  671. return $node;
  672. }
  673. /**
  674. * Find proxy auto generate modes for their names and int values
  675. *
  676. * @return array{names: list<string>, values: list<int>}
  677. */
  678. private function getAutoGenerateModes(): array
  679. {
  680. $constPrefix = 'AUTOGENERATE_';
  681. $prefixLen = strlen($constPrefix);
  682. $refClass = new ReflectionClass('Doctrine\Common\Proxy\AbstractProxyFactory');
  683. $constsArray = $refClass->getConstants();
  684. $namesArray = [];
  685. $valuesArray = [];
  686. foreach ($constsArray as $key => $value) {
  687. if (strpos($key, $constPrefix) !== 0) {
  688. continue;
  689. }
  690. $namesArray[] = substr($key, $prefixLen);
  691. $valuesArray[] = (int) $value;
  692. }
  693. return [
  694. 'names' => $namesArray,
  695. 'values' => $valuesArray,
  696. ];
  697. }
  698. /**
  699. * Returns the correct deprecation param's as an array for setDeprecated.
  700. *
  701. * Symfony/Config v5.1 introduces a deprecation notice when calling
  702. * setDeprecation() with less than 3 args and the getDeprecation method was
  703. * introduced at the same time. By checking if getDeprecation() exists,
  704. * we can determine the correct param count to use when calling setDeprecated.
  705. *
  706. * @return list<string>|array{0:string, 1: numeric-string, string}
  707. */
  708. private function getDeprecationMsg(string $message, string $version): array
  709. {
  710. if (method_exists(BaseNode::class, 'getDeprecation')) {
  711. return [
  712. 'doctrine/doctrine-bundle',
  713. $version,
  714. $message,
  715. ];
  716. }
  717. return [$message];
  718. }
  719. }