vendor/jms/serializer-bundle/DependencyInjection/JMSSerializerExtension.php line 232

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace JMS\SerializerBundle\DependencyInjection;
  4. use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
  5. use JMS\Serializer\Exception\RuntimeException;
  6. use JMS\Serializer\Handler\SubscribingHandlerInterface;
  7. use JMS\Serializer\Metadata\Driver\AttributeDriver\AttributeReader;
  8. use JMS\Serializer\Metadata\Driver\DocBlockDriver;
  9. use JMS\Serializer\Metadata\Driver\TypedPropertiesDriver;
  10. use Symfony\Component\Config\FileLocator;
  11. use Symfony\Component\DependencyInjection\Alias;
  12. use Symfony\Component\DependencyInjection\ContainerBuilder;
  13. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
  14. use Symfony\Component\DependencyInjection\Reference;
  15. use Symfony\Component\Finder\Finder;
  16. use Symfony\Component\HttpKernel\DependencyInjection\ConfigurableExtension;
  17. use Symfony\Component\Stopwatch\Stopwatch;
  18. use Symfony\Component\Templating\Helper\Helper;
  19. class JMSSerializerExtension extends ConfigurableExtension
  20. {
  21. public function loadInternal(array $config, ContainerBuilder $container)
  22. {
  23. $container
  24. ->registerForAutoconfiguration(EventSubscriberInterface::class)
  25. ->addTag('jms_serializer.event_subscriber');
  26. $container
  27. ->registerForAutoconfiguration(SubscribingHandlerInterface::class)
  28. ->addTag('jms_serializer.subscribing_handler');
  29. $loader = new XmlFileLoader($container, new FileLocator([__DIR__ . '/../Resources/config/']));
  30. $loader->load('services.xml');
  31. // Built-in handlers.
  32. $container->getDefinition('jms_serializer.datetime_handler')
  33. ->addArgument($config['handlers']['datetime']['default_format'])
  34. ->addArgument($config['handlers']['datetime']['default_timezone'])
  35. ->addArgument($config['handlers']['datetime']['cdata']);
  36. $container->getDefinition('jms_serializer.array_collection_handler')
  37. ->replaceArgument(0, $config['handlers']['array_collection']['initialize_excluded']);
  38. // Built-in subscribers.
  39. $container->getDefinition('jms_serializer.doctrine_proxy_subscriber')
  40. ->replaceArgument(0, !$config['subscribers']['doctrine_proxy']['initialize_virtual_types'])
  41. ->replaceArgument(1, $config['subscribers']['doctrine_proxy']['initialize_excluded']);
  42. // Built-in object constructor.
  43. $container->getDefinition('jms_serializer.doctrine_object_constructor')
  44. ->replaceArgument(2, $config['object_constructors']['doctrine']['fallback_strategy']);
  45. // property naming
  46. $container
  47. ->getDefinition('jms_serializer.camel_case_naming_strategy')
  48. ->addArgument($config['property_naming']['separator'])
  49. ->addArgument($config['property_naming']['lower_case']);
  50. if (!empty($config['property_naming']['id'])) {
  51. $container->setAlias('jms_serializer.naming_strategy', $config['property_naming']['id']);
  52. }
  53. if (!class_exists(Helper::class)) {
  54. $container->removeDefinition('jms_serializer.templating.helper.serializer');
  55. }
  56. $bundles = $container->getParameter('kernel.bundles');
  57. if (!isset($bundles['TwigBundle'])) {
  58. $container->removeDefinition('jms_serializer.twig_extension.serializer');
  59. $container->removeDefinition('jms_serializer.twig_extension.serializer_runtime_helper');
  60. }
  61. if (!empty($config['expression_evaluator']['id'])) {
  62. $container
  63. ->getDefinition('jms_serializer.deserialization_graph_navigator_factory')
  64. ->replaceArgument(5, new Reference($config['expression_evaluator']['id']));
  65. $container
  66. ->getDefinition('jms_serializer.serialization_graph_navigator_factory')
  67. ->replaceArgument(4, new Reference($config['expression_evaluator']['id']));
  68. $container
  69. ->getDefinition('jms_serializer.accessor_strategy.default')
  70. ->setArgument(0, new Reference($config['expression_evaluator']['id']));
  71. } else {
  72. $container->removeDefinition('jms_serializer.expression_evaluator');
  73. }
  74. // metadata
  75. if ('none' === $config['metadata']['cache']) {
  76. $container->removeAlias('jms_serializer.metadata.cache');
  77. $container->removeDefinition('jms_serializer.cache.cache_clearer');
  78. } elseif ('file' === $config['metadata']['cache']) {
  79. $container
  80. ->getDefinition('jms_serializer.metadata.cache.file_cache')
  81. ->replaceArgument(0, $config['metadata']['file_cache']['dir']);
  82. $dir = $container->getParameterBag()->resolveValue($config['metadata']['file_cache']['dir']);
  83. if (!is_dir($dir) && !@mkdir($dir, 0777, true) && !is_dir($dir)) {
  84. throw new RuntimeException(sprintf('Could not create cache directory "%s".', $dir));
  85. }
  86. } else {
  87. $container->setAlias('jms_serializer.metadata.cache', new Alias($config['metadata']['cache'], false));
  88. }
  89. if (false === $config['metadata']['infer_types_from_doctrine_metadata']) {
  90. $container->setParameter('jms_serializer.infer_types_from_doctrine_metadata', false);
  91. }
  92. if ($config['metadata']['infer_types_from_doc_block'] && class_exists(DocBlockDriver::class)) {
  93. $container->getDefinition('jms_serializer.metadata.doc_block_driver')
  94. ->setDecoratedService('jms_serializer.metadata_driver')
  95. ->setPublic(false);
  96. }
  97. if (PHP_VERSION_ID >= 70400 && class_exists(TypedPropertiesDriver::class)) {
  98. $container->getDefinition('jms_serializer.metadata.typed_properties_driver')
  99. ->setDecoratedService('jms_serializer.metadata_driver')
  100. ->setPublic(false);
  101. }
  102. if (PHP_VERSION_ID >= 80000 && class_exists(AttributeReader::class)) {
  103. $container->register('jms_serializer.metadata.annotation_and_attributes_reader', AttributeReader::class)
  104. ->setArgument(0, new Reference('annotation_reader'));
  105. $container->findDefinition('jms_serializer.metadata.annotation_driver')
  106. ->setArgument(0, new Reference('jms_serializer.metadata.annotation_and_attributes_reader'));
  107. }
  108. $container
  109. ->getDefinition('jms_serializer.metadata_factory')
  110. ->replaceArgument(2, $config['metadata']['debug'])
  111. ->addMethodCall('setIncludeInterfaces', [$config['metadata']['include_interfaces']]);
  112. // warmup
  113. if (!empty($config['metadata']['warmup']['paths']['included']) && class_exists(Finder::class)) {
  114. $container
  115. ->getDefinition('jms_serializer.cache.cache_warmer')
  116. ->replaceArgument(0, $config['metadata']['warmup']['paths']['included'])
  117. ->replaceArgument(2, $config['metadata']['warmup']['paths']['excluded']);
  118. } else {
  119. $container->removeDefinition('jms_serializer.cache.cache_warmer');
  120. }
  121. // directories
  122. $directories = [];
  123. if ($config['metadata']['auto_detection']) {
  124. foreach ($bundles as $name => $class) {
  125. $ref = new \ReflectionClass($class);
  126. $dir = dirname($ref->getFileName()) . '/Resources/config/serializer';
  127. if (file_exists($dir)) {
  128. $directories[$ref->getNamespaceName()] = $dir;
  129. }
  130. }
  131. }
  132. foreach ($config['metadata']['directories'] as $directory) {
  133. $directory['path'] = rtrim(str_replace('\\', '/', $directory['path']), '/');
  134. if ('@' === $directory['path'][0]) {
  135. $pathParts = explode('/', $directory['path']);
  136. $bundleName = substr($pathParts[0], 1);
  137. if (!isset($bundles[$bundleName])) {
  138. throw new RuntimeException(sprintf('The bundle "%s" has not been registered with AppKernel. Available bundles: %s', $bundleName, implode(', ', array_keys($bundles))));
  139. }
  140. $ref = new \ReflectionClass($bundles[$bundleName]);
  141. $directory['path'] = dirname($ref->getFileName()) . substr($directory['path'], strlen('@' . $bundleName));
  142. }
  143. $dir = rtrim($directory['path'], '\\/');
  144. if (!file_exists($dir)) {
  145. throw new RuntimeException(sprintf('The metadata directory "%s" does not exist for the namespace "%s"', $dir, $directory['namespace_prefix']));
  146. }
  147. $directories[rtrim($directory['namespace_prefix'], '\\')] = $dir;
  148. }
  149. $container
  150. ->getDefinition('jms_serializer.metadata.file_locator')
  151. ->replaceArgument(0, $directories);
  152. $this->setVisitorOptions($config, $container);
  153. if (!$container->getParameter('kernel.debug') || !class_exists(Stopwatch::class)) {
  154. $container->removeDefinition('jms_serializer.stopwatch_subscriber');
  155. }
  156. // context factories
  157. $services = [
  158. 'serialization' => 'jms_serializer.configured_serialization_context_factory',
  159. 'deserialization' => 'jms_serializer.configured_deserialization_context_factory',
  160. ];
  161. foreach ($services as $configKey => $serviceId) {
  162. $contextFactory = $container->getDefinition($serviceId);
  163. if (isset($config['default_context'][$configKey]['id'])) {
  164. $container->setAlias('jms_serializer.' . $configKey . '_context_factory', new Alias($config['default_context'][$configKey]['id'], true));
  165. $container->setAlias('JMS\\Serializer\\ContextFactory\\' . ucfirst($configKey) . 'ContextFactoryInterface', new Alias($config['default_context'][$configKey]['id'], true));
  166. $container->removeDefinition($serviceId);
  167. continue;
  168. }
  169. if (isset($config['default_context'][$configKey]['version'])) {
  170. $contextFactory->addMethodCall('setVersion', [$config['default_context'][$configKey]['version']]);
  171. }
  172. if (isset($config['default_context'][$configKey]['serialize_null'])) {
  173. $contextFactory->addMethodCall('setSerializeNulls', [$config['default_context'][$configKey]['serialize_null']]);
  174. }
  175. if (!empty($config['default_context'][$configKey]['attributes'])) {
  176. $contextFactory->addMethodCall('setAttributes', [$config['default_context'][$configKey]['attributes']]);
  177. }
  178. if (!empty($config['default_context'][$configKey]['groups'])) {
  179. $contextFactory->addMethodCall('setGroups', [$config['default_context'][$configKey]['groups']]);
  180. }
  181. if (!empty($config['default_context'][$configKey]['enable_max_depth_checks'])) {
  182. $contextFactory->addMethodCall('enableMaxDepthChecks');
  183. }
  184. }
  185. }
  186. public function getConfiguration(array $config, ContainerBuilder $container)
  187. {
  188. return new Configuration($container->getParameterBag()->resolveValue('%kernel.debug%'));
  189. }
  190. private function setVisitorOptions(array $config, ContainerBuilder $container): void
  191. {
  192. // json (serialization)
  193. if (isset($config['visitors']['json_serialization']['options'])) {
  194. $container->getDefinition('jms_serializer.json_serialization_visitor')
  195. ->addMethodCall('setOptions', [$config['visitors']['json_serialization']['options']]);
  196. }
  197. if (isset($config['visitors']['json_serialization']['depth'])) {
  198. $container->getDefinition('jms_serializer.json_serialization_visitor')
  199. ->addMethodCall('setDepth', [$config['visitors']['json_serialization']['depth']]);
  200. }
  201. // json (deserialization)
  202. if (isset($config['visitors']['json_deserialization']['options'])) {
  203. $container->getDefinition('jms_serializer.json_deserialization_visitor')
  204. ->addMethodCall('setOptions', [$config['visitors']['json_deserialization']['options']]);
  205. }
  206. // xml (serialization)
  207. if (!empty($config['visitors']['xml_serialization']['default_root_name'])) {
  208. $container->getDefinition('jms_serializer.xml_serialization_visitor')
  209. ->addMethodCall('setDefaultRootName', [
  210. $config['visitors']['xml_serialization']['default_root_name'],
  211. $config['visitors']['xml_serialization']['default_root_ns'],
  212. ]);
  213. }
  214. if (!empty($config['visitors']['xml_serialization']['version'])) {
  215. $container->getDefinition('jms_serializer.xml_serialization_visitor')
  216. ->addMethodCall('setDefaultVersion', [$config['visitors']['xml_serialization']['version']]);
  217. }
  218. if (!empty($config['visitors']['xml_serialization']['encoding'])) {
  219. $container->getDefinition('jms_serializer.xml_serialization_visitor')
  220. ->addMethodCall('setDefaultEncoding', [$config['visitors']['xml_serialization']['encoding']]);
  221. }
  222. if (!empty($config['visitors']['xml_serialization']['format_output'])) {
  223. $container->getDefinition('jms_serializer.xml_serialization_visitor')
  224. ->addMethodCall('setFormatOutput', [$config['visitors']['xml_serialization']['format_output']]);
  225. }
  226. // xml (deserialization)
  227. if (!empty($config['visitors']['xml_deserialization']['doctype_whitelist'])) {
  228. $container->getDefinition('jms_serializer.xml_deserialization_visitor')
  229. ->addMethodCall('setDoctypeWhitelist', [$config['visitors']['xml_deserialization']['doctype_whitelist']]);
  230. }
  231. if (!empty($config['visitors']['xml_deserialization']['external_entities'])) {
  232. $container->getDefinition('jms_serializer.xml_deserialization_visitor')
  233. ->addMethodCall('enableExternalEntities', [$config['visitors']['xml_deserialization']['external_entities']]);
  234. }
  235. if (!empty($config['visitors']['xml_deserialization']['options'])) {
  236. $container->getDefinition('jms_serializer.xml_deserialization_visitor')
  237. ->addMethodCall('setOptions', [$config['visitors']['xml_deserialization']['options']]);
  238. }
  239. }
  240. }