`:
+
+.. code-block:: html+twig
+
+ {% set voter_decision = access_decision('post_edit', post) %}
+ {% if voter_decision.isGranted() %}
+ {# ... #}
+ {% else %}
+ {# before showing voter messages to end users, make sure it's safe to do so #}
+ {{ voter_decision.message }}
+ {% endif %}
+
+ {% set voter_decision = access_decision('post_edit', post, anotherUser) %}
+ {% if voter_decision.isGranted() %}
+ {# ... #}
+ {% else %}
+ The {{ anotherUser.name }} user doesn't have sufficient permission:
+ {# before showing voter messages to end users, make sure it's safe to do so #}
+ {{ voter_decision.message }}
+ {% endif %}
+
.. _security-isgrantedforuser:
Securing other Services
@@ -2594,10 +2229,36 @@ want to include extra details only for users that have a ``ROLE_SALES_ADMIN`` ro
is unavailable (e.g., in a CLI context such as a message queue or cron job), you
can use the ``isGrantedForUser()`` method to explicitly set the target user.
- .. versionadded:: 7.3
+You can also use the ``getAccessDecision()`` and ``getAccessDecisionForUser()``
+methods to check authorization and get to retrieve the reasons for denying
+permission in :ref:`your custom security voters `::
- The :method:`Symfony\\Bundle\\SecurityBundle\\Security::isGrantedForUser`
- method was introduced in Symfony 7.3.
+ // src/SalesReport/SalesReportManager.php
+
+ // ...
+ use Symfony\Bundle\SecurityBundle\Security;
+
+ class SalesReportManager
+ {
+ public function __construct(
+ private Security $security,
+ ) {
+ }
+
+ public function generateReport(): void
+ {
+ $voterDecision = $this->security->getAccessDecision('ROLE_SALES_ADMIN');
+ if ($voterDecision->isGranted('ROLE_SALES_ADMIN')) {
+ // ...
+ } else {
+ // do something with $voterDecision->getMessage()
+ }
+
+ // ...
+ }
+
+ // ...
+ }
If you're using the :ref:`default services.yaml configuration `,
Symfony will automatically pass the ``security.helper`` to your service
@@ -2634,31 +2295,6 @@ the login page):
# but require authentication for all other admin routes
- { path: ^/admin, roles: ROLE_ADMIN }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -2713,11 +2349,6 @@ anonymous users access by checking if there is no user set on the token::
}
}
-.. versionadded:: 7.3
-
- The ``$vote`` argument of the ``voteOnAttribute()`` method was introduced
- in Symfony 7.3.
-
Setting Individual User Permissions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2809,11 +2440,6 @@ Two strategies are supported:
return $data;
}
-.. versionadded:: 7.3
-
- Support for hashing passwords with ``crc32c`` in session serialization was
- introduced in Symfony 7.3.
-
If you're having problems authenticating, it could be that you *are* authenticating
successfully, but you immediately lose authentication after the first redirect.
@@ -2863,26 +2489,6 @@ for these events.
- name: kernel.event_subscriber
dispatcher: security.event_dispatcher.main
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -3023,3 +2629,4 @@ Authorization (Denying Access)
.. _`Login CSRF attacks`: https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests
.. _`PHP date relative formats`: https://www.php.net/manual/en/datetime.formats.php#datetime.formats.relative
.. _`Oauth2-client`: https://github.com/thephpleague/oauth2-client
+.. _`Mermaid CLI`: https://github.com/mermaid-js/mermaid-cli
diff --git a/security/access_control.rst b/security/access_control.rst
index 8e62e8a84c7..3bece6b7210 100644
--- a/security/access_control.rst
+++ b/security/access_control.rst
@@ -62,48 +62,6 @@ Take the following ``access_control`` entries as an example:
- { attributes: {'_route': 'admin'}, roles: ROLE_ADMIN }
- { route: 'admin', roles: ROLE_ADMIN }
- .. code-block:: xml
-
-
-
-
-
-
- 10.0.0.1, 10.0.0.2
-
-
-
-
-
-
-
-
-
-
-
-
- 127.0.0.1
- ::1
- %env(TRUSTED_IPS)%
-
-
-
-
-
-
-
- admin
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -292,31 +250,6 @@ pattern so that it is only accessible by requests from the local server itself:
- { path: '^/internal', roles: PUBLIC_ACCESS, ips: [127.0.0.1, ::1, 192.168.0.1/24] }
- { path: '^/internal', roles: ROLE_NO_ACCESS }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
- 127.0.0.1
- ::1
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -383,28 +316,6 @@ key:
roles: 'ROLE_ADMIN'
allow_if: "'127.0.0.1' == request.getClientIp() or request.headers.has('X-Secure-Access')"
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -462,27 +373,6 @@ access those URLs via a specific port. This could be useful for example for
access_control:
- { path: ^/cart/checkout, roles: PUBLIC_ACCESS, port: 8080 }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -516,27 +406,6 @@ the user will be redirected to ``https``:
access_control:
- { path: ^/cart/checkout, roles: PUBLIC_ACCESS, requires_channel: https }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
diff --git a/security/access_denied_handler.rst b/security/access_denied_handler.rst
index 37490e3120b..94c77479441 100644
--- a/security/access_denied_handler.rst
+++ b/security/access_denied_handler.rst
@@ -64,25 +64,6 @@ Now, configure this service ID as the entry point for the firewall:
# ...
entry_point: App\Security\AuthenticationEntryPoint
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -140,25 +121,6 @@ configure it under your firewall:
# ...
access_denied_handler: App\Security\AccessDeniedHandler
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
diff --git a/security/access_token.rst b/security/access_token.rst
index 2c070f72e92..4992189e57b 100644
--- a/security/access_token.rst
+++ b/security/access_token.rst
@@ -39,25 +39,6 @@ digital signature, etc.).
access_token:
token_handler: App\Security\AccessTokenHandler
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -164,31 +145,6 @@ You can also create a custom extractor. The class must implement
# or provide the service ID of a custom extractor
token_extractors: 'App\Security\CustomTokenExtractor'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
- request_body
-
-
- App\Security\CustomTokenExtractor
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -226,28 +182,6 @@ important**: the first in the list is called first.
- 'header'
- 'App\Security\CustomTokenExtractor'
- .. code-block:: xml
-
-
-
-
-
-
-
-
- header
- App\Security\CustomTokenExtractor
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -301,27 +235,6 @@ and configure the service ID as the ``success_handler``:
token_handler: App\Security\AccessTokenHandler
success_handler: App\Security\Authentication\AuthenticationSuccessHandler
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -377,27 +290,6 @@ and retrieve the user info:
token_handler:
oidc_user_info: https://www.example.com/realms/demo/protocol/openid-connect/userinfo
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -437,31 +329,6 @@ Next, configure the ``base_uri`` and ``discovery`` options:
cache:
id: cache.app
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -478,10 +345,6 @@ Next, configure the ``base_uri`` and ``discovery`` options:
;
};
-.. versionadded:: 7.3
-
- Support for OpenID Connect Discovery was introduced in Symfony 7.3.
-
Following the `OpenID Connect Specification`_, the ``sub`` claim is used as user
identifier by default. To use another claim, specify it using the ``claim`` option:
@@ -499,29 +362,6 @@ identifier by default. To use another claim, specify it using the ``claim`` opti
claim: email
base_uri: https://www.example.com/realms/demo/protocol/openid-connect/userinfo
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -554,29 +394,6 @@ specify the service name via the ``client`` option:
oidc_user_info:
client: oidc.client
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -644,41 +461,6 @@ it, and retrieves the user information from it. Optionally, the token can be enc
algorithms: ['ECDH-ES', 'A128GCM']
keyset: '{"keys": [...]}' # Encryption private keyset
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ES256
- RS256
- https://oidc.example.com
-
- ECDH-ES
- A128GCM
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -708,15 +490,6 @@ it, and retrieves the user information from it. Optionally, the token can be enc
;
};
-.. versionadded:: 7.1
-
- The support of multiple algorithms to sign the JWS was introduced in Symfony 7.1.
- In previous versions, only the ``ES256`` algorithm was supported.
-
-.. versionadded:: 7.3
-
- Support for encryption algorithms to decrypt JWEs was introduced in Symfony 7.3.
-
To enable `OpenID Connect Discovery`_, the ``OidcTokenHandler`` requires the
``symfony/cache`` package to store the OIDC configuration in the cache. If you
haven't installed it yet, run the following command:
@@ -748,34 +521,6 @@ from the OpenID Connect Discovery), and configure the ``discovery`` option:
cache:
id: cache.app
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
- ES256
- RS256
- https://oidc.example.com
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -817,33 +562,6 @@ configuration:
audience: 'api-example'
issuers: ['https://oidc.example.com']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
- ES256
- RS256
- https://oidc.example.com
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -877,12 +595,82 @@ create your own User from the claims, you must
}
}
-Using CAS 2.0
--------------
+Configuring Multiple OIDC Discovery Endpoints
+.............................................
-.. versionadded:: 7.1
+The ``OidcTokenHandler`` supports multiple OIDC discovery endpoints, allowing it
+to validate tokens from different identity providers:
- The support for CAS token handlers was introduced in Symfony 7.1.
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # config/packages/security.yaml
+ security:
+ firewalls:
+ main:
+ access_token:
+ token_handler:
+ oidc:
+ algorithms: ['ES256', 'RS256']
+ audience: 'api-example'
+ issuers: ['https://oidc1.example.com', 'https://oidc2.example.com']
+ discovery:
+ base_uri:
+ - https://idp1.example.com/realms/demo/
+ - https://idp2.example.com/realms/demo/
+ cache:
+ id: cache.app
+
+ .. code-block:: php
+
+ // config/packages/security.php
+ use Symfony\Config\SecurityConfig;
+
+ return static function (SecurityConfig $security) {
+ $security->firewall('main')
+ ->accessToken()
+ ->tokenHandler()
+ ->oidc()
+ ->algorithms(['ES256', 'RS256'])
+ ->audience('api-example')
+ ->issuers(['https://oidc1.example.com', 'https://oidc2.example.com'])
+ ->discovery()
+ ->baseUri([
+ 'https://idp1.example.com/realms/demo/',
+ 'https://idp2.example.com/realms/demo/',
+ ])
+ ->cache(['id' => 'cache.app'])
+ ;
+ };
+
+The token handler fetches the JWK sets from all configured discovery endpoints
+and builds a combined JWK set for token validation. This lets your application
+accept and validate tokens from multiple identity providers within a single firewall.
+
+Creating a OIDC token from the command line
+-------------------------------------------
+
+The ``security:oidc:generate-token`` command helps you generate JWTs. It's mostly
+useful when developing or testing applications that use OIDC authentication:
+
+.. code-block:: terminal
+
+ # generate a token using the default configuration
+ $ php bin/console security:oidc:generate-token john.doe@example.com
+
+ # specify the firewall, algorithm, and issuer if multiple are available
+ $ php bin/console security:oidc:generate-token john.doe@example.com \
+ --firewall="api" \
+ --algorithm="HS256" \
+ --issuer="https://example.com"
+
+.. note::
+
+ The JWK used for signing must have the appropriate `key operation flags`_ set.
+
+Using CAS 2.0
+-------------
`Central Authentication Service (CAS)`_ is an enterprise multilingual single
sign-on solution and identity provider for the web and attempts to be a
@@ -914,29 +702,6 @@ You can configure a ``cas`` token handler as follows:
cas:
validation_url: https://www.example.com/cas/validate
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -969,29 +734,6 @@ specify the service name via the ``http_client`` option:
validation_url: https://www.example.com/cas/validate
http_client: cas.client
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -1024,29 +766,6 @@ By default the token handler will read the validation URL XML response with
validation_url: https://www.example.com/cas/validate
prefix: cas-example
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -1099,3 +818,4 @@ for :ref:`stateless firewalls `.
.. _`OpenID Connect Discovery`: https://openid.net/specs/openid-connect-discovery-1_0.html
.. _`RFC6750`: https://datatracker.ietf.org/doc/html/rfc6750
.. _`SAML2 (XML structures)`: https://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html
+.. _`key operation flags`: https://www.iana.org/assignments/jose/jose.xhtml#web-key-operations
diff --git a/security/csrf.rst b/security/csrf.rst
index 295a43fd9ff..14834c2476b 100644
--- a/security/csrf.rst
+++ b/security/csrf.rst
@@ -61,23 +61,6 @@ for more information):
# ...
csrf_protection: ~
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/framework.php
@@ -135,25 +118,6 @@ Globally, you can configure it under the ``framework.form`` option:
enabled: true
field_name: 'custom_token_name'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/framework.php
@@ -321,14 +285,26 @@ array, the attribute is ignored for that request, and no CSRF validation occurs:
// ... delete the object
}
-.. versionadded:: 7.1
+You can also choose where the CSRF token is read from using the ``tokenSource``
+parameter. This is a bitfield that allows you to combine different sources:
- The :class:`Symfony\\Component\\Security\\Http\\Attribute\\IsCsrfTokenValid`
- attribute was introduced in Symfony 7.1.
+* ``IsCsrfTokenValid::SOURCE_PAYLOAD`` (default): request payload (POST body / json)
+* ``IsCsrfTokenValid::SOURCE_QUERY``: query string
+* ``IsCsrfTokenValid::SOURCE_HEADER``: request header
-.. versionadded:: 7.3
+Example::
- The ``methods`` parameter was introduced in Symfony 7.3.
+ #[IsCsrfTokenValid(
+ 'delete-item',
+ tokenKey: 'token',
+ tokenSource: IsCsrfTokenValid::SOURCE_PAYLOAD | IsCsrfTokenValid::SOURCE_QUERY
+ )]
+ public function delete(Post $post): Response
+ {
+ // ... delete the object
+ }
+
+The token is checked against each selected source, and validation fails if none match.
CSRF Tokens and Compression Side-Channel Attacks
------------------------------------------------
@@ -344,10 +320,6 @@ and used to scramble it.
Stateless CSRF Tokens
---------------------
-.. versionadded:: 7.2
-
- Stateless anti-CSRF protection was introduced in Symfony 7.2.
-
Traditionally, CSRF tokens are stateful, meaning they're stored in the session.
However, some token IDs can be declared as stateless using the
``stateless_token_ids`` option. Stateless CSRF tokens are enabled by default
@@ -363,27 +335,6 @@ in applications using :ref:`Symfony Flex `.
csrf_protection:
stateless_token_ids: ['submit', 'authenticate', 'logout']
- .. code-block:: xml
-
-
-
-
-
-
-
- submit
- authenticate
- logout
-
-
-
-
.. code-block:: php
// config/packages/csrf.php
@@ -431,25 +382,6 @@ own services), and it sets ``submit`` as their default token identifier:
csrf_protection:
token_id: 'submit'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/csrf.php
diff --git a/security/custom_authenticator.rst b/security/custom_authenticator.rst
index 462ec21521c..ae7078cadd2 100644
--- a/security/custom_authenticator.rst
+++ b/security/custom_authenticator.rst
@@ -118,27 +118,6 @@ should review it:
custom_authenticators:
- App\Security\ApiKeyAuthenticator
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
- App\Security\ApiKeyAuthenticator
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -289,10 +268,6 @@ lowercasing identifiers helps treat values like "john.doe", "John.Doe", or
If needed, you can pass a normalizer as the third argument to ``UserBadge``.
This callable receives the ``$userIdentifier`` and must return a string.
-.. versionadded:: 7.3
-
- Support for user identifier normalizers was introduced in Symfony 7.3.
-
The example below uses a normalizer that converts usernames to a normalized,
ASCII-only, lowercase format::
diff --git a/security/entry_point.rst b/security/entry_point.rst
index cfbef00ff88..530692d61cb 100644
--- a/security/entry_point.rst
+++ b/security/entry_point.rst
@@ -30,33 +30,6 @@ You can configure this using the ``entry_point`` setting:
# configure the form authentication as the entry point for unauthenticated users
entry_point: form_login
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
- App\Security\SocialConnectAuthenticator
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -118,34 +91,6 @@ split the configuration into two separate firewalls:
- { path: '^/api', roles: ROLE_API_USER }
- { path: '^/', roles: ROLE_USER }
- .. code-block:: xml
-
-
-
-
-
-
-
-
- App\Security\ApiTokenAuthenticator
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
diff --git a/security/expressions.rst b/security/expressions.rst
index a4ec02c7b84..83b785999c4 100644
--- a/security/expressions.rst
+++ b/security/expressions.rst
@@ -228,11 +228,6 @@ returns an array of values that will be injected into the closure::
}
}
-.. versionadded:: 7.3
-
- The support for closures in the ``#[IsGranted]`` attribute was introduced
- in Symfony 7.3 and requires PHP 8.5.
-
Learn more
----------
diff --git a/security/firewall_restriction.rst b/security/firewall_restriction.rst
index be0237c0e39..1637fd79ab7 100644
--- a/security/firewall_restriction.rst
+++ b/security/firewall_restriction.rst
@@ -38,26 +38,6 @@ if the request path matches the configured ``pattern``.
pattern: ^/admin
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -97,26 +77,6 @@ only initialize if the host from the request matches against the configuration.
host: ^admin\.example\.com$
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -157,26 +117,6 @@ the provided HTTP methods.
methods: [GET, POST]
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -215,26 +155,6 @@ If the above options don't fit your needs you can configure any service implemen
request_matcher: App\Security\CustomRequestMatcher
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
diff --git a/security/force_https.rst b/security/force_https.rst
index 03d5230ca50..9e8bd60de9a 100644
--- a/security/force_https.rst
+++ b/security/force_https.rst
@@ -25,27 +25,6 @@ access control:
# catch all other URLs
- { path: '^/', roles: PUBLIC_ACCESS, requires_channel: https }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
diff --git a/security/form_login.rst b/security/form_login.rst
index 2b5eba96340..1ae00479575 100644
--- a/security/form_login.rst
+++ b/security/form_login.rst
@@ -39,27 +39,6 @@ a relative/absolute URL or a Symfony route name:
# ...
default_target_path: after_login_route_name
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -96,28 +75,6 @@ previously requested URL and always redirect to the default page:
# ...
always_use_default_target_path: true
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -184,28 +141,6 @@ parameter is included in the request, you may use the value of the
# ...
use_referer: true
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -251,28 +186,6 @@ option to define a new target via a relative/absolute URL or a Symfony route nam
# ...
failure_path: login_failure_route_name
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -327,29 +240,6 @@ redirects can be customized using the ``target_path_parameter`` and
target_path_parameter: go_to
failure_path_parameter: back_to
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
diff --git a/security/impersonating_user.rst b/security/impersonating_user.rst
index 6f22e7aace6..5625f930bb0 100644
--- a/security/impersonating_user.rst
+++ b/security/impersonating_user.rst
@@ -27,28 +27,6 @@ listener:
# ...
switch_user: true
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -93,26 +71,6 @@ as the value to the current URL:
# ...
switch_user: { parameter: X-Switch-User }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -211,27 +169,6 @@ also adjust the query parameter name via the ``parameter`` setting:
# ...
switch_user: { role: ROLE_ADMIN, parameter: _want_to_be_this_user }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -269,27 +206,6 @@ This feature allows you to control the redirection target route via ``target_rou
# ...
switch_user: { target_route: app_user_dashboard }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -325,27 +241,6 @@ be called):
# ...
switch_user: { role: CAN_SWITCH_USER }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
diff --git a/security/ldap.rst b/security/ldap.rst
index c4c3646122b..e5676e04745 100644
--- a/security/ldap.rst
+++ b/security/ldap.rst
@@ -78,33 +78,6 @@ An LDAP client can be configured using the built-in
protocol_version: 3
referrals: false
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
- my-server
- 389
- tls
-
- 3
- false
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -154,30 +127,6 @@ use the ``ldap`` user provider.
uid_key: uid
extra_fields: ['email']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -270,10 +219,6 @@ Symfony provides ``Symfony\Component\Ldap\Security\MemberOfRoles``, a concrete
implementation of the interface that fetches roles from the ``ismemberof``
attribute.
-.. versionadded:: 7.3
-
- The ``role_fetcher`` configuration option was introduced in Symfony 7.3.
-
uid_key
.......
@@ -392,26 +337,6 @@ Configuration example for form login
service: Symfony\Component\Ldap\Ldap
dn_string: 'uid={user_identifier},dc=example,dc=com'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -444,28 +369,6 @@ Configuration example for HTTP Basic
service: Symfony\Component\Ldap\Ldap
dn_string: 'uid={user_identifier},dc=example,dc=com'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -502,30 +405,6 @@ Configuration example for form login and query_string
search_dn: '...'
search_password: 'the-raw-password'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
diff --git a/security/login_link.rst b/security/login_link.rst
index 57d353278c2..c71a02b1a03 100644
--- a/security/login_link.rst
+++ b/security/login_link.rst
@@ -35,27 +35,6 @@ and ``signature_properties`` (explained below):
check_route: login_check
signature_properties: ['id']
- .. code-block:: xml
-
-
-
-
-
-
-
-
- id
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -106,19 +85,6 @@ intercept requests to this route:
login_check:
path: /login_check
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/routes.php
@@ -338,28 +304,6 @@ seconds). You can customize this using the ``lifetime`` option:
# lifetime in seconds
lifetime: 300
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -423,28 +367,6 @@ You can add more properties to the ``hash`` by using the
check_route: login_check
signature_properties: [id, email]
- .. code-block:: xml
-
-
-
-
-
-
-
-
- id
- email
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -493,30 +415,6 @@ cache. Enable this support by setting the ``max_uses`` option:
# optionally, configure the cache pool
#used_link_cache: 'cache.redis'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -568,28 +466,6 @@ the authenticator only handle HTTP POST methods:
check_post_only: true
max_uses: 1
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -713,30 +589,6 @@ Then, configure this service ID as the ``success_handler``:
max_uses: 1
success_handler: App\Security\Authentication\AuthenticationSuccessHandler
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
diff --git a/security/passwords.rst b/security/passwords.rst
index 7f05bc3acb9..e22c0d2a727 100644
--- a/security/passwords.rst
+++ b/security/passwords.rst
@@ -35,35 +35,6 @@ optionally some *algorithm options*:
algorithm: 'auto'
cost: 15
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -256,6 +227,60 @@ You can customize the reset password bundle's behavior by updating the
``reset_password.yaml`` file. For more information on the configuration,
check out the `SymfonyCastsResetPasswordBundle`_ guide.
+Injecting a Specific Password Hasher
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In some cases, you may define a password hasher in your configuration that is
+not tied to a user class. For example, you might use a separate hasher for
+password recovery codes or API tokens.
+
+With the following configuration:
+
+.. code-block:: yaml
+
+ # config/packages/security.yaml
+ security:
+ password_hashers:
+ recovery_code: 'auto'
+
+ firewalls:
+ main:
+ # ...
+
+You can inject the ``recovery_code`` password hasher into any service. However,
+you can't rely on standard autowiring, as Symfony doesn't know which specific
+hasher to provide.
+
+Instead, use the ``#[Target]`` attribute to explicitly request the hasher by
+its configuration key::
+
+ // src/Controller/HomepageController.php
+ namespace App\Controller;
+
+ use Symfony\Component\DependencyInjection\Attribute\Target;
+ use Symfony\Component\PasswordHasher\PasswordHasherInterface;
+
+ class HomepageController extends AbstractController
+ {
+ public function __construct(
+ #[Target('recovery_code')]
+ private readonly PasswordHasherInterface $passwordHasher,
+ ) {
+ }
+
+ #[Route('/')]
+ public function index(): Response
+ {
+ $plaintextToken = 'some-secret-token';
+
+ // Note: use hash(), not hashPassword(), as we are not using a UserInterface object
+ $hashedToken = $this->passwordHasher->hash($plaintextToken);
+ }
+ }
+
+When injecting a specific hasher by its name, you should type-hint the generic
+:class:`Symfony\\Component\\PasswordHasher\\PasswordHasherInterface`.
+
.. _security-password-migration:
Password Migration
@@ -299,40 +324,6 @@ on the new hasher to point to the old, legacy hasher(s):
- bcrypt # uses the "bcrypt" hasher with the default options
- legacy # uses the "legacy" hasher configured above
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
- bcrypt
-
-
- legacy
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -532,27 +523,6 @@ cost. This can be done with named hashers:
algorithm: auto
cost: 15
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -629,26 +599,6 @@ you must register a service for it in order to use it as a named hasher:
app_hasher:
id: 'App\Security\Hasher\MyCustomPasswordHasher'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -846,27 +796,6 @@ Now, define a password hasher using the ``id`` setting:
# the service ID of your custom hasher (the FQCN using the default services.yaml)
id: 'App\Security\Hasher\MyCustomPasswordHasher'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
diff --git a/security/remember_me.rst b/security/remember_me.rst
index 2fd0f7e8d1e..f62fde81d9e 100644
--- a/security/remember_me.rst
+++ b/security/remember_me.rst
@@ -26,37 +26,6 @@ the session lasts using a cookie with the ``remember_me`` firewall option:
# following line to always enable it.
#always_remember_me: true
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -77,12 +46,6 @@ the session lasts using a cookie with the ``remember_me`` firewall option:
;
};
-.. versionadded:: 7.2
-
- The ``secret`` option is no longer required starting from Symfony 7.2. By
- default, ``%kernel.secret%`` is used, which is defined using the
- ``APP_SECRET`` environment variable.
-
After enabling the ``remember_me`` system in the configuration, there are a
couple more things to do before remember me works correctly:
@@ -176,31 +139,6 @@ allow users to opt-out. In these cases, you can use the
# ...
always_remember_me: true
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -337,32 +275,6 @@ are fetched from the user object using the
# ...
signature_properties: ['password', 'updatedAt']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
- password
- updatedAt
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -420,31 +332,6 @@ You can enable the doctrine token provider using the ``doctrine`` setting:
token_provider:
doctrine: true
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -507,31 +394,6 @@ Then, configure the service ID of your custom token provider as ``service``:
token_provider:
service: App\Security\RememberMe\CustomTokenProvider
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
diff --git a/security/user_checkers.rst b/security/user_checkers.rst
index cf38aafa57e..7c385ddedb3 100644
--- a/security/user_checkers.rst
+++ b/security/user_checkers.rst
@@ -59,10 +59,6 @@ displayed to the user::
}
}
-.. versionadded:: 7.2
-
- The ``token`` argument for the ``checkPostAuth()`` method was introduced in Symfony 7.2.
-
Enabling the Custom User Checker
--------------------------------
@@ -87,28 +83,6 @@ is the service id of your user checker:
user_checker: App\Security\UserChecker
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -155,29 +129,6 @@ order in which user checkers are called::
tags:
- { name: security.user_checker.api, priority: 5 }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -218,33 +169,6 @@ Once your checker services are tagged, next you will need configure your firewal
user_checker: security.user_checker.chain.main
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
diff --git a/security/user_providers.rst b/security/user_providers.rst
index 73b723faaaf..9bd87648baa 100644
--- a/security/user_providers.rst
+++ b/security/user_providers.rst
@@ -45,32 +45,6 @@ the user provider uses :doc:`Doctrine ` to retrieve them.
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -140,27 +114,6 @@ To finish this, remove the ``property`` key from the user provider in
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -210,30 +163,6 @@ After setting up hashing, you can configure all the user information in
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -297,47 +226,6 @@ providers until the user is found:
chain:
providers: ['legacy_users', 'users', 'backend_users']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- backend_users
- legacy_users
- users
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -467,27 +355,6 @@ the user provider by adding it in ``security.yaml``:
your_custom_user_provider:
id: App\Security\UserProvider
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
diff --git a/security/voters.rst b/security/voters.rst
index 3543eae86c0..ea3f14665cb 100644
--- a/security/voters.rst
+++ b/security/voters.rst
@@ -49,11 +49,6 @@ which makes creating a voter even easier::
abstract protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null): bool;
}
-.. versionadded:: 7.3
-
- The ``$vote`` argument of the ``voteOnAttribute()`` method was introduced
- in Symfony 7.3.
-
.. _how-to-use-the-voter-in-a-controller:
Setup: Checking for Access in a Controller
@@ -124,6 +119,8 @@ calls out to the "voter" system. Right now, no voters will vote on whether or no
the user can "view" or "edit" a ``Post``. But you can create your *own* voter that
decides this using whatever logic you want.
+.. _creating-the-custom-voter:
+
Creating the custom Voter
-------------------------
@@ -210,6 +207,13 @@ would look like this::
}
}
+.. tip::
+
+ Votes define an ``$extraData`` property that you can use to store any data
+ that you might need later::
+
+ $vote->extraData['key'] = 'value'; // values can be of any type
+
That's it! The voter is done! Next, :ref:`configure it `.
To recap, here's what's expected from the two abstract methods:
@@ -433,24 +437,6 @@ security configuration:
strategy: unanimous
allow_if_all_abstain: false
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -480,23 +466,6 @@ option to use a custom service (your service must implement the
strategy_service: App\Security\MyCustomAccessDecisionStrategy
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
@@ -510,6 +479,56 @@ option to use a custom service (your service must implement the
;
};
+When creating custom decision strategies, you can store additional data in votes
+to be used later when making a decision. For example, if not all votes should
+have the same weight, you could store a ``score`` value for each vote::
+
+ // src/Security/PostVoter.php
+ namespace App\Security;
+
+ use App\Entity\Post;
+ use App\Entity\User;
+ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+ use Symfony\Component\Security\Core\Authorization\Voter\Vote;
+ use Symfony\Component\Security\Core\Authorization\Voter\Voter;
+
+ class PostVoter extends Voter
+ {
+ // ...
+
+ protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null): bool
+ {
+ // ...
+ $vote->extraData['score'] = 10;
+
+ // ...
+ }
+ }
+
+Then, access that value when counting votes to make a decision::
+
+ // src/Security/MyCustomAccessDecisionStrategy.php
+ use Symfony\Component\Security\Core\Authorization\Strategy\AccessDecisionStrategyInterface;
+
+ class MyCustomAccessDecisionStrategy implements AccessDecisionStrategyInterface
+ {
+ public function decide(\Traversable $results, $accessDecision = null): bool
+ {
+ $score = 0;
+
+ foreach ($results as $key => $result) {
+ $vote = $accessDecision->votes[$key];
+ if (array_key_exists('score', $vote->extraData)) {
+ $score += $vote->extraData['score'];
+ } else {
+ $score += $vote->result;
+ }
+ }
+
+ // ...
+ }
+ }
+
Custom Access Decision Manager
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -527,23 +546,6 @@ must implement the :class:`Symfony\\Component\\Security\\Core\\Authorization\\Ac
service: App\Security\MyCustomAccessDecisionManager
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/security.php
diff --git a/serializer.rst b/serializer.rst
index 0fb8f3039c0..35d4c364ffc 100644
--- a/serializer.rst
+++ b/serializer.rst
@@ -317,26 +317,6 @@ instance to disallow extra fields while deserializing:
default_context:
allow_extra_attributes: false
- .. code-block:: xml
-
-
-
-
-
-
-
-
- false
-
-
-
-
-
.. code-block:: php
// config/packages/serializer.php
@@ -1228,24 +1208,6 @@ setting the ``name_converter`` setting to
serializer:
name_converter: 'serializer.name_converter.camel_case_to_snake_case'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/serializer.php
@@ -1289,24 +1251,6 @@ setting the ``name_converter`` setting to
serializer:
name_converter: 'serializer.name_converter.snake_case_to_camel_case'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/serializer.php
@@ -1329,10 +1273,6 @@ setting the ``name_converter`` setting to
];
$serializer = new Serializer($normalizers, $encoders);
-.. versionadded:: 7.2
-
- The snake_case to CamelCase converter was introduced in Symfony 7.2.
-
.. _serializer-built-in-normalizers:
Serializer Normalizers
@@ -1377,10 +1317,6 @@ normalizers (in order of priority):
context option ``DateTimeNormalizer::CAST_KEY`` to ``int`` or
``float``.
- .. versionadded:: 7.1
-
- The ``DateTimeNormalizer::CAST_KEY`` context option was introduced in Symfony 7.1.
-
:class:`Symfony\\Component\\Serializer\\Normalizer\\ConstraintViolationListNormalizer`
This normalizer converts objects that implement
:class:`Symfony\\Component\\Validator\\ConstraintViolationListInterface`
@@ -1420,10 +1356,6 @@ normalizers (in order of priority):
This normalizer converts between :phpclass:`BcMath\\Number` or :phpclass:`GMP` objects and
strings or integers.
-.. versionadded:: 7.3
-
- The ``NumberNormalizer`` was introduced in Symfony 7.3.
-
:class:`Symfony\\Component\\Serializer\\Normalizer\\DataUriNormalizer`
This normalizer converts between :phpclass:`SplFileInfo` objects and a
`data URI`_ string (``data:...``) such that files can be embedded into
@@ -1476,7 +1408,7 @@ normalizers (in order of priority):
to read and write in the object. This allows it to access properties
directly or using getters, setters, hassers, issers, canners, adders and
removers. Names are generated by removing the ``get``, ``set``,
- ``has``, ``is``, ``add`` or ``remove`` prefix from the method name and
+ ``has``, ``is``, ``can``, ``add`` or ``remove`` prefix from the method name and
transforming the first letter to lowercase (e.g. ``getFirstName()`` ->
``firstName``).
@@ -1512,28 +1444,6 @@ like:
# register the normalizer with a high priority (called earlier)
- { name: 'serializer.normalizer', priority: 500 }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1599,10 +1509,6 @@ like:
Named Serializers
-----------------
-.. versionadded:: 7.2
-
- Named serializers were introduced in Symfony 7.2.
-
Sometimes, you may need multiple configurations for the serializer, such as
different default contexts, name converters, or sets of normalizers and encoders,
depending on the use case. For example, when your application communicates with
@@ -1627,39 +1533,6 @@ the ``named_serializers`` option:
default_context:
enable_max_depth: false
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
-
-
- false
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/serializer.php
@@ -1725,32 +1598,6 @@ or :ref:`serializer.encoder ` tags:
# add this normalizer to all serializers, including the default one
- serializer.normalizer: { serializer: '*' }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1771,13 +1618,6 @@ or :ref:`serializer.encoder ` tags:
;
};
-.. versionadded:: 7.3
-
- Before Symfony 7.3, named serializer normalizers were added automatically
- to the default serializer, so you had to set their ``autoconfigure``
- option to ``false`` to disable them. As of Symfony 7.3, they are no longer
- registered by default.
-
When the ``serializer`` attribute is not set, the service is registered only with
the default serializer.
@@ -1805,30 +1645,6 @@ named serializer by setting the ``include_built_in_normalizers`` and
include_built_in_normalizers: false
include_built_in_encoders: true
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/serializer.php
@@ -2471,10 +2287,6 @@ Now it deserializes like this:
$invoiceLine = $serializer->deserialize('{"invoiceItem":{...},...}', InvoiceLine::class, 'json');
// $invoiceLine contains new InvoiceLine(new Product(...))
-.. versionadded:: 7.3
-
- The ``defaultType`` parameter was added in Symfony 7.3.
-
.. _serializer-unwrapping-denormalizer:
Deserializing Input Partially (Unwrapping)
@@ -2536,10 +2348,6 @@ setting the serializer context option
Handling Boolean Values
~~~~~~~~~~~~~~~~~~~~~~~
-.. versionadded:: 7.1
-
- The ``AbstractNormalizer::FILTER_BOOL`` context option was introduced in Symfony 7.1.
-
PHP considers many different values as true or false. For example, the
strings ``true``, ``1``, and ``yes`` are considered true, while
``false``, ``0``, and ``no`` are considered false.
diff --git a/serializer/custom_name_converter.rst b/serializer/custom_name_converter.rst
index 49dafb02cc4..8fd6f419eec 100644
--- a/serializer/custom_name_converter.rst
+++ b/serializer/custom_name_converter.rst
@@ -43,19 +43,6 @@ A custom name converter can handle such cases::
}
}
-.. versionadded:: 7.1
-
- Accessing the current class name, format and context via
- :method:`Symfony\\Component\\Serializer\\NameConverter\\NameConverterInterface::normalize`
- and :method:`Symfony\\Component\\Serializer\\NameConverter\\NameConverterInterface::denormalize`
- was introduced in Symfony 7.1.
-
-.. note::
-
- You can also implement
- :class:`Symfony\\Component\\Serializer\\NameConverter\\AdvancedNameConverterInterface`
- to access the current class name, format and context.
-
Then, configure the serializer to use your name converter:
.. configuration-block::
@@ -68,25 +55,6 @@ Then, configure the serializer to use your name converter:
# pass the service ID of your name converter
name_converter: 'App\Serializer\OrgPrefixNameConverter'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/serializer.php
diff --git a/serializer/custom_normalizer.rst b/serializer/custom_normalizer.rst
index 9e3b6c94544..21c0c00791c 100644
--- a/serializer/custom_normalizer.rst
+++ b/serializer/custom_normalizer.rst
@@ -86,27 +86,6 @@ If you're not using ``autoconfigure``, you have to tag the service with
# register the normalizer with a high priority (called earlier)
- { name: 'serializer.normalizer', priority: 500 }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
diff --git a/serializer/encoders.rst b/serializer/encoders.rst
index 3d75d9073cf..8d3a53cab3a 100644
--- a/serializer/encoders.rst
+++ b/serializer/encoders.rst
@@ -64,13 +64,6 @@ are available to customize the behavior of the encoder:
Sets the field enclosure (one character only).
``csv_end_of_line`` (default: ``\n``)
Sets the character(s) used to mark the end of each line in the CSV file.
-``csv_escape_char`` (default: empty string)
-
- .. deprecated:: 7.2
-
- The ``csv_escape_char`` option was deprecated in Symfony 7.2.
-
- Sets the escape character (at most one character).
``csv_key_separator`` (default: ``.``)
Sets the separator for array's keys during its flattening
``csv_headers`` (default: ``[]``, inferred from input data's keys)
@@ -205,16 +198,15 @@ These are the options available on the :ref:`serializer context &]/``)
A regular expression pattern to determine if a value should be wrapped
in a CDATA section.
+``cdata_wrapping_name_pattern`` (default: ``false``)
+ A regular expression pattern that defines the names of fields whose values
+ should always be wrapped in a CDATA section, even if their contents don't
+ require it. Example: ``'/(firstname|lastname)/'``
``ignore_empty_attributes`` (default: ``false``)
If set to true, ignores all attributes with empty values in the generated XML
-
-.. versionadded:: 7.1
-
- The ``cdata_wrapping_pattern`` option was introduced in Symfony 7.1.
-
-.. versionadded:: 7.3
-
- The ``ignore_empty_attributes`` option was introduced in Symfony 7.3.
+``preserve_numeric_keys`` (default: ``false``)
+ If set to true, it keeps numeric array indexes (e.g. ``- ``)
+ instead of collapsing them into ``
- `` nodes.
Example with a custom ``context``::
@@ -246,6 +238,45 @@ Example with a custom ``context``::
// 2019-10-24
//
+Example with ``preserve_numeric_keys``::
+
+ use Symfony\Component\Serializer\Encoder\XmlEncoder;
+
+ $data = [
+ 'person' => [
+ ['firstname' => 'Benjamin', 'lastname' => 'Alexandre'],
+ ['firstname' => 'Damien', 'lastname' => 'Clay'],
+ ],
+ ];
+
+ $xmlEncoder->encode($data, 'xml', ['preserve_numeric_keys' => false]);
+ // outputs:
+ //
+ //
+ // Benjamin
+ // Alexandre
+ //
+ //
+ // Damien
+ // Clay
+ //
+ //
+
+ $xmlEncoder->encode($data, 'xml', ['preserve_numeric_keys' => true]);
+ // outputs:
+ //
+ //
+ //
-
+ // Benjamin
+ // Alexandre
+ //
+ // -
+ // Damien
+ // Clay
+ //
+ //
+ //
+
The ``YamlEncoder``
-------------------
@@ -331,24 +362,6 @@ to register your class as a service and tag it with
App\Serializer\NeonEncoder:
tags: ['serializer.encoder']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
diff --git a/serializer/streaming_json.rst b/serializer/streaming_json.rst
index 3fd44824bc6..aa17b7ebfc7 100644
--- a/serializer/streaming_json.rst
+++ b/serializer/streaming_json.rst
@@ -1,11 +1,6 @@
Streaming JSON
==============
-.. versionadded:: 7.3
-
- The JsonStreamer component was introduced in Symfony 7.3 as an
- :doc:`experimental feature `.
-
Symfony can encode PHP data structures to JSON streams and decode JSON streams
back into PHP data structures.
@@ -541,6 +536,12 @@ When callables are not enough, you can use a service implementing the
The ``getStreamValueType()`` method must return the value's type as it will
appear in the JSON stream.
+.. tip::
+
+ The ``$options`` argument of the ``transform()`` method includes a special
+ option called ``_current_object`` which gives access to the object holding
+ the current property (or ``null`` if there's none).
+
To use this transformer in a class, configure the ``#[ValueTransformer]`` attribute::
// src/Dto/Dog.php
diff --git a/service_container.rst b/service_container.rst
index 8b86d06a833..8c65ea9eec8 100644
--- a/service_container.rst
+++ b/service_container.rst
@@ -168,31 +168,6 @@ each time you ask for it.
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -240,21 +215,6 @@ each time you ask for it.
- '../src/AnotherDirectory/'
- '../src/SomeFile.php'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -319,10 +279,6 @@ environment, you can use the ``#[WhenNot]`` attribute::
// ...
}
-.. versionadded:: 7.2
-
- The ``#[WhenNot]`` attribute was introduced in Symfony 7.2.
-
.. _services-constructor-injection:
Injecting Services/Config into a Service
@@ -421,54 +377,6 @@ as arguments of other services:
first: !php/const true
second: 'Foo'
- .. code-block:: xml
-
-
-
-
-
-
-
-
- Foo
- 7
- 3.14
-
- Foo
-
- true
-
-
- E_ALL
- PDO::FETCH_NUM
- Symfony\Component\HttpKernel\Kernel::VERSION
- App\Config\SomeEnum::SomeCase
-
-
-
-
-
- VGhpcyBpcyBhIEJlbGwgY2hhciAH
-
-
-
- true
- Foo
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -639,32 +547,6 @@ pass here. No problem! In your configuration, you can explicitly set this argume
arguments:
$adminEmail: 'manager@example.com'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- manager@example.com
-
-
-
-
.. code-block:: php
// config/services.php
@@ -704,8 +586,7 @@ all their types (string, boolean, array, binary and PHP constant parameters).
However, there is another type of parameter related to services. In YAML config,
any string which starts with ``@`` is considered as the ID of a service, instead
-of a regular string. In XML config, use the ``type="service"`` type for the
-parameter and in PHP config use the ``service()`` function:
+of a regular string. In PHP config use the ``service()`` function:
.. configuration-block::
@@ -723,22 +604,6 @@ parameter and in PHP config use the ``service()`` function:
# the following example would be parsed as the string '@securepassword'
# - '@@securepassword'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -824,25 +689,6 @@ But, you can control this and pass in a different logger:
# and not just the *string* 'monolog.logger.request'
$logger: '@monolog.logger.request'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -956,26 +802,6 @@ Our configuration looks like this:
$logger: '@monolog.logger.request'
$generateMessageHash: !closure '@App\Hash\MessageHashGenerator'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1032,43 +858,6 @@ You can also use the ``bind`` keyword to bind specific arguments by name or type
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
- manager@example.com
-
-
-
-
- manager@example.com
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1133,24 +922,6 @@ the name of the argument and some short description about its purpose:
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
- should be defined by Pass
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1230,10 +1001,6 @@ application to production (e.g. in your continuous integration server):
# the command will fail if any of those environment variables are missing
$ php bin/console lint:container --resolve-env-vars
-.. versionadded:: 7.2
-
- The ``--resolve-env-vars`` option was introduced in Symfony 7.2.
-
Performing those checks whenever the container is compiled can hurt performance.
That's why they are implemented in :doc:`compiler passes `
called ``CheckTypeDeclarationsPass`` and ``CheckAliasValidityPass``, which are
@@ -1241,10 +1008,6 @@ disabled by default and enabled only when executing the ``lint:container`` comma
If you don't mind the performance loss, you can enable these compiler passes in
your application.
-.. versionadded:: 7.1
-
- The ``CheckAliasValidityPass`` compiler pass was introduced in Symfony 7.1.
-
.. _container-public:
Public Versus Private Services
@@ -1273,23 +1036,6 @@ setting:
App\Service\PublicService:
public: true
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1343,22 +1089,6 @@ key. For example, the default Symfony configuration contains this:
resource: '../src/'
exclude: '../src/{DependencyInjection,Entity,Kernel.php}'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1417,23 +1147,6 @@ for classes under the same namespace:
resource: '../src/Domain/*'
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1509,34 +1222,6 @@ admin email. In this case, each needs to have a unique service id:
# the site_update_manager.superadmin will be used
App\Service\SiteUpdateManager: '@site_update_manager.superadmin'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
- superadmin@example.com
-
-
-
-
-
- contact@example.com
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1674,27 +1359,6 @@ an adapter for a functional interface through configuration:
class: App\Service\MessageFormatterInterface
from_callable: [!service {class: 'App\Service\MessageUtils'}, 'format']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
diff --git a/service_container/alias_private.rst b/service_container/alias_private.rst
index 22bf649d861..b0425469f05 100644
--- a/service_container/alias_private.rst
+++ b/service_container/alias_private.rst
@@ -35,19 +35,6 @@ You can also control the ``public`` option on a service-by-service basis:
App\Service\Foo:
public: true
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -133,22 +120,6 @@ services.
alias: App\Mail\PhpMailer
public: true
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -203,10 +174,6 @@ The ``#[AsAlias]`` attribute can also be limited to one or more specific
// ...
}
-.. versionadded:: 7.3
-
- The ``when`` argument of the ``#[AsAlias]`` attribute was introduced in Symfony 7.3.
-
.. tip::
When using ``#[AsAlias]`` attribute, you may omit passing ``id`` argument
@@ -251,27 +218,6 @@ or you decided not to maintain it anymore), you can deprecate its definition:
version: '1.2'
message: 'The "%alias_id%" alias is deprecated. Do not use it anymore.'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
- The "%alias_id%" service alias is deprecated. Don't use it anymore.
-
-
-
-
-
.. code-block:: php
$container
@@ -317,24 +263,6 @@ The following example shows how to inject an anonymous service into another serv
- !service
class: App\AnonymousBar
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -368,24 +296,6 @@ Using an anonymous service as a factory looks like this:
App\Foo:
factory: [ !service { class: App\FooFactory }, 'constructFoo' ]
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -418,21 +328,6 @@ or you decided not to maintain it anymore), you can deprecate its definition:
version: '2.8'
message: The "%service_id%" service is deprecated since vendor-name/package-name 2.8 and will be removed in 3.0.
- .. code-block:: xml
-
-
-
-
-
-
-
- The "%service_id%" service is deprecated since vendor-name/package-name 2.8 and will be removed in 3.0.
-
-
-
-
.. code-block:: php
// config/services.php
diff --git a/service_container/autowiring.rst b/service_container/autowiring.rst
index 7d7aff64271..6ff0c9c67d6 100644
--- a/service_container/autowiring.rst
+++ b/service_container/autowiring.rst
@@ -80,25 +80,6 @@ both services:
App\Util\Rot13Transformer:
autowire: true
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -215,22 +196,6 @@ adding a service alias:
# an App\Util\Rot13Transformer type-hint is detected
App\Util\Rot13Transformer: '@app.rot13.transformer'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -321,22 +286,6 @@ To fix that, add an :ref:`alias `:
# an App\Util\TransformerInterface type-hint is detected
App\Util\TransformerInterface: '@App\Util\Rot13Transformer'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -476,30 +425,6 @@ the injection::
# $transformer: '@App\Util\UppercaseTransformer'
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -794,11 +719,6 @@ by using the property name as method name::
}
}
-.. versionadded:: 7.1
-
- The :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireMethodOf`
- attribute was introduced in Symfony 7.1.
-
.. _autowiring-calls:
Autowiring other Methods (e.g. Setters and Public Typed Properties)
@@ -865,10 +785,6 @@ typed properties:
Autowiring Anonymous Services Inline
------------------------------------
-.. versionadded:: 7.1
-
- The ``#[AutowireInline]`` attribute was added in Symfony 7.1.
-
Similar to how anonymous services can be defined inline in configuration files,
the :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireInline`
attribute allows you to declare anonymous services inline, directly next to their
diff --git a/service_container/calls.rst b/service_container/calls.rst
index cb364b59489..67777e25728 100644
--- a/service_container/calls.rst
+++ b/service_container/calls.rst
@@ -40,25 +40,6 @@ To configure the container to call the ``setLogger`` method, use the ``calls`` k
calls:
- setLogger: ['@logger']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -112,25 +93,6 @@ The configuration to tell the container it should do so would be like:
calls:
- withLogger: !returns_clone ['@logger']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
diff --git a/service_container/configurators.rst b/service_container/configurators.rst
index 7817a383761..460aa65d1d5 100644
--- a/service_container/configurators.rst
+++ b/service_container/configurators.rst
@@ -136,28 +136,6 @@ all the classes are already loaded as services. All you need to do is specify th
App\Mail\GreetingCardManager:
configurator: ['@App\Mail\EmailConfigurator', 'configure']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -206,28 +184,6 @@ Services can be configured via invokable configurators (replacing the
App\Mail\GreetingCardManager:
configurator: '@App\Mail\EmailConfigurator'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
diff --git a/service_container/debug.rst b/service_container/debug.rst
index 9e3e28a5343..0a7898108fb 100644
--- a/service_container/debug.rst
+++ b/service_container/debug.rst
@@ -51,9 +51,3 @@ its id:
.. code-block:: terminal
$ php bin/console debug:container App\Service\Mailer
-
-.. deprecated:: 7.3
-
- Starting in Symfony 7.3, this command displays the service arguments by default.
- In earlier Symfony versions, you needed to use the ``--show-arguments`` option,
- which is now deprecated.
diff --git a/service_container/definitions.rst b/service_container/definitions.rst
index a2a50591668..6240f56e126 100644
--- a/service_container/definitions.rst
+++ b/service_container/definitions.rst
@@ -6,7 +6,7 @@ build a service. They are not the actual services used by your applications.
The container will create the actual class instances based on the configuration
in the definition.
-Normally, you would use YAML, XML or PHP to describe the service definitions.
+Normally, you would use YAML or PHP to describe the service definitions.
But if you're doing advanced things with the service container, like working
with a :doc:`Compiler Pass ` or creating a
:doc:`Dependency Injection Extension `, you may need to
diff --git a/service_container/expression_language.rst b/service_container/expression_language.rst
index 41c538db468..88a6dd0fa27 100644
--- a/service_container/expression_language.rst
+++ b/service_container/expression_language.rst
@@ -27,26 +27,6 @@ to another service: ``App\Mailer``. One way to do this is with an expression:
# when using double-quoted strings, the backslash needs to be escaped twice (see https://yaml.org/spec/1.2/spec.html#id2787109)
# arguments: ["@=service('App\\\\Mail\\\\MailerConfiguration').getMailerMethod()"]
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
- service('App\\Mail\\MailerConfiguration').getMailerMethod()
-
-
-
-
.. code-block:: php
// config/services.php
@@ -89,22 +69,6 @@ via a ``container`` variable. Here's another example:
# the '@=' prefix is required when using expressions for arguments in YAML files
arguments: ["@=container.hasParameter('some_param') ? parameter('some_param') : 'default_value'"]
- .. code-block:: xml
-
-
-
-
-
-
-
- container.hasParameter('some_param') ? parameter('some_param') : 'default_value'
-
-
-
-
.. code-block:: php
// config/services.php
diff --git a/service_container/factories.rst b/service_container/factories.rst
index 9864287d57a..4ecde32af5e 100644
--- a/service_container/factories.rst
+++ b/service_container/factories.rst
@@ -49,23 +49,6 @@ create its object:
# the first argument is the class and the second argument is the static method
factory: ['App\Email\NewsletterManagerStaticFactory', 'createNewsletterManager']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -132,22 +115,6 @@ You can omit the class on the factory declaration:
arguments:
$sender: 'fabien@symfony.com'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -201,21 +168,6 @@ as the factory class:
arguments:
$sender: 'fabien@symfony.com'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -253,29 +205,6 @@ Configuration of the service container then looks like this:
App\Email\NewsletterManager:
factory: ['@App\Email\NewsletterManagerFactory', 'createNewsletterManager']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -335,25 +264,6 @@ method name:
class: App\Email\NewsletterManager
factory: '@App\Email\InvokableNewsletterManagerFactory'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -393,29 +303,6 @@ e.g. change the service based on a parameter:
arguments:
- '@App\Email\NewsletterManagerFactory'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -467,25 +354,6 @@ previous examples takes the ``templating`` service as an argument:
factory: ['@App\Email\NewsletterManagerFactory', createNewsletterManager]
arguments: ['@templating']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
diff --git a/service_container/import.rst b/service_container/import.rst
index 47af34d3a34..ab1a846045c 100644
--- a/service_container/import.rst
+++ b/service_container/import.rst
@@ -4,7 +4,7 @@ How to Import Configuration Files/Resources
.. tip::
In this section, service configuration files are referred to as *resources*.
- While most configuration resources are files (e.g. YAML, XML, PHP), Symfony is
+ While most configuration resources are files (e.g. YAML, PHP), Symfony is
able to load configuration from anywhere (e.g. a database or even via an external
web service).
@@ -38,24 +38,6 @@ decided to move some configuration to a new file:
services:
# ... some services
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services/mailer.php
@@ -85,30 +67,6 @@ a relative or absolute path to the imported file:
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -173,33 +131,6 @@ from auto-registering classes that are defined manually elsewhere:
- '../src/Mailer/'
- '../src/SpecificClass.php'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ../src/Mailer/
- ../src/SpecificClass.php
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -246,34 +177,6 @@ same file. These later definitions will override the auto-registered ones:
App\Mailer\MyMailer:
arguments: ['%env(MAILER_DSN)%']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- %env(MAILER_DSN)%
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -329,57 +232,6 @@ can override the auto-discovered ones.
# definitions here override anything from the imports above
# consider keeping most definitions inside imported files
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
- ../../src/Mailer/
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services/autodiscovery.php
diff --git a/service_container/injection_types.rst b/service_container/injection_types.rst
index 91c2a562d81..48c87e02389 100644
--- a/service_container/injection_types.rst
+++ b/service_container/injection_types.rst
@@ -44,24 +44,6 @@ service container configuration:
App\Mail\NewsletterManager:
arguments: ['@mailer']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -147,26 +129,6 @@ In order to use this type of injection, don't forget to configure it:
calls:
- withMailer: !returns_clone ['@mailer']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -246,26 +208,6 @@ that accepts the dependency::
calls:
- setMailer: ['@mailer']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -330,24 +272,6 @@ Another possibility is setting public fields of the class directly::
properties:
mailer: '@mailer'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
diff --git a/service_container/lazy_services.rst b/service_container/lazy_services.rst
index abb3c2cca7f..0959e18ebd1 100644
--- a/service_container/lazy_services.rst
+++ b/service_container/lazy_services.rst
@@ -42,20 +42,6 @@ You can mark the service as ``lazy`` by manipulating its definition:
App\Twig\AppExtension:
lazy: true
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -138,10 +124,6 @@ It defines an optional parameter used to define interfaces for proxy and interse
) {
}
-.. versionadded:: 7.1
-
- The ``#[Lazy]`` attribute was introduced in Symfony 7.1.
-
Interface Proxifying
--------------------
@@ -165,24 +147,6 @@ specific interfaces.
tags:
- { name: 'proxy', interface: 'Twig\Extension\ExtensionInterface' }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
diff --git a/service_container/optional_dependencies.rst b/service_container/optional_dependencies.rst
index bc8f03cf7e0..ec77a95777f 100644
--- a/service_container/optional_dependencies.rst
+++ b/service_container/optional_dependencies.rst
@@ -13,24 +13,6 @@ if the service does not exist:
.. configuration-block::
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -69,24 +51,6 @@ call if the service exists and remove the method call if it does not:
calls:
- setLogger: ['@?logger']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
diff --git a/service_container/parent_services.rst b/service_container/parent_services.rst
index b82222c43af..8112c224f3c 100644
--- a/service_container/parent_services.rst
+++ b/service_container/parent_services.rst
@@ -78,37 +78,6 @@ avoid duplicated service definitions:
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -184,39 +153,6 @@ the child class:
arguments:
index_0: '@doctrine.custom_entity_manager'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
diff --git a/service_container/service_closures.rst b/service_container/service_closures.rst
index 88b0ab64002..73aed59bdd3 100644
--- a/service_container/service_closures.rst
+++ b/service_container/service_closures.rst
@@ -59,26 +59,6 @@ argument of type ``service_closure``:
# the shortcut also works for optional dependencies
# arguments: ['@>?mailer']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -97,10 +77,6 @@ argument of type ``service_closure``:
// ->args([service_closure('mailer')->ignoreOnInvalid()]);
};
-.. versionadded:: 7.3
-
- The ``@>`` shortcut syntax for YAML was introduced in Symfony 7.3.
-
.. seealso::
Service closures can be injected :ref:`by using autowiring `
diff --git a/service_container/service_decoration.rst b/service_container/service_decoration.rst
index 7b5e8edbcc2..81399eb4b49 100644
--- a/service_container/service_decoration.rst
+++ b/service_container/service_decoration.rst
@@ -16,23 +16,6 @@ When overriding an existing definition, the original service is lost:
App\Mailer:
class: App\NewMailer
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -84,26 +67,6 @@ but keeps a reference of the old one as ``.inner``:
# but that service is still available as ".inner"
decorates: App\Mailer
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -123,6 +86,11 @@ but keeps a reference of the old one as ``.inner``:
->decorate(Mailer::class);
};
+.. tip::
+
+ You can apply multiple ``#[AsDecorator]`` attributes to the same class to
+ decorate multiple services with it.
+
The ``decorates`` option tells the container that the ``App\DecoratingMailer``
service replaces the ``App\Mailer`` service. If you're using the
:ref:`default services.yaml configuration `,
@@ -170,26 +138,6 @@ automatically changed to ``'.inner'``):
# pass the old service as an argument
arguments: ['@.inner']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -238,40 +186,6 @@ name via the ``decoration_inner_name`` option:
decoration_inner_name: 'App\Mailer.original'
arguments: ['@App\Mailer.original']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -364,28 +278,6 @@ the ``decoration_priority`` option. Its value is an integer that defaults to
decoration_priority: 1
arguments: ['@.inner']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -443,35 +335,6 @@ ordered services, each one decorating the next:
- Bar: ~
- Foo: ~
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -526,32 +389,6 @@ advanced example of composition:
- Bar: ~
- Foo: ~
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -605,15 +442,6 @@ The result will be::
Baz: ~
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
.. code-block:: php
// ...
@@ -667,24 +495,6 @@ Three different behaviors are available:
decoration_on_invalid: ignore
arguments: ['@.inner']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
diff --git a/service_container/service_subscribers_locators.rst b/service_container/service_subscribers_locators.rst
index 9026478cf33..f9f39a70abf 100644
--- a/service_container/service_subscribers_locators.rst
+++ b/service_container/service_subscribers_locators.rst
@@ -135,11 +135,6 @@ count and iterate over the services of the locator::
// do something with the service, the service id or both
}
-.. versionadded:: 7.1
-
- The :class:`Symfony\\Contracts\\Service\\ServiceCollectionInterface` was
- introduced in Symfony 7.1.
-
Including Services
------------------
@@ -226,23 +221,6 @@ service type to a service.
tags:
- { name: 'container.service_subscriber', key: 'logger', id: 'monolog.logger.event' }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -307,14 +285,6 @@ This is done by having ``getSubscribedServices()`` return an array of
];
}
-.. deprecated:: 7.1
-
- The :class:`Symfony\\Component\\DependencyInjection\\Attribute\\TaggedIterator`
- and :class:`Symfony\\Component\\DependencyInjection\\Attribute\\TaggedLocator`
- attributes were deprecated in Symfony 7.1 in favor of
- :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireIterator`
- and :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator`.
-
.. note::
The above example requires using ``3.2`` version or newer of ``symfony/service-contracts``.
@@ -459,7 +429,7 @@ some services into it via a service locator::
}
}
-Symfony allows you to inject the service locator using YAML/XML/PHP configuration
+Symfony allows you to inject the service locator using YAML or PHP configuration
or directly via PHP attributes:
.. configuration-block::
@@ -492,24 +462,6 @@ or directly via PHP attributes:
App\FooCommand: '@app.command_handler.foo'
App\BarCommand: '@app.command_handler.bar'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -555,31 +507,6 @@ other services. To do so, create a new service definition using the
# add the following tag to the service definition:
# tags: ['container.service_locator']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -634,23 +561,6 @@ Now you can inject the service locator in any other services:
App\CommandBus:
arguments: ['@app.command_handler_locator']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -739,31 +649,6 @@ to index the services:
# inject all services tagged with app.handler as first argument
arguments: [!tagged_locator { tag: 'app.handler', index_by: 'key' }]
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -848,25 +733,6 @@ get the value used to index the services:
# inject all services tagged with app.handler as first argument
arguments: [!tagged_locator { tag: 'app.handler', default_index_method: 'getLocatorKey' }]
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -937,11 +803,6 @@ services based on type-hinted helper methods::
}
}
-.. versionadded:: 7.1
-
- The ``ServiceMethodsSubscriberTrait`` was introduced in Symfony 7.1.
- In previous Symfony versions it was called ``ServiceSubscriberTrait``.
-
This allows you to create helper traits like RouterAware, LoggerAware, etc...
and compose your services with them::
diff --git a/service_container/shared.rst b/service_container/shared.rst
index 4e79ae28116..fa3aae90278 100644
--- a/service_container/shared.rst
+++ b/service_container/shared.rst
@@ -32,13 +32,6 @@ in your service definition:
shared: false
# ...
- .. code-block:: xml
-
-
-
-
-
-
.. code-block:: php
// config/services.php
diff --git a/service_container/synthetic_services.rst b/service_container/synthetic_services.rst
index 09b195db02c..9f60bb7ddaf 100644
--- a/service_container/synthetic_services.rst
+++ b/service_container/synthetic_services.rst
@@ -41,23 +41,6 @@ configuration:
app.synthetic_service:
synthetic: true
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
diff --git a/service_container/tags.rst b/service_container/tags.rst
index 3444569a604..0814f242c59 100644
--- a/service_container/tags.rst
+++ b/service_container/tags.rst
@@ -14,22 +14,6 @@ example:
App\Twig\AppExtension:
tags: ['twig.extension']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -81,20 +65,6 @@ If you want to apply tags automatically for your own services, use the
tags: ['app.custom_tag']
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -317,20 +287,6 @@ Then, define the chain as a service:
services:
App\Mail\TransportChain: ~
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -364,28 +320,6 @@ For example, you may add the following transports as services:
MailerSendmailTransport:
tags: ['app.mail_transport']
- .. code-block:: xml
-
-
-
-
-
-
-
- %mailer_host%
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -523,33 +457,6 @@ To answer this, change the service declaration:
tags:
- { name: 'app.mail_transport', alias: ['sendmail', 'anotherAlias']}
- .. code-block:: xml
-
-
-
-
-
-
-
- %mailer_host%
-
-
-
-
-
-
-
- sendmail
- anotherAlias
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -571,7 +478,7 @@ To answer this, change the service declaration:
.. tip::
The ``name`` attribute is used by default to define the name of the tag.
- If you want to add a ``name`` attribute to some tag in XML or YAML formats,
+ If you want to add a ``name`` attribute to some tag in YAML format,
you need to use this special syntax:
.. configuration-block::
@@ -588,26 +495,6 @@ To answer this, change the service declaration:
# this is a tag called 'app.mail_transport' with two attributes ('name' and 'alias')
- app.mail_transport: { name: 'arbitrary-value', alias: 'smtp' }
- .. code-block:: xml
-
-
-
-
-
-
-
- %mailer_host%
-
-
-
- app.mail_transport
-
-
-
-
.. tip::
In YAML format, you may provide the tag as a simple string as long as
@@ -682,7 +569,7 @@ all services tagged with ``app.handler`` into its constructor argument::
}
}
-Symfony allows you to inject the services using YAML/XML/PHP configuration or
+Symfony allows you to inject the services using YAML or PHP configuration or
directly via PHP attributes:
.. configuration-block::
@@ -719,31 +606,6 @@ directly via PHP attributes:
arguments:
- !tagged_iterator app.handler
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -809,32 +671,6 @@ iterator, add the ``exclude`` option:
arguments:
- !tagged_iterator { tag: app.handler, exclude: ['App\Handler\Three'] }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- App\Handler\Three
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -892,32 +728,6 @@ disabled by setting the ``exclude_self`` option to ``false``:
arguments:
- !tagged_iterator { tag: app.handler, exclude: ['App\Handler\Three'], exclude_self: false }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- App\Handler\Three
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -960,22 +770,6 @@ the number, the earlier the tagged service will be located in the collection:
tags:
- { name: 'app.handler', priority: 20 }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1037,28 +831,11 @@ you can define it in the configuration of the collecting service:
arguments:
- !tagged_iterator { tag: app.handler, default_priority_method: getPriority }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
- use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
-
return function (ContainerConfigurator $container): void {
$services = $container->services();
@@ -1117,30 +894,6 @@ to index the services:
App\HandlerCollection:
arguments: [!tagged_iterator { tag: 'app.handler', index_by: 'key' }]
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1148,7 +901,6 @@ to index the services:
use App\Handler\One;
use App\Handler\Two;
- use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
return function (ContainerConfigurator $container): void {
$services = $container->services();
@@ -1225,34 +977,12 @@ get the value used to index the services:
App\HandlerCollection:
arguments: [!tagged_iterator { tag: 'app.handler', default_index_method: 'getIndex' }]
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use App\HandlerCollection;
- use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
return function (ContainerConfigurator $container) {
$services = $container->services();
@@ -1309,9 +1039,4 @@ same service under different indexes::
// ...
}
-.. versionadded:: 7.3
-
- The feature to apply the ``#[AsTaggedItem]`` attribute multiple times was
- introduced in Symfony 7.3.
-
.. _`PHP constructor promotion`: https://www.php.net/manual/en/language.oop5.decon.php#language.oop5.decon.constructor.promotion
diff --git a/session.rst b/session.rst
index 9fec0e46441..e787fa216f2 100644
--- a/session.rst
+++ b/session.rst
@@ -301,32 +301,6 @@ configuration ` in
cookie_samesite: lax
storage_factory_id: session.storage.factory.native
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/framework.php
@@ -384,24 +358,6 @@ session metadata files:
handler_id: 'session.handler.native_file'
save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/framework.php
@@ -436,11 +392,6 @@ Check out the Symfony config reference to learn more about the other available
``session.auto_start = 1`` This directive should be turned off in
``php.ini``, in the web server directives or in ``.htaccess``.
-.. deprecated:: 7.2
-
- The ``sid_length`` and ``sid_bits_per_character`` options were deprecated
- in Symfony 7.2 and will be ignored in Symfony 8.0.
-
The session cookie is also available in :ref:`the Response object `.
This is useful to get that cookie in the CLI context or when using PHP runners
like Roadrunner or Swoole.
@@ -523,11 +474,6 @@ Alternatively, you can configure these settings by passing ``gc_probability``,
or to the :method:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage::setOptions`
method.
-.. versionadded:: 7.2
-
- Using the ``php.ini`` directive as the default value for ``gc_probability``
- was introduced in Symfony 7.2.
-
.. _session-database:
Store Sessions in a Database
@@ -592,46 +538,6 @@ a Symfony service for the connection to the Redis server:
# - auth:
# - ['%env(REDIS_USER)%','%env(REDIS_PASSWORD)%']
- .. code-block:: xml
-
-
-
-
-
-
-
-
- %env(REDIS_HOST)%
- %env(int:REDIS_PORT)%
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -670,24 +576,6 @@ configuration option to tell Symfony to use this service as the session handler:
session:
handler_id: Symfony\Component\HttpFoundation\Session\Storage\Handler\RedisSessionHandler
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/framework.php
@@ -745,31 +633,6 @@ To use it, first register a new handler service with your database credentials:
# - 'mysql:dbname=mydatabase; host=myhost; port=myport'
# - { db_username: myuser, db_password: mypassword }
- .. code-block:: xml
-
-
-
-
-
-
-
- %env(DATABASE_URL)%
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -808,25 +671,6 @@ configuration option to tell Symfony to use this service as the session handler:
# ...
handler_id: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/framework.php
@@ -860,26 +704,6 @@ passed to the ``PdoSessionHandler`` service:
- '%env(DATABASE_URL)%'
- { db_table: 'customer_session', db_id_col: 'guid' }
- .. code-block:: xml
-
-
-
-
-
-
-
- %env(DATABASE_URL)%
-
- customer_session
- guid
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1055,28 +879,6 @@ the MongoDB connection as argument, and the required parameters:
- '@doctrine_mongodb.odm.default_connection'
- { database: '%env(MONGODB_DB)%', collection: 'sessions' }
- .. code-block:: xml
-
-
-
-
-
-
-
- doctrine_mongodb.odm.default_connection
-
- %env('MONGODB_DB')%
- sessions
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1108,25 +910,6 @@ configuration option to tell Symfony to use this service as the session handler:
# ...
handler_id: Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/framework.php
@@ -1174,28 +957,6 @@ configure these values with the second argument passed to the
id_field: '_guid'
expiry_field: 'eol'
- .. code-block:: xml
-
-
-
-
-
-
-
- doctrine_mongodb.odm.default_connection
-
- %env('MONGODB_DB')%
- sessions
- _guid
- eol
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1288,18 +1049,6 @@ You need to pass the TTL in the options array of the session handler you are usi
- '@Redis'
- { 'ttl': 600 }
- .. code-block:: xml
-
-
-
-
-
-
- 600
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1338,23 +1087,6 @@ has to return an integer which will be used as TTL.
# Inject whatever dependencies you need to be able to resolve a TTL for the current session
- '@security'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1455,25 +1187,6 @@ via some "Change Locale" route & controller), or create a route with the
# uncomment the next line if you are not using autoconfigure
# tags: [kernel.event_subscriber]
- .. code-block:: xml
-
-
-
-
-
-
-
- %kernel.default_locale%
-
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1584,21 +1297,6 @@ Symfony to use your session handler instead of the default one:
# ...
handler_id: App\Session\CustomSessionHandler
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/framework.php
@@ -1683,25 +1381,6 @@ Then, register the ``SodiumMarshaller`` service using this key:
- ['%env(file:resolve:SESSION_DECRYPTION_FILE)%']
- '@.inner'
- .. code-block:: xml
-
-
-
-
-
-
-
- env(file:resolve:SESSION_DECRYPTION_FILE)
-
-
-
-
-
-
.. code-block:: php
// config/services.php
@@ -1792,23 +1471,6 @@ for the ``handler_id``:
storage_factory_id: session.storage.factory.php_bridge
handler_id: ~
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/framework.php
@@ -1852,23 +1514,6 @@ the example below:
storage_factory_id: session.storage.factory.php_bridge
handler_id: session.handler.native_file
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/framework.php
diff --git a/setup.rst b/setup.rst
index a7fa8c66826..3d18a9b9388 100644
--- a/setup.rst
+++ b/setup.rst
@@ -14,7 +14,7 @@ Technical Requirements
Before creating your first Symfony application you must:
-* Install PHP 8.2 or higher and these PHP extensions (which are installed and
+* Install PHP 8.4 or higher and these PHP extensions (which are installed and
enabled by default in most PHP 8 installations): `Ctype`_, `iconv`_,
`PCRE`_, `Session`_, `SimpleXML`_, and `Tokenizer`_;
* `Install Composer`_, which is used to install PHP packages.
@@ -48,10 +48,10 @@ application:
.. code-block:: terminal
# run this if you are building a traditional web application
- $ symfony new my_project_directory --version="7.3.x" --webapp
+ $ symfony new my_project_directory --version="8.0.x" --webapp
# run this if you are building a microservice, console application or API
- $ symfony new my_project_directory --version="7.3.x"
+ $ symfony new my_project_directory --version="8.0.x"
The only difference between these two commands is the number of packages
installed by default. The ``--webapp`` option installs extra packages to give
@@ -63,12 +63,12 @@ Symfony application using Composer:
.. code-block:: terminal
# run this if you are building a traditional web application
- $ composer create-project symfony/skeleton:"7.3.x" my_project_directory
+ $ composer create-project symfony/skeleton:"8.0.x" my_project_directory
$ cd my_project_directory
$ composer require webapp
# run this if you are building a microservice, console application or API
- $ composer create-project symfony/skeleton:"7.3.x" my_project_directory
+ $ composer create-project symfony/skeleton:"8.0.x" my_project_directory
No matter which command you run to create the Symfony application. All of them
will create a new ``my_project_directory/`` directory, download some dependencies
diff --git a/string.rst b/string.rst
index 026ef587dca..c4e681d495f 100644
--- a/string.rst
+++ b/string.rst
@@ -237,19 +237,6 @@ Methods to Change Case
// other cases can be achieved by chaining methods, e.g. :
u('Foo: Bar-baz.')->camel()->upper(); // 'FOOBARBAZ'
-.. versionadded:: 7.1
-
- The ``localeLower()``, ``localeUpper()`` and ``localeTitle()`` methods were
- introduced in Symfony 7.1.
-
-.. versionadded:: 7.2
-
- The ``kebab()`` method was introduced in Symfony 7.2.
-
-.. versionadded:: 7.3
-
- The ``pascal()`` method was introduced in Symfony 7.3.
-
The methods of all string classes are case-sensitive by default. You can perform
case-insensitive operations with the ``ignoreCase()`` method::
@@ -415,10 +402,6 @@ Methods to Join, Split, Truncate and Reverse
// returns up to the last complete word that fits in the given length, surpassing it if needed
u('Lorem ipsum dolor sit amet')->truncate(8, cut: TruncateMode::WordAfter); // 'Lorem ipsum'
-.. versionadded:: 7.2
-
- The ``TruncateMode`` parameter for truncate function was introduced in Symfony 7.2.
-
::
// breaks the string into lines of the given length
@@ -678,10 +661,6 @@ Symfony also provides inflectors for other languages::
$result = $inflector->singularize('aviones'); // ['avión']
$result = $inflector->pluralize('miércoles'); // ['miércoles']
-.. versionadded:: 7.2
-
- The ``SpanishInflector`` class was introduced in Symfony 7.2.
-
.. note::
Symfony provides an :class:`Symfony\\Component\\String\\Inflector\\InflectorInterface`
diff --git a/templates.rst b/templates.rst
index a7e122d83db..b4ab002a887 100644
--- a/templates.rst
+++ b/templates.rst
@@ -230,24 +230,6 @@ Consider the following routing configuration:
path: /article/{slug}
controller: App\Controller\BlogController::show
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/routes.php
@@ -416,24 +398,6 @@ inside the main Twig configuration file:
globals:
ga_tracking: 'UA-xxxxx-x'
- .. code-block:: xml
-
-
-
-
-
-
-
- UA-xxxxx-x
-
-
-
.. code-block:: php
// config/packages/twig.php
@@ -474,24 +438,6 @@ in container parameters `:
# the value is the service's id
uuid: '@App\Generator\UuidGenerator'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/twig.php
@@ -661,10 +607,6 @@ a block to render::
}
}
-.. versionadded:: 7.2
-
- The ``#[Template]`` attribute's ``block`` argument was introduced in Symfony 7.2.
-
Rendering a Template in Services
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -743,43 +685,6 @@ provided by Symfony:
Content-Type: 'text/html'
foo: 'bar'
- .. code-block:: xml
-
-
-
-
-
-
-
- static/privacy.html.twig
-
-
- 200
-
-
- 86400
- 86400
-
-
- true
-
-
-
- ACME
- dark
-
-
-
-
- text/html
-
-
-
-
.. code-block:: php
// config/routes.php
@@ -817,10 +722,6 @@ provided by Symfony:
;
};
-.. versionadded:: 7.2
-
- The ``headers`` option was introduced in Symfony 7.2.
-
Checking if a Template Exists
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -873,15 +774,6 @@ errors. It's useful to run it before deploying your application to production
# you can also excludes directories
$ php bin/console lint:twig templates/ --excludes=data_collector --excludes=dev_tool
-.. versionadded:: 7.1
-
- The option to exclude directories was introduced in Symfony 7.1.
-
-.. versionadded:: 7.3
-
- Before Symfony 7.3, the ``--show-deprecations`` option only displayed the
- first deprecation found, so you had to run the command repeatedly.
-
When running the linter inside `GitHub Actions`_, the output is automatically
adapted to the format required by GitHub, but you can force that format too:
@@ -1090,23 +982,6 @@ template fragments. Configure that special URL in the ``fragments`` option:
# ...
fragments: { path: /_fragment }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/framework.php
@@ -1163,23 +1038,6 @@ default content rendering some template:
fragments:
hinclude_default_template: hinclude.html.twig
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/framework.php
@@ -1409,25 +1267,6 @@ the ``value`` is the Twig namespace, which is explained later:
'email/default/templates': ~
'backend/templates': ~
- .. code-block:: xml
-
-
-
-
-
-
-
- email/default/templates
- backend/templates
-
-
-
.. code-block:: php
// config/packages/twig.php
@@ -1467,23 +1306,6 @@ configuration to define a namespace for each template directory:
'email/default/templates': 'email'
'backend/templates': 'admin'
- .. code-block:: xml
-
-
-
-
-
-
- email/default/templates
- backend/templates
-
-
-
.. code-block:: php
// config/packages/twig.php
@@ -1598,13 +1420,6 @@ If you want to create a function instead of a filter, use the
Along with custom filters and functions, you can also register
`global variables`_.
-.. versionadded:: 7.3
-
- Support for the ``#[AsTwigFilter]``, ``#[AsTwigFunction]`` and ``#[AsTwigTest]``
- attributes was introduced in Symfony 7.3. Previously, you had to extend the
- ``AbstractExtension`` class, and override the ``getFilters()`` and ``getFunctions()``
- methods.
-
If you're using the :ref:`default services.yaml configuration `,
the :ref:`service autoconfiguration ` feature will enable
this class as a Twig extension. Otherwise, you need to define a service manually
diff --git a/testing.rst b/testing.rst
index a0f8b1c6a18..9dca2338aca 100644
--- a/testing.rst
+++ b/testing.rst
@@ -170,21 +170,6 @@ code to production:
twig:
strict_variables: true
- .. code-block:: xml
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/test/twig.php
@@ -994,11 +979,11 @@ However, Symfony provides useful shortcut methods for the most common cases:
Response Assertions
...................
-``assertResponseIsSuccessful(string $message = '', bool $verbose = true)``
+``assertResponseIsSuccessful(string $message = '', ?bool $verbose = null)``
Asserts that the response was successful (HTTP status is 2xx).
-``assertResponseStatusCodeSame(int $expectedCode, string $message = '', bool $verbose = true)``
+``assertResponseStatusCodeSame(int $expectedCode, string $message = '', ?bool $verbose = null)``
Asserts a specific HTTP status code.
-``assertResponseRedirects(?string $expectedLocation = null, ?int $expectedCode = null, string $message = '', bool $verbose = true)``
+``assertResponseRedirects(?string $expectedLocation = null, ?int $expectedCode = null, string $message = '', ?bool $verbose = null)``
Asserts the response is a redirect response (optionally, you can check
the target location and status code). The excepted location can be either
an absolute or a relative path.
@@ -1016,12 +1001,16 @@ Response Assertions
Asserts the response format returned by the
:method:`Symfony\\Component\\HttpFoundation\\Response::getFormat` method
is the same as the expected value.
-``assertResponseIsUnprocessable(string $message = '', bool $verbose = true)``
+``assertResponseIsUnprocessable(string $message = '', bool ?$verbose = null)``
Asserts the response is unprocessable (HTTP status is 422)
-.. versionadded:: 7.1
+By default, these assert methods provide detailed error messages when they fail.
+You can control the verbosity level using the optional ``verbose`` argument in
+each assert method. To set this verbosity level globally, use the
+``setBrowserKitAssertionsAsVerbose()`` method from the
+:class:`Symfony\\Bundle\\FrameworkBundle\\Test\\BrowserKitAssertionsTrait`::
- The ``$verbose`` parameters were introduced in Symfony 7.1.
+ BrowserKitAssertionsTrait::setBrowserKitAssertionsAsVerbose(false);
Request Assertions
..................
@@ -1041,6 +1030,10 @@ Browser Assertions
``assertBrowserCookieValueSame(string $name, string $expectedValue, string $path = '/', ?string $domain = null, string $message = '')``
Asserts the given cookie in the test Client is set to the expected
value.
+``assertBrowserHistoryIsOnFirstPage(string $message = '')``/``assertBrowserHistoryIsNotOnFirstPage(string $message = '')``
+ Asserts that the browser history is (not) on the first page.
+``assertBrowserHistoryIsOnLastPage(string $message = '')``/``assertBrowserHistoryIsNotOnLastPage(string $message = '')``
+ Asserts that the browser history is (not) on the last page.
``assertThatForClient(Constraint $constraint, string $message = '')``
Asserts the given Constraint in the Client. Useful for using your custom asserts
in the same way as built-in asserts (i.e. without passing the Client as argument)::
@@ -1113,8 +1106,8 @@ Mailer Assertions
``assertEmailHeaderSame(RawMessage $email, string $headerName, string $expectedValue, string $message = '')``/``assertEmailHeaderNotSame(RawMessage $email, string $headerName, string $expectedValue, string $message = '')``
Asserts that the given email does (not) have the expected header set to
the expected value.
-``assertEmailAddressContains(RawMessage $email, string $headerName, string $expectedValue, string $message = '')``
- Asserts that the given address header equals the expected e-mail
+``assertEmailAddressContains(RawMessage $email, string $headerName, string $expectedValue, string $message = '')``/``assertEmailAddressNotContains(RawMessage $email, string $headerName, string $expectedValue, string $message = '')``
+ Asserts that the given address header does (not) equal the expected e-mail
address. This assertion normalizes addresses like ``Jane Smith
`` into ``jane@example.com``.
``assertEmailSubjectContains(RawMessage $email, string $expectedValue, string $message = '')``/``assertEmailSubjectNotContains(RawMessage $email, string $expectedValue, string $message = '')``
diff --git a/testing/profiling.rst b/testing/profiling.rst
index 085cd100c2d..59fa76cfb3e 100644
--- a/testing/profiling.rst
+++ b/testing/profiling.rst
@@ -24,23 +24,6 @@ tests significantly. That's why Symfony disables it by default:
framework:
profiler: { enabled: true, collect: false }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/test/web_profiler.php
diff --git a/translation.rst b/translation.rst
index 47f9124a5f2..fa0c592593d 100644
--- a/translation.rst
+++ b/translation.rst
@@ -77,25 +77,6 @@ are located:
translator:
default_path: '%kernel.project_dir%/translations'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/translation.php
@@ -343,6 +324,20 @@ Templates are now much simpler because you can pass translatable objects to the
There's also a :ref:`function called t() `,
available both in Twig and PHP, as a shortcut to create translatable objects.
+Non-Translatable Messages
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In some cases, you may want to explicitly prevent a message from being
+translated. You can ensure this behavior by using the
+:class:`Symfony\\Component\\Translation\\StaticMessage` class::
+
+ use Symfony\Component\Translation\StaticMessage;
+
+ $message = new StaticMessage('This message will never be translated.');
+
+This can be useful when rendering user-defined content or other strings
+that must remain exactly as given.
+
.. _translation-in-templates:
Translations in Templates
@@ -425,10 +420,6 @@ You can also specify the message domain and pass some additional variables:
Global Translation Parameters
-----------------------------
-.. versionadded:: 7.3
-
- The global translation parameters feature was introduced in Symfony 7.3.
-
If the content of a translation parameter is repeated across multiple
translation messages (e.g. a company name, or a version number), you can define
it as a global translation parameter. This helps you avoid repeating the same
@@ -450,31 +441,6 @@ of your main configuration file using either ``%...%`` or ``{...}`` syntax:
'{app_version}': '1.2.3'
'{url}': { message: 'url', parameters: { scheme: 'https://' }, domain: 'global' }
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
- My application
-
-
- https://
-
-
-
-
-
.. code-block:: php
// config/packages/translator.php
@@ -570,10 +536,6 @@ to spot untranslated strings:
# when using the --no-fill option, the --prefix option is ignored
$ php bin/console translation:extract --force --no-fill fr
-.. versionadded:: 7.2
-
- The ``--no-fill`` option was introduced in Symfony 7.2.
-
.. _translation-resource-locations:
Translation Resource/File Names and Locations
@@ -648,25 +610,6 @@ if you're generating translations with specialized programs or teams.
paths:
- '%kernel.project_dir%/custom/path/to/translations'
- .. code-block:: xml
-
-
-
-
-
-
-
- %kernel.project_dir%/custom/path/to/translations
-
-
-
-
.. code-block:: php
// config/packages/translation.php
@@ -770,31 +713,6 @@ configure the ``providers`` option:
domains: ['messages']
locales: ['en', 'fr']
- .. code-block:: xml
-
-
-
-
-
-
-
-
- messages
-
- en
- fr
-
-
-
-
-
-
.. code-block:: php
# config/packages/translation.php
@@ -993,21 +911,6 @@ A better policy is to include the locale in the URL using the
requirements:
_locale: en|fr|de
- .. code-block:: xml
-
-
-
-
-
-
- controller="App\Controller\ContactController::index">
- en|fr|de
-
-
-
.. code-block:: php
// config/routes.php
@@ -1054,21 +957,6 @@ the framework:
framework:
default_locale: en
- .. code-block:: xml
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/translation.php
@@ -1102,10 +990,6 @@ match between them, Symfony will try to find a partial match based on the langua
If there's no perfect or partial match, this method returns the first locale passed
as argument (that's why the order of the passed locales is important).
-.. versionadded:: 7.1
-
- The feature to match locales partially was introduced in Symfony 7.1.
-
.. _translation-fallback:
Fallback Translation Locales
@@ -1139,26 +1023,6 @@ checks translation resources for several locales:
fallbacks: ['en']
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
- en
-
-
-
-
-
.. code-block:: php
// config/packages/translation.php
@@ -1517,10 +1381,6 @@ to check that the translation contents are also correct:
# checks the contents of the translation catalogues for Italian (it) and Japanese (ja) locales
$ php bin/console lint:translations --locale=it --locale=ja
-.. versionadded:: 7.2
-
- The ``lint:translations`` command was introduced in Symfony 7.2.
-
Pseudo-localization translator
------------------------------
@@ -1584,37 +1444,6 @@ it in the translator configuration:
# also translate the contents of these HTML attributes
localizable_html_attributes: ['title']
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
- title
-
-
-
-
-
.. code-block:: php
// config/packages/translation.php
diff --git a/validation/custom_constraint.rst b/validation/custom_constraint.rst
index fa05085dcf2..95d6213093c 100644
--- a/validation/custom_constraint.rst
+++ b/validation/custom_constraint.rst
@@ -664,7 +664,3 @@ class to check precisely which of the constraints failed to pass::
}
}
-.. versionadded:: 7.2
-
- The :class:`Symfony\\Component\\Validator\\Test\\CompoundConstraintTestCase`
- class was introduced in Symfony 7.2.
diff --git a/validation/raw_values.rst b/validation/raw_values.rst
index 9c900ff2b36..4fecb7c44ee 100644
--- a/validation/raw_values.rst
+++ b/validation/raw_values.rst
@@ -75,7 +75,7 @@ Validation of arrays is possible using the ``Collection`` constraint::
]),
'email' => new Assert\Email(),
'simple' => new Assert\Length(['min' => 102]),
- 'eye_color' => new Assert\Choice([3, 4]),
+ 'eye_color' => new Assert\Choice(choices: [3, 4]),
'file' => new Assert\File(),
'password' => new Assert\Length(['min' => 60]),
'tags' => new Assert\Optional([
diff --git a/validation/translations.rst b/validation/translations.rst
index db2cd518eb7..37defea81fc 100644
--- a/validation/translations.rst
+++ b/validation/translations.rst
@@ -169,25 +169,6 @@ The default translation domain can be changed globally using the
validation:
translation_domain: validation_errors
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/validator.php
diff --git a/web_link.rst b/web_link.rst
index 2f2f96d106b..c4fbeacbeb6 100644
--- a/web_link.rst
+++ b/web_link.rst
@@ -201,6 +201,26 @@ You can also add links to the HTTP response directly from controllers and servic
are also defined as constants in the :class:`Symfony\\Component\\WebLink\\Link`
class (e.g. ``Link::REL_PRELOAD``, ``Link::REL_PRECONNECT``, etc.).
+Parsing Link Headers
+--------------------
+
+Some third-party APIs provide resources such as pagination URLs using the
+``Link`` HTTP header. The WebLink component provides the
+:class:`Symfony\\Component\\WebLink\\HttpHeaderParser` utility class to parse
+those headers and transform them into :class:`Symfony\\Component\\WebLink\\Link`
+instances::
+
+ use Symfony\Component\WebLink\HttpHeaderParser;
+
+ $parser = new HttpHeaderParser();
+ // get the value of the Link header from the Request
+ $linkHeader = '; rel="prerender",; rel="dns-prefetch"; pr="0.7",; rel="preload"; as="script"';
+
+ $links = $parser->parse($linkHeader)->getLinks();
+ $links[0]->getRels(); // ['prerender']
+ $links[1]->getAttributes(); // ['pr' => '0.7']
+ $links[2]->getHref(); // '/baz.js'
+
.. _`WebLink`: https://github.com/symfony/web-link
.. _`HTTP/2 Server Push`: https://tools.ietf.org/html/rfc7540#section-8.2
.. _`Resource Hints`: https://www.w3.org/TR/resource-hints/
diff --git a/webhook.rst b/webhook.rst
index d27a6e6d906..77c04b22f94 100644
--- a/webhook.rst
+++ b/webhook.rst
@@ -42,19 +42,6 @@ Sendgrid ``mailer.webhook.request_parser.sendgrid``
Sweego ``mailer.webhook.request_parser.sweego``
============== ============================================
-.. versionadded:: 7.1
-
- The support for ``Resend`` and ``MailerSend`` were introduced in Symfony 7.1.
-
-.. versionadded:: 7.2
-
- The ``Mandrill``, ``Mailomat``, ``Mailtrap``, and ``Sweego`` integrations were introduced in
- Symfony 7.2.
-
-.. versionadded:: 7.3
-
- The ``AhaSend`` integration was introduced in Symfony 7.3.
-
.. note::
Install the third-party mailer provider you want to use as described in the
@@ -76,26 +63,6 @@ component routing:
service: 'mailer.webhook.request_parser.mailgun'
secret: '%env(MAILER_MAILGUN_SECRET)%'
- .. code-block:: xml
-
-
-
-
-
-
-
- mailer.webhook.request_parser.mailgun
- %env(MAILER_MAILGUN_SECRET)%
-
-
-
-
-
.. code-block:: php
// config/packages/framework.php
@@ -175,9 +142,10 @@ Currently, the following third-party SMS transports support webhooks:
============ ==========================================
SMS service Parser service name
============ ==========================================
-Twilio ``notifier.webhook.request_parser.twilio``
+LOX24 ``notifier.webhook.request_parser.lox24``
Smsbox ``notifier.webhook.request_parser.smsbox``
Sweego ``notifier.webhook.request_parser.sweego``
+Twilio ``notifier.webhook.request_parser.twilio``
Vonage ``notifier.webhook.request_parser.vonage``
============ ==========================================
diff --git a/workflow.rst b/workflow.rst
index 2a3d1d908ef..f1c7a610abd 100644
--- a/workflow.rst
+++ b/workflow.rst
@@ -76,50 +76,6 @@ follows:
from: reviewed
to: rejected
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
- currentPlace
-
- App\Entity\BlogPost
- draft
-
-
- draft
- reviewed
- rejected
- published
-
-
- draft
- reviewed
-
-
- reviewed
- published
-
-
- reviewed
- rejected
-
-
-
-
-
.. code-block:: php
// config/packages/workflow.php
@@ -178,11 +134,6 @@ follows:
that are used in the workflow. Symfony will automatically extract the places
from the transitions.
- .. versionadded:: 7.1
-
- The support for omitting the ``places`` option was introduced in
- Symfony 7.1.
-
The configured property will be used via its implemented getter/setter methods by the marking store::
// src/Entity/BlogPost.php
@@ -294,6 +245,320 @@ what actions are allowed on a blog post::
// See a specific available transition for the post in the current state
$transition = $workflow->getEnabledTransition($post, 'publish');
+Using Enums as Workflow Places
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When using a state machine, you can use PHP backend enums as places in your
+workflows. First, define your enum with backed values::
+
+ // src/Enumeration/BlogPostStatus.php
+ namespace App\Enumeration;
+
+ enum BlogPostStatus: string
+ {
+ case Draft = 'draft';
+ case Reviewed = 'reviewed';
+ case Published = 'published';
+ case Rejected = 'rejected';
+ }
+
+Then configure the workflow using the enum cases as places, initial marking,
+and transitions:
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # config/packages/workflow.yaml
+ framework:
+ workflows:
+ blog_publishing:
+ type: 'workflow'
+ marking_store:
+ type: 'method'
+ property: 'status'
+ supports:
+ - App\Entity\BlogPost
+ initial_marking: !php/enum App\Enumeration\BlogPostStatus::Draft
+ places: !php/enum App\Enumeration\BlogPostStatus
+ transitions:
+ to_review:
+ from: !php/enum App\Enumeration\BlogPostStatus::Draft
+ to: !php/enum App\Enumeration\BlogPostStatus::Reviewed
+ publish:
+ from: !php/enum App\Enumeration\BlogPostStatus::Reviewed
+ to: !php/enum App\Enumeration\BlogPostStatus::Published
+ reject:
+ from: !php/enum App\Enumeration\BlogPostStatus::Reviewed
+ to: !php/enum App\Enumeration\BlogPostStatus::Rejected
+
+ .. code-block:: php
+
+ // config/packages/workflow.php
+ use App\Entity\BlogPost;
+ use App\Enumeration\BlogPostStatus;
+ use Symfony\Config\FrameworkConfig;
+
+ return static function (FrameworkConfig $framework): void {
+ $blogPublishing = $framework->workflows()->workflows('blog_publishing');
+ $blogPublishing
+ ->type('workflow')
+ ->supports([BlogPost::class])
+ ->initialMarking([BlogPostStatus::Draft]);
+
+ $blogPublishing->markingStore()
+ ->type('method')
+ ->property('status');
+
+ $blogPublishing->places(BlogPostStatus::cases());
+
+ $blogPublishing->transition()
+ ->name('to_review')
+ ->from(BlogPostStatus::Draft)
+ ->to([BlogPostStatus::Reviewed]);
+
+ $blogPublishing->transition()
+ ->name('publish')
+ ->from([BlogPostStatus::Reviewed])
+ ->to([BlogPostStatus::Published]);
+
+ $blogPublishing->transition()
+ ->name('reject')
+ ->from([BlogPostStatus::Reviewed])
+ ->to([BlogPostStatus::Rejected]);
+ };
+
+The component will now transparently cast the enum to its backing value
+when needed and vice-versa when working with your objects::
+
+ // src/Entity/BlogPost.php
+ namespace App\Entity;
+
+ class BlogPost
+ {
+ private BlogPostStatus $status;
+
+ public function getStatus(): BlogPostStatus
+ {
+ return $this->status;
+ }
+
+ public function setStatus(BlogPostStatus $status): void
+ {
+ $this->status = $status;
+ }
+ }
+
+.. tip::
+
+ You can also use `glob patterns`_ of PHP constants and enums to list the places:
+
+ .. configuration-block::
+
+ .. code-block:: yaml
+
+ # config/packages/workflow.yaml
+ framework:
+ workflows:
+ my_workflow_name:
+ # with constants:
+ places: 'App\Workflow\MyWorkflow::PLACE_*'
+
+ # with enums:
+ places: !php/enum App\Workflow\Places
+
+ # ...
+
+ .. code-block:: php
+
+ // config/packages/workflow.php
+ use App\Entity\BlogPost;
+ use App\Enumeration\BlogPostStatus;
+ use Symfony\Config\FrameworkConfig;
+
+ return static function (FrameworkConfig $framework): void {
+ $blogPublishing = $framework->workflows()->workflows('my_workflow_name');
+
+ // with constants:
+ $blogPublishing->places('App\Workflow\MyWorkflow::PLACE_*');
+
+ // with enums:
+ $blogPublishing->places(BlogPostStatus::cases());
+
+ // ...
+ };
+
+Using Weighted Transitions
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A key feature of workflows (as opposed to state machines) is that an object can
+be in multiple places simultaneously. For example, when building a product, you
+might assemble several components in parallel. However, in the previous example,
+each place could only record whether the object was there or not, like a binary flag.
+
+**Weighted transitions** introduce multiplicity: a place can now track how many
+times an object is in that place. Technically, weighted transitions allow you to
+define transitions where multiple tokens (instances) are consumed from or produced
+to places. This is useful for modeling complex workflows such as manufacturing
+processes, resource allocation, or any scenario where multiple instances of something
+need to be produced or consumed.
+
+For example, imagine a table-making workflow where you need to create 4 legs, 1 top,
+and track the process with a stopwatch. You can use weighted transitions to model this:
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # config/packages/workflow.yaml
+ framework:
+ workflows:
+ make_table:
+ type: 'workflow'
+ marking_store:
+ type: 'method'
+ property: 'marking'
+ supports:
+ - App\Entity\TableProject
+ initial_marking: init
+ places:
+ - init
+ - prepare_leg
+ - prepare_top
+ - stopwatch_running
+ - leg_created
+ - top_created
+ - finished
+ transitions:
+ start:
+ from: init
+ to:
+ - place: prepare_leg
+ weight: 4
+ - place: prepare_top
+ weight: 1
+ - place: stopwatch_running
+ weight: 1
+ build_leg:
+ from: prepare_leg
+ to: leg_created
+ build_top:
+ from: prepare_top
+ to: top_created
+ join:
+ from:
+ - place: leg_created
+ weight: 4
+ - top_created # weight defaults to 1
+ - stopwatch_running
+ to: finished
+
+ .. code-block:: php
+
+ // config/packages/workflow.php
+ use App\Entity\TableProject;
+ use Symfony\Config\FrameworkConfig;
+
+ return static function (FrameworkConfig $framework): void {
+ $makeTable = $framework->workflows()->workflows('make_table');
+ $makeTable
+ ->type('workflow')
+ ->supports([TableProject::class])
+ ->initialMarking(['init']);
+
+ $makeTable->markingStore()
+ ->type('method')
+ ->property('marking');
+
+ $makeTable->place()->name('init');
+ $makeTable->place()->name('prepare_leg');
+ $makeTable->place()->name('prepare_top');
+ $makeTable->place()->name('stopwatch_running');
+ $makeTable->place()->name('leg_created');
+ $makeTable->place()->name('top_created');
+ $makeTable->place()->name('finished');
+
+ $makeTable->transition()
+ ->name('start')
+ ->from(['init'])
+ ->to([
+ ['place' => 'prepare_leg', 'weight' => 4],
+ ['place' => 'prepare_top', 'weight' => 1],
+ ['place' => 'stopwatch_running', 'weight' => 1],
+ ]);
+
+ $makeTable->transition()
+ ->name('build_leg')
+ ->from(['prepare_leg'])
+ ->to(['leg_created']);
+
+ $makeTable->transition()
+ ->name('build_top')
+ ->from(['prepare_top'])
+ ->to(['top_created']);
+
+ $makeTable->transition()
+ ->name('join')
+ ->from([
+ ['place' => 'leg_created', 'weight' => 4],
+ 'top_created', // weight defaults to 1
+ 'stopwatch_running',
+ ])
+ ->to(['finished']);
+ };
+
+In this example, when the ``start`` transition is applied, it creates 4 tokens in
+the ``prepare_leg`` place, 1 token in ``prepare_top``, and 1 token in
+``stopwatch_running``. Then, the ``build_leg`` transition must be applied 4 times
+(once for each token), and the ``build_top`` transition once. Finally, the ``join``
+transition can only be applied when all 4 legs are created, the top is created,
+and the stopwatch is still running.
+
+Weighted transitions can also be defined programmatically using the
+:class:`Symfony\\Component\\Workflow\\Arc` class::
+
+ use Symfony\Component\Workflow\Arc;
+ use Symfony\Component\Workflow\Definition;
+ use Symfony\Component\Workflow\Transition;
+ use Symfony\Component\Workflow\Workflow;
+
+ $definition = new Definition(
+ ['init', 'prepare_leg', 'prepare_top', 'stopwatch_running', 'leg_created', 'top_created', 'finished'],
+ [
+ new Transition('start', 'init', [
+ new Arc('prepare_leg', 4),
+ new Arc('prepare_top', 1),
+ 'stopwatch_running', // defaults to weight 1
+ ]),
+ new Transition('build_leg', 'prepare_leg', 'leg_created'),
+ new Transition('build_top', 'prepare_top', 'top_created'),
+ new Transition('join', [
+ new Arc('leg_created', 4),
+ 'top_created',
+ 'stopwatch_running',
+ ], 'finished'),
+ ]
+ );
+
+ $workflow = new Workflow($definition);
+ $workflow->apply($subject, 'start');
+
+ // Build each leg (4 times)
+ $workflow->apply($subject, 'build_leg');
+ $workflow->apply($subject, 'build_leg');
+ $workflow->apply($subject, 'build_leg');
+ $workflow->apply($subject, 'build_leg');
+
+ // Build the top
+ $workflow->apply($subject, 'build_top');
+
+ // Now we can join all parts
+ $workflow->apply($subject, 'join');
+
+The ``Arc`` class takes two parameters: the place name and the weight (which must be
+greater than or equal to 1). When a place is specified as a simple string instead of
+an ``Arc`` object, it defaults to a weight of 1.
+
Using a multiple state marking store
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -390,11 +655,6 @@ To get the enabled transition of a Workflow, you can use
:method:`Symfony\\Component\\Workflow\\WorkflowInterface::getEnabledTransition`
method.
-.. versionadded:: 7.1
-
- The :method:`Symfony\\Component\\Workflow\\WorkflowInterface::getEnabledTransition`
- method was introduced in Symfony 7.1.
-
.. tip::
If you want to retrieve all workflows, for documentation purposes for example,
@@ -410,10 +670,6 @@ method.
Learn more about :ref:`tag attributes ` and
:ref:`storing workflow metadata `.
- .. versionadded:: 7.1
-
- The attached configuration to the tag was introduced in Symfony 7.1.
-
.. tip::
You can find the list of available workflow services with the
@@ -614,10 +870,6 @@ workflow leaves a place::
You can also use this method in your custom events via the
:class:`Symfony\\Component\\Workflow\\Event\\EventNameTrait`.
- .. versionadded:: 7.1
-
- The ``getName()`` method was introduced in Symfony 7.1.
-
If some listeners update the context during a transition, you can retrieve
it via the marking::
@@ -727,30 +979,6 @@ to :ref:`Guard events `, which are always fired:
# ...
- .. code-block:: xml
-
-
-
-
-
-
-
- workflow.leave
- workflow.completed
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/workflow.php
@@ -882,49 +1110,6 @@ transition. The value of this option is any valid expression created with the
from: reviewed
to: rejected
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
- is_granted("ROLE_REVIEWER")
- draft
- reviewed
-
-
-
-
- is_authenticated
- reviewed
- published
-
-
-
-
- is_granted("ROLE_ADMIN") and subject.isStatusReviewed()
- reviewed
- rejected
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/workflow.php
@@ -1047,24 +1232,6 @@ it:
marking_store:
service: 'App\Workflow\MarkingStore\BlogPostMarkingStore'
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/workflow.php
@@ -1180,47 +1347,6 @@ be only the title of the workflow or very complex objects:
hour_limit: 20
explanation: 'You can not publish after 8 PM.'
- .. code-block:: xml
-
-
-
-
-
-
-
- Blog Publishing Workflow
-
-
-
-
- 500
-
-
-
-
- draft
- review
-
- 0.5
-
-
-
- reviewed
- published
-
- 20
- You can not publish after 8 PM.
-
-
-
-
-
-
.. code-block:: php
// config/packages/workflow.php
@@ -1392,24 +1518,6 @@ After implementing your validator, configure your workflow to use it:
definition_validators:
- App\Workflow\Validator\BlogPublishingValidator
- .. code-block:: xml
-
-
-
-
-
-
-
- App\Workflow\Validator\BlogPublishingValidator
-
-
-
-
.. code-block:: php
// config/packages/workflow.php
@@ -1429,10 +1537,6 @@ After implementing your validator, configure your workflow to use it:
The ``BlogPublishingValidator`` will be executed during container compilation
to validate the workflow definition.
-.. versionadded:: 7.3
-
- Support for workflow definition validators was introduced in Symfony 7.3.
-
Learn more
----------
@@ -1441,3 +1545,5 @@ Learn more
/workflow/workflow-and-state-machine
/workflow/dumping-workflows
+
+.. _`glob patterns`: https://php.net/glob
diff --git a/workflow/dumping-workflows.rst b/workflow/dumping-workflows.rst
index 8262fefd6c1..971cf6abec4 100644
--- a/workflow/dumping-workflows.rst
+++ b/workflow/dumping-workflows.rst
@@ -161,104 +161,6 @@ Below is the configuration for the pull request state machine with styling added
from: closed
to: review
- .. code-block:: xml
-
-
-
-
-
-
-
-
- method
- currentPlace
-
-
- App\Entity\PullRequest
-
- start
-
- start
- coding
- test
-
-
- Human review
-
-
- merged
-
-
- DeepSkyBlue
-
-
-
-
- start
-
- test
-
-
-
- coding
- test
- review
-
- test
-
-
- Turquoise
-
-
-
-
- test
-
- review
-
-
- Orange
-
-
-
-
- review
-
- coding
-
-
-
- review
-
- merged
-
-
- Accept PR
-
-
-
-
- review
-
- closed
-
-
-
- closed
-
- review
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/workflow.php
diff --git a/workflow/workflow-and-state-machine.rst b/workflow/workflow-and-state-machine.rst
index 3a034b97357..3992e7cfa2f 100644
--- a/workflow/workflow-and-state-machine.rst
+++ b/workflow/workflow-and-state-machine.rst
@@ -115,82 +115,6 @@ Below is the configuration for the pull request state machine.
from: closed
to: review
- .. code-block:: xml
-
-
-
-
-
-
-
- start
-
-
-
-
- App\Entity\PullRequest
-
- start
- coding
- test
- review
- merged
- closed
-
-
- start
-
- test
-
-
-
- coding
- test
- review
-
- test
-
-
-
- test
-
- review
-
-
-
- review
-
- coding
-
-
-
- review
-
- merged
-
-
-
- review
-
- closed
-
-
-
- closed
-
- review
-
-
-
-
-
-
-
.. code-block:: php
// config/packages/workflow.php
@@ -258,11 +182,6 @@ Below is the configuration for the pull request state machine.
that are used in the workflow. Symfony will automatically extract the places
from the transitions.
- .. versionadded:: 7.1
-
- The support for omitting the ``places`` option was introduced in
- Symfony 7.1.
-
Symfony automatically creates a service for each workflow (:class:`Symfony\\Component\\Workflow\\Workflow`)
or state machine (:class:`Symfony\\Component\\Workflow\\StateMachine`) you
have defined in your configuration. You can use the workflow inside a class by using