From 106f154b0f00e322a374c541379738fb8fa6baae Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 17 Oct 2025 19:08:35 +0200 Subject: [PATCH] Replace the fluent PHP config format by the array-shape one --- bundles/configuration.rst | 27 +- bundles/prepend_extension.rst | 14 +- cache.rst | 295 ++++---- components/dependency_injection.rst | 42 +- .../_imports-parameters-note.rst.inc | 10 +- components/uid.rst | 35 +- components/var_dumper.rst | 10 +- configuration.rst | 192 +++-- configuration/env_var_processors.rst | 345 +++++---- .../front_controllers_and_kernel.rst | 11 +- configuration/micro_kernel_trait.rst | 17 +- configuration/override_dir_structure.rst | 26 +- configuration/secrets.rst | 35 +- console/commands_as_services.rst | 13 +- controller/error_pages.rst | 33 +- controller/service.rst | 29 +- controller/upload_file.rst | 18 +- controller/value_resolver.rst | 19 +- deployment/proxies.rst | 20 +- doctrine/custom_dql_functions.rst | 61 +- doctrine/dbal.rst | 36 +- doctrine/events.rst | 90 +-- doctrine/multiple_entity_managers.rst | 74 +- doctrine/resolve_target_entity.rst | 17 +- event_dispatcher.rst | 30 +- form/bootstrap4.rst | 12 +- form/bootstrap5.rst | 12 +- form/create_custom_field_type.rst | 16 +- form/form_themes.rst | 28 +- form/type_guesser.rst | 12 +- forms.rst | 12 +- frontend/custom_version_strategy.rst | 37 +- html_sanitizer.rst | 355 +++++---- http_cache.rst | 16 +- http_cache/cache_invalidation.rst | 26 +- http_cache/esi.rst | 31 +- http_cache/ssi.rst | 16 +- http_client.rst | 245 ++++--- lock.rst | 80 +- logging.rst | 145 ++-- logging/channels_handlers.rst | 45 +- logging/formatter.rst | 22 +- logging/handlers.rst | 80 +- logging/monolog_console.rst | 27 +- logging/monolog_email.rst | 163 ++--- logging/monolog_exclude_http_codes.rst | 26 +- logging/processors.rst | 74 +- mailer.rst | 258 ++++--- mercure.rst | 67 +- messenger.rst | 687 +++++++++++------- messenger/custom-transport.rst | 30 +- notifier.rst | 169 +++-- performance.rst | 18 +- profiler.rst | 62 +- quick_tour/the_architecture.rst | 29 +- rate_limiter.rst | 136 ++-- reference/configuration/debug.rst | 10 +- reference/configuration/doctrine.rst | 415 ++++++----- reference/configuration/framework.rst | 502 ++++++++----- reference/configuration/kernel.rst | 8 +- reference/configuration/security.rst | 246 ++++--- reference/configuration/twig.rst | 48 +- reference/constraints/PasswordStrength.rst | 19 +- reference/dic_tags.rst | 341 ++++++--- routing.rst | 623 +++++++++------- routing/custom_route_loader.rst | 113 +-- security.rst | 609 +++++++++------- security/access_control.rst | 179 ++--- security/access_denied_handler.rst | 38 +- security/access_token.rst | 478 +++++++----- security/csrf.rst | 65 +- security/custom_authenticator.rst | 22 +- security/entry_point.rst | 76 +- security/firewall_restriction.rst | 78 +- security/force_https.rst | 36 +- security/form_login.rst | 112 +-- security/impersonating_user.rst | 93 ++- security/ldap.rst | 149 ++-- security/login_link.rst | 166 +++-- security/passwords.rst | 157 ++-- security/remember_me.rst | 130 ++-- security/user_checkers.rst | 79 +- security/user_providers.rst | 155 ++-- security/voters.rst | 48 +- serializer.rst | 57 +- serializer/custom_name_converter.rst | 18 +- serializer/custom_normalizer.rst | 23 +- serializer/encoders.rst | 16 +- service_container.rst | 440 ++++++----- service_container/alias_private.rst | 134 ++-- service_container/autowiring.rst | 129 ++-- service_container/calls.rst | 31 +- service_container/configurators.rst | 59 +- service_container/expression_language.rst | 35 +- service_container/factories.rst | 148 ++-- service_container/import.rst | 188 ++--- service_container/injection_types.rst | 66 +- service_container/lazy_services.rst | 32 +- service_container/optional_dependencies.rst | 43 +- service_container/parent_services.rst | 85 +-- service_container/service_closures.rst | 26 +- service_container/service_decoration.rst | 276 ++++--- .../service_subscribers_locators.rst | 138 ++-- service_container/shared.rst | 15 +- service_container/synthetic_services.rst | 19 +- service_container/tags.rst | 282 ++++--- session.rst | 398 +++++----- templates.rst | 146 ++-- testing.rst | 10 +- testing/profiling.rst | 21 +- translation.rst | 146 ++-- validation/translations.rst | 14 +- webhook.rst | 24 +- workflow.rst | 391 +++++----- workflow/dumping-workflows.rst | 136 ++-- workflow/workflow-and-state-machine.rst | 113 ++- 116 files changed, 7367 insertions(+), 5722 deletions(-) diff --git a/bundles/configuration.rst b/bundles/configuration.rst index a2f1083230c..e3feea38e12 100644 --- a/bundles/configuration.rst +++ b/bundles/configuration.rst @@ -23,11 +23,13 @@ as integration of other related components: .. code-block:: php // config/packages/framework.php - use Symfony\Config\FrameworkConfig; + namespace Symfony\Config; - return static function (FrameworkConfig $framework): void { - $framework->form()->enabled(true); - }; + return [ + new FrameworkConfig([ + 'form' => true, + ]), + ]; There are two different ways of creating friendly configuration for a bundle: @@ -148,13 +150,16 @@ can add some configuration that looks like this: .. code-block:: php // config/packages/acme_social.php - use Symfony\Config\AcmeSocialConfig; - - return static function (AcmeSocialConfig $acmeSocial): void { - $acmeSocial->twitter() - ->clientId(123) - ->clientSecret('your_secret'); - }; + namespace Symfony\Config; + + return [ + new AcmeSocialConfig([ + 'twitter' => [ + 'client_id' => 123, + 'client_secret' => 'your_secret', + ], + ]), + ]; The basic idea is that instead of having the user override individual parameters, you let the user configure just a few, specifically created, diff --git a/bundles/prepend_extension.rst b/bundles/prepend_extension.rst index 40df06ac834..fc33116e224 100644 --- a/bundles/prepend_extension.rst +++ b/bundles/prepend_extension.rst @@ -111,19 +111,19 @@ registered and the ``entity_manager_name`` setting for ``acme_hello`` is set to .. code-block:: php // config/packages/acme_something.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; - return static function (ContainerConfigurator $container): void { - $container->extension('acme_something', [ + return [ + new AcmeSomethingConfig([ // ... 'use_acme_goodbye' => false, 'entity_manager_name' => 'non_default', - ]); - $container->extension('acme_other', [ + ]), + new AcmeOtherConfig([ // ... 'use_acme_goodbye' => false, - ]); - }; + ]), + ]; Prepending Extension in the Bundle Class ---------------------------------------- diff --git a/cache.rst b/cache.rst index 560ba6a7e07..bf9b27a966e 100644 --- a/cache.rst +++ b/cache.rst @@ -64,14 +64,16 @@ adapter (template) they use by using the ``app`` and ``system`` key like: .. code-block:: php // config/packages/cache.php - use Symfony\Config\FrameworkConfig; + namespace Symfony\Config; - return static function (FrameworkConfig $framework): void { - $framework->cache() - ->app('cache.adapter.filesystem') - ->system('cache.adapter.system') - ; - }; + return [ + new FrameworkConfig([ + 'cache' => [ + 'app' => 'cache.adapter.filesystem', + 'system' => 'cache.adapter.system', + ], + ]), + ]; .. tip:: @@ -117,20 +119,20 @@ Some of these adapters could be configured via shortcuts. .. code-block:: php // config/packages/cache.php - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework): void { - $framework->cache() - // Only used with cache.adapter.filesystem - ->directory('%kernel.cache_dir%/pools') - - ->defaultDoctrineDbalProvider('doctrine.dbal.default_connection') - ->defaultPsr6Provider('app.my_psr6_service') - ->defaultRedisProvider('redis://localhost') - ->defaultMemcachedProvider('memcached://localhost') - ->defaultPdoProvider('pgsql:host=localhost') - ; - }; + namespace Symfony\Config; + + return [ + new FrameworkConfig([ + 'cache' => [ + 'directory' => '%kernel.cache_dir%/pools', // Only used with cache.adapter.filesystem + 'default_doctrine_dbal_provider' => 'doctrine.dbal.default_connection', + 'default_psr6_provider' => 'app.my_psr6_service', + 'default_redis_provider' => 'redis://localhost', + 'default_memcached_provider' => 'memcached://localhost', + 'default_pdo_provider' => 'pgsql:host=localhost', + ], + ]), + ]; .. _cache-create-pools: @@ -178,36 +180,43 @@ You can also create more customized pools: .. code-block:: php // config/packages/cache.php - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework): void { - $cache = $framework->cache(); - $cache->defaultMemcachedProvider('memcached://localhost'); - - // creates a "custom_thing.cache" service - // autowireable via "CacheInterface $customThingCache" - // uses the "app" cache configuration - $cache->pool('custom_thing.cache') - ->adapters(['cache.app']); - - // creates a "my_cache_pool" service - // autowireable via "CacheInterface $myCachePool" - $cache->pool('my_cache_pool') - ->adapters(['cache.adapter.filesystem']); - - // uses the default_memcached_provider from above - $cache->pool('acme.cache') - ->adapters(['cache.adapter.memcached']); - - // control adapter's configuration - $cache->pool('foobar.cache') - ->adapters(['cache.adapter.memcached']) - ->provider('memcached://user:password@example.com'); - - $cache->pool('short_cache') - ->adapters(['foobar.cache']) - ->defaultLifetime(60); - }; + namespace Symfony\Config; + + return [ + new FrameworkConfig([ + 'cache' => [ + 'default_memcached_provider' => 'memcached://localhost', + 'pools' => [ + // creates a "custom_thing.cache" service + // autowireable via "CacheInterface $customThingCache" + // uses the "app" cache configuration + 'custom_thing.cache' => [ + 'adapter' => 'cache.app', + ], + // creates a "my_cache_pool" service + // autowireable via "CacheInterface $myCachePool" + 'my_cache_pool' => [ + 'adapter' => 'cache.adapter.filesystem', + ], + // uses the default_memcached_provider from above + 'acme.cache' => [ + 'adapter' => 'cache.adapter.memcached', + ], + // control adapter's configuration + 'foobar.cache' => [ + 'adapter' => 'cache.adapter.memcached', + 'provider' => 'memcached://user:password@example.com', + ], + // uses the "foobar.cache" pool as its backend but controls + // the lifetime and (like all pools) has a separate cache namespace + 'short_cache' => [ + 'adapter' => 'foobar.cache', + 'default_lifetime' => 60, + ], + ], + ], + ]), + ]; Each pool manages a set of independent cache keys: keys from different pools *never* collide, even if they share the same backend. This is achieved by prefixing @@ -289,27 +298,29 @@ and use that when configuring the pool. .. code-block:: php // config/packages/cache.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; use Symfony\Component\Cache\Adapter\RedisAdapter; - use Symfony\Component\DependencyInjection\ContainerBuilder; - use Symfony\Config\FrameworkConfig; - - return static function (ContainerBuilder $container, FrameworkConfig $framework): void { - $framework->cache() - ->pool('cache.my_redis') - ->adapters(['cache.adapter.redis']) - ->provider('app.my_custom_redis_provider'); - - $container->register('app.my_custom_redis_provider', \Redis::class) - ->setFactory([RedisAdapter::class, 'createConnection']) - ->addArgument('redis://localhost') - ->addArgument([ - 'retry_interval' => 2, - 'timeout' => 10 - ]) - ; - }; + + return [ + new FrameworkConfig([ + 'cache' => [ + 'pools' => [ + 'cache.my_redis' => [ + 'adapter' => 'cache.adapter.redis', + 'provider' => 'app.my_custom_redis_provider', + ], + ], + ], + ]), + new ServicesConfig([ + 'app.my_custom_redis_provider' => [ + 'class' => \Redis::class, + 'factory' => [RedisAdapter::class, 'createConnection'], + 'arguments' => ['redis://localhost', ['retry_interval' => 2, 'timeout' => 10]], + ], + ]), + ]; Creating a Cache Chain ---------------------- @@ -348,19 +359,24 @@ Symfony stores the item automatically in all the missing pools. .. code-block:: php // config/packages/cache.php - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework): void { - $framework->cache() - ->pool('my_cache_pool') - ->defaultLifetime(31536000) // One year - ->adapters([ - 'cache.adapter.array', - 'cache.adapter.apcu', - ['name' => 'cache.adapter.redis', 'provider' => 'redis://user:password@example.com'], - ]) - ; - }; + namespace Symfony\Config; + + return [ + new FrameworkConfig([ + 'cache' => [ + 'pools' => [ + 'my_cache_pool' => [ + 'default_lifetime' => 31536000, // One year + 'adapters' => [ + 'cache.adapter.array', + 'cache.adapter.apcu', + ['name' => 'cache.adapter.redis', 'provider' => 'redis://user:password@example.com'], + ], + ], + ], + ], + ]), + ]; .. _cache-using-cache-tags: @@ -420,15 +436,20 @@ to enable this feature. This could be added by using the following configuration .. code-block:: php // config/packages/cache.php - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework): void { - $framework->cache() - ->pool('my_cache_pool') - ->tags(true) - ->adapters(['cache.adapter.redis_tag_aware']) - ; - }; + namespace Symfony\Config; + + return [ + new FrameworkConfig([ + 'cache' => [ + 'pools' => [ + 'my_cache_pool' => [ + 'adapter' => 'cache.adapter.redis_tag_aware', + 'tags' => true, + ], + ], + ], + ]), + ]; Tags are stored in the same pool by default. This is good in most scenarios. But sometimes it might be better to store the tags in a different pool. That could be @@ -451,20 +472,23 @@ achieved by specifying the adapter. .. code-block:: php // config/packages/cache.php - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework): void { - $framework->cache() - ->pool('my_cache_pool') - ->tags('tag_pool') - ->adapters(['cache.adapter.redis']) - ; - - $framework->cache() - ->pool('tag_pool') - ->adapters(['cache.adapter.apcu']) - ; - }; + namespace Symfony\Config; + + return [ + new FrameworkConfig([ + 'cache' => [ + 'pools' => [ + 'my_cache_pool' => [ + 'adapter' => 'cache.adapter.redis', + 'tags' => 'tag_pool', + ], + 'tag_pool' => [ + 'adapter' => 'cache.adapter.apcu', + ], + ], + ], + ]), + ]; .. note:: @@ -573,16 +597,23 @@ Then, register the ``SodiumMarshaller`` service using this key: .. code-block:: php // config/packages/cache.php + namespace Symfony\Config; + use Symfony\Component\Cache\Marshaller\SodiumMarshaller; - use Symfony\Component\DependencyInjection\ChildDefinition; - use Symfony\Component\DependencyInjection\Reference; - // ... - $container->setDefinition(SodiumMarshaller::class, new ChildDefinition('cache.default_marshaller')) - ->addArgument(['env(base64:CACHE_DECRYPTION_KEY)']) - // use multiple keys in order to rotate them - //->addArgument(['env(base64:CACHE_DECRYPTION_KEY)', 'env(base64:OLD_CACHE_DECRYPTION_KEY)']) - ->addArgument(new Reference('.inner')); + return [ + new ServicesConfig([ + SodiumMarshaller::class => [ + 'decorates' => 'cache.default_marshaller', + 'arguments' => [ + [env('CACHE_DECRYPTION_KEY')->base64()], + // use multiple keys in order to rotate them + // [env('CACHE_DECRYPTION_KEY')->base64(), env('OLD_CACHE_DECRYPTION_KEY')->base64()] + service('.inner'), + ], + ], + ]), + ]; .. danger:: @@ -678,21 +709,29 @@ a message bus to compute values in a worker: .. code-block:: php // config/framework/framework.php + namespace Symfony\Config; + use Symfony\Component\Cache\Messenger\EarlyExpirationMessage; - use Symfony\Config\FrameworkConfig; - use function Symfony\Component\DependencyInjection\Loader\Configurator\env; - - return static function (FrameworkConfig $framework): void { - $framework->cache() - ->pool('async.cache') - ->earlyExpirationMessageBus('messenger.default_bus'); - - $framework->messenger() - ->transport('async_bus') - ->dsn(env('MESSENGER_TRANSPORT_DSN')) - ->routing(EarlyExpirationMessage::class) - ->senders(['async_bus']); - }; + + return [ + new FrameworkConfig([ + 'cache' => [ + 'pools' => [ + 'async.cache' => [ + 'early_expiration_message_bus' => 'messenger.default_bus', + ], + ], + ], + 'messenger' => [ + 'transports' => [ + 'async_bus' => env('MESSENGER_TRANSPORT_DSN'), + ], + 'routing' => [ + EarlyExpirationMessage::class => 'async_bus', + ], + ], + ]), + ]; You can now start the consumer: diff --git a/components/dependency_injection.rst b/components/dependency_injection.rst index 3ae645aa289..dca95f55e11 100644 --- a/components/dependency_injection.rst +++ b/components/dependency_injection.rst @@ -260,6 +260,7 @@ config files: .. code-block:: yaml + # config/services.yaml parameters: # ... mailer.transport: sendmail @@ -275,27 +276,30 @@ config files: .. code-block:: php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + // config/services.php + namespace Symfony\Config; - return static function (ContainerConfigurator $container): void { - $container->parameters() + use App\Mailer; + use App\NewsletterManager; + + return [ + new ParametersConfig([ // ... - ->set('mailer.transport', 'sendmail') - ; - - $services = $container->services(); - $services->set('mailer', 'Mailer') - ->args(['%mailer.transport%']) - ; - - $services->set('mailer', 'Mailer') - ->args([param('mailer.transport')]) - ; - - $services->set('newsletter_manager', 'NewsletterManager') - ->call('setMailer', [service('mailer')]) - ; - }; + 'mailer.transport' => 'sendmail', + ]), + new ServicesConfig([ + 'mailer' => [ + 'class' => Mailer::class, + 'arguments' => [param('mailer.transport')], + ], + 'newsletter_manager' => [ + 'class' => NewsletterManager::class, + 'calls' => [ + 'setMailer' => [service('mailer')], + ], + ], + ]), + ]; Learn More ---------- diff --git a/components/dependency_injection/_imports-parameters-note.rst.inc b/components/dependency_injection/_imports-parameters-note.rst.inc index 41b523afddd..f1571ce9a1a 100644 --- a/components/dependency_injection/_imports-parameters-note.rst.inc +++ b/components/dependency_injection/_imports-parameters-note.rst.inc @@ -15,8 +15,10 @@ .. code-block:: php // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; - return static function (ContainerConfigurator $container): void { - $container->import('%kernel.project_dir%/somefile.yaml'); - }; + return [ + new ImportsConfig([ + ['resource => '%kernel.project_dir%/somefile.yaml'], + ]), + ]; diff --git a/components/uid.rst b/components/uid.rst index 4de8005f683..5b7dfcbdfdf 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -207,15 +207,10 @@ You can configure these default values:: .. code-block:: php // config/packages/uid.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; - return static function (ContainerConfigurator $container): void { - $services = $container->services() - ->defaults() - ->autowire() - ->autoconfigure(); - - $container->extension('framework', [ + return [ + new FrameworkConfig([ 'uid' => [ 'default_uuid_version' => 6, 'name_based_uuid_version' => 3, @@ -223,8 +218,8 @@ You can configure these default values:: 'time_based_uuid_version' => 6, 'time_based_uuid_node' => 121212121212, ], - ]); - }; + ]), + ]; Converting UUIDs ~~~~~~~~~~~~~~~~ @@ -662,22 +657,22 @@ configuration in your application before using these commands: .. code-block:: php // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; use Symfony\Component\Uid\Command\GenerateUlidCommand; use Symfony\Component\Uid\Command\GenerateUuidCommand; use Symfony\Component\Uid\Command\InspectUlidCommand; use Symfony\Component\Uid\Command\InspectUuidCommand; - return static function (ContainerConfigurator $container): void { - // ... - - $services - ->set(GenerateUlidCommand::class) - ->set(GenerateUuidCommand::class) - ->set(InspectUlidCommand::class) - ->set(InspectUuidCommand::class); - }; + return [ + new ServicesConfig([ + // ... + GenerateUlidCommand::class => null, + GenerateUuidCommand::class => null, + InspectUlidCommand::class => null, + InspectUuidCommand::class => null, + ]), + ]; Now you can generate UUIDs/ULIDs as follows (add the ``--help`` option to the commands to learn about all their options): diff --git a/components/var_dumper.rst b/components/var_dumper.rst index 01dbbdec15e..bf8c7dd2c4e 100644 --- a/components/var_dumper.rst +++ b/components/var_dumper.rst @@ -127,13 +127,13 @@ the :ref:`dump_destination option ` of the .. code-block:: php // config/packages/debug.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; - return static function (ContainerConfigurator $container): void { - $container->extension('debug', [ + return [ + new DebugConfig([ 'dump_destination' => 'tcp://%env(VAR_DUMPER_SERVER)%', - ]); - }; + ]), + ]; Outside a Symfony application, use the :class:`Symfony\\Component\\VarDumper\\Dumper\\ServerDumper` class:: diff --git a/configuration.rst b/configuration.rst index 858300d6ec6..5ef7e204009 100644 --- a/configuration.rst +++ b/configuration.rst @@ -97,22 +97,22 @@ configuration files, even if they use a different format: .. code-block:: php // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; - return static function (ContainerConfigurator $container): void { - $container->import('legacy_config.php'); + return [ + new ImportsConfig([ + ['resource' => 'legacy_config.php'], - // glob expressions are also supported to load multiple files - $container->import('/etc/myapp/*.yaml'); + // glob expressions are also supported to load multiple files + ['resource' => '/etc/myapp/*.yaml'], - // the third optional argument of import() is 'ignore_errors' - // 'ignore_errors' set to 'not_found' silently discards errors if the loaded file doesn't exist - $container->import('my_config_file.yaml', null, 'not_found'); - // 'ignore_errors' set to true silently discards all errors (including invalid code and not found) - $container->import('my_config_file.yaml', null, true); - }; + // ignore_errors: not_found silently discards errors if the loaded file doesn't exist + ['resource' => 'my_config_file.xml', 'ignore_errors' => 'not_found'], - // ... + // ignore_errors: true silently discards all errors (including invalid code and not found) + ['resource' => 'my_other_config_file.xml', 'ignore_errors' => true], + ]), + ]; .. _config-parameter-intro: .. _config-parameters-yml: @@ -124,7 +124,7 @@ Configuration Parameters Sometimes the same configuration value is used in several configuration files. Instead of repeating it, you can define it as a "parameter", which is like a reusable configuration value. By convention, parameters are defined under the -``parameters`` key in the ``config/services.yaml`` file: +``parameters`` key: .. configuration-block:: @@ -157,35 +157,34 @@ reusable configuration value. By convention, parameters are defined under the .. code-block:: php // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; use App\Entity\BlogPost; use App\Enum\PostState; - return static function (ContainerConfigurator $container): void { - $container->parameters() + return [ + new ParametersConfig([ // the parameter name is an arbitrary string (the 'app.' prefix is recommended // to better differentiate your parameters from Symfony parameters). - ->set('app.admin_email', 'something@example.com') + 'app.admin_email' => 'something@example.com', // boolean parameters - ->set('app.enable_v2_protocol', true) + 'app.enable_v2_protocol' => true, // array/collection parameters - ->set('app.supported_locales', ['en', 'es', 'fr']) + 'app.supported_locales' => ['en', 'es', 'fr'], - // binary content parameters (use the PHP escape sequences) - ->set('app.some_parameter', 'This is a Bell char: \x07') + // binary content parameters (encode the contents with base64_encode()) + 'app.some_parameter' => base64_decode('VGhpcyBpcyBhIEJlbGwgY2hhciAA'), // PHP constants as parameter values - ->set('app.some_constant', GLOBAL_CONSTANT) - ->set('app.another_constant', BlogPost::MAX_ITEMS) + 'app.some_constant' => GLOBAL_CONSTANT, + 'app.another_constant' => BlogPost::MAX_ITEMS, // Enum case as parameter values - ->set('app.some_enum', PostState::Published); - }; - - // ... + 'app.some_enum' => PostState::Published, + ]), + ]; Once defined, you can reference this parameter value from any other configuration file using a special syntax: wrap the parameter name in two ``%`` @@ -203,11 +202,10 @@ configuration file using a special syntax: wrap the parameter name in two ``%`` .. code-block:: php // config/packages/some_package.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; - use function Symfony\Component\DependencyInjection\Loader\Configurator\param; + namespace Symfony\Config; - return static function (ContainerConfigurator $container): void { - $container->extension('some_package', [ + return [ + new SomePackageConfig([ // when using the param() function, you only have to pass the parameter name... 'email_address' => param('app.admin_email'), @@ -215,8 +213,8 @@ configuration file using a special syntax: wrap the parameter name in two ``%`` // surrounded by two % (same as in YAML format) and Symfony will // replace it by that parameter value 'email_address' => '%app.admin_email%', - ]); - }; + ]), + ]; .. note:: @@ -236,12 +234,13 @@ configuration file using a special syntax: wrap the parameter name in two ``%`` .. code-block:: php // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; - return static function (ContainerConfigurator $container): void { - $container->parameters() - ->set('url_pattern', 'http://symfony.com/?foo=%%s&bar=%%d'); - }; + return [ + new ParametersConfig([ + 'url_pattern' => 'http://symfony.com/?foo=%%s&bar=%%d', + ]), + ]; .. include:: /components/dependency_injection/_imports-parameters-note.rst.inc @@ -355,27 +354,22 @@ files directly in the ``config/packages/`` directory. .. code-block:: php - // config/packages/framework.php - use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; - use Symfony\Config\WebpackEncoreConfig; - - return static function (WebpackEncoreConfig $webpackEncore, ContainerConfigurator $container): void { - $webpackEncore - ->outputPath('%kernel.project_dir%/public/build') - ->strictMode(true) - ->cache(false) - ; - - // cache is enabled only in the "prod" environment - if ('prod' === $container->env()) { - $webpackEncore->cache(true); - } - - // disable strict mode only in the "test" environment - if ('test' === $container->env()) { - $webpackEncore->strictMode(false); - } - }; + // config/packages/webpack_encore.php + namespace Symfony\Config; + + return [ + new WebpackEncoreConfig([ + 'output_path' => '%kernel.project_dir%/public/build', + 'strict_mode' => true, + 'cache' => false, + ]), + 'when@prod' => new WebpackEncoreConfig([ + 'cache' => true, + ]), + 'when@test' => new WebpackEncoreConfig([ + 'strict_mode' => false, + ]), + ]; .. seealso:: @@ -476,14 +470,14 @@ This example shows how you could configure the application secret using an env v .. code-block:: php // config/packages/framework.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; - return static function (ContainerConfigurator $container): void { - $container->extension('framework', [ + return [ + new FrameworkConfig([ // by convention the env var names are always uppercase - 'secret' => '%env(APP_SECRET)%', - ]); - }; + 'secret' => env('APP_SECRET'), + ]), + ]; .. note:: @@ -516,7 +510,7 @@ To do so, define a parameter with the same name as the env var using this syntax .. code-block:: yaml - # config/packages/framework.yaml + # config/services.yaml parameters: # if the SECRET env var value is not defined anywhere, Symfony uses this value env(SECRET): 'some_secret' @@ -525,22 +519,18 @@ To do so, define a parameter with the same name as the env var using this syntax .. code-block:: php - // config/packages/framework.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; - - use Symfony\Component\DependencyInjection\ContainerBuilder; - use Symfony\Config\FrameworkConfig; - - return static function (ContainerBuilder $container, FrameworkConfig $framework) { - // if the SECRET env var value is not defined anywhere, Symfony uses this value - $container->setParameter('env(SECRET)', 'some_secret'); + // config/services.php + namespace Symfony\Config; - // ... - }; + return [ + new ParametersConfig([ + 'env(SECRET)' => 'some_secret', + ]), + ]; .. tip:: - Some hosts - like Platform.sh - offer easy `utilities to manage env vars`_ + Some hosts - like Upsun.com - offer easy `utilities to manage env vars`_ in production. .. note:: @@ -982,18 +972,22 @@ doesn't work for parameters: .. code-block:: php // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; use App\Service\MessageGenerator; - return static function (ContainerConfigurator $container): void { - $container->parameters() - ->set('app.contents_dir', '...'); - - $container->services() - ->get(MessageGenerator::class) - ->arg('$contentsDir', '%app.contents_dir%'); - }; + return [ + new ParametersConfig([ + 'app.contents_dir' => '...', + ]), + new ServicesConfig([ + MessageGenerator::class => [ + 'arguments' => [ + '$contentsDir' => param('app.contents_dir'), + ], + ], + ]), + ]; If you inject the same parameters over and over again, use the ``services._defaults.bind`` option instead. The arguments defined in that option are @@ -1019,17 +1013,19 @@ whenever a service/controller defines a ``$projectDir`` argument, use this: .. code-block:: php // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; - - return static function (ContainerConfigurator $container): void { - $container->services() - ->defaults() - // pass this value to any $projectDir argument for any service - // that's created in this file (including controller arguments) - ->bind('$projectDir', '%kernel.project_dir%'); - - // ... - }; + namespace Symfony\Config; + + return [ + new ServicesConfig([ + '_defaults' => [ + 'bind' => [ + // pass this value to any $projectDir argument for any service + // that's created in this file (including controller arguments) + '$projectDir' => param('kernel.project_dir'), + ], + ], + ]), + ]; .. seealso:: diff --git a/configuration/env_var_processors.rst b/configuration/env_var_processors.rst index 4b7c55f59fc..4ea1c2c27b8 100644 --- a/configuration/env_var_processors.rst +++ b/configuration/env_var_processors.rst @@ -24,17 +24,15 @@ processor to turn the value of the ``HTTP_PORT`` env var into an integer: .. code-block:: php // config/packages/framework.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework): void { - $framework->router() - ->httpPort('%env(int:HTTP_PORT)%') - // or - ->httpPort(env('HTTP_PORT')->int()) - ; - }; + return [ + new FrameworkConfig([ + 'router' => [ + 'http_port' => env('HTTP_PORT')->int(), + ], + ]), + ]; Built-In Environment Variable Processors ---------------------------------------- @@ -57,15 +55,16 @@ Symfony provides the following env var processors: .. code-block:: php // config/packages/framework.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; - - use Symfony\Component\DependencyInjection\ContainerBuilder; - use Symfony\Config\FrameworkConfig; + namespace Symfony\Config; - return static function (ContainerBuilder $container, FrameworkConfig $framework): void { - $container->setParameter('env(SECRET)', 'some_secret'); - $framework->secret(env('SECRET')->string()); - }; + return [ + new ParametersConfig([ + 'env(SECRET)' => 'some_secret', + ]), + new FrameworkConfig([ + 'secret' => env('SECRET')->string(), + ]), + ]; ``env(bool:FOO)`` Casts ``FOO`` to a bool (``true`` values are ``'true'``, ``'on'``, ``'yes'``, @@ -85,15 +84,16 @@ Symfony provides the following env var processors: .. code-block:: php // config/packages/framework.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; - - use Symfony\Component\DependencyInjection\ContainerBuilder; - use Symfony\Config\FrameworkConfig; + namespace Symfony\Config; - return static function (ContainerBuilder $container, FrameworkConfig $framework): void { - $container->setParameter('env(HTTP_METHOD_OVERRIDE)', 'true'); - $framework->httpMethodOverride(env('HTTP_METHOD_OVERRIDE')->bool()); - }; + return [ + new ParametersConfig([ + 'env(HTTP_METHOD_OVERRIDE)' => 'true', + ]), + new FrameworkConfig([ + 'http_method_override' => env('HTTP_METHOD_OVERRIDE')->bool(), + ]), + ]; ``env(not:FOO)`` Casts ``FOO`` to a bool (just as ``env(bool:...)`` does) except it returns the inverted value @@ -110,7 +110,13 @@ Symfony provides the following env var processors: .. code-block:: php // config/services.php - $container->setParameter('safe_for_production', '%env(not:APP_DEBUG)%'); + namespace Symfony\Config; + + return [ + new ParametersConfig([ + 'safe_for_production' => env('APP_DEBUG')->not(), + ]), + ]; ``env(int:FOO)`` Casts ``FOO`` to an int. @@ -135,15 +141,18 @@ Symfony provides the following env var processors: .. code-block:: php // config/packages/security.php - use Symfony\Component\DependencyInjection\ContainerBuilder; - use Symfony\Config\SecurityConfig; + namespace Symfony\Config; - return static function (ContainerBuilder $container, SecurityConfig $security): void { - $container->setParameter('env(HEALTH_CHECK_METHOD)', 'Symfony\Component\HttpFoundation\Request::METHOD_HEAD'); - $security->accessControl() - ->path('^/health-check$') - ->methods([env('HEALTH_CHECK_METHOD')->const()]); - }; + return [ + new ParametersConfig([ + 'env(HEALTH_CHECK_METHOD)' => 'Symfony\Component\HttpFoundation\Request::METHOD_HEAD', + ]), + new SecurityConfig([ + 'access_control' => [ + ['path' => '^/health-check$', 'methods' => env('HEALTH_CHECK_METHOD')->const()], + ], + ]), + ]; ``env(base64:FOO)`` Decodes the content of ``FOO``, which is a base64 encoded string. @@ -156,23 +165,22 @@ Symfony provides the following env var processors: .. code-block:: yaml - # config/packages/framework.yaml + # config/services.yaml parameters: env(ALLOWED_LANGUAGES): '["en","de","es"]' app_allowed_languages: '%env(json:ALLOWED_LANGUAGES)%' .. code-block:: php - // config/packages/framework.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; - - use Symfony\Component\DependencyInjection\ContainerBuilder; - use Symfony\Config\FrameworkConfig; + // config/services.php + namespace Symfony\Config; - return static function (ContainerBuilder $container): void { - $container->setParameter('env(ALLOWED_LANGUAGES)', '["en","de","es"]'); - $container->setParameter('app_allowed_languages', '%env(json:ALLOWED_LANGUAGES)%'); - }; + return [ + new ParametersConfig([ + 'env(ALLOWED_LANGUAGES)' => '["en","de","es"]', + 'app_allowed_languages' => env('ALLOWED_LANGUAGES')->json(), + ]), + ]; ``env(resolve:FOO)`` If the content of ``FOO`` includes container parameters (with the syntax @@ -192,11 +200,17 @@ Symfony provides the following env var processors: .. code-block:: php // config/packages/sentry.php - $container->setParameter('sentry_host', '10.0.0.1'); - $container->setParameter('env(SENTRY_DSN)', 'http://%sentry_host%/project'); - $container->loadFromExtension('sentry', [ - 'dsn' => '%env(resolve:SENTRY_DSN)%', - ]); + namespace Symfony\Config; + + return [ + new ParametersConfig([ + 'sentry_host' => '10.0.0.1', + 'env(SENTRY_DSN)' => 'http://%sentry_host%/project', + ]), + new SentryConfig([ + 'dsn' => env('SENTRY_DSN')->resolve(), + ]), + ]; ``env(csv:FOO)`` Decodes the content of ``FOO``, which is a CSV-encoded string: @@ -205,23 +219,22 @@ Symfony provides the following env var processors: .. code-block:: yaml - # config/packages/framework.yaml + # config/services.yaml parameters: env(ALLOWED_LANGUAGES): "en,de,es" app_allowed_languages: '%env(csv:ALLOWED_LANGUAGES)%' .. code-block:: php - // config/packages/framework.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; - - use Symfony\Component\DependencyInjection\ContainerBuilder; - use Symfony\Config\FrameworkConfig; + // config/services.php + namespace Symfony\Config; - return static function (ContainerBuilder $container): void { - $container->setParameter('env(ALLOWED_LANGUAGES)', 'en,de,es'); - $container->setParameter('app_allowed_languages', '%env(csv:ALLOWED_LANGUAGES)%'); - }; + return [ + new ParametersConfig([ + 'env(ALLOWED_LANGUAGES)' => 'en,de,es', + 'app_allowed_languages' => env('ALLOWED_LANGUAGES')->csv(), + ]), + ]; ``env(shuffle:FOO)`` Randomly shuffles values of the ``FOO`` env var, which must be an array. @@ -230,7 +243,7 @@ Symfony provides the following env var processors: .. code-block:: yaml - # config/packages/framework.yaml + # config/services.yaml parameters: env(REDIS_NODES): "127.0.0.1:6380,127.0.0.1:6381" services: @@ -241,12 +254,19 @@ Symfony provides the following env var processors: .. code-block:: php // config/services.php - use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; + namespace Symfony\Config; - return static function (ContainerConfigurator $containerConfigurator): void { - $container = $containerConfigurator->services() - ->set(\RedisCluster::class, \RedisCluster::class)->args([null, '%env(shuffle:csv:REDIS_NODES)%']); - }; + return [ + new ParametersConfig([ + 'env(REDIS_NODES)' => '127.0.0.1:6380,127.0.0.1:6381', + ]), + new ServicesConfig([ + \RedisCluster::class => [ + 'class' => \RedisCluster::class, + 'arguments' => [null, env('REDIS_NODES')->csv()->shuffle()], + ], + ]), + ]; ``env(file:FOO)`` Returns the contents of a file whose path is the value of the ``FOO`` env var: @@ -255,7 +275,7 @@ Symfony provides the following env var processors: .. code-block:: yaml - # config/packages/framework.yaml + # config/packages/google.yaml parameters: env(AUTH_FILE): '%kernel.project_dir%/config/auth.json' google: @@ -263,11 +283,17 @@ Symfony provides the following env var processors: .. code-block:: php - // config/packages/framework.php - $container->setParameter('env(AUTH_FILE)', '../config/auth.json'); - $container->loadFromExtension('google', [ - 'auth' => '%env(file:AUTH_FILE)%', - ]); + // config/packages/google.php + namespace Symfony\Config; + + return [ + new ParametersConfig([ + 'env(AUTH_FILE)' => '../config/auth.json', + ]), + new GoogleConfig([ + 'auth' => env('AUTH_FILE')->file(), + ]), + ]; ``env(require:FOO)`` ``require()`` the PHP file whose path is the value of the ``FOO`` @@ -277,19 +303,25 @@ Symfony provides the following env var processors: .. code-block:: yaml - # config/packages/framework.yaml + # config/packages/google.yaml parameters: env(PHP_FILE): '%kernel.project_dir%/config/.runtime-evaluated.php' - app: + google: auth: '%env(require:PHP_FILE)%' .. code-block:: php - // config/packages/framework.php - $container->setParameter('env(PHP_FILE)', '../config/.runtime-evaluated.php'); - $container->loadFromExtension('app', [ - 'auth' => '%env(require:PHP_FILE)%', - ]); + // config/packages/google.php + namespace Symfony\Config; + + return [ + new ParametersConfig([ + 'env(PHP_FILE)' => '../config/.runtime-evaluated.php', + ]), + new GoogleConfig([ + 'auth' => env('PHP_FILE')->require(), + ]), + ]; ``env(trim:FOO)`` Trims the content of ``FOO`` env var, removing whitespaces from the beginning @@ -300,7 +332,7 @@ Symfony provides the following env var processors: .. code-block:: yaml - # config/packages/framework.yaml + # config/packages/google.yaml parameters: env(AUTH_FILE): '%kernel.project_dir%/config/auth.json' google: @@ -308,11 +340,17 @@ Symfony provides the following env var processors: .. code-block:: php - // config/packages/framework.php - $container->setParameter('env(AUTH_FILE)', '../config/auth.json'); - $container->loadFromExtension('google', [ - 'auth' => '%env(trim:file:AUTH_FILE)%', - ]); + // config/packages/google.php + namespace Symfony\Config; + + return [ + new ParametersConfig([ + 'env(AUTH_FILE)' => '../config/auth.json', + ]), + new GoogleConfig([ + 'auth' => env('AUTH_FILE')->file()->trim(), + ]), + ]; ``env(key:FOO:BAR)`` Retrieves the value associated with the key ``FOO`` from the array whose @@ -331,8 +369,15 @@ Symfony provides the following env var processors: .. code-block:: php // config/services.php - $container->setParameter('env(SECRETS_FILE)', '/opt/application/.secrets.json'); - $container->setParameter('database_password', '%env(key:database_password:json:file:SECRETS_FILE)%'); + namespace Symfony\Config; + + return [ + new ParametersConfig([ + 'env(SECRETS_FILE)' => '/opt/application/.secrets.json', + 'database_password' => env('SECRETS_FILE')->file()->json()->key('database_password'), + // if SECRETS_FILE contents are: {"database_password": "secret"} it returns "secret" + ]), + ]; ``env(default:fallback_param:BAR)`` Retrieves the value of the parameter ``fallback_param`` when the ``BAR`` env @@ -351,10 +396,15 @@ Symfony provides the following env var processors: .. code-block:: php // config/services.php + namespace Symfony\Config; - // if PRIVATE_KEY is not a valid file path, the content of raw_key is returned - $container->setParameter('private_key', '%env(default:raw_key:file:PRIVATE_KEY)%'); - $container->setParameter('raw_key', '%env(PRIVATE_KEY)%'); + return [ + new ParametersConfig([ + // if PRIVATE_KEY is not a valid file path, the content of raw_key is returned + 'private_key' => env('PRIVATE_KEY')->file()->default('raw_key'), + 'raw_key' => env('PRIVATE_KEY'), + ]), + ]; When the fallback parameter is omitted (e.g. ``env(default::API_KEY)``), then the returned value is ``null``. @@ -386,25 +436,29 @@ Symfony provides the following env var processors: .. code-block:: php // config/packages/mongodb.php - $container->loadFromExtension('mongodb', [ - 'clients' => [ - 'default' => [ - 'hosts' => [ - [ - 'host' => '%env(string:key:host:url:MONGODB_URL)%', - 'port' => '%env(int:key:port:url:MONGODB_URL)%', + namespace Symfony\Config; + + return [ + new MongoDbConfig([ + 'clients' => [ + 'default' => [ + 'hosts' => [ + [ + 'host' => env('MONGODB_URL')->url()->key('host')->string(), + 'port' => env('MONGODB_URL')->url()->key('port')->int(), + ], ], + 'username' => env('MONGODB_URL')->url()->key('user')->string(), + 'password' => env('MONGODB_URL')->url()->key('pass')->string(), ], - 'username' => '%env(string:key:user:url:MONGODB_URL)%', - 'password' => '%env(string:key:pass:url:MONGODB_URL)%', ], - ], - 'connections' => [ - 'default' => [ - 'database_name' => '%env(key:path:url:MONGODB_URL)%', + 'connections' => [ + 'default' => [ + 'database_name' => env('MONGODB_URL')->url()->key('path'), + ], ], - ], - ]); + ]), + ]; .. warning:: @@ -434,14 +488,18 @@ Symfony provides the following env var processors: .. code-block:: php // config/packages/mongodb.php - $container->loadFromExtension('mongodb', [ - 'clients' => [ - 'default' => [ - // ... - 'connectTimeoutMS' => '%env(int:key:timeout:query_string:MONGODB_URL)%', + namespace Symfony\Config; + + return [ + new MongoDbConfig([ + 'clients' => [ + 'default' => [ + // ... + 'connectTimeoutMS' => env('MONGODB_URL')->queryString()->key('timeout')->int(), + ], ], - ], - ]); + ]), + ]; ``env(enum:FooEnum:BAR)`` Tries to convert an environment variable to an actual ``\BackedEnum`` value. @@ -467,7 +525,15 @@ Symfony provides the following env var processors: .. code-block:: php // config/services.php - $container->setParameter('suit', '%env(enum:App\Enum\Suit:CARD_SUIT)%'); + namespace Symfony\Config; + + use App\Enum\Suit; + + return [ + new ParametersConfig([ + 'suit' => env('CARD_SUIT')->enum(Suit::class), + ]), + ]; The value stored in the ``CARD_SUIT`` env var would be a string (e.g. ``'spades'``) but the application will use the enum value (e.g. ``Suit::Spades``). @@ -487,7 +553,13 @@ Symfony provides the following env var processors: .. code-block:: php // config/services.php - $container->setParameter('typed_env', '%env(defined:FOO)%'); + namespace Symfony\Config; + + return [ + new ParametersConfig([ + 'typed_env' => env('FOO')->defined(), + ]), + ]; .. _urlencode_environment_variable_processor: @@ -500,23 +572,22 @@ Symfony provides the following env var processors: .. code-block:: yaml - # config/packages/framework.yaml + # config/services.yaml parameters: env(DATABASE_URL): 'mysql://db_user:foo@b$r@127.0.0.1:3306/db_name' encoded_database_url: '%env(urlencode:DATABASE_URL)%' .. code-block:: php - // config/packages/framework.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; - - use Symfony\Component\DependencyInjection\ContainerBuilder; - use Symfony\Config\FrameworkConfig; + // config/services.php + namespace Symfony\Config; - return static function (ContainerBuilder $container): void { - $container->setParameter('env(DATABASE_URL)', 'mysql://db_user:foo@b$r@127.0.0.1:3306/db_name'); - $container->setParameter('encoded_database_url', '%env(urlencode:DATABASE_URL)%'); - }; + return [ + new ParametersConfig([ + 'env(DATABASE_URL)' => 'mysql://db_user:foo@b$r@127.0.0.1:3306/db_name', + 'encoded_database_url' => env('DATABASE_URL')->urlencode(), + ]), + ]; It is also possible to combine any number of processors: @@ -524,7 +595,7 @@ It is also possible to combine any number of processors: .. code-block:: yaml - # config/packages/framework.yaml + # config/packages/google.yaml parameters: env(AUTH_FILE): "%kernel.project_dir%/config/auth.json" google: @@ -536,15 +607,21 @@ It is also possible to combine any number of processors: .. code-block:: php - // config/packages/framework.php - $container->setParameter('env(AUTH_FILE)', '%kernel.project_dir%/config/auth.json'); - // 1. gets the value of the AUTH_FILE env var - // 2. replaces the values of any config param to get the config path - // 3. gets the content of the file stored in that path - // 4. JSON-decodes the content of the file and returns it - $container->loadFromExtension('google', [ - 'auth' => '%env(json:file:resolve:AUTH_FILE)%', - ]); + // config/packages/google.php + namespace Symfony\Config; + + return [ + new ParametersConfig([ + 'env(AUTH_FILE)' => '%kernel.project_dir%/config/auth.json', + ]), + new GoogleConfig([ + // 1. gets the value of the AUTH_FILE env var + // 2. replaces the values of any config param to get the config path + // 3. gets the content of the file stored in that path + // 4. JSON-decodes the content of the file and returns it + 'auth' => env('AUTH_FILE')->resolve()->file()->json(), + ]), + ]; Custom Environment Variable Processors -------------------------------------- diff --git a/configuration/front_controllers_and_kernel.rst b/configuration/front_controllers_and_kernel.rst index 428aa13e871..ad09a1134a6 100644 --- a/configuration/front_controllers_and_kernel.rst +++ b/configuration/front_controllers_and_kernel.rst @@ -169,12 +169,13 @@ parameter used, for example, to turn Twig's debug mode on: .. code-block:: php // config/packages/twig.php - use Symfony\Config\TwigConfig; + namespace Symfony\Config; - return static function (TwigConfig $twig): void { - // ... - $twig->debug('%kernel.debug%'); - }; + return [ + new TwigConfig([ + 'debug' => '%kernel.debug%', + ]), + ]; The Environments ---------------- diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst index 947abefc807..01678cf12f7 100644 --- a/configuration/micro_kernel_trait.rst +++ b/configuration/micro_kernel_trait.rst @@ -360,15 +360,14 @@ because the configuration started to get bigger: .. code-block:: php // config/framework.php - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework): void { - $framework - ->secret('SOME_SECRET') - ->profiler() - ->onlyExceptions(false) - ; - }; + namespace Symfony\Config; + + return [ + new FrameworkConfig([ + 'secret' => 'SOME_SECRET', + 'profiler' => ['only_exceptions' => false], + ]), + ]; This also loads attribute routes from an ``src/Controller/`` directory, which has one file in it:: diff --git a/configuration/override_dir_structure.rst b/configuration/override_dir_structure.rst index 1ace31069d3..7b8bb617919 100644 --- a/configuration/override_dir_structure.rst +++ b/configuration/override_dir_structure.rst @@ -169,11 +169,13 @@ for multiple directories): .. code-block:: php // config/packages/twig.php - use Symfony\Config\TwigConfig; + namespace Symfony\Config; - return static function (TwigConfig $twig): void { - $twig->defaultPath('%kernel.project_dir%/resources/views'); - }; + return [ + new TwigConfig([ + 'default_path' => '%kernel.project_dir%/resources/views', + ]), + ]; Override the Translations Directory ----------------------------------- @@ -195,13 +197,15 @@ configuration option to define your own translations directory (use :ref:`framew .. code-block:: php // config/packages/translation.php - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework): void { - $framework->translator() - ->defaultPath('%kernel.project_dir%/i18n') - ; - }; + namespace Symfony\Config; + + return [ + new FrameworkConfig([ + 'translator' => [ + 'default_path' => '%kernel.project_dir%/i18n', + ], + ]), + ]; .. _override-web-dir: .. _override-the-web-directory: diff --git a/configuration/secrets.rst b/configuration/secrets.rst index 5e91c82a611..c4e46f8bb60 100644 --- a/configuration/secrets.rst +++ b/configuration/secrets.rst @@ -117,14 +117,15 @@ If you stored a ``DATABASE_PASSWORD`` secret, you can reference it by: .. code-block:: php // config/packages/doctrine.php - use Symfony\Config\DoctrineConfig; + namespace Symfony\Config; - return static function (DoctrineConfig $doctrine): void { - $doctrine->dbal() - ->connection('default') - ->password(env('DATABASE_PASSWORD')) - ; - }; + return [ + new DoctrineConfig([ + 'dbal' => [ + 'password' => env('DATABASE_PASSWORD'), + ], + ]), + ]; The actual value will be resolved at runtime: container compilation and cache warmup don't need the **decryption key**. @@ -280,12 +281,14 @@ The secrets system is enabled by default and some of its behavior can be configu .. code-block:: php // config/packages/framework.php - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework): void { - $framework->secrets() - // ->vaultDirectory('%kernel.project_dir%/config/secrets/%kernel.environment%') - // ->localDotenvFile('%kernel.project_dir%/.env.%kernel.environment%.local') - // ->decryptionEnvVar('base64:default::SYMFONY_DECRYPTION_SECRET') - ; - }; + namespace Symfony\Config; + + return [ + new FrameworkConfig([ + 'secrets' => [ + // 'vault_directory' => '%kernel.project_dir%/config/secrets/%kernel.environment%', + // 'local_dotenv_file' => '%kernel.project_dir%/.env.%kernel.environment%.local', + // 'decryption_env_var' => 'base64:default::SYMFONY_DECRYPTION_SECRET', + ], + ]), + ]; diff --git a/console/commands_as_services.rst b/console/commands_as_services.rst index da8e664ba80..eed55235f2d 100644 --- a/console/commands_as_services.rst +++ b/console/commands_as_services.rst @@ -81,12 +81,17 @@ Or set the ``command`` attribute on the ``console.command`` tag in your service .. code-block:: php // config/services.php + namespace Symfony\Config; + use App\Command\SunshineCommand; - // ... - $container->register(SunshineCommand::class) - ->addTag('console.command', ['command' => 'app:sunshine']) - ; + return [ + new ServicesConfig([ + SunshineCommand::class => [ + 'tags' => ['console.command', ['command' => 'app:sunshine']], + ], + ]), + ]; .. note:: diff --git a/controller/error_pages.rst b/controller/error_pages.rst index 7fb7043de82..8c28e1f7902 100644 --- a/controller/error_pages.rst +++ b/controller/error_pages.rst @@ -161,15 +161,17 @@ automatically when installing ``symfony/framework-bundle``): .. code-block:: php // config/routes/framework.php - use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; - - return function (RoutingConfigurator $routes): void { - if ('dev' === $routes->env()) { - $routes->import('@FrameworkBundle/Resources/config/routing/errors.php', 'php') - ->prefix('/_error') - ; - } - }; + namespace Symfony\Config; + + return [ + 'when@dev' => new RoutesConfig([ + '_errors' => [ + 'resource' => '@FrameworkBundle/Resources/config/routing/errors.php', + 'type' => 'php', + 'prefix' => '/_error', + ], + ]), + ]; With this route added, you can use URLs like these to preview the *error* page for a given status code as HTML or for a given status code and format (you might @@ -245,12 +247,15 @@ configuration option to point to it: .. code-block:: php // config/packages/framework.php - use Symfony\Config\FrameworkConfig; + namespace Symfony\Config; + + use App\Controller\ErrorController; - return static function (FrameworkConfig $framework): void { - // ... - $framework->errorController('App\Controller\ErrorController::show'); - }; + return [ + new FrameworkConfig([ + 'error_controller' => ErrorController::class . '::show', + ]), + ]; The :class:`Symfony\\Component\\HttpKernel\\EventListener\\ErrorListener` class used by the FrameworkBundle as a listener of the ``kernel.exception`` event creates diff --git a/controller/service.rst b/controller/service.rst index 6d78b6dae02..995a1fb0b0c 100644 --- a/controller/service.rst +++ b/controller/service.rst @@ -146,15 +146,17 @@ a service like: ``App\Controller\HelloController::index``: .. code-block:: php // config/routes.php + namespace Symfony\Config; + use App\Controller\HelloController; - use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; - return function (RoutingConfigurator $routes): void { - $routes->add('hello', '/hello') - ->controller([HelloController::class, 'index']) - ->methods(['GET']) - ; - }; + return new RoutesConfig([ + 'hello' => [ + 'path' => '/hello', + 'controller' => [HelloController::class, 'index'], + 'methods' => ['GET'], + ], + ]); .. _controller-service-invoke: @@ -193,12 +195,17 @@ which is a common practice when following the `ADR pattern`_ .. code-block:: php + // config/routes.php + namespace Symfony\Config; + use App\Controller\HelloController; - // app/config/routing.php - $collection->add('hello', new Route('/hello', [ - '_controller' => HelloController::class, - ])); + return new RoutesConfig([ + 'hello' => [ + 'path' => '/hello/{name}', + 'controller' => [HelloController::class, 'index'], + ], + ]); Alternatives to base Controller Methods --------------------------------------- diff --git a/controller/upload_file.rst b/controller/upload_file.rst index 88b8855d4d8..7cdd77c15e6 100644 --- a/controller/upload_file.rst +++ b/controller/upload_file.rst @@ -288,17 +288,19 @@ Then, define a service for this class: .. code-block:: php // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; use App\Service\FileUploader; - return static function (ContainerConfigurator $container): void { - $services = $container->services(); - - $services->set(FileUploader::class) - ->arg('$targetDirectory', '%brochures_directory%') - ; - }; + return [ + new ServicesConfig([ + FileUploader::class => [ + 'arguments' => [ + '$targetDirectory' => param('brochures_directory'), + ], + ], + ]), + ]; Now you're ready to use this service in the controller:: diff --git a/controller/value_resolver.rst b/controller/value_resolver.rst index 35f199826a9..f96f0125c0f 100644 --- a/controller/value_resolver.rst +++ b/controller/value_resolver.rst @@ -365,17 +365,20 @@ but you can set it yourself to change its ``priority`` or ``name`` attributes. .. code-block:: php // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; use App\ValueResolver\BookingIdValueResolver; - return static function (ContainerConfigurator $containerConfigurator): void { - $services = $containerConfigurator->services(); - - $services->set(BookingIdValueResolver::class) - ->tag('controller.argument_value_resolver', ['name' => 'booking_id', 'priority' => 150]) - ; - }; + return [ + new ServicesConfig([ + // ... + BookingIdValueResolver::class => [ + 'tags' => [ + 'controller.argument_value_resolver' => ['name' => 'booking_id', 'priority' => 150], + ], + ], + ]), + ]; While adding a priority is optional, it's recommended to add one to make sure the expected value is injected. The built-in ``RequestAttributeValueResolver``, diff --git a/deployment/proxies.rst b/deployment/proxies.rst index 016ef136412..795c8cc3c6a 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -47,20 +47,20 @@ using the following configuration options: .. code-block:: php // config/packages/framework.php - use Symfony\Config\FrameworkConfig; + namespace Symfony\Config; - return static function (FrameworkConfig $framework): void { - $framework + return [ + new FrameworkConfig([ // the IP address (or range) of your proxy - ->trustedProxies('192.0.0.1,10.0.0.0/8') + 'trusted_proxies' => ['192.0.0.1,10.0.0.0/8', 'private_ranges'], // shortcut for private IP address ranges of your proxy - ->trustedProxies('private_ranges') - // trust *all* "X-Forwarded-*" headers (the ! prefix means to not trust those headers) - ->trustedHeaders(['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port', 'x-forwarded-prefix']) + 'trusted_proxies' => 'private_ranges', + // trust *all* "X-Forwarded-*" headers + 'trusted_headers' => ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port', 'x-forwarded-prefix'], // or, if your proxy instead uses the "Forwarded" header - ->trustedHeaders(['forwarded']) - ; - }; + 'trusted_headers' => ['forwarded'], + ]), + ]; .. danger:: diff --git a/doctrine/custom_dql_functions.rst b/doctrine/custom_dql_functions.rst index dfb13d5ca0f..524b493bf2b 100644 --- a/doctrine/custom_dql_functions.rst +++ b/doctrine/custom_dql_functions.rst @@ -26,23 +26,31 @@ In Symfony, you can register your custom DQL functions as follows: .. code-block:: php // config/packages/doctrine.php + namespace Symfony\Config; + use App\DQL\DatetimeFunction; use App\DQL\NumericFunction; use App\DQL\SecondStringFunction; use App\DQL\StringFunction; - use Symfony\Config\DoctrineConfig; - - return static function (DoctrineConfig $doctrine): void { - $defaultDql = $doctrine->orm() - ->entityManager('default') - // ... - ->dql(); - $defaultDql->stringFunction('test_string', StringFunction::class); - $defaultDql->stringFunction('second_string', SecondStringFunction::class); - $defaultDql->numericFunction('test_numeric', NumericFunction::class); - $defaultDql->datetimeFunction('test_datetime', DatetimeFunction::class); - }; + return [ + new DoctrineConfig([ + 'orm' => [ + 'dql' => [ + 'string_functions' => [ + 'test_string' => StringFunction::class, + 'second_string' => SecondStringFunction::class, + ], + 'numeric_functions' => [ + 'test_numeric' => NumericFunction::class, + ], + 'datetime_functions' => [ + 'test_datetime' => DatetimeFunction::class, + ], + ], + ], + ]), + ]; .. note:: @@ -68,17 +76,26 @@ In Symfony, you can register your custom DQL functions as follows: .. code-block:: php // config/packages/doctrine.php + namespace Symfony\Config; + use App\DQL\DatetimeFunction; - use Symfony\Config\DoctrineConfig; - - return static function (DoctrineConfig $doctrine): void { - $doctrine->orm() - // ... - ->entityManager('example_manager') - // place your functions here - ->dql() - ->datetimeFunction('test_datetime', DatetimeFunction::class); - }; + + return [ + new DoctrineConfig([ + 'orm' => [ + 'entity_managers' => [ + 'example_manager' => [ + // Place your functions here + 'dql' => [ + 'datetime_functions' => [ + 'test_datetime' => DatetimeFunction::class, + ], + ], + ], + ], + ], + ]), + ]; .. warning:: diff --git a/doctrine/dbal.rst b/doctrine/dbal.rst index fd6f748401d..b1619f75a7d 100644 --- a/doctrine/dbal.rst +++ b/doctrine/dbal.rst @@ -81,15 +81,21 @@ mapping types, read Doctrine's `Custom Mapping Types`_ section of their document .. code-block:: php // config/packages/doctrine.php + namespace Symfony\Config; + use App\Type\CustomFirst; use App\Type\CustomSecond; - use Symfony\Config\DoctrineConfig; - return static function (DoctrineConfig $doctrine): void { - $dbal = $doctrine->dbal(); - $dbal->type('custom_first')->class(CustomFirst::class); - $dbal->type('custom_second')->class(CustomSecond::class); - }; + return [ + new DoctrineConfig([ + 'dbal' => [ + 'types' => [ + 'custom_first' => CustomFirst::class, + 'custom_second' => CustomSecond::class, + ], + ], + ]), + ]; Registering custom Mapping Types in the SchemaTool -------------------------------------------------- @@ -114,13 +120,17 @@ mapping type: .. code-block:: php // config/packages/doctrine.php - use Symfony\Config\DoctrineConfig; - - return static function (DoctrineConfig $doctrine): void { - $dbalDefault = $doctrine->dbal() - ->connection('default'); - $dbalDefault->mappingType('enum', 'string'); - }; + namespace Symfony\Config; + + return [ + new DoctrineConfig([ + 'dbal' => [ + 'mapping_types' => [ + 'enum' => 'string', + ], + ], + ]), + ]; .. _`PDO`: https://www.php.net/pdo .. _`Doctrine`: https://www.doctrine-project.org/ diff --git a/doctrine/events.rst b/doctrine/events.rst index 0cd4803ccc7..3f9239238e4 100644 --- a/doctrine/events.rst +++ b/doctrine/events.rst @@ -180,35 +180,36 @@ with the ``doctrine.orm.entity_listener`` tag as follows: .. code-block:: php // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; use App\Entity\User; use App\EventListener\UserChangedNotifier; - return static function (ContainerConfigurator $container): void { - $services = $container->services(); - - $services->set(UserChangedNotifier::class) - ->tag('doctrine.orm.entity_listener', [ - // These are the options required to define the entity listener: - 'event' => 'postUpdate', - 'entity' => User::class, - - // These are other options that you may define if needed: - - // set the 'lazy' option to TRUE to only instantiate listeners when they are used - // 'lazy' => true, - - // set the 'entity_manager' option if the listener is not associated to the default manager - // 'entity_manager' => 'custom', - - // by default, Symfony looks for a method called after the event (e.g. postUpdate()) - // if it doesn't exist, it tries to execute the '__invoke()' method, but you can - // configure a custom method name with the 'method' option - // 'method' => 'checkUserChanges', - ]) - ; - }; + return [ + new ServicesConfig([ + UserChangedNotifier::class => [ + 'tags' => [ + 'doctrine.orm.entity_listener' => [ + // these are the options required to define the entity listener + 'event' => 'postUpdate', + 'entity' => User::class, + + // these are other options that you may define if needed + // set the 'lazy' option to TRUE to only instantiate listeners when they are used + // 'lazy' => true + + // set the 'entity_manager' option if the listener is not associated to the default manager + // 'entity_manager' => 'custom' + + // by default, Symfony looks for a method called after the event (e.g. postUpdate()) + // if it doesn't exist, it tries to execute the '__invoke()' method, but you can + // configure a custom method name with the 'method' option + // 'method' => 'checkUserChanges' + ], + ], + ], + ]), + ]; .. _doctrine-lifecycle-listener: @@ -294,28 +295,29 @@ listener in the Symfony application by creating a new service for it and .. code-block:: php // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; use App\EventListener\SearchIndexer; - return static function (ContainerConfigurator $container): void { - $services = $container->services(); - - // listeners are applied by default to all Doctrine connections - $services->set(SearchIndexer::class) - ->tag('doctrine.event_listener', [ - // this is the only required option for the lifecycle listener tag - 'event' => 'postPersist', - - // listeners can define their priority in case multiple listeners are associated - // to the same event (default priority = 0; higher numbers = listener is run earlier) - 'priority' => 500, - - # you can also restrict listeners to a specific Doctrine connection - 'connection' => 'default', - ]) - ; - }; + return [ + new ServicesConfig([ + SearchIndexer::class => [ + 'tags' => [ + 'doctrine.event_listener' => [ + // this is the only required option for the lifecycle listener tag + 'event' => 'postPersist', + + // listeners can define their priority in case multiple listeners are associated + // to the same event (default priority = 0; higher numbers = listener is run earlier) + 'priority' => 500, + + // you can also restrict listeners to a specific Doctrine connection + 'connection' => 'default', + ], + ], + ], + ]), + ]; .. versionadded:: 2.8.0 diff --git a/doctrine/multiple_entity_managers.rst b/doctrine/multiple_entity_managers.rst index 3d295b9939f..dedd002d231 100644 --- a/doctrine/multiple_entity_managers.rst +++ b/doctrine/multiple_entity_managers.rst @@ -58,36 +58,50 @@ The following configuration code shows how you can configure two entity managers .. code-block:: php // config/packages/doctrine.php - use Symfony\Config\DoctrineConfig; - - return static function (DoctrineConfig $doctrine): void { - // Connections: - $doctrine->dbal() - ->connection('default') - ->url(env('DATABASE_URL')->resolve()); - $doctrine->dbal() - ->connection('customer') - ->url(env('CUSTOMER_DATABASE_URL')->resolve()); - $doctrine->dbal()->defaultConnection('default'); - - // Entity Managers: - $doctrine->orm()->defaultEntityManager('default'); - $defaultEntityManager = $doctrine->orm()->entityManager('default'); - $defaultEntityManager->connection('default'); - $defaultEntityManager->mapping('Main') - ->isBundle(false) - ->dir('%kernel.project_dir%/src/Entity/Main') - ->prefix('App\Entity\Main') - ->alias('Main'); - $customerEntityManager = $doctrine->orm()->entityManager('customer'); - $customerEntityManager->connection('customer'); - $customerEntityManager->mapping('Customer') - ->isBundle(false) - ->dir('%kernel.project_dir%/src/Entity/Customer') - ->prefix('App\Entity\Customer') - ->alias('Customer') - ; - }; + namespace Symfony\Config; + + return [ + new DoctrineConfig([ + 'dbal' => [ + 'connections' => [ + 'default' => [ + 'url' => env('DATABASE_URL')->resolve(), + ], + 'customer' => [ + 'url' => env('CUSTOMER_DATABASE_URL')->resolve(), + ], + ], + 'default_connection' => 'default', + ], + 'orm' => [ + 'default_entity_manager' => 'default', + 'entity_managers' => [ + 'default' => [ + 'connection' => 'default', + 'mappings' => [ + 'Main' => [ + 'is_bundle' => false, + 'dir' => '%kernel.project_dir%/src/Entity/Main', + 'prefix' => 'App\Entity\Main', + 'alias' => 'Main', + ], + ], + ], + 'customer' => [ + 'connection' => 'customer', + 'mappings' => [ + 'Customer' => [ + 'is_bundle' => false, + 'dir' => '%kernel.project_dir%/src/Entity/Customer', + 'prefix' => 'App\Entity\Customer', + 'alias' => 'Customer', + ], + ], + ], + ], + ], + ]), + ]; In this case, you've defined two entity managers and called them ``default`` and ``customer``. The ``default`` entity manager manages entities in the diff --git a/doctrine/resolve_target_entity.rst b/doctrine/resolve_target_entity.rst index 1e281f52b62..6f4e7dd65bf 100644 --- a/doctrine/resolve_target_entity.rst +++ b/doctrine/resolve_target_entity.rst @@ -105,15 +105,20 @@ how to replace the interface with the concrete class: .. code-block:: php // config/packages/doctrine.php + namespace Symfony\Config; + use App\Entity\Customer; use App\Model\InvoiceSubjectInterface; - use Symfony\Config\DoctrineConfig; - return static function (DoctrineConfig $doctrine): void { - $orm = $doctrine->orm(); - // ... - $orm->resolveTargetEntity(InvoiceSubjectInterface::class, Customer::class); - }; + return [ + new DoctrineConfig([ + 'orm' => [ + 'resolve_target_entities' => [ + InvoiceSubjectInterface::class => Customer::class, + ], + ], + ]), + ]; Final Thoughts -------------- diff --git a/event_dispatcher.rst b/event_dispatcher.rst index 0a47922ffeb..31b1e39759d 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -74,17 +74,17 @@ notify Symfony that it is an event listener by using a special "tag": .. code-block:: php // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; use App\EventListener\ExceptionListener; - return function(ContainerConfigurator $container): void { - $services = $container->services(); - - $services->set(ExceptionListener::class) - ->tag('kernel.event_listener') - ; - }; + return [ + new ServicesConfig([ + ExceptionListener::class => [ + 'tags' => ['kernel.event_listener'], + ], + ]), + ]; Symfony follows this logic to decide which method to call inside the event listener class: @@ -470,10 +470,16 @@ First, define some token configuration as parameters: .. code-block:: php // config/services.php - $container->setParameter('tokens', [ - 'client1' => 'pass1', - 'client2' => 'pass2', - ]); + namespace Symfony\Config; + + return [ + new ParametersConfig([ + 'tokens' => [ + 'client1' => 'pass1', + 'client2' => 'pass2', + ], + ]), + ]; Tag Controllers to Be Checked ............................. diff --git a/form/bootstrap4.rst b/form/bootstrap4.rst index 620a3b78ed8..a28875d464a 100644 --- a/form/bootstrap4.rst +++ b/form/bootstrap4.rst @@ -37,13 +37,13 @@ configuration: .. code-block:: php // config/packages/twig.php - use Symfony\Config\TwigConfig; + namespace Symfony\Config; - return static function (TwigConfig $twig): void { - $twig->formThemes(['bootstrap_4_layout.html.twig']); - - // ... - }; + return [ + new TwigConfig([ + 'form_themes' => ['bootstrap_4_layout.html.twig'], + ]), + ]; If you prefer to apply the Bootstrap styles on a form to form basis, include the ``form_theme`` tag in the templates where those forms are used: diff --git a/form/bootstrap5.rst b/form/bootstrap5.rst index deb21c23fe2..7a8c98f4a58 100644 --- a/form/bootstrap5.rst +++ b/form/bootstrap5.rst @@ -37,13 +37,13 @@ configuration: .. code-block:: php // config/packages/twig.php - use Symfony\Config\TwigConfig; + namespace Symfony\Config; - return static function(TwigConfig $twig): void { - $twig->formThemes(['bootstrap_5_layout.html.twig']); - - // ... - }; + return [ + new TwigConfig([ + 'form_themes' => ['bootstrap_5_layout.html.twig'], + ]), + ]; If you prefer to apply the Bootstrap styles on a form to form basis, include the ``form_theme`` tag in the templates where those forms are used: diff --git a/form/create_custom_field_type.rst b/form/create_custom_field_type.rst index 3fb0ed7edee..98a2c149526 100644 --- a/form/create_custom_field_type.rst +++ b/form/create_custom_field_type.rst @@ -379,14 +379,16 @@ add this new template at the end of the list (each theme overrides all the previ .. code-block:: php // config/packages/twig.php - use Symfony\Config\TwigConfig; + namespace Symfony\Config; - return static function (TwigConfig $twig): void { - $twig->formThemes([ - '...', - 'form/custom_types.html.twig', - ]); - }; + return [ + new TwigConfig([ + 'form_themes' => [ + '...', + 'form/custom_types.html.twig', + ], + ]), + ]; The last step is to create the actual Twig template that will render the type. The template contents depend on which HTML, CSS and JavaScript frameworks and diff --git a/form/form_themes.rst b/form/form_themes.rst index 58aa4b7251f..80739bd65a0 100644 --- a/form/form_themes.rst +++ b/form/form_themes.rst @@ -70,15 +70,13 @@ want to use another theme for all the forms of your app, configure it in the .. code-block:: php // config/packages/twig.php - use Symfony\Config\TwigConfig; + namespace Symfony\Config; - return static function (TwigConfig $twig): void { - $twig->formThemes([ - 'bootstrap_5_horizontal_layout.html.twig', - ]); - - // ... - }; + return [ + new TwigConfig([ + 'form_themes' => ['bootstrap_5_horizontal_layout.html.twig'], + ]), + ]; You can pass multiple themes to this option because sometimes form themes only redefine a few elements. This way, if some theme doesn't override some element, @@ -480,15 +478,13 @@ you want to apply the theme globally to all forms, define the .. code-block:: php // config/packages/twig.php - use Symfony\Config\TwigConfig; + namespace Symfony\Config; - return static function (TwigConfig $twig): void { - $twig->formThemes([ - 'form/my_theme.html.twig', - ]); - - // ... - }; + return [ + new TwigConfig([ + 'form_themes' => ['form/my_theme.html.twig'], + ]), + ]; If you only want to apply it to some specific forms, use the ``form_theme`` tag: diff --git a/form/type_guesser.rst b/form/type_guesser.rst index 59fdfffe37f..e3f3405d077 100644 --- a/form/type_guesser.rst +++ b/form/type_guesser.rst @@ -194,11 +194,17 @@ and tag it with ``form.type_guesser``: .. code-block:: php // config/services.php + namespace Symfony\Config; + use App\Form\TypeGuesser\PhpDocTypeGuesser; - $container->register(PhpDocTypeGuesser::class) - ->addTag('form.type_guesser') - ; + return [ + new ServicesConfig([ + PhpDocTypeGuesser::class => [ + 'tags' => ['form.type_guesser'], + ], + ]), + ]; .. sidebar:: Registering a Type Guesser in the Component diff --git a/forms.rst b/forms.rst index 3d75efe3c57..38a80ae37a8 100644 --- a/forms.rst +++ b/forms.rst @@ -342,13 +342,13 @@ can set this option to generate forms compatible with the Bootstrap 5 CSS framew .. code-block:: php // config/packages/twig.php - use Symfony\Config\TwigConfig; + namespace Symfony\Config; - return static function (TwigConfig $twig): void { - $twig->formThemes(['bootstrap_5_layout.html.twig']); - - // ... - }; + return [ + new TwigConfig([ + 'form_themes' => ['bootstrap_5_layout.html.twig'], + ]), + ]; The :ref:`built-in Symfony form themes ` include Bootstrap 3, 4 and 5, Foundation 5 and 6, as well as Tailwind 2. You can also diff --git a/frontend/custom_version_strategy.rst b/frontend/custom_version_strategy.rst index 8a20c6acfaa..f8ff1479c8e 100644 --- a/frontend/custom_version_strategy.rst +++ b/frontend/custom_version_strategy.rst @@ -108,21 +108,20 @@ After creating the strategy PHP class, register it as a Symfony service. .. code-block:: php // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; + namespace Symfony\Config; use App\Asset\VersionStrategy\GulpBusterVersionStrategy; - return function(ContainerConfigurator $container): void { - $services = $container->services(); - - $services->set(GulpBusterVersionStrategy::class) - ->args( - [ + return [ + new ServicesConfig([ + GulpBusterVersionStrategy::class => [ + 'arguments' => [ '%kernel.project_dir%/busters.json', '%%s?version=%%s', - ] - ); - }; + ], + ], + ]), + ]; Finally, enable the new asset versioning for all the application assets or just for some :ref:`asset package ` thanks to @@ -141,14 +140,16 @@ the :ref:`version_strategy ` option: .. code-block:: php // config/packages/framework.php + namespace Symfony\Config; + use App\Asset\VersionStrategy\GulpBusterVersionStrategy; - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework): void { - // ... - $framework->assets() - ->versionStrategy(GulpBusterVersionStrategy::class) - ; - }; + + return [ + new FrameworkConfig([ + 'assets' => [ + 'version_strategy' => GulpBusterVersionStrategy::class, + ], + ]), + ]; .. _`gulp-buster`: https://www.npmjs.com/package/gulp-buster diff --git a/html_sanitizer.rst b/html_sanitizer.rst index 63a3caea4bc..2292e69549a 100644 --- a/html_sanitizer.rst +++ b/html_sanitizer.rst @@ -171,14 +171,19 @@ You can do this by defining a new HTML sanitizer in the configuration: .. code-block:: php // config/packages/framework.php - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework): void { - $framework->htmlSanitizer() - ->sanitizer('app.post_sanitizer') - ->blockElement('h1') - ; - }; + namespace Symfony\Config; + + return [ + new FrameworkConfig([ + 'html_sanitizer' => [ + 'sanitizers' => [ + 'app.post_sanitizer' => [ + 'block_elements' => ['h1'], + ], + ], + ], + ]), + ]; .. code-block:: php-standalone @@ -264,16 +269,21 @@ Safe elements .. code-block:: php // config/packages/framework.php - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework): void { - $framework->htmlSanitizer() - ->sanitizer('app.post_sanitizer') - // enable either of these - ->allowSafeElements(true) - ->allowStaticElements(true) - ; - }; + namespace Symfony\Config; + + return [ + new FrameworkConfig([ + 'html_sanitizer' => [ + 'sanitizers' => [ + 'app.post_sanitizer' => [ + // enable either of these + 'allow_safe_elements' => true, + 'allow_static_elements' => true, + ], + ], + ], + ]), + ]; .. code-block:: php-standalone @@ -317,24 +327,28 @@ attributes from the `W3C Standard Proposal`_ are allowed. .. code-block:: php // config/packages/framework.php - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework): void { - $framework->htmlSanitizer() - ->sanitizer('app.post_sanitizer') - // allow the
element and 2 attributes - ->allowElement('article', ['class', 'data-attr']) - - // allow the element and preserve the src attribute - ->allowElement('img', 'src') - - // allow the

element with all safe attributes - ->allowElement('h1', '*') - - // allow the
element with no attributes - ->allowElement('div', []) - ; - }; + namespace Symfony\Config; + + return [ + new FrameworkConfig([ + 'html_sanitizer' => [ + 'sanitizers' => [ + 'app.post_sanitizer' => [ + 'allow_elements' => [ + // allow the
element and 2 attributes + 'article' => ['class', 'data-attr'], + // allow the element and preserve the src attribute + 'img' => 'src', + // allow the

element with all safe attributes + 'h1' => '*', + // allow the
element with no attributes + 'div' => [], + ], + ], + ], + ], + ]), + ]; .. code-block:: php-standalone @@ -384,17 +398,22 @@ This can also be used to remove elements from the allow list. .. code-block:: php // config/packages/framework.php - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework): void { - $framework->htmlSanitizer() - ->sanitizer('app.post_sanitizer') - // remove
, but process the children - ->blockElement('div') - // remove
and its children - ->dropElement('figure') - ; - }; + namespace Symfony\Config; + + return [ + new FrameworkConfig([ + 'html_sanitizer' => [ + 'sanitizers' => [ + 'app.post_sanitizer' => [ + // remove
, but process the children + 'block_elements' => ['div'], + // remove
and its children + 'drop_elements' => ['figure'], + ], + ], + ], + ]), + ]; .. code-block:: php-standalone @@ -436,18 +455,24 @@ on all elements allowed *before this setting*. .. code-block:: php // config/packages/framework.php - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework): void { - $framework->htmlSanitizer() - ->sanitizer('app.post_sanitizer') - // allow "src' on