From 90ba4de5ea2253904d6d88db69ef6cd0d455cc38 Mon Sep 17 00:00:00 2001 From: Hamza Amrouche Date: Wed, 29 May 2019 07:32:31 +0200 Subject: [PATCH 0001/1519] minor: update remove of loggingmiddleware --- components/messenger.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/messenger.rst b/components/messenger.rst index 3825d1571ae..9fb4dc6eec8 100644 --- a/components/messenger.rst +++ b/components/messenger.rst @@ -75,8 +75,7 @@ middleware stack. The component comes with a set of middleware that you can use. When using the message bus with Symfony's FrameworkBundle, the following middleware are configured for you: -#. :class:`Symfony\\Component\\Messenger\\Middleware\\LoggingMiddleware` (logs the processing of your messages) -#. :class:`Symfony\\Component\\Messenger\\Middleware\\SendMessageMiddleware` (enables asynchronous processing) +#. :class:`Symfony\\Component\\Messenger\\Middleware\\SendMessageMiddleware` (enables asynchronous processing, logs the processing of your messages if you pass a logger) #. :class:`Symfony\\Component\\Messenger\\Middleware\\HandleMessageMiddleware` (calls the registered handler(s)) Example:: From bcc55c55a68ab728fe56730fbc7d044bdf557fee Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 29 May 2019 12:17:56 +0200 Subject: [PATCH 0002/1519] Removed Symfony 4.* versionadded directives --- cache.rst | 8 --- .../cache/adapters/memcached_adapter.rst | 4 -- components/cache/adapters/redis_adapter.rst | 8 --- components/cache/psr6_psr16_adapters.rst | 8 --- components/console/helpers/progressbar.rst | 4 -- components/console/helpers/questionhelper.rst | 4 -- components/dom_crawler.rst | 16 ------ components/dotenv.rst | 4 -- components/finder.rst | 9 ---- components/http_client.rst | 4 -- components/intl.rst | 24 --------- components/lock.rst | 4 -- components/options_resolver.rst | 4 -- components/property_access.rst | 5 -- components/routing.rst | 50 ------------------- components/security/authentication.rst | 4 -- components/serializer.rst | 7 +-- configuration/environment_variables.rst | 20 -------- console/coloring.rst | 4 -- form/form_customization.rst | 4 -- form/form_themes.rst | 4 -- http_cache.rst | 5 -- logging.rst | 5 -- logging/processors.rst | 5 -- messenger.rst | 9 ---- reference/configuration/framework.rst | 22 -------- reference/configuration/security.rst | 10 ---- reference/constraints/Bic.rst | 12 ----- reference/constraints/CardScheme.rst | 4 -- reference/constraints/Choice.rst | 8 --- reference/constraints/Negative.rst | 4 -- reference/constraints/NegativeOrZero.rst | 4 -- reference/constraints/NotBlank.rst | 4 -- .../constraints/NotCompromisedPassword.rst | 4 -- reference/constraints/Positive.rst | 4 -- reference/constraints/PositiveOrZero.rst | 4 -- reference/constraints/Timezone.rst | 4 -- reference/forms/types/button.rst | 4 -- reference/forms/types/number.rst | 8 --- .../attr_translation_parameters.rst.inc | 4 -- .../forms/types/options/block_prefix.rst.inc | 4 -- .../date_input_format_description.rst.inc | 4 -- .../help_translation_parameters.rst.inc | 4 -- .../label_translation_parameters.rst.inc | 4 -- reference/forms/types/percent.rst | 4 -- reference/forms/types/time.rst | 4 -- reference/forms/types/timezone.rst | 4 -- routing.rst | 9 ---- routing/custom_route_loader.rst | 5 -- routing/debug.rst | 4 -- routing/service_container_parameters.rst | 4 -- security/csrf.rst | 4 -- security/impersonating_user.rst | 8 --- service_container/alias_private.rst | 4 -- service_container/autowiring.rst | 4 -- service_container/configurators.rst | 4 -- service_container/factories.rst | 4 -- templating/hinclude.rst | 6 --- testing.rst | 4 -- testing/functional_tests_assertions.rst | 5 -- translation.rst | 5 -- workflow.rst | 10 +--- 62 files changed, 2 insertions(+), 429 deletions(-) diff --git a/cache.rst b/cache.rst index 01542cb9b85..c397c031393 100644 --- a/cache.rst +++ b/cache.rst @@ -30,10 +30,6 @@ Basic uses of the cache looks like this:: Symfony supports the Cache Contracts, PSR-6/16 and Doctrine Cache interfaces. You can read more about these at the :doc:`component documentation `. -.. versionadded:: 4.2 - - The cache contracts were introduced in Symfony 4.2. - .. _cache-configuration-with-frameworkbundle: Configuring Cache with FrameworkBundle @@ -612,10 +608,6 @@ To see all available cache pools: $ php bin/console cache:pool:list -.. versionadded:: 4.3 - - The ``cache:pool:list`` command was introduced in Symfony 4.3. - Clear one pool: .. code-block:: terminal diff --git a/components/cache/adapters/memcached_adapter.rst b/components/cache/adapters/memcached_adapter.rst index 42ae791d2d3..b024f3f4178 100644 --- a/components/cache/adapters/memcached_adapter.rst +++ b/components/cache/adapters/memcached_adapter.rst @@ -70,10 +70,6 @@ helper method allows creating and configuring a `Memcached`_ class instance usin 'memcached:?host[localhost]&host[localhost:12345]&host[/some/memcached.sock:]=3' ); -.. versionadded:: 4.2 - - The option to define multiple servers in a single DSN was introduced in Symfony 4.2. - The `Data Source Name (DSN)`_ for this adapter must use the following format: .. code-block:: text diff --git a/components/cache/adapters/redis_adapter.rst b/components/cache/adapters/redis_adapter.rst index 53b28c58466..1cbccc4d749 100644 --- a/components/cache/adapters/redis_adapter.rst +++ b/components/cache/adapters/redis_adapter.rst @@ -102,14 +102,6 @@ name of your service group:: 'redis:?host[redis1:26379]&host[redis2:26379]&host[redis3:26379]&redis_sentinel=mymaster' ); -.. versionadded:: 4.2 - - The option to define multiple servers in a single DSN was introduced in Symfony 4.2. - -.. versionadded:: 4.4 - - Redis Sentinel support was introduced in Symfony 4.4. - .. note:: See the :class:`Symfony\\Component\\Cache\\Traits\\RedisTrait` for more options diff --git a/components/cache/psr6_psr16_adapters.rst b/components/cache/psr6_psr16_adapters.rst index 96e29a6d8ea..1bf299ca9d4 100644 --- a/components/cache/psr6_psr16_adapters.rst +++ b/components/cache/psr6_psr16_adapters.rst @@ -46,10 +46,6 @@ this use-case:: // now use this wherever you want $githubApiClient = new GitHubApiClient($psr6Cache); -.. versionadded:: 4.3 - - The ``Psr16Adapter`` class was introduced in Symfony 4.3. - Using a PSR-6 Cache Object as a PSR-16 Cache -------------------------------------------- @@ -87,8 +83,4 @@ this use-case:: // now use this wherever you want $githubApiClient = new GitHubApiClient($psr16Cache); -.. versionadded:: 4.3 - - The ``Psr16Cache`` class was introduced in Symfony 4.3. - .. _`PSR-16`: http://www.php-fig.org/psr/psr-16/ diff --git a/components/console/helpers/progressbar.rst b/components/console/helpers/progressbar.rst index bf832b3131e..04ed076d1a6 100644 --- a/components/console/helpers/progressbar.rst +++ b/components/console/helpers/progressbar.rst @@ -118,10 +118,6 @@ If ``$iterable = [1, 2]``, the previous code will output the following: 1/2 [==============>-------------] 50% 2/2 [============================] 100% -.. versionadded:: 4.3 - - The ``iterate()`` method was introduced in Symfony 4.3. - Customizing the Progress Bar ---------------------------- diff --git a/components/console/helpers/questionhelper.rst b/components/console/helpers/questionhelper.rst index 997e56daf33..348b0f891e6 100644 --- a/components/console/helpers/questionhelper.rst +++ b/components/console/helpers/questionhelper.rst @@ -212,10 +212,6 @@ provide a callback function to dynamically generate suggestions:: $filePath = $helper->ask($input, $output, $question); } -.. versionadded:: 4.3 - - The ``setAutocompleterCallback()`` method was introduced in Symfony 4.3. - Hiding the User's Response ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/components/dom_crawler.rst b/components/dom_crawler.rst index 3f14da6c751..0681b08e764 100644 --- a/components/dom_crawler.rst +++ b/components/dom_crawler.rst @@ -77,10 +77,6 @@ tree. The DomCrawler component will use it automatically when the content has an HTML5 doctype. - .. versionadded:: 4.3 - - The automatic support of the html5-php library was introduced in Symfony 4.3. - Node Filtering ~~~~~~~~~~~~~~ @@ -216,10 +212,6 @@ Access the value of the first node of the current selection:: // avoid the exception passing an argument that text() returns when node does not exist $message = $crawler->filterXPath('//body/p')->text('Default text content'); -.. versionadded:: 4.3 - - The default argument of ``text()`` was introduced in Symfony 4.3. - Access the attribute value of the first node of the current selection:: $class = $crawler->filterXPath('//body/p')->attr('class'); @@ -236,10 +228,6 @@ Extract attribute and/or node values from the list of nodes:: Special attribute ``_text`` represents a node value, while ``_name`` represents the element name (the HTML tag name). - .. versionadded:: 4.3 - - The special attribute ``_name`` was introduced in Symfony 4.3. - Call an anonymous function on each node of the list:: use Symfony\Component\DomCrawler\Crawler; @@ -333,10 +321,6 @@ and :phpclass:`DOMNode` objects:: // avoid the exception passing an argument that html() returns when node does not exist $html = $crawler->html('Default HTML content'); - .. versionadded:: 4.3 - - The default argument of ``html()`` was introduced in Symfony 4.3. - Expression Evaluation ~~~~~~~~~~~~~~~~~~~~~ diff --git a/components/dotenv.rst b/components/dotenv.rst index da4aa3f9cdd..b8856864be0 100644 --- a/components/dotenv.rst +++ b/components/dotenv.rst @@ -104,10 +104,6 @@ You can adjust the variable defining the environment, default environment and te environments by passing them as additional arguments to ``Dotenv::loadEnv()`` (see :method:`Symfony\\Component\\Dotenv\\Dotenv::loadEnv` for details). -.. versionadded:: 4.2 - - The ``Dotenv::loadEnv()`` method was introduced in Symfony 4.2. - You should never store a ``.env`` file in your code repository as it might contain sensitive information; create a ``.env.dist`` file (or multiple environment-specific ones as shown above) with sensible defaults instead. diff --git a/components/finder.rst b/components/finder.rst index 00c5df2bf79..c411a4e83c5 100644 --- a/components/finder.rst +++ b/components/finder.rst @@ -150,10 +150,6 @@ rules to exclude files and directories from the results with the // excludes files/directories matching the .gitignore patterns $finder->ignoreVCSIgnored(true); -.. versionadded:: 4.3 - - The ``ignoreVCSIgnored()`` method was introduced in Symfony 4.3. - File Name ~~~~~~~~~ @@ -250,11 +246,6 @@ Multiple paths can be excluded by chaining calls or passing an array:: // same as above $finder->notPath(['first/dir', 'other/dir']); -.. versionadded:: 4.2 - - Support for passing arrays to ``notPath()`` was introduced in Symfony - 4.2 - File Size ~~~~~~~~~ diff --git a/components/http_client.rst b/components/http_client.rst index 96eee00c476..7ad605f5c5c 100644 --- a/components/http_client.rst +++ b/components/http_client.rst @@ -8,10 +8,6 @@ The HttpClient Component The HttpClient component is a low-level HTTP client with support for both PHP stream wrappers and cURL. It also provides utilities to consume APIs. -.. versionadded:: 4.3 - - The HttpClient component was introduced in Symfony 4.3. - Installation ------------ diff --git a/components/intl.rst b/components/intl.rst index 3e0f8a03208..69e090628e2 100644 --- a/components/intl.rst +++ b/components/intl.rst @@ -92,10 +92,6 @@ You can also check if a given language code is valid:: $isValidLanguage = Languages::exists($languageCode); -.. versionadded:: 4.3 - - The ``Languages`` class was introduced in Symfony 4.3. - The ``Scripts`` class provides access to the optional four-letter script code that can follow the language code according to the `Unicode ISO 15924 Registry`_ (e.g. ``HANS`` in ``zh_HANS`` for simplified Chinese and ``HANT`` in ``zh_HANT`` @@ -125,10 +121,6 @@ You can also check if a given script code is valid:: $isValidScript = Scripts::exists($scriptCode); -.. versionadded:: 4.3 - - The ``Scripts`` class was introduced in Symfony 4.3. - Country Names ~~~~~~~~~~~~~ @@ -160,10 +152,6 @@ You can also check if a given country code is valid:: $isValidCountry = Countries::exists($countryCode); -.. versionadded:: 4.3 - - The ``Countries`` class was introduced in Symfony 4.3. - Locales ~~~~~~~ @@ -196,10 +184,6 @@ You can also check if a given locale code is valid:: $isValidLocale = Locales::exists($localeCode); -.. versionadded:: 4.3 - - The ``Locales`` class was introduced in Symfony 4.3. - Currencies ~~~~~~~~~~ @@ -240,10 +224,6 @@ You can also check if a given currency code is valid:: $isValidCurrency = Currencies::exists($currencyCode); -.. versionadded:: 4.3 - - The ``Currencies`` class was introduced in Symfony 4.3. - Timezones ~~~~~~~~~ @@ -273,10 +253,6 @@ You can also check if a given timezone ID is valid:: $isValidTimezone = Timezones::exists($timezoneId); -.. versionadded:: 4.3 - - The ``Timezones`` class was introduced in Symfony 4.3. - Learn more ---------- diff --git a/components/lock.rst b/components/lock.rst index 92d917b2fc3..f6e1a761208 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -223,10 +223,6 @@ support blocking, and expects a TTL to avoid stalled locks:: MongoDbStore ~~~~~~~~~~~~ -.. versionadded:: 4.3 - - The ``MongoDbStore`` was introduced in Symfony 4.3. - The MongoDbStore saves locks on a MongoDB server, it requires a ``\MongoDB\Client`` connection from `mongodb/mongodb`_. This store does not support blocking and expects a TTL to avoid stalled locks:: diff --git a/components/options_resolver.rst b/components/options_resolver.rst index 16f891ea869..17fde396792 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -439,10 +439,6 @@ This way, the ``$value`` argument will receive the previously normalized value, otherwise you can prepend the new normalizer by passing ``true`` as third argument. -.. versionadded:: 4.3 - - The ``addNormalizer()`` method was introduced in Symfony 4.3. - Default Values that Depend on another Option ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/components/property_access.rst b/components/property_access.rst index c362da2da22..ef6394393a8 100644 --- a/components/property_access.rst +++ b/components/property_access.rst @@ -169,11 +169,6 @@ This will produce: ``He is an author`` Accessing a non Existing Property Path ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 4.3 - - The ``disableExceptionOnInvalidPropertyPath()`` method was introduced in - Symfony 4.3. - By default a :class:`Symfony\\Component\\PropertyAccess\\Exception\\NoSuchPropertyException` is thrown if the property path passed to :method:`PropertyAccessor::getValue` does not exist. You can change this behavior using the diff --git a/components/routing.rst b/components/routing.rst index dc0600d0eb0..111ea10f9e5 100644 --- a/components/routing.rst +++ b/components/routing.rst @@ -454,56 +454,6 @@ routes with UTF-8 characters: ; }; -.. versionadded:: 4.3 - - The ``utf8`` option/method has been introduced in Symfony 4.3. - Before you had to use the ``options`` setting to define this value: - - .. configuration-block:: - - .. code-block:: php-annotations - - route1: - path: /category/{name} - controller: App\Controller\DefaultController::category - options: { utf8: true } - - .. code-block:: yaml - - route1: - path: /category/{name} - controller: App\Controller\DefaultController::category - utf8: true - - .. code-block:: xml - - - - - - - - - - .. code-block:: php - - // config/routes.php - namespace Symfony\Component\Routing\Loader\Configurator; - - use App\Controller\DefaultController; - - return function (RoutingConfigurator $routes) { - $routes->add('route1', '/category/{name}') - ->controller([DefaultController::class, 'category']) - ->options(['utf8' => true]) - ; - }; - In this route, the ``utf8`` option set to ``true`` makes Symfony consider the ``.`` requirement to match any UTF-8 characters instead of just a single byte character. This means that so the following URLs would match: diff --git a/components/security/authentication.rst b/components/security/authentication.rst index 7fd59c6c857..5b91ab2c183 100644 --- a/components/security/authentication.rst +++ b/components/security/authentication.rst @@ -318,10 +318,6 @@ the ``switch_user`` firewall listener. The ``Symfony\Component\Security\Http\Event\DeauthenticatedEvent`` event is triggered when a token has been deauthenticated because of a user change, it can help you doing some clean-up task when a logout has been triggered. -.. versionadded:: 4.3 - - The ``Symfony\Component\Security\Http\Event\DeauthenticatedEvent`` event was introduced in Symfony 4.3. - .. seealso:: For more information on switching users, see diff --git a/components/serializer.rst b/components/serializer.rst index 1c6359033bc..76819a816ed 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -223,11 +223,6 @@ normalized data, instead of the denormalizer re-creating them. Note that arrays of objects. Those will still be replaced when present in the normalized data. -.. versionadded:: 4.3 - - The ``AbstractObjectNormalizer::DEEP_OBJECT_TO_POPULATE`` option was - introduced in Symfony 4.3. - .. _component-serializer-attributes-groups: Attributes Groups @@ -664,7 +659,7 @@ When serializing, you can set a callback to format a specific object property:: 'createdAt' => $callback, ], ]; - + $normalizer = new GetSetMethodNormalizer(null, null, null, null, null, $defaultContext); $serializer = new Serializer([$normalizer], [$encoder]); diff --git a/configuration/environment_variables.rst b/configuration/environment_variables.rst index e9e258c4aa1..b59ef5de690 100644 --- a/configuration/environment_variables.rst +++ b/configuration/environment_variables.rst @@ -497,19 +497,11 @@ Symfony provides the following env var processors: 'auth' => '%env(require:AUTH_FILE)%', ]); - .. versionadded:: 4.3 - - The ``require`` processor was introduced in Symfony 4.3. - ``env(trim:FOO)`` Trims the content of ``FOO`` env var, removing whitespaces from the beginning and end of the string. This is especially useful in combination with the ``file`` processor, as it'll remove newlines at the end of a file. - .. versionadded:: 4.3 - - The ``trim`` processor was introduced in Symfony 4.3. - ``env(key:FOO:BAR)`` Retrieves the value associated with the key ``FOO`` from the array whose contents are stored in the ``BAR`` env var: @@ -591,10 +583,6 @@ Symfony provides the following env var processors: When the fallback parameter is omitted (e.g. ``env(default::API_KEY)``), the value returned is ``null``. - .. versionadded:: 4.3 - - The ``default`` processor was introduced in Symfony 4.3. - ``env(url:FOO)`` Parses an absolute URL and returns its components as an associative array. @@ -664,10 +652,6 @@ Symfony provides the following env var processors: In order to ease extraction of the resource from the URL, the leading ``/`` is trimmed from the ``path`` component. - .. versionadded:: 4.3 - - The ``url`` processor was introduced in Symfony 4.3. - ``env(query_string:FOO)`` Parses the query string part of the given URL and returns its components as an associative array. @@ -714,10 +698,6 @@ Symfony provides the following env var processors: ], ]); - .. versionadded:: 4.3 - - The ``query_string`` processor was introduced in Symfony 4.3. - It is also possible to combine any number of processors: .. code-block:: yaml diff --git a/console/coloring.rst b/console/coloring.rst index 2963fefa682..32625377aba 100644 --- a/console/coloring.rst +++ b/console/coloring.rst @@ -77,10 +77,6 @@ You can also set these colors and options directly inside the tag name:: Displaying Clickable Links ~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 4.3 - - The feature to display clickable links was introduced in Symfony 4.3. - Commands can use the special ```` tag to display links similar to the ```` elements of web pages:: diff --git a/form/form_customization.rst b/form/form_customization.rst index 3094eb08f40..ef5733b3146 100644 --- a/form/form_customization.rst +++ b/form/form_customization.rst @@ -315,10 +315,6 @@ spot (since it'll render the field for you). form_parent(form_view) ...................... -.. versionadded:: 4.3 - - The ``form_parent()`` function was introduced in Symfony 4.3. - Returns the parent form view or ``null`` if the form view already is the root form. Using this function should be preferred over accessing the parent form using ``form.parent``. The latter way will produce different results diff --git a/form/form_themes.rst b/form/form_themes.rst index 32322381c08..659dfde50ee 100644 --- a/form/form_themes.rst +++ b/form/form_themes.rst @@ -294,10 +294,6 @@ field without having to :doc:`create a custom form type ` constraint uses the public API provided by `haveibeenpwned.com`_. This option allows to define a different, but compatible, API endpoint to make the password diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index 5fba7fc34ad..5b00a9c5206 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -246,11 +246,6 @@ encoding algorithm. Also, each algorithm defines different config options: alternative is provided because starting from Symfony 5.0 this value will be hardcoded to ``1`` (one thread). -.. versionadded:: 4.3 - - The ``sodium`` algorithm was introduced in Symfony 4.3. In previous Symfony - versions it was called ``argon2i``. - .. tip:: You can also create your own password encoders as services and you can even @@ -263,11 +258,6 @@ encoding algorithm. Also, each algorithm defines different config options: Using the Sodium Password Encoder ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 4.3 - - The ``SodiumPasswordEncoder`` was introduced in Symfony 4.3. In previous - Symfony versions it was called ``Argon2iPasswordEncoder``. - It uses the `Argon2 key derivation function`_ and it's the encoder recommended by Symfony. Argon2 support was introduced in PHP 7.2, but if you use an earlier PHP version, you can install the `libsodium`_ PHP extension. diff --git a/reference/constraints/Bic.rst b/reference/constraints/Bic.rst index e12aacbaf63..c65d3223110 100644 --- a/reference/constraints/Bic.rst +++ b/reference/constraints/Bic.rst @@ -92,10 +92,6 @@ iban **type**: ``string`` **default**: ``null`` -.. versionadded:: 4.3 - - The ``iban`` option was introduced in Symfony 4.3. - An IBAN value to validate that the BIC is associated with it. ibanMessage @@ -103,10 +99,6 @@ ibanMessage **type**: ``string`` **default**: ``This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}.`` -.. versionadded:: 4.3 - - The ``ibanMessage`` option was introduced in Symfony 4.3. - The default message supplied when the value does not pass the combined BIC/IBAN check. ibanPropertyPath @@ -114,10 +106,6 @@ ibanPropertyPath **type**: ``string`` **default**: ``null`` -.. versionadded:: 4.3 - - The ``ibanPropertyPath`` option was introduced in Symfony 4.3. - It defines the object property whose value stores the IBAN used to check the BIC with. For example, if you want to compare the ``$bic`` property of some object diff --git a/reference/constraints/CardScheme.rst b/reference/constraints/CardScheme.rst index 6362d9932ee..6adfe62d893 100644 --- a/reference/constraints/CardScheme.rst +++ b/reference/constraints/CardScheme.rst @@ -138,10 +138,6 @@ Valid values are: * ``UATP`` * ``VISA`` -.. versionadded:: 4.3 - - The ``UATP`` and ``MIR`` number schemes were introduced in Symfony 4.3. - For more information about the used schemes, see `Wikipedia: Issuer identification number (IIN)`_. diff --git a/reference/constraints/Choice.rst b/reference/constraints/Choice.rst index 7cc8ae3ac1f..25feac3506e 100644 --- a/reference/constraints/Choice.rst +++ b/reference/constraints/Choice.rst @@ -322,10 +322,6 @@ Parameter Description ``{{ value }}`` The current (invalid) value ================= ============================================================ -.. versionadded:: 4.3 - - The ``{{ choices }}`` parameter was introduced in Symfony 4.3. - message ~~~~~~~ @@ -370,10 +366,6 @@ Parameter Description ``{{ value }}`` The current (invalid) value ================= ============================================================ -.. versionadded:: 4.3 - - The ``{{ choices }}`` parameter was introduced in Symfony 4.3. - multiple ~~~~~~~~ diff --git a/reference/constraints/Negative.rst b/reference/constraints/Negative.rst index c90a1fb1c98..76d97a5bf98 100644 --- a/reference/constraints/Negative.rst +++ b/reference/constraints/Negative.rst @@ -1,10 +1,6 @@ Negative ======== -.. versionadded:: 4.3 - - The ``Negative`` constraint was introduced in Symfony 4.3. - Validates that a value is a negative number. Zero is neither positive nor negative, so you must use :doc:`/reference/constraints/NegativeOrZero` if you want to allow zero as value. diff --git a/reference/constraints/NegativeOrZero.rst b/reference/constraints/NegativeOrZero.rst index 15d0926bc5d..66ae33e914b 100644 --- a/reference/constraints/NegativeOrZero.rst +++ b/reference/constraints/NegativeOrZero.rst @@ -1,10 +1,6 @@ NegativeOrZero ============== -.. versionadded:: 4.3 - - The ``NegativeOrZero`` constraint was introduced in Symfony 4.3. - Validates that a value is a negative number or equal to zero. If you don't want to allow zero as value, use :doc:`/reference/constraints/Negative` instead. diff --git a/reference/constraints/NotBlank.rst b/reference/constraints/NotBlank.rst index 83b2713d225..0eed60ef9df 100644 --- a/reference/constraints/NotBlank.rst +++ b/reference/constraints/NotBlank.rst @@ -90,10 +90,6 @@ allowNull If set to ``true``, ``null`` values are considered valid and won't trigger a constraint violation. -.. versionadded:: 4.3 - - The ``allowNull`` option was introduced in Symfony 4.3. - .. include:: /reference/constraints/_groups-option.rst.inc message diff --git a/reference/constraints/NotCompromisedPassword.rst b/reference/constraints/NotCompromisedPassword.rst index ffa9fe99d8d..6d2cb52f1aa 100644 --- a/reference/constraints/NotCompromisedPassword.rst +++ b/reference/constraints/NotCompromisedPassword.rst @@ -1,10 +1,6 @@ NotCompromisedPassword ====================== -.. versionadded:: 4.3 - - The ``NotCompromisedPassword`` constraint was introduced in Symfony 4.3. - Validates that the given password has not been compromised by checking that it is not included in any of the public data breaches tracked by `haveibeenpwned.com`_. diff --git a/reference/constraints/Positive.rst b/reference/constraints/Positive.rst index b9bef408fa5..5800347ba8e 100644 --- a/reference/constraints/Positive.rst +++ b/reference/constraints/Positive.rst @@ -1,10 +1,6 @@ Positive ======== -.. versionadded:: 4.3 - - The ``Positive`` constraint was introduced in Symfony 4.3. - Validates that a value is a positive number. Zero is neither positive nor negative, so you must use :doc:`/reference/constraints/PositiveOrZero` if you want to allow zero as value. diff --git a/reference/constraints/PositiveOrZero.rst b/reference/constraints/PositiveOrZero.rst index 70196a6b9fa..4b526026fd9 100644 --- a/reference/constraints/PositiveOrZero.rst +++ b/reference/constraints/PositiveOrZero.rst @@ -1,10 +1,6 @@ PositiveOrZero ============== -.. versionadded:: 4.3 - - The ``PositiveOrZero`` constraint was introduced in Symfony 4.3. - Validates that a value is a positive number or equal to zero. If you don't want to allow zero as value, use :doc:`/reference/constraints/Positive` instead. diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index c195a5d46f6..032df5f07f2 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -1,10 +1,6 @@ Timezone ======== -.. versionadded:: 4.3 - - The ``Timezone`` constraint was introduced in Symfony 4.3. - Validates that a value is a valid timezone identifier (e.g. ``Europe/Paris``). ========== ====================================================================== diff --git a/reference/forms/types/button.rst b/reference/forms/types/button.rst index d009b80235e..9978c5fb50a 100644 --- a/reference/forms/types/button.rst +++ b/reference/forms/types/button.rst @@ -59,10 +59,6 @@ label_translation_parameters **type**: ``array`` **default**: ``[]`` -.. versionadded:: 4.3 - - The ``label_translation_parameters`` option was introduced in Symfony 4.3. - The content of the `label`_ option is translated before displaying it, so it can contain :ref:`translation placeholders `. This option defines the values used to replace those placeholders. diff --git a/reference/forms/types/number.rst b/reference/forms/types/number.rst index c5db2c7b092..c3306269c18 100644 --- a/reference/forms/types/number.rst +++ b/reference/forms/types/number.rst @@ -53,10 +53,6 @@ html5 **type**: ``boolean`` **default**: ``false`` -.. versionadded:: 4.3 - - The ``html5`` option was introduced in Symfony 4.3. - If set to ``true``, the HTML input will be rendered as a native HTML5 ``type="number"`` form. @@ -65,10 +61,6 @@ input **type**: ``string`` **default**: ``number`` -.. versionadded:: 4.3 - - The ``input`` option was introduced in Symfony 4.3. - The format of the input data - i.e. the format that the number is stored on your underlying object. Valid values are ``number`` and ``string``. Setting this option to ``string`` can be useful if the underlying data is a string diff --git a/reference/forms/types/options/attr_translation_parameters.rst.inc b/reference/forms/types/options/attr_translation_parameters.rst.inc index 98326ba4abe..71187cd75c5 100644 --- a/reference/forms/types/options/attr_translation_parameters.rst.inc +++ b/reference/forms/types/options/attr_translation_parameters.rst.inc @@ -3,10 +3,6 @@ attr_translation_parameters **type**: ``array`` **default**: ``[]`` -.. versionadded:: 4.3 - - The ``attr_translation_parameters`` option was introduced in Symfony 4.3. - The content of the ``title`` and ``placeholder`` values defined in the `attr`_ option is translated before displaying it, so it can contain :ref:`translation placeholders `. This diff --git a/reference/forms/types/options/block_prefix.rst.inc b/reference/forms/types/options/block_prefix.rst.inc index f02feb0ce70..db012bc3c42 100644 --- a/reference/forms/types/options/block_prefix.rst.inc +++ b/reference/forms/types/options/block_prefix.rst.inc @@ -4,10 +4,6 @@ block_prefix **type**: ``string`` or ``null`` **default**: ``null`` (see :ref:`Knowing which block to customize `) -.. versionadded:: 4.3 - - The ``block_prefix`` option was introduced in Symfony 4.3. - Allows you to add a custom block prefix and override the block name used to render the form type. Useful for example if you have multiple instances of the same form and you need to personalize the rendering diff --git a/reference/forms/types/options/date_input_format_description.rst.inc b/reference/forms/types/options/date_input_format_description.rst.inc index 4cd9b353e31..e411cd12d70 100644 --- a/reference/forms/types/options/date_input_format_description.rst.inc +++ b/reference/forms/types/options/date_input_format_description.rst.inc @@ -1,7 +1,3 @@ -.. versionadded:: 4.3 - - The ``input_format`` option was introduced in Symfony 4.3. - If the ``input`` option is set to ``string``, this option specifies the format of the date. This must be a valid `PHP date format`_. diff --git a/reference/forms/types/options/help_translation_parameters.rst.inc b/reference/forms/types/options/help_translation_parameters.rst.inc index 4294fb2b185..2b69e237941 100644 --- a/reference/forms/types/options/help_translation_parameters.rst.inc +++ b/reference/forms/types/options/help_translation_parameters.rst.inc @@ -3,10 +3,6 @@ help_translation_parameters **type**: ``array`` **default**: ``[]`` -.. versionadded:: 4.3 - - The ``help_translation_parameters`` option was introduced in Symfony 4.3. - The content of the `help`_ option is translated before displaying it, so it can contain :ref:`translation placeholders `. This option defines the values used to replace those placeholders. diff --git a/reference/forms/types/options/label_translation_parameters.rst.inc b/reference/forms/types/options/label_translation_parameters.rst.inc index 443c6706f14..815b780553e 100644 --- a/reference/forms/types/options/label_translation_parameters.rst.inc +++ b/reference/forms/types/options/label_translation_parameters.rst.inc @@ -3,10 +3,6 @@ label_translation_parameters **type**: ``array`` **default**: ``[]`` -.. versionadded:: 4.3 - - The ``label_translation_parameters`` option was introduced in Symfony 4.3. - The content of the `label`_ option is translated before displaying it, so it can contain :ref:`translation placeholders `. This option defines the values used to replace those placeholders. diff --git a/reference/forms/types/percent.rst b/reference/forms/types/percent.rst index b90d57de2b5..5bf742da1b0 100644 --- a/reference/forms/types/percent.rst +++ b/reference/forms/types/percent.rst @@ -61,10 +61,6 @@ symbol **type**: ``boolean`` or ``string`` **default**: ``true`` -.. versionadded:: 4.3 - - The ``symbol`` option was introduced in Symfony 4.3. - By default, fields are rendered with a percentage sign ``%`` after the input. Setting the value to ``false`` will not display the percentage sign. Setting the value to a ``string`` (e.g. ``‱``), will show that string instead of the default diff --git a/reference/forms/types/time.rst b/reference/forms/types/time.rst index 0636f34fb5b..1aea97ad89d 100644 --- a/reference/forms/types/time.rst +++ b/reference/forms/types/time.rst @@ -137,10 +137,6 @@ input_format **type**: ``string`` **default**: ``H:i:s`` -.. versionadded:: 4.3 - - The ``input_format`` option was introduced in Symfony 4.3. - If the ``input`` option is set to ``string``, this option specifies the format of the time. This must be a valid `PHP time format`_. diff --git a/reference/forms/types/timezone.rst b/reference/forms/types/timezone.rst index 96e61de0d34..a76c5ae2363 100644 --- a/reference/forms/types/timezone.rst +++ b/reference/forms/types/timezone.rst @@ -69,10 +69,6 @@ on your underlying object. Valid values are: * ``intltimezone`` (an ``\IntlTimeZone`` object) * ``string`` (e.g. ``America/New_York``) -.. versionadded:: 4.3 - - The ``intltimezone`` input type was introduced in Symfony 4.3. - regions ~~~~~~~ diff --git a/routing.rst b/routing.rst index ec05ef50071..e4a3e3b51aa 100644 --- a/routing.rst +++ b/routing.rst @@ -535,11 +535,6 @@ If you want to always include some default value in the generated URL (for example to force the generation of ``/blog/1`` instead of ``/blog`` in the previous example) add the ``!`` character before the placeholder name: ``/blog/{!page}`` -.. versionadded:: 4.3 - - The feature to force the inclusion of default values in generated URLs was - introduced in Symfony 4.3. - As it happens with requirements, default values can also be inlined in each placeholder using the syntax ``{placeholder_name?default_value}``. This feature is compatible with inlined requirements, so you can inline both in a single @@ -845,10 +840,6 @@ You can also use special attributes to configure them (except ``_fragment``): These attributes can also be used for route imports. -.. versionadded:: 4.3 - - The special attributes were introduced in Symfony 4.3. - .. _routing-trailing-slash-redirection: Redirecting URLs with Trailing Slashes diff --git a/routing/custom_route_loader.rst b/routing/custom_route_loader.rst index 748558a3c78..3fac4e5af09 100644 --- a/routing/custom_route_loader.rst +++ b/routing/custom_route_loader.rst @@ -137,11 +137,6 @@ extend or implement any special class, but the called method must return a If your service is invokable, you don't need to precise the method to use. -.. versionadded:: 4.3 - - The support of the ``__invoke()`` method to create invokable route loader - services was introduced in Symfony 4.3. - Creating a custom Loader ------------------------ diff --git a/routing/debug.rst b/routing/debug.rst index f83331488cc..7de6d8bb930 100644 --- a/routing/debug.rst +++ b/routing/debug.rst @@ -65,7 +65,3 @@ which route is associated with the given URL: | | utf8: true | | Condition | context.getMethod() in ['GET', 'HEAD', 'POST'] | +--------------+---------------------------------------------------------+ - -.. versionadded:: 4.3 - - The ``Condition`` was added to the router debug output in Symfony 4.3. diff --git a/routing/service_container_parameters.rst b/routing/service_container_parameters.rst index 58c26ad7da2..ba73b35d63c 100644 --- a/routing/service_container_parameters.rst +++ b/routing/service_container_parameters.rst @@ -75,10 +75,6 @@ inside your routing configuration: ; }; -.. versionadded:: 4.3 - - Support for boolean container parameters in routes was introduced in Symfony 4.3. - You can now control and set the ``app.locales`` parameter somewhere in your container: diff --git a/security/csrf.rst b/security/csrf.rst index 620df0f887e..45520e4bf2b 100644 --- a/security/csrf.rst +++ b/security/csrf.rst @@ -113,10 +113,6 @@ You can also customize the rendering of the CSRF form field creating a custom the field (e.g. define ``{% block csrf_token_widget %} ... {% endblock %}`` to customize the entire form field contents). -.. versionadded:: 4.3 - - The ``csrf_token`` form field prefix was introduced in Symfony 4.3. - CSRF Protection in Login Forms ------------------------------ diff --git a/security/impersonating_user.rst b/security/impersonating_user.rst index 1a6e47365b4..365cd86fc6b 100644 --- a/security/impersonating_user.rst +++ b/security/impersonating_user.rst @@ -98,10 +98,6 @@ to show a link to exit impersonation: Finding the Original User ------------------------- -.. versionadded:: 4.3 - - The ``SwitchUserToken`` class was introduced in Symfony 4.3. - In some cases, you may need to get the object that represents the impersonator user rather than the impersonated user. When a user is impersonated the token stored in the token storage will be a ``SwitchUserToken`` instance. Use the @@ -234,10 +230,6 @@ Create the voter class:: } } -.. versionadded:: 4.3 - - The ``getRoleNames()`` method was introduced in Symfony 4.3. - To enable the new voter in the app, register it as a service and :doc:`tag it ` with the ``security.voter`` tag. If you're using the diff --git a/service_container/alias_private.rst b/service_container/alias_private.rst index 307056e4056..828e6d71284 100644 --- a/service_container/alias_private.rst +++ b/service_container/alias_private.rst @@ -205,10 +205,6 @@ The message is actually a message template, which replaces occurrences of the ``%alias_id%`` placeholder by the service alias id. You **must** have at least one occurrence of the ``%alias_id%`` placeholder in your template. -.. versionadded:: 4.3 - - The ``deprecated`` option for service aliases was introduced in Symfony 4.3. - Anonymous Services ------------------ diff --git a/service_container/autowiring.rst b/service_container/autowiring.rst index 26c8f55ed0d..c02f2ef08dc 100644 --- a/service_container/autowiring.rst +++ b/service_container/autowiring.rst @@ -480,10 +480,6 @@ If the argument is named ``$shoutyTransformer``, But, you can also manually wire any *other* service by specifying the argument under the arguments key. -.. versionadded:: 4.2 - - Named autowiring aliases have been introduced in Symfony 4.2. - Fixing Non-Autowireable Arguments --------------------------------- diff --git a/service_container/configurators.rst b/service_container/configurators.rst index def35e3fef9..7f61c671747 100644 --- a/service_container/configurators.rst +++ b/service_container/configurators.rst @@ -197,10 +197,6 @@ the service id and the method name: .. _configurators-invokable: -.. versionadded:: 4.3 - - Invokable configurators for services were introduced in Symfony 4.3. - Services can be configured via invokable configurators (replacing the ``configure()`` method with ``__invoke()``) by omitting the method name, just as routes can reference :ref:`invokable controllers `. diff --git a/service_container/factories.rst b/service_container/factories.rst index 3fc4a979336..e698b4eea95 100644 --- a/service_container/factories.rst +++ b/service_container/factories.rst @@ -175,10 +175,6 @@ factory service can be used as a callback:: } } -.. versionadded:: 4.3 - - Invokable factories for services were introduced in Symfony 4.3. - Services can be created and configured via invokable factories by omitting the method name, just as routes can reference :ref:`invokable controllers `. diff --git a/templating/hinclude.rst b/templating/hinclude.rst index ee5047cc124..7814e0130f6 100644 --- a/templating/hinclude.rst +++ b/templating/hinclude.rst @@ -97,12 +97,6 @@ in your application configuration: ], ]); -.. versionadded:: 4.3 - - The ``framework.fragments.hinclude_default_template`` option was introduced - in Symfony 4.3. In previous Symfony versions it was called - ``framework.templating.hinclude_default_template``. - You can define default templates per ``render()`` function (which will override any global default template that is defined): diff --git a/testing.rst b/testing.rst index 3163d57721a..d79871c4432 100644 --- a/testing.rst +++ b/testing.rst @@ -215,10 +215,6 @@ its existence, attributes, text, etc. The ``assertSelectorTextContains`` method is not a native PHPUnit assertion and is available thanks to the ``WebTestCase`` class. -.. versionadded:: 4.3 - - The ``WebTestCase`` assertions were introduced in Symfony 4.3 - .. seealso:: Using native PHPUnit methods, the same assertion would look like this:: diff --git a/testing/functional_tests_assertions.rst b/testing/functional_tests_assertions.rst index 63482dd046b..812b35ef94f 100644 --- a/testing/functional_tests_assertions.rst +++ b/testing/functional_tests_assertions.rst @@ -4,11 +4,6 @@ Functional Test specific Assertions =================================== -.. versionadded:: 4.3 - - The shortcut methods for assertions using ``WebTestCase`` were introduced - in Symfony 4.3. - When doing functional tests, sometimes you need to make complex assertions in order to check whether the ``Request``, the ``Response`` or the ``Crawler`` contain the expected information to make your test succeed. diff --git a/translation.rst b/translation.rst index 3b1692c3755..c095793038b 100644 --- a/translation.rst +++ b/translation.rst @@ -368,11 +368,6 @@ The ``translation:update`` command looks for missing translations in: * Any PHP file/class that injects or :doc:`autowires ` the ``translator`` service and makes calls to the ``trans()`` function. -.. versionadded:: 4.3 - - The extraction of missing translation strings from PHP files was introduced - in Symfony 4.3. - .. note:: If you want to see the missing translation strings without actually updating diff --git a/workflow.rst b/workflow.rst index e2a542c8683..37017b6ba66 100644 --- a/workflow.rst +++ b/workflow.rst @@ -318,7 +318,7 @@ workflow leaves a place:: class WorkflowLogger implements EventSubscriberInterface { private $logger; - + public function __construct(LoggerInterface $logger) { $this->logger = $logger; @@ -502,10 +502,6 @@ place:: } } -.. versionadded:: 4.1 - - The transition blockers were introduced in Symfony 4.1. - Usage in Twig ------------- @@ -559,10 +555,6 @@ The following example shows these functions in action: Storing Metadata ---------------- -.. versionadded:: 4.1 - - The feature to store metadata in workflows was introduced in Symfony 4.1. - In case you need it, you can store arbitrary metadata in workflows, their places, and their transitions using the ``metadata`` option. This metadata can be as simple as the title of the workflow or as complex as your own application From 6bf9ef5d835f9e870e2ca92173aa9b8d853a5895 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 30 May 2019 12:46:10 +0200 Subject: [PATCH 0003/1519] Removed the deprecation message --- components/messenger.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/components/messenger.rst b/components/messenger.rst index 13fb4093dac..9fb4dc6eec8 100644 --- a/components/messenger.rst +++ b/components/messenger.rst @@ -78,11 +78,6 @@ are configured for you: #. :class:`Symfony\\Component\\Messenger\\Middleware\\SendMessageMiddleware` (enables asynchronous processing, logs the processing of your messages if you pass a logger) #. :class:`Symfony\\Component\\Messenger\\Middleware\\HandleMessageMiddleware` (calls the registered handler(s)) -.. deprecated:: 4.3 - - The ``LoggingMiddleware`` is deprecated since Symfony 4.3 and will be - removed in 5.0. Pass a logger to ``SendMessageMiddleware`` instead. - Example:: use App\Message\MyMessage; From ce64ac294bf9ec5479fa0b9a1976b5b24d7433b4 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 29 May 2019 13:15:44 +0200 Subject: [PATCH 0004/1519] Removed deprecated contents --- bundles/configuration.rst | 4 - components/config/definition.rst | 4 - components/serializer.rst | 24 +- configuration/environment_variables.rst | 8 +- configuration/environments.rst | 10 +- console/commands_as_services.rst | 7 - controller/argument_value_resolver.rst | 11 - controller/upload_file.rst | 8 +- form/create_custom_field_type.rst | 6 - reference/configuration/framework.rst | 138 ------ reference/configuration/kernel.rst | 30 +- reference/configuration/security.rst | 31 +- reference/configuration/twig.rst | 7 - reference/constraints/Email.rst | 40 +- reference/constraints/Locale.rst | 20 +- reference/constraints/Url.rst | 167 +------ reference/dic_tags.rst | 48 -- reference/forms/types/date.rst | 5 - reference/forms/types/datetime.rst | 20 - reference/forms/types/integer.rst | 17 +- reference/forms/types/timezone.rst | 13 +- templating/PHP.rst | 572 +----------------------- translation.rst | 11 +- 23 files changed, 33 insertions(+), 1168 deletions(-) diff --git a/bundles/configuration.rst b/bundles/configuration.rst index 88e038e833f..256679e9bc1 100644 --- a/bundles/configuration.rst +++ b/bundles/configuration.rst @@ -197,10 +197,6 @@ The ``Configuration`` class to handle the sample configuration looks like:: } } -.. deprecated:: 4.2 - - Not passing the root node name to ``TreeBuilder`` was deprecated in Symfony 4.2. - .. seealso:: The ``Configuration`` class can be much more complicated than shown here, diff --git a/components/config/definition.rst b/components/config/definition.rst index e76b55da1a0..27f9da0688d 100644 --- a/components/config/definition.rst +++ b/components/config/definition.rst @@ -68,10 +68,6 @@ implements the :class:`Symfony\\Component\\Config\\Definition\\ConfigurationInte } } -.. deprecated:: 4.2 - - Not passing the root node name to ``TreeBuilder`` was deprecated in Symfony 4.2. - Adding Node Definitions to the Tree ----------------------------------- diff --git a/components/serializer.rst b/components/serializer.rst index 1c6359033bc..f7fe691835c 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -434,12 +434,6 @@ key in the ``context`` parameter of the desired serializer method:: $serializer = new Serializer([$normalizer], [$encoder]); $serializer->serialize($person, 'json', ['ignored_attributes' => ['age']]); // Output: {"name":"foo"} -.. deprecated:: 4.2 - - The :method:`Symfony\\Component\\Serializer\\Normalizer\\AbstractNormalizer::setIgnoredAttributes` - method that was used as an alternative to the ``ignored_attributes`` option - was deprecated in Symfony 4.2. - .. _component-serializer-converting-property-names-when-serializing-and-deserializing: Converting Property Names when Serializing and Deserializing @@ -639,12 +633,6 @@ and ``remove``. Using Callbacks to Serialize Properties with Object Instances ------------------------------------------------------------- -.. deprecated:: 4.2 - - The :method:`Symfony\\Component\\Serializer\\Normalizer\\AbstractNormalizer::setCallbacks` - method is deprecated since Symfony 4.2. Use the ``callbacks`` - key of the context instead. - When serializing, you can set a callback to format a specific object property:: use App\Model\Person; @@ -664,7 +652,7 @@ When serializing, you can set a callback to format a specific object property:: 'createdAt' => $callback, ], ]; - + $normalizer = new GetSetMethodNormalizer(null, null, null, null, null, $defaultContext); $serializer = new Serializer([$normalizer], [$encoder]); @@ -800,10 +788,6 @@ The ``CsvEncoder`` encodes to and decodes from CSV. You can pass the context key ``as_collection`` in order to have the results always as a collection. -.. deprecated:: 4.2 - - Relying on the default value ``false`` is deprecated since Symfony 4.2. - The ``XmlEncoder`` ~~~~~~~~~~~~~~~~~~ @@ -951,12 +935,6 @@ The ``setCircularReferenceLimit()`` method of this normalizer sets the number of times it will serialize the same object before considering it a circular reference. Its default value is ``1``. -.. deprecated:: 4.2 - - The :method:`Symfony\\Component\\Serializer\\Normalizer\\AbstractNormalizer::setCircularReferenceHandler` - method is deprecated since Symfony 4.2. Use the ``circular_reference_handler`` - key of the context instead. - Instead of throwing an exception, circular references can also be handled by custom callables. This is especially useful when serializing entities having unique identifiers:: diff --git a/configuration/environment_variables.rst b/configuration/environment_variables.rst index e9e258c4aa1..a6ed20db35b 100644 --- a/configuration/environment_variables.rst +++ b/configuration/environment_variables.rst @@ -97,11 +97,11 @@ whenever the corresponding environment variable is *not* found: // config/services.php $container->setParameter('env(DATABASE_HOST)', 'localhost'); -.. deprecated:: 4.3 +.. note:: - Passing non-string values as default values for environment variables is - deprecated since Symfony 4.3. Use :ref:`environment variable processors ` - if you need to transform those string default values into other data types. + The default values of environment variables must be strings, but you can use + :ref:`environment variable processors ` to transform + them into other data types. .. _configuration-env-var-in-prod: diff --git a/configuration/environments.rst b/configuration/environments.rst index 0efac1eb899..863dc63739b 100644 --- a/configuration/environments.rst +++ b/configuration/environments.rst @@ -173,13 +173,9 @@ Selecting the Environment for Console Commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ By default, Symfony commands are executed in whatever environment is defined by -the ``APP_ENV`` environment variable (usually configured in your ``.env`` file). -In previous Symfony versions you could use the ``--env`` (and ``--no-debug``) -command line options to override this value. However, those options were -deprecated in Symfony 4.2. - -Use the ``APP_ENV`` (and ``APP_DEBUG``) environment variables to change the -environment and the debug behavior of the commands: +the ``APP_ENV`` environment variable and with the debug mode set by ``APP_DEBUG``. +It's recommended to configure these env vars in your ``.env`` file, but you can +also override them for some specific commands as follows: .. code-block:: terminal diff --git a/console/commands_as_services.rst b/console/commands_as_services.rst index 09e02c8c9a7..c2bed37d404 100644 --- a/console/commands_as_services.rst +++ b/console/commands_as_services.rst @@ -60,13 +60,6 @@ works! You can call the ``app:sunshine`` command and start logging. work (e.g. making database queries), as that code will be run, even if you're using the console to execute a different command. -.. note:: - - In previous Symfony versions, you could make the command class extend from - :class:`Symfony\\Bundle\\FrameworkBundle\\Command\\ContainerAwareCommand` to - get services via ``$this->getContainer()->get('SERVICE_ID')``. This is - deprecated in Symfony 4.2 and it won't work in future Symfony versions. - .. _console-command-service-lazy-loading: Lazy Loading diff --git a/controller/argument_value_resolver.rst b/controller/argument_value_resolver.rst index 0ac95a12ad6..669fa6e7282 100644 --- a/controller/argument_value_resolver.rst +++ b/controller/argument_value_resolver.rst @@ -53,17 +53,6 @@ In addition, some components and official bundles provide other value resolvers: the controller can be accessed by anonymous users. It requires installing the :doc:`Security component `. -:class:`Symfony\\Bundle\\SecurityBundle\\SecurityUserValueResolver` - Injects the object that represents the current logged in user if type-hinted - with ``UserInterface``. Default value can be set to ``null`` in case - the controller can be accessed by anonymous users. It requires installing - the `SecurityBundle`_. - -.. deprecated:: 4.1 - - The ``SecurityUserValueResolver`` was deprecated in Symfony 4.1 in favor of - :class:`Symfony\\Component\\Security\\Http\\Controller\\UserValueResolver`. - ``Psr7ServerRequestResolver`` Injects a `PSR-7`_ compliant version of the current request if type-hinted with ``RequestInterface``, ``MessageInterface`` or ``ServerRequestInterface``. diff --git a/controller/upload_file.rst b/controller/upload_file.rst index ab38a3025ec..982669dadce 100644 --- a/controller/upload_file.rst +++ b/controller/upload_file.rst @@ -182,19 +182,13 @@ There are some important things to consider in the code of the above controller: users. This also applies to the files uploaded by your visitors. The ``UploadedFile`` class provides methods to get the original file extension (:method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::getExtension`), - the original file size (:method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::getClientSize`) + the original file size (:method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::getSize`) and the original file name (:method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::getClientOriginalName`). However, they are considered *not safe* because a malicious user could tamper that information. That's why it's always better to generate a unique name and use the :method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::guessExtension` method to let Symfony guess the right extension according to the file MIME type; -.. deprecated:: 4.1 - - The :method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::getClientSize` - method was deprecated in Symfony 4.1 and will be removed in Symfony 5.0. - Use ``getSize()`` instead. - You can use the following code to link to the PDF brochure of a product: .. code-block:: html+twig diff --git a/form/create_custom_field_type.rst b/form/create_custom_field_type.rst index 2f0d59e3446..b6dce419fc9 100644 --- a/form/create_custom_field_type.rst +++ b/form/create_custom_field_type.rst @@ -164,12 +164,6 @@ link for details), create a ``shipping_widget`` block to handle this: {% endspaceless %} {% endblock %} -.. note:: - - Symfony 4.2 deprecated calling ``FormRenderer::searchAndRenderBlock`` for - fields that have already been rendered. That's why the previous example - includes the ``... if not child.rendered`` statement. - .. tip:: You can further customize the template used to render each children of the diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index d0e76c61b00..b9918d3f649 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -187,16 +187,6 @@ Configuration * `storage_id`_ * `use_cookies`_ -* `templating`_ - - * :ref:`cache ` - * `engines`_ - * :ref:`form ` - - * `resources`_ - - * `loaders`_ - * `test`_ * `translator`_ @@ -224,7 +214,6 @@ Configuration * `endpoint`_ * `static_method`_ - * `strict_email`_ * `translation_domain`_ * `workflows`_ @@ -1847,119 +1836,6 @@ package: If you request an asset that is *not found* in the ``manifest.json`` file, the original - *unmodified* - asset path will be returned. -templating -~~~~~~~~~~ - -.. _reference-templating-form: - -form -.... - -resources -""""""""" - -**type**: ``string[]`` **default**: ``['FrameworkBundle:Form']`` - -.. deprecated:: 4.3 - - The integration of the Templating component in FrameworkBundle has been - deprecated since version 4.3 and will be removed in 5.0. Form theming with - PHP templates will no longer be supported and you'll need to use Twig instead. - -A list of all resources for form theming in PHP. This setting is not required -if you're :ref:`using the Twig format for your themes `. - -Assume you have custom global form themes in ``templates/form_themes/``, you can -configure this like: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/framework.yaml - framework: - templating: - form: - resources: - - 'form_themes' - - .. code-block:: xml - - - - - - - - - form_themes - - - - - - .. code-block:: php - - // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'templating' => [ - 'form' => [ - 'resources' => [ - 'form_themes', - ], - ], - ], - ]); - -.. note:: - - The default form templates from ``FrameworkBundle:Form`` will always - be included in the form resources. - -.. seealso:: - - See :ref:`forms-theming-global` for more information. - -.. _reference-templating-cache: - -cache -..... - -**type**: ``string`` - -The path to the cache directory for templates. When this is not set, caching -is disabled. - -.. note:: - - When using Twig templating, the caching is already handled by the - TwigBundle and doesn't need to be enabled for the FrameworkBundle. - -engines -....... - -**type**: ``string[]`` / ``string`` **required** - -The Templating Engine to use. This can either be a string (when only one -engine is configured) or an array of engines. - -At least one engine is required. - -loaders -....... - -**type**: ``string[]`` - -An array (or a string when configuring just one loader) of service ids for -templating loaders. Templating loaders are used to find and load templates -from a resource (e.g. a filesystem or database). Templating loaders must -implement :class:`Symfony\\Component\\Templating\\Loader\\LoaderInterface`. - translator ~~~~~~~~~~ @@ -2155,20 +2031,6 @@ metadata of the class. You can define an array of strings with the names of several methods. In that case, all of them will be called in that order to load the metadata. -strict_email -............ - -**type**: ``Boolean`` **default**: ``false`` - -.. deprecated:: 4.1 - - The ``strict_email`` option was deprecated in Symfony 4.1. Use the new - ``email_validation_mode`` option instead. - -If this option is enabled, the `egulias/email-validator`_ library will be -used by the :doc:`/reference/constraints/Email` constraint validator. Otherwise, -the validator uses a simple regular expression to validate email addresses. - email_validation_mode ..................... diff --git a/reference/configuration/kernel.rst b/reference/configuration/kernel.rst index 2081ba5ffad..35006dd4591 100644 --- a/reference/configuration/kernel.rst +++ b/reference/configuration/kernel.rst @@ -12,12 +12,17 @@ Configuration ------------- * `Charset`_ -* `Kernel Name`_ * `Project Directory`_ * `Cache Directory`_ * `Log Directory`_ * `Container Build Time`_ +In previous Symfony versions there was another configuration option to define +the "kernel name", which is only important when +:doc:`using applications with multiple kernels `. +If you need a unique ID for your kernels use the ``kernel.container_class`` +parameter or the ``Kernel::getContainerClass()`` method. + .. _configuration-kernel-charset: Charset @@ -44,29 +49,6 @@ charset:: } } -Kernel Name -~~~~~~~~~~~ - -**type**: ``string`` **default**: ``src`` (i.e. the directory name holding -the kernel class) - -.. deprecated:: 4.2 - - The ``kernel.name`` parameter and the ``Kernel::getName()`` method were - deprecated in Symfony 4.2. If you need a unique ID for your kernels use the - ``kernel.container_class`` parameter or the ``Kernel::getContainerClass()`` method. - -The name of the kernel isn't usually directly important - it's used in the -generation of cache files - and you probably will only change it when -:doc:`using applications with multiple kernels `. - -This value is exposed via the ``kernel.name`` configuration parameter and the -:method:`Symfony\\Component\\HttpKernel\\Kernel::getName` method. - -To change this setting, override the ``getName()`` method. Alternatively, move -your kernel into a different directory. For example, if you moved the kernel -into a ``foo/`` directory (instead of ``src/``), the kernel name will be ``foo``. - .. _configuration-kernel-project-directory: Project Directory diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index 5fba7fc34ad..266d5cf7a66 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -145,7 +145,6 @@ encoding algorithm. Also, each algorithm defines different config options: algorithm: 'sodium' memory_cost: 16384 # Amount in KiB. (16384 = 16 MiB) time_cost: 2 # Number of iterations - threads: 4 # Number of parallel threads # PBKDF2 encoder using SHA512 hashing with default options App\Entity\User: 'sha512' @@ -183,14 +182,12 @@ encoding algorithm. Also, each algorithm defines different config options: + time_cost: number of iterations --> @@ -230,7 +227,6 @@ encoding algorithm. Also, each algorithm defines different config options: 'algorithm' => 'sodium', 'memory_cost' => 16384, // Amount in KiB. (16384 = 16 MiB) 'time_cost' => 2, // Number of iterations - 'threads' => 4, // Number of parallel threads ], // PBKDF2 encoder using SHA512 hashing with default options @@ -240,12 +236,6 @@ encoding algorithm. Also, each algorithm defines different config options: ], ]); -.. deprecated:: 4.3 - - The ``threads`` configuration option was deprecated in Symfony 4.3. No - alternative is provided because starting from Symfony 5.0 this value will be - hardcoded to ``1`` (one thread). - .. versionadded:: 4.3 The ``sodium`` algorithm was introduced in Symfony 4.3. In previous Symfony @@ -540,25 +530,6 @@ The ``invalidate_session`` option allows to redefine this behavior. Set this option to ``false`` in every firewall and the user will only be logged out from the current firewall and not the other ones. -logout_on_user_change -~~~~~~~~~~~~~~~~~~~~~ - -**type**: ``boolean`` **default**: ``true`` - -.. deprecated:: 4.1 - - The ``logout_on_user_change`` option was deprecated in Symfony 4.1. - -If ``false`` this option makes Symfony to not trigger a logout when the user has -changed. Doing that is deprecated, so this option should set to ``true`` or -unset to avoid getting deprecation messages. - -The user is considered to have changed when the user class implements -:class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface` and the -``isEqualTo()`` method returns ``false``. Also, when any of the properties -required by the :class:`Symfony\\Component\\Security\\Core\\User\\UserInterface` -(like the username, password or salt) changes. - success_handler ~~~~~~~~~~~~~~~ diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst index 1e801569f28..f8c6fe08597 100644 --- a/reference/configuration/twig.rst +++ b/reference/configuration/twig.rst @@ -317,19 +317,12 @@ paths **type**: ``array`` **default**: ``null`` -.. deprecated:: 4.2 - - Using the ``src/Resources/views/`` directory to store templates was - deprecated in Symfony 4.2. Use instead the directory defined in the - ``default_path`` option (which is ``templates/`` by default). - This option defines the directories where Symfony will look for Twig templates in addition to the default locations. Symfony looks for the templates in the following order: #. The directories defined in this option; #. The ``Resources/views/`` directories of the bundles used in the application; -#. The ``src/Resources/views/`` directory of the application; #. The directory defined in the ``default_path`` option. The values of the ``paths`` option are defined as ``key: value`` pairs where the diff --git a/reference/constraints/Email.rst b/reference/constraints/Email.rst index 8b68f59bea2..7621a379f72 100644 --- a/reference/constraints/Email.rst +++ b/reference/constraints/Email.rst @@ -6,9 +6,7 @@ cast to a string before being validated. ========== =================================================================== Applies to :ref:`property or method ` -Options - `checkHost`_ - - `checkMX`_ - - `groups`_ +Options - `groups`_ - `message`_ - `mode`_ - `normalizer`_ @@ -33,8 +31,7 @@ Basic Usage { /** * @Assert\Email( - * message = "The email '{{ value }}' is not a valid email.", - * checkMX = true + * message = "The email '{{ value }}' is not a valid email." * ) */ protected $email; @@ -48,7 +45,6 @@ Basic Usage email: - Email: message: The email "{{ value }}" is not a valid email. - checkMX: true .. code-block:: xml @@ -62,7 +58,6 @@ Basic Usage - @@ -82,7 +77,6 @@ Basic Usage { $metadata->addPropertyConstraint('email', new Assert\Email([ 'message' => 'The email "{{ value }}" is not a valid email.', - 'checkMX' => true, ])); } } @@ -92,36 +86,6 @@ Basic Usage Options ------- -checkHost -~~~~~~~~~ - -**type**: ``boolean`` **default**: ``false`` - -.. deprecated:: 4.2 - - This option was deprecated in Symfony 4.2. - -If true, then the :phpfunction:`checkdnsrr` PHP function will be used to -check the validity of the MX *or* the A *or* the AAAA record of the host -of the given email. - -checkMX -~~~~~~~ - -**type**: ``boolean`` **default**: ``false`` - -.. deprecated:: 4.2 - - This option was deprecated in Symfony 4.2. - -If true, then the :phpfunction:`checkdnsrr` PHP function will be used to -check the validity of the MX record of the host of the given email. - -.. caution:: - - This option is not reliable because it depends on the network conditions - and some valid servers refuse to respond to those requests. - .. include:: /reference/constraints/_groups-option.rst.inc message diff --git a/reference/constraints/Locale.rst b/reference/constraints/Locale.rst index 8887124a153..04edab5a197 100644 --- a/reference/constraints/Locale.rst +++ b/reference/constraints/Locale.rst @@ -8,10 +8,13 @@ the two letter `ISO 639-1`_ *language* code (e.g. ``fr``), or the language code followed by an underscore (``_``) and the `ISO 3166-1 alpha-2`_ *country* code (e.g. ``fr_FR`` for French/France). +The given locale values are *canonicalized* before validating them to avoid +issues with wrong uppercase/lowercase values and to remove unneeded elements +(e.g. ``FR-fr.utf8`` will be validated as ``fr_FR``). + ========== =================================================================== Applies to :ref:`property or method ` -Options - `canonicalize`_ - - `groups`_ +Options - `groups`_ - `message`_ - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Locale` @@ -89,19 +92,6 @@ Basic Usage Options ------- -canonicalize -~~~~~~~~~~~~ - -**type**: ``boolean`` **default**: ``false`` - -.. deprecated:: 4.1 - - Using this option with value ``false`` was deprecated in Symfony 4.1 and it - will throw an exception in Symfony 5.0. Use ``true`` instead. - -If ``true``, the :phpmethod:`Locale::canonicalize` method will be applied before checking -the validity of the given locale (e.g. ``FR-fr.utf8`` is transformed into ``fr_FR``). - .. include:: /reference/constraints/_groups-option.rst.inc message diff --git a/reference/constraints/Url.rst b/reference/constraints/Url.rst index 4c9885d0147..fdc58880797 100644 --- a/reference/constraints/Url.rst +++ b/reference/constraints/Url.rst @@ -5,9 +5,7 @@ Validates that a value is a valid URL string. ========== =================================================================== Applies to :ref:`property or method ` -Options - `checkDNS`_ - - `dnsMessage`_ - - `groups`_ +Options - `groups`_ - `message`_ - `normalizer`_ - `payload`_ @@ -76,170 +74,15 @@ Basic Usage } } +This constraint doesn't check that the host of the given URL really exists, +because the information of the DNS records is not reliable. Use the +:phpfunction:`checkdnsrr` PHP function if you still want to check that. + .. include:: /reference/constraints/_empty-values-are-valid.rst.inc Options ------- -checkDNS -~~~~~~~~ - -**type**: ``boolean`` **default**: ``false`` - -.. deprecated:: 4.1 - - This option was deprecated in Symfony 4.1 and will be removed in Symfony 5.0, - because checking the DNS records is not reliable enough to validate the - existence of the host. Use the :phpfunction:`checkdnsrr` PHP function if you - still want to use this kind of validation. - -By default, this constraint just validates the syntax of the given URL. If you -also need to check whether the associated host exists, set the ``checkDNS`` -option to the value of any of the ``CHECK_DNS_TYPE_*`` constants in the -:class:`Symfony\\Component\\Validator\\Constraints\\Url` class: - -.. configuration-block:: - - .. code-block:: php-annotations - - // src/Entity/Author.php - namespace App\Entity; - - use Symfony\Component\Validator\Constraints as Assert; - - class Author - { - /** - * @Assert\Url( - * checkDNS = "ANY" - * ) - */ - protected $bioUrl; - } - - .. code-block:: yaml - - # config/validator/validation.yaml - App\Entity\Author: - properties: - bioUrl: - - Url: { checkDNS: 'ANY' } - - .. code-block:: xml - - - - - - - - - - - - - - - .. code-block:: php - - // src/Entity/Author.php - namespace App\Entity; - - use Symfony\Component\Validator\Constraints as Assert; - use Symfony\Component\Validator\Mapping\ClassMetadata; - - class Author - { - public static function loadValidatorMetadata(ClassMetadata $metadata) - { - $metadata->addPropertyConstraint('bioUrl', new Assert\Url([ - 'checkDNS' => Assert\Url::CHECK_DNS_TYPE_ANY, - ])); - } - } - -This option uses the :phpfunction:`checkdnsrr` PHP function to check the validity -of the DNS record corresponding to the host associated with the given URL. - -dnsMessage -~~~~~~~~~~ - -**type**: ``string`` **default**: ``The host could not be resolved.`` - -.. deprecated:: 4.1 - - This option was deprecated in Symfony 4.1 and will be removed in Symfony 5.0, - because checking the DNS records is not reliable enough to validate the - existence of the host. Use the :phpfunction:`checkdnsrr` PHP function if you - still want to use this kind of validation. - -This message is shown when the ``checkDNS`` option is set to ``true`` and the -DNS check failed. - -.. configuration-block:: - - .. code-block:: php-annotations - - // src/Entity/Author.php - namespace App\Entity; - - use Symfony\Component\Validator\Constraints as Assert; - - class Author - { - /** - * @Assert\Url( - * dnsMessage = "The host '{{ value }}' could not be resolved." - * ) - */ - protected $bioUrl; - } - - .. code-block:: yaml - - # config/validator/validation.yaml - App\Entity\Author: - properties: - bioUrl: - - Url: { dnsMessage: 'The host "{{ value }}" could not be resolved.' } - - .. code-block:: xml - - - - - - - - - - - - - - - .. code-block:: php - - // src/Entity/Author.php - namespace App\Entity; - - use Symfony\Component\Validator\Constraints as Assert; - use Symfony\Component\Validator\Mapping\ClassMetadata; - - class Author - { - public static function loadValidatorMetadata(ClassMetadata $metadata) - { - $metadata->addPropertyConstraint('bioUrl', new Assert\Url([ - 'dnsMessage' => 'The host "{{ value }}" could not be resolved.', - ])); - } - } - .. include:: /reference/constraints/_groups-option.rst.inc message diff --git a/reference/dic_tags.rst b/reference/dic_tags.rst index eec54e6d680..f894070aa18 100644 --- a/reference/dic_tags.rst +++ b/reference/dic_tags.rst @@ -36,7 +36,6 @@ Tag Name Usage `serializer.encoder`_ Register a new encoder in the ``serializer`` service `serializer.normalizer`_ Register a new normalizer in the ``serializer`` service `swiftmailer.default.plugin`_ Register a custom SwiftMailer Plugin -`templating.helper`_ Make your service available in PHP templates `translation.loader`_ Register a custom service that loads translations `translation.extractor`_ Register a custom service that extracts translation messages from a file `translation.dumper`_ Register a custom service that dumps translation messages @@ -789,53 +788,6 @@ For more information on plugins, see `SwiftMailer's Plugin Documentation`_. Several SwiftMailer plugins are core to Symfony and can be activated via different configuration. For details, see :doc:`/reference/configuration/swiftmailer`. -templating.helper ------------------ - -**Purpose**: Make your service available in PHP templates - -.. deprecated:: 4.3 - - The ``templating.helper`` tag is deprecated since version 4.3 and will be - removed in 5.0; use Twig instead. - -To enable a custom template helper, add it as a regular service in one -of your configuration, tag it with ``templating.helper`` and define an -``alias`` attribute (the helper will be accessible via this alias in the -templates): - -.. configuration-block:: - - .. code-block:: yaml - - services: - App\Templating\AppHelper: - tags: - - { name: templating.helper, alias: alias_name } - - .. code-block:: xml - - - - - - - - - - - - .. code-block:: php - - use App\Templating\AppHelper; - - $container->register(AppHelper::class) - ->addTag('templating.helper', ['alias' => 'alias_name']) - ; - .. _dic-tags-translation-loader: translation.loader diff --git a/reference/forms/types/date.rst b/reference/forms/types/date.rst index 6e2be4140e3..30f9cb3d2ec 100644 --- a/reference/forms/types/date.rst +++ b/reference/forms/types/date.rst @@ -171,11 +171,6 @@ values for the year, month and day fields:: .. include:: /reference/forms/types/options/date_format.rst.inc -.. deprecated:: 4.3 - - Using the ``format`` option when the ``html5`` option is enabled is deprecated - since Symfony 4.3. - .. include:: /reference/forms/types/options/html5.rst.inc .. _form-reference-date-input: diff --git a/reference/forms/types/datetime.rst b/reference/forms/types/datetime.rst index 99fb9aa1722..18290532afa 100644 --- a/reference/forms/types/datetime.rst +++ b/reference/forms/types/datetime.rst @@ -74,11 +74,6 @@ Defines the ``format`` option that will be passed down to the date field. See the :ref:`DateType's format option ` for more details. -.. deprecated:: 4.3 - - Using the ``date_format`` option when the form is rendered as an HTML 5 - datetime input is deprecated since Symfony 4.3. - date_label ~~~~~~~~~~ @@ -98,11 +93,6 @@ date_widget .. include:: /reference/forms/types/options/date_widget_description.rst.inc -.. deprecated:: 4.3 - - Using the ``date_widget`` option when the ``widget`` option is set to - ``single_text`` is deprecated since Symfony 4.3. - .. include:: /reference/forms/types/options/days.rst.inc placeholder @@ -144,11 +134,6 @@ used by the HTML5 ``datetime-local`` field. Keeping the default value will cause the field to be rendered as an ``input`` field with ``type="datetime-local"``. For more information on valid formats, see `Date/Time Format Syntax`_. -.. deprecated:: 4.3 - - Using the ``format`` option when the ``html5`` option is enabled is deprecated - since Symfony 4.3. - .. include:: /reference/forms/types/options/hours.rst.inc .. include:: /reference/forms/types/options/html5.rst.inc @@ -208,11 +193,6 @@ time_widget Defines the ``widget`` option for the :doc:`TimeType `. -.. deprecated:: 4.3 - - Using the ``time_widget`` option when the ``widget`` option is set to - ``single_text`` is deprecated since Symfony 4.3. - .. include:: /reference/forms/types/options/view_timezone.rst.inc widget diff --git a/reference/forms/types/integer.rst b/reference/forms/types/integer.rst index 0ce32ddbadc..18ef5a0d0da 100644 --- a/reference/forms/types/integer.rst +++ b/reference/forms/types/integer.rst @@ -20,7 +20,7 @@ integers. By default, all non-integer values (e.g. 6.78) will round down | | - `rounding_mode`_ | +-------------+-----------------------------------------------------------------------+ | Overridden | - `compound`_ | -| options | - `scale`_ | +| options | | +-------------+-----------------------------------------------------------------------+ | Inherited | - `data`_ | | options | - `disabled`_ | @@ -84,21 +84,6 @@ Overridden Options .. include:: /reference/forms/types/options/compound_type.rst.inc -scale -~~~~~ - -**type**: ``integer`` **default**: ``0`` - -.. deprecated:: 4.2 - - The ``scale`` option is deprecated since Symfony 4.2 and will be removed - in 5.0. - -This specifies how many decimals will be allowed until the field rounds the -submitted value (via ``rounding_mode``). This option inherits from -:doc:`number ` type and is overriden to ``0`` for -``IntegerType``. - Inherited Options ----------------- diff --git a/reference/forms/types/timezone.rst b/reference/forms/types/timezone.rst index 96e61de0d34..0e8694db324 100644 --- a/reference/forms/types/timezone.rst +++ b/reference/forms/types/timezone.rst @@ -18,7 +18,7 @@ manually, but then you should just use the ``ChoiceType`` directly. | Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | +-------------+------------------------------------------------------------------------+ | Options | - `input`_ | -| | - `regions`_ | +| | | +-------------+------------------------------------------------------------------------+ | Overridden | - `choices`_ | | options | | @@ -73,17 +73,6 @@ on your underlying object. Valid values are: The ``intltimezone`` input type was introduced in Symfony 4.3. -regions -~~~~~~~ - -**type**: ``int`` **default**: ``\DateTimeZone::ALL`` - -.. deprecated:: 4.2 - - This option was deprecated in Symfony 4.2. - -The available regions in the timezone choice list. For example: ``DateTimeZone::AMERICA | DateTimeZone::EUROPE`` - Overridden Options ------------------ diff --git a/templating/PHP.rst b/templating/PHP.rst index 1ea3196c4cb..15d4354bf07 100644 --- a/templating/PHP.rst +++ b/templating/PHP.rst @@ -4,575 +4,7 @@ How to Use PHP instead of Twig for Templates ============================================ -.. deprecated:: 4.3 - - The integration of the Templating component in FrameworkBundle has been - deprecated since version 4.3 and will be removed in 5.0. PHP templates will - no longer be supported and you'll need to use Twig instead. - -Symfony defaults to Twig for its template engine, but you can still use -plain PHP code if you want. Both templating engines are supported equally in -Symfony. Symfony adds some nice features on top of PHP to make writing -templates with PHP more powerful. - -.. tip:: - - If you choose *not* use Twig and you disable it, you'll need to implement - your own exception handler via the ``kernel.exception`` event. - -Rendering PHP Templates ------------------------ - -.. deprecated:: 4.3 - - The integration of the Templating component in FrameworkBundle has been - deprecated since version 4.3 and will be removed in 5.0. PHP templates will - no longer be supported and you'll need to use Twig instead. - -If you want to use the PHP templating engine, first install the templating component: - -.. code-block:: terminal - - $ composer require symfony/templating - -Next, enable the php engine: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/framework.yaml - framework: - # ... - templating: - engines: ['twig', 'php'] - - .. code-block:: xml - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/framework.php - $container->loadFromExtension('framework', [ - // ... - 'templating' => [ - 'engines' => ['twig', 'php'], - ], - ]); - -You can now render a PHP template instead of a Twig one by using the ``.php`` -extension in the template name instead of ``.twig``. The controller below -renders the ``index.html.php`` template:: - - // src/Controller/HelloController.php - - // ... - public function index($name) - { - // template is stored in src/Resources/views/hello/index.html.php - return $this->render('hello/index.html.php', [ - 'name' => $name - ]); - } - .. caution:: - Enabling the ``php`` and ``twig`` template engines simultaneously is - allowed, but it will produce an undesirable side effect in your application: - the ``@`` notation for Twig namespaces will no longer be supported for the - ``render()`` method:: - - public function index() - { - // ... - - // namespaced templates will no longer work in controllers - $this->render('@SomeNamespace/hello/index.html.twig'); - - // you must use the traditional template notation - $this->render('hello/index.html.twig'); - } - - .. code-block:: twig - - {# inside a Twig template, namespaced templates work as expected #} - {{ include('@SomeNamespace/hello/index.html.twig') }} - - {# traditional template notation will also work #} - {{ include('hello/index.html.twig') }} - -.. index:: - single: Templating; Layout - single: Layout - -Decorating Templates --------------------- - -More often than not, templates in a project share common elements, like the -well-known header and footer. In Symfony, this problem is thought about -differently: a template can be decorated by another one. - -The ``index.html.php`` template is decorated by ``layout.html.php``, thanks to -the ``extend()`` call: - -.. code-block:: html+php - - - extend('layout.html.php') ?> - - Hello ! - -Now, have a look at the ``layout.html.php`` file: - -.. code-block:: html+php - - - extend('base.html.php') ?> - -

Hello Application

- - output('_content') ?> - -The layout is itself decorated by another one (``base.html.php``). Symfony -supports multiple decoration levels: a layout can itself be decorated by -another one: - -.. code-block:: html+php - - - - - - - <?php $view['slots']->output('title', 'Hello Application') ?> - - - output('_content') ?> - - - -For both layouts, the ``$view['slots']->output('_content')`` expression is -replaced by the content of the child template, ``index.html.php`` and -``layout.html.php`` respectively (more on slots in the next section). - -As you can see, Symfony provides methods on a mysterious ``$view`` object. In -a template, the ``$view`` variable is always available and refers to a special -object that provides a bunch of methods that makes the template engine tick. - -.. index:: - single: Templating; Slot - single: Slot - -Working with Slots ------------------- - -A slot is a snippet of code, defined in a template, and reusable in any layout -decorating the template. In the ``index.html.php`` template, define a -``title`` slot: - -.. code-block:: html+php - - - extend('layout.html.php') ?> - - set('title', 'Hello World Application') ?> - - Hello ! - -The base layout already has the code to output the title in the header: - -.. code-block:: html+php - - - - - <?php $view['slots']->output('title', 'Hello Application') ?> - - -The ``output()`` method inserts the content of a slot and optionally takes a -default value if the slot is not defined. And ``_content`` is just a special -slot that contains the rendered child template. - -For large slots, there is also an extended syntax: - -.. code-block:: html+php - - start('title') ?> - Some large amount of HTML - stop() ?> - -.. index:: - single: Templating; Include - -Including other Templates -------------------------- - -The best way to share a snippet of template code is to define a template that -can then be included into other templates. - -Create a ``hello.html.php`` template: - -.. code-block:: html+php - - - Hello ! - -And change the ``index.html.php`` template to include it: - -.. code-block:: html+php - - - extend('layout.html.php') ?> - - render('hello/hello.html.php', ['name' => $name]) ?> - -The ``render()`` method evaluates and returns the content of another template -(this is the exact same method as the one used in the controller). - -.. index:: - single: Templating; Embedding pages - -Embedding other Controllers ---------------------------- - -And what if you want to embed the result of another controller in a template? -That's very useful when working with Ajax, or when the embedded template needs -some variable not available in the main template. - -If you create a ``fancy`` action, and want to include it into the -``index.html.php`` template, use the following code: - -.. code-block:: html+php - - - render( - new \Symfony\Component\HttpKernel\Controller\ControllerReference( - 'App\Controller\HelloController::fancy', - [ - 'name' => $name, - 'color' => 'green', - ] - ) - ) ?> - -But where is the ``$view['actions']`` array element defined? Like -``$view['slots']``, it's called a template helper, and the next section tells -you more about those. - -.. index:: - single: Templating; Helpers - -Using Template Helpers ----------------------- - -The Symfony templating system can be extended via helpers. Helpers are -PHP objects that provide features useful in a template context. ``actions`` and -``slots`` are two of the built-in Symfony helpers. - -Creating Links between Pages -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Speaking of web applications, creating links between pages is a must. Instead -of hardcoding URLs in templates, the ``router`` helper knows how to generate -URLs based on the routing configuration. That way, all your URLs can be -updated by changing the configuration: - -.. code-block:: html+php - -
- Greet Thomas! - - -The ``path()`` method takes the route name and an array of parameters as -arguments. The route name is the main key under which routes are referenced -and the parameters are the values of the placeholders defined in the route -pattern: - -.. code-block:: yaml - - # config/routes.yaml - hello: - path: /hello/{name} - controller: App\Controller\HelloController::index - -Using Assets: Images, JavaScripts and Stylesheets -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -What would the Internet be without images, JavaScripts, and stylesheets? -Symfony provides the ``assets`` tag to deal with them: - -.. code-block:: html+php - - - - - -The ``assets`` helper's main purpose is to make your application more -portable. Thanks to this helper, you can move the application root directory -anywhere under your web root directory without changing anything in your -template's code. - -Profiling Templates -~~~~~~~~~~~~~~~~~~~ - -By using the ``stopwatch`` helper, you are able to time parts of your template -and display it on the timeline of the WebProfilerBundle:: - - start('foo') ?> - ... things that get timed - stop('foo') ?> - -.. tip:: - - If you use the same name more than once in your template, the times are - grouped on the same line in the timeline. - -Output Escaping ---------------- - -When using PHP templates, escape variables whenever they are displayed to the -user:: - - escape($var) ?> - -By default, the ``escape()`` method assumes that the variable is outputted -within an HTML context. The second argument lets you change the context. For -instance, to output something in a JavaScript script, use the ``js`` context:: - - escape($var, 'js') ?> - -Form Theming in PHP -------------------- - -When using PHP as a templating engine, the only method to customize a fragment -is to create a new template file - this is similar to the second method used by -Twig. - -The template file must be named after the fragment. You must create a ``integer_widget.html.php`` -file in order to customize the ``integer_widget`` fragment. - -.. code-block:: html+php - - -
- block( - $form, - 'form_widget_simple', - ['type' => isset($type) ? $type : "number"] - ) ?> -
- -Now that you've created the customized form template, you need to tell Symfony -to use it. Inside the template where you're actually rendering your form, -tell Symfony to use the theme via the ``setTheme()`` helper method:: - - setTheme($form, [':form']) ?> - - widget($form['age']) ?> - -When the ``form.age`` widget is rendered, Symfony will use the customized -``integer_widget.html.php`` template and the ``input`` tag will be wrapped in -the ``div`` element. - -If you want to apply a theme to a specific child form, pass it to the ``setTheme()`` -method:: - - setTheme($form['child'], ':form') ?> - -.. note:: - - The ``:form`` syntax is based on the functional names for templates: - ``Bundle:Directory``. As the form directory lives in the - ``templates/`` directory, the ``Bundle`` part is empty, resulting - in ``:form``. - -Making Application-wide Customizations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you'd like a certain form customization to be global to your application, -you can accomplish this by making the form customizations in an external -template and then importing it inside your application configuration. - -By using the following configuration, any customized form fragments inside the -``templates/form`` folder will be used globally when a -form is rendered. - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/framework.yaml - framework: - templating: - form: - resources: - - 'App:Form' - # ... - - .. code-block:: xml - - - - - - - - - App:Form - - - - - - - .. code-block:: php - - // config/packages/framework.php - // PHP - $container->loadFromExtension('framework', [ - 'templating' => [ - 'form' => [ - 'resources' => [ - 'App:Form', - ], - ], - ], - - // ... - ]); - -By default, the PHP engine uses a *div* layout when rendering forms. Some people, -however, may prefer to render forms in a *table* layout. Use the ``FrameworkBundle:FormTable`` -resource to use such a layout: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/framework.yaml - framework: - templating: - form: - resources: - - 'FrameworkBundle:FormTable' - - .. code-block:: xml - - - - - - - - - FrameworkBundle:FormTable - - - - - - - .. code-block:: php - - // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'templating' => [ - 'form' => [ - 'resources' => [ - 'FrameworkBundle:FormTable', - ], - ], - ], - - // ... - ]); - -If you only want to make the change in one template, add the following line to -your template file rather than adding the template as a resource: - -.. code-block:: html+php - - setTheme($form, ['FrameworkBundle:FormTable']) ?> - -Note that the ``$form`` variable in the above code is the form view variable -that you passed to your template. - -Adding a "Required" Asterisk to Field Labels -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you want to denote all of your required fields with a required asterisk -(``*``), you can do this by customizing the ``form_label`` fragment. - -When using PHP as a templating engine you have to copy the content from the -original template: - -.. code-block:: html+php - - - - - - - humanize($name); } ?> - - - - - * - - -Adding "help" Messages -~~~~~~~~~~~~~~~~~~~~~~ - -You can also customize your form widgets to have an optional "help" message. - -When using PHP as a templating engine you have to copy the content from the -original template: - -.. code-block:: html+php - - - - - value="escape($value) ?>" - block($form, 'widget_attributes') ?> - /> - - - - escape($help) ?> - - -.. _`@Template`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/view + Starting from Symfony 5.0, PHP templates are no longer supported. Use + :doc:`Twig ` instead to create your templates. diff --git a/translation.rst b/translation.rst index 3b1692c3755..c33ae20d8ca 100644 --- a/translation.rst +++ b/translation.rst @@ -386,19 +386,10 @@ Translation Resource/File Names and Locations Symfony looks for message files (i.e. translations) in the following default locations: * the ``translations/`` directory (at the root of the project); - -* the ``src/Resources//translations/`` directory; - * the ``Resources/translations/`` directory inside of any bundle. -.. deprecated:: 4.2 - - Using the ``src/Resources//translations/`` directory to store - translations was deprecated in Symfony 4.2. Use instead the directory - defined in the ``default_path`` option (which is ``translations/`` by default). - The locations are listed here with the highest priority first. That is, you can -override the translation messages of a bundle in any of the top two directories. +override the translation messages of a bundle in the first directory. The override mechanism works at a key level: only the overridden keys need to be listed in a higher priority message file. When a key is not found From f990c8188b523233063c96a8040ea39de1854a5c Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 6 Jun 2019 09:54:01 +0200 Subject: [PATCH 0005/1519] Remove old versionadded directives --- components/http_client.rst | 4 ---- components/phpunit_bridge.rst | 4 ---- doctrine.rst | 4 ---- mailer.rst | 5 ----- translation.rst | 6 ------ 5 files changed, 23 deletions(-) diff --git a/components/http_client.rst b/components/http_client.rst index f2312c38cb2..040512fafdf 100644 --- a/components/http_client.rst +++ b/components/http_client.rst @@ -389,10 +389,6 @@ Responses can be canceled at any moment before they are completed using the $response->cancel(); } -.. versionadded:: 4.4 - - The ``cancel()`` method was introduced in Symfony 4.4. - Dealing with Network Timeouts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index a27914a300a..77c5b4fd165 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -295,10 +295,6 @@ class autoloading time. This can be disabled with the ``debug-class-loader`` opt -.. versionadded:: 4.2 - - The ``DebugClassLoader`` integration was introduced in Symfony 4.2. - Write Assertions about Deprecations ----------------------------------- diff --git a/doctrine.rst b/doctrine.rst index 01b7682d7fe..c2368f39a1a 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -484,10 +484,6 @@ doesn't replace the validation configuration entirely. You still need to add some :doc:`validation constraints ` to ensure that data provided by the user is correct. -.. versionadded:: 4.3 - - The automatic validation has been added in Symfony 4.3. - Fetching Objects from the Database ---------------------------------- diff --git a/mailer.rst b/mailer.rst index 3b83c5454ec..857b813aa2d 100644 --- a/mailer.rst +++ b/mailer.rst @@ -1,11 +1,6 @@ Sending Emails with Mailer ========================== -.. versionadded:: 4.3 - - The Mailer component was added in Symfony 4.3 and is currently experimental. - The previous solution - Swift Mailer - is still valid: :doc:`Swift Mailer`. - Installation ------------ diff --git a/translation.rst b/translation.rst index d3a33ffc5c9..7efa0320b86 100644 --- a/translation.rst +++ b/translation.rst @@ -216,12 +216,6 @@ To manage these situations, Symfony follows the `ICU MessageFormat`_ syntax by using PHP's :phpclass:`MessageFormatter` class. Read more about this in :doc:`/translation/message_format`. -.. versionadded:: 4.2 - - Support for ICU MessageFormat was introduced in Symfony 4.2. Prior to this, - pluralization was managed by the - :method:`Symfony\\Component\\Translation\\Translator::transChoice` method. - Translations in Templates ------------------------- From ae30492e78826033642ab0c6d207ed4682b4ccc3 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 11 Jun 2019 09:41:19 +0200 Subject: [PATCH 0006/1519] Remove old deprecated directive --- service_container/tags.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/service_container/tags.rst b/service_container/tags.rst index de83480727d..bca6c8a902b 100644 --- a/service_container/tags.rst +++ b/service_container/tags.rst @@ -456,10 +456,6 @@ compiler pass just for that. In the following example, all services tagged with ``app.handler`` are passed as first constructor argument to the ``App\HandlerCollection`` service: -.. deprecated:: 4.4 - - ``tagged`` has been deprecated since version 4.4 and will be removed in 5.0. Use ``tagged_iterator`` instead. - .. configuration-block:: .. code-block:: yaml From b270e2d12102ae4be90b438f8fb37e57827aabc3 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 11 Jun 2019 10:05:58 +0200 Subject: [PATCH 0007/1519] Remove old versionadded directives --- reference/constraints/_comparison-propertypath-option.rst.inc | 4 ---- translation/message_format.rst | 4 ---- 2 files changed, 8 deletions(-) diff --git a/reference/constraints/_comparison-propertypath-option.rst.inc b/reference/constraints/_comparison-propertypath-option.rst.inc index 66932a0e983..9512d59310a 100644 --- a/reference/constraints/_comparison-propertypath-option.rst.inc +++ b/reference/constraints/_comparison-propertypath-option.rst.inc @@ -15,7 +15,3 @@ with regard to the ``$startDate`` property of the same object, use ``{{ compared_value_path }}`` placeholder. Although it's not intended to include it in the error messages displayed to end users, it's useful when using APIs for doing any mapping logic on client-side. - - .. versionadded:: 4.4 - - The ``{{ compared_value_path }}`` placeholder was introduced in Symfony 4.4. diff --git a/translation/message_format.rst b/translation/message_format.rst index a0761ec75f6..b4f1f2769cc 100644 --- a/translation/message_format.rst +++ b/translation/message_format.rst @@ -4,10 +4,6 @@ How to Translate Messages using the ICU MessageFormat ===================================================== -.. versionadded:: 4.2 - - Support for ICU MessageFormat was introduced in Symfony 4.2. - Messages (i.e. strings) in applications are almost never completely static. They contain variables or other complex logic like pluralization. In order to handle this, the Translator component supports the `ICU MessageFormat`_ syntax. From 8c33fce7e9453c7b51871ca404bbad1e83daaebe Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 17 Jun 2019 08:35:03 +0200 Subject: [PATCH 0008/1519] Remove old versionadded directives --- reference/constraints/Type.rst | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/reference/constraints/Type.rst b/reference/constraints/Type.rst index 319387416ec..81eed39be6c 100644 --- a/reference/constraints/Type.rst +++ b/reference/constraints/Type.rst @@ -126,11 +126,6 @@ function) and ``accessCode`` contains either only letters or only digits (using } } -.. versionadded:: 4.4 - - The feature to define multiple types in the ``type`` option was introduced - in Symfony 4.4. - Options ------- @@ -161,11 +156,6 @@ type **type**: ``string`` or ``array`` [:ref:`default option `] -.. versionadded:: 4.4 - - The feature to define multiple types in the ``type`` option was introduced - in Symfony 4.4. - This required option defines the type or collection of types allowed for the given value. Each type is defined as the fully qualified class name or one of the PHP datatypes as determined by PHP's ``is_*()`` functions. From 25b70a3f54ef6b7c1970e1d82e7392b3e21c7848 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 18 Jun 2019 11:07:43 +0200 Subject: [PATCH 0009/1519] Removed old deprecated directives. --- components/serializer.rst | 17 ------ configuration.rst | 5 -- .../front_controllers_and_kernel.rst | 5 -- reference/twig_reference.rst | 52 ------------------- translation/templates.rst | 40 ++------------ 5 files changed, 3 insertions(+), 116 deletions(-) diff --git a/components/serializer.rst b/components/serializer.rst index b000fd6ede9..b5604d8996c 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -660,11 +660,6 @@ When serializing, you can set a callback to format a specific object property:: $serializer->serialize($person, 'json'); // Output: {"name":"cordoval", "age": 34, "createdAt": "2014-03-22T09:43:12-0500"} -.. deprecated:: 4.2 - - The :method:`Symfony\\Component\\Serializer\\Normalizer\\AbstractNormalizer::setCallbacks` is deprecated since - Symfony 4.2, use the "callbacks" key of the context instead. - .. _component-serializer-normalizers: Normalizers @@ -951,12 +946,6 @@ having unique identifiers:: var_dump($serializer->serialize($org, 'json')); // {"name":"Les-Tilleuls.coop","members":[{"name":"K\u00e9vin", organization: "Les-Tilleuls.coop"}]} -.. deprecated:: 4.2 - - The :method:`Symfony\\Component\\Serializer\\Normalizer\\AbstractNormalizer::setCircularReferenceHandler` - method is deprecated since Symfony 4.2. Use the ``circular_reference_handler`` - key of the context instead. - Handling Serialization Depth ---------------------------- @@ -1108,12 +1097,6 @@ having unique identifiers:: ]; */ -.. deprecated:: 4.2 - - The :method:`Symfony\\Component\\Serializer\\Normalizer\\AbstractNormalizer::setMaxDepthHandler` - method is deprecated since Symfony 4.2. Use the ``max_depth_handler`` - key of the context instead. - Handling Arrays --------------- diff --git a/configuration.rst b/configuration.rst index 39369c0cab2..2bda9d4e394 100644 --- a/configuration.rst +++ b/configuration.rst @@ -325,11 +325,6 @@ can override it for commands by setting the ``APP_ENV`` value before running the # Ignore the .env file and run this command in production $ APP_ENV=prod php bin/console command_name -.. deprecated:: 4.2 - - In previous Symfony versions you could configure the environment with the - ``--env`` command option, which was deprecated in Symfony 4.2. - Creating a New Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/configuration/front_controllers_and_kernel.rst b/configuration/front_controllers_and_kernel.rst index 865a4077157..d986d7471b7 100644 --- a/configuration/front_controllers_and_kernel.rst +++ b/configuration/front_controllers_and_kernel.rst @@ -156,11 +156,6 @@ before running them: # Ignore the .env file and enable the debug mode for this command $ APP_DEBUG=1 php bin/console command_name -.. deprecated:: 4.2 - - In previous Symfony versions you could configure the debug mode with the - ``--no-debug`` command option, which was deprecated in Symfony 4.2. - Internally, the value of the debug mode becomes the ``kernel.debug`` parameter used inside the :doc:`service container `. If you look inside the application configuration file, you'll see the diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 083583727e7..6642d775911 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -356,33 +356,6 @@ trans Translates the text into the current language. More information in :ref:`Translation Filters `. -transchoice -~~~~~~~~~~~ - -.. deprecated:: 4.2 - - The ``transchoice`` filter is deprecated since Symfony 4.2 and will be - removed in 5.0. Use the :doc:`ICU MessageFormat ` with - the ``trans`` filter instead. - -.. code-block:: twig - - {{ message|transchoice(count, arguments = [], domain = null, locale = null) }} - -``message`` - **type**: ``string`` -``count`` - **type**: ``integer`` -``arguments`` *(optional)* - **type**: ``array`` **default**: ``[]`` -``domain`` *(optional)* - **type**: ``string`` **default**: ``null`` -``locale`` *(optional)* - **type**: ``string`` **default**: ``null`` - -Translates the text with pluralization support. More information in -:ref:`Translation Filters `. - yaml_encode ~~~~~~~~~~~ @@ -591,31 +564,6 @@ trans Renders the translation of the content. More information in :ref:`translation-tags`. -transchoice -~~~~~~~~~~~ - -.. deprecated:: 4.2 - - The ``transchoice`` tag is deprecated since Symfony 4.2 and will be - removed in 5.0. Use the :doc:`ICU MessageFormat ` with - the ``trans`` tag instead. - -.. code-block:: twig - - {% transchoice count with vars from domain into locale %}{% endtranschoice %} - -``count`` - **type**: ``integer`` -``vars`` *(optional)* - **type**: ``array`` **default**: ``[]`` -``domain`` *(optional)* - **type**: ``string`` **default**: ``null`` -``locale`` *(optional)* - **type**: ``string`` **default**: ``null`` - -Renders the translation of the content with pluralization support, more -information in :ref:`translation-tags`. - trans_default_domain ~~~~~~~~~~~~~~~~~~~~ diff --git a/translation/templates.rst b/translation/templates.rst index 903f1934d92..b820bfb0fba 100644 --- a/translation/templates.rst +++ b/translation/templates.rst @@ -9,27 +9,13 @@ Twig Templates Using Twig Tags ~~~~~~~~~~~~~~~ -Symfony provides specialized Twig tags (``trans`` and ``transchoice``) to -help with message translation of *static blocks of text*: +Symfony provides a specialized Twig tag ``trans`` to help with message +translation of *static blocks of text*: .. code-block:: twig {% trans %}Hello %name%{% endtrans %} - {% transchoice count %} - {0} There are no apples|{1} There is one apple|]1,Inf[ There are %count% apples - {% endtranschoice %} - -The ``transchoice`` tag automatically gets the ``%count%`` variable from -the current context and passes it to the translator. This mechanism only -works when you use a placeholder following the ``%var%`` pattern. - -.. deprecated:: 4.2 - - The ``transchoice`` tag is deprecated since Symfony 4.2 and will be - removed in 5.0. Use the :doc:`ICU MessageFormat ` with - the ``trans`` tag instead. - .. caution:: The ``%var%`` notation of placeholders is required when translating in @@ -48,34 +34,19 @@ You can also specify the message domain and pass some additional variables: {% trans with {'%name%': 'Fabien'} from 'app' into 'fr' %}Hello %name%{% endtrans %} - {% transchoice count with {'%name%': 'Fabien'} from 'app' %} - {0} %name%, there are no apples|{1} %name%, there is one apple|]1,Inf[ %name%, there are %count% apples - {% endtranschoice %} - .. _translation-filters: Using Twig Filters ~~~~~~~~~~~~~~~~~~ -The ``trans`` and ``transchoice`` filters can be used to translate *variable -texts* and complex expressions: +The ``trans`` filter can be used to translate *variable texts* and complex expressions: .. code-block:: twig {{ message|trans }} - {{ message|transchoice(5) }} - {{ message|trans({'%name%': 'Fabien'}, 'app') }} - {{ message|transchoice(5, {'%name%': 'Fabien'}, 'app') }} - -.. deprecated:: 4.2 - - The ``transchoice`` filter is deprecated since Symfony 4.2 and will be - removed in 5.0. Use the :doc:`ICU MessageFormat ` with - the ``trans`` filter instead. - .. tip:: Using the translation tags or filters have the same effect, but with @@ -116,8 +87,3 @@ The translator service is accessible in PHP templates through the trans('Symfony is great') ?> - transChoice( - '{0} There are no apples|{1} There is one apple|]1,Inf[ There are %count% apples', - 10, - ['%count%' => 10] - ) ?> From 426432a287d4ed5d683306a51d706982c1350253 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 3 Jul 2019 10:27:00 +0200 Subject: [PATCH 0010/1519] Removed versionadded directive --- mailer.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mailer.rst b/mailer.rst index 8e7563c8808..f40c1a44fc2 100644 --- a/mailer.rst +++ b/mailer.rst @@ -539,10 +539,6 @@ directly from GitHub and save it in ``assets/css``. Signing and Encrypting Messages ------------------------------- -.. versionadded:: 4.4 - - The option to sign and/or encrypt messages was introduced in Symfony 4.4. - It's possible to sign and/or encrypt email messages applying the `S/MIME`_ standard to increase their integrity/security. Both options can be combined (to encrypt a signed message and to sign an encrypted message) and they require to From bb315b24dd966e73775f21b1e53a3c0006f347e1 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 3 Jul 2019 11:16:43 +0200 Subject: [PATCH 0011/1519] Removed a versionadded directive --- configuration.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/configuration.rst b/configuration.rst index b2d9decda7d..4b54274b955 100644 --- a/configuration.rst +++ b/configuration.rst @@ -467,10 +467,6 @@ are defined and have the expected values: # run this command to show all the details for a specific env var: $ php bin/console debug:container --env-var=FOO -.. versionadded:: 4.3 - - The option to debug environment variables was introduced in Symfony 4.3. - .. _configuration-env-var-in-dev: .. _config-dot-env: From f6e79a3bd9d3a09bf2ea743e208ac074a446c193 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 4 Jul 2019 16:52:04 +0200 Subject: [PATCH 0012/1519] Reword --- reference/constraints/Length.rst | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/reference/constraints/Length.rst b/reference/constraints/Length.rst index fb56d8070d2..b1529efb1e0 100644 --- a/reference/constraints/Length.rst +++ b/reference/constraints/Length.rst @@ -113,16 +113,11 @@ Options allowEmptyString ~~~~~~~~~~~~~~~~ -**type**: ``boolean`` **default**: ``true`` +**type**: ``boolean`` **default**: ``false`` -.. versionadded:: 4.4 - - The ``allowEmptyString`` option was introduced in Symfony 4.4. - -When using the ``min`` option, it's mandatory to also define this option. If -set to ``true``, empty strings are considered valid (which is the same behavior -as previous Symfony versions). Set it to ``false`` to consider empty strings not -valid. +If set to ``true``, empty strings are considered valid (which is the same +behavior as previous Symfony versions). The default ``false`` value considers +empty strings not valid. charset ~~~~~~~ From 1c21c45c5ace28e4fe38f06c7585954f0bd6bda4 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 10 Jul 2019 12:33:16 +0200 Subject: [PATCH 0013/1519] Removed the deprecatedWebServerBundle --- _build/redirection_map | 1 + setup/built_in_web_server.rst | 127 ---------------------------------- 2 files changed, 1 insertion(+), 127 deletions(-) delete mode 100644 setup/built_in_web_server.rst diff --git a/_build/redirection_map b/_build/redirection_map index 7c4a5188b46..ef7effc1705 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -428,3 +428,4 @@ /profiler/storage /profiler /setup/composer /setup /security/security_checker /setup +/setup/built_in_web_server /setup/symfony_server diff --git a/setup/built_in_web_server.rst b/setup/built_in_web_server.rst deleted file mode 100644 index bb0f563f0ee..00000000000 --- a/setup/built_in_web_server.rst +++ /dev/null @@ -1,127 +0,0 @@ -.. index:: - single: Web Server; Built-in Web Server - -How to Use PHP's built-in Web Server -==================================== - -.. deprecated:: 4.4 - - This article explains how to use the WebServerBundle to run Symfony - applications on your local computer. However, that bundle is deprecated - since Symfony 4.4 and will be removed in Symfony 5.0. - - Instead of using WebServerBundle, the preferred way to run your Symfony - applications locally is to use the :doc:`Symfony Local Web Server `. - -The PHP CLI SAPI comes with a `built-in web server`_. It can be used to run your -PHP applications locally during development, for testing or for application -demonstrations. This way, you don't have to bother configuring a full-featured -web server such as :doc:`Apache or Nginx `. - -.. caution:: - - The built-in web server is meant to be run in a controlled environment. - It is not designed to be used on public networks. - -Symfony provides a web server built on top of this PHP server to simplify your -local setup. This server is distributed as a bundle, so you must first install -and enable the server bundle. - -Installing the Web Server Bundle --------------------------------- - -Move into your project directory and run this command: - -.. code-block:: terminal - - $ cd your-project/ - $ composer require --dev symfony/web-server-bundle - -Starting the Web Server ------------------------ - -To run a Symfony application using PHP's built-in web server, execute the -``server:start`` command: - -.. code-block:: terminal - - $ php bin/console server:start - -This starts the web server at ``localhost:8000`` in the background that serves -your Symfony application. - -By default, the web server listens on port 8000 on the loopback device. You -can change the socket passing an IP address and a port as a command-line argument: - -.. code-block:: terminal - - # passing a specific IP and port - $ php bin/console server:start 192.168.0.1:8080 - - # passing '*' as the IP means to use 0.0.0.0 (i.e. any local IP address) - $ php bin/console server:start *:8080 - -.. note:: - - You can use the ``server:status`` command to check if a web server is - listening: - - .. code-block:: terminal - - $ php bin/console server:status - -.. tip:: - - Some systems do not support the ``server:start`` command, in these cases - you can execute the ``server:run`` command. This command behaves slightly - different. Instead of starting the server in the background, it will block - the current terminal until you terminate it (this is usually done by - pressing Ctrl and C). - -.. sidebar:: Using the built-in Web Server from inside a Virtual Machine - - If you want to use the built-in web server from inside a virtual machine - and then load the site from a browser on your host machine, you'll need - to listen on the ``0.0.0.0:8000`` address (i.e. on all IP addresses that - are assigned to the virtual machine): - - .. code-block:: terminal - - $ php bin/console server:start 0.0.0.0:8000 - - .. caution:: - - You should **NEVER** listen to all interfaces on a computer that is - directly accessible from the Internet. The built-in web server is - not designed to be used on public networks. - -Command Options -~~~~~~~~~~~~~~~ - -The built-in web server expects a "router" script (read about the "router" -script on `php.net`_) as an argument. Symfony already passes such a router -script when the command is executed in the ``prod`` or ``dev`` environment. -Use the ``--router`` option to use your own router script: - -.. code-block:: terminal - - $ php bin/console server:start --router=config/my_router.php - -If your application's document root differs from the standard directory layout, -you have to pass the correct location using the ``--docroot`` option: - -.. code-block:: terminal - - $ php bin/console server:start --docroot=public_html - -Stopping the Server -------------------- - -When you finish your work, you can stop the web server with the following command: - -.. code-block:: terminal - - $ php bin/console server:stop - -.. _`built-in web server`: https://php.net/manual/en/features.commandline.webserver.php -.. _`php.net`: https://php.net/manual/en/features.commandline.webserver.php#example-411 From 28140816fd459739d85ad30f68b4bd7477092932 Mon Sep 17 00:00:00 2001 From: MarvinBlstrli <45764446+MarvinBlstrli@users.noreply.github.com> Date: Wed, 10 Jul 2019 13:55:02 +0200 Subject: [PATCH 0014/1519] fix data-widget-counter --- reference/forms/types/collection.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/forms/types/collection.rst b/reference/forms/types/collection.rst index ba61e8ca3c3..65e89202c94 100644 --- a/reference/forms/types/collection.rst +++ b/reference/forms/types/collection.rst @@ -182,7 +182,7 @@ And update the template as follows:

+

+ to_review Priority +

    +
  • + to_review: + {{ workflow_metadata(blog_post, 'priority', workflow_transition(blog_post, 'to_review')) }} +
  • +
+

Learn more ---------- From 44ca44fad09c1bc61f46c17541ade902897db14f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 26 Jun 2020 16:52:29 +0200 Subject: [PATCH 0352/1519] Don't use Twig as a public service --- templates.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/templates.rst b/templates.rst index 540e8e493fb..a3d3702f82c 100644 --- a/templates.rst +++ b/templates.rst @@ -565,12 +565,9 @@ Checking if a Template Exists Templates are loaded in the application using a `Twig template loader`_, which also provides a method to check for template existence. First, get the loader:: - // in a controller extending from AbstractController - $loader = $this->get('twig')->getLoader(); - - // in a service using autowiring use Twig\Environment; + // this code assumes that your service uses autowiring to inject dependencies public function __construct(Environment $twig) { $loader = $twig->getLoader(); From f20f59b8ca9cb235c7b9c987e6c775eff897d750 Mon Sep 17 00:00:00 2001 From: Fabien Salathe Date: Thu, 25 Jun 2020 22:02:39 +0200 Subject: [PATCH 0353/1519] Fix wrong RoutingConfigurator#import usage --- configuration/micro_kernel_trait.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst index 00f19d6a951..116c79502c1 100644 --- a/configuration/micro_kernel_trait.rst +++ b/configuration/micro_kernel_trait.rst @@ -174,12 +174,12 @@ hold the kernel. Now it looks like this:: { // import the WebProfilerRoutes, only if the bundle is enabled if (isset($this->bundles['WebProfilerBundle'])) { - $routes->import('@WebProfilerBundle/Resources/config/routing/wdt.xml', '/_wdt'); - $routes->import('@WebProfilerBundle/Resources/config/routing/profiler.xml', '/_profiler'); + $routes->import('@WebProfilerBundle/Resources/config/routing/wdt.xml')->prefix('/_wdt'); + $routes->import('@WebProfilerBundle/Resources/config/routing/profiler.xml')->prefix('/_profiler'); } // load the annotation routes - $routes->import(__DIR__.'/../src/Controller/', '/', 'annotation'); + $routes->import(__DIR__.'/../src/Controller/', 'annotation'); } // optional, to use the standard Symfony cache directory From 54ddd621d07289de7301011c920ebefa61d2966a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 27 Jun 2020 10:10:24 +0200 Subject: [PATCH 0354/1519] Tweak --- templates.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/templates.rst b/templates.rst index a3d3702f82c..40880d76f63 100644 --- a/templates.rst +++ b/templates.rst @@ -568,6 +568,7 @@ also provides a method to check for template existence. First, get the loader:: use Twig\Environment; // this code assumes that your service uses autowiring to inject dependencies + // otherwise, inject the service called 'twig' manually public function __construct(Environment $twig) { $loader = $twig->getLoader(); From bb10e94dc9bb494a938b150fa492e117b1b8204a Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sun, 28 Jun 2020 10:52:11 +0200 Subject: [PATCH 0355/1519] Fixed build error --- notifier.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notifier.rst b/notifier.rst index c90df3fa1a9..5e0b971827c 100644 --- a/notifier.rst +++ b/notifier.rst @@ -281,9 +281,9 @@ transport: - + + ]]> From a4f4c4f4c72a7940a427e0bf177ce6f849c8dff6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 29 Jun 2020 09:42:12 +0200 Subject: [PATCH 0356/1519] Readded a content removed by error --- messenger.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/messenger.rst b/messenger.rst index f0c3a93b12d..6033442a725 100644 --- a/messenger.rst +++ b/messenger.rst @@ -911,6 +911,9 @@ a table named ``messenger_messages``. The ability to automatically generate a migration for the ``messenger_messages`` table was introduced in Symfony 5.1 and DoctrineBundle 2.1. +Or, to create the table yourself, set the ``auto_setup`` option to ``false`` and +:ref:`generate a migration `. + The transport has a number of options: .. configuration-block:: From 55a1815f9fb88dc887b47e00b131f3862fc09e0e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 30 Jun 2020 09:48:21 +0200 Subject: [PATCH 0357/1519] Updated the version numbers --- setup.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.rst b/setup.rst index e16d5b4def1..60bee1afed4 100644 --- a/setup.rst +++ b/setup.rst @@ -50,10 +50,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_name --version=4.4 --full + $ symfony new my_project_name --version=5.0 --full # run this if you are building a microservice, console application or API - $ symfony new my_project_name --version=4.4 + $ symfony new my_project_name --version=5.0 The only difference between these two commands is the number of packages installed by default. The ``--full`` option installs all the packages that you @@ -65,10 +65,10 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/website-skeleton:"^4.4" my_project_name + $ composer create-project symfony/website-skeleton:"^5.0" my_project_name # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton:"^4.4" my_project_name + $ composer create-project symfony/skeleton:"^5.0" my_project_name No matter which command you run to create the Symfony application. All of them will create a new ``my_project_name/`` directory, download some dependencies From 63fd4fbbe98b66c77f8ef0945d8cddae028e9c53 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 30 Jun 2020 09:49:05 +0200 Subject: [PATCH 0358/1519] Updated the version numbers --- setup.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.rst b/setup.rst index 60bee1afed4..f18ac19e9dc 100644 --- a/setup.rst +++ b/setup.rst @@ -50,10 +50,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_name --version=5.0 --full + $ symfony new my_project_name --full # run this if you are building a microservice, console application or API - $ symfony new my_project_name --version=5.0 + $ symfony new my_project_name The only difference between these two commands is the number of packages installed by default. The ``--full`` option installs all the packages that you @@ -65,10 +65,10 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/website-skeleton:"^5.0" my_project_name + $ composer create-project symfony/website-skeleton my_project_name # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton:"^5.0" my_project_name + $ composer create-project symfony/skeleton my_project_name No matter which command you run to create the Symfony application. All of them will create a new ``my_project_name/`` directory, download some dependencies From bd6cbc830c650b36a59a7ccd8b5ab7c94c9c9819 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 30 Jun 2020 09:50:53 +0200 Subject: [PATCH 0359/1519] Updated version numbers --- setup.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.rst b/setup.rst index f18ac19e9dc..08ad45fe407 100644 --- a/setup.rst +++ b/setup.rst @@ -50,10 +50,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_name --full + $ symfony new my_project_name --version=next --full # run this if you are building a microservice, console application or API - $ symfony new my_project_name + $ symfony new my_project_name --version=next The only difference between these two commands is the number of packages installed by default. The ``--full`` option installs all the packages that you @@ -65,10 +65,10 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/website-skeleton my_project_name + $ composer create-project symfony/website-skeleton:"5.2.x@dev" my_project_name # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton my_project_name + $ composer create-project symfony/skeleton:"5.2.x@dev" my_project_name No matter which command you run to create the Symfony application. All of them will create a new ``my_project_name/`` directory, download some dependencies From 66b8ee2ceeef32cb37fea317710641339162a798 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 30 Jun 2020 10:43:02 +0200 Subject: [PATCH 0360/1519] Removed a merge leftover --- http_client.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/http_client.rst b/http_client.rst index 8e43d8f4e3d..ca273b873f6 100644 --- a/http_client.rst +++ b/http_client.rst @@ -319,7 +319,6 @@ autoconfigure the HTTP client based on the requested URL: ], ], ]); ->>>>>>> 5.0:http_client.rst .. code-block:: php-standalone From ac7ecfc22159139793d91fd1abe111923808b9fd Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 30 Jun 2020 10:46:33 +0200 Subject: [PATCH 0361/1519] Updated a wrong reference --- components/asset.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/asset.rst b/components/asset.rst index fee6acd6aa5..20b5ce20b2d 100644 --- a/components/asset.rst +++ b/components/asset.rst @@ -167,7 +167,7 @@ In those cases, use the If your JSON file is not on your local filesystem but is accessible over HTTP, use the :class:`Symfony\\Component\\Asset\\VersionStrategy\\RemoteJsonManifestVersionStrategy` -with the :doc:`HttpClient component `:: +with the :doc:`HttpClient component `:: use Symfony\Component\Asset\Package; use Symfony\Component\Asset\VersionStrategy\RemoteJsonManifestVersionStrategy; From 105ff11c5aebe8d3c742f397d9ea7a0bb5a81938 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Tue, 30 Jun 2020 15:19:53 +0200 Subject: [PATCH 0362/1519] Test redirecting to a specific section from redirection_map --- _build/redirection_map | 1 + 1 file changed, 1 insertion(+) diff --git a/_build/redirection_map b/_build/redirection_map index 28b3aad29e5..ebc50553de8 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -507,3 +507,4 @@ /components/class_loader https://github.com/symfony/class-loader /frontend/encore/versus-assetic /frontend /components/http_client /http_client +/redirection_test /session/database.html#store-sessions-in-a-nosql-database-mongodb From 8574f41d17f59d24104a2cb5b16485275a100a37 Mon Sep 17 00:00:00 2001 From: Ahmed TAILOULOUTE Date: Wed, 1 Jul 2020 13:39:50 +0200 Subject: [PATCH 0363/1519] Update serializer.rst --- components/serializer.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/serializer.rst b/components/serializer.rst index 3191276ae8b..4fe9e67c1ad 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -830,8 +830,7 @@ always as a collection. .. tip:: XML comments are ignored by default when decoding contents, but this - behavior can be changed with the optional ``$decoderIgnoredNodeTypes`` argument of - the ``XmlEncoder`` class constructor. + behavior can be changed with the optional context key ``XmlEncoder::DECODER_IGNORED_NODE_TYPES``. Data with ``#comment`` keys are encoded to XML comments by default. This can be changed with the optional ``$encoderIgnoredNodeTypes`` argument of the From abcb1839877fa2b08cd740af659a219815a3a26b Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Wed, 1 Jul 2020 14:41:13 +0200 Subject: [PATCH 0364/1519] Update docs regarding 2nd argument of DomCrawler text() The 2nd Argument is true by default, therefore whitespace is trimmed by default. Passing false will alter the default behaviour. Previous documentation suggested the other way around. --- components/dom_crawler.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/dom_crawler.rst b/components/dom_crawler.rst index 8bc6a093fc8..cda18b47662 100644 --- a/components/dom_crawler.rst +++ b/components/dom_crawler.rst @@ -220,9 +220,9 @@ Access the value of the first node of the current selection:: // avoid the exception passing an argument that text() returns when node does not exist $message = $crawler->filterXPath('//body/p')->text('Default text content'); - // pass TRUE as the second argument of text() to remove all extra white spaces, including + // pass false as the second argument of text() to not remove all extra white spaces, including // the internal ones (e.g. " foo\n bar baz \n " is returned as "foo bar baz") - $crawler->filterXPath('//body/p')->text('Default text content', true); + $crawler->filterXPath('//body/p')->text('Default text content', false); Access the attribute value of the first node of the current selection:: From d182a48bad37b8e35b094402ba57703b5028586c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 1 Jul 2020 17:24:04 +0200 Subject: [PATCH 0365/1519] Reword --- components/dom_crawler.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/dom_crawler.rst b/components/dom_crawler.rst index cda18b47662..eb0e6850ccd 100644 --- a/components/dom_crawler.rst +++ b/components/dom_crawler.rst @@ -220,8 +220,9 @@ Access the value of the first node of the current selection:: // avoid the exception passing an argument that text() returns when node does not exist $message = $crawler->filterXPath('//body/p')->text('Default text content'); - // pass false as the second argument of text() to not remove all extra white spaces, including - // the internal ones (e.g. " foo\n bar baz \n " is returned as "foo bar baz") + // by default, text() trims white spaces, including the internal ones + // (e.g. " foo\n bar baz \n " is returned as "foo bar baz") + // pass FALSE as the second argument to return the original text unchanged $crawler->filterXPath('//body/p')->text('Default text content', false); Access the attribute value of the first node of the current selection:: From 377c0c0d544277b48879e918f515bc2f1142c423 Mon Sep 17 00:00:00 2001 From: Alexander Grimalovsky Date: Wed, 1 Jul 2020 22:55:10 +0300 Subject: [PATCH 0366/1519] Fixed mention of minimum PHP version for v5.x Minimum PHP version for Symfony 5.x is 7.2.5, but documentation doesn't reflect this change and keep same PHP version as 3.x. --- contributing/code/pull_requests.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contributing/code/pull_requests.rst b/contributing/code/pull_requests.rst index 74048987ced..ee8ce72825b 100644 --- a/contributing/code/pull_requests.rst +++ b/contributing/code/pull_requests.rst @@ -25,7 +25,7 @@ Before working on Symfony, setup a friendly environment with the following software: * Git; -* PHP version 7.1.3 or above. +* PHP version 7.2.5 or above. Configure Git ~~~~~~~~~~~~~ @@ -193,8 +193,8 @@ want to debug are installed by running ``composer install`` inside it. .. tip:: - If symlinks to your local Symfony fork cannot be resolved inside your project due to - your dev environment (for instance when using Vagrant where only the current project + If symlinks to your local Symfony fork cannot be resolved inside your project due to + your dev environment (for instance when using Vagrant where only the current project directory is mounted), you can alternatively use the ``--copy`` option. .. _work-on-your-patch: From 427d99285b51165d39ac251bea19b4759c8a573b Mon Sep 17 00:00:00 2001 From: Surfoo Date: Mon, 29 Jun 2020 13:52:21 +0200 Subject: [PATCH 0367/1519] Fixed micro kernel demo --- configuration/micro_kernel_trait.rst | 62 ++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst index 00f19d6a951..54fdbb54f0b 100644 --- a/configuration/micro_kernel_trait.rst +++ b/configuration/micro_kernel_trait.rst @@ -54,9 +54,7 @@ Next, create an ``index.php`` file that defines the kernel class and executes it protected function configureRoutes(RoutingConfigurator $routes) { - // kernel is a service that points to this class - // optional 3rd argument is the route name - $routes->add('/random/{limit}', 'kernel::randomNumber'); + $routes->add('random_number', '/random/{limit}')->controller([$this, 'randomNumber']); } public function randomNumber($limit) @@ -151,7 +149,7 @@ hold the kernel. Now it looks like this:: ]; if ($this->getEnvironment() == 'dev') { - $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); + $bundles[] = new \Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); } return $bundles; @@ -160,6 +158,7 @@ hold the kernel. Now it looks like this:: protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader) { $loader->load(__DIR__.'/../config/framework.yaml'); + $loader->load(__DIR__.'/../config/services.yaml'); // configure WebProfilerBundle only if the bundle is enabled if (isset($this->bundles['WebProfilerBundle'])) { @@ -201,6 +200,61 @@ Before continuing, run this command to add support for the new dependencies: $ composer require symfony/yaml symfony/twig-bundle symfony/web-profiler-bundle doctrine/annotations +You need add the following service configuration, which is the default config for a new project: + +.. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + # default configuration for services in *this* file + _defaults: + autowire: true # Automatically injects dependencies in your services. + autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. + + # makes classes in src/ available to be used as services + # this creates a service per class whose id is the fully-qualified class name + App\: + resource: '../src/*' + + .. code-block:: xml + + + + + + + + + + + + + + + + .. code-block:: php + + // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + return function(ContainerConfigurator $configurator) { + // default configuration for services in *this* file + $services = $configurator->services() + ->defaults() + ->autowire() // Automatically injects dependencies in your services. + ->autoconfigure() // Automatically registers your services as commands, event subscribers, etc. + ; + + // makes classes in src/ available to be used as services + // this creates a service per class whose id is the fully-qualified class name + $services->load('App\\', '../src/*'); + }; + Unlike the previous kernel, this loads an external ``config/framework.yaml`` file, because the configuration started to get bigger: From e1c35a5385d20f0f32e49de94de8f9e5428c129d Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Tue, 7 Jul 2020 15:02:05 +0200 Subject: [PATCH 0368/1519] [#13919] Use ContainerConfigurator and fixes some bugs after testing the example code --- configuration/micro_kernel_trait.rst | 105 +++++++-------------------- 1 file changed, 27 insertions(+), 78 deletions(-) diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst index 42da9fdeff2..84d8da1f028 100644 --- a/configuration/micro_kernel_trait.rst +++ b/configuration/micro_kernel_trait.rst @@ -24,8 +24,7 @@ Next, create an ``index.php`` file that defines the kernel class and executes it // index.php use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; - use Symfony\Component\Config\Loader\LoaderInterface; - use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Kernel as BaseKernel; @@ -37,27 +36,27 @@ Next, create an ``index.php`` file that defines the kernel class and executes it { use MicroKernelTrait; - public function registerBundles() + public function registerBundles(): array { return [ - new Symfony\Bundle\FrameworkBundle\FrameworkBundle() + new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), ]; } - protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader) + protected function configureContainer(ContainerConfigurator $c): void { // PHP equivalent of config/packages/framework.yaml - $c->loadFromExtension('framework', [ + $c->extension('framework', [ 'secret' => 'S0ME_SECRET' ]); } - protected function configureRoutes(RoutingConfigurator $routes) + protected function configureRoutes(RoutingConfigurator $routes): void { $routes->add('random_number', '/random/{limit}')->controller([$this, 'randomNumber']); } - public function randomNumber($limit) + public function randomNumber(int $limit): JsonResponse { return new JsonResponse([ 'number' => random_int(0, $limit), @@ -89,9 +88,9 @@ that define your bundles, your services and your routes: **registerBundles()** This is the same ``registerBundles()`` that you see in a normal kernel. -**configureContainer(ContainerBuilder $c, LoaderInterface $loader)** +**configureContainer(ContainerConfigurator $c)** This method builds and configures the container. In practice, you will use - ``loadFromExtension`` to configure different bundles (this is the equivalent + ``extension()`` to configure different bundles (this is the equivalent of what you see in a normal ``config/packages/*`` file). You can also register services directly in PHP or load external configuration files (shown below). @@ -132,8 +131,7 @@ hold the kernel. Now it looks like this:: namespace App; use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; - use Symfony\Component\Config\Loader\LoaderInterface; - use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use Symfony\Component\HttpKernel\Kernel as BaseKernel; use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; @@ -141,7 +139,7 @@ hold the kernel. Now it looks like this:: { use MicroKernelTrait; - public function registerBundles() + public function registerBundles(): array { $bundles = [ new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(), @@ -155,21 +153,27 @@ hold the kernel. Now it looks like this:: return $bundles; } - protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader) + protected function configureContainer(ContainerConfigurator $c): void { - $loader->load(__DIR__.'/../config/framework.yaml'); - $loader->load(__DIR__.'/../config/services.yaml'); + $c->import(__DIR__.'/../config/framework.yaml'); + + // register all classes in /src/ as service + $c->services() + ->load('App\\', __DIR__.'/*') + ->autowire() + ->autoconfigure() + ; // configure WebProfilerBundle only if the bundle is enabled if (isset($this->bundles['WebProfilerBundle'])) { - $c->loadFromExtension('web_profiler', [ + $c->extension('web_profiler', [ 'toolbar' => true, 'intercept_redirects' => false, ]); } } - protected function configureRoutes(RoutingConfigurator $routes) + protected function configureRoutes(RoutingConfigurator $routes): void { // import the WebProfilerRoutes, only if the bundle is enabled if (isset($this->bundles['WebProfilerBundle'])) { @@ -178,17 +182,17 @@ hold the kernel. Now it looks like this:: } // load the annotation routes - $routes->import(__DIR__.'/../src/Controller/', 'annotation'); + $routes->import(__DIR__.'/Controller/', 'annotation'); } // optional, to use the standard Symfony cache directory - public function getCacheDir() + public function getCacheDir(): string { return __DIR__.'/../var/cache/'.$this->getEnvironment(); } // optional, to use the standard Symfony logs directory - public function getLogDir() + public function getLogDir(): string { return __DIR__.'/../var/log'; } @@ -200,61 +204,6 @@ Before continuing, run this command to add support for the new dependencies: $ composer require symfony/yaml symfony/twig-bundle symfony/web-profiler-bundle doctrine/annotations -You need add the following service configuration, which is the default config for a new project: - -.. configuration-block:: - - .. code-block:: yaml - - # config/services.yaml - services: - # default configuration for services in *this* file - _defaults: - autowire: true # Automatically injects dependencies in your services. - autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. - - # makes classes in src/ available to be used as services - # this creates a service per class whose id is the fully-qualified class name - App\: - resource: '../src/*' - - .. code-block:: xml - - - - - - - - - - - - - - - - .. code-block:: php - - // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; - - return function(ContainerConfigurator $configurator) { - // default configuration for services in *this* file - $services = $configurator->services() - ->defaults() - ->autowire() // Automatically injects dependencies in your services. - ->autoconfigure() // Automatically registers your services as commands, event subscribers, etc. - ; - - // makes classes in src/ available to be used as services - // this creates a service per class whose id is the fully-qualified class name - $services->load('App\\', '../src/*'); - }; - Unlike the previous kernel, this loads an external ``config/framework.yaml`` file, because the configuration started to get bigger: @@ -299,6 +248,7 @@ has one file in it:: namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; class MicroController extends AbstractController @@ -306,7 +256,7 @@ has one file in it:: /** * @Route("/random/{limit}") */ - public function randomNumber($limit) + public function randomNumber(int $limit): Response { $number = random_int(0, $limit); @@ -381,7 +331,6 @@ As before you can use the :doc:`Symfony Local Web Server .. code-block:: terminal - cd public/ $ symfony server:start Then visit the page in your browser: http://localhost:8000/random/10 From 02ee00b734d96aa7929012e8ad938d72d1c04d12 Mon Sep 17 00:00:00 2001 From: Thomas Trautner Date: Tue, 7 Jul 2020 10:18:53 +0200 Subject: [PATCH 0369/1519] Remove links to not existing channel pages --- notifier.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/notifier.rst b/notifier.rst index 5e0b971827c..cc66c6f854d 100644 --- a/notifier.rst +++ b/notifier.rst @@ -31,10 +31,10 @@ by using transports. The notifier component supports the following channels: -* `SMS `_ sends notifications to phones via SMS messages -* `Chat `_ sends notifications to chat services like Slack +* SMS sends notifications to phones via SMS messages +* Chat sends notifications to chat services like Slack and Telegram; -* `Email `_ integrates the :doc:`Symfony Mailer `; +* Email integrates the :doc:`Symfony Mailer `; * Browser uses :ref:`flash messages `. .. tip:: From 9848b6ed5bada3a6ef8fc56c4a4219946b1f1d57 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 8 Jul 2020 17:14:23 +0200 Subject: [PATCH 0370/1519] Added some links --- notifier.rst | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/notifier.rst b/notifier.rst index cc66c6f854d..4857a3a2d18 100644 --- a/notifier.rst +++ b/notifier.rst @@ -31,17 +31,19 @@ by using transports. The notifier component supports the following channels: -* SMS sends notifications to phones via SMS messages -* Chat sends notifications to chat services like Slack - and Telegram; -* Email integrates the :doc:`Symfony Mailer `; -* Browser uses :ref:`flash messages `. +* :ref:`SMS channel ` sends notifications to phones via + SMS messages; +* :ref:`Chat channel ` sends notifications to chat + services like Slack and Telegram; +* :ref:`Email channel ` integrates the :doc:`Symfony Mailer `; +* Browser channel uses :ref:`flash messages `. .. tip:: Use :doc:`secrets ` to securily store your API's tokens. +.. _notifier-sms-channel: .. _notifier-texter-dsn: SMS Channel @@ -109,6 +111,7 @@ configure the ``texter_transports``: ], ]); +.. _notifier-chat-channel: .. _notifier-chatter-dsn: Chat Channel @@ -174,6 +177,8 @@ Chatters are configured using the ``chatter_transports`` setting: ], ]); +.. _notifier-email-channel: + Email Channel ~~~~~~~~~~~~~ @@ -279,7 +284,7 @@ transport: %env(SLACK_DSN)% || %env(TELEGRAM_DSN)% - Date: Wed, 8 Jul 2020 17:22:02 +0200 Subject: [PATCH 0371/1519] Updated some Docrine config changes for Symfony 5.1 --- doctrine/multiple_entity_managers.rst | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/doctrine/multiple_entity_managers.rst b/doctrine/multiple_entity_managers.rst index 3cbfbd75eb3..38711b468c1 100644 --- a/doctrine/multiple_entity_managers.rst +++ b/doctrine/multiple_entity_managers.rst @@ -192,8 +192,8 @@ for each entity manager. the connection or entity manager, the default (i.e. ``default``) is used. If you use a different name than ``default`` for the default entity manager, - you will need to redefine the default entity manager in ``prod`` environment - configuration too: + you will need to redefine the default entity manager in the ``prod`` environment + configuration and in the Doctrine migrations configuration (if you use that): .. code-block:: yaml @@ -204,6 +204,13 @@ for each entity manager. # ... + .. code-block:: yaml + + # config/packages/doctrine_migrations.yaml + doctrine_migrations: + # ... + em: 'your default entity manager name' + When working with multiple connections to create your databases: .. code-block:: terminal From 8b1767fc8b74a6c5e6835ec30c583f3f14921131 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 9 Jul 2020 09:11:14 +0200 Subject: [PATCH 0372/1519] Removed the versionadded directive --- components/property_info.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/components/property_info.rst b/components/property_info.rst index dd6cda0b742..44bfe2c9558 100644 --- a/components/property_info.rst +++ b/components/property_info.rst @@ -490,10 +490,6 @@ service by defining it as a service with one or more of the following * ``property_info.initializable_extractor`` if it provides initializable information (it checks if a property can be initialized through the constructor). -.. versionadded:: 4.2 - - The ``property_info.initializable_extractor`` was introduced in Symfony 4.2. - .. _`phpDocumentor Reflection`: https://github.com/phpDocumentor/ReflectionDocBlock .. _`phpdocumentor/reflection-docblock`: https://packagist.org/packages/phpdocumentor/reflection-docblock .. _`Doctrine ORM`: https://www.doctrine-project.org/projects/orm.html From 486a1fe9b3d4280507c4f5acb6c7971e76457725 Mon Sep 17 00:00:00 2001 From: Souhail Date: Fri, 10 Jul 2020 10:54:54 +0200 Subject: [PATCH 0373/1519] Update experimental_authenticators.rst Fix the link for `PreAuthenticatedUserBadge` class --- security/experimental_authenticators.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index 4299a452dcf..a8c5ee3cc55 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -464,7 +464,7 @@ the following badges are supported: authentication. The constructor requires a token ID (unique per form) and CSRF token (unique per request). See :doc:`/security/csrf`. -:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\PreAuthenticatedBadge` +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\PreAuthenticatedUserBadge` Indicates that this user was pre-authenticated (i.e. before Symfony was initiated). This skips the :doc:`pre-authentication user checker `. From 9b7bae9656bd7bfea13dcfb8c946949a06069e9c Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Sun, 12 Jul 2020 23:27:40 +0200 Subject: [PATCH 0374/1519] Add doc for Isin constraint --- reference/constraints.rst | 1 + reference/constraints/Isin.rst | 99 +++++++++++++++++++++++++++++++ reference/constraints/map.rst.inc | 1 + 3 files changed, 101 insertions(+) create mode 100644 reference/constraints/Isin.rst diff --git a/reference/constraints.rst b/reference/constraints.rst index faa5ed3cac2..a3c99715834 100644 --- a/reference/constraints.rst +++ b/reference/constraints.rst @@ -62,6 +62,7 @@ Validation Constraints Reference constraints/Bic constraints/Isbn constraints/Issn + constraints/Isin constraints/AtLeastOneOf constraints/Sequentially diff --git a/reference/constraints/Isin.rst b/reference/constraints/Isin.rst new file mode 100644 index 00000000000..86c1c3a3973 --- /dev/null +++ b/reference/constraints/Isin.rst @@ -0,0 +1,99 @@ +Isin +==== + +Validates that a value is a valid +`International Securities Identification Number (ISIN)`_. + +========== =================================================================== +Applies to :ref:`property or method ` +Options - `groups`_ + - `message`_ + - `payload`_ +Class :class:`Symfony\\Component\\Validator\\Constraints\\Isin` +Validator :class:`Symfony\\Component\\Validator\\Constraints\\IsinValidator` +========== =================================================================== + +Basic Usage +----------- + +.. configuration-block:: + + .. code-block:: php-annotations + + // src/Entity/UnitAccount.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class UnitAccount + { + /** + * @Assert\Isin + */ + protected $isin; + } + + .. code-block:: yaml + + # config/validator/validation.yaml + App\Entity\UnitAccount: + properties: + isin: + - Isin: ~ + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/UnitAccount.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; + + class UnitAccount + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('isin', new Assert\Isin()); + } + } + +.. include:: /reference/constraints/_empty-values-are-valid.rst.inc + +Options +------- + +.. include:: /reference/constraints/_groups-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` default: ``This value is not a valid International Securities Identification Number (ISIN).`` + +The message shown if the given value is not a valid ISIN. + +You can use the following parameters in this message: + +=============== ============================================================== +Parameter Description +=============== ============================================================== +``{{ value }}`` The current (invalid) value +=============== ============================================================== + +.. include:: /reference/constraints/_payload-option.rst.inc + +.. _`International Securities Identification Number (ISIN)`: https://en.wikipedia.org/wiki/International_Securities_Identification_Number diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index 05e820db8ee..d8e8cfcd2f9 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -80,6 +80,7 @@ Financial and other Number Constraints * :doc:`Iban ` * :doc:`Isbn ` * :doc:`Issn ` +* :doc:`Isin ` Other Constraints ~~~~~~~~~~~~~~~~~ From 4de67df7cdb8d299ac0ab57f8cb5bb7a12b351fb Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 13 Jul 2020 15:17:22 +0200 Subject: [PATCH 0375/1519] [Mailer] Allow UTF-8 chars in email addresses --- mailer.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mailer.rst b/mailer.rst index 9dd1df9bb39..51bc410ce8a 100644 --- a/mailer.rst +++ b/mailer.rst @@ -161,6 +161,16 @@ both strings or address objects:: :class:`Symfony\\Component\\Mailer\\Event\\MessageEvent` event to set the same ``From`` email to all messages. +.. note:: + + The local part of the address (what goes before the ``@``) can include UTF-8 + characters, except for the sender address (to avoid issues with bounced emails). + For example: ``föóbàr@example.com``, ``用户@example.com``, ``θσερ@example.com``, etc. + + .. versionadded:: 5.2 + + Support for UTF-8 characters in email addresses was introduced in Symfony 5.2. + Multiple addresses are defined with the ``addXXX()`` methods:: $email = (new Email()) From 3be2860ceb7f0203bab46930b89d9b5fcc7a2af0 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 14 Jul 2020 10:33:29 -0400 Subject: [PATCH 0376/1519] default path of migrations changed in recipe --- doctrine.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doctrine.rst b/doctrine.rst index 99f0384892a..abeb4daa46d 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -225,7 +225,7 @@ If everything worked, you should see something like this: SUCCESS! - Next: Review the new migration "src/Migrations/Version20180207231217.php" + Next: Review the new migration "migrations/Version20180207231217.php" Then: Run the migration with php bin/console doctrine:migrations:migrate If you open this file, it contains the SQL needed to update your database! To run From 264aaf1bb51c00b2a98ec9a7c83aef668bb60bcb Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 13 Jul 2020 14:46:55 +0200 Subject: [PATCH 0377/1519] [HttpFoundation] Document HeaderUtils::parseQuery() --- components/http_foundation.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index e29c16ff384..0677f3a2f73 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -272,6 +272,14 @@ this complexity and defines some methods for the most common tasks:: HeaderUtils::unquote('"foo \"bar\""'); // => 'foo "bar"' + // Parses a query string but maintains dots (PHP parse_str() replaces '.' by '_') + HeaderUtils::parseQuery('foo[bar.baz]=qux'); + // => ['foo' => ['bar.baz' => 'qux']] + +.. versionadded:: 5.2 + + The ``parseQuery()`` method was introduced in Symfony 5.2. + Accessing ``Accept-*`` Headers Data ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From fe2ad65e1563f8eba3414aa91b63206e4f53ed60 Mon Sep 17 00:00:00 2001 From: Abdouni Abdelkarim Date: Wed, 15 Jul 2020 10:40:39 +0200 Subject: [PATCH 0378/1519] Update service_container.rst Hello, I removed the `Migrations` folder from exclude. Since 5.1, this directory has been moved outside of `src`. --- service_container.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/service_container.rst b/service_container.rst index 67195adeb3b..c78af339afb 100644 --- a/service_container.rst +++ b/service_container.rst @@ -159,7 +159,7 @@ each time you ask for it. # this creates a service per class whose id is the fully-qualified class name App\: resource: '../src/*' - exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}' + exclude: '../src/{DependencyInjection,Entity,Tests,Kernel.php}' # ... @@ -178,7 +178,7 @@ each time you ask for it. - + @@ -201,7 +201,7 @@ each time you ask for it. // makes classes in src/ available to be used as services // this creates a service per class whose id is the fully-qualified class name $services->load('App\\', '../src/*') - ->exclude('../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'); + ->exclude('../src/{DependencyInjection,Entity,Tests,Kernel.php}'); }; .. tip:: @@ -408,7 +408,7 @@ pass here. No problem! In your configuration, you can explicitly set this argume # same as before App\: resource: '../src/*' - exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}' + exclude: '../src/{DependencyInjection,Entity,Tests,Kernel.php}' # explicitly configure the service App\Updates\SiteUpdateManager: @@ -431,7 +431,7 @@ pass here. No problem! In your configuration, you can explicitly set this argume @@ -453,7 +453,7 @@ pass here. No problem! In your configuration, you can explicitly set this argume // same as before $services->load('App\\', '../src/*') - ->exclude('../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'); + ->exclude('../src/{DependencyInjection,Entity,Tests,Kernel.php}'); $services->set(SiteUpdateManager::class) ->arg('$adminEmail', 'manager@example.com') @@ -929,7 +929,7 @@ key. For example, the default Symfony configuration contains this: # this creates a service per class whose id is the fully-qualified class name App\: resource: '../src/*' - exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}' + exclude: '../src/{DependencyInjection,Entity,Tests,Kernel.php}' .. code-block:: xml @@ -943,7 +943,7 @@ key. For example, the default Symfony configuration contains this: - + @@ -958,7 +958,7 @@ key. For example, the default Symfony configuration contains this: // makes classes in src/ available to be used as services // this creates a service per class whose id is the fully-qualified class name $services->load('App\\', '../src/*') - ->exclude('../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'); + ->exclude('../src/{DependencyInjection,Entity,Tests,Kernel.php}'); }; .. tip:: From 6a539f68eb8fc3b91dc9ccc016f536f611c44867 Mon Sep 17 00:00:00 2001 From: Iliya Miroslavov Iliev Date: Tue, 21 Jul 2020 11:10:22 +0300 Subject: [PATCH 0379/1519] Update OVH Cloud configuration --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index ebc46605a22..c1b6ebfabe5 100644 --- a/notifier.rst +++ b/notifier.rst @@ -59,7 +59,7 @@ Service Package DSN ========== =============================== ==================================================== Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` -OvhCloud ``symfony/ovhcloud-notifier`` ``ovhcloud://KEY:SECRET@default?from=FROM`` +OvhCloud ``symfony/ovhcloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` FreeMobile ``symfony/freemobile-notifier`` ``freemobile://LOGIN:PASS@default?phone=PHONE`` ========== =============================== ==================================================== From ae0b34e90e7893bfb96c91481c18c35fccec2e6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Moln=C3=A1r?= Date: Tue, 28 Jul 2020 09:11:30 +0200 Subject: [PATCH 0380/1519] [String] Fix missing locale in slugger substitution map --- components/string.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/string.rst b/components/string.rst index 2d5d1dd8e9e..7d2ec49a198 100644 --- a/components/string.rst +++ b/components/string.rst @@ -469,7 +469,7 @@ that only includes safe ASCII characters:: // $slug = 'Workspace-settings' // you can also pass an array with additional character substitutions - $slugger = new AsciiSlugger('en', ['%' => 'percent', '€' => 'euro']); + $slugger = new AsciiSlugger('en', ['en' => ['%' => 'percent', '€' => 'euro']]); $slug = $slugger->slug('10% or 5€'); // $slug = '10-percent-or-5-euro' From a1ce6020bc31ce49cb5b0c6b15a451be755bda3d Mon Sep 17 00:00:00 2001 From: fliespl Date: Tue, 28 Jul 2020 13:05:34 +0200 Subject: [PATCH 0381/1519] verify_peer in dsn should be 0 Setting it to false value resolves to true in php 7.4 since false is taken as string. --- components/mailer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mailer.rst b/components/mailer.rst index 1f004e90bc6..7e2dd89e798 100644 --- a/components/mailer.rst +++ b/components/mailer.rst @@ -171,7 +171,7 @@ configurable with the ``verify_peer`` option. Although it's not recommended to disable this verification for security reasons, it can be useful while developing the application or when using a self-signed certificate:: - $dsn = 'smtp://user:pass@smtp.example.com?verify_peer=false' + $dsn = 'smtp://user:pass@smtp.example.com?verify_peer=0' .. versionadded:: 5.1 From 4ea23f77a4353a57d7dd9a7e308eee4db7dff692 Mon Sep 17 00:00:00 2001 From: Andrius Date: Mon, 3 Aug 2020 00:56:30 +0300 Subject: [PATCH 0382/1519] Update performance.rst Correct path for opcache.preload in symfony cache dir. --- performance.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/performance.rst b/performance.rst index b919f6a3906..7d4ea2e5fb9 100644 --- a/performance.rst +++ b/performance.rst @@ -120,7 +120,7 @@ The preload file path is the same as the compiled service container but with the .. code-block:: ini ; php.ini - opcache.preload=/path/to/project/var/cache/prod/srcApp_KernelProdContainer.preload.php + opcache.preload=/path/to/project/var/cache/prod/App_KernelProdContainer.preload.php Use the :ref:`container.preload ` and :ref:`container.no_preload ` service tags to define From ff3a2b58b1a81167ed8b771f29466de3542ee141 Mon Sep 17 00:00:00 2001 From: Milan Pavkovic Date: Wed, 5 Aug 2020 18:30:28 +0200 Subject: [PATCH 0383/1519] Remove reference to non-existing fromBinary method --- components/uid.rst | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index f2fcd074533..c8eee0ece94 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -62,15 +62,10 @@ to create each type of UUID:: If your UUID is generated by another system, use the ``fromString()`` method to create an object and make use of the utilities available for Symfony UUIDs:: - // this value is generated somewhere else + // this value is generated somewhere else (can also be in binary format) $uuidValue = 'd9e7a184-5d5b-11ea-a62a-3499710062d0'; $uuid = Uuid::fromString($uuidValue); -If your UUIDs are generated in binary format, use the ``fromBinary()`` method -to create the objects for them:: - - $uuid = Uuid::fromBinary($uuidBinaryContents); - Converting UUIDs ~~~~~~~~~~~~~~~~ @@ -140,15 +135,10 @@ Instantiate the ``Ulid`` class to generate a random ULID value:: If your ULID is generated by another system, use the ``fromString()`` method to create an object and make use of the utilities available for Symfony ULIDs:: - // this value is generated somewhere else + // this value is generated somewhere else (can also be in binary format) $ulidValue = '01E439TP9XJZ9RPFH3T1PYBCR8'; $ulid = Ulid::fromString($ulidValue); -If your ULIDs are generated in binary format, use the ``fromBinary()`` method -to create the objects for them:: - - $ulid = Ulid::fromBinary($ulidBinaryContents); - Converting ULIDs ~~~~~~~~~~~~~~~~ From d6f8fd83dce5cb5ed477cecc8a013bfceeb76ebf Mon Sep 17 00:00:00 2001 From: Lorenzo Date: Sun, 9 Aug 2020 20:09:25 +0100 Subject: [PATCH 0384/1519] Update chatters.rst fix to use a working image url --- notifier/chatters.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier/chatters.rst b/notifier/chatters.rst index 17eac35885f..40e9cea2096 100644 --- a/notifier/chatters.rst +++ b/notifier/chatters.rst @@ -77,7 +77,7 @@ some interactive options called `Block elements`_:: ->text('The Symfony Community') ->accessory( new SlackImageBlockElement( - 'https://example.com/symfony-logo.png', + 'https://symfony.com/favicons/apple-touch-icon.png', 'Symfony' ) ) From b92adf679b1f2630bd07d7f03bed92d34523a35f Mon Sep 17 00:00:00 2001 From: Ivan Yivoff Date: Tue, 11 Aug 2020 15:47:15 +0200 Subject: [PATCH 0385/1519] Update event_dispatcher.rst Update code example to match 5.1 PHP configuration format. --- event_dispatcher.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/event_dispatcher.rst b/event_dispatcher.rst index 8bef74f26d9..15742afce71 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -101,8 +101,10 @@ using a special "tag": // config/services.php use App\EventListener\ExceptionListener; + + $services = $containerConfigurator->services(); - $container->register(ExceptionListener::class) + $services->set(ExceptionListener::class) ->addTag('kernel.event_listener', ['event' => 'kernel.exception']) ; From e82b66b787a929d2c2898efc98aa7bb18ff7c77b Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Mon, 27 Jul 2020 19:32:49 -0500 Subject: [PATCH 0386/1519] [Console] allow multiline responses to console questions --- components/console/helpers/questionhelper.rst | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/components/console/helpers/questionhelper.rst b/components/console/helpers/questionhelper.rst index e2c5898fa49..89716c8d078 100644 --- a/components/console/helpers/questionhelper.rst +++ b/components/console/helpers/questionhelper.rst @@ -234,6 +234,36 @@ You can also specify if you want to not trim the answer by setting it directly w $name = $helper->ask($input, $output, $question); } +Accept Multiline Answers +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.2 + + The ``setMultiline()`` and ``isMultiline()`` methods were introduced in + Symfony 5.2. + +By default, the question helper stops reading user input when it receives a newline +character (i.e., when the user hits ``ENTER`` once). However, you may specify that +the response to a question should allow multiline answers by passing ``true`` to +:method:`Symfony\\Component\\Console\\Question\\Question::setMultiline`:: + + use Symfony\Component\Console\Question\Question; + + // ... + public function execute(InputInterface $input, OutputInterface $output) + { + // ... + $helper = $this->getHelper('question'); + + $question = new Question('How do you solve world peace?'); + $question->setMultiline(true); + + $answer = $helper->ask($input, $output, $question); + } + +Multiline questions stop reading user input after receiving an end-of-transmission +control character (``Ctrl-D`` on Unix systems or ``Ctrl-Z`` on Windows). + Hiding the User's Response ~~~~~~~~~~~~~~~~~~~~~~~~~~ From 605e9888ff1481b765363895f0a617d8f9e955b4 Mon Sep 17 00:00:00 2001 From: fernandokarpinski <31803120+fernandokarpinski@users.noreply.github.com> Date: Tue, 11 Aug 2020 23:41:59 -0300 Subject: [PATCH 0387/1519] Update routing.rst --- routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routing.rst b/routing.rst index b2e252d87b5..0b675a67a60 100644 --- a/routing.rst +++ b/routing.rst @@ -1881,7 +1881,7 @@ Now, if the session is used, the application will report it based on your * ``enabled``: will throw an :class:`Symfony\\Component\\HttpKernel\\Exception\\UnexpectedSessionUsageException` exception * ``disabled``: will log a warning -It well help you understanding and hopefully fixing unexpected behavior in your application. +It will help you in understanding and hopefully fixing unexpected behavior in your application. .. _routing-generating-urls: From 4a5be126e1f1e7adfc3f55e95e1219b1b2159e2d Mon Sep 17 00:00:00 2001 From: khoptynskyi Date: Sun, 16 Aug 2020 17:25:22 +0300 Subject: [PATCH 0388/1519] [Console] added TableCellStyle documentation --- components/console/helpers/table.rst | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/components/console/helpers/table.rst b/components/console/helpers/table.rst index bc680cc5ad0..d50cc160c06 100644 --- a/components/console/helpers/table.rst +++ b/components/console/helpers/table.rst @@ -393,3 +393,36 @@ This will display the following table in the terminal: | Love | | Symfony | +---------+ + +.. versionadded:: 5.2 + +Styling of table cells +---------------------- + +You can customize a table cell via :class:`Symfony\\Component\\Console\\Helper\\TableCellStyle`:: + + use Symfony\Component\Console\Helper\Table; + use Symfony\Component\Console\Helper\TableCellStyle; + + $table = new Table($output); + + $table->setRows([ + [ + '978-0804169127', + new TableCell( + 'Divine Comedy', + [ + 'style' => new TableCellStyle([ + 'align' => 'center', + 'fg' => 'red', + 'bg' => 'green', + + // or + 'cellFormat' => '%s', + ]) + ] + ) + ], + ]); + + $table->render(); From abf4680a807eaaa3b597abb250407aee2c26e860 Mon Sep 17 00:00:00 2001 From: Antonio Pauletich Date: Mon, 17 Aug 2020 01:03:24 +0200 Subject: [PATCH 0389/1519] Add Beanstalkd Messenger bridge documentation --- messenger.rst | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/messenger.rst b/messenger.rst index 87f37600524..3b5e81ced07 100644 --- a/messenger.rst +++ b/messenger.rst @@ -992,6 +992,102 @@ auto_setup Whether the table should be created automatically during send / get. true ================== =================================== ====================== +Beanstalkd Transport +~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.2 + + Install it by running: + + .. code-block:: terminal + + $ composer require symfony/beanstalkd-messenger + +.. code-block:: bash + + # .env + MESSENGER_TRANSPORT_DSN=beanstalkd://localhost + +The format is ``beanstalkd://:?tube_name=&timeout=&ttr=``. + +The ``port`` setting is optional and defaults to ``11300`` if not set. + +The transport has a number of options: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/messenger.yaml + framework: + messenger: + transports: + async_priority_high: "%env(MESSENGER_TRANSPORT_DSN)%?tube_name=high_priority" + async_normal: + dsn: "%env(MESSENGER_TRANSPORT_DSN)%" + options: + tube_name: normal_priority + + .. code-block:: xml + + + + + + + + + + + + normal_priority + + + + + + + + .. code-block:: php + + // config/packages/messenger.php + $container->loadFromExtension('framework', [ + 'messenger' => [ + 'transports' => [ + 'async_priority_high' => '%env(MESSENGER_TRANSPORT_DSN)%?tube_name=high_priority', + 'async_priority_low' => [ + 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', + 'options' => [ + 'tube_name' => 'normal_priority' + ] + ], + ], + ], + ]); + +Options defined under ``options`` take precedence over ones defined in the DSN. + +================== =================================== ====================== + Option Description Default +================== =================================== ====================== +tube_name Name of the queue default +timeout Message reservation timeout 0 (will cause the + - in seconds. server to immediately + return either a + response or a + TransportException + will be thrown) +ttr The message time to run before it + is put back in the ready queue + - in seconds. 90 +================== =================================== ====================== + Redis Transport ~~~~~~~~~~~~~~~ From 54eafd372f054ad17151700fd0c9fda633a4373d Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER Date: Sun, 16 Aug 2020 21:03:42 +0200 Subject: [PATCH 0390/1519] Documentation about custom data collectors with autowire/autoconfigure --- profiler/data_collector.rst | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/profiler/data_collector.rst b/profiler/data_collector.rst index 41378ab6464..5081ac76692 100644 --- a/profiler/data_collector.rst +++ b/profiler/data_collector.rst @@ -104,18 +104,25 @@ The information collected by your data collector can be displayed both in the web debug toolbar and in the web profiler. To do so, you need to create a Twig template that includes some specific blocks. -However, first you must add some getters in the data collector class to give the +However, first make your DataCollector to extends :class:`Symfony\\Bundle\\FrameworkBundle\\DataCollector\\AbstractDataCollector` instead of :class:`Symfony\\Component\\HttpKernel\\DataCollector\\DataCollector`. When extending :class:`Symfony\\Bundle\\FrameworkBundle\\DataCollector\\AbstractDataCollector`, you don't need to implement `getName` method; your collector FQDN is returned as identifier (you can also override it if needed). Though you need to implement `getTemplate` with the template you're going to use in the profiler (see below). + +Then you must add some getters in the data collector class to give the template access to the collected information:: // src/DataCollector/RequestCollector.php namespace App\DataCollector; - use Symfony\Component\HttpKernel\DataCollector\DataCollector; + use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector; - class RequestCollector extends DataCollector + class RequestCollector extends AbstractDataCollector { // ... + public static function getTemplate(): ?string + { + return 'data_collector/template.html.twig'; + } + public function getMethod() { return $this->data['method']; @@ -227,8 +234,9 @@ The ``menu`` and ``panel`` blocks are the only required blocks to define the contents displayed in the web profiler panel associated with this data collector. All blocks have access to the ``collector`` object. -Finally, to enable the data collector template, override your service configuration -to specify a tag that contains the template: +That's it ! Your data collector is now accessible in the toolbar. + +If you don't use the default configuration with :ref:`autowire and autoconfigure `, you'll need to configure the data collector explicitely: .. configuration-block:: @@ -240,9 +248,8 @@ to specify a tag that contains the template: tags: - name: data_collector - template: 'data_collector/template.html.twig' # must match the value returned by the getName() method - id: 'app.request_collector' + id: 'App\DataCollector\RequestCollector' # optional priority # priority: 300 @@ -259,8 +266,7 @@ to specify a tag that contains the template: @@ -277,10 +283,8 @@ to specify a tag that contains the template: $services = $configurator->services(); $services->set(RequestCollector::class) - ->autowire() ->tag('data_collector', [ - 'template' => 'data_collector/template.html.twig', - 'id' => 'app.request_collector', + 'id' => RequestCollector::class, // 'priority' => 300, ]); }; @@ -289,3 +293,12 @@ The position of each panel in the toolbar is determined by the collector priorit Priorities are defined as positive or negative integers and they default to ``0``. Most built-in collectors use ``255`` as their priority. If you want your collector to be displayed before them, use a higher value (like 300). + +.. versionadded:: 5.2 + + :class:`Symfony\\Bundle\\FrameworkBundle\\DataCollector\\AbstractDataCollector` was introduced in Symfony 5.2. + +.. note:: + + Before the introduction of :class:`Symfony\\Bundle\\FrameworkBundle\\DataCollector\\AbstractDataCollector`, template path was defined in the service configuration (`template` key). This is still possible to define the template in the service configuration. In this case **template in service configuration takes precedence over template defined in data collector code**. + From 5892dfb9876233188cd94a9bd21cb28bbed7170c Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER Date: Mon, 17 Aug 2020 15:22:30 +0200 Subject: [PATCH 0391/1519] Fix debug:container command --- components/phpunit_bridge.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 2150bbb487a..2b6ad5f5e1b 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -336,7 +336,7 @@ the compiling and warming up of the container: .. code-block:: terminal - $ debug:container --deprecations + $ php bin/console debug:container --deprecations .. versionadded:: 5.1 From 0025c0645f5cbdeb1090c883ae5513ca0c8b7ab7 Mon Sep 17 00:00:00 2001 From: Tomas Date: Tue, 18 Aug 2020 10:38:41 +0300 Subject: [PATCH 0392/1519] Fix inconsistent security docs --- security/form_login.rst | 9 +++++---- security/guard_authentication.rst | 9 +++++---- security/json_login_setup.rst | 18 ++++++++++-------- security/multiple_guard_authenticators.rst | 18 ++++++++++-------- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/security/form_login.rst b/security/form_login.rst index 4dcd039e347..06d7e22c500 100644 --- a/security/form_login.rst +++ b/security/form_login.rst @@ -28,7 +28,8 @@ First, enable ``form_login`` under your firewall: firewalls: main: - anonymous: lazy + anonymous: true + lazy: true form_login: login_path: login check_path: login @@ -46,8 +47,7 @@ First, enable ``form_login`` under your firewall: https://symfony.com/schema/dic/security/security-1.0.xsd"> - - + @@ -59,7 +59,8 @@ First, enable ``form_login`` under your firewall: $container->loadFromExtension('security', [ 'firewalls' => [ 'main' => [ - 'anonymous' => 'lazy', + 'anonymous' => true, + 'lazy' => true, 'form_login' => [ 'login_path' => 'login', 'check_path' => 'login', diff --git a/security/guard_authentication.rst b/security/guard_authentication.rst index d88bea0de20..9245faace34 100644 --- a/security/guard_authentication.rst +++ b/security/guard_authentication.rst @@ -189,7 +189,8 @@ Finally, configure your ``firewalls`` key in ``security.yaml`` to use this authe # ... main: - anonymous: lazy + anonymous: true + lazy: true logout: ~ guard: @@ -217,8 +218,7 @@ Finally, configure your ``firewalls`` key in ``security.yaml`` to use this authe - - + @@ -241,7 +241,8 @@ Finally, configure your ``firewalls`` key in ``security.yaml`` to use this authe 'firewalls' => [ 'main' => [ 'pattern' => '^/', - 'anonymous' => 'lazy', + 'anonymous' => true, + 'lazy' => true, 'logout' => true, 'guard' => [ 'authenticators' => [ diff --git a/security/json_login_setup.rst b/security/json_login_setup.rst index 44ffa5d02e9..b304286bc30 100644 --- a/security/json_login_setup.rst +++ b/security/json_login_setup.rst @@ -17,7 +17,8 @@ First, enable the JSON login under your firewall: firewalls: main: - anonymous: lazy + anonymous: true + lazy: true json_login: check_path: /login @@ -34,8 +35,7 @@ First, enable the JSON login under your firewall: https://symfony.com/schema/dic/security/security-1.0.xsd"> - - + @@ -47,7 +47,8 @@ First, enable the JSON login under your firewall: $container->loadFromExtension('security', [ 'firewalls' => [ 'main' => [ - 'anonymous' => 'lazy', + 'anonymous' => true, + 'lazy' => true, 'json_login' => [ 'check_path' => '/login', ], @@ -165,7 +166,8 @@ The security configuration should be: firewalls: main: - anonymous: lazy + anonymous: true + lazy: true json_login: check_path: login username_path: security.credentials.login @@ -184,8 +186,7 @@ The security configuration should be: https://symfony.com/schema/dic/security/security-1.0.xsd"> - - + @@ -199,7 +200,8 @@ The security configuration should be: $container->loadFromExtension('security', [ 'firewalls' => [ 'main' => [ - 'anonymous' => 'lazy', + 'anonymous' => true, + 'lazy' => true, 'json_login' => [ 'check_path' => 'login', 'username_path' => 'security.credentials.login', diff --git a/security/multiple_guard_authenticators.rst b/security/multiple_guard_authenticators.rst index d3ef59a2494..b6ea9ca5f11 100644 --- a/security/multiple_guard_authenticators.rst +++ b/security/multiple_guard_authenticators.rst @@ -27,7 +27,8 @@ This is how your security configuration can look in action: # ... firewalls: default: - anonymous: lazy + anonymous: true + lazy: true guard: authenticators: - App\Security\LoginFormAuthenticator @@ -48,8 +49,7 @@ This is how your security configuration can look in action: - - + App\Security\LoginFormAuthenticator App\Security\FacebookConnectAuthenticator @@ -68,7 +68,8 @@ This is how your security configuration can look in action: // ... 'firewalls' => [ 'default' => [ - 'anonymous' => 'lazy', + 'anonymous' => true, + 'lazy' => true, 'guard' => [ 'entry_point' => LoginFormAuthenticator::class, 'authenticators' => [ @@ -105,7 +106,8 @@ the solution is to split the configuration into two separate firewalls: authenticators: - App\Security\ApiTokenAuthenticator default: - anonymous: lazy + anonymous: true + lazy: true guard: authenticators: - App\Security\LoginFormAuthenticator @@ -133,8 +135,7 @@ the solution is to split the configuration into two separate firewalls: App\Security\ApiTokenAuthenticator - - + App\Security\LoginFormAuthenticator @@ -163,7 +164,8 @@ the solution is to split the configuration into two separate firewalls: ], ], 'default' => [ - 'anonymous' => 'lazy', + 'anonymous' => true, + 'lazy' => true, 'guard' => [ 'authenticators' => [ LoginFormAuthenticator::class, From 8586afa9600590ff900fd26926ba39f0b0dce146 Mon Sep 17 00:00:00 2001 From: Thibaut Cheymol Date: Tue, 18 Aug 2020 09:14:14 +0200 Subject: [PATCH 0393/1519] [Mailer] Add documentation for Mailjet mailer --- mailer.rst | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/mailer.rst b/mailer.rst index 7f22f370dcf..3bb13432a36 100644 --- a/mailer.rst +++ b/mailer.rst @@ -45,6 +45,7 @@ Amazon SES ``composer require symfony/amazon-mailer`` Gmail ``composer require symfony/google-mailer`` MailChimp ``composer require symfony/mailchimp-mailer`` Mailgun ``composer require symfony/mailgun-mailer`` +Mailjet ``composer require symfony/mailjet-mailer`` Postmark ``composer require symfony/postmark-mailer`` SendGrid ``composer require symfony/sendgrid-mailer`` ================== ============================================= @@ -86,16 +87,17 @@ transport, but you can force to use one: This table shows the full list of available DNS formats for each third party provider: -==================== ========================================== =========================================== ======================================== - Provider SMTP HTTP API -==================== ========================================== =========================================== ======================================== - Amazon SES ses+smtp://ACCESS_KEY:SECRET_KEY@default ses+https://ACCESS_KEY:SECRET_KEY@default ses+api://ACCESS_KEY:SECRET_KEY@default - Google Gmail gmail+smtp://USERNAME:PASSWORD@default n/a n/a - Mailchimp Mandrill mandrill+smtp://USERNAME:PASSWORD@default mandrill+https://KEY@default mandrill+api://KEY@default - Mailgun mailgun+smtp://USERNAME:PASSWORD@default mailgun+https://KEY:DOMAIN@default mailgun+api://KEY:DOMAIN@default - Postmark postmark+smtp://ID:ID@default n/a postmark+api://KEY@default - Sendgrid sendgrid+smtp://apikey:KEY@default n/a sendgrid+api://KEY@default -==================== ========================================== =========================================== ======================================== +==================== ============================================= =========================================== ======================================== + Provider SMTP HTTP API +==================== ============================================= =========================================== ======================================== + Amazon SES ses+smtp://ACCESS_KEY:SECRET_KEY@default ses+https://ACCESS_KEY:SECRET_KEY@default ses+api://ACCESS_KEY:SECRET_KEY@default + Google Gmail gmail+smtp://USERNAME:PASSWORD@default n/a n/a + Mailchimp Mandrill mandrill+smtp://USERNAME:PASSWORD@default mandrill+https://KEY@default mandrill+api://KEY@default + Mailgun mailgun+smtp://USERNAME:PASSWORD@default mailgun+https://KEY:DOMAIN@default mailgun+api://KEY:DOMAIN@default + Mailjet mailjet+smtp://ACCESS_KEY:SECRET_KEY@default n/a mailjet+api://ACCESS_KEY:SECRET_KEY@default + Postmark postmark+smtp://ID:ID@default n/a postmark+api://KEY@default + Sendgrid sendgrid+smtp://apikey:KEY@default n/a sendgrid+api://KEY@default +==================== ============================================= =========================================== ======================================== .. caution:: From 0bf59205ecd7aa4e93797f9e78154409ad0e6e54 Mon Sep 17 00:00:00 2001 From: noniagriconomie Date: Wed, 12 Aug 2020 11:26:56 +0200 Subject: [PATCH 0394/1519] Fix package name modified post merge --- notifier.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/notifier.rst b/notifier.rst index c1b6ebfabe5..a6a8a32d9aa 100644 --- a/notifier.rst +++ b/notifier.rst @@ -54,15 +54,15 @@ to send SMS messages to mobile phones. This feature requires subscribing to a third-party service that sends SMS messages. Symfony provides integration with a couple popular SMS services: -========== =============================== ==================================================== -Service Package DSN -========== =============================== ==================================================== -Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` -Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` -OvhCloud ``symfony/ovhcloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` -Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` -FreeMobile ``symfony/freemobile-notifier`` ``freemobile://LOGIN:PASS@default?phone=PHONE`` -========== =============================== ==================================================== +========== ================================ ==================================================== +Service Package DSN +========== ================================ ==================================================== +Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` +Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` +OvhCloud ``symfony/ovhcloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` +Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` +FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` +========== ================================ ==================================================== .. versionadded:: 5.1 From 2fdc9caeb4649af80539f1f89ec7a9f9f6e95152 Mon Sep 17 00:00:00 2001 From: Mohammad Emran Hasan Date: Thu, 30 Apr 2020 15:42:31 +0600 Subject: [PATCH 0395/1519] [Notifier] Add Zulip entry --- notifier.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/notifier.rst b/notifier.rst index f832cd01780..daba65356de 100644 --- a/notifier.rst +++ b/notifier.rst @@ -125,14 +125,15 @@ The chat channel is used to send chat messages to users by using :class:`Symfony\\Component\\Notifier\\Chatter` classes. Symfony provides integration with these chat services: -========== =============================== ============================================ +========== =============================== ================================================= Service Package DSN -========== =============================== ============================================ +========== =============================== ================================================= Slack ``symfony/slack-notifier`` ``slack://default/ID`` Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` Mattermost ``symfony/mattermost-notifier`` ``mattermost://TOKEN@ENDPOINT?channel=CHANNEL`` RocketChat ``symfony/rocketchat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` -========== =============================== ============================================ +Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:APIKEY@ENDPOINT?channel=CHANNEL`` +========== =============================== ================================================= .. versionadded:: 5.1 @@ -140,6 +141,10 @@ RocketChat ``symfony/rocketchat-notifier`` ``rocketchat://TOKEN@ENDPOINT?chann 5.1. The Slack DSN changed in Symfony 5.1 to use Slack Incoming Webhooks instead of legacy tokens. +.. versionadded:: 5.2 + + The Zulip integration was introduced in Symfony 5.2. + Chatters are configured using the ``chatter_transports`` setting: .. code-block:: bash From e1c774bab6c795e5a1938cab9734d1142168b8d0 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 21 Aug 2020 17:03:31 +0200 Subject: [PATCH 0396/1519] [#13716] add versionadded directive --- notifier.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/notifier.rst b/notifier.rst index 380e3000610..13aa4c51246 100644 --- a/notifier.rst +++ b/notifier.rst @@ -69,6 +69,10 @@ Smsapi ``symfony/smsapi-notifier`` ``smsapi://TOKEN@default?from=FROM` The OvhCloud, Sinch and FreeMobile integrations were introduced in Symfony 5.1. +.. versionadded:: 5.2 + + The Smsapi integration was introduced in Symfony 5.2. + To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: From bc29b4c0048d176fa1a939b976564cc694dd1cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4dlich?= Date: Fri, 7 Aug 2020 12:46:23 +0200 Subject: [PATCH 0397/1519] [Notifier] Adjust notifier documentation --- notifier.rst | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/notifier.rst b/notifier.rst index 80e15e1042d..c4ab9fd660e 100644 --- a/notifier.rst +++ b/notifier.rst @@ -338,7 +338,7 @@ To send a notification, autowire the use Symfony\Component\Notifier\Notification\Notification; use Symfony\Component\Notifier\NotifierInterface; - use Symfony\Component\Notifier\Recipient\AdminRecipient; + use Symfony\Component\Notifier\Recipient\Recipient; class InvoiceController extends AbstractController { @@ -355,7 +355,7 @@ To send a notification, autowire the ->content('You got a new invoice for 15 EUR.'); // The receiver of the Notification - $recipient = new AdminRecipient( + $recipient = new Recipient( $user->getEmail(), $user->getPhonenumber() ); @@ -375,7 +375,7 @@ both an email and sms notification to the user. The default notification also has a ``content()`` and ``emoji()`` method to set the notification content and icon. -Symfony provides three types of recipients: +Symfony provides the following recipients: :class:`Symfony\\Component\\Notifier\\Recipient\\NoRecipient` This is the default and is useful when there is no need to have @@ -383,14 +383,15 @@ Symfony provides three types of recipients: the current requests's :ref:`session flashbag `; :class:`Symfony\\Component\\Notifier\\Recipient\\Recipient` - This contains only the email address of the user and can be used for - messages on the email and browser channel; - -:class:`Symfony\\Component\\Notifier\\Recipient\\AdminRecipient` This can contain both email address and phonenumber of the user. This recipient can be used for all channels (depending on whether they are actually set). +.. versionadded:: 5.2 + + The ``AdminRecipient`` class was removed in Symfony 5.2, you should use + ``Recipient`` instead. + Configuring Channel Policies ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -505,7 +506,8 @@ very high and the recipient has a phone number:: namespace App\Notifier; use Symfony\Component\Notifier\Notification\Notification; - use Symfony\Component\Notifier\Recipient\Recipient; + use Symfony\Component\Notifier\Recipient\RecipientInterface; + use Symfony\Component\Notifier\Recipient\SmsRecipientInterface; class InvoiceNotification extends Notification { @@ -516,12 +518,11 @@ very high and the recipient has a phone number:: $this->price = $price; } - public function getChannels(Recipient $recipient) + public function getChannels(RecipientInterface $recipient) { if ( $this->price > 10000 - && $recipient instanceof AdminRecipient - && null !== $recipient->getPhone() + && $recipient instanceof SmsRecipientInterface ) { return ['sms']; } @@ -545,7 +546,7 @@ and its ``asChatMessage()`` method:: use Symfony\Component\Notifier\Message\ChatMessage; use Symfony\Component\Notifier\Notification\ChatNotificationInterface; use Symfony\Component\Notifier\Notification\Notification; - use Symfony\Component\Notifier\Recipient\Recipient; + use Symfony\Component\Notifier\Recipient\SmsRecipientInterface; class InvoiceNotification extends Notification implements ChatNotificationInterface { @@ -556,7 +557,7 @@ and its ``asChatMessage()`` method:: $this->price = $price; } - public function asChatMessage(Recipient $recipient, string $transport = null): ?ChatMessage + public function asChatMessage(RecipientInterface $recipient, string $transport = null): ?ChatMessage { // Add a custom emoji if the message is sent to Slack if ('slack' === $transport) { From 7bfacde00a13c34fe94370d80109ce2b531eca35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20TAMARELLE?= Date: Fri, 31 Jul 2020 18:53:14 +0200 Subject: [PATCH 0398/1519] [Notifier] Add GoogleChat to the list of supported chat transports --- notifier.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/notifier.rst b/notifier.rst index cbb9ce65dc2..a3d21bb3f76 100644 --- a/notifier.rst +++ b/notifier.rst @@ -133,15 +133,16 @@ The chat channel is used to send chat messages to users by using :class:`Symfony\\Component\\Notifier\\Chatter` classes. Symfony provides integration with these chat services: -========== =============================== ================================================= +========== =============================== ============================================================================ Service Package DSN -========== =============================== ================================================= +========== =============================== ============================================================================ Slack ``symfony/slack-notifier`` ``slack://default/ID`` Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` +GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?threadKey=THREAD_KEY`` Mattermost ``symfony/mattermost-notifier`` ``mattermost://TOKEN@ENDPOINT?channel=CHANNEL`` RocketChat ``symfony/rocketchat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:APIKEY@ENDPOINT?channel=CHANNEL`` -========== =============================== ================================================= +========== =============================== ============================================================================ .. versionadded:: 5.1 @@ -151,7 +152,7 @@ Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:APIKEY@ENDPOINT?cha .. versionadded:: 5.2 - The Zulip integration was introduced in Symfony 5.2. + The GoogleChat and Zulip integrations were introduced in Symfony 5.2. Chatters are configured using the ``chatter_transports`` setting: From e7bc75f4eca455a4484f8060a8d15dd4d800d9cc Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 22 Aug 2020 13:18:40 +0200 Subject: [PATCH 0399/1519] fix table markup --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 488db6b878b..bb1aa53fb6c 100644 --- a/notifier.rst +++ b/notifier.rst @@ -55,7 +55,7 @@ a third-party service that sends SMS messages. Symfony provides integration with a couple popular SMS services: ========== ================================ ==================================================== -Service Package DSN +Service Package DSN ========== ================================ ==================================================== Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` From 157a21b47f1ce91fe741db3994315674adbca5d6 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 22 Aug 2020 13:34:41 +0200 Subject: [PATCH 0400/1519] fix table markup --- notifier.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/notifier.rst b/notifier.rst index bb1aa53fb6c..858deeacfee 100644 --- a/notifier.rst +++ b/notifier.rst @@ -133,16 +133,16 @@ The chat channel is used to send chat messages to users by using :class:`Symfony\\Component\\Notifier\\Chatter` classes. Symfony provides integration with these chat services: -========== =============================== ============================================================================ -Service Package DSN -========== =============================== ============================================================================ +========== ================================ ============================================================================ +Service Package DSN +========== ================================ ============================================================================ Slack ``symfony/slack-notifier`` ``slack://default/ID`` Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?threadKey=THREAD_KEY`` Mattermost ``symfony/mattermost-notifier`` ``mattermost://TOKEN@ENDPOINT?channel=CHANNEL`` RocketChat ``symfony/rocketchat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:APIKEY@ENDPOINT?channel=CHANNEL`` -========== =============================== ============================================================================ +========== ================================ ============================================================================ .. versionadded:: 5.1 From ff655425243bf4a0a584168a06ec755942c214dd Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 22 Aug 2020 13:54:42 +0200 Subject: [PATCH 0401/1519] finally fix the table markup --- notifier.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/notifier.rst b/notifier.rst index 858deeacfee..32455105550 100644 --- a/notifier.rst +++ b/notifier.rst @@ -136,12 +136,12 @@ integration with these chat services: ========== ================================ ============================================================================ Service Package DSN ========== ================================ ============================================================================ -Slack ``symfony/slack-notifier`` ``slack://default/ID`` -Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` +Slack ``symfony/slack-notifier`` ``slack://default/ID`` +Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?threadKey=THREAD_KEY`` -Mattermost ``symfony/mattermost-notifier`` ``mattermost://TOKEN@ENDPOINT?channel=CHANNEL`` -RocketChat ``symfony/rocketchat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` -Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:APIKEY@ENDPOINT?channel=CHANNEL`` +Mattermost ``symfony/mattermost-notifier`` ``mattermost://TOKEN@ENDPOINT?channel=CHANNEL`` +RocketChat ``symfony/rocketchat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` +Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:APIKEY@ENDPOINT?channel=CHANNEL`` ========== ================================ ============================================================================ .. versionadded:: 5.1 From b7928e520f0057542a4743d95447fc1e9b2bbb17 Mon Sep 17 00:00:00 2001 From: tambait Date: Tue, 25 Aug 2020 13:35:36 +0200 Subject: [PATCH 0402/1519] [Notifier] Fix wrong package name for the RocketChat service --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index a6a8a32d9aa..be0a87937d9 100644 --- a/notifier.rst +++ b/notifier.rst @@ -134,7 +134,7 @@ Service Package DSN Slack ``symfony/slack-notifier`` ``slack://default/ID`` Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` Mattermost ``symfony/mattermost-notifier`` ``mattermost://TOKEN@ENDPOINT?channel=CHANNEL`` -RocketChat ``symfony/rocketchat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` +RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` ========== =============================== ============================================ .. versionadded:: 5.1 From 0847c868631ad49c964eba2b0414f61bc2f170f6 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 25 Aug 2020 14:19:07 +0200 Subject: [PATCH 0403/1519] Fix: Indention --- notifier.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/notifier.rst b/notifier.rst index eb204af9067..4dafd6d63b6 100644 --- a/notifier.rst +++ b/notifier.rst @@ -57,12 +57,12 @@ with a couple popular SMS services: ========== ================================ ==================================================== Service Package DSN ========== ================================ ==================================================== -Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` -Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` -OvhCloud ``symfony/ovhcloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` -Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` -FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` -Smsapi ``symfony/smsapi-notifier`` ``smsapi://TOKEN@default?from=FROM`` +Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` +Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` +OvhCloud ``symfony/ovhcloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` +Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` +FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` +Smsapi ``symfony/smsapi-notifier`` ``smsapi://TOKEN@default?from=FROM`` ========== ================================ ==================================================== .. versionadded:: 5.1 From f526431fe423a0a7e3e6ffc4c3e2ddb4d515f112 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 25 Aug 2020 18:17:03 +0200 Subject: [PATCH 0404/1519] fix table markup --- notifier.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/notifier.rst b/notifier.rst index be0a87937d9..7aab8e37de0 100644 --- a/notifier.rst +++ b/notifier.rst @@ -128,14 +128,14 @@ The chat channel is used to send chat messages to users by using :class:`Symfony\\Component\\Notifier\\Chatter` classes. Symfony provides integration with these chat services: -========== =============================== ============================================ -Service Package DSN -========== =============================== ============================================ -Slack ``symfony/slack-notifier`` ``slack://default/ID`` -Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` -Mattermost ``symfony/mattermost-notifier`` ``mattermost://TOKEN@ENDPOINT?channel=CHANNEL`` -RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` -========== =============================== ============================================ +========== ================================ ============================================ +Service Package DSN +========== ================================ ============================================ +Slack ``symfony/slack-notifier`` ``slack://default/ID`` +Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` +Mattermost ``symfony/mattermost-notifier`` ``mattermost://TOKEN@ENDPOINT?channel=CHANNEL`` +RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` +========== ================================ ============================================ .. versionadded:: 5.1 From 883dc985a43b826528a37a7721a1c2754104dc5e Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER Date: Sat, 15 Aug 2020 18:52:12 +0200 Subject: [PATCH 0405/1519] RedisTagAwareAdapter integration --- cache.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cache.rst b/cache.rst index d29265d5f7f..1cb422990c3 100644 --- a/cache.rst +++ b/cache.rst @@ -102,6 +102,11 @@ The Cache component comes with a series of adapters pre-configured: * :doc:`cache.adapter.pdo ` * :doc:`cache.adapter.psr6 ` * :doc:`cache.adapter.redis ` +* :ref:`cache.adapter.redis_tag_aware ` (Redis adapter optimized to work with tags) + +.. versionadded:: 5.2 + + ``cache.adapter.redis_tag_aware`` has been introduced in Symfony 5.2. Some of these adapters could be configured via shortcuts. Using these shortcuts will create pools with service IDs that follow the pattern ``cache.[type]``. From 8631322f7e0144b0ff11cb5c0df29ed053e5d52e Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Tue, 25 Aug 2020 17:39:42 +0200 Subject: [PATCH 0406/1519] [PropertyAccess] Allow to disable magic __get & __set --- components/property_access.rst | 34 +++++++++++++++++++++------ reference/configuration/framework.rst | 28 ++++++++++++++++++++++ 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/components/property_access.rst b/components/property_access.rst index df0f3d99b51..7c8390f9a24 100644 --- a/components/property_access.rst +++ b/components/property_access.rst @@ -191,6 +191,8 @@ method:: $value = $propertyAccessor->getValue($person, 'birthday'); +.. _components-property-access-magic-get: + Magic ``__get()`` Method ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -213,6 +215,11 @@ The ``getValue()`` method can also use the magic ``__get()`` method:: var_dump($propertyAccessor->getValue($person, 'Wouter')); // [...] +.. versionadded:: 5.2 + + The magic `__get` method can be disabled since in Symfony 5.2. + see `Enable other Features`_. + .. _components-property-access-magic-call: Magic ``__call()`` Method @@ -273,6 +280,8 @@ also write to an array. This can be achieved using the // or // var_dump($person['first_name']); // 'Wouter' +.. _components-property-access-writing-to-objects: + Writing to Objects ------------------ @@ -351,6 +360,11 @@ see `Enable other Features`_:: var_dump($person->getWouter()); // [...] +.. versionadded:: 5.2 + + The magic `__set` method can be disabled since in Symfony 5.2. + see `Enable other Features`_. + Writing to Array Properties ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -461,14 +475,20 @@ configured to enable extra features. To do that you could use the // ... $propertyAccessorBuilder = PropertyAccess::createPropertyAccessorBuilder(); - // enables magic __call - $propertyAccessorBuilder->enableMagicCall(); + $propertyAccessorBuilder->enableMagicCall(); // enables magic __call + $propertyAccessorBuilder->enableMagicGet(); // enables magic __get + $propertyAccessorBuilder->enableMagicSet(); // enables magic __set + $propertyAccessorBuilder->enableMagicMethods(); // enables magic __get, __set and __call - // disables magic __call - $propertyAccessorBuilder->disableMagicCall(); + $propertyAccessorBuilder->disableMagicCall(); // enables magic __call + $propertyAccessorBuilder->disableMagicGet(); // enables magic __get + $propertyAccessorBuilder->disableMagicSet(); // enables magic __set + $propertyAccessorBuilder->disableMagicMethods(); // enables magic __get, __set and __call - // checks if magic __call handling is enabled + // checks if magic __call, __get or __set handling are enabled $propertyAccessorBuilder->isMagicCallEnabled(); // true or false + $propertyAccessorBuilder->isMagicGetEnabled(); // true or false + $propertyAccessorBuilder->isMagicSetEnabled(); // true or false // At the end get the configured property accessor $propertyAccessor = $propertyAccessorBuilder->getPropertyAccessor(); @@ -480,7 +500,7 @@ configured to enable extra features. To do that you could use the Or you can pass parameters directly to the constructor (not the recommended way):: - // ... - $propertyAccessor = new PropertyAccessor(true); // this enables handling of magic __call + // enable handling of magic __call, __set but not __get: + $propertyAccessor = new PropertyAccessor(PropertyAccessor::MAGIC_CALL | PropertyAccessor::MAGIC_SET); .. _The Inflector component: https://github.com/symfony/inflector diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 6c64626f07a..3db77d3c328 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -167,6 +167,8 @@ Configuration * `property_access`_ * `magic_call`_ + * `magic_get`_ + * `magic_set`_ * `throw_exception_on_invalid_index`_ * `throw_exception_on_invalid_property_path`_ @@ -2127,6 +2129,32 @@ When enabled, the ``property_accessor`` service uses PHP's :ref:`magic __call() method ` when its ``getValue()`` method is called. +magic_get +......... + +**type**: ``boolean`` **default**: ``true`` + +When enabled, the ``property_accessor`` service uses PHP's +:ref:`magic __get() method ` when +its ``getValue()`` method is called. + +.. versionadded:: 5.2 + + The magic `magic_get` option was introduced in Symfony 5.2. + +magic_set +......... + +**type**: ``boolean`` **default**: ``true`` + +When enabled, the ``property_accessor`` service uses PHP's +:ref:`magic __set() method ` when +its ``setValue()`` method is called. + +.. versionadded:: 5.2 + + The magic `magic_set` option was introduced in Symfony 5.2. + throw_exception_on_invalid_index ................................ From 27f13a880fe9c46140763207a56caf36a862940a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Wed, 26 Aug 2020 10:56:09 +0200 Subject: [PATCH 0407/1519] Change the way to create table in Lock PDO --- components/lock.rst | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index cc14aa01334..95734c22c2e 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -350,25 +350,11 @@ support blocking, and expects a TTL to avoid stalled locks:: This store does not support TTL lower than 1 second. -Before storing locks in the database, you must create the table that stores -the information. The store provides a method called -:method:`Symfony\\Component\\Lock\\Store\\PdoStore::createTable` -to set up this table for you according to the database engine used:: - - try { - $store->createTable(); - } catch (\PDOException $exception) { - // the table could not be created for some reason - } - -A great way to set up the table in production is to call the ``createTable()`` -method in your local computer and then generate a -:ref:`database migration `: - -.. code-block:: terminal - - $ php bin/console doctrine:migrations:diff - $ php bin/console doctrine:migrations:migrate +The table where values are stored is created automatically on the first call to +the :method:`Symfony\\Component\\Lock\\Store\\PdoStore::save` method. +You can also create this table explicitly by calling the +:method:`Symfony\\Component\\Lock\\Store\\PdoStore::createTable` method in +your code. .. _lock-store-redis: From 6d37db16e3fce3965d4dbd644e21980801cab66b Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 26 Aug 2020 11:21:55 +0200 Subject: [PATCH 0408/1519] minor #14055 --- routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routing.rst b/routing.rst index 0b675a67a60..188ba1d8fba 100644 --- a/routing.rst +++ b/routing.rst @@ -1881,7 +1881,7 @@ Now, if the session is used, the application will report it based on your * ``enabled``: will throw an :class:`Symfony\\Component\\HttpKernel\\Exception\\UnexpectedSessionUsageException` exception * ``disabled``: will log a warning -It will help you in understanding and hopefully fixing unexpected behavior in your application. +It will help you understand and hopefully fixing unexpected behavior in your application. .. _routing-generating-urls: From 9a74dce178cbacaee4dacda8b6b3113ebf776d8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Wed, 26 Aug 2020 12:44:50 +0200 Subject: [PATCH 0409/1519] Document RecoverableMessageHandlingException --- messenger.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/messenger.rst b/messenger.rst index f334ae66b89..ff43fd0ec08 100644 --- a/messenger.rst +++ b/messenger.rst @@ -725,6 +725,15 @@ and should not be retried. If you throw :class:`Symfony\\Component\\Messenger\\Exception\\UnrecoverableMessageHandlingException`, the message will not be retried. + +Forcing Retrying +~~~~~~~~~~~~~~~~ + +Sometimes handling a message must fail in a way that you *know* is temporary +and must be retried. If you throw +:class:`Symfony\\Component\\Messenger\\Exception\\RecoverableMessageHandlingException`, +the message will always be retried. + .. _messenger-failure-transport: Saving & Retrying Failed Messages From 5f6f585aec060aff8fe6571daeb4ca1eb7e29286 Mon Sep 17 00:00:00 2001 From: Gary PEGEOT Date: Fri, 28 Aug 2020 11:39:19 +0200 Subject: [PATCH 0410/1519] [HTTP_CLIENT] Add documentation for "mock_response_factory" --- http_client.rst | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/http_client.rst b/http_client.rst index 33e6c9732dd..5eb3b09f711 100644 --- a/http_client.rst +++ b/http_client.rst @@ -1373,6 +1373,82 @@ However, using ``MockResponse`` allows simulating chunked responses and timeouts $mockResponse = new MockResponse($body()); +Using the Symfony Framework, if you want to use your callback in functional tests, you can do as follow: + +First, create an invokable or iterable class responsible of generating the response:: + + namespace App\Tests; + + use Symfony\Contracts\HttpClient\ResponseInterface; + use Symfony\Component\HttpClient\Response\MockResponse; + + class MockClientCallback + { + public function __invoke(string $method, string $url, array $options = []): ResponseInterface + { + // load a fixture file or generate data + // ... + return new MockResponse($data); + } + } + +Then configure the framework to use your callback: + +.. configuration-block:: + + .. code-block:: yaml + + # config/services_test.yaml + services: + # ... + App\Tests\MockClientCallback: ~ + + # config/packages/test/framework.yaml + framework: + http_client: + mock_response_factory: App\Tests\MockClientCallback + + .. code-block:: xml + + + + + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/framework.php + $container->loadFromExtension('framework', [ + 'http_client' => [ + 'mock_response_factory' => MockClientCallback::class, + ], + ]); + + +The ``MockHttpClient`` will now be used in test environment with your callback to generate responses. + .. _`cURL PHP extension`: https://www.php.net/curl .. _`PSR-17`: https://www.php-fig.org/psr/psr-17/ .. _`PSR-18`: https://www.php-fig.org/psr/psr-18/ From 6a3b3554a7d3163a8199d740903558040e828c57 Mon Sep 17 00:00:00 2001 From: Valentin Date: Fri, 28 Aug 2020 23:42:48 +0200 Subject: [PATCH 0411/1519] [Serializer] Add an @Ignore annotation #28744 Update serializer.rst Update components/serializer.rst Co-authored-by: Oskar Stark Update components/serializer.rst Co-authored-by: Antoine Makdessi Update components/serializer.rst Co-authored-by: Antoine Makdessi Update components/serializer.rst Co-authored-by: Oskar Stark Update components/serializer.rst Co-authored-by: Antoine Makdessi Update serializer.rst --- components/serializer.rst | 77 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/components/serializer.rst b/components/serializer.rst index ef205bf59be..b3735deb32a 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -413,8 +413,81 @@ As for groups, attributes can be selected during both the serialization and dese Ignoring Attributes ------------------- -As an option, there's a way to ignore attributes from the origin object. -To remove those attributes provide an array via the ``AbstractNormalizer::IGNORED_ATTRIBUTES`` +All attributes are included by default when serializing objects. You have two alternatives to ignore some of those attributes. + +* `Option 1: Using @Ignore annotation`_ +* `Option 2: Using the context`_ + +Option 1: Using ``@Ignore`` annotation +-------------------------------------- + +.. configuration-block:: + + .. code-block:: php-annotations + + namespace App\Model; + + use Symfony\Component\Serializer\Annotation\Ignore; + + class MyClass + { + public $foo; + + /** + * @Ignore() + */ + public $bar; + } + + .. code-block:: yaml + + App\Model\MyClass: + attributes: + foo: + ignore: false + bar: + ignore: true + + .. code-block:: xml + + + + + + false + + + + true + + + + +You are now able to ignore specific attributes during serialization:: + + use App\Model\MyClass; + use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; + use Symfony\Component\Serializer\Serializer; + + $obj = new MyClass(); + $obj->foo = 'foo'; + $obj->bar = 'bar'; + + $normalizer = new ObjectNormalizer($classMetadataFactory); + $serializer = new Serializer([$normalizer]); + + $data = $serializer->normalize($obj); + // $data = ['foo' => 'foo']; + + +Option 2: Using the context +--------------------------- + +By providing an array via the ``AbstractNormalizer::IGNORED_ATTRIBUTES`` key in the ``context`` parameter of the desired serializer method:: use Acme\Person; From 57cfedbfd15ebd7f65e76f847dd86f22164829be Mon Sep 17 00:00:00 2001 From: Stewart Malik Date: Sun, 23 Aug 2020 18:35:49 +0930 Subject: [PATCH 0412/1519] [Workflow] Choose which Workflow events should be dispatched --- workflow.rst | 169 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 159 insertions(+), 10 deletions(-) diff --git a/workflow.rst b/workflow.rst index 21ae4192d58..c44b821b3ce 100644 --- a/workflow.rst +++ b/workflow.rst @@ -351,14 +351,6 @@ order: * ``workflow.[workflow name].announce`` * ``workflow.[workflow name].announce.[transition name]`` - You can avoid triggering those events by using the context:: - - $workflow->apply($subject, $transitionName, [Workflow::DISABLE_ANNOUNCE_EVENT => true]); - - .. versionadded:: 5.1 - - The ``Workflow::DISABLE_ANNOUNCE_EVENT`` constant was introduced in Symfony 5.1. - .. note:: The leaving and entering events are triggered even for transitions that stay @@ -452,6 +444,163 @@ missing a title:: The optional second argument of ``setBlocked()`` was introduced in Symfony 5.1. +Choosing which Events to Dispatch +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.2 + + Ability to choose which events to dispatch was introduced in Symfony 5.2. + +You are able to specify which events (does not apply to Guard event) will be +fired when performing each transition by passing an array of workflow events +to the ``events_to_dispatch`` configuration option. + +Valid options for ``events_to_dispatch`` are: + + * ``null`` - all events are dispatched + * ``[]`` - no events are dispatched + * ``['workflow.leave', 'workflow.completed']`` - only specific events are dispatched + +.. note:: + + Guard Events are still dispatched in all instances. + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/workflow.yaml + framework: + workflows: + blog_publishing: + # ... + events_to_dispatch: ['workflow.leave', 'workflow.completed'] + # ... + + .. code-block:: xml + + + + + + + + workflow.leave + workflow.completed + + + + + + .. code-block:: php + + // config/packages/workflow.php + $container->loadFromExtension('framework', [ + // ... + 'workflows' => [ + 'blog_publishing' => [ + // ... + 'events_to_dispatch' => [ + 'workflow.leave', + 'workflow.completed', + ], + // ... + ], + ], + ]); + +To specify that no events will be dispatched pass an empty array to the +configuration option. + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/workflow.yaml + framework: + workflows: + blog_publishing: + # ... + events_to_dispatch: [] + # ... + + .. code-block:: xml + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/workflow.php + $container->loadFromExtension('framework', [ + // ... + 'workflows' => [ + 'blog_publishing' => [ + // ... + 'events_to_dispatch' => [], + // ... + ], + ], + ]); + +You are also able to explicitly disable a specific event from being fired +when applying a transition:: + + use App\Entity\BlogPost; + use Symfony\Component\Workflow\Exception\LogicException; + + $post = new BlogPost(); + + $workflow = $this->container->get('workflow.blog_publishing'); + + try { + $workflow->apply($post, 'to_review', [ + Workflow::DISABLE_ANNOUNCE_EVENT => true, + Workflow::DISABLE_LEAVE_EVENT => true, + ]); + } catch (LogicException $exception) { + // ... + } + +Choosing to disable an event for a specific transition will take precedence +over any events specified in the workflow configuration. In the above example +the ``workflow.leave`` event will not be fired, even if it has been specified +as an event to be dispatched for all transitions in the workflow configuration. + +.. versionadded:: 5.1 + + The ``Workflow::DISABLE_ANNOUNCE_EVENT`` constant was introduced in Symfony 5.1. + +.. versionadded:: 5.2 + + The constants for other events (as seen below) were introduced in Symfony 5.2. + + * ``Workflow::DISABLE_LEAVE_EVENT`` + * ``Workflow::DISABLE_TRANSITION_EVENT`` + * ``Workflow::DISABLE_ENTER_EVENT`` + * ``Workflow::DISABLE_ENTERED_EVENT`` + * ``Workflow::DISABLE_COMPLETED_EVENT`` + Event Methods ~~~~~~~~~~~~~ @@ -665,7 +814,7 @@ of domain logic in your templates: ``workflow_has_marked_place()`` Returns ``true`` if the marking of the given object has the given state. - + ``workflow_transition_blockers()`` Returns :class:`Symfony\\Component\\Workflow\\TransitionBlockerList` for the given transition. @@ -700,7 +849,7 @@ The following example shows these functions in action: {% if 'reviewed' in workflow_marked_places(post) %} Reviewed {% endif %} - + {# Loop through the transition blockers #} {% for blocker in workflow_transition_blockers(post, 'publish') %} {{ blocker.message }} From 237468ee17a8ac1c3ebad7bc278a359ebe86062c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 31 Aug 2020 09:43:11 +0200 Subject: [PATCH 0413/1519] Tweaks and rewords --- workflow.rst | 90 ++++++++++++---------------------------------------- 1 file changed, 21 insertions(+), 69 deletions(-) diff --git a/workflow.rst b/workflow.rst index c44b821b3ce..4bbd6ee8ccc 100644 --- a/workflow.rst +++ b/workflow.rst @@ -451,19 +451,9 @@ Choosing which Events to Dispatch Ability to choose which events to dispatch was introduced in Symfony 5.2. -You are able to specify which events (does not apply to Guard event) will be -fired when performing each transition by passing an array of workflow events -to the ``events_to_dispatch`` configuration option. - -Valid options for ``events_to_dispatch`` are: - - * ``null`` - all events are dispatched - * ``[]`` - no events are dispatched - * ``['workflow.leave', 'workflow.completed']`` - only specific events are dispatched - -.. note:: - - Guard Events are still dispatched in all instances. +If you prefer to control which events are fired when performing each transition, +use the ``events_to_dispatch`` configuration option. This option does not apply +to :ref:`Guard events `, which are always fired: .. configuration-block:: @@ -473,8 +463,12 @@ Valid options for ``events_to_dispatch`` are: framework: workflows: blog_publishing: - # ... + # you can pass one or more event names events_to_dispatch: ['workflow.leave', 'workflow.completed'] + + # pass an empty array to not dispatch any event + events_to_dispatch: [] + # ... .. code-block:: xml @@ -489,9 +483,13 @@ Valid options for ``events_to_dispatch`` are: > - + workflow.leave workflow.completed + + + + @@ -504,67 +502,21 @@ Valid options for ``events_to_dispatch`` are: // ... 'workflows' => [ 'blog_publishing' => [ - // ... + // you can pass one or more event names 'events_to_dispatch' => [ 'workflow.leave', 'workflow.completed', ], - // ... - ], - ], - ]); - -To specify that no events will be dispatched pass an empty array to the -configuration option. - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/workflow.yaml - framework: - workflows: - blog_publishing: - # ... - events_to_dispatch: [] - # ... - - .. code-block:: xml - - - - - - - - - - - - - - .. code-block:: php - // config/packages/workflow.php - $container->loadFromExtension('framework', [ - // ... - 'workflows' => [ - 'blog_publishing' => [ - // ... + // pass an empty array to not dispatch any event 'events_to_dispatch' => [], + // ... ], ], ]); -You are also able to explicitly disable a specific event from being fired -when applying a transition:: +You can also disable a specific event from being fired when applying a transition:: use App\Entity\BlogPost; use Symfony\Component\Workflow\Exception\LogicException; @@ -582,10 +534,10 @@ when applying a transition:: // ... } -Choosing to disable an event for a specific transition will take precedence -over any events specified in the workflow configuration. In the above example -the ``workflow.leave`` event will not be fired, even if it has been specified -as an event to be dispatched for all transitions in the workflow configuration. +Disabling an event for a specific transition will take precedence over any +events specified in the workflow configuration. In the above example the +``workflow.leave`` event will not be fired, even if it has been specified as an +event to be dispatched for all transitions in the workflow configuration. .. versionadded:: 5.1 From e492a64fed530e78bccabd5483d51c983edc128e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 31 Aug 2020 09:47:19 +0200 Subject: [PATCH 0414/1519] Removed an unneeded versionadded directive --- components/property_info.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/components/property_info.rst b/components/property_info.rst index 40b8b94ea77..d67034b04fa 100644 --- a/components/property_info.rst +++ b/components/property_info.rst @@ -293,10 +293,6 @@ string values: ``array``, ``bool``, ``callable``, ``float``, ``int``, Constants inside the :class:`Symfony\\Component\\PropertyInfo\\Type` class, in the form ``Type::BUILTIN_TYPE_*``, are provided for convenience. -.. versionadded:: 4.4 - - Support for typed properties (added in PHP 7.4) was introduced in Symfony 4.4. - ``Type::isNullable()`` ~~~~~~~~~~~~~~~~~~~~~~ From 24c1086aa16a04852c95d170751fc04ab3ca4edd Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 31 Aug 2020 10:29:14 +0200 Subject: [PATCH 0415/1519] Minor syntax fixes --- components/property_access.rst | 4 ++-- reference/configuration/framework.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/property_access.rst b/components/property_access.rst index 7c8390f9a24..c99091c4e15 100644 --- a/components/property_access.rst +++ b/components/property_access.rst @@ -217,7 +217,7 @@ The ``getValue()`` method can also use the magic ``__get()`` method:: .. versionadded:: 5.2 - The magic `__get` method can be disabled since in Symfony 5.2. + The magic ``__get()`` method can be disabled since in Symfony 5.2. see `Enable other Features`_. .. _components-property-access-magic-call: @@ -362,7 +362,7 @@ see `Enable other Features`_:: .. versionadded:: 5.2 - The magic `__set` method can be disabled since in Symfony 5.2. + The magic ``__set()`` method can be disabled since in Symfony 5.2. see `Enable other Features`_. Writing to Array Properties diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 3db77d3c328..e2015e923fa 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -2140,7 +2140,7 @@ its ``getValue()`` method is called. .. versionadded:: 5.2 - The magic `magic_get` option was introduced in Symfony 5.2. + The ``magic_get`` option was introduced in Symfony 5.2. magic_set ......... @@ -2153,7 +2153,7 @@ its ``setValue()`` method is called. .. versionadded:: 5.2 - The magic `magic_set` option was introduced in Symfony 5.2. + The ``magic_set`` option was introduced in Symfony 5.2. throw_exception_on_invalid_index ................................ From 74041eeb27f67b1b10b327bc6288df48b7aa5df2 Mon Sep 17 00:00:00 2001 From: Smaine Milianni Date: Wed, 19 Aug 2020 08:51:09 +0100 Subject: [PATCH 0416/1519] linkedin documentation wip --- notifier.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 460be529f97..6c19202a77e 100644 --- a/notifier.rst +++ b/notifier.rst @@ -142,6 +142,7 @@ GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_T Mattermost ``symfony/mattermost-notifier`` ``mattermost://TOKEN@ENDPOINT?channel=CHANNEL`` RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:APIKEY@ENDPOINT?channel=CHANNEL`` +LinkedIn ``symfony/linked-in-notifier`` ``linkedin://TOKEN:USER_ID@default`` ========== ================================ =========================================================================== .. versionadded:: 5.1 @@ -152,7 +153,7 @@ Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:APIKEY@ENDPOINT?ch .. versionadded:: 5.2 - The GoogleChat and Zulip integrations were introduced in Symfony 5.2. + The GoogleChat, LinkedIn and Zulip integrations were introduced in Symfony 5.2. Chatters are configured using the ``chatter_transports`` setting: From 56be70089e07a3d36c47bf298b1bb065d13f0030 Mon Sep 17 00:00:00 2001 From: Valentin Silvestre <17164385+vasilvestre@users.noreply.github.com> Date: Mon, 31 Aug 2020 11:44:16 +0200 Subject: [PATCH 0417/1519] Update serializer.rst --- components/serializer.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/serializer.rst b/components/serializer.rst index b3735deb32a..fefa16f55f1 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -419,7 +419,7 @@ All attributes are included by default when serializing objects. You have two al * `Option 2: Using the context`_ Option 1: Using ``@Ignore`` annotation --------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. configuration-block:: @@ -485,7 +485,7 @@ You are now able to ignore specific attributes during serialization:: Option 2: Using the context ---------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~ By providing an array via the ``AbstractNormalizer::IGNORED_ATTRIBUTES`` key in the ``context`` parameter of the desired serializer method:: From dcd5b4ce86088786de05a6ee61930137d4746c0e Mon Sep 17 00:00:00 2001 From: Valentin Silvestre <17164385+vasilvestre@users.noreply.github.com> Date: Mon, 31 Aug 2020 14:24:01 +0200 Subject: [PATCH 0418/1519] Update serializer.rst Remove default value (false) from ignoring rules in XML and YML files as I didn't put them in PHP code. --- components/serializer.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/components/serializer.rst b/components/serializer.rst index fefa16f55f1..8bc88446651 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -443,8 +443,6 @@ Option 1: Using ``@Ignore`` annotation App\Model\MyClass: attributes: - foo: - ignore: false bar: ignore: true @@ -457,10 +455,6 @@ Option 1: Using ``@Ignore`` annotation https://symfony.com/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd" > - - false - - true From 563206fc4ee10ece5b3808de156dbc37dd26c3c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Fri, 28 Aug 2020 16:08:30 +0200 Subject: [PATCH 0419/1519] [Sempahore] Added first round of documentation --- components/semaphore.rst | 79 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 components/semaphore.rst diff --git a/components/semaphore.rst b/components/semaphore.rst new file mode 100644 index 00000000000..4677b0627ba --- /dev/null +++ b/components/semaphore.rst @@ -0,0 +1,79 @@ +.. index:: + single: Semaphore + single: Components; Semaphore + +The Semaphore Component +======================= + + The Semaphore Component manages `semaphores`_, a mechanism to provide + exclusive access to a shared resource. + +.. versionadded:: 5.2 + + The Semaphore Component was introduced in Symfony 5.2. + +Installation +------------ + +.. code-block:: terminal + + $ composer require symfony/semaphore + +.. include:: /components/require_autoload.rst.inc + +Usage +----- + +Semaphore are used to guarantee exclusive access to some shared resource. + +Semaphore are created using a :class:`Symfony\\Component\\Semaphore\\SemaphoreFactory` class, +which in turn requires another class to manage the storage of Semaphore:: + + use Symfony\Component\Semaphore\SemaphoreFactory; + use Symfony\Component\Semaphore\Store\RedisStore; + + $redis = new Redis(); + $redis->connect('172.17.0.2'); + + $store = new RedisStore($redis); + $factory = new SemaphoreFactory($store); + + +The semaphore is created by calling the +:method:`Symfony\\Component\\Semaphore\\SemaphoreFactory::createSemaphore` +method. Its first argument is an arbitrary string that represents the locked +resource. Its second argument is the number of process allowed. Then, a call to +the :method:`Symfony\\Component\\Semaphore\\SemaphoreInterface::acquire` method +will try to acquire the semaphore:: + + // ... + $semaphore = $factory->createSemaphore('pdf-invoice-generation', 2); + + if ($semaphore->acquire()) { + // The resource "pdf-invoice-generation" is locked. + // You can compute and generate invoice safely here. + + $semaphore->release(); + } + +If the semaphore can not be acquired, the method returns ``false``. The +``acquire()`` method can be safely called repeatedly, even if the semaphore is +already acquired. + +.. note:: + + Unlike other implementations, the Semaphore Component distinguishes + semaphores instances even when they are created for the same resource. If a + semaphore has to be used by several services, they should share the same + ``Semaphore`` instance returned by the ``SemaphoreFactory::createSemaphore`` + method. + +.. tip:: + + If you don't release the semaphore explicitly, it will be released + automatically on instance destruction. In some cases, it can be useful to + lock a resource across several requests. To disable the automatic release + behavior, set the last argument of the ``createLock()`` method to + ``false``. + +.. _`semaphores`: https://en.wikipedia.org/wiki/Semaphore_(programming) From 4188b0a9b642a7e2a6a5cba4df1c1bd796f37b7d Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 31 Aug 2020 17:58:13 +0200 Subject: [PATCH 0420/1519] Minor tweak --- components/console/helpers/table.rst | 66 ++++++++++++++-------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/components/console/helpers/table.rst b/components/console/helpers/table.rst index d50cc160c06..aa4c293d834 100644 --- a/components/console/helpers/table.rst +++ b/components/console/helpers/table.rst @@ -265,6 +265,39 @@ Here is a full list of things you can customize: This method can also be used to override a built-in style. +.. versionadded:: 5.2 + + The option to style table cells was introduced in Symfony 5.2. + +In addition to the built-in table styles, you can also apply different styles +to each table cell via :class:`Symfony\\Component\\Console\\Helper\\TableCellStyle`:: + + use Symfony\Component\Console\Helper\Table; + use Symfony\Component\Console\Helper\TableCellStyle; + + $table = new Table($output); + + $table->setRows([ + [ + '978-0804169127', + new TableCell( + 'Divine Comedy', + [ + 'style' => new TableCellStyle([ + 'align' => 'center', + 'fg' => 'red', + 'bg' => 'green', + + // or + 'cellFormat' => '%s', + ]) + ] + ) + ], + ]); + + $table->render(); + Spanning Multiple Columns and Rows ---------------------------------- @@ -393,36 +426,3 @@ This will display the following table in the terminal: | Love | | Symfony | +---------+ - -.. versionadded:: 5.2 - -Styling of table cells ----------------------- - -You can customize a table cell via :class:`Symfony\\Component\\Console\\Helper\\TableCellStyle`:: - - use Symfony\Component\Console\Helper\Table; - use Symfony\Component\Console\Helper\TableCellStyle; - - $table = new Table($output); - - $table->setRows([ - [ - '978-0804169127', - new TableCell( - 'Divine Comedy', - [ - 'style' => new TableCellStyle([ - 'align' => 'center', - 'fg' => 'red', - 'bg' => 'green', - - // or - 'cellFormat' => '%s', - ]) - ] - ) - ], - ]); - - $table->render(); From d6331b371dc71e0c730fb397440eb7b53393bd26 Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER Date: Tue, 1 Sep 2020 15:22:14 +0200 Subject: [PATCH 0421/1519] Add documentation about quiet configuration --- components/phpunit_bridge.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 2b6ad5f5e1b..fc7c0d6ae2e 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -296,6 +296,8 @@ By default, the bridge will display a detailed output with the number of deprecations and where they arise. If this is too much for you, you can use ``SYMFONY_DEPRECATIONS_HELPER=verbose=0`` to turn the verbose output off. +It's also possible to change verbosity per deprecation type, for instance ``quiet[]=indirect&quiet[]=other`` will hide details for deprecations of types "indirect" and "other". + Disabling the Deprecation Helper ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 3c9e289e31b2cb84f8969a0e36ed9abdaa6ecfc3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 3 Sep 2020 17:51:42 +0200 Subject: [PATCH 0422/1519] Minor tweak --- components/serializer.rst | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/components/serializer.rst b/components/serializer.rst index 8bc88446651..6f15604325e 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -413,12 +413,10 @@ As for groups, attributes can be selected during both the serialization and dese Ignoring Attributes ------------------- -All attributes are included by default when serializing objects. You have two alternatives to ignore some of those attributes. +All attributes are included by default when serializing objects. There are two +options to ignore some of those attributes. -* `Option 1: Using @Ignore annotation`_ -* `Option 2: Using the context`_ - -Option 1: Using ``@Ignore`` annotation +Option 1: Using ``@Ignore`` Annotation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. configuration-block:: @@ -461,7 +459,7 @@ Option 1: Using ``@Ignore`` annotation -You are now able to ignore specific attributes during serialization:: +You can now ignore specific attributes during serialization:: use App\Model\MyClass; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; @@ -477,12 +475,12 @@ You are now able to ignore specific attributes during serialization:: $data = $serializer->normalize($obj); // $data = ['foo' => 'foo']; - -Option 2: Using the context +Option 2: Using the Context ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -By providing an array via the ``AbstractNormalizer::IGNORED_ATTRIBUTES`` -key in the ``context`` parameter of the desired serializer method:: +Pass an array with the names of the attributes to ignore using the +``AbstractNormalizer::IGNORED_ATTRIBUTES`` key in the ``context`` of the +serializer method:: use Acme\Person; use Symfony\Component\Serializer\Encoder\JsonEncoder; @@ -805,7 +803,7 @@ There are several types of normalizers available: :class:`Symfony\\Component\\Serializer\\Normalizer\\ProblemNormalizer` Normalizes errors according to the API Problem spec `RFC 7807`_. - + .. _component-serializer-encoders: Encoders From e2989290cf3a28ebcc454d1cb13354116744e5cf Mon Sep 17 00:00:00 2001 From: Zmey Date: Thu, 3 Sep 2020 01:21:08 +0300 Subject: [PATCH 0423/1519] Added support for using the "{{ label }}" placeholder in constraint messages --- components/form.rst | 5 +++++ forms.rst | 5 +++++ reference/constraints/Blank.rst | 5 +++++ reference/constraints/CardScheme.rst | 5 +++++ reference/constraints/Choice.rst | 5 +++++ reference/constraints/Currency.rst | 5 +++++ reference/constraints/Date.rst | 5 +++++ reference/constraints/DateTime.rst | 5 +++++ reference/constraints/Email.rst | 5 +++++ reference/constraints/Expression.rst | 5 +++++ reference/constraints/Hostname.rst | 5 +++++ reference/constraints/Iban.rst | 5 +++++ reference/constraints/Ip.rst | 5 +++++ reference/constraints/IsFalse.rst | 5 +++++ reference/constraints/IsNull.rst | 5 +++++ reference/constraints/IsTrue.rst | 5 +++++ reference/constraints/Isbn.rst | 20 ++++++++++++++++++++ reference/constraints/Isin.rst | 5 +++++ reference/constraints/Issn.rst | 5 +++++ reference/constraints/Language.rst | 5 +++++ reference/constraints/Locale.rst | 5 +++++ reference/constraints/Luhn.rst | 5 +++++ reference/constraints/NotBlank.rst | 5 +++++ reference/constraints/NotNull.rst | 5 +++++ reference/constraints/Range.rst | 5 +++++ reference/constraints/Regex.rst | 5 +++++ reference/constraints/Time.rst | 5 +++++ reference/constraints/Timezone.rst | 5 +++++ reference/constraints/Type.rst | 5 +++++ reference/constraints/UniqueEntity.rst | 5 +++++ reference/constraints/Url.rst | 5 +++++ reference/constraints/Uuid.rst | 5 +++++ 32 files changed, 175 insertions(+) diff --git a/components/form.rst b/components/form.rst index 7ac59478ceb..cdcf9ee54a8 100644 --- a/components/form.rst +++ b/components/form.rst @@ -728,6 +728,11 @@ and the errors will display next to the fields on error. For a list of all of the built-in validation constraints, see :doc:`/reference/constraints`. +.. versionadded:: 5.2 + + Constraint message can contains ``{{ label }}`` placeholder that will be replaced + by corresponding form field label (in view of ``label_format`` option). + Accessing Form Errors ~~~~~~~~~~~~~~~~~~~~~ diff --git a/forms.rst b/forms.rst index 02336d32169..9ab6b2101ab 100644 --- a/forms.rst +++ b/forms.rst @@ -548,6 +548,11 @@ corresponding errors printed out with the form. Read the :doc:`Symfony validation documentation ` to learn more about this powerful feature. +.. versionadded:: 5.2 + + Constraint message can contains ``{{ label }}`` placeholder that will be replaced + by corresponding form field label (in view of ``label_format`` option). + Other Common Form Features -------------------------- diff --git a/reference/constraints/Blank.rst b/reference/constraints/Blank.rst index 5f0c6191fc1..8a5ba13671a 100644 --- a/reference/constraints/Blank.rst +++ b/reference/constraints/Blank.rst @@ -102,6 +102,11 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/CardScheme.rst b/reference/constraints/CardScheme.rst index 6adfe62d893..64d6157e2c8 100644 --- a/reference/constraints/CardScheme.rst +++ b/reference/constraints/CardScheme.rst @@ -112,8 +112,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc schemes diff --git a/reference/constraints/Choice.rst b/reference/constraints/Choice.rst index 707bfd11bc5..fd8481d6152 100644 --- a/reference/constraints/Choice.rst +++ b/reference/constraints/Choice.rst @@ -392,6 +392,11 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Currency.rst b/reference/constraints/Currency.rst index 901a989010b..651af1b1a92 100644 --- a/reference/constraints/Currency.rst +++ b/reference/constraints/Currency.rst @@ -94,8 +94,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc .. _`3-letter ISO 4217`: https://en.wikipedia.org/wiki/ISO_4217 diff --git a/reference/constraints/Date.rst b/reference/constraints/Date.rst index db55de84dd6..4b1e99c3ed1 100644 --- a/reference/constraints/Date.rst +++ b/reference/constraints/Date.rst @@ -98,6 +98,11 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/DateTime.rst b/reference/constraints/DateTime.rst index 41b4db2acc0..582f93aeac8 100644 --- a/reference/constraints/DateTime.rst +++ b/reference/constraints/DateTime.rst @@ -107,6 +107,11 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Email.rst b/reference/constraints/Email.rst index ce8d428858a..468051004a0 100644 --- a/reference/constraints/Email.rst +++ b/reference/constraints/Email.rst @@ -101,8 +101,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + mode ~~~~ diff --git a/reference/constraints/Expression.rst b/reference/constraints/Expression.rst index f3af00f1d3a..2ed816f3a03 100644 --- a/reference/constraints/Expression.rst +++ b/reference/constraints/Expression.rst @@ -260,8 +260,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc values diff --git a/reference/constraints/Hostname.rst b/reference/constraints/Hostname.rst index 4cbe606ccb4..9e67fb3c8fc 100644 --- a/reference/constraints/Hostname.rst +++ b/reference/constraints/Hostname.rst @@ -110,8 +110,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc ``requireTld`` diff --git a/reference/constraints/Iban.rst b/reference/constraints/Iban.rst index aa3caeb67f8..709270f7b12 100644 --- a/reference/constraints/Iban.rst +++ b/reference/constraints/Iban.rst @@ -108,8 +108,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc .. _`International Bank Account Number (IBAN)`: https://en.wikipedia.org/wiki/International_Bank_Account_Number diff --git a/reference/constraints/Ip.rst b/reference/constraints/Ip.rst index 60865c024bc..9d744d54c09 100644 --- a/reference/constraints/Ip.rst +++ b/reference/constraints/Ip.rst @@ -95,8 +95,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_normalizer-option.rst.inc .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/IsFalse.rst b/reference/constraints/IsFalse.rst index 861072a1250..17881aa9a75 100644 --- a/reference/constraints/IsFalse.rst +++ b/reference/constraints/IsFalse.rst @@ -125,6 +125,11 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/IsNull.rst b/reference/constraints/IsNull.rst index 2bded13311d..252c23d934b 100644 --- a/reference/constraints/IsNull.rst +++ b/reference/constraints/IsNull.rst @@ -96,6 +96,11 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/IsTrue.rst b/reference/constraints/IsTrue.rst index 2066b6d4e73..2698ad233e9 100644 --- a/reference/constraints/IsTrue.rst +++ b/reference/constraints/IsTrue.rst @@ -129,6 +129,11 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Isbn.rst b/reference/constraints/Isbn.rst index d2ad1e2c909..e30d4e96040 100644 --- a/reference/constraints/Isbn.rst +++ b/reference/constraints/Isbn.rst @@ -109,8 +109,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_groups-option.rst.inc isbn10Message @@ -127,8 +132,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + isbn13Message ~~~~~~~~~~~~~ @@ -143,8 +153,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + message ~~~~~~~ @@ -159,8 +174,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc type diff --git a/reference/constraints/Isin.rst b/reference/constraints/Isin.rst index 86c1c3a3973..c646f33a53a 100644 --- a/reference/constraints/Isin.rst +++ b/reference/constraints/Isin.rst @@ -92,8 +92,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc .. _`International Securities Identification Number (ISIN)`: https://en.wikipedia.org/wiki/International_Securities_Identification_Number diff --git a/reference/constraints/Issn.rst b/reference/constraints/Issn.rst index 374cc7d2751..6cc5734aaa2 100644 --- a/reference/constraints/Issn.rst +++ b/reference/constraints/Issn.rst @@ -102,8 +102,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc requireHyphen diff --git a/reference/constraints/Language.rst b/reference/constraints/Language.rst index 7d58491c416..dac3e2819db 100644 --- a/reference/constraints/Language.rst +++ b/reference/constraints/Language.rst @@ -106,8 +106,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc .. _`ISO 639-1`: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes diff --git a/reference/constraints/Locale.rst b/reference/constraints/Locale.rst index dbdf0905df5..f5f381629e3 100644 --- a/reference/constraints/Locale.rst +++ b/reference/constraints/Locale.rst @@ -107,8 +107,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc .. _`ICU format locale IDs`: http://userguide.icu-project.org/locale diff --git a/reference/constraints/Luhn.rst b/reference/constraints/Luhn.rst index 6d322349da4..2bee41d5f2c 100644 --- a/reference/constraints/Luhn.rst +++ b/reference/constraints/Luhn.rst @@ -101,8 +101,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc .. _`Luhn algorithm`: https://en.wikipedia.org/wiki/Luhn_algorithm diff --git a/reference/constraints/NotBlank.rst b/reference/constraints/NotBlank.rst index c3c16f21eae..f5711e001c3 100644 --- a/reference/constraints/NotBlank.rst +++ b/reference/constraints/NotBlank.rst @@ -105,8 +105,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_normalizer-option.rst.inc .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/NotNull.rst b/reference/constraints/NotNull.rst index 2c548b2eb3e..56d088c4cba 100644 --- a/reference/constraints/NotNull.rst +++ b/reference/constraints/NotNull.rst @@ -94,6 +94,11 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Range.rst b/reference/constraints/Range.rst index 6e7fc8d7f86..4470d26eb07 100644 --- a/reference/constraints/Range.rst +++ b/reference/constraints/Range.rst @@ -330,8 +330,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + max ~~~ diff --git a/reference/constraints/Regex.rst b/reference/constraints/Regex.rst index d7e3c8f2ebd..642a1fc180d 100644 --- a/reference/constraints/Regex.rst +++ b/reference/constraints/Regex.rst @@ -275,8 +275,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + pattern ~~~~~~~ diff --git a/reference/constraints/Time.rst b/reference/constraints/Time.rst index a8e362d22dc..e94613e1f6f 100644 --- a/reference/constraints/Time.rst +++ b/reference/constraints/Time.rst @@ -101,6 +101,11 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index 045c258bda4..98ca73c156a 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -123,8 +123,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc zone diff --git a/reference/constraints/Type.rst b/reference/constraints/Type.rst index 209520c41c7..1962dffa284 100644 --- a/reference/constraints/Type.rst +++ b/reference/constraints/Type.rst @@ -162,8 +162,13 @@ Parameter Description =============== ============================================================== ``{{ type }}`` The expected type ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc .. _reference-constraint-type-type: diff --git a/reference/constraints/UniqueEntity.rst b/reference/constraints/UniqueEntity.rst index e6e449d949b..2bf2533f57e 100644 --- a/reference/constraints/UniqueEntity.rst +++ b/reference/constraints/UniqueEntity.rst @@ -291,8 +291,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_payload-option.rst.inc repositoryMethod diff --git a/reference/constraints/Url.rst b/reference/constraints/Url.rst index fdc58880797..5f4ac23245f 100644 --- a/reference/constraints/Url.rst +++ b/reference/constraints/Url.rst @@ -98,8 +98,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. configuration-block:: .. code-block:: php-annotations diff --git a/reference/constraints/Uuid.rst b/reference/constraints/Uuid.rst index 4406555ac30..6e9794b8b5d 100644 --- a/reference/constraints/Uuid.rst +++ b/reference/constraints/Uuid.rst @@ -97,8 +97,13 @@ You can use the following parameters in this message: Parameter Description =============== ============================================================== ``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label =============== ============================================================== +.. versionadded:: 5.2 + + The ``{{ label }}`` parameter was introduced in Symfony 5.2. + .. include:: /reference/constraints/_normalizer-option.rst.inc .. include:: /reference/constraints/_payload-option.rst.inc From 070450bdd76cae5151b9f98ce70debc0d0e01f91 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 3 Sep 2020 17:57:19 +0200 Subject: [PATCH 0424/1519] Removed some unneeded versionadded directives --- components/form.rst | 5 ----- forms.rst | 5 ----- 2 files changed, 10 deletions(-) diff --git a/components/form.rst b/components/form.rst index cdcf9ee54a8..7ac59478ceb 100644 --- a/components/form.rst +++ b/components/form.rst @@ -728,11 +728,6 @@ and the errors will display next to the fields on error. For a list of all of the built-in validation constraints, see :doc:`/reference/constraints`. -.. versionadded:: 5.2 - - Constraint message can contains ``{{ label }}`` placeholder that will be replaced - by corresponding form field label (in view of ``label_format`` option). - Accessing Form Errors ~~~~~~~~~~~~~~~~~~~~~ diff --git a/forms.rst b/forms.rst index 9ab6b2101ab..02336d32169 100644 --- a/forms.rst +++ b/forms.rst @@ -548,11 +548,6 @@ corresponding errors printed out with the form. Read the :doc:`Symfony validation documentation ` to learn more about this powerful feature. -.. versionadded:: 5.2 - - Constraint message can contains ``{{ label }}`` placeholder that will be replaced - by corresponding form field label (in view of ``label_format`` option). - Other Common Form Features -------------------------- From b7bd5728b15b89a32ea79eebe737abf948a256e1 Mon Sep 17 00:00:00 2001 From: Damien Fayet Date: Sun, 6 Sep 2020 20:20:39 +0200 Subject: [PATCH 0425/1519] Leave impersonation functions --- reference/twig_reference.rst | 27 +++++++++++++++++++++++++++ security/impersonating_user.rst | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 4a97ab73308..4e05024cb1b 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -267,6 +267,33 @@ expression Creates an :class:`Symfony\\Component\\ExpressionLanguage\\Expression` related to the :doc:`ExpressionLanguage component `. +impersonation_exit_path +~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: twig + + {{ impersonation_exit_path(exitTo = null) }} + +``exitTo`` *(optional)* + **type**: ``string`` + +Generates a relative URL to exit impersonation. If `exitTo` is specified it will use its value to build the URl, +elsewhere it will use the current URI. +If we are not impersonating a user, it will return an empty string. + +impersonation_exit_url +~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: twig + + {{ impersonation_exit_url(exitTo = null) }} + +``exitTo`` *(optional)* + **type**: ``string`` + +Equal to the `impersonation_exit_path`_ function, but it'll generate an absolute URL +instead of a relative one. + Form Related Functions ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/security/impersonating_user.rst b/security/impersonating_user.rst index 8ab25dab9a6..4ea6482f5f0 100644 --- a/security/impersonating_user.rst +++ b/security/impersonating_user.rst @@ -94,7 +94,7 @@ instance, to show a link to exit impersonation in a template: .. code-block:: html+twig {% if is_granted('IS_IMPERSONATOR') %} - Exit impersonation + Exit impersonation {% endif %} .. versionadded:: 5.1 From 4787bba5f8526b44c0d7bc07d311585ee2a3c080 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 7 Sep 2020 14:48:19 +0200 Subject: [PATCH 0426/1519] Rewords --- reference/twig_reference.rst | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 4e05024cb1b..a12e712abce 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -277,9 +277,15 @@ impersonation_exit_path ``exitTo`` *(optional)* **type**: ``string`` -Generates a relative URL to exit impersonation. If `exitTo` is specified it will use its value to build the URl, -elsewhere it will use the current URI. -If we are not impersonating a user, it will return an empty string. +.. versionadded:: 5.2 + + The ``impersonation_exit_path()` function was introduced in Symfony 5.2. + +Generates a URL that you can visit to exit :doc:`user impersonation `. +After exiting impersonation, the user is redirected to the current URI. If you +prefer to redirect to a different URI, define its value in the ``exitTo`` argument. + +If no user is being impersonated, the function returns an empty string. impersonation_exit_url ~~~~~~~~~~~~~~~~~~~~~~ @@ -291,8 +297,12 @@ impersonation_exit_url ``exitTo`` *(optional)* **type**: ``string`` -Equal to the `impersonation_exit_path`_ function, but it'll generate an absolute URL -instead of a relative one. +.. versionadded:: 5.2 + + The ``impersonation_exit_url()` function was introduced in Symfony 5.2. + +It's similar to the `impersonation_exit_path`_ function, but it generates +absolute URLs instead of relative URLs. Form Related Functions ~~~~~~~~~~~~~~~~~~~~~~ From a4d71a2c82e12c17d5ab828ae5da1add67255b21 Mon Sep 17 00:00:00 2001 From: Ian Littman Date: Fri, 4 Sep 2020 01:31:46 -0500 Subject: [PATCH 0427/1519] Add information about HttpBrowser header handling --- components/browser_kit.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/components/browser_kit.rst b/components/browser_kit.rst index d248b7de939..ffd49aa2483 100644 --- a/components/browser_kit.rst +++ b/components/browser_kit.rst @@ -310,6 +310,30 @@ dedicated web crawler or scraper such as `Goutte`_:: $openPullRequests = trim($browser->clickLink('Pull requests')->filter( '.table-list-header-toggle a:nth-child(1)' )->text()); + +Dealing with Headers +~~~~~~~~~~~~~~~~~~~~ + +The fifth parameter of `request()` accepts an array of headers in the same format +you'd see in a FastCGI request: all-upper-case, dashes replaced with underscores, +prefixed with `HTTP_`. Array keys are lower-cased, with `HTTP_` stripped, and +underscores turned to dashes, before saving those headers to the request. + +If you're making a request to an application that has special rules about header +capitalization or punctuation, you'll want to override HttpBrowser's `getHeaders()` +method, which takes a Request object and returns an asociative array of headers. +For example:: + + protected function getHeaders(Request $request): array + { + $headers = parent::getHeaders($request); + if (isset($request->getServer()['api_key'])) { + $headers['api_key'] = $request->getServer()['api_key']; + } + return $headers; + } + +This override is available as of Symfony 5.2. Learn more ---------- From e3991444ab4c40b27066fc22fb4027087ea34c5c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 7 Sep 2020 20:09:27 +0200 Subject: [PATCH 0428/1519] Minor reword --- components/browser_kit.rst | 50 ++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/components/browser_kit.rst b/components/browser_kit.rst index ffd49aa2483..b73783f95e0 100644 --- a/components/browser_kit.rst +++ b/components/browser_kit.rst @@ -161,6 +161,32 @@ provides access to the form properties (e.g. ``$form->getUri()``, // submit that form $crawler = $client->submit($form); +Custom Header Handling +~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.2 + + The ``getHeaders()`` method was introduced in Symfony 5.2. + +The optional HTTP headers passed to the ``request()`` method follows the FastCGI +request format (uppercase, underscores instead of dashes and prefixed with ``HTTP_``). +Before saving those headers to the request, they are lower-cased, with ``HTTP_`` +stripped, and underscores turned to dashes. + +If you're making a request to an application that has special rules about header +capitalization or punctuation, override the ``getHeaders()`` method, which must +return an associative array of headers:: + + protected function getHeaders(Request $request): array + { + $headers = parent::getHeaders($request); + if (isset($request->getServer()['api_key'])) { + $headers['api_key'] = $request->getServer()['api_key']; + } + + return $headers; + } + Cookies ------- @@ -310,30 +336,6 @@ dedicated web crawler or scraper such as `Goutte`_:: $openPullRequests = trim($browser->clickLink('Pull requests')->filter( '.table-list-header-toggle a:nth-child(1)' )->text()); - -Dealing with Headers -~~~~~~~~~~~~~~~~~~~~ - -The fifth parameter of `request()` accepts an array of headers in the same format -you'd see in a FastCGI request: all-upper-case, dashes replaced with underscores, -prefixed with `HTTP_`. Array keys are lower-cased, with `HTTP_` stripped, and -underscores turned to dashes, before saving those headers to the request. - -If you're making a request to an application that has special rules about header -capitalization or punctuation, you'll want to override HttpBrowser's `getHeaders()` -method, which takes a Request object and returns an asociative array of headers. -For example:: - - protected function getHeaders(Request $request): array - { - $headers = parent::getHeaders($request); - if (isset($request->getServer()['api_key'])) { - $headers['api_key'] = $request->getServer()['api_key']; - } - return $headers; - } - -This override is available as of Symfony 5.2. Learn more ---------- From 63d7ffb152fd0276c64aea3faa6b8c611600056f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 7 Sep 2020 20:51:06 +0200 Subject: [PATCH 0429/1519] Added the missing versionadded directive --- messenger.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index 677a2cf7dce..7518a22488e 100644 --- a/messenger.rst +++ b/messenger.rst @@ -725,10 +725,13 @@ and should not be retried. If you throw :class:`Symfony\\Component\\Messenger\\Exception\\UnrecoverableMessageHandlingException`, the message will not be retried. - Forcing Retrying ~~~~~~~~~~~~~~~~ +.. versionadded:: 5.1 + + The ``RecoverableMessageHandlingException`` was introduced in Symfony 5.1. + Sometimes handling a message must fail in a way that you *know* is temporary and must be retried. If you throw :class:`Symfony\\Component\\Messenger\\Exception\\RecoverableMessageHandlingException`, From 940b4021829d638a63dc4c32ded08c4802316ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Tue, 8 Sep 2020 09:44:14 +0200 Subject: [PATCH 0430/1519] Debugging the validator constraints --- validation.rst | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/validation.rst b/validation.rst index fd18f003d56..14aab162aae 100644 --- a/validation.rst +++ b/validation.rst @@ -719,6 +719,81 @@ constraint that's applied to the class itself. When that class is validated, methods specified by that constraint are simply executed so that each can provide more custom validation. +Debugging the constraints +------------------------- + +The ``debug:validator 'App\Entity\DummyClassOne'`` command lists validation constraints of ``App\Entity\DummyClassOne`` resource. + +.. code-block:: terminal + + $ php bin/console debug:validator 'App\Entity\DummyClassOne' + + App\Entity\DummyClassOne + ----------------------------------------------------- + + +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ + | Property | Name | Groups | Options | + +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ + | firstArgument | Symfony\Component\Validator\Constraints\NotBlank | Default | [ | + | | | | "message" => "This value should not be blank.", | + | | | | "allowNull" => false, | + | | | | "normalizer" => null, | + | | | | "payload" => null | + | | | | ] | + | firstArgument | Symfony\Component\Validator\Constraints\Email | Default | [ | + | | | | "message" => "This value is not a valid email address.", | + | | | | "mode" => null, | + | | | | "normalizer" => null, | + | | | | "payload" => null | + | | | | ] | + +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ + +You can also list validation constraints for all resources of a path. + +.. code-block:: terminal + + $ php bin/console debug:validator src/Entity + + App\Entity\DummyClassOne + ------------------------ + + +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ + | Property | Name | Groups | Options | + +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ + | firstArgument | Symfony\Component\Validator\Constraints\NotBlank | Default | [ | + | | | | "message" => "This value should not be blank.", | + | | | | "allowNull" => false, | + | | | | "normalizer" => null, | + | | | | "payload" => null | + | | | | ] | + | firstArgument | Symfony\Component\Validator\Constraints\Email | Default | [ | + | | | | "message" => "This value is not a valid email address.", | + | | | | "mode" => null, | + | | | | "normalizer" => null, | + | | | | "payload" => null | + | | | | ] | + +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ + + App\Entity\DummyClassTwo + ------------------------ + + +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ + | Property | Name | Groups | Options | + +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ + | firstArgument | Symfony\Component\Validator\Constraints\NotBlank | Default | [ | + | | | | "message" => "This value should not be blank.", | + | | | | "allowNull" => false, | + | | | | "normalizer" => null, | + | | | | "payload" => null | + | | | | ] | + | firstArgument | Symfony\Component\Validator\Constraints\Email | Default | [ | + | | | | "message" => "This value is not a valid email address.", | + | | | | "mode" => null, | + | | | | "normalizer" => null, | + | | | | "payload" => null | + | | | | ] | + +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ + Final Thoughts -------------- From eb910e3a7f25966ee7c42ee8fddaf7dc48fe0c90 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 8 Sep 2020 19:15:01 +0200 Subject: [PATCH 0431/1519] Added the versionadded directive --- components/phpunit_bridge.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index fc7c0d6ae2e..177131e9415 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -296,7 +296,13 @@ By default, the bridge will display a detailed output with the number of deprecations and where they arise. If this is too much for you, you can use ``SYMFONY_DEPRECATIONS_HELPER=verbose=0`` to turn the verbose output off. -It's also possible to change verbosity per deprecation type, for instance ``quiet[]=indirect&quiet[]=other`` will hide details for deprecations of types "indirect" and "other". +It's also possible to change verbosity per deprecation type. For example, using +``quiet[]=indirect&quiet[]=other`` will hide details for deprecations of types +"indirect" and "other". + +.. versionadded:: 5.1 + + The ``quiet`` option was introduced in Symfony 5.1. Disabling the Deprecation Helper ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From a8396f3da3dc2f569f8f712691b2c638d8fb3cbc Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 8 Sep 2020 19:26:29 +0200 Subject: [PATCH 0432/1519] Tweaks --- validation.rst | 55 +++++++++----------------------------------------- 1 file changed, 10 insertions(+), 45 deletions(-) diff --git a/validation.rst b/validation.rst index 14aab162aae..559c31a74f8 100644 --- a/validation.rst +++ b/validation.rst @@ -719,16 +719,21 @@ constraint that's applied to the class itself. When that class is validated, methods specified by that constraint are simply executed so that each can provide more custom validation. -Debugging the constraints +Debugging the Constraints ------------------------- -The ``debug:validator 'App\Entity\DummyClassOne'`` command lists validation constraints of ``App\Entity\DummyClassOne`` resource. +.. versionadded:: 5.2 + + The ``debug:validator`` command was introduced in Symfony 5.2. + +Use the ``debug:validator`` command to list the validation constraints of a +given class: .. code-block:: terminal - $ php bin/console debug:validator 'App\Entity\DummyClassOne' + $ php bin/console debug:validator 'App\Entity\SomeClass' - App\Entity\DummyClassOne + App\Entity\SomeClass ----------------------------------------------------- +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ @@ -748,52 +753,12 @@ The ``debug:validator 'App\Entity\DummyClassOne'`` command lists validation cons | | | | ] | +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ -You can also list validation constraints for all resources of a path. +You can also validate all the classes stored in a given directory: .. code-block:: terminal $ php bin/console debug:validator src/Entity - App\Entity\DummyClassOne - ------------------------ - - +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ - | Property | Name | Groups | Options | - +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ - | firstArgument | Symfony\Component\Validator\Constraints\NotBlank | Default | [ | - | | | | "message" => "This value should not be blank.", | - | | | | "allowNull" => false, | - | | | | "normalizer" => null, | - | | | | "payload" => null | - | | | | ] | - | firstArgument | Symfony\Component\Validator\Constraints\Email | Default | [ | - | | | | "message" => "This value is not a valid email address.", | - | | | | "mode" => null, | - | | | | "normalizer" => null, | - | | | | "payload" => null | - | | | | ] | - +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ - - App\Entity\DummyClassTwo - ------------------------ - - +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ - | Property | Name | Groups | Options | - +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ - | firstArgument | Symfony\Component\Validator\Constraints\NotBlank | Default | [ | - | | | | "message" => "This value should not be blank.", | - | | | | "allowNull" => false, | - | | | | "normalizer" => null, | - | | | | "payload" => null | - | | | | ] | - | firstArgument | Symfony\Component\Validator\Constraints\Email | Default | [ | - | | | | "message" => "This value is not a valid email address.", | - | | | | "mode" => null, | - | | | | "normalizer" => null, | - | | | | "payload" => null | - | | | | ] | - +---------------+--------------------------------------------------+---------+------------------------------------------------------------+ - Final Thoughts -------------- From f54b53b63887fefd59446c6f86b7795dea1c8c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Romey?= Date: Mon, 4 May 2020 10:18:18 +0200 Subject: [PATCH 0433/1519] [Notifier] Add Infobip --- notifier.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 6c19202a77e..4e44eb75d02 100644 --- a/notifier.rst +++ b/notifier.rst @@ -63,6 +63,7 @@ OvhCloud ``symfony/ovhcloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPL Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` Smsapi ``symfony/smsapi-notifier`` ``smsapi://TOKEN@default?from=FROM`` +Infobip ``symfony/infobip-notifier`` ``infobip://TOKEN@default?from=FROM`` ========== ================================ ==================================================== .. versionadded:: 5.1 @@ -71,7 +72,7 @@ Smsapi ``symfony/smsapi-notifier`` ``smsapi://TOKEN@default?from=FRO .. versionadded:: 5.2 - The Smsapi integration was introduced in Symfony 5.2. + The Smsapi and Infobip integrations were introduced in Symfony 5.2. To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: From 63ea8b7db68c2486650e5edb328bfb86aada02eb Mon Sep 17 00:00:00 2001 From: Deamon Date: Thu, 30 Apr 2020 23:56:33 +0200 Subject: [PATCH 0434/1519] Add Mobyt Notifier doc --- notifier.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/notifier.rst b/notifier.rst index 4e44eb75d02..023c4d110be 100644 --- a/notifier.rst +++ b/notifier.rst @@ -64,7 +64,8 @@ Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@d FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` Smsapi ``symfony/smsapi-notifier`` ``smsapi://TOKEN@default?from=FROM`` Infobip ``symfony/infobip-notifier`` ``infobip://TOKEN@default?from=FROM`` -========== ================================ ==================================================== +Mobyt ``symfony/mobyt-notifier`` ``mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM`` +========== =============================== ==================================================== .. versionadded:: 5.1 @@ -72,7 +73,7 @@ Infobip ``symfony/infobip-notifier`` ``infobip://TOKEN@default?from=FROM .. versionadded:: 5.2 - The Smsapi and Infobip integrations were introduced in Symfony 5.2. + The Smsapi, Infobip and Mobyt integrations were introduced in Symfony 5.2. To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: From 34ff1e3a72153c084f85f7b725d70b2e72918441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4dlich?= Date: Thu, 10 Sep 2020 14:56:09 +0200 Subject: [PATCH 0435/1519] fix build error: inline literal start-string without end-string --- reference/twig_reference.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index a12e712abce..0a6c9db3154 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -279,7 +279,7 @@ impersonation_exit_path .. versionadded:: 5.2 - The ``impersonation_exit_path()` function was introduced in Symfony 5.2. + The ``impersonation_exit_path()`` function was introduced in Symfony 5.2. Generates a URL that you can visit to exit :doc:`user impersonation `. After exiting impersonation, the user is redirected to the current URI. If you @@ -299,7 +299,7 @@ impersonation_exit_url .. versionadded:: 5.2 - The ``impersonation_exit_url()` function was introduced in Symfony 5.2. + The ``impersonation_exit_url()`` function was introduced in Symfony 5.2. It's similar to the `impersonation_exit_path`_ function, but it generates absolute URLs instead of relative URLs. From 9204ff20ef28376260ec0aa2836e7bc661163f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Romey?= Date: Thu, 10 Sep 2020 14:57:07 +0200 Subject: [PATCH 0436/1519] Sort notifiers --- notifier.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/notifier.rst b/notifier.rst index 7aab8e37de0..9737df6395e 100644 --- a/notifier.rst +++ b/notifier.rst @@ -57,11 +57,11 @@ with a couple popular SMS services: ========== ================================ ==================================================== Service Package DSN ========== ================================ ==================================================== -Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` +FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` OvhCloud ``symfony/ovhcloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` -FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` +Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` ========== ================================ ==================================================== .. versionadded:: 5.1 @@ -131,10 +131,10 @@ integration with these chat services: ========== ================================ ============================================ Service Package DSN ========== ================================ ============================================ -Slack ``symfony/slack-notifier`` ``slack://default/ID`` -Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` Mattermost ``symfony/mattermost-notifier`` ``mattermost://TOKEN@ENDPOINT?channel=CHANNEL`` RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` +Slack ``symfony/slack-notifier`` ``slack://default/ID`` +Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` ========== ================================ ============================================ .. versionadded:: 5.1 From 8dec0b7ccf950bfb0b6958e102b017dcd9cea7a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4dlich?= Date: Thu, 10 Sep 2020 14:53:05 +0200 Subject: [PATCH 0437/1519] add symfony/esendex-notifier integration docs --- notifier.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 37545c22534..ea066e5ed00 100644 --- a/notifier.rst +++ b/notifier.rst @@ -57,6 +57,7 @@ with a couple popular SMS services: ========== ================================ ==================================================== Service Package DSN ========== ================================ ==================================================== +Esendex ``symfony/esendex-notifier`` ``esendex://USER_NAME:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM`` FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` Infobip ``symfony/infobip-notifier`` ``infobip://TOKEN@default?from=FROM`` Mobyt ``symfony/mobyt-notifier`` ``mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM`` @@ -73,7 +74,7 @@ Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from= .. versionadded:: 5.2 - The Smsapi, Infobip and Mobyt integrations were introduced in Symfony 5.2. + The Smsapi, Infobip, Mobyt and Esendex integrations were introduced in Symfony 5.2. To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: From 93f8374641aaadbb2115ee8df4972897213674b7 Mon Sep 17 00:00:00 2001 From: Tomas Date: Fri, 11 Sep 2020 10:47:51 +0300 Subject: [PATCH 0438/1519] Add Uid normalizer to normalizers list --- components/serializer.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/serializer.rst b/components/serializer.rst index 6f15604325e..5cbe58e0487 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -804,6 +804,12 @@ There are several types of normalizers available: :class:`Symfony\\Component\\Serializer\\Normalizer\\ProblemNormalizer` Normalizes errors according to the API Problem spec `RFC 7807`_. +:class:`Symfony\\Component\\Serializer\\Normalizer\\UidNormalizer` + This normalizer converts objects that implement + :class:`Symfony\\Component\\Uid\\AbstractUid` into strings. Also it can + denormalize ``uuid`` or ``ulid`` strings to :class:`Symfony\\Component\\Uid\\Uuid` + or :class:`Symfony\\Component\\Uid\\Ulid`. + .. _component-serializer-encoders: Encoders From 082923b47022d93d6df16198ac73e17a5694e6cc Mon Sep 17 00:00:00 2001 From: Zmey Date: Fri, 11 Sep 2020 17:33:09 +0300 Subject: [PATCH 0439/1519] Added ability to use csv ips in security.access_control --- security/access_control.rst | 67 +++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/security/access_control.rst b/security/access_control.rst index d7a96345b8e..385a499d2fb 100644 --- a/security/access_control.rst +++ b/security/access_control.rst @@ -133,6 +133,73 @@ if ``ip``, ``port``, ``host`` or ``method`` are not specified for an entry, that :ref:`Deny access in PHP code ` if you want to disallow access based on ``$_GET`` parameter values. +.. versionadded:: 5.2 + + Environment variables can be used to pass comma separated ip addresses + (as a single value or as one of array values): + + .. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + parameters: + env(TRUSTED_IPS): '10.0.0.1, 10.0.0.2' + security: + # ... + access_control: + - { path: '^/admin', ips: '%env(TRUSTED_IPS)%' } + - { path: '^/admin', ips: [127.0.0.1, ::1, '%env(TRUSTED_IPS)%'] } + + .. code-block:: xml + + + + + + + 10.0.0.1, 10.0.0.2 + + + + + + + 127.0.0.1 + ::1 + %env(TRUSTED_IPS)% + + + + + .. code-block:: php + + // config/packages/security.php + $container->setParameter('env(TRUSTED_IPS)', '10.0.0.1, 10.0.0.2'); + $container->loadFromExtension('security', [ + // ... + 'access_control' => [ + [ + 'path' => '^/admin', + 'ips' => '%env(TRUSTED_IPS)%', + ], + [ + 'path' => '^/admin', + 'ips' => [ + '127.0.0.1', + '::1', + '%env(TRUSTED_IPS)%', + ], + ], + ], + ]); + .. _security-access-control-enforcement-options: 2. Access Enforcement From 6e85c11b7970e7705e3174eda1d1c78d115ea993 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 11 Sep 2020 20:40:25 +0200 Subject: [PATCH 0440/1519] Added the versionadded directive --- components/serializer.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/serializer.rst b/components/serializer.rst index 5cbe58e0487..84a8b297848 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -810,6 +810,10 @@ There are several types of normalizers available: denormalize ``uuid`` or ``ulid`` strings to :class:`Symfony\\Component\\Uid\\Uuid` or :class:`Symfony\\Component\\Uid\\Ulid`. +.. versionadded:: 5.2 + + The ``UidNormalizer`` was introduced in Symfony 5.2. + .. _component-serializer-encoders: Encoders From 86c2f6dda4f0057a0429f2d831cb1c430b9ea670 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 12 Sep 2020 11:16:28 +0200 Subject: [PATCH 0441/1519] [Console] Documented the info() method --- console/style.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/console/style.rst b/console/style.rst index c800e56f976..a8cdad20004 100644 --- a/console/style.rst +++ b/console/style.rst @@ -325,6 +325,27 @@ Result Methods 'Consectetur adipiscing elit', ]); +:method:`Symfony\\Component\\Console\\Style\\SymfonyStyle::info` + It's similar to the ``success()`` method (the given string or array of strings + are displayed with a green background) but the ``[OK]`` label is not prefixed. + It's meant to be used once to display the final result of executing the given + command, without showing the result as a successful or failed one:: + + // use simple strings for short success messages + $io->info('Lorem ipsum dolor sit amet'); + + // ... + + // consider using arrays when displaying long success messages + $io->info([ + 'Lorem ipsum dolor sit amet', + 'Consectetur adipiscing elit', + ]); + +.. versionadded:: 5.2 + + The ``info()`` method was introduced in Symfony 5.2. + :method:`Symfony\\Component\\Console\\Style\\SymfonyStyle::warning` It displays the given string or array of strings highlighted as a warning message (with a red background and the ``[WARNING]`` label). It's meant to be From a83c6e124ac2ce76e728913810f5395e8931f035 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 12 Sep 2020 11:37:15 +0200 Subject: [PATCH 0442/1519] [Console] Document the setAutoExit() method --- console.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/console.rst b/console.rst index 8b015737c85..e76d2743425 100644 --- a/console.rst +++ b/console.rst @@ -376,6 +376,14 @@ console:: } } +If you are using a :doc:`single-command application `, +call ``setAutoExit(false)`` on it to get the command result in ``CommandTester``. + +.. versionadded:: 5.2 + + The ``setAutoExit()`` method for single-command applications was introduced + in Symfony 5.2. + .. tip:: You can also test a whole console application by using From cec6219b430950a6b3ae4cfa008f69b3a1929381 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 12 Sep 2020 11:57:38 +0200 Subject: [PATCH 0443/1519] Minor tweak --- messenger.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/messenger.rst b/messenger.rst index bff5ce65a3f..8b3b93ad415 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1009,11 +1009,13 @@ Beanstalkd Transport .. versionadded:: 5.2 - Install it by running: + The Beanstalkd transport was introduced in Symfony 5.2. - .. code-block:: terminal +Install it by running: + +.. code-block:: terminal - $ composer require symfony/beanstalkd-messenger + $ composer require symfony/beanstalkd-messenger .. code-block:: bash From 62a71dc67c479625ea11c3767d117ef8e3460121 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 12 Sep 2020 12:11:36 +0200 Subject: [PATCH 0444/1519] [Console] Choice values can also be objects --- components/console/helpers/questionhelper.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/console/helpers/questionhelper.rst b/components/console/helpers/questionhelper.rst index 89716c8d078..a4cc68b80b2 100644 --- a/components/console/helpers/questionhelper.rst +++ b/components/console/helpers/questionhelper.rst @@ -105,6 +105,7 @@ from a predefined list:: $helper = $this->getHelper('question'); $question = new ChoiceQuestion( 'Please select your favorite color (defaults to red)', + // choices can also be PHP objects that implement __toString() method ['red', 'blue', 'yellow'], 0 ); @@ -116,6 +117,10 @@ from a predefined list:: // ... do something with the color } +.. versionadded:: 5.2 + + Support for using PHP objects as choice values was introduced in Symfony 5.2. + The option which should be selected by default is provided with the third argument of the constructor. The default is ``null``, which means that no option is the default one. From dfd97c57ab8faf8548442381382a3cbe36fb24bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Sat, 12 Sep 2020 14:25:27 +0200 Subject: [PATCH 0445/1519] Add documentation about read/write locks --- components/lock.rst | 72 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index 09c7abab8eb..53a7514e935 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -165,6 +165,56 @@ This component also provides two useful methods related to expiring locks: ``getExpiringDate()`` (which returns ``null`` or a ``\DateTimeImmutable`` object) and ``isExpired()`` (which returns a boolean). +Shared Locks +------------ + +Sometimes, a data structure cannot be updated atomically and is invalid during +the time of the update. In this situation, other process should not read or +write the data until the update is complete. But once updated, multiple process +can read the data in parallel. + +In this situation, a common solution is to use shared lock which allows +concurent access for read-only operations, while write operations require +exclusive access. + +Use the :method:`Symfony\\Component\\Lock\\LockInterface::acquireRead` method +to acquire a read-only lock, and the existing +:method:`Symfony\\Component\\Lock\\LockInterface::acquire` method to acquire a +write lock.:: + + $lock = $factory->createLock('user'.$user->id); + if (!$lock->acquireRead()) { + return; + } + +Similare to the ``acquire`` method, pass ``true`` as the argument of the ``acquireRead()`` +method to acquire the lock in a blocking mode.:: + + $lock = $factory->createLock('user'.$user->id); + $lock->acquireRead(true); + +When a read-only lock is acquired with the method ``acquireRead``, it's +possible to **Promote** the lock, and change it to write lock, by calling the +``acquire`` method.:: + + $lock = $factory->createLock('user'.$userId); + $lock->acquireRead(true); + + if (!$this->shouldUpdate($userId)) { + return; + } + + $lock->acquire(true); // Promote the lock to write lock + $this->update($userId); + +In the same way, it's possible to **Demote** a write lock, and change it to a +read-only lock by calling the ``acquireRead`` method. + +.. versionadded:: 5.2 + + The ``Lock::acquireRead`` method and ``SharedLockStoreInterface`` interface + and were introduced in Symfony 5.2. + The Owner of The Lock --------------------- @@ -219,17 +269,17 @@ Locks are created and managed in ``Stores``, which are classes that implement The component includes the following built-in store types: -============================================ ====== ======== ======== -Store Scope Blocking Expiring -============================================ ====== ======== ======== -:ref:`FlockStore ` local yes no -:ref:`MemcachedStore ` remote no yes -:ref:`MongoDbStore ` remote no yes -:ref:`PdoStore ` remote no yes -:ref:`RedisStore ` remote no yes -:ref:`SemaphoreStore ` local yes no -:ref:`ZookeeperStore ` remote no no -============================================ ====== ======== ======== +============================================ ====== ======== ======== ======= +Store Scope Blocking Expiring Sharing +============================================ ====== ======== ======== ======= +:ref:`FlockStore ` local yes no yes +:ref:`MemcachedStore ` remote no yes no +:ref:`MongoDbStore ` remote no yes no +:ref:`PdoStore ` remote no yes no +:ref:`RedisStore ` remote no yes yes +:ref:`SemaphoreStore ` local yes no no +:ref:`ZookeeperStore ` remote no no no +============================================ ====== ======== ======== ======= .. _lock-store-flock: From c5c006ffff68c276026d7fd82c6396699ddb43ae Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 12 Sep 2020 15:11:15 +0200 Subject: [PATCH 0446/1519] [Process] Document the method to configure options --- components/process.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/components/process.rst b/components/process.rst index c7b286fec71..c70c602ac98 100644 --- a/components/process.rst +++ b/components/process.rst @@ -102,6 +102,21 @@ with a non-zero code):: :method:`Symfony\\Component\\Process\\Process::getLastOutputTime` method. This method returns ``null`` if the process wasn't started! +Configuring Process Options +--------------------------- + +.. versionadded:: 5.2 + + The feature to configure process options was introduced in Symfony 5.2. + +Symfony uses the PHP :phpfunction:`proc_open` function to run the processes. +You can configure the options passed to the ``other_options`` argument of +``proc_open()`` using the ``setOptions()`` method:: + + $process = new Process(['...', '...', '...']); + // this option allows a subprocess to continue running after the main script exited + $process->setOptions(['create_new_console' => true]); + Using Features From the OS Shell -------------------------------- From 0e3d907dbd7358d24ee01c77dc1a92c2d55483d7 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 12 Sep 2020 15:24:23 +0200 Subject: [PATCH 0447/1519] [Cache] Mention the changes in prefix_seed --- reference/configuration/framework.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 6710badcece..b443750a124 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -2716,6 +2716,12 @@ It's also useful when using `blue/green deployment`_ strategies and more generally, when you need to abstract out the actual deployment directory (for example, when warming caches offline). +.. versionadded:: 5.2 + + Starting from Symfony 5.2, the ``%kernel.container_class%`` parameter is no + longer appended automatically to the value of this option. This allows + sharing caches between applications or different environments. + .. _reference-lock: lock From 12c71a6e2f83f44033ba7239eba334c300f11297 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 12 Sep 2020 15:51:52 +0200 Subject: [PATCH 0448/1519] Tweaks --- notifier.rst | 10 +++++++++- notifier/chatters.rst | 10 +++++++--- notifier/texters.rst | 10 +++++++--- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/notifier.rst b/notifier.rst index ea066e5ed00..9d0b5148553 100644 --- a/notifier.rst +++ b/notifier.rst @@ -376,7 +376,7 @@ To send a notification, autowire the ); // Send the notification to the recipient - $notifier->send($notification, $recipient); + $sentMessage = $notifier->send($notification, $recipient); // ... } @@ -387,6 +387,14 @@ channels. The channels specify which channel (or transport) should be used to send the notification. For instance, ``['email', 'sms']`` will send both an email and sms notification to the user. +The ``send()`` method used to send the notification returns a variable of type +:class:`Symfony\\Component\\Notifier\\Message\\SentMessage` which provides +information such as the message ID and the original message contents. + +.. versionadded:: 5.2 + + The ``SentMessage`` class was introduced in Symfony 5.2. + The default notification also has a ``content()`` and ``emoji()`` method to set the notification content and icon. diff --git a/notifier/chatters.rst b/notifier/chatters.rst index fa8392f4a48..efbd040593e 100644 --- a/notifier/chatters.rst +++ b/notifier/chatters.rst @@ -38,9 +38,13 @@ you to send messages to chat services like Slack or Telegram:: } } -The ``$sentMessage`` (instance of -:class:`Symfony\\Component\\Notifier\\Message\\SentMessage`) returned by -``send()`` contains info about the sent message. +The ``send()`` method returns a variable of type +:class:`Symfony\\Component\\Notifier\\Message\\SentMessage` which provides +information such as the message ID and the original message contents. + +.. versionadded:: 5.2 + + The ``SentMessage`` class was introduced in Symfony 5.2. .. seealso:: diff --git a/notifier/texters.rst b/notifier/texters.rst index bd9ec44ebcd..eb663b13726 100644 --- a/notifier/texters.rst +++ b/notifier/texters.rst @@ -39,9 +39,13 @@ you to send SMS messages:: } } -The ``$sentMessage`` (instance of -:class:`Symfony\\Component\\Notifier\\Message\\SentMessage`) returned by -``send()`` contains info about the sent message. +The ``send()`` method returns a variable of type +:class:`Symfony\\Component\\Notifier\\Message\\SentMessage` which provides +information such as the message ID and the original message contents. + +.. versionadded:: 5.2 + + The ``SentMessage`` class was introduced in Symfony 5.2. .. seealso:: From 5d971ee2f4cefd89b51dd35fed317bfb1a52da6f Mon Sep 17 00:00:00 2001 From: Ahmad Ra'fat Date: Mon, 27 Jul 2020 14:03:28 +0200 Subject: [PATCH 0449/1519] [Stopwatch] Add name property to the stopwatchEvent --- components/stopwatch.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/components/stopwatch.rst b/components/stopwatch.rst index e6e11d9c53e..c0265f272e5 100644 --- a/components/stopwatch.rst +++ b/components/stopwatch.rst @@ -102,6 +102,7 @@ For example:: $event->getEndTime(); // returns the end time of the very last period $event->getDuration(); // returns the event duration, including all periods $event->getMemory(); // returns the max memory usage of all periods + $event->getName(); // returns the event name Sections -------- From fc9ab91cc45500444742f7b393574793c8ad5453 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 12 Sep 2020 15:56:01 +0200 Subject: [PATCH 0450/1519] Added the versionadded directive --- components/stopwatch.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/stopwatch.rst b/components/stopwatch.rst index c0265f272e5..d381d3316a5 100644 --- a/components/stopwatch.rst +++ b/components/stopwatch.rst @@ -104,6 +104,10 @@ For example:: $event->getMemory(); // returns the max memory usage of all periods $event->getName(); // returns the event name +.. versionadded:: 5.2 + + The ``getName()`` method was introduced in Symfony 5.2. + Sections -------- From 729c7df5d62d2d9adce8d0ef120a192a523b7fc9 Mon Sep 17 00:00:00 2001 From: pizzaminded Date: Mon, 7 Sep 2020 23:09:12 +0200 Subject: [PATCH 0451/1519] [HttpClient] Providing additional options to CurlHttpClient section --- http_client.rst | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/http_client.rst b/http_client.rst index a1d8c4bd0a3..8814f8f2292 100644 --- a/http_client.rst +++ b/http_client.rst @@ -728,6 +728,39 @@ When using this component in a full-stack Symfony application, this behavior is not configurable and cURL will be used automatically if the cURL PHP extension is installed and enabled. Otherwise, the native PHP streams will be used. +Providing Additional Options to CurlHttpClient +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is possible to provide additional cURL options to ``CurlHttpClient``. PHP exposes +a lot of `cURL options`_ that can be passed to ``curl_setopt`` function, but only some +of them are used in ``CurlHttpClient`` in favor of bigger component portability. + +To provide cURL-related parameters to request, add an ``extra.curl`` option in your +configuration:: + + use Symfony\Component\HttpClient\CurlHttpClient; + + $client = new CurlHttpClient(); + + $client->request('POST', 'https://...', [ + // ... + 'extra' => [ + 'curl' => [ + CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V6 + ] + ] + ]); + + +This option is available only when using ``CurlHttpClient``, other clients will ignore these options. + +.. note:: + + Some cURL options are impossible to override due of. e.g Thread Safety or existing options in + ``$options`` configuration which will set given attributes internally. An exception will be + thrown while overriding them. + + HTTP/2 Support ~~~~~~~~~~~~~~ @@ -1391,3 +1424,4 @@ However, using ``MockResponse`` allows simulating chunked responses and timeouts .. _`Symfony Contracts`: https://github.com/symfony/contracts .. _`libcurl`: https://curl.haxx.se/libcurl/ .. _`amphp/http-client`: https://packagist.org/packages/amphp/http-client +.. _`cURL options`: https://www.php.net/manual/en/function.curl-setopt.php From 935ea466268a7376594ab08902eb643e17d8b267 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 12 Sep 2020 16:06:44 +0200 Subject: [PATCH 0452/1519] Minor reword --- http_client.rst | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/http_client.rst b/http_client.rst index 8814f8f2292..c34911ceaf6 100644 --- a/http_client.rst +++ b/http_client.rst @@ -728,15 +728,19 @@ When using this component in a full-stack Symfony application, this behavior is not configurable and cURL will be used automatically if the cURL PHP extension is installed and enabled. Otherwise, the native PHP streams will be used. -Providing Additional Options to CurlHttpClient -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Configuring CurlHttpClient Options +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -It is possible to provide additional cURL options to ``CurlHttpClient``. PHP exposes -a lot of `cURL options`_ that can be passed to ``curl_setopt`` function, but only some -of them are used in ``CurlHttpClient`` in favor of bigger component portability. +.. versionadded:: 5.2 -To provide cURL-related parameters to request, add an ``extra.curl`` option in your -configuration:: + The feature to configure extra cURL options was introduced in Symfony 5.2. + +PHP allows to configure lots of `cURL options`_ via the :phpfunction:`curl_setopt` +function. In order to make the component more portable when not using cURL, the +``CurlHttpClient`` only uses some of those options (and they are ignored in the +rest of clients). + +Add an ``extra.curl`` option in your configuration to pass those extra options:: use Symfony\Component\HttpClient\CurlHttpClient; @@ -751,15 +755,10 @@ configuration:: ] ]); - -This option is available only when using ``CurlHttpClient``, other clients will ignore these options. - .. note:: - Some cURL options are impossible to override due of. e.g Thread Safety or existing options in - ``$options`` configuration which will set given attributes internally. An exception will be - thrown while overriding them. - + Some cURL options are impossible to override (e.g. because of thread safety) + and you'll get an exception when trying to override them. HTTP/2 Support ~~~~~~~~~~~~~~ From 90caccc0f04e7a32671a57a012307b9a950bd31b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 12 Sep 2020 12:27:17 +0200 Subject: [PATCH 0453/1519] [Uid] Mention the new Doctrine types and generators --- components/uid.rst | 111 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/components/uid.rst b/components/uid.rst index c8eee0ece94..f1c569df97d 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -112,6 +112,62 @@ UUID objects created with the ``Uuid`` class can use the following methods // * int < 0 if $uuid1 is less than $uuid4 $uuid1->compare($uuid4); // e.g. int(4) +Storing UUIDs in Databases +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can store UUID values as any other regular string/binary values in the database. +However, if you :doc:`use Doctrine `, it's more convenient to use the +special Doctrine types which convert to/from UUID objects automatically:: + + // src/Entity/Product.php + namespace App\Entity; + + use Doctrine\ORM\Mapping as ORM; + + /** + * @ORM\Entity(repositoryClass="App\Repository\ProductRepository") + */ + class Product + { + /** + * @ORM\Column(type="uuid") + */ + private $someProperty; + + /** + * @ORM\Column(type="uuid_binary") + */ + private $anotherProperty; + + // ... + } + +There's also a Doctrine generator to help autogenerate UUID values for the +entity primary keys:: + + // there are generators for UUID V1 and V6 too + use Symfony\Bridge\Doctrine\Types\UuidV4Generator; + + /** + * @ORM\Entity(repositoryClass="App\Repository\ProductRepository") + */ + class Product + { + /** + * @ORM\Id + * @ORM\Column(type="uuid", unique=true) + * @ORM\GeneratedValue(strategy="CUSTOM") + * @ORM\CustomIdGenerator(class=UuidV4Generator::class) + */ + private $id; + + // ... + } + +.. versionadded:: 5.2 + + The UUID types and generators were introduced in Symfony 5.2. + ULIDs ----- @@ -172,6 +228,61 @@ ULID objects created with the ``Ulid`` class can use the following methods:: // this method returns $ulid1 <=> $ulid2 $ulid1->compare($ulid2); // e.g. int(-1) +Storing ULIDs in Databases +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can store ULID values as any other regular string/binary values in the database. +However, if you :doc:`use Doctrine `, it's more convenient to use the +special Doctrine types which convert to/from ULID objects automatically:: + + // src/Entity/Product.php + namespace App\Entity; + + use Doctrine\ORM\Mapping as ORM; + + /** + * @ORM\Entity(repositoryClass="App\Repository\ProductRepository") + */ + class Product + { + /** + * @ORM\Column(type="ulid") + */ + private $someProperty; + + /** + * @ORM\Column(type="ulid_binary") + */ + private $anotherProperty; + + // ... + } + +There's also a Doctrine generator to help autogenerate ULID values for the +entity primary keys:: + + use Symfony\Bridge\Doctrine\Types\UlidGenerator; + + /** + * @ORM\Entity(repositoryClass="App\Repository\ProductRepository") + */ + class Product + { + /** + * @ORM\Id + * @ORM\Column(type="uuid", unique=true) + * @ORM\GeneratedValue(strategy="CUSTOM") + * @ORM\CustomIdGenerator(class=UlidGenerator::class) + */ + private $id; + + // ... + } + +.. versionadded:: 5.2 + + The ULID types and generator were introduced in Symfony 5.2. + .. _`unique identifiers`: https://en.wikipedia.org/wiki/UID .. _`UUIDs`: https://en.wikipedia.org/wiki/Universally_unique_identifier .. _`ULIDs`: https://github.com/ulid/spec From f41ef122c26ec0bb532dab399d2ba4c9f93af8eb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 30 May 2020 15:42:21 +0200 Subject: [PATCH 0454/1519] [HttpClient] add doc about extending and AsyncDecoratorTrait --- http_client.rst | 104 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/http_client.rst b/http_client.rst index 42a4b0388da..7c4c50932ae 100644 --- a/http_client.rst +++ b/http_client.rst @@ -1322,6 +1322,110 @@ This allows using them where native PHP streams are needed:: // later on if you need to, you can access the response from the stream $response = stream_get_meta_data($streamResource)['wrapper_data']->getResponse(); +Extensibility +------------- + +In order to extend the behavior of a base HTTP client, decoration is the way to go:: + + class MyExtendedHttpClient implements HttpClientInterface + { + private $decoratedClient; + + public function __construct(HttpClientInterface $decoratedClient = null) + { + $this->decoratedClient = $decoratedClient ?? HttpClient::create(); + } + + public function request(string $method, string $url, array $options = []): ResponseInterface + { + // do what you want here with $method, $url and/or $options + + $response = $this->decoratedClient->request(); + + //!\ calling any method on $response here would break async, see below for a better way + + return $response; + } + + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + return $this->decoratedClient->stream($responses, $timeout); + } + } + +A decorator like this one is suited for use cases where processing the +requests' arguments is enough. + +By decorating the ``on_progress`` option, one can +even implement basic monitoring of the response. But since calling responses' +methods forces synchronous operations, doing so in ``request()`` breaks async. +The solution then is to also decorate the response object itself. +:class:`Symfony\\Component\\HttpClient\\TraceableHttpClient` and +:class:`Symfony\\Component\\HttpClient\\Response\\TraceableResponse` are good +examples as a starting point. + +.. versionadded:: 5.2 + + ``AsyncDecoratorTrait`` was introduced in Symfony 5.2. + +In order to help writing more advanced response processors, the component provides +an :class:`Symfony\\Component\\HttpClient\\AsyncDecoratorTrait`. This trait allows +processing the stream of chunks as they come back from the network:: + + class MyExtendedHttpClient implements HttpClientInterface + { + use AsyncDecoratorTrait; + + public function request(string $method, string $url, array $options = []): ResponseInterface + { + // do what you want here with $method, $url and/or $options + + $passthru = function (ChunkInterface $chunk, AsyncContext $context) { + + // do what you want with chunks, e.g. split them + // in smaller chunks, group them, skip some, etc. + + yield $chunk; + }; + + return new AsyncResponse($this->client, $method, $url, $options, $passthru); + } + } + +Because the trait already implements a constructor and the ``stream()`` method, +you don't need to add them. The ``request()`` method should still be defined; +it shall return an +:class:`Symfony\\Component\\HttpClient\\Response\\AsyncResponse`. + +The custom processing of chunks should happen in ``$passthru``: this generator +is where you need to write your logic. It will be called for each chunk yielded by +the underlying client. A ``$passthru`` that does nothing would just ``yield $chunk;``. +Of course, you could also yield a modified chunk, split the chunk into many +ones by yielding several times, or even skip a chunk altogether by issuing a +``return;`` instead of yielding. + +In order to control the stream, the chunk passthru receives an +:class:`Symfony\\Component\\HttpClient\\Response\\AsyncContext` as second +argument. This context object has methods to read the current state of the +response. It also allows altering the response stream with methods to create new +chunks of content, pause the stream, cancel the stream, change the info of the +response, replace the current request by another one or change the chunk passthru +itself. + +Checking the test cases implemented in +:class:`Symfony\\Component\\HttpClient\\Response\\Tests\\AsyncDecoratorTraitTest` +might be a good start to get various working examples for a better understanding. +Here are the use cases that it simulates: + +* retry a failed request; +* send a preflight request, e.g. for authentication needs; +* issue subrequests and include their content in the main response's body. + +The logic in :class:`Symfony\\Component\\HttpClient\\Response\\AsyncResponse` has +many safety checks that will throw a ``LogicException`` if the chunk passthru +doesn't behave correctly; e.g. if a chunk is yielded after an ``isLast()`` one, +or if a content chunk is yielded before an ``isFirst()`` one, etc. + Testing HTTP Clients and Responses ---------------------------------- From db7298f7d081361867e6d7cf08e2f4dab7c59d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Honor=C3=A9=20Hounwanou?= Date: Mon, 14 Sep 2020 10:59:27 -0400 Subject: [PATCH 0455/1519] Fix small typo by removing semicolon --- security/experimental_authenticators.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index a8c5ee3cc55..83b3199d9ef 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -493,7 +493,7 @@ authenticator, you would initialize the passport like this:: return new Passport($user, new PasswordCredentials($password), [ // $this->userRepository must implement PasswordUpgraderInterface new PasswordUpgradeBadge($password, $this->userRepository), - new CsrfTokenBadge('login', $csrfToken); + new CsrfTokenBadge('login', $csrfToken), ]); } } From 8d28f6b089045459e65245b3d615a07418f6d2d7 Mon Sep 17 00:00:00 2001 From: Andrey Bolonin Date: Tue, 11 Aug 2020 21:40:16 +0300 Subject: [PATCH 0456/1519] Update custom-transport.rst --- messenger/custom-transport.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/messenger/custom-transport.rst b/messenger/custom-transport.rst index e0fbcb3ca23..f4e5531109c 100644 --- a/messenger/custom-transport.rst +++ b/messenger/custom-transport.rst @@ -35,7 +35,7 @@ The transport object needs to implement the and :class:`Symfony\\Component\\Messenger\\Transport\\Receiver\\ReceiverInterface`). Here is a simplified example of a database transport:: - use Ramsey\Uuid\Uuid; + use Symfony\Component\Uid\Uuid; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Stamp\TransportMessageIdStamp; use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; @@ -108,8 +108,7 @@ Here is a simplified example of a database transport:: public function send(Envelope $envelope): Envelope { $encodedMessage = $this->serializer->encode($envelope); - $uuid = Uuid::uuid4()->toString(); - + $uuid = (string) Uuid::v4(); // Add a message to the "my_queue" table $this->db->createQuery( 'INSERT INTO my_queue (id, envelope, delivered_at, handled) From 51aa10d2096bf4e234aaf1fb6ae4eee15c06ba13 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 15 Sep 2020 08:24:37 +0200 Subject: [PATCH 0457/1519] Sort import statements in a code example --- messenger/custom-transport.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger/custom-transport.rst b/messenger/custom-transport.rst index f4e5531109c..be41d63a41e 100644 --- a/messenger/custom-transport.rst +++ b/messenger/custom-transport.rst @@ -35,12 +35,12 @@ The transport object needs to implement the and :class:`Symfony\\Component\\Messenger\\Transport\\Receiver\\ReceiverInterface`). Here is a simplified example of a database transport:: - use Symfony\Component\Uid\Uuid; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Stamp\TransportMessageIdStamp; use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; use Symfony\Component\Messenger\Transport\TransportInterface; + use Symfony\Component\Uid\Uuid; class YourTransport implements TransportInterface { From 53fb3c73582b0fd1897b29098f89a871f628b7f8 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Tue, 15 Sep 2020 01:19:38 -0400 Subject: [PATCH 0458/1519] Add new way of mapping form data --- form/data_mappers.rst | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/form/data_mappers.rst b/form/data_mappers.rst index 15e66ce54b3..24a0f41d39e 100644 --- a/form/data_mappers.rst +++ b/form/data_mappers.rst @@ -189,6 +189,45 @@ method:: Cool! When using the ``ColorType`` form, the custom data mapper methods will create a new ``Color`` object now. +Mapping Form Fields Using Callbacks +----------------------------------- + +Conveniently, you can also map data from and into a form field by using the +``getter`` and ``setter`` options. For example, suppose you have a form with some +fields and only one of them needs to be mapped in some special way or you only +need to change how it's written into the underlying object. In that case, register +a PHP callable that is able to write or read to/from that specific object:: + + public function buildForm(FormBuilderInterface $builder, array $options) + { + // ... + + $builder->add('state', ChoiceType::class, [ + 'choices' => [ + 'active' => true, + 'paused' => false, + ], + 'getter' => function (Task $task, FormInterface $form): bool { + return !$task->isCancelled() && !$task->isPaused(); + }, + 'setter' => function (Task &$task, bool $state, FormInterface $form): void { + if ($state) { + $task->activate(); + } else { + $task->pause(); + } + }, + ]); + } + +If available, these options have priority over the property path accessor and +the default data mapper will still use the :doc:`PropertyAccess component ` +for the other form fields. + +.. versionadded:: 5.2 + + The ``getter`` and ``setter`` options were introduced in Symfony 5.2. + .. caution:: When a form has the ``inherit_data`` option set to ``true``, it does not use the data mapper and From 26ff76c7382250e33f17c562eca6ee00898e06c6 Mon Sep 17 00:00:00 2001 From: Gary Houbre Date: Tue, 15 Sep 2020 15:57:49 +0200 Subject: [PATCH 0459/1519] Path from Controller Test - Messenger Page Doc --- messenger.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/messenger.rst b/messenger.rst index 3d7e8c32563..d20b46472c2 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1110,8 +1110,8 @@ Then, while testing, messages will *not* be delivered to the real transport. Even better, in a test, you can check that exactly one message was sent during a request:: - // tests/DefaultControllerTest.php - namespace App\Tests; + // tests/Controller/DefaultControllerTest.php + namespace App\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\Messenger\Transport\InMemoryTransport; From 5b3a13b6cf1cf958a3ccefa40205929cd196f31e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Thu, 17 Sep 2020 13:58:49 +0200 Subject: [PATCH 0460/1519] Add documentation for Retryable client --- http_client.rst | 23 +++++ reference/configuration/framework.rst | 126 ++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) diff --git a/http_client.rst b/http_client.rst index 3ead5a7a6f8..44be44aee82 100644 --- a/http_client.rst +++ b/http_client.rst @@ -143,6 +143,7 @@ Some options are described in this guide: * `Query String Parameters`_ * `Headers`_ * `Redirects`_ +* `Retry Failed Requests`_ * `HTTP Proxies`_ Check out the full :ref:`http_client config reference ` @@ -654,6 +655,28 @@ making a request. Use the ``max_redirects`` setting to configure this behavior 'max_redirects' => 0, ]); +Retry Failed Requests +~~~~~~~~~~~~~~~~~~~~~ + +Some times, requests failed because of temporary issue in the server or +because network issue. You can use the +:class:`Symfony\\Component\\HttpClient\\RetryableHttpClient` +client to automatically retry the request when it fails.:: + + use Symfony\Component\HttpClient\RetryableHttpClient; + + $client = new RetryableHttpClient(HttpClient::create()); + +The ``RetryableHttpClient`` uses a +:class:`Symfony\\Component\\HttpClient\\Retry\\RetryDeciderInterface` to +decide if the request should be retried, and a +:class:`Symfony\\Component\\HttpClient\\Retry\\RetryBackOffInterface` to +define the waiting time between each retry. + +By default, it retries until 3 attemps, the requests responding with a +status code in (423, 425, 429, 500, 502, 503, 504, 507 or 510) and wait +expentially from 1 second for the first retry, to 4 seconds at the 3rd attempt. + HTTP Proxies ~~~~~~~~~~~~ diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index b443750a124..1d1b788f7a5 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -137,11 +137,34 @@ Configuration * `proxy`_ * `query`_ * `resolve`_ + + * :ref:`retry_failed ` + + * `backoff_service`_ + * `decider_service`_ + * :ref:`enabled ` + * `delay`_ + * `http_codes`_ + * `max_delay`_ + * `max_retries`_ + * `multiplier`_ + * `timeout`_ * `max_duration`_ * `verify_host`_ * `verify_peer`_ + * :ref:`retry_failed ` + + * `backoff_service`_ + * `decider_service`_ + * :ref:`enabled ` + * `delay`_ + * `http_codes`_ + * `max_delay`_ + * `max_retries`_ + * `multiplier`_ + * `http_method_override`_ * `ide`_ * :ref:`lock ` @@ -742,6 +765,33 @@ If you use for example as the type and name of an argument, autowiring will inject the ``my_api.client`` service into your autowired classes. +.. _reference-http-client-retry-failed: + +By enabling the optional ``retry_failed`` configuration, the HTTP client service +will automaticaly retry failed HTTP requests. + +.. code-block:: yaml + + # config/packages/framework.yaml + framework: + # ... + http_client: + # ... + retry_failed: + # backoff_service: app.custom_backoff + # decider_service: app.custom_decider + http_codes: [429, 500] + max_retries: 2 + delay: 1000 + multiplier: 3 + max_delay: 500 + + scoped_clients: + my_api.client: + # ... + retry_failed: + max_retries: 4 + auth_basic .......... @@ -769,6 +819,19 @@ in the `Microsoft NTLM authentication protocol`_. The value of this option must follow the format ``username:password``. This authentication mechanism requires using the cURL-based transport. +backoff_service +............... + +**type**: ``string`` + +The service id used to compute the time to wait between retries. By default, it +uses an instance of +:class:`Symfony\\Component\\HttpClient\\Retry\\ExponentialBackOff` configured +with ``delay``, ``max_delay`` and ``multiplier`` options. This class has to +implement :class:`Symfony\\Component\\HttpClient\\Retry\\RetryBackOffInterface`. +This options cannot be used along `delay`_, `max_delay`_ or `multiplier`_ +options. + base_uri ........ @@ -837,6 +900,36 @@ ciphers A list of the names of the ciphers allowed for the SSL/TLS connections. They can be separated by colons, commas or spaces (e.g. ``'RC4-SHA:TLS13-AES-128-GCM-SHA256'``). +decider_service +............... + +**type**: ``string`` + +The service id used to decide if a request should be retried. By default, it +uses an instance of +:class:`Symfony\\Component\\HttpClient\\Retry\\HttpStatusCodeDecider` configured +with ``http_codes`` options. This class has to +implement :class:`Symfony\\Component\\HttpClient\\Retry\\RetryDeciderInterface`. +This options cannot be used along `http_codes`_ option. + +delay +..... + +**type**: ``integer`` **default**: ``1000`` + +The initial delay in milliseconds used to compute the waiting time between +retries. This options cannot be used along `backoff_service`_ option. + +.. _reference-http-client-retry-enabled: + +enabled +....... + +**type**: ``boolean`` **default**: ``false`` + +Whether to enable the support for retry failed HTTP request or not. +This setting is automatically set to true when one of the child settings is configured. + headers ....... @@ -845,6 +938,14 @@ headers An associative array of the HTTP headers added before making the request. This value must use the format ``['header-name' => header-value, ...]``. +http_codes +.......... + +**type**: ``array`` **default**: ``[423, 425, 429, 500, 502, 503, 504, 507, 510]`` + +The list of HTTP status codes that triggers a retry of the request. +This options cannot be used along `decider_service`_ option. + http_version ............ @@ -870,6 +971,15 @@ local_pk The path of a file that contains the `PEM formatted`_ private key of the certificate defined in the ``local_cert`` option. +max_delay +......... + +**type**: ``integer`` **default**: ``0`` + +The maximum amount of milliseconds initial to wait between retries. +Use ``0`` to not limit the duration. +This options cannot be used along `backoff_service`_ option. + max_duration ............ @@ -896,6 +1006,22 @@ max_redirects The maximum number of redirects to follow. Use ``0`` to not follow any redirection. +max_retries +........... + +**type**: ``integer`` **default**: ``3`` + +The maximum number of retries before aborting. When the maximum is reach, the +client returns the last received responses. + +multiplier +.......... + +**type**: ``float`` **default**: ``2`` + +Multiplier to apply to the delay each time a retry occurs. +This options cannot be used along `backoff_service`_ option. + no_proxy ........ From 98dcd36a1accc647f14fb319568470a088b4c56a Mon Sep 17 00:00:00 2001 From: Valentin Silvestre Date: Fri, 18 Sep 2020 09:52:01 +0200 Subject: [PATCH 0461/1519] Add AMPS support --- messenger.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/messenger.rst b/messenger.rst index 6fe7fe7d3f3..3064ef12793 100644 --- a/messenger.rst +++ b/messenger.rst @@ -844,6 +844,12 @@ options. AMQP Transport ~~~~~~~~~~~~~~ +.. versionadded:: 5.2 + + Starting from Symfony 5.2, the AMQP transport can handle AMQPS DSN. + Be aware that using it without using CA certificate can throw an exception. + An alternative is to use AMQP DSN and specify the port to use. + .. versionadded:: 5.1 Starting from Symfony 5.1, the AMQP transport has moved to a separate package. @@ -860,7 +866,13 @@ The ``amqp`` transport configuration looks like this: # .env MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages + # or use the AMQPS protocol + MESSENGER_TRANSPORT_DSN=amqps://guest:guest@localhost/%2f/messages + + To use Symfony's built-in AMQP transport, you need the AMQP PHP extension. +If you want to use TLS/SSL encrypted AMQP you must provide a CA certificate. You need to set it using ``amqp.cacert = /etc/ssl/certs`` (path depends on your system) in your ``php.ini`` file or by setting the ``cacert`` parameter (e.g ``amqps://localhost?cacert=/etc/ssl/certs/``) +By default TLS/SSL encrypted AMQP uses port 5671. You can overwrite this behavior by setting the ``port`` parameter (e.g. ``amqps://localhost?cacert=/etc/ssl/certs/&port=12345``). .. note:: From f168c286c665aed785fae1b78a22daaa91e2c544 Mon Sep 17 00:00:00 2001 From: Mynyx Date: Fri, 18 Sep 2020 11:02:55 +0200 Subject: [PATCH 0462/1519] Update forms.rst https://symfony.com/doc/current/form/form_themes.html#symfony-built-in-form-themes --- forms.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forms.rst b/forms.rst index ab433b533db..5867d2f07d1 100644 --- a/forms.rst +++ b/forms.rst @@ -352,7 +352,7 @@ can set this option to generate forms compatible with the Bootstrap 4 CSS framew ]); The :ref:`built-in Symfony form themes ` include -Bootstrap 3 and 4 and Foundation 5. You can also +Bootstrap 3 and 4 as well as Foundation 5 and 6. You can also :ref:`create your own Symfony form theme `. In addition to form themes, Symfony allows you to From c0a2ef5de26888e529e2d0bcdbdf5e06ebbbb58c Mon Sep 17 00:00:00 2001 From: Egor Ushakov Date: Fri, 18 Sep 2020 12:57:55 +0300 Subject: [PATCH 0463/1519] Update serializer.rst IMHO using "format" in current edition confuses readers with $format parameter next to $type --- serializer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serializer.rst b/serializer.rst index 81cc0e4ad93..dfee3270aee 100644 --- a/serializer.rst +++ b/serializer.rst @@ -70,7 +70,7 @@ As well as the following normalizers: * :class:`Symfony\\Component\\Serializer\\Normalizer\\JsonSerializableNormalizer` to deal with objects implementing the :phpclass:`JsonSerializable` interface * :class:`Symfony\\Component\\Serializer\\Normalizer\\ArrayDenormalizer` to - denormalize arrays of objects using a format like `MyObject[]` (note the `[]` suffix) + denormalize arrays of objects using for a `$type` parameter string in `MyObject[]` format (note the `[]` suffix) * :class:`Symfony\\Component\\Serializer\\Normalizer\\ConstraintViolationListNormalizer` for objects implementing the :class:`Symfony\\Component\\Validator\\ConstraintViolationListInterface` interface * :class:`Symfony\\Component\\Serializer\\Normalizer\\ProblemNormalizer` for :class:`Symfony\\Component\\ErrorHandler\\Exception\\FlattenException` objects From cd6c0fd8b4396b48ddd9a0baa986d9b21b8f82db Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 18 Sep 2020 17:53:53 +0200 Subject: [PATCH 0464/1519] Tweak --- serializer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serializer.rst b/serializer.rst index dfee3270aee..1fae4a6e4f3 100644 --- a/serializer.rst +++ b/serializer.rst @@ -70,7 +70,7 @@ As well as the following normalizers: * :class:`Symfony\\Component\\Serializer\\Normalizer\\JsonSerializableNormalizer` to deal with objects implementing the :phpclass:`JsonSerializable` interface * :class:`Symfony\\Component\\Serializer\\Normalizer\\ArrayDenormalizer` to - denormalize arrays of objects using for a `$type` parameter string in `MyObject[]` format (note the `[]` suffix) + denormalize arrays of objects using a notation like ``MyObject[]`` (note the ``[]`` suffix) * :class:`Symfony\\Component\\Serializer\\Normalizer\\ConstraintViolationListNormalizer` for objects implementing the :class:`Symfony\\Component\\Validator\\ConstraintViolationListInterface` interface * :class:`Symfony\\Component\\Serializer\\Normalizer\\ProblemNormalizer` for :class:`Symfony\\Component\\ErrorHandler\\Exception\\FlattenException` objects From b73c12889b07da6a08c56b5164d80d72870d6313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD?= Date: Sun, 20 Sep 2020 16:18:57 +0500 Subject: [PATCH 0465/1519] Update reset_password.rst --- security/reset_password.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/reset_password.rst b/security/reset_password.rst index 7899440ba86..bbde221f015 100644 --- a/security/reset_password.rst +++ b/security/reset_password.rst @@ -12,7 +12,7 @@ Generating the Reset Password Code .. code-block:: terminal - $ php composer require symfonycasts/reset-password-bundle + $ composer require symfonycasts/reset-password-bundle ..... $ php bin/console make:reset-password From a533c359913a4dd6ae7bc195c67fec37732c2a85 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 22 Sep 2020 15:36:55 +0200 Subject: [PATCH 0466/1519] Tweaks and rewords --- components/lock.rst | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index 53a7514e935..c0f20586e6d 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -168,34 +168,37 @@ object) and ``isExpired()`` (which returns a boolean). Shared Locks ------------ -Sometimes, a data structure cannot be updated atomically and is invalid during -the time of the update. In this situation, other process should not read or -write the data until the update is complete. But once updated, multiple process -can read the data in parallel. +.. versionadded:: 5.2 + + Shared locks (and the associated ``acquireRead()`` method and + ``SharedLockStoreInterface``) were introduced in Symfony 5.2. -In this situation, a common solution is to use shared lock which allows -concurent access for read-only operations, while write operations require -exclusive access. +A shared or `readers–writer lock`_ is a synchronization primitive that allows +concurrent access for read-only operations, while write operations require +exclusive access. This means that multiple threads can read the data in parallel +but an exclusive lock is needed for writing or modifying data. They are used for +example for data structures that cannot be updated atomically and are invalid +until the update is complete. Use the :method:`Symfony\\Component\\Lock\\LockInterface::acquireRead` method to acquire a read-only lock, and the existing :method:`Symfony\\Component\\Lock\\LockInterface::acquire` method to acquire a -write lock.:: +write lock:: $lock = $factory->createLock('user'.$user->id); if (!$lock->acquireRead()) { return; } -Similare to the ``acquire`` method, pass ``true`` as the argument of the ``acquireRead()`` -method to acquire the lock in a blocking mode.:: +Similar to the ``acquire()`` method, pass ``true`` as the argument of ``acquireRead()`` +to acquire the lock in a blocking mode:: $lock = $factory->createLock('user'.$user->id); $lock->acquireRead(true); -When a read-only lock is acquired with the method ``acquireRead``, it's -possible to **Promote** the lock, and change it to write lock, by calling the -``acquire`` method.:: +When a read-only lock is acquired with the method ``acquireRead()``, it's +possible to **promote** the lock, and change it to write lock, by calling the +``acquire()`` method:: $lock = $factory->createLock('user'.$userId); $lock->acquireRead(true); @@ -207,13 +210,8 @@ possible to **Promote** the lock, and change it to write lock, by calling the $lock->acquire(true); // Promote the lock to write lock $this->update($userId); -In the same way, it's possible to **Demote** a write lock, and change it to a -read-only lock by calling the ``acquireRead`` method. - -.. versionadded:: 5.2 - - The ``Lock::acquireRead`` method and ``SharedLockStoreInterface`` interface - and were introduced in Symfony 5.2. +In the same way, it's possible to **demote** a write lock, and change it to a +read-only lock by calling the ``acquireRead()`` method. The Owner of The Lock --------------------- @@ -833,3 +831,4 @@ are still running. .. _`PHP semaphore functions`: https://www.php.net/manual/en/book.sem.php .. _`Replica Set Read and Write Semantics`: https://docs.mongodb.com/manual/applications/replication/ .. _`ZooKeeper`: https://zookeeper.apache.org/ +.. _`readers–writer lock`: https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock From d485b85259ca9a9f46148b781dc5f8f47f02e160 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 22 Sep 2020 15:47:05 +0200 Subject: [PATCH 0467/1519] Fix a PHPUnit deprecation --- form/unit_testing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/form/unit_testing.rst b/form/unit_testing.rst index ee096c167dd..795fd55c9ea 100644 --- a/form/unit_testing.rst +++ b/form/unit_testing.rst @@ -159,7 +159,7 @@ make sure the ``FormRegistry`` uses the created instance:: { private $objectManager; - protected function setUp() + protected function setUp(): void { // mock any dependencies $this->objectManager = $this->createMock(ObjectManager::class); From b7c8de755637db188b93b9ee4c6d7953bc749efc Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 22 Sep 2020 16:05:37 +0200 Subject: [PATCH 0468/1519] [String] Allow to define slugger substitutions with PHP closures --- components/string.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/components/string.rst b/components/string.rst index 7d2ec49a198..10c0ab43e66 100644 --- a/components/string.rst +++ b/components/string.rst @@ -473,10 +473,19 @@ that only includes safe ASCII characters:: $slug = $slugger->slug('10% or 5€'); // $slug = '10-percent-or-5-euro' + // for more dynamic substitutions, pass a PHP closure instead of an array + $slugger = new AsciiSlugger('en', function ($string, $locale) { + return str_replace('❤️', 'love', $string); + }); + .. versionadded:: 5.1 The feature to define additional substitutions was introduced in Symfony 5.1. +.. versionadded:: 5.2 + + The feature to use a PHP closure to define substitutions was introduced in Symfony 5.2. + The separator between words is a dash (``-``) by default, but you can define another separator as the second argument:: From 8a9cf7adbd5d205a95a323de5adcff4ae783ec2d Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 22 Sep 2020 16:32:08 +0200 Subject: [PATCH 0469/1519] [Messneger] documented the delete_after_ack option --- messenger.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/messenger.rst b/messenger.rst index d20b46472c2..6107fcec87b 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1046,6 +1046,8 @@ group The Redis consumer group name symfony consumer Consumer name used in Redis consumer auto_setup Create the Redis group automatically? true auth The Redis password +delete_after_ack If ``true``, messages are deleted false + automatically after processing them serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` in Redis (the ``Redis::OPT_SERIALIZER`` option) @@ -1056,6 +1058,17 @@ stream_max_entries The maximum number of entries which ``0`` (which means "n tls Enable TLS support for the connection false ================== ===================================== ========================= +.. tip:: + + Set ``delete_after_ack`` to ``true`` (if you use a single group) or define + ``stream_max_entries`` (if you can estimate how many max entries is acceptable + in your case) to avoid memory leaks. Otherwise, all messages will remain + forever in Redis. + +.. versionadded:: 5.1 + + The ``delete_after_ack`` option was introduced in Symfony 5.1. + In Memory Transport ~~~~~~~~~~~~~~~~~~~ From 171b2631f9509b2b47f39ce28f7ff25799ad5cd3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 22 Sep 2020 17:30:38 +0200 Subject: [PATCH 0470/1519] Rewords --- profiler/data_collector.rst | 117 ++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 58 deletions(-) diff --git a/profiler/data_collector.rst b/profiler/data_collector.rst index 6d7e7ac47c6..276d1e88324 100644 --- a/profiler/data_collector.rst +++ b/profiler/data_collector.rst @@ -14,9 +14,13 @@ Creating a custom Data Collector A data collector is a PHP class that implements the :class:`Symfony\\Component\\HttpKernel\\DataCollector\\DataCollectorInterface`. For convenience, your data collectors can also extend from the -:class:`Symfony\\Component\\HttpKernel\\DataCollector\\DataCollector` class, which -implements the interface and provides some utilities and the ``$this->data`` -property to store the collected information. +:class:`Symfony\\Bundle\\FrameworkBundle\\DataCollector\\AbstractDataCollector` +class, which implements the interface and provides some utilities and the +``$this->data`` property to store the collected information. + +.. versionadded:: 5.2 + + The ``AbstractDataCollector`` class was introduced in Symfony 5.2. The following example shows a custom collector that stores information about the request:: @@ -24,11 +28,12 @@ request:: // src/DataCollector/RequestCollector.php namespace App\DataCollector; + use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\DataCollector\DataCollector; - class RequestCollector extends DataCollector + class RequestCollector extends AbstractDataCollector { public function collect(Request $request, Response $response, \Throwable $exception = null) { @@ -37,25 +42,14 @@ request:: 'acceptable_content_types' => $request->getAcceptableContentTypes(), ]; } - - public function reset() - { - $this->data = []; - } - - public function getName() - { - return 'app.request_collector'; - } - - // ... } +These are the method that you can define in the data collector class: + :method:`Symfony\\Component\\HttpKernel\\DataCollector\\DataCollectorInterface::collect` method: Stores the collected data in local properties (``$this->data`` if you extend - from :class:`Symfony\\Component\\HttpKernel\\DataCollector\\DataCollector`). - If the data to collect cannot be obtained through the request or response, - inject the needed services in the data collector. + from ``AbstractDataCollector``). If you need some services to collect the + data, inject those services in the data collector constructor. .. caution:: @@ -70,14 +64,16 @@ request:: to provide your own ``serialize()`` method. :method:`Symfony\\Component\\HttpKernel\\DataCollector\\DataCollectorInterface::reset` method: - It's called between requests to reset the state of the profiler. Use it to - remove all the information collected with the ``collect()`` method. + It's called between requests to reset the state of the profiler. By default + it only empties the ``$this->data`` contents, but you can override this method + to do additional cleaning. :method:`Symfony\\Component\\HttpKernel\\DataCollector\\DataCollectorInterface::getName` method: Returns the collector identifier, which must be unique in the application. + By default it returns the FQCN of the data collector class, but you can + override this method to return a custom name (e.g. ``app.request_collector``). This value is used later to access the collector information (see - :doc:`/testing/profiling`) so it's recommended to return a string which is - short, lowercase and without white spaces. + :doc:`/testing/profiling`) so you may prefer using short strings instead of FQCN strings. The ``collect()`` method is called during the :ref:`kernel.response ` event. If you need to collect data that is only available later, implement @@ -85,17 +81,11 @@ event. If you need to collect data that is only available later, implement and define the ``lateCollect()`` method, which is invoked right before the profiler data serialization (during :ref:`kernel.terminate ` event). -.. _data_collector_tag: - -Enabling Custom Data Collectors -------------------------------- - -If you're using the :ref:`default services.yaml configuration ` -with ``autoconfigure``, then Symfony will automatically see your new data collector! -Your ``collect()`` method should be called next time your refresh. +.. note:: -If you're not using ``autoconfigure``, you can also :ref:`manually wire your service ` -and :doc:`tag ` it with ``data_collector``. + If you're using the :ref:`default services.yaml configuration ` + with ``autoconfigure``, then Symfony will start using your data collector after the + next page refresh. Otherwise, :ref:`enable the data collector by hand `. Adding Web Profiler Templates ----------------------------- @@ -104,10 +94,9 @@ The information collected by your data collector can be displayed both in the web debug toolbar and in the web profiler. To do so, you need to create a Twig template that includes some specific blocks. -However, first make your DataCollector to extends :class:`Symfony\\Bundle\\FrameworkBundle\\DataCollector\\AbstractDataCollector` instead of :class:`Symfony\\Component\\HttpKernel\\DataCollector\\DataCollector`. When extending :class:`Symfony\\Bundle\\FrameworkBundle\\DataCollector\\AbstractDataCollector`, you don't need to implement `getName` method; your collector FQDN is returned as identifier (you can also override it if needed). Though you need to implement `getTemplate` with the template you're going to use in the profiler (see below). - -Then you must add some getters in the data collector class to give the -template access to the collected information:: +First, add the ``getTemplate()`` method in your data collector class to return +the path of the Twig template to use. Then, add some *getters* to give the +template access to the collected information:::: // src/DataCollector/RequestCollector.php namespace App\DataCollector; @@ -140,6 +129,7 @@ block and set the value of two variables called ``icon`` and ``text``: .. code-block:: html+twig + {# templates/data_collector/template.html.twig #} {% extends '@WebProfiler/Profiler/layout.html.twig' %} {% block toolbar %} @@ -185,6 +175,7 @@ must also define additional blocks: .. code-block:: html+twig + {# templates/data_collector/template.html.twig #} {% extends '@WebProfiler/Profiler/layout.html.twig' %} {% block toolbar %} @@ -234,9 +225,25 @@ The ``menu`` and ``panel`` blocks are the only required blocks to define the contents displayed in the web profiler panel associated with this data collector. All blocks have access to the ``collector`` object. -That's it ! Your data collector is now accessible in the toolbar. +.. note:: + + The position of each panel in the toolbar is determined by the collector + priority, which can only be defined when :ref:`configuring the data collector by hand `. + +.. note:: + + If you're using the :ref:`default services.yaml configuration ` + with ``autoconfigure``, then Symfony will start displaying your collector data + in the toolbar after the next page refresh. Otherwise, :ref:`enable the data collector by hand `. + +.. _data_collector_tag: + +Enabling Custom Data Collectors +------------------------------- -If you don't use the default configuration with :ref:`autowire and autoconfigure `, you'll need to configure the data collector explicitely: +If you don't use Symfony's default configuration with +:ref:`autowire and autoconfigure ` +you'll need to configure the data collector explicitly: .. configuration-block:: @@ -247,10 +254,12 @@ If you don't use the default configuration with :ref:`autowire and autoconfigure App\DataCollector\RequestCollector: tags: - - name: data_collector + name: data_collector # must match the value returned by the getName() method - id: 'App\DataCollector\RequestCollector' - # optional priority + id: 'App\DataCollector\RequestCollector' + # optional template (it has more priority than the value returned by getTemplate()) + template: 'data_collector/template.html.twig' + # optional priority (positive or negative integer; default = 0) # priority: 300 .. code-block:: xml @@ -264,10 +273,13 @@ If you don't use the default configuration with :ref:`autowire and autoconfigure - + + + @@ -284,21 +296,10 @@ If you don't use the default configuration with :ref:`autowire and autoconfigure $services->set(RequestCollector::class) ->tag('data_collector', [ - 'id' => RequestCollector::class, + 'id' => RequestCollector::class, + // optional template (it has more priority than the value returned by getTemplate()) + 'template' => 'data_collector/template.html.twig', + // optional priority (positive or negative integer; default = 0) // 'priority' => 300, ]); }; - -The position of each panel in the toolbar is determined by the collector priority. -Priorities are defined as positive or negative integers and they default to ``0``. -Most built-in collectors use ``255`` as their priority. If you want your collector -to be displayed before them, use a higher value (like 300). - -.. versionadded:: 5.2 - - :class:`Symfony\\Bundle\\FrameworkBundle\\DataCollector\\AbstractDataCollector` was introduced in Symfony 5.2. - -.. note:: - - Before the introduction of :class:`Symfony\\Bundle\\FrameworkBundle\\DataCollector\\AbstractDataCollector`, template path was defined in the service configuration (`template` key). This is still possible to define the template in the service configuration. In this case **template in service configuration takes precedence over template defined in data collector code**. - From b8e8449bb6a98a48e3a848711b539588a4b1dced Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 22 Sep 2020 17:54:01 +0200 Subject: [PATCH 0471/1519] Minor reword --- messenger.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/messenger.rst b/messenger.rst index e23e5fb76fa..ced96444d69 100644 --- a/messenger.rst +++ b/messenger.rst @@ -844,12 +844,6 @@ options. AMQP Transport ~~~~~~~~~~~~~~ -.. versionadded:: 5.2 - - Starting from Symfony 5.2, the AMQP transport can handle AMQPS DSN. - Be aware that using it without using CA certificate can throw an exception. - An alternative is to use AMQP DSN and specify the port to use. - .. versionadded:: 5.1 Starting from Symfony 5.1, the AMQP transport has moved to a separate package. @@ -869,10 +863,18 @@ The ``amqp`` transport configuration looks like this: # or use the AMQPS protocol MESSENGER_TRANSPORT_DSN=amqps://guest:guest@localhost/%2f/messages +.. versionadded:: 5.2 + + The AMQPS protocol support was introduced in Symfony 5.2. To use Symfony's built-in AMQP transport, you need the AMQP PHP extension. -If you want to use TLS/SSL encrypted AMQP you must provide a CA certificate. You need to set it using ``amqp.cacert = /etc/ssl/certs`` (path depends on your system) in your ``php.ini`` file or by setting the ``cacert`` parameter (e.g ``amqps://localhost?cacert=/etc/ssl/certs/``) -By default TLS/SSL encrypted AMQP uses port 5671. You can overwrite this behavior by setting the ``port`` parameter (e.g. ``amqps://localhost?cacert=/etc/ssl/certs/&port=12345``). +If you want to use TLS/SSL encrypted AMQP, you must also provide a CA certificate. +Define the certificate path in the ``amqp.cacert`` PHP.ini setting +(e.g. ``amqp.cacert = /etc/ssl/certs``) or in the ``cacert`` parameter of the +DSN (e.g ``amqps://localhost?cacert=/etc/ssl/certs/``). + +The default port used by TLS/SSL encrypted AMQP is 5671, but you can overwrite +it in the ``port`` parameter of the DSN (e.g. ``amqps://localhost?cacert=/etc/ssl/certs/&port=12345``). .. note:: From 1bfa68fd2279bcccc46461c4b4063b88b3701db5 Mon Sep 17 00:00:00 2001 From: soyuka Date: Thu, 6 Aug 2020 10:48:05 +0200 Subject: [PATCH 0472/1519] Document EventSourceHttpClient --- http_client.rst | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/http_client.rst b/http_client.rst index 3ead5a7a6f8..84f3f14f30b 100644 --- a/http_client.rst +++ b/http_client.rst @@ -1143,6 +1143,52 @@ installed in your application:: ``CachingHttpClient`` accepts a third argument to set the options of the ``HttpCache``. +Consuming Server-Sent Events +---------------------------- + +This component provides an `EventSource`_ implementation to consume Server-Sent Events. +Use the :class:`Symfony\\Component\\HttpClient\\EventSourceHttpClient`, open a +connection to a server with the `text/event-stream` content type and consume the stream:: + + use Symfony\Component\HttpClient\EventSourceHttpClient; + + $client = new EventSourceHttpClient($client, 10); + $source = $client->connect('http://localhost:8080/events'); + while ($source) { + foreach ($client->stream($source, 2) as $r => $chunk) { + // You should handle these chunks yourself + if ($chunk->isTimeout()) { + dump([ + 'timeout' => [ + 'retry' => 1 + count($r->getInfo('previous_info') ?? []) + ], + ]); + continue; + } + if ($chunk->isLast()) { + dump([ + 'eof' => [ + 'retries' => count($r->getInfo('previous_info') ?? []) + ], + ]); + $source = null; + return; + } + + // This is a special ServerSentEvent chunk holding the pushed message + if ($chunk instanceof ServerSentEvent) { + dump($chunk); + } + } + } + +The default reconnection time is `10` seconds and is given onto the second argument of +the :class:`Symfony\\Component\\HttpClient\\EventSourceHttpClient`. The method +:method:`Symfony\\Component\\HttpClient\\Response\\AsyncResponse::stream` takes an +optional timeout argument. +The :class:`Symfony\\Component\\HttpClient\\Chunk\\ServerSentEvent` is a special chunk +capable of parsing an event stream as specified by the `EventSource`_ specification. + Interoperability ---------------- @@ -1419,3 +1465,4 @@ However, using ``MockResponse`` allows simulating chunked responses and timeouts .. _`libcurl`: https://curl.haxx.se/libcurl/ .. _`amphp/http-client`: https://packagist.org/packages/amphp/http-client .. _`cURL options`: https://www.php.net/manual/en/function.curl-setopt.php +.. _`EventSource`: https://www.w3.org/TR/eventsource/#eventsource From da7c12b5ade242d9848f18fd423c84db15167b84 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 23 Sep 2020 12:14:57 +0200 Subject: [PATCH 0473/1519] Rewords and tweaks --- http_client.rst | 56 +++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/http_client.rst b/http_client.rst index 84f3f14f30b..7e46abfce4e 100644 --- a/http_client.rst +++ b/http_client.rst @@ -1146,49 +1146,54 @@ installed in your application:: Consuming Server-Sent Events ---------------------------- -This component provides an `EventSource`_ implementation to consume Server-Sent Events. -Use the :class:`Symfony\\Component\\HttpClient\\EventSourceHttpClient`, open a -connection to a server with the `text/event-stream` content type and consume the stream:: +.. versionadded:: 5.2 + + The feature to consume server-sent events was introduced in Symfony 5.2. + +`Server-sent events`_ is an Internet standard used to push data to web pages. +Its JavaScript API is built around an `EventSource`_ object, which listens to +the events sent from some URL. The events are a stream of data (served with the +``text/event-stream`` MIME type) with the following format: + +.. code-block:: text + + data: This is the first message. + + data: This is the second message, it + data: has two lines. + + data: This is the third message. + +Symfony's HTTP client provides an EventSource implementation to consume these +server-sent events. Use the :class:`Symfony\\Component\\HttpClient\\EventSourceHttpClient` +to wrap your HTTP client, open a connection to a server that responds with a +``text/event-stream`` content type and consume the stream as follows:: use Symfony\Component\HttpClient\EventSourceHttpClient; + // the second optional argument is the reconnection time in seconds (default = 10) $client = new EventSourceHttpClient($client, 10); - $source = $client->connect('http://localhost:8080/events'); + $source = $client->connect('https://localhost:8080/events'); while ($source) { foreach ($client->stream($source, 2) as $r => $chunk) { - // You should handle these chunks yourself if ($chunk->isTimeout()) { - dump([ - 'timeout' => [ - 'retry' => 1 + count($r->getInfo('previous_info') ?? []) - ], - ]); + // ... continue; } + if ($chunk->isLast()) { - dump([ - 'eof' => [ - 'retries' => count($r->getInfo('previous_info') ?? []) - ], - ]); - $source = null; + // ... + return; } - // This is a special ServerSentEvent chunk holding the pushed message + // this is a special ServerSentEvent chunk holding the pushed message if ($chunk instanceof ServerSentEvent) { - dump($chunk); + // do something with the server event ... } } } -The default reconnection time is `10` seconds and is given onto the second argument of -the :class:`Symfony\\Component\\HttpClient\\EventSourceHttpClient`. The method -:method:`Symfony\\Component\\HttpClient\\Response\\AsyncResponse::stream` takes an -optional timeout argument. -The :class:`Symfony\\Component\\HttpClient\\Chunk\\ServerSentEvent` is a special chunk -capable of parsing an event stream as specified by the `EventSource`_ specification. - Interoperability ---------------- @@ -1465,4 +1470,5 @@ However, using ``MockResponse`` allows simulating chunked responses and timeouts .. _`libcurl`: https://curl.haxx.se/libcurl/ .. _`amphp/http-client`: https://packagist.org/packages/amphp/http-client .. _`cURL options`: https://www.php.net/manual/en/function.curl-setopt.php +.. _`Server-sent events`: https://html.spec.whatwg.org/multipage/server-sent-events.html .. _`EventSource`: https://www.w3.org/TR/eventsource/#eventsource From 42e156e728f59e7fc0b6ef677eb24a22c68016c5 Mon Sep 17 00:00:00 2001 From: Alexander Menshchikov Date: Wed, 23 Sep 2020 20:31:47 +0300 Subject: [PATCH 0474/1519] New DI configuration syntax (PHP) instead of "legacy" --- controller/argument_value_resolver.rst | 12 +++- controller/upload_file.rst | 11 ++- doctrine/events.rst | 92 ++++++++++++++++---------- routing/custom_route_loader.rst | 12 +++- session/database.rst | 80 ++++++++++++++-------- 5 files changed, 136 insertions(+), 71 deletions(-) diff --git a/controller/argument_value_resolver.rst b/controller/argument_value_resolver.rst index cfd90123e51..00a57bfa0d9 100644 --- a/controller/argument_value_resolver.rst +++ b/controller/argument_value_resolver.rst @@ -226,11 +226,17 @@ and adding a priority. .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\ArgumentResolver\UserValueResolver; - $container->autowire(UserValueResolver::class) - ->addTag('controller.argument_value_resolver', ['priority' => 50]) - ; + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(UserValueResolver::class) + ->tag('controller.argument_value_resolver', ['priority' => 50]) + ; + }; While adding a priority is optional, it's recommended to add one to make sure the expected value is injected. The built-in ``RequestAttributeValueResolver``, diff --git a/controller/upload_file.rst b/controller/upload_file.rst index 470fbf61dcd..86d2eb72206 100644 --- a/controller/upload_file.rst +++ b/controller/upload_file.rst @@ -317,10 +317,17 @@ Then, define a service for this class: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Service\FileUploader; - $container->autowire(FileUploader::class) - ->setArgument('$targetDirectory', '%brochures_directory%'); + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(FileUploader::class) + ->arg('$targetDirectory', '%brochures_directory%') + ; + }; Now you're ready to use this service in the controller:: diff --git a/doctrine/events.rst b/doctrine/events.rst index b1a1fc8e825..7864b3c22f6 100644 --- a/doctrine/events.rst +++ b/doctrine/events.rst @@ -198,22 +198,28 @@ with the ``doctrine.event_listener`` tag: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\EventListener\SearchIndexer; - // listeners are applied by default to all Doctrine connections - $container->autowire(SearchIndexer::class) - ->addTag('doctrine.event_listener', [ - // this is the only required option for the lifecycle listener tag - 'event' => 'postPersist', + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + // listeners are applied by default to all Doctrine connections + $services->set(SearchIndexer::class) + ->tag('doctrine.event_listener', [ + // this is the only required option for the lifecycle listener tag + 'event' => 'postPersist', - // listeners can define their priority in case multiple listeners are associated - // to the same event (default priority = 0; higher numbers = listener is run earlier) - 'priority' => 500, + // listeners can define their priority in case multiple listeners are associated + // to the same event (default priority = 0; higher numbers = listener is run earlier) + 'priority' => 500, - # you can also restrict listeners to a specific Doctrine connection - 'connection' => 'default', - ]) - ; + # you can also restrict listeners to a specific Doctrine connection + 'connection' => 'default', + ]) + ; + }; .. tip:: @@ -314,29 +320,35 @@ with the ``doctrine.orm.entity_listener`` tag: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Entity\User; use App\EventListener\UserChangedNotifier; - $container->autowire(UserChangedNotifier::class) - ->addTag('doctrine.orm.entity_listener', [ - // These are the options required to define the entity listener: - 'event' => 'postUpdate', - 'entity' => User::class, + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(UserChangedNotifier::class) + ->tag('doctrine.orm.entity_listener', [ + // These are the options required to define the entity listener: + 'event' => 'postUpdate', + 'entity' => User::class, - // These are other options that you may define if needed: + // These are other options that you may define if needed: - // set the 'lazy' option to TRUE to only instantiate listeners when they are used - // 'lazy' => true, + // set the 'lazy' option to TRUE to only instantiate listeners when they are used + // 'lazy' => true, - // set the 'entity_manager' option if the listener is not associated to the default manager - // 'entity_manager' => 'custom', + // set the 'entity_manager' option if the listener is not associated to the default manager + // 'entity_manager' => 'custom', - // by default, Symfony looks for a method called after the event (e.g. postUpdate()) - // if it doesn't exist, it tries to execute the '__invoke()' method, but you can - // configure a custom method name with the 'method' option - // 'method' => 'checkUserChanges', - ]) - ; + // by default, Symfony looks for a method called after the event (e.g. postUpdate()) + // if it doesn't exist, it tries to execute the '__invoke()' method, but you can + // configure a custom method name with the 'method' option + // 'method' => 'checkUserChanges', + ]) + ; + }; Doctrine Lifecycle Subscribers ------------------------------ @@ -434,11 +446,17 @@ with the ``doctrine.event_subscriber`` tag: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\EventListener\DatabaseActivitySubscriber; - $container->autowire(DatabaseActivitySubscriber::class) - ->addTag('doctrine.event_subscriber') - ; + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(DatabaseActivitySubscriber::class) + ->tag('doctrine.event_subscriber') + ; + }; If you need to associate the subscriber with a specific Doctrine connection, you can do it in the service configuration: @@ -473,11 +491,17 @@ can do it in the service configuration: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\EventListener\DatabaseActivitySubscriber; - $container->autowire(DatabaseActivitySubscriber::class) - ->addTag('doctrine.event_subscriber', ['connection' => 'default']) - ; + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(DatabaseActivitySubscriber::class) + ->tag('doctrine.event_subscriber', ['connection' => 'default']) + ; + }; .. tip:: diff --git a/routing/custom_route_loader.rst b/routing/custom_route_loader.rst index 1aa1c882f94..a339ec74f61 100644 --- a/routing/custom_route_loader.rst +++ b/routing/custom_route_loader.rst @@ -327,11 +327,17 @@ Now define a service for the ``ExtraLoader``: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Routing\ExtraLoader; - $container->autowire(ExtraLoader::class) - ->addTag('routing.loader') - ; + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(ExtraLoader::class) + ->tag('routing.loader') + ; + }; Notice the tag ``routing.loader``. All services with this *tag* will be marked as potential route loaders and added as specialized route loaders to the diff --git a/session/database.rst b/session/database.rst index 8766ab9f2a8..e01d32c6d79 100644 --- a/session/database.rst +++ b/session/database.rst @@ -217,16 +217,22 @@ first register a new handler service with your database credentials: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; - $storageDefinition = $container->autowire(PdoSessionHandler::class) - ->setArguments([ - '%env(DATABASE_URL)%', - // you can also use PDO configuration, but requires passing two arguments: - // 'mysql:dbname=mydatabase; host=myhost; port=myport', - // ['db_username' => 'myuser', 'db_password' => 'mypassword'], - ]) - ; + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(PdoSessionHandler::class) + ->args([ + '%env(DATABASE_URL)%', + // you can also use PDO configuration, but requires passing two arguments: + // 'mysql:dbname=mydatabase; host=myhost; port=myport', + // ['db_username' => 'myuser', 'db_password' => 'mypassword'], + ]) + ; + }; Next, use the :ref:`handler_id ` configuration option to tell Symfony to use this service as the session handler: @@ -306,15 +312,20 @@ passed to the ``PdoSessionHandler`` service: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; - // ... - $container->autowire(PdoSessionHandler::class) - ->setArguments([ - '%env(DATABASE_URL)%', - ['db_table' => 'customer_session', 'db_id_col' => 'guid'], - ]) - ; + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(PdoSessionHandler::class) + ->args([ + '%env(DATABASE_URL)%', + ['db_table' => 'customer_session', 'db_id_col' => 'guid'], + ]) + ; + }; These are parameters that you can configure: @@ -466,13 +477,19 @@ the MongoDB connection as argument: .. code-block:: php // config/services.php - use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler; + namespace Symfony\Component\DependencyInjection\Loader\Configurator; - $storageDefinition = $container->autowire(MongoDbSessionHandler::class) - ->setArguments([ - new Reference('doctrine_mongodb.odm.default_connection'), - ]) - ; + use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; + + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(MongoDbSessionHandler::class) + ->args([ + service('doctrine_mongodb.odm.default_connection'), + ]) + ; + }; Next, use the :ref:`handler_id ` configuration option to tell Symfony to use this service as the session handler: @@ -569,15 +586,20 @@ configure these values with the second argument passed to the .. code-block:: php // config/services.php - use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler; - // ... + namespace Symfony\Component\DependencyInjection\Loader\Configurator; - $container->autowire(MongoDbSessionHandler::class) - ->setArguments([ - '...', - ['id_field' => '_guid', 'expiry_field' => 'eol'], - ]) - ; + use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; + + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(MongoDbSessionHandler::class) + ->args([ + service('doctrine_mongodb.odm.default_connection'), + ['id_field' => '_guid', 'expiry_field' => 'eol'],, + ]) + ; + }; These are parameters that you can configure: From 295c688499218b75ea40e940e5d55b514509fa7a Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Thu, 24 Sep 2020 10:28:44 +0200 Subject: [PATCH 0475/1519] simple_preauth was removed in symfony 5.0 https://github.com/symfony/symfony/blob/master/UPGRADE-5.0.md#securitybundle --- reference/configuration/security.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index 9b5be8b387d..b0763e37b59 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -395,8 +395,6 @@ depend on the authentication mechanism, which can be any of these: # ... remote_user: # ... - simple_preauth: - # ... guard: # ... form_login: @@ -405,8 +403,6 @@ depend on the authentication mechanism, which can be any of these: # ... json_login: # ... - simple_form: - # ... http_basic: # ... http_basic_ldap: From 303419c615c39757d07b849aadde377bcff28f2c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 22 Sep 2020 16:36:54 +0200 Subject: [PATCH 0476/1519] [Messenger] Documented the delete_after_reject option --- messenger.rst | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/messenger.rst b/messenger.rst index 90d8c1c80a6..14cce1c4931 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1149,25 +1149,27 @@ a running Redis server (^5.0). A number of options can be configured via the DSN or via the ``options`` key under the transport in ``messenger.yaml``: -================== ===================================== ========================= - Option Description Default -================== ===================================== ========================= -stream The Redis stream name messages -group The Redis consumer group name symfony -consumer Consumer name used in Redis consumer -auto_setup Create the Redis group automatically? true -auth The Redis password -delete_after_ack If ``true``, messages are deleted false - automatically after processing them -serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` - in Redis (the - ``Redis::OPT_SERIALIZER`` option) -stream_max_entries The maximum number of entries which ``0`` (which means "no trimming") - the stream will be trimmed to. Set - it to a large enough number to - avoid losing pending messages -tls Enable TLS support for the connection false -================== ===================================== ========================= +=================== ===================================== ========================= + Option Description Default +=================== ===================================== ========================= +stream The Redis stream name messages +group The Redis consumer group name symfony +consumer Consumer name used in Redis consumer +auto_setup Create the Redis group automatically? true +auth The Redis password +delete_after_ack If ``true``, messages are deleted false + automatically after processing them +delete_after_reject If ``true``, messages are deleted true + automatically if they are rejected +serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` + in Redis (the + ``Redis::OPT_SERIALIZER`` option) +stream_max_entries The maximum number of entries which ``0`` (which means "no trimming") + the stream will be trimmed to. Set + it to a large enough number to + avoid losing pending messages +tls Enable TLS support for the connection false +=================== ===================================== ========================= .. tip:: @@ -1180,6 +1182,10 @@ tls Enable TLS support for the connection false The ``delete_after_ack`` option was introduced in Symfony 5.1. +.. versionadded:: 5.2 + + The ``delete_after_reject`` option was introduced in Symfony 5.2. + In Memory Transport ~~~~~~~~~~~~~~~~~~~ From 7db3301e3cc1d22bd7df4be39391517c5c900bf5 Mon Sep 17 00:00:00 2001 From: Alexander Menshchikov Date: Wed, 23 Sep 2020 20:31:47 +0300 Subject: [PATCH 0477/1519] New DI configuration syntax (PHP) instead of "legacy" (cherry picked from commit 42e156e728f59e7fc0b6ef677eb24a22c68016c5) --- controller/argument_value_resolver.rst | 12 +++- controller/upload_file.rst | 11 ++- doctrine/events.rst | 92 ++++++++++++++++---------- routing/custom_route_loader.rst | 12 +++- session/database.rst | 80 ++++++++++++++-------- 5 files changed, 136 insertions(+), 71 deletions(-) diff --git a/controller/argument_value_resolver.rst b/controller/argument_value_resolver.rst index cfd90123e51..00a57bfa0d9 100644 --- a/controller/argument_value_resolver.rst +++ b/controller/argument_value_resolver.rst @@ -226,11 +226,17 @@ and adding a priority. .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\ArgumentResolver\UserValueResolver; - $container->autowire(UserValueResolver::class) - ->addTag('controller.argument_value_resolver', ['priority' => 50]) - ; + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(UserValueResolver::class) + ->tag('controller.argument_value_resolver', ['priority' => 50]) + ; + }; While adding a priority is optional, it's recommended to add one to make sure the expected value is injected. The built-in ``RequestAttributeValueResolver``, diff --git a/controller/upload_file.rst b/controller/upload_file.rst index 470fbf61dcd..86d2eb72206 100644 --- a/controller/upload_file.rst +++ b/controller/upload_file.rst @@ -317,10 +317,17 @@ Then, define a service for this class: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Service\FileUploader; - $container->autowire(FileUploader::class) - ->setArgument('$targetDirectory', '%brochures_directory%'); + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(FileUploader::class) + ->arg('$targetDirectory', '%brochures_directory%') + ; + }; Now you're ready to use this service in the controller:: diff --git a/doctrine/events.rst b/doctrine/events.rst index b1a1fc8e825..7864b3c22f6 100644 --- a/doctrine/events.rst +++ b/doctrine/events.rst @@ -198,22 +198,28 @@ with the ``doctrine.event_listener`` tag: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\EventListener\SearchIndexer; - // listeners are applied by default to all Doctrine connections - $container->autowire(SearchIndexer::class) - ->addTag('doctrine.event_listener', [ - // this is the only required option for the lifecycle listener tag - 'event' => 'postPersist', + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + // listeners are applied by default to all Doctrine connections + $services->set(SearchIndexer::class) + ->tag('doctrine.event_listener', [ + // this is the only required option for the lifecycle listener tag + 'event' => 'postPersist', - // listeners can define their priority in case multiple listeners are associated - // to the same event (default priority = 0; higher numbers = listener is run earlier) - 'priority' => 500, + // listeners can define their priority in case multiple listeners are associated + // to the same event (default priority = 0; higher numbers = listener is run earlier) + 'priority' => 500, - # you can also restrict listeners to a specific Doctrine connection - 'connection' => 'default', - ]) - ; + # you can also restrict listeners to a specific Doctrine connection + 'connection' => 'default', + ]) + ; + }; .. tip:: @@ -314,29 +320,35 @@ with the ``doctrine.orm.entity_listener`` tag: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Entity\User; use App\EventListener\UserChangedNotifier; - $container->autowire(UserChangedNotifier::class) - ->addTag('doctrine.orm.entity_listener', [ - // These are the options required to define the entity listener: - 'event' => 'postUpdate', - 'entity' => User::class, + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(UserChangedNotifier::class) + ->tag('doctrine.orm.entity_listener', [ + // These are the options required to define the entity listener: + 'event' => 'postUpdate', + 'entity' => User::class, - // These are other options that you may define if needed: + // These are other options that you may define if needed: - // set the 'lazy' option to TRUE to only instantiate listeners when they are used - // 'lazy' => true, + // set the 'lazy' option to TRUE to only instantiate listeners when they are used + // 'lazy' => true, - // set the 'entity_manager' option if the listener is not associated to the default manager - // 'entity_manager' => 'custom', + // set the 'entity_manager' option if the listener is not associated to the default manager + // 'entity_manager' => 'custom', - // by default, Symfony looks for a method called after the event (e.g. postUpdate()) - // if it doesn't exist, it tries to execute the '__invoke()' method, but you can - // configure a custom method name with the 'method' option - // 'method' => 'checkUserChanges', - ]) - ; + // by default, Symfony looks for a method called after the event (e.g. postUpdate()) + // if it doesn't exist, it tries to execute the '__invoke()' method, but you can + // configure a custom method name with the 'method' option + // 'method' => 'checkUserChanges', + ]) + ; + }; Doctrine Lifecycle Subscribers ------------------------------ @@ -434,11 +446,17 @@ with the ``doctrine.event_subscriber`` tag: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\EventListener\DatabaseActivitySubscriber; - $container->autowire(DatabaseActivitySubscriber::class) - ->addTag('doctrine.event_subscriber') - ; + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(DatabaseActivitySubscriber::class) + ->tag('doctrine.event_subscriber') + ; + }; If you need to associate the subscriber with a specific Doctrine connection, you can do it in the service configuration: @@ -473,11 +491,17 @@ can do it in the service configuration: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\EventListener\DatabaseActivitySubscriber; - $container->autowire(DatabaseActivitySubscriber::class) - ->addTag('doctrine.event_subscriber', ['connection' => 'default']) - ; + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(DatabaseActivitySubscriber::class) + ->tag('doctrine.event_subscriber', ['connection' => 'default']) + ; + }; .. tip:: diff --git a/routing/custom_route_loader.rst b/routing/custom_route_loader.rst index 1aa1c882f94..a339ec74f61 100644 --- a/routing/custom_route_loader.rst +++ b/routing/custom_route_loader.rst @@ -327,11 +327,17 @@ Now define a service for the ``ExtraLoader``: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Routing\ExtraLoader; - $container->autowire(ExtraLoader::class) - ->addTag('routing.loader') - ; + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(ExtraLoader::class) + ->tag('routing.loader') + ; + }; Notice the tag ``routing.loader``. All services with this *tag* will be marked as potential route loaders and added as specialized route loaders to the diff --git a/session/database.rst b/session/database.rst index 8766ab9f2a8..e01d32c6d79 100644 --- a/session/database.rst +++ b/session/database.rst @@ -217,16 +217,22 @@ first register a new handler service with your database credentials: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; - $storageDefinition = $container->autowire(PdoSessionHandler::class) - ->setArguments([ - '%env(DATABASE_URL)%', - // you can also use PDO configuration, but requires passing two arguments: - // 'mysql:dbname=mydatabase; host=myhost; port=myport', - // ['db_username' => 'myuser', 'db_password' => 'mypassword'], - ]) - ; + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(PdoSessionHandler::class) + ->args([ + '%env(DATABASE_URL)%', + // you can also use PDO configuration, but requires passing two arguments: + // 'mysql:dbname=mydatabase; host=myhost; port=myport', + // ['db_username' => 'myuser', 'db_password' => 'mypassword'], + ]) + ; + }; Next, use the :ref:`handler_id ` configuration option to tell Symfony to use this service as the session handler: @@ -306,15 +312,20 @@ passed to the ``PdoSessionHandler`` service: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; - // ... - $container->autowire(PdoSessionHandler::class) - ->setArguments([ - '%env(DATABASE_URL)%', - ['db_table' => 'customer_session', 'db_id_col' => 'guid'], - ]) - ; + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(PdoSessionHandler::class) + ->args([ + '%env(DATABASE_URL)%', + ['db_table' => 'customer_session', 'db_id_col' => 'guid'], + ]) + ; + }; These are parameters that you can configure: @@ -466,13 +477,19 @@ the MongoDB connection as argument: .. code-block:: php // config/services.php - use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler; + namespace Symfony\Component\DependencyInjection\Loader\Configurator; - $storageDefinition = $container->autowire(MongoDbSessionHandler::class) - ->setArguments([ - new Reference('doctrine_mongodb.odm.default_connection'), - ]) - ; + use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; + + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(MongoDbSessionHandler::class) + ->args([ + service('doctrine_mongodb.odm.default_connection'), + ]) + ; + }; Next, use the :ref:`handler_id ` configuration option to tell Symfony to use this service as the session handler: @@ -569,15 +586,20 @@ configure these values with the second argument passed to the .. code-block:: php // config/services.php - use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler; - // ... + namespace Symfony\Component\DependencyInjection\Loader\Configurator; - $container->autowire(MongoDbSessionHandler::class) - ->setArguments([ - '...', - ['id_field' => '_guid', 'expiry_field' => 'eol'], - ]) - ; + use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; + + return static function (ContainerConfigurator $container) { + $services = $configurator->services(); + + $services->set(MongoDbSessionHandler::class) + ->args([ + service('doctrine_mongodb.odm.default_connection'), + ['id_field' => '_guid', 'expiry_field' => 'eol'],, + ]) + ; + }; These are parameters that you can configure: From 11f45325f49f518244ea669e1ec7327e2397f833 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 24 Sep 2020 17:57:18 +0200 Subject: [PATCH 0478/1519] User service() instead of ref() --- service_container.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service_container.rst b/service_container.rst index 95ef942fab6..24fb39dc982 100644 --- a/service_container.rst +++ b/service_container.rst @@ -483,7 +483,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 ``ref`` function: +parameter and in PHP config use the ``service()`` function: .. configuration-block:: From a2ad274caafaa4d4bafa5f28e6a4768519c8d0b5 Mon Sep 17 00:00:00 2001 From: Nate Wiebe Date: Mon, 14 Sep 2020 18:16:20 -0400 Subject: [PATCH 0479/1519] Translatable objects --- reference/twig_reference.rst | 29 ++++++++++++++++++++++++++++- translation.rst | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 0a6c9db3154..ed02f32d633 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -304,6 +304,27 @@ impersonation_exit_url It's similar to the `impersonation_exit_path`_ function, but it generates absolute URLs instead of relative URLs. +t +~ + +.. code-block:: twig + + {{ t(message, parameters = [], domain = 'messages')|trans }} + +``message`` + **type**: ``string`` +``parameters`` *(optional)* + **type**: ``array`` **default**: ``[]`` +``domain`` *(optional)* + **type**: ``string`` **default**: ``messages`` + +.. versionadded:: 5.2 + + The ``t()`` function was introduced in Symfony 5.2. + +Creates a ``Translatable`` object that can be passed to the +:ref:`trans filter `. + Form Related Functions ~~~~~~~~~~~~~~~~~~~~~~ @@ -341,6 +362,8 @@ Makes a technical name human readable (i.e. replaces underscores by spaces or transforms camelCase text like ``helloWorld`` to ``hello world`` and then capitalizes the string). +.. _reference-twig-filter-trans: + trans ~~~~~ @@ -349,7 +372,7 @@ trans {{ message|trans(arguments = [], domain = null, locale = null) }} ``message`` - **type**: ``string`` + **type**: ``string`` | ``Translatable`` ``arguments`` *(optional)* **type**: ``array`` **default**: ``[]`` ``domain`` *(optional)* @@ -357,6 +380,10 @@ trans ``locale`` *(optional)* **type**: ``string`` **default**: ``null`` +.. versionadded:: 5.2 + + ``message`` accepting ``Translatable`` as a valid type was introduced in Symfony 5.2. + Translates the text into the current language. More information in :ref:`Translation Filters `. diff --git a/translation.rst b/translation.rst index 19525ea38ce..2c7fc7922b6 100644 --- a/translation.rst +++ b/translation.rst @@ -292,6 +292,41 @@ To manage these situations, Symfony follows the `ICU MessageFormat`_ syntax by using PHP's :phpclass:`MessageFormatter` class. Read more about this in :doc:`/translation/message_format`. +Translatable Objects +-------------------- + +.. versionadded:: 5.2 + + Translatable objects were introduced in Symfony 5.2. + +Sometimes you may want to create a message, but at the time of creation aren't +sure how it would be translated. For example, it could be translated multiple +times if intended to be displayed to multiple users. + +Using translatable objects also allows preparing translations without having a +dependency on an entrypoint (such as a router) where the context for performing +the translation is provided. For example, entities could prepare translatable +strings (such as labels) without the need for a translator. + +Instead of translating a string at the time of creation, a ``Translatable`` +object can be created that can then be translated when used. Later this message +can be translated with a translator in either PHP or in Twig. + +PHP:: + + $message = new Translatable('Symfony is great!'); + $message = t('Symfony is great!'); + + Translatable::trans($translator, $message); + +Twig: + +.. code-block:: html+twig + + {% set message = t('Symfony is great!') %} + +

{{ message|trans }}

+ .. _translation-in-templates: Translations in Templates From 5aa74875e52cdaab6bbbe7e1f7967ac07a7c56b2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 25 Sep 2020 12:24:17 +0200 Subject: [PATCH 0480/1519] Minor rewords --- reference/twig_reference.rst | 2 ++ translation.rst | 40 ++++++++++++++++++++---------------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index ed02f32d633..b70dbb0e0aa 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -304,6 +304,8 @@ impersonation_exit_url It's similar to the `impersonation_exit_path`_ function, but it generates absolute URLs instead of relative URLs. +.. _reference-twig-function-t: + t ~ diff --git a/translation.rst b/translation.rst index 2c7fc7922b6..1c667e2e3ca 100644 --- a/translation.rst +++ b/translation.rst @@ -299,33 +299,37 @@ Translatable Objects Translatable objects were introduced in Symfony 5.2. -Sometimes you may want to create a message, but at the time of creation aren't -sure how it would be translated. For example, it could be translated multiple -times if intended to be displayed to multiple users. +Sometimes translating contents in templates is cumbersome because you need the +original message, the translation parameters and the translation domain for +each content. Making the translation in the controller or services simplifies +your templates, but requires injecting the translator service in different +parts of your application and mocking it in your tests. -Using translatable objects also allows preparing translations without having a -dependency on an entrypoint (such as a router) where the context for performing -the translation is provided. For example, entities could prepare translatable -strings (such as labels) without the need for a translator. +Instead of translating a string at the time of creation, you can use a +"translatable object", which is an instance of the +:class:`Symfony\\Component\\Translation\\Translatable` class. This object stores +all the information needed to fully translate its contents when needed:: -Instead of translating a string at the time of creation, a ``Translatable`` -object can be created that can then be translated when used. Later this message -can be translated with a translator in either PHP or in Twig. - -PHP:: + use Symfony\Component\Translation\Translatable; + // the first argument is required and it's the original message $message = new Translatable('Symfony is great!'); - $message = t('Symfony is great!'); - - Translatable::trans($translator, $message); + // the optional second argument defines the translation parameters and + // the optional third argument is the translation domain + $status = new Translatable('order.status', ['order' => $order], 'store'); -Twig: +Templates are now much simpler because you can pass translatable objects to the +``trans`` filter: .. code-block:: html+twig - {% set message = t('Symfony is great!') %} -

{{ message|trans }}

+

{{ status|trans }}

+ +.. tip:: + + There's also a :ref:`function called t() `, + available both in Twig and PHP, as a shortcut to create translatable objects. .. _translation-in-templates: From a1e19e2d67b1f92cb444d24c52835f6b18c08a3b Mon Sep 17 00:00:00 2001 From: Yann LUCAS Date: Wed, 23 Sep 2020 14:26:28 +0200 Subject: [PATCH 0481/1519] [Mailer] Added documentation for Sendinblue bridge --- mailer.rst | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/mailer.rst b/mailer.rst index 7c75e72032b..e2c166af89c 100644 --- a/mailer.rst +++ b/mailer.rst @@ -38,9 +38,9 @@ Using a 3rd Party Transport Instead of using your own SMTP server, you can send emails via a 3rd party provider. Mailer supports several - install whichever you want: -================== ============================================= +================== ============================================== Service Install with -================== ============================================= +================== ============================================== Amazon SES ``composer require symfony/amazon-mailer`` Gmail ``composer require symfony/google-mailer`` MailChimp ``composer require symfony/mailchimp-mailer`` @@ -48,7 +48,8 @@ Mailgun ``composer require symfony/mailgun-mailer`` Mailjet ``composer require symfony/mailjet-mailer`` Postmark ``composer require symfony/postmark-mailer`` SendGrid ``composer require symfony/sendgrid-mailer`` -================== ============================================= +Sendinblue ``composer require symfony/sendinblue-mailer`` +================== ============================================== Each library includes a :ref:`Symfony Flex recipe ` that will add a configuration example to your ``.env`` file. For example, suppose you want to @@ -87,17 +88,18 @@ transport, but you can force to use one: This table shows the full list of available DSN formats for each third party provider: -==================== ============================================= =========================================== ======================================== - Provider SMTP HTTP API -==================== ============================================= =========================================== ======================================== - Amazon SES ses+smtp://ACCESS_KEY:SECRET_KEY@default ses+https://ACCESS_KEY:SECRET_KEY@default ses+api://ACCESS_KEY:SECRET_KEY@default - Google Gmail gmail+smtp://USERNAME:PASSWORD@default n/a n/a - Mailchimp Mandrill mandrill+smtp://USERNAME:PASSWORD@default mandrill+https://KEY@default mandrill+api://KEY@default - Mailgun mailgun+smtp://USERNAME:PASSWORD@default mailgun+https://KEY:DOMAIN@default mailgun+api://KEY:DOMAIN@default - Mailjet mailjet+smtp://ACCESS_KEY:SECRET_KEY@default n/a mailjet+api://ACCESS_KEY:SECRET_KEY@default - Postmark postmark+smtp://ID:ID@default n/a postmark+api://KEY@default - Sendgrid sendgrid+smtp://apikey:KEY@default n/a sendgrid+api://KEY@default -==================== ============================================= =========================================== ======================================== +==================== ==================================================== =========================================== ======================================== + Provider SMTP HTTP API +==================== ==================================================== =========================================== ======================================== + Amazon SES ses+smtp://ACCESS_KEY:SECRET_KEY@default ses+https://ACCESS_KEY:SECRET_KEY@default ses+api://ACCESS_KEY:SECRET_KEY@default + Google Gmail gmail+smtp://USERNAME:PASSWORD@default n/a n/a + Mailchimp Mandrill mandrill+smtp://USERNAME:PASSWORD@default mandrill+https://KEY@default mandrill+api://KEY@default + Mailgun mailgun+smtp://USERNAME:PASSWORD@default mailgun+https://KEY:DOMAIN@default mailgun+api://KEY:DOMAIN@default + Mailjet mailjet+smtp://ACCESS_KEY:SECRET_KEY@default n/a mailjet+api://ACCESS_KEY:SECRET_KEY@default + Postmark postmark+smtp://ID:ID@default n/a postmark+api://KEY@default + Sendgrid sendgrid+smtp://apikey:KEY@default n/a sendgrid+api://KEY@default + Sendinblue sendinblue+smtp://apikey:USERNAME:PASSWORD@default n/a sendinblue+api://KEY@default +==================== ==================================================== =========================================== ======================================== .. caution:: From 6e81b35e4cf3de24228ae227196c593776045165 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 25 Sep 2020 14:17:36 +0200 Subject: [PATCH 0482/1519] Added the versionadded directive --- mailer.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mailer.rst b/mailer.rst index e2c166af89c..0745bc014de 100644 --- a/mailer.rst +++ b/mailer.rst @@ -51,6 +51,10 @@ SendGrid ``composer require symfony/sendgrid-mailer`` Sendinblue ``composer require symfony/sendinblue-mailer`` ================== ============================================== +.. versionadded:: 5.2 + + The Sendinblue integration was introduced in Symfony 5.2. + Each library includes a :ref:`Symfony Flex recipe ` that will add a configuration example to your ``.env`` file. For example, suppose you want to use SendGrid. First, install it: From 82880aaee60fc0286d67f50a63cb1fe6bd4c485e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 25 Sep 2020 14:50:32 +0200 Subject: [PATCH 0483/1519] [Validator] Document the invalidDateTimeMessage option --- reference/constraints/Range.rst | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/reference/constraints/Range.rst b/reference/constraints/Range.rst index 4470d26eb07..d5b473362dd 100644 --- a/reference/constraints/Range.rst +++ b/reference/constraints/Range.rst @@ -6,6 +6,7 @@ Validates that a given number or ``DateTime`` object is *between* some minimum a ========== =================================================================== Applies to :ref:`property or method ` Options - `groups`_ + - `invalidDateTimeMessage`_ - `invalidMessage`_ - `max`_ - `maxMessage`_ @@ -316,13 +317,33 @@ Options .. include:: /reference/constraints/_groups-option.rst.inc +invalidDateTimeMessage +~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``This value should be a valid number.`` + +.. versionadded:: 5.2 + + The ``invalidDateTimeMessage`` option was introduced in Symfony 5.2. + +The message displayed when the ``min`` and ``max`` values are PHP datetimes but +the given value is not. + +You can use the following parameters in this message: + +=============== ============================================================== +Parameter Description +=============== ============================================================== +``{{ value }}`` The current (invalid) value +=============== ============================================================== + invalidMessage ~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This value should be a valid number.`` -The message that will be shown if the underlying value is not a number (per -the :phpfunction:`is_numeric` PHP function). +The message displayed when the ``min`` and ``max`` values are numeric (per +the :phpfunction:`is_numeric` PHP function) but the given value is not. You can use the following parameters in this message: From 6c5a809675c7a4cb7ae86969356998ff5ca0aa44 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 25 Sep 2020 15:29:18 +0200 Subject: [PATCH 0484/1519] Minor tweak --- http_client.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/http_client.rst b/http_client.rst index f7aa8546da9..51cd799fea6 100644 --- a/http_client.rst +++ b/http_client.rst @@ -1462,9 +1462,12 @@ However, using ``MockResponse`` allows simulating chunked responses and timeouts $mockResponse = new MockResponse($body()); -Using the Symfony Framework, if you want to use your callback in functional tests, you can do as follow: +.. versionadded:: 5.2 + + The feature explained below was introduced in Symfony 5.2. -First, create an invokable or iterable class responsible of generating the response:: +Finally, you can also create an invokable or iterable class that generates the +responses and use it as a callback in functional tests:: namespace App\Tests; @@ -1481,7 +1484,7 @@ First, create an invokable or iterable class responsible of generating the respo } } -Then configure the framework to use your callback: +Then configure Symfony to use your callback: .. configuration-block:: @@ -1535,9 +1538,6 @@ Then configure the framework to use your callback: ], ]); - -The ``MockHttpClient`` will now be used in test environment with your callback to generate responses. - .. _`cURL PHP extension`: https://www.php.net/curl .. _`PSR-17`: https://www.php-fig.org/psr/psr-17/ .. _`PSR-18`: https://www.php-fig.org/psr/psr-18/ From 5cb0e366431c938c541a64d5220a0f13c38ba9b6 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Thu, 13 Aug 2020 16:59:22 +0200 Subject: [PATCH 0485/1519] [VarDumper] Document the VAR_DUMPER_FORMAT=server format --- components/var_dumper.rst | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/components/var_dumper.rst b/components/var_dumper.rst index e89c822c21f..44bb21c6304 100644 --- a/components/var_dumper.rst +++ b/components/var_dumper.rst @@ -66,7 +66,7 @@ current PHP SAPI: You can also select the output format explicitly defining the ``VAR_DUMPER_FORMAT`` environment variable and setting its value to either - ``html`` or ``cli``. + ``html``, ``cli`` or :ref:`server `. .. note:: @@ -186,6 +186,39 @@ Then you can use the following command to start a server out-of-the-box: $ ./vendor/bin/var-dump-server [OK] Server listening on tcp://127.0.0.1:9912 +.. _var-dumper-dump-server-format: + +Debug any project with the server format +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There is a way to force the ``VarDumper`` to dump to a server, without the need to configure anything in your +application: by using the ``VAR_DUMPER_FORMAT=server`` environment variable. +It is especially useful to debug any project (as soon as the VarDumper component is installed), +without altering its code by: + +* starting a server: + + .. code-block:: terminal + + $ ./vendor/bin/var-dump-server + +* running your code with the ``VAR_DUMPER_FORMAT=server`` env variable. For instance, for a CLI command: + + .. code-block:: terminal + + $ VAR_DUMPER_FORMAT=server [your-cli-command] + + .. tip:: + + If your project loads environment variables from a dotenv file, you can set the ``VAR_DUMPER_FORMAT=server`` + environment variable in there as well. + +.. note:: + + The host used to contact the server when using the ``server`` format is the one configured by the + ``VAR_DUMPER_SERVER`` var or defaults to ``127.0.0.1:9912``. + But you can configure the host through the ``VAR_DUMPER_FORMAT=tcp://127.0.0.1:1234`` environment variable as well. + DebugBundle and Twig Integration -------------------------------- From 738ed6907167c68d1657a9a6b009ef69caf18d95 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 25 Sep 2020 16:19:01 +0200 Subject: [PATCH 0486/1519] Reword --- components/var_dumper.rst | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/components/var_dumper.rst b/components/var_dumper.rst index 44bb21c6304..b661bd7a44a 100644 --- a/components/var_dumper.rst +++ b/components/var_dumper.rst @@ -188,36 +188,36 @@ Then you can use the following command to start a server out-of-the-box: .. _var-dumper-dump-server-format: -Debug any project with the server format -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Configuring the Dump Server with Environment Variables +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -There is a way to force the ``VarDumper`` to dump to a server, without the need to configure anything in your -application: by using the ``VAR_DUMPER_FORMAT=server`` environment variable. -It is especially useful to debug any project (as soon as the VarDumper component is installed), -without altering its code by: +.. versionadded:: 5.2 -* starting a server: + The ``VAR_DUMPER_FORMAT=server`` feature was introduced in Symfony 5.2. - .. code-block:: terminal +If you prefer to not modify the application configuration (e.g. to quickly debug +a project given to you) use the ``VAR_DUMPER_FORMAT`` env var. - $ ./vendor/bin/var-dump-server +First, start the server as usual: -* running your code with the ``VAR_DUMPER_FORMAT=server`` env variable. For instance, for a CLI command: +.. code-block:: terminal - .. code-block:: terminal + $ ./vendor/bin/var-dump-server - $ VAR_DUMPER_FORMAT=server [your-cli-command] +Then, run your code with the ``VAR_DUMPER_FORMAT=server`` env var by configuring +this value in the :ref:`.env file of your application `. For +console commands, you can also define this env var as follows: - .. tip:: +.. code-block:: terminal - If your project loads environment variables from a dotenv file, you can set the ``VAR_DUMPER_FORMAT=server`` - environment variable in there as well. + $ VAR_DUMPER_FORMAT=server [your-cli-command] .. note:: - The host used to contact the server when using the ``server`` format is the one configured by the - ``VAR_DUMPER_SERVER`` var or defaults to ``127.0.0.1:9912``. - But you can configure the host through the ``VAR_DUMPER_FORMAT=tcp://127.0.0.1:1234`` environment variable as well. + The host used by the ``server`` format is the one configured in the + ``VAR_DUMPER_SERVER`` env var or ``127.0.0.1:9912`` if none is defined. + If you prefer, you can also configure the host in the ``VAR_DUMPER_FORMAT`` + env var like this: ``VAR_DUMPER_FORMAT=tcp://127.0.0.1:1234``. DebugBundle and Twig Integration -------------------------------- From 03f119a3d156ec7dd137c3a9921d2a06ff7b0f79 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 25 Sep 2020 16:37:42 +0200 Subject: [PATCH 0487/1519] Tweaks --- event_dispatcher.rst | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/event_dispatcher.rst b/event_dispatcher.rst index 5f299cd2459..466464287b0 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -100,13 +100,17 @@ using a special "tag": .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\EventListener\ExceptionListener; - - $services = $containerConfigurator->services(); - $services->set(ExceptionListener::class) - ->addTag('kernel.event_listener', ['event' => 'kernel.exception']) - ; + return function(ContainerConfigurator $configurator) { + $services = $configurator->services(); + + $services->set(ExceptionListener::class) + ->addTag('kernel.event_listener', ['event' => 'kernel.exception']) + ; + }; Symfony follows this logic to decide which method to call inside the event listener class: From 945a879c1d3d0b428d5b0dfb0c2938d80e2b387a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 25 Sep 2020 17:04:47 +0200 Subject: [PATCH 0488/1519] Fixed CI issue --- http_client.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http_client.rst b/http_client.rst index 51cd799fea6..49d7cc780b4 100644 --- a/http_client.rst +++ b/http_client.rst @@ -1471,8 +1471,8 @@ responses and use it as a callback in functional tests:: namespace App\Tests; - use Symfony\Contracts\HttpClient\ResponseInterface; use Symfony\Component\HttpClient\Response\MockResponse; + use Symfony\Contracts\HttpClient\ResponseInterface; class MockClientCallback { From 84de0dc77713b1448d2fc293f2fa1eb6d8d3fc30 Mon Sep 17 00:00:00 2001 From: Matt Trask Date: Tue, 28 Jul 2020 11:00:29 -0500 Subject: [PATCH 0489/1519] [Process] Update process.rst --- components/process.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/components/process.rst b/components/process.rst index c7b286fec71..092009a5b40 100644 --- a/components/process.rst +++ b/components/process.rst @@ -377,10 +377,9 @@ instead:: Using a Prepared Command Line ----------------------------- -You can run the process by using a a prepared command line using the -double bracket notation. You can use a placeholder in order to have a -process that can only be changed with the values and without changing -the PHP code:: +You can run a process by using a prepared command line with double quote variable notation. +This allows you to use placeholders so that only the parameterized values can be changed, +but not the rest of the script: use Symfony\Component\Process\Process; From 43f5af5d13caeb8ecc3c2a6ac538f17138524c09 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 25 Sep 2020 17:35:27 +0200 Subject: [PATCH 0490/1519] Wrap some long lines --- components/process.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/process.rst b/components/process.rst index 092009a5b40..527214dca62 100644 --- a/components/process.rst +++ b/components/process.rst @@ -377,9 +377,9 @@ instead:: Using a Prepared Command Line ----------------------------- -You can run a process by using a prepared command line with double quote variable notation. -This allows you to use placeholders so that only the parameterized values can be changed, -but not the rest of the script: +You can run a process by using a prepared command line with double quote +variable notation. This allows you to use placeholders so that only the +parameterized values can be changed, but not the rest of the script: use Symfony\Component\Process\Process; From 517cbc0378fd38db07444e6caf7e36c0c4099281 Mon Sep 17 00:00:00 2001 From: Steve Grunwell Date: Fri, 25 Sep 2020 15:23:57 -0400 Subject: [PATCH 0491/1519] Document the SYMFONY_MAX_PHPUNIT_VERSION environment variable This documentation corresponds with symfony/symfony#38305. --- components/phpunit_bridge.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 2e824973354..dba2d4b9e4e 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -876,6 +876,10 @@ If you have installed the bridge through Composer, you can run it by calling e.g It's also possible to set ``SYMFONY_PHPUNIT_VERSION`` as a real env var (not defined in a :ref:`dotenv file `). + In the same way, ``SYMFONY_MAX_PHPUNIT_VERSION`` will set the maximum version + of PHPUnit to be considered. This is useful when testing a framework that does + not support the latest version(s) of PHPUnit. + .. tip:: If you still need to use ``prophecy`` (but not ``symfony/yaml``), From 24b9aeba8f108a10e2900bbfc18725d85f17e5ce Mon Sep 17 00:00:00 2001 From: Nate Wiebe Date: Sun, 27 Sep 2020 10:45:10 -0400 Subject: [PATCH 0492/1519] Change translatable example parameter key --- translation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translation.rst b/translation.rst index 1c667e2e3ca..238e80ee38c 100644 --- a/translation.rst +++ b/translation.rst @@ -316,7 +316,7 @@ all the information needed to fully translate its contents when needed:: $message = new Translatable('Symfony is great!'); // the optional second argument defines the translation parameters and // the optional third argument is the translation domain - $status = new Translatable('order.status', ['order' => $order], 'store'); + $status = new Translatable('order.status', ['%status%' => $order->getStatus()], 'store'); Templates are now much simpler because you can pass translatable objects to the ``trans`` filter: From bebcc58191dd515e5590bf8c887d53c3a7ed7421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Mon, 28 Sep 2020 15:47:15 +0200 Subject: [PATCH 0493/1519] Add documentation about fallback logic in lock --- components/lock.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/components/lock.rst b/components/lock.rst index c0f20586e6d..245aaa1de65 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -90,6 +90,18 @@ they can be decorated with the ``RetryTillSaveStore`` class:: $lock = $factory->createLock('notification-flush'); $lock->acquire(true); +When the provided store does not implements the +:class:`Symfony\\Component\\Lock\\BlockingStoreInterface` interface, the +``Lock`` class will try in a loop to acquire the lock in a non-blocking way +until the lock is acquired. + +.. deprecated:: 5.2 + + As of Symfony 5.2, you don't need anymore using the ``RetryTillSaveStore`` + class. The ``Lock`` class now provides the default logic to acquire locks in + blocking mode when the store does not implements the ``BlockingStoreInterface`` + interface. + Expiring Locks -------------- @@ -213,6 +225,11 @@ possible to **promote** the lock, and change it to write lock, by calling the In the same way, it's possible to **demote** a write lock, and change it to a read-only lock by calling the ``acquireRead()`` method. +When the provided store does not implements the +:class:`Symfony\\Component\\Lock\\SharedLockStoreInterface` interface, the +``Lock`` class will fallback to a write lock by calling the ``acquire()`` +method. + The Owner of The Lock --------------------- From d8fc70d486f3ca492661dc05c1b368ac82980bc1 Mon Sep 17 00:00:00 2001 From: Romaric Drigon Date: Mon, 28 Sep 2020 17:43:11 +0200 Subject: [PATCH 0494/1519] [Form] Added documentation for "html5" option of MoneyType and PercentType --- reference/forms/types/money.rst | 16 ++++++++++++++++ reference/forms/types/percent.rst | 14 +++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/reference/forms/types/money.rst b/reference/forms/types/money.rst index 9fd1d4a95f4..5952ba77b67 100644 --- a/reference/forms/types/money.rst +++ b/reference/forms/types/money.rst @@ -17,6 +17,7 @@ how the input and output of the data is handled. | Options | - `currency`_ | | | - `divisor`_ | | | - `grouping`_ | +| | - `html5`_ | | | - `rounding_mode`_ | | | - `scale`_ | +-------------+---------------------------------------------------------------------+ @@ -90,6 +91,21 @@ be set back on your object. .. include:: /reference/forms/types/options/rounding_mode.rst.inc +html5 +~~~~~ + +**type**: ``boolean`` **default**: ``false`` + +.. versionadded:: 5.2 + + This option was introduced in Symfony 5.2. + +If set to true, the HTML input will be rendered as a native HTML5 type="number" form. + +.. caution:: + + As HTML5 number format is normalized, it is incompatible with ``grouping`` option. + scale ~~~~~ diff --git a/reference/forms/types/percent.rst b/reference/forms/types/percent.rst index ca6c1c2e456..e35d54a022b 100644 --- a/reference/forms/types/percent.rst +++ b/reference/forms/types/percent.rst @@ -15,7 +15,8 @@ the input. +-------------+-----------------------------------------------------------------------+ | Rendered as | ``input`` ``text`` field | +-------------+-----------------------------------------------------------------------+ -| Options | - `rounding_mode`_ | +| Options | - `html5`_ | +| | - `rounding_mode`_ | | | - `scale`_ | | | - `symbol`_ | | | - `type`_ | @@ -57,6 +58,17 @@ Field Options The ``rounding_mode`` option was introduced in Symfony 5.1. +html5 +~~~~~ + +**type**: ``boolean`` **default**: ``false`` + +.. versionadded:: 5.2 + + This option was introduced in Symfony 5.2. + +If set to true, the HTML input will be rendered as a native HTML5 type="number" form. + scale ~~~~~ From c0ce045e61b9df49c8ad9ef4cbc90a3737f849e4 Mon Sep 17 00:00:00 2001 From: drixs6o9 Date: Tue, 29 Sep 2020 09:38:40 +0200 Subject: [PATCH 0495/1519] [Notifier] Added Sendinblue bridge documentation --- notifier.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 9d0b5148553..ab45707d306 100644 --- a/notifier.rst +++ b/notifier.rst @@ -63,6 +63,7 @@ Infobip ``symfony/infobip-notifier`` ``infobip://TOKEN@default?from=FRO Mobyt ``symfony/mobyt-notifier`` ``mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM`` Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` OvhCloud ``symfony/ovhcloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` +Sendinblue ``symfony/sendinblue-notifier`` ``sendinblue://API_KEY@default?sender=PHONE`` Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` Smsapi ``symfony/smsapi-notifier`` ``smsapi://TOKEN@default?from=FROM`` Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` @@ -74,7 +75,7 @@ Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from= .. versionadded:: 5.2 - The Smsapi, Infobip, Mobyt and Esendex integrations were introduced in Symfony 5.2. + The Smsapi, Infobip, Mobyt, Esendex and Sendinblue integrations were introduced in Symfony 5.2. To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: From 48b4756aa00778a99a009a500faaf17684cec691 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 29 Sep 2020 17:27:00 +0200 Subject: [PATCH 0496/1519] Tweaks --- components/lock.rst | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index 245aaa1de65..b9044baefca 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -90,17 +90,17 @@ they can be decorated with the ``RetryTillSaveStore`` class:: $lock = $factory->createLock('notification-flush'); $lock->acquire(true); -When the provided store does not implements the +When the provided store does not implement the :class:`Symfony\\Component\\Lock\\BlockingStoreInterface` interface, the -``Lock`` class will try in a loop to acquire the lock in a non-blocking way -until the lock is acquired. +``Lock`` class will retry to acquire the lock in a non-blocking way until the +lock is acquired. .. deprecated:: 5.2 - As of Symfony 5.2, you don't need anymore using the ``RetryTillSaveStore`` - class. The ``Lock`` class now provides the default logic to acquire locks in - blocking mode when the store does not implements the ``BlockingStoreInterface`` - interface. + As of Symfony 5.2, you don't need to use the ``RetryTillSaveStore`` class + anymore. The ``Lock`` class now provides the default logic to acquire locks + in blocking mode when the store does not implement the + ``BlockingStoreInterface`` interface. Expiring Locks -------------- @@ -225,10 +225,9 @@ possible to **promote** the lock, and change it to write lock, by calling the In the same way, it's possible to **demote** a write lock, and change it to a read-only lock by calling the ``acquireRead()`` method. -When the provided store does not implements the +When the provided store does not implement the :class:`Symfony\\Component\\Lock\\SharedLockStoreInterface` interface, the -``Lock`` class will fallback to a write lock by calling the ``acquire()`` -method. +``Lock`` class will fallback to a write lock by calling the ``acquire()`` method. The Owner of The Lock --------------------- From e5aa7615eb7125fa773310e3b9250a6cae73e000 Mon Sep 17 00:00:00 2001 From: Titouan Galopin Date: Sat, 26 Sep 2020 13:55:35 +0200 Subject: [PATCH 0497/1519] [Webpack Encore] Change default assets directory structure --- frontend/encore/advanced-config.rst | 8 +++---- frontend/encore/bootstrap.rst | 2 +- frontend/encore/code-splitting.rst | 6 ++--- frontend/encore/copy-files.rst | 2 +- frontend/encore/faq.rst | 2 +- frontend/encore/installation.rst | 18 +++++++-------- frontend/encore/shared-entry.rst | 10 ++++----- frontend/encore/simple-example.rst | 34 ++++++++++++++--------------- frontend/encore/split-chunks.rst | 8 +++---- mailer.rst | 8 +++---- 10 files changed, 49 insertions(+), 49 deletions(-) diff --git a/frontend/encore/advanced-config.rst b/frontend/encore/advanced-config.rst index eb77baef504..86bdb812b94 100644 --- a/frontend/encore/advanced-config.rst +++ b/frontend/encore/advanced-config.rst @@ -65,8 +65,8 @@ state of the current configuration to build a new one: Encore .setOutputPath('public/build/first_build/') .setPublicPath('/build/first_build') - .addEntry('app', './assets/js/app.js') - .addStyleEntry('global', './assets/css/global.scss') + .addEntry('app', './assets/app.js') + .addStyleEntry('global', './assets/styles/global.scss') .enableSassLoader() .autoProvidejQuery() .enableSourceMaps(!Encore.isProduction()) @@ -85,8 +85,8 @@ state of the current configuration to build a new one: Encore .setOutputPath('public/build/second_build/') .setPublicPath('/build/second_build') - .addEntry('mobile', './assets/js/mobile.js') - .addStyleEntry('mobile', './assets/css/mobile.less') + .addEntry('mobile', './assets/mobile.js') + .addStyleEntry('mobile', './assets/styles/mobile.less') .enableLessLoader() .enableSourceMaps(!Encore.isProduction()) ; diff --git a/frontend/encore/bootstrap.rst b/frontend/encore/bootstrap.rst index ff281f588ac..f1e28cabc37 100644 --- a/frontend/encore/bootstrap.rst +++ b/frontend/encore/bootstrap.rst @@ -18,7 +18,7 @@ a ``global.scss`` file, import it from there: .. code-block:: scss - // assets/css/global.scss + // assets/styles/global.scss // customize some Bootstrap variables $primary: darken(#428bca, 20%); diff --git a/frontend/encore/code-splitting.rst b/frontend/encore/code-splitting.rst index ffbfe8b4d28..759987e5f0a 100644 --- a/frontend/encore/code-splitting.rst +++ b/frontend/encore/code-splitting.rst @@ -9,7 +9,7 @@ clicked a link: .. code-block:: javascript - // assets/js/app.js + // assets/app.js import $ from 'jquery'; // a fictional "large" module (e.g. it imports video.js internally) @@ -27,13 +27,13 @@ the code via AJAX when it's needed: .. code-block:: javascript - // assets/js/app.js + // assets/app.js import $ from 'jquery'; $('.js-open-video').on('click', function() { // you could start a loading animation here - + // use import() as a function - it returns a Promise import('./components/VideoPlayer').then(({ default: VideoPlayer }) => { // you could stop a loading animation here diff --git a/frontend/encore/copy-files.rst b/frontend/encore/copy-files.rst index bc263ef056a..7ea5a541622 100644 --- a/frontend/encore/copy-files.rst +++ b/frontend/encore/copy-files.rst @@ -12,7 +12,7 @@ To reference an image tag from inside a JavaScript file, *require* the file: .. code-block:: javascript - // assets/js/app.js + // assets/app.js // returns the final, public path to this file // path is relative to this file - e.g. assets/images/logo.png diff --git a/frontend/encore/faq.rst b/frontend/encore/faq.rst index 3c621c3b8d0..c6c6d86c257 100644 --- a/frontend/encore/faq.rst +++ b/frontend/encore/faq.rst @@ -116,7 +116,7 @@ But, instead of working, you see an error: This dependency was not found: - * respond.js in ./assets/js/app.js + * respond.js in ./assets/app.js Typically, a package will "advertise" its "main" file by adding a ``main`` key to its ``package.json``. But sometimes, old libraries won't have this. Instead, you'll diff --git a/frontend/encore/installation.rst b/frontend/encore/installation.rst index 7cf878a1637..8241dbcd0b2 100644 --- a/frontend/encore/installation.rst +++ b/frontend/encore/installation.rst @@ -79,9 +79,9 @@ is the main config file for both Webpack and Webpack Encore: * Each entry will result in one JavaScript file (e.g. app.js) * and one CSS file (e.g. app.css) if your JavaScript imports CSS. */ - .addEntry('app', './assets/js/app.js') - //.addEntry('page1', './assets/js/page1.js') - //.addEntry('page2', './assets/js/page2.js') + .addEntry('app', './assets/app.js') + //.addEntry('page1', './assets/page1.js') + //.addEntry('page2', './assets/page2.js') // When enabled, Webpack "splits" your files into smaller pieces for greater optimization. .splitEntryChunks() @@ -124,17 +124,17 @@ is the main config file for both Webpack and Webpack Encore: // uncomment if you use API Platform Admin (composer require api-admin) //.enableReactPreset() - //.addEntry('admin', './assets/js/admin.js') + //.addEntry('admin', './assets/admin.js') ; module.exports = Encore.getWebpackConfig(); -Next, open the new ``assets/js/app.js`` file which contains some JavaScript code +Next, open the new ``assets/app.js`` file which contains some JavaScript code *and* imports some CSS: .. code-block:: javascript - // assets/js/app.js + // assets/app.js /* * Welcome to your app's main JavaScript file! * @@ -148,13 +148,13 @@ Next, open the new ``assets/js/app.js`` file which contains some JavaScript code // Need jQuery? Install it with "yarn add jquery", then uncomment to import it. // import $ from 'jquery'; - console.log('Hello Webpack Encore! Edit me in assets/js/app.js'); + console.log('Hello Webpack Encore! Edit me in assets/app.js'); -And the new ``assets/css/app.css`` file: +And the new ``assets/styles/app.css`` file: .. code-block:: css - /* assets/css/app.css */ + /* assets/styles/app.css */ body { background-color: lightgray; } diff --git a/frontend/encore/shared-entry.rst b/frontend/encore/shared-entry.rst index 6693b649d8d..a2c2d08ea2a 100644 --- a/frontend/encore/shared-entry.rst +++ b/frontend/encore/shared-entry.rst @@ -18,11 +18,11 @@ Update your code to use ``createSharedEntry()``: Encore // ... - - .addEntry('app', './assets/js/app.js') - + .createSharedEntry('app', './assets/js/app.js') - .addEntry('homepage', './assets/js/homepage.js') - .addEntry('blog', './assets/js/blog.js') - .addEntry('store', './assets/js/store.js') + - .addEntry('app', './assets/app.js') + + .createSharedEntry('app', './assets/app.js') + .addEntry('homepage', './assets/homepage.js') + .addEntry('blog', './assets/blog.js') + .addEntry('store', './assets/store.js') Before making this change, if both ``app.js`` and ``store.js`` require ``jquery``, then ``jquery`` would be packaged into *both* files, which is wasteful. By making diff --git a/frontend/encore/simple-example.rst b/frontend/encore/simple-example.rst index 03c5626ee02..30aa4400d1c 100644 --- a/frontend/encore/simple-example.rst +++ b/frontend/encore/simple-example.rst @@ -4,8 +4,8 @@ Encore: Setting up your Project After :doc:`installing Encore `, your app already has one CSS and one JS file, organized into an ``assets/`` directory: -* ``assets/js/app.js`` -* ``assets/css/app.css`` +* ``assets/app.js`` +* ``assets/styles/app.css`` With Encore, think of your ``app.js`` file like a standalone JavaScript application: it will *require* all of the dependencies it needs (e.g. jQuery or React), @@ -14,7 +14,7 @@ application: it will *require* all of the dependencies it needs (e.g. jQuery or .. code-block:: javascript - // assets/js/app.js + // assets/app.js // ... import '../css/app.css'; @@ -43,14 +43,14 @@ of your project. It already holds the basic config you need: // public path used by the web server to access the output path .setPublicPath('/build') - .addEntry('app', './assets/js/app.js') + .addEntry('app', './assets/app.js') // ... ; // ... -The *key* part is ``addEntry()``: this tells Encore to load the ``assets/js/app.js`` +The *key* part is ``addEntry()``: this tells Encore to load the ``assets/app.js`` file and follow *all* of the ``require()`` statements. It will then package everything together and - thanks to the first ``app`` argument - output final ``app.js`` and ``app.css`` files into the ``public/build`` directory. @@ -115,7 +115,7 @@ can do most of the work for you: .. _encore-entrypointsjson-simple-description: That's it! When you refresh your page, all of the JavaScript from -``assets/js/app.js`` - as well as any other JavaScript files it included - will +``assets/app.js`` - as well as any other JavaScript files it included - will be executed. All the CSS files that were required will also be displayed. The ``encore_entry_link_tags()`` and ``encore_entry_script_tags()`` functions @@ -143,7 +143,7 @@ files. First, create a file that exports a function: .. code-block:: javascript - // assets/js/greet.js + // assets/greet.js module.exports = function(name) { return `Yo yo ${name} - welcome to Encore!`; }; @@ -158,7 +158,7 @@ Great! Use ``require()`` to import ``jquery`` and ``greet.js``: .. code-block:: diff - // assets/js/app.js + // assets/app.js // ... + // loads the jquery package from node_modules @@ -187,7 +187,7 @@ To export values using the alternate syntax, use ``export``: .. code-block:: diff - // assets/js/greet.js + // assets/greet.js - module.exports = function(name) { + export default function(name) { return `Yo yo ${name} - welcome to Encore!`; @@ -197,7 +197,7 @@ To import values, use ``import``: .. code-block:: diff - // assets/js/app.js + // assets/app.js - require('../css/app.css'); + import '../css/app.css'; @@ -219,12 +219,12 @@ etc.). To handle this, create a new "entry" JavaScript file for each page: .. code-block:: javascript - // assets/js/checkout.js + // assets/checkout.js // custom code for your checkout page .. code-block:: javascript - // assets/js/account.js + // assets/account.js // custom code for your account page Next, use ``addEntry()`` to tell Webpack to read these two new files when it builds: @@ -234,9 +234,9 @@ Next, use ``addEntry()`` to tell Webpack to read these two new files when it bui // webpack.config.js Encore // ... - .addEntry('app', './assets/js/app.js') - + .addEntry('checkout', './assets/js/checkout.js') - + .addEntry('account', './assets/js/account.js') + .addEntry('app', './assets/app.js') + + .addEntry('checkout', './assets/checkout.js') + + .addEntry('account', './assets/account.js') // ... And because you just changed the ``webpack.config.js`` file, make sure to stop @@ -285,7 +285,7 @@ file to ``app.scss`` and update the ``import`` statement: .. code-block:: diff - // assets/js/app.js + // assets/app.js - import '../css/app.css'; + import '../css/app.scss'; @@ -336,7 +336,7 @@ If you want to only compile a CSS file, that's possible via ``addStyleEntry()``: Encore // ... - .addStyleEntry('some_page', './assets/css/some_page.css') + .addStyleEntry('some_page', './assets/styles/some_page.css') ; This will output a new ``some_page.css``. diff --git a/frontend/encore/split-chunks.rst b/frontend/encore/split-chunks.rst index ebaa4ee48ce..0205537b7d0 100644 --- a/frontend/encore/split-chunks.rst +++ b/frontend/encore/split-chunks.rst @@ -14,10 +14,10 @@ To enable this, call ``splitEntryChunks()``: // ... // multiple entry files, which probably import the same code - .addEntry('app', './assets/js/app.js') - .addEntry('homepage', './assets/js/homepage.js') - .addEntry('blog', './assets/js/blog.js') - .addEntry('store', './assets/js/store.js') + .addEntry('app', './assets/app.js') + .addEntry('homepage', './assets/homepage.js') + .addEntry('blog', './assets/blog.js') + .addEntry('store', './assets/store.js') + .splitEntryChunks() diff --git a/mailer.rst b/mailer.rst index 2d4838ba4b5..a932050c049 100644 --- a/mailer.rst +++ b/mailer.rst @@ -626,7 +626,7 @@ called ``css`` that points to the directory where ``email.css`` lives: paths: # point this wherever your css files live - '%kernel.project_dir%/assets/css': css + '%kernel.project_dir%/assets/styles': styles .. code-block:: xml @@ -642,7 +642,7 @@ called ``css`` that points to the directory where ``email.css`` lives: - %kernel.project_dir%/assets/css + %kernel.project_dir%/assets/styles @@ -653,7 +653,7 @@ called ``css`` that points to the directory where ``email.css`` lives: // ... 'paths' => [ // point this wherever your css files live - '%kernel.project_dir%/assets/css' => 'css', + '%kernel.project_dir%/assets/styles' => 'styles', ], ]); @@ -741,7 +741,7 @@ You can combine all filters to create complex email messages: This makes use of the :ref:`css Twig namespace ` we created earlier. You could, for example, `download the foundation-emails.css file`_ -directly from GitHub and save it in ``assets/css``. +directly from GitHub and save it in ``assets/styles``. Signing and Encrypting Messages ------------------------------- From f40fd45adda961236f6da8e3f767f8353138b176 Mon Sep 17 00:00:00 2001 From: RiffFred <72142966+RiffFred@users.noreply.github.com> Date: Wed, 30 Sep 2020 15:54:02 +0200 Subject: [PATCH 0498/1519] typo fix for the Signing Messages chapter fixes the syntax highlighting for the SMimeSigner code example fixes the DKIM wikipedia link --- mailer.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mailer.rst b/mailer.rst index 4f2ec4718a0..e257869b94d 100644 --- a/mailer.rst +++ b/mailer.rst @@ -798,7 +798,7 @@ S/MIME Signer ............. `S/MIME`_ is a standard for public key encryption and signing of MIME data. It -requires using both a certificate and a private key: +requires using both a certificate and a private key:: use Symfony\Component\Mime\Crypto\SMimeSigner; use Symfony\Component\Mime\Email; @@ -1168,7 +1168,7 @@ a specific address, instead of the *real* address: .. _`Markdown syntax`: https://commonmark.org/ .. _`Inky`: https://get.foundation/emails/docs/inky.html .. _`S/MIME`: https://en.wikipedia.org/wiki/S/MIME -.. _`DKIM`: `https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail +.. _`DKIM`: https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail .. _`OpenSSL PHP extension`: https://www.php.net/manual/en/book.openssl.php .. _`PEM encoded`: https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail .. _`default_socket_timeout`: https://www.php.net/manual/en/filesystem.configuration.php#ini.default-socket-timeout From 9fcc215a9f045f206cc776a2c4b87e7173d4e9dc Mon Sep 17 00:00:00 2001 From: Henri Larget <1727893+decima@users.noreply.github.com> Date: Thu, 1 Oct 2020 14:31:21 +0200 Subject: [PATCH 0499/1519] Update mailer.rst This is the signature of the method: ``` public function __construct(string $pk, string $domainName, string $selector, array $defaultOptions = [], string $passphrase = '') ``` --- mailer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mailer.rst b/mailer.rst index e257869b94d..352e3613fea 100644 --- a/mailer.rst +++ b/mailer.rst @@ -841,7 +841,7 @@ key but not a certificate:: // second and third arguments: the domain name and "selector" used to perform a DNS lookup // (the selector is a string used to point to a specific DKIM public key record in your DNS) $signer = new DkimSigner('file:///path/to/private-key.key', 'example.com', 'sf'); - // if the private key has a passphrase, pass it as the fourth argument + // if the private key has a passphrase, pass it as the fifth argument // new DkimSigner('file:///path/to/private-key.key', 'example.com', 'sf', [], 'the-passphrase'); $signedEmail = $signer->sign($email); From 7f0e8d8e8005db4420e7c0d854d76b4c08c19f43 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 2 Oct 2020 12:45:46 +0200 Subject: [PATCH 0500/1519] Tweaks and rewords --- http_client.rst | 25 ++++++++----- reference/configuration/framework.rst | 52 ++++++++++++++++++++------- 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/http_client.rst b/http_client.rst index 53e58bdcf39..7f44141a6dc 100644 --- a/http_client.rst +++ b/http_client.rst @@ -658,10 +658,23 @@ making a request. Use the ``max_redirects`` setting to configure this behavior Retry Failed Requests ~~~~~~~~~~~~~~~~~~~~~ -Some times, requests failed because of temporary issue in the server or -because network issue. You can use the -:class:`Symfony\\Component\\HttpClient\\RetryableHttpClient` -client to automatically retry the request when it fails.:: +.. versionadded:: 5.2 + + The feature to retry failed HTTP requests was introduced in Symfony 5.2. + +Sometimes, requests fail because of network issues or temporary server errors. +Symfony's HttpClient allows to retry failed requests automatically using the +:ref:`retry_failed option `. When enabled, +each failed request with an HTTP status of ``423``, ``425``, ``429``, ``500``, +``502``, ``503``, ``504``, ``507``, or ``510`` is retried up to 3 times, with an +exponential delay between retries (first retry = 1 second; third retry: 4 seconds). + +Check out the full list of configurable :ref:`retry_failed options ` +to learn how to tweak each of them to fit your application needs. + +When using the HttpClient outside of a Symfony application, use the +:class:`Symfony\\Component\\HttpClient\\RetryableHttpClient` class to wrap your +original HTTP client:: use Symfony\Component\HttpClient\RetryableHttpClient; @@ -673,10 +686,6 @@ decide if the request should be retried, and a :class:`Symfony\\Component\\HttpClient\\Retry\\RetryBackOffInterface` to define the waiting time between each retry. -By default, it retries until 3 attemps, the requests responding with a -status code in (423, 425, 429, 500, 502, 503, 504, 507 or 510) and wait -expentially from 1 second for the first retry, to 4 seconds at the 3rd attempt. - HTTP Proxies ~~~~~~~~~~~~ diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 1501f5a1540..c1c189d1f5a 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -792,6 +792,10 @@ will automaticaly retry failed HTTP requests. retry_failed: max_retries: 4 +.. versionadded:: 5.2 + + The ``retry_failed`` option was introduced in Symfony 5.2. + auth_basic .......... @@ -824,13 +828,15 @@ backoff_service **type**: ``string`` +.. versionadded:: 5.2 + + The ``backoff_service`` option was introduced in Symfony 5.2. + The service id used to compute the time to wait between retries. By default, it uses an instance of :class:`Symfony\\Component\\HttpClient\\Retry\\ExponentialBackOff` configured with ``delay``, ``max_delay`` and ``multiplier`` options. This class has to implement :class:`Symfony\\Component\\HttpClient\\Retry\\RetryBackOffInterface`. -This options cannot be used along `delay`_, `max_delay`_ or `multiplier`_ -options. base_uri ........ @@ -905,20 +911,26 @@ decider_service **type**: ``string`` +.. versionadded:: 5.2 + + The ``decider_service`` option was introduced in Symfony 5.2. + The service id used to decide if a request should be retried. By default, it uses an instance of :class:`Symfony\\Component\\HttpClient\\Retry\\HttpStatusCodeDecider` configured -with ``http_codes`` options. This class has to -implement :class:`Symfony\\Component\\HttpClient\\Retry\\RetryDeciderInterface`. -This options cannot be used along `http_codes`_ option. +with the ``http_codes`` option. This class has to implement +:class:`Symfony\\Component\\HttpClient\\Retry\\RetryDeciderInterface`. delay ..... **type**: ``integer`` **default**: ``1000`` -The initial delay in milliseconds used to compute the waiting time between -retries. This options cannot be used along `backoff_service`_ option. +.. versionadded:: 5.2 + + The ``delay`` option was introduced in Symfony 5.2. + +The initial delay in milliseconds used to compute the waiting time between retries. .. _reference-http-client-retry-enabled: @@ -943,8 +955,11 @@ http_codes **type**: ``array`` **default**: ``[423, 425, 429, 500, 502, 503, 504, 507, 510]`` +.. versionadded:: 5.2 + + The ``http_codes`` option was introduced in Symfony 5.2. + The list of HTTP status codes that triggers a retry of the request. -This options cannot be used along `decider_service`_ option. http_version ............ @@ -976,9 +991,12 @@ max_delay **type**: ``integer`` **default**: ``0`` +.. versionadded:: 5.2 + + The ``max_delay`` option was introduced in Symfony 5.2. + The maximum amount of milliseconds initial to wait between retries. Use ``0`` to not limit the duration. -This options cannot be used along `backoff_service`_ option. max_duration ............ @@ -1011,16 +1029,24 @@ max_retries **type**: ``integer`` **default**: ``3`` -The maximum number of retries before aborting. When the maximum is reach, the -client returns the last received responses. +.. versionadded:: 5.2 + + The ``max_retries`` option was introduced in Symfony 5.2. + +The maximum number of retries for failing requests. When the maximum is reached, +the client returns the last received response. multiplier .......... **type**: ``float`` **default**: ``2`` -Multiplier to apply to the delay each time a retry occurs. -This options cannot be used along `backoff_service`_ option. +.. versionadded:: 5.2 + + The ``multiplier`` option was introduced in Symfony 5.2. + +This value is multiplied to the delay each time a retry occurs, to distribute +retries in time instead of making all of them sequentially. no_proxy ........ From b86e003aef789ad9ac5746ec12e7e67c9cac3001 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 2 Oct 2020 15:24:55 +0200 Subject: [PATCH 0501/1519] Tweak --- reference/forms/types/money.rst | 3 ++- reference/forms/types/percent.rst | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/reference/forms/types/money.rst b/reference/forms/types/money.rst index 5952ba77b67..bb91d0b08da 100644 --- a/reference/forms/types/money.rst +++ b/reference/forms/types/money.rst @@ -100,7 +100,8 @@ html5 This option was introduced in Symfony 5.2. -If set to true, the HTML input will be rendered as a native HTML5 type="number" form. +If set to ``true``, the HTML input will be rendered as a native HTML5 +```` element. .. caution:: diff --git a/reference/forms/types/percent.rst b/reference/forms/types/percent.rst index e35d54a022b..4b21f1f2856 100644 --- a/reference/forms/types/percent.rst +++ b/reference/forms/types/percent.rst @@ -67,7 +67,8 @@ html5 This option was introduced in Symfony 5.2. -If set to true, the HTML input will be rendered as a native HTML5 type="number" form. +If set to ``true``, the HTML input will be rendered as a native HTML5 +```` element. scale ~~~~~ From fd03b5ef92db7ad6f38059713d97fa88e30e4aea Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sat, 3 Oct 2020 10:12:27 +0200 Subject: [PATCH 0502/1519] Adding docs about Request::toArray() --- components/http_foundation.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index c4662198bdb..27842974496 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -188,9 +188,16 @@ Finally, the raw data sent with the request body can be accessed using $content = $request->getContent(); -For instance, this may be useful to process a JSON string sent to the +For instance, this may be useful to process a XML string sent to the application by a remote service using the HTTP POST method. +.. versionadded:: 5.2 + + If the request body is a JSON string, it can be accessed using + :method:`Symfony\\Component\\HttpFoundation\\Request::toArray`:: + + $data = $request->toArray(); + Identifying a Request ~~~~~~~~~~~~~~~~~~~~~ From b5156615f019e6974abe14d7f0f66d28460e7959 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 3 Oct 2020 15:12:38 +0200 Subject: [PATCH 0503/1519] [#14325] Moved contents out of versionadded directive --- components/http_foundation.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 27842974496..62815a98a8b 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -191,12 +191,14 @@ Finally, the raw data sent with the request body can be accessed using For instance, this may be useful to process a XML string sent to the application by a remote service using the HTTP POST method. -.. versionadded:: 5.2 +If the request body is a JSON string, it can be accessed using +:method:`Symfony\\Component\\HttpFoundation\\Request::toArray`:: + + $data = $request->toArray(); - If the request body is a JSON string, it can be accessed using - :method:`Symfony\\Component\\HttpFoundation\\Request::toArray`:: +.. versionadded:: 5.2 - $data = $request->toArray(); + The ``toArray()`` method was introduced in Symfony 5.2. Identifying a Request ~~~~~~~~~~~~~~~~~~~~~ From 14d9473720bf374cf02166d6f121db9947b07643 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 3 Oct 2020 15:40:46 +0200 Subject: [PATCH 0504/1519] [#14219] Merged the two IPs examples --- security/access_control.rst | 111 ++++++++++++++---------------------- 1 file changed, 42 insertions(+), 69 deletions(-) diff --git a/security/access_control.rst b/security/access_control.rst index 6bc661ce540..225687c02f6 100644 --- a/security/access_control.rst +++ b/security/access_control.rst @@ -25,7 +25,7 @@ access control should be used on this request. The following ``access_control`` options are used for matching: * ``path``: a regular expression (without delimiters) -* ``ip`` or ``ips``: netmasks are also supported +* ``ip`` or ``ips``: netmasks are also supported (can be a comma-separated string) * ``port``: an integer * ``host``: a regular expression * ``methods``: one or many methods @@ -37,6 +37,9 @@ Take the following ``access_control`` entries as an example: .. code-block:: yaml # config/packages/security.yaml + parameters: + env(TRUSTED_IPS): '10.0.0.1, 10.0.0.2' + security: # ... access_control: @@ -45,6 +48,10 @@ Take the following ``access_control`` entries as an example: - { path: '^/admin', roles: ROLE_USER_HOST, host: symfony\.com$ } - { path: '^/admin', roles: ROLE_USER_METHOD, methods: [POST, PUT] } + # ips can be comma-separated, which is especially useful when using env variables + - { path: '^/admin', roles: ROLE_USER_IP, ips: '%env(TRUSTED_IPS)%' } + - { path: '^/admin', roles: ROLE_USER_IP, ips: [127.0.0.1, ::1, '%env(TRUSTED_IPS)%'] } + .. code-block:: xml @@ -57,18 +64,31 @@ Take the following ``access_control`` entries as an example: http://symfony.com/schema/dic/security https://symfony.com/schema/dic/security/security-1.0.xsd"> + + 10.0.0.1, 10.0.0.2 + + + + + + + 127.0.0.1 + ::1 + %env(TRUSTED_IPS)% + .. code-block:: php // config/packages/security.php + $container->setParameter('env(TRUSTED_IPS)', '10.0.0.1, 10.0.0.2'); $container->loadFromExtension('security', [ // ... 'access_control' => [ @@ -92,10 +112,30 @@ Take the following ``access_control`` entries as an example: 'path' => '^/admin', 'roles' => 'ROLE_USER_METHOD', 'methods' => 'POST, PUT', - ] + ], + + // ips can be comma-separated, which is especially useful when using env variables + [ + 'path' => '^/admin', + 'roles' => 'ROLE_USER_IP', + 'ips' => '%env(TRUSTED_IPS)%', + ], + [ + 'path' => '^/admin', + 'roles' => 'ROLE_USER_IP', + 'ips' => [ + '127.0.0.1', + '::1', + '%env(TRUSTED_IPS)%', + ], + ], ], ]); +.. versionadded:: 5.2 + + Support for comma-separated IP addresses was introduced in Symfony 5.2. + For each incoming request, Symfony will decide which ``access_control`` to use based on the URI, the client's IP address, the incoming host name, and the request method. Remember, the first rule that matches is used, and @@ -133,73 +173,6 @@ if ``ip``, ``port``, ``host`` or ``method`` are not specified for an entry, that :ref:`Deny access in PHP code ` if you want to disallow access based on ``$_GET`` parameter values. -.. versionadded:: 5.2 - - Environment variables can be used to pass comma separated ip addresses - (as a single value or as one of array values): - - .. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - parameters: - env(TRUSTED_IPS): '10.0.0.1, 10.0.0.2' - security: - # ... - access_control: - - { path: '^/admin', ips: '%env(TRUSTED_IPS)%' } - - { path: '^/admin', ips: [127.0.0.1, ::1, '%env(TRUSTED_IPS)%'] } - - .. code-block:: xml - - - - - - - 10.0.0.1, 10.0.0.2 - - - - - - - 127.0.0.1 - ::1 - %env(TRUSTED_IPS)% - - - - - .. code-block:: php - - // config/packages/security.php - $container->setParameter('env(TRUSTED_IPS)', '10.0.0.1, 10.0.0.2'); - $container->loadFromExtension('security', [ - // ... - 'access_control' => [ - [ - 'path' => '^/admin', - 'ips' => '%env(TRUSTED_IPS)%', - ], - [ - 'path' => '^/admin', - 'ips' => [ - '127.0.0.1', - '::1', - '%env(TRUSTED_IPS)%', - ], - ], - ], - ]); - .. _security-access-control-enforcement-options: 2. Access Enforcement From f853c9a5b2a9ac46f890bd5bc00d79a1c1f2ccdf Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 3 Oct 2020 15:58:06 +0200 Subject: [PATCH 0505/1519] [#14286] Added versionadded directive --- components/phpunit_bridge.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index dba2d4b9e4e..04d080d974f 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -877,9 +877,14 @@ If you have installed the bridge through Composer, you can run it by calling e.g (not defined in a :ref:`dotenv file `). In the same way, ``SYMFONY_MAX_PHPUNIT_VERSION`` will set the maximum version - of PHPUnit to be considered. This is useful when testing a framework that does + of PHPUnit to be considered. This is useful when testing a framework that does not support the latest version(s) of PHPUnit. +.. versionadded:: 5.2 + + The ``SYMFONY_MAX_PHPUNIT_VERSION`` env variable was introduced in + Symfony 5.2. + .. tip:: If you still need to use ``prophecy`` (but not ``symfony/yaml``), From 64886940917ddbf0bc918c16c48cb04137f56afc Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 3 Oct 2020 23:20:52 +0200 Subject: [PATCH 0506/1519] Removed versionadded 4.4 directives --- components/serializer.rst | 4 ---- service_container/tags.rst | 4 ---- 2 files changed, 8 deletions(-) diff --git a/components/serializer.rst b/components/serializer.rst index e109b883993..8fa9a5484fd 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -1256,10 +1256,6 @@ These are the options available: ``output_utf8_bom`` Outputs special `UTF-8 BOM`_ along with encoded data (default: ``false``). -.. versionadded:: 4.4 - - The ``output_utf8_bom`` option was introduced in Symfony 4.4. - Handling Constructor Arguments ------------------------------ diff --git a/service_container/tags.rst b/service_container/tags.rst index 8793048211b..9e394fc75d7 100644 --- a/service_container/tags.rst +++ b/service_container/tags.rst @@ -588,10 +588,6 @@ application handlers:: Tagged Services with Priority ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 4.4 - - The ability to prioritize tagged services was introduced in Symfony 4.4. - The tagged services can be prioritized using the ``priority`` attribute, thus providing a way to inject a sorted collection of services: From ce94f893ae8453861d76d98287804a929da392db Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sun, 4 Oct 2020 14:30:41 +0200 Subject: [PATCH 0507/1519] Removed versionadded 4.4 directives --- configuration.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/configuration.rst b/configuration.rst index b84e1b0e90e..5d4354d562b 100644 --- a/configuration.rst +++ b/configuration.rst @@ -144,10 +144,6 @@ configuration files, even if they use a different format: // ... -.. versionadded:: 4.4 - - The ``not_found`` option value for ``ignore_errors`` was introduced in Symfony 4.4. - .. _config-parameter-intro: .. _config-parameters-yml: .. _configuration-parameters: From 1a56331bee4daf037f09b1a0e991f9ef9c5d539c Mon Sep 17 00:00:00 2001 From: HypeMC Date: Sun, 4 Oct 2020 18:34:50 +0200 Subject: [PATCH 0508/1519] Add alternative FormDataPart array structure --- http_client.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/http_client.rst b/http_client.rst index 7f44141a6dc..240d28d1e73 100644 --- a/http_client.rst +++ b/http_client.rst @@ -619,6 +619,35 @@ according to the ``multipart/form-data`` content-type. The 'body' => $formData->bodyToIterable(), ]); +.. tip:: + + When using multidimensional arrays the :class:`Symfony\\Component\\Mime\\Part\\Multipart\\FormDataPart` + automatically appends ``[key]`` to the name of the field:: + + $formData = new FormDataPart([ + 'array_field' => [ + 'some value', + 'other value', + ], + ]); + + $formData->getParts(); // Returns two instances of TextPart + // with the names "array_field[0]" and "array_field[1]" + + This behavior can be bypassed by using the following array structure:: + + $formData = new FormDataPart([ + ['array_field' => 'some value'], + ['array_field' => 'other value'], + ]); + + $formData->getParts(); // Returns two instances of TextPart both + // with the name "array_field" + + .. versionadded:: 5.2 + + The alternative array structure was introduced in Symfony 5.2. + By default, HttpClient streams the body contents when uploading them. This might not work with all servers, resulting in HTTP status code 411 ("Length Required") because there is no ``Content-Length`` header. The solution is to turn the body From bf310c1ecb2c3289a3517c60965732db17fb207d Mon Sep 17 00:00:00 2001 From: Johan Date: Sun, 4 Oct 2020 15:49:59 +0200 Subject: [PATCH 0509/1519] 14300 Update support for Uuid 6 --- reference/constraints/Uuid.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/reference/constraints/Uuid.rst b/reference/constraints/Uuid.rst index 6e9794b8b5d..3b81433d28a 100644 --- a/reference/constraints/Uuid.rst +++ b/reference/constraints/Uuid.rst @@ -124,9 +124,9 @@ will allow alternate input formats like: ``versions`` ~~~~~~~~~~~~ -**type**: ``int[]`` **default**: ``[1,2,3,4,5]`` +**type**: ``int[]`` **default**: ``[1,2,3,4,5,6]`` -This option can be used to only allow specific `UUID versions`_. Valid versions are 1 - 5. +This option can be used to only allow specific `UUID versions`_. Valid versions are 1 - 6. The following PHP constants can also be used: * ``Uuid::V1_MAC`` @@ -134,8 +134,9 @@ The following PHP constants can also be used: * ``Uuid::V3_MD5`` * ``Uuid::V4_RANDOM`` * ``Uuid::V5_SHA1`` +* ``Uuid::V6_SORTABLE`` -All five versions are allowed by default. +All six versions are allowed by default. .. _`Universally unique identifier (UUID)`: https://en.wikipedia.org/wiki/Universally_unique_identifier .. _`RFC 4122`: https://tools.ietf.org/html/rfc4122 From 0017158c805d9fadbc66bfbc04ba02901d726d23 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 5 Oct 2020 12:24:09 +0200 Subject: [PATCH 0510/1519] Added versionadded directive --- reference/constraints/Uuid.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/reference/constraints/Uuid.rst b/reference/constraints/Uuid.rst index 3b81433d28a..427a373f788 100644 --- a/reference/constraints/Uuid.rst +++ b/reference/constraints/Uuid.rst @@ -138,6 +138,10 @@ The following PHP constants can also be used: All six versions are allowed by default. +.. versionadded:: 5.2 + + The UUID 6 version support was introduced in Symfony 5.2. + .. _`Universally unique identifier (UUID)`: https://en.wikipedia.org/wiki/Universally_unique_identifier .. _`RFC 4122`: https://tools.ietf.org/html/rfc4122 .. _`UUID versions`: https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions From 4ff6a1a97b130a40f98ffc91740ec9e9c09d3547 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 6 Oct 2020 13:40:45 +0200 Subject: [PATCH 0511/1519] Minor: Fix build --- reference/constraints/Sequentially.rst | 2 +- validation/custom_constraint.rst | 2 +- validation/sequence_provider.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/reference/constraints/Sequentially.rst b/reference/constraints/Sequentially.rst index a8e7c6be298..39424a6c523 100644 --- a/reference/constraints/Sequentially.rst +++ b/reference/constraints/Sequentially.rst @@ -5,7 +5,7 @@ This constraint allows you to apply a set of rules that should be validated step-by-step, allowing to interrupt the validation once the first violation is raised. As an alternative in situations ``Sequentially`` cannot solve, you may consider -using :doc:`GroupSequence` which allows more control. +using :doc:`GroupSequence ` which allows more control. .. versionadded:: 5.1 diff --git a/validation/custom_constraint.rst b/validation/custom_constraint.rst index 5d5ae9fa22c..5e727fa97c1 100644 --- a/validation/custom_constraint.rst +++ b/validation/custom_constraint.rst @@ -185,7 +185,7 @@ Create a Reusable Set of Constraints ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In case you need to apply some common set of constraints in different places -consistently across your application, you can extend the :doc:`Compound constraint`. +consistently across your application, you can extend the :doc:`Compound constraint `. .. versionadded:: 5.1 diff --git a/validation/sequence_provider.rst b/validation/sequence_provider.rst index ad59e529839..52cf0940460 100644 --- a/validation/sequence_provider.rst +++ b/validation/sequence_provider.rst @@ -360,7 +360,7 @@ How to Sequentially Apply Constraints on a Single Property ---------------------------------------------------------- Sometimes, you may want to apply constraints sequentially on a single -property. The :doc:`Sequentially constraint` +property. The :doc:`Sequentially constraint ` can solve this for you in a more straightforward way than using a ``GroupSequence``. .. versionadded:: 5.1 From b37ca011beccd17893b4e7a0ec81686ae418b276 Mon Sep 17 00:00:00 2001 From: laurent35240 Date: Mon, 5 Oct 2020 22:10:40 +0200 Subject: [PATCH 0512/1519] [Validator] Add documention for ULID validator --- reference/constraints/Ulid.rst | 107 ++++++++++++++++++++++++++++++ reference/constraints/map.rst.inc | 1 + 2 files changed, 108 insertions(+) create mode 100644 reference/constraints/Ulid.rst diff --git a/reference/constraints/Ulid.rst b/reference/constraints/Ulid.rst new file mode 100644 index 00000000000..7bcae08e961 --- /dev/null +++ b/reference/constraints/Ulid.rst @@ -0,0 +1,107 @@ +ULID +==== + +.. versionadded:: 5.2 + + The ULID validator was introduced in Symfony 5.2. + +Validates that a value is a valid `Universally Unique Lexicographically Sortable Identifier (ULID)`_. + +========== =================================================================== +Applies to :ref:`property or method ` +Options - `groups`_ + - `message`_ + - `normalizer`_ + - `payload`_ +Class :class:`Symfony\\Component\\Validator\\Constraints\\Ulid` +Validator :class:`Symfony\\Component\\Validator\\Constraints\\UlidValidator` +========== =================================================================== + +Basic Usage +----------- + +.. configuration-block:: + + .. code-block:: php-annotations + + // src/Entity/File.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class File + { + /** + * @Assert\Ulid + */ + protected $identifier; + } + + .. code-block:: yaml + + # config/validator/validation.yaml + App\Entity\File: + properties: + identifier: + - Ulid: ~ + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/File.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; + + class File + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('identifier', new Assert\Ulid()); + } + } + +.. include:: /reference/constraints/_empty-values-are-valid.rst.inc + +Options +------- + +.. include:: /reference/constraints/_groups-option.rst.inc + +``message`` +~~~~~~~~~~~ + +**type**: ``string`` **default**: ``This is not a valid ULID.`` + +This message is shown if the string is not a valid ULID. + +You can use the following parameters in this message: + +=============== ============================================================== +Parameter Description +=============== ============================================================== +``{{ value }}`` The current (invalid) value +``{{ label }}`` Corresponding form field label +=============== ============================================================== + +.. include:: /reference/constraints/_normalizer-option.rst.inc + +.. include:: /reference/constraints/_payload-option.rst.inc + + +.. _`Universally Unique Lexicographically Sortable Identifier (ULID)`: https://github.com/ulid/spec diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index f9bf67e80f6..020e84cde65 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -24,6 +24,7 @@ String Constraints * :doc:`Ip ` * :doc:`Json ` * :doc:`Uuid ` +* :doc:`Ulid ` * :doc:`UserPassword ` * :doc:`NotCompromisedPassword ` From 3facbc530c0aaae1f7687671a4d239d0702a3539 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 6 Oct 2020 14:19:34 +0200 Subject: [PATCH 0513/1519] Fix: Build --- reference/constraints.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/reference/constraints.rst b/reference/constraints.rst index b0ca049124f..56acb087114 100644 --- a/reference/constraints.rst +++ b/reference/constraints.rst @@ -21,6 +21,7 @@ Validation Constraints Reference constraints/Hostname constraints/Ip constraints/Uuid + constraints/Ulid constraints/Json constraints/EqualTo From 921e09654c3729303f129609f325d85e88269079 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 6 Oct 2020 14:37:27 +0200 Subject: [PATCH 0514/1519] Minor --- http_client.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http_client.rst b/http_client.rst index 240d28d1e73..7ef133d339e 100644 --- a/http_client.rst +++ b/http_client.rst @@ -622,7 +622,7 @@ according to the ``multipart/form-data`` content-type. The .. tip:: When using multidimensional arrays the :class:`Symfony\\Component\\Mime\\Part\\Multipart\\FormDataPart` - automatically appends ``[key]`` to the name of the field:: + class automatically appends ``[key]`` to the name of the field:: $formData = new FormDataPart([ 'array_field' => [ From 3df4d9ea244b4e4f9273cea465fb51e347bc92e2 Mon Sep 17 00:00:00 2001 From: Antoine Makdessi Date: Tue, 6 Oct 2020 17:57:30 +0200 Subject: [PATCH 0515/1519] Document usage of Symfony Mailer for error email Related to https://github.com/symfony/monolog-bundle/pull/354 --- logging/monolog_email.rst | 49 +++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/logging/monolog_email.rst b/logging/monolog_email.rst index 5d172ca0428..cfa2730265f 100644 --- a/logging/monolog_email.rst +++ b/logging/monolog_email.rst @@ -4,10 +4,9 @@ How to Configure Monolog to Email Errors ======================================== -.. caution:: +.. versionadded:: 3.6.0 - This feature is not compatible yet with the new :doc:`Symfony mailer `, - so it requires using SwiftMailer. + Support for emailing errors using :doc:`Symfony mailer ` was added in MonologBundle 3.6.0. `Monolog`_ can be configured to send an email when an error occurs within an application. The configuration for this requires a few nested handlers @@ -33,9 +32,9 @@ it is broken down. handler: deduplicated deduplicated: type: deduplication - handler: swift - swift: - type: swift_mailer + handler: symfony_mailer + symfony_mailer: + type: symfony_mailer from_email: 'error@example.com' to_email: 'error@example.com' # or list of recipients @@ -73,11 +72,11 @@ it is broken down. [ 'type' => 'deduplication', - 'handler' => 'swift', + 'handler' => 'symfony_mailer', ], - 'swift' => [ - 'type' => 'swift_mailer', + 'symfony_mailer' => [ + 'type' => 'symfony_mailer', 'from_email' => 'error@example.com', 'to_email' => 'error@example.com', // or a list of recipients @@ -162,7 +161,7 @@ You can adjust the time period using the ``time`` option: type: deduplication # the time in seconds during which duplicate entries are discarded (default: 60) time: 10 - handler: swift + handler: symfony_mailer .. code-block:: xml @@ -172,7 +171,7 @@ You can adjust the time period using the ``time`` option: + handler="symfony_mailer"/> .. code-block:: php @@ -184,12 +183,12 @@ You can adjust the time period using the ``time`` option: 'type' => 'deduplication', // the time in seconds during which duplicate entries are discarded (default: 60) 'time' => 10, - 'handler' => 'swift', + 'handler' => 'symfony_mailer', ], ], ]); -The messages are then passed to the ``swift`` handler. This is the handler that +The messages are then passed to the ``symfony_mailer`` handler. This is the handler that actually deals with emailing you the error. The settings for this are straightforward, the to and from addresses, the formatter, the content type and the subject. @@ -217,9 +216,9 @@ get logged on the server as well as the emails being sent: level: debug deduplicated: type: deduplication - handler: swift - swift: - type: swift_mailer + handler: symfony_mailer + symfony_mailer: + type: symfony_mailer from_email: 'error@example.com' to_email: 'error@example.com' subject: 'An Error Occurred! %%message%%' @@ -259,11 +258,11 @@ get logged on the server as well as the emails being sent: [ 'type' => 'deduplication', - 'handler' => 'swift', + 'handler' => 'symfony_mailer', ], - 'swift' => [ - 'type' => 'swift_mailer', + 'symfony_mailer' => [ + 'type' => 'symfony_mailer', 'from_email' => 'error@example.com', 'to_email' => 'error@example.com', // or a list of recipients From 922932f6c1b32580a19937ab06211e04100cd8fc Mon Sep 17 00:00:00 2001 From: Antoine Makdessi Date: Tue, 6 Oct 2020 18:09:46 +0200 Subject: [PATCH 0516/1519] Makes DOCtor-RST happy Error: You are not allowed to use version "3.6.0". Only major version "5" is allowed. Error: Please only provide ".. versionadded::" if the version is greater/equal "5.0" --- logging/monolog_email.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logging/monolog_email.rst b/logging/monolog_email.rst index cfa2730265f..225bcd923c8 100644 --- a/logging/monolog_email.rst +++ b/logging/monolog_email.rst @@ -4,7 +4,7 @@ How to Configure Monolog to Email Errors ======================================== -.. versionadded:: 3.6.0 +.. versionadded:: 3.6 Support for emailing errors using :doc:`Symfony mailer ` was added in MonologBundle 3.6.0. From d20f07c2e560ffca6790ff3ef54793decb2f637d Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 7 Oct 2020 08:13:14 +0200 Subject: [PATCH 0517/1519] Fix: DOXtor-RST --- .doctor-rst.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.doctor-rst.yaml b/.doctor-rst.yaml index f3ac893b0cd..3051b9325f4 100644 --- a/.doctor-rst.yaml +++ b/.doctor-rst.yaml @@ -92,3 +92,4 @@ whitelist: - '.. versionadded:: 0.2' # MercureBundle - 'provides a ``loginUser()`` method to simulate logging in in your functional' - '.. code-block:: twig' + - '.. versionadded:: 3.6' # MonologBundle From 202b9e6834df02d151fb87349e71597973d5e0a1 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 7 Oct 2020 08:13:50 +0200 Subject: [PATCH 0518/1519] Update message --- logging/monolog_email.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logging/monolog_email.rst b/logging/monolog_email.rst index 225bcd923c8..2a07a08f706 100644 --- a/logging/monolog_email.rst +++ b/logging/monolog_email.rst @@ -6,7 +6,7 @@ How to Configure Monolog to Email Errors .. versionadded:: 3.6 - Support for emailing errors using :doc:`Symfony mailer ` was added in MonologBundle 3.6.0. + Support for emailing errors using :doc:`Symfony mailer ` was added in MonologBundle 3.6. `Monolog`_ can be configured to send an email when an error occurs within an application. The configuration for this requires a few nested handlers From 5ddd135bc3669aa61278fd57c71b32b16999c37a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 7 Oct 2020 09:24:48 +0200 Subject: [PATCH 0519/1519] Tweaks --- components/semaphore.rst | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/components/semaphore.rst b/components/semaphore.rst index 4677b0627ba..5f26c781164 100644 --- a/components/semaphore.rst +++ b/components/semaphore.rst @@ -24,10 +24,14 @@ Installation Usage ----- -Semaphore are used to guarantee exclusive access to some shared resource. +In computer science, a semaphore is a variable or abstract data type used to +control access to a common resource by multiple processes in a concurrent +system such as a multitasking operating system. The main difference +with :doc:`locks ` is that semaphores allow more than one process to +access a resource, whereas locks only allow one process. -Semaphore are created using a :class:`Symfony\\Component\\Semaphore\\SemaphoreFactory` class, -which in turn requires another class to manage the storage of Semaphore:: +Create semaphores with the :class:`Symfony\\Component\\Semaphore\\SemaphoreFactory` +class, which in turn requires another class to manage the storage:: use Symfony\Component\Semaphore\SemaphoreFactory; use Symfony\Component\Semaphore\Store\RedisStore; @@ -38,13 +42,12 @@ which in turn requires another class to manage the storage of Semaphore:: $store = new RedisStore($redis); $factory = new SemaphoreFactory($store); - The semaphore is created by calling the :method:`Symfony\\Component\\Semaphore\\SemaphoreFactory::createSemaphore` method. Its first argument is an arbitrary string that represents the locked -resource. Its second argument is the number of process allowed. Then, a call to -the :method:`Symfony\\Component\\Semaphore\\SemaphoreInterface::acquire` method -will try to acquire the semaphore:: +resource. Its second argument is the maximum number of process allowed. Then, a +call to the :method:`Symfony\\Component\\Semaphore\\SemaphoreInterface::acquire` +method will try to acquire the semaphore:: // ... $semaphore = $factory->createSemaphore('pdf-invoice-generation', 2); @@ -62,7 +65,7 @@ already acquired. .. note:: - Unlike other implementations, the Semaphore Component distinguishes + Unlike other implementations, the Semaphore component distinguishes semaphores instances even when they are created for the same resource. If a semaphore has to be used by several services, they should share the same ``Semaphore`` instance returned by the ``SemaphoreFactory::createSemaphore`` @@ -73,7 +76,6 @@ already acquired. If you don't release the semaphore explicitly, it will be released automatically on instance destruction. In some cases, it can be useful to lock a resource across several requests. To disable the automatic release - behavior, set the last argument of the ``createLock()`` method to - ``false``. + behavior, set the fifth argument of the ``createLock()`` method to ``false``. .. _`semaphores`: https://en.wikipedia.org/wiki/Semaphore_(programming) From 2bad79552545666d5032e6aece2fb1109b6c1bba Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 7 Oct 2020 13:19:59 +0200 Subject: [PATCH 0520/1519] Wrap long lines --- logging/monolog_email.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/logging/monolog_email.rst b/logging/monolog_email.rst index 2a07a08f706..22ed4d08928 100644 --- a/logging/monolog_email.rst +++ b/logging/monolog_email.rst @@ -6,7 +6,8 @@ How to Configure Monolog to Email Errors .. versionadded:: 3.6 - Support for emailing errors using :doc:`Symfony mailer ` was added in MonologBundle 3.6. + Support for emailing errors using :doc:`Symfony mailer ` was added + in MonologBundle 3.6. `Monolog`_ can be configured to send an email when an error occurs within an application. The configuration for this requires a few nested handlers From 3914a0649a51503fd6de039679a360d457764415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Wed, 7 Oct 2020 15:54:25 +0200 Subject: [PATCH 0521/1519] Add jitter documentation --- reference/configuration/framework.rst | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index efaff7afcd6..2a02171ff83 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -148,6 +148,7 @@ Configuration * `max_delay`_ * `max_retries`_ * `multiplier`_ + * `jitter`_ * `timeout`_ * `max_duration`_ @@ -164,6 +165,7 @@ Configuration * `max_delay`_ * `max_retries`_ * `multiplier`_ + * `jitter`_ * `http_method_override`_ * `ide`_ @@ -784,7 +786,8 @@ will automaticaly retry failed HTTP requests. max_retries: 2 delay: 1000 multiplier: 3 - max_delay: 500 + max_delay: 5000 + jitter: 0.3 scoped_clients: my_api.client: @@ -835,8 +838,8 @@ backoff_service The service id used to compute the time to wait between retries. By default, it uses an instance of :class:`Symfony\\Component\\HttpClient\\Retry\\ExponentialBackOff` configured -with ``delay``, ``max_delay`` and ``multiplier`` options. This class has to -implement :class:`Symfony\\Component\\HttpClient\\Retry\\RetryBackOffInterface`. +with ``delay``, ``max_delay``, ``multiplier`` and ``jitter`` options. This +class has to implement :class:`Symfony\\Component\\HttpClient\\Retry\\RetryBackOffInterface`. base_uri ........ @@ -969,6 +972,18 @@ http_version The HTTP version to use, typically ``'1.1'`` or ``'2.0'``. Leave it to ``null`` to let Symfony select the best version automatically. +jitter +...... + +**type**: ``float`` **default**: ``0.1`` + +.. versionadded:: 5.2 + + The ``jitter`` option was introduced in Symfony 5.2. + +The probability (expressed with a float between ``0.0`` and ``1.0``) of +randomness to apply to the delay to wait between retries. + local_cert .......... From f4f5eb9b66b2226838f9c62b413c2edfd54ce130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Wed, 7 Oct 2020 11:18:17 +0200 Subject: [PATCH 0522/1519] Various fixes --- components/lock.rst | 5 ++--- lock.rst | 28 ++++++++++++++++------------ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index 3dfda5c4f07..0e6cd64f036 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -276,8 +276,6 @@ support blocking, and expects a TTL to avoid stalled locks:: Memcached does not support TTL lower than 1 second. -.. _lock-store-pdo: - .. _lock-store-mongodb: MongoDbStore @@ -339,6 +337,7 @@ MongoDB Connection String: The ``collection`` querystring parameter is not part of the `MongoDB Connection String`_ definition. It is used to allow constructing a ``MongoDbStore`` using a `Data Source Name (DSN)`_ without ``$options``. +.. _lock-store-pdo: PdoStore ~~~~~~~~ @@ -350,7 +349,7 @@ support blocking, and expects a TTL to avoid stalled locks:: use Symfony\Component\Lock\Store\PdoStore; // a PDO, a Doctrine DBAL connection or DSN for lazy connecting through PDO - $databaseConnectionOrDSN = 'mysql:host=127.0.0.1;dbname=lock'; + $databaseConnectionOrDSN = 'mysql:host=127.0.0.1;dbname=app'; $store = new PdoStore($databaseConnectionOrDSN, ['db_username' => 'myuser', 'db_password' => 'mypassword']); .. note:: diff --git a/lock.rst b/lock.rst index 72fb36dc779..1eb5ce95c64 100644 --- a/lock.rst +++ b/lock.rst @@ -56,10 +56,11 @@ this behavior by using the ``lock`` key like: lock: 'zookeeper://z1.docker' lock: 'zookeeper://z1.docker,z2.docker' lock: 'sqlite:///%kernel.project_dir%/var/lock.db' - lock: 'mysql:host=127.0.0.1;dbname=lock' - lock: 'pgsql:host=127.0.0.1;dbname=lock' - lock: 'sqlsrv:server=localhost;Database=test' - lock: 'oci:host=localhost;dbname=test' + lock: 'mysql:host=127.0.0.1;dbname=app' + lock: 'pgsql:host=127.0.0.1;dbname=app' + lock: 'sqlsrv:server=127.0.0.1;Database=app' + lock: 'oci:host=127.0.0.1;dbname=app' + lock: 'mongodb://127.0.0.1/app?collection=lock' lock: '%env(LOCK_DSN)%' # named locks @@ -102,13 +103,15 @@ this behavior by using the ``lock`` key like: sqlite:///%kernel.project_dir%/var/lock.db - mysql:host=127.0.0.1;dbname=lock + mysql:host=127.0.0.1;dbname=app - pgsql:host=127.0.0.1;dbname=lock + pgsql:host=127.0.0.1;dbname=app - sqlsrv:server=localhost;Database=test + sqlsrv:server=127.0.0.1;Database=app - oci:host=localhost;dbname=test + oci:host=127.0.0.1;dbname=app + + mongodb://127.0.0.1/app?collection=lock %env(LOCK_DSN)% @@ -135,10 +138,11 @@ this behavior by using the ``lock`` key like: 'lock' => 'zookeeper://z1.docker', 'lock' => 'zookeeper://z1.docker,z2.docker', 'lock' => 'sqlite:///%kernel.project_dir%/var/lock.db', - 'lock' => 'mysql:host=127.0.0.1;dbname=lock', - 'lock' => 'pgsql:host=127.0.0.1;dbname=lock', - 'lock' => 'sqlsrv:server=localhost;Database=test', - 'lock' => 'oci:host=localhost;dbname=test', + 'lock' => 'mysql:host=127.0.0.1;dbname=app', + 'lock' => 'pgsql:host=127.0.0.1;dbname=app', + 'lock' => 'sqlsrv:server=127.0.0.1;Database=app', + 'lock' => 'oci:host=127.0.0.1;dbname=app', + 'lock' => 'mongodb://127.0.0.1/app?collection=lock', 'lock' => '%env(LOCK_DSN)%', // named locks From 8909cde0a7f8c69b371ff56f77e4a76efe0a1e57 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 7 Oct 2020 16:56:04 +0200 Subject: [PATCH 0523/1519] Reword --- reference/configuration/framework.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 2a02171ff83..be472a8fe41 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -975,14 +975,16 @@ to let Symfony select the best version automatically. jitter ...... -**type**: ``float`` **default**: ``0.1`` +**type**: ``float`` **default**: ``0.1`` (must be between 0.0 and 1.0) .. versionadded:: 5.2 The ``jitter`` option was introduced in Symfony 5.2. -The probability (expressed with a float between ``0.0`` and ``1.0``) of -randomness to apply to the delay to wait between retries. +This option adds some randomness to the delay. It's useful to avoid sending +multiple requests to the server at the exact same time. The randomness is +calculated as ``delay * jitter``. For example: if delay is ``1000ms`` and jitter +is ``0.2``, the actual delay will be a number between ``800`` and ``1200`` (1000 +/- 20%). local_cert .......... From cc7ba8020df045225526c3343100a0e959b1f149 Mon Sep 17 00:00:00 2001 From: Nate Wiebe Date: Wed, 7 Oct 2020 17:23:08 -0400 Subject: [PATCH 0524/1519] Rename the translatable class --- translation.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/translation.rst b/translation.rst index 238e80ee38c..fbf08ba14a1 100644 --- a/translation.rst +++ b/translation.rst @@ -307,16 +307,16 @@ parts of your application and mocking it in your tests. Instead of translating a string at the time of creation, you can use a "translatable object", which is an instance of the -:class:`Symfony\\Component\\Translation\\Translatable` class. This object stores +:class:`Symfony\\Component\\Translation\\TranslatableMessage` class. This object stores all the information needed to fully translate its contents when needed:: - use Symfony\Component\Translation\Translatable; + use Symfony\Component\Translation\TranslatableMessage; // the first argument is required and it's the original message - $message = new Translatable('Symfony is great!'); + $message = new TranslatableMessage('Symfony is great!'); // the optional second argument defines the translation parameters and // the optional third argument is the translation domain - $status = new Translatable('order.status', ['%status%' => $order->getStatus()], 'store'); + $status = new TranslatableMessage('order.status', ['%status%' => $order->getStatus()], 'store'); Templates are now much simpler because you can pass translatable objects to the ``trans`` filter: From 496ea825b3a9c54f819b0cc1dc6b2f29cc652aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Wed, 7 Oct 2020 10:55:55 +0200 Subject: [PATCH 0525/1519] Add documentation for Postgresql --- components/lock.rst | 40 ++++++++++++++++++++++++++++++++++++++++ lock.rst | 4 ++++ 2 files changed, 44 insertions(+) diff --git a/components/lock.rst b/components/lock.rst index 18b50f9aa46..b159f09f9ae 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -319,6 +319,7 @@ Store Scope Blocking Expiring Sharing :ref:`MemcachedStore ` remote no yes no :ref:`MongoDbStore ` remote no yes no :ref:`PdoStore ` remote no yes no +:ref:`PostgreSqlStore ` remote yes yes yes :ref:`RedisStore ` remote no yes yes :ref:`SemaphoreStore ` local yes no no :ref:`ZookeeperStore ` remote no no no @@ -452,6 +453,29 @@ You can also create this table explicitly by calling the :method:`Symfony\\Component\\Lock\\Store\\PdoStore::createTable` method in your code. +.. _lock-store-pgsql: + +PostgreSqlStore +~~~~~~~~~~~~~~~ + +The PostgreSqlStore uses `Advisory Locks`_ provided by PostgreSQL. It requires a +`PDO`_ connection, a `Doctrine DBAL Connection`_, or a +`Data Source Name (DSN)`_. it nativly supports blocking, as weel as sharing +locks. + + use Symfony\Component\Lock\Store\PostgreSqlStore; + + // a PDO, a Doctrine DBAL connection or DSN for lazy connecting through PDO + $databaseConnectionOrDSN = 'postgresql://myuser:mypassword@localhost:5634/lock'; + $store = new PostgreSqlStore($databaseConnectionOrDSN); + +In opposite to the ``PdoStore``, the ``PostgreSqlStore`` does not need a table to +stores locks and does not expires. + +.. versionadded:: 5.2 + + PostgreSqlStore were introduced in Symfony 5.2. + .. _lock-store-redis: RedisStore @@ -551,6 +575,7 @@ Remote Stores Remote stores (:ref:`MemcachedStore `, :ref:`MongoDbStore `, :ref:`PdoStore `, +:ref:`PostgreSqlStore `, :ref:`RedisStore ` and :ref:`ZookeeperStore `) use a unique token to recognize the true owner of the lock. This token is stored in the @@ -760,6 +785,20 @@ have synchronized clocks. To ensure locks don't expire prematurely; the TTLs should be set with enough extra time to account for any clock drift between nodes. +PostgreSqlStore +~~~~~~~~~~~~~~~ + +The PdoStore relies on the `Advisory Locks`_ properties of the PostgreSQL +database. That means that by using :ref:`PostgreSqlStore ` +the locks will be automatically released at the end of the session in case the +client cannot unlock for any reason. + +If the PostgreSQL service or the machine hosting it restarts, every lock would +be lost without notifying the running processes. + +If the TCP connection is lost, the PostgreSQL may release locks without +notifying the application. + RedisStore ~~~~~~~~~~ @@ -864,6 +903,7 @@ are still running. .. _`a maximum of 1024 bytes in length`: https://docs.mongodb.com/manual/reference/limits/#Index-Key-Limit .. _`ACID`: https://en.wikipedia.org/wiki/ACID +.. _`Advisory Locks`: https://www.postgresql.org/docs/current/explicit-locking.html .. _`Data Source Name (DSN)`: https://en.wikipedia.org/wiki/Data_source_name .. _`Doctrine DBAL Connection`: https://github.com/doctrine/dbal/blob/master/src/Connection.php .. _`Expire Data from Collections by Setting TTL`: https://docs.mongodb.com/manual/tutorial/expire-data/ diff --git a/lock.rst b/lock.rst index 1eb5ce95c64..c3d5cb365e5 100644 --- a/lock.rst +++ b/lock.rst @@ -58,6 +58,7 @@ this behavior by using the ``lock`` key like: lock: 'sqlite:///%kernel.project_dir%/var/lock.db' lock: 'mysql:host=127.0.0.1;dbname=app' lock: 'pgsql:host=127.0.0.1;dbname=app' + lock: 'pgsql+advisory:host=127.0.0.1;dbname=lock' lock: 'sqlsrv:server=127.0.0.1;Database=app' lock: 'oci:host=127.0.0.1;dbname=app' lock: 'mongodb://127.0.0.1/app?collection=lock' @@ -107,6 +108,8 @@ this behavior by using the ``lock`` key like: pgsql:host=127.0.0.1;dbname=app + pgsql+advisory:host=127.0.0.1;dbname=lock + sqlsrv:server=127.0.0.1;Database=app oci:host=127.0.0.1;dbname=app @@ -140,6 +143,7 @@ this behavior by using the ``lock`` key like: 'lock' => 'sqlite:///%kernel.project_dir%/var/lock.db', 'lock' => 'mysql:host=127.0.0.1;dbname=app', 'lock' => 'pgsql:host=127.0.0.1;dbname=app', + 'lock' => 'pgsql+advisory:host=127.0.0.1;dbname=lock', 'lock' => 'sqlsrv:server=127.0.0.1;Database=app', 'lock' => 'oci:host=127.0.0.1;dbname=app', 'lock' => 'mongodb://127.0.0.1/app?collection=lock', From 62a39bce24081a2fa505cfc6014ae985e654398e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 8 Oct 2020 17:31:22 +0200 Subject: [PATCH 0526/1519] Tweaks --- components/lock.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index b159f09f9ae..d34908c2777 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -460,8 +460,7 @@ PostgreSqlStore The PostgreSqlStore uses `Advisory Locks`_ provided by PostgreSQL. It requires a `PDO`_ connection, a `Doctrine DBAL Connection`_, or a -`Data Source Name (DSN)`_. it nativly supports blocking, as weel as sharing -locks. +`Data Source Name (DSN)`_. It supports native blocking, as well as sharing locks. use Symfony\Component\Lock\Store\PostgreSqlStore; @@ -470,11 +469,11 @@ locks. $store = new PostgreSqlStore($databaseConnectionOrDSN); In opposite to the ``PdoStore``, the ``PostgreSqlStore`` does not need a table to -stores locks and does not expires. +store locks and does not expire. .. versionadded:: 5.2 - PostgreSqlStore were introduced in Symfony 5.2. + The ``PostgreSqlStore`` was introduced in Symfony 5.2. .. _lock-store-redis: From d90991e30b62aba571592c10aae522840fb562b8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 7 Oct 2020 16:26:51 +0200 Subject: [PATCH 0527/1519] [RateLimiter] Added the docs for the new component --- index.rst | 1 + rate_limiter.rst | 195 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 rate_limiter.rst diff --git a/index.rst b/index.rst index 52614d4d9b8..a4f512151f5 100644 --- a/index.rst +++ b/index.rst @@ -52,6 +52,7 @@ Topics notifier performance profiler + rate_limiter routing security session diff --git a/rate_limiter.rst b/rate_limiter.rst new file mode 100644 index 00000000000..358a1d62c00 --- /dev/null +++ b/rate_limiter.rst @@ -0,0 +1,195 @@ +Rate Limiter +============ + +.. versionadded:: 5.2 + + The RateLimiter component was introduced in Symfony 5.2 as an + :doc:`experimental feature `. + +A "rate limiter" controls how frequently some event (e.g. an HTTP request or a +login attempt) is allowed to happen. Rate limiting is commonly used as a +defensive measure to protect services from excessive use (intended or not) and +maintain their availability. It's also useful to control your internal or +outbound processes (e.g. limit the number of simultaneously processed messages). + +Symfony uses these rate limiters in built-in features like "login throttling", +which limits how many failed login attempts a user can make in a given period of +time, but you can use them for your own features too. + +Rate Limiting Strategies +------------------------ + +Symfony's rate limiter implements two of the most common strategies to enforce +rate limits: **fixed window** and **token bucket**. + +Fixed Window Rate Limiter +~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is the simplest technique and it's based on setting a limit for a given +interval of time. For example: 5,000 requests per hour or 3 login attempts +every 15 minutes. + +Its main drawback is that resource usage is not evenly distributed in time and +it can overload the server at the window edges. In the previous example, a user +could make the 4,999 requests in the last minute of some hour and another 5,000 +requests during the first minute of the next hour, making 9,999 requests in +total in two minutes and possibly overloading the server. + +Token Bucket Rate Limiter +~~~~~~~~~~~~~~~~~~~~~~~~~ + +This technique implements the `token bucket algorithm`_, which defines a +continuously updating budget of resource usage. It roughly works like this: + +* A bucket is created with an initial set of tokens; +* A new token is added to the bucket with a predefined frequency (e.g. every second); +* Allowing an event consumes one or more tokens; +* If the bucket still contains tokens, the event is allowed; otherwise, it's denied; +* If the bucket is at full capacity, new tokens are discarded. + +Installation +------------ + +Before using a rate limiter for the first time, run the following command to +install the associated Symfony Component in your application: + +.. code-block:: terminal + + $ composer require symfony/rate-limiter + +Configuration +------------- + +The following example creates two different rate limiters for an API service, to +enforce different levels of service (free or paid): + +.. code-block:: yaml + + # config/packages/rate_limiter.yaml + framework: + rate_limiter: + anonymous_api: + strategy: fixed_window + limit: 100 + interval: '60 minutes' + authenticated_api: + strategy: token_bucket + limit: 5000 + rate: { interval: '15 minutes', amount: 500 } + +.. note:: + + The value of the ``interval`` option must be a number followed by any of the + units accepted by the `PHP date relative formats`_ (e.g. ``3 seconds``, + ``10 hours``, ``1 day``, etc.) + +In the ``anonymous_api`` limiter, after making the first HTTP request, you can +make up to 100 requests in the next 60 minutes. After that time, the counter +resets and you have another 100 requests for the following 60 minutes. + +In the ``authenticated_api`` limiter, after making the first HTTP request you +are allowed to make up to 5,000 HTTP requests in total, and this number grows +at a rate of another 500 requests every 15 minutes. If you don't make that +number of requests, the unused ones don't accumulate (the ``limit`` option +prevents that number from being higher than 5,000). + +Rate Limiting in Action +----------------------- + +After having installed and configured the rate limiter, inject it in any service +or controller and call the ``consume()`` method to try to consume a given number +of tokens. For example, this controller uses the previous rate limiter to control +the number of requests to the API:: + + // src/Controller/ApiController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; + use Symfony\Component\RateLimiter\Limiter; + + class ApiController extends AbstractController + { + // the variable name must be: "rate limiter name" + "limiter" suffix + public function index(Limiter $anonymousApiLimiter) + { + // create a limiter based on a unique identifier of the client + // (e.g. the client's IP address, a username/email, an API key, etc.) + $limiter = $anonymousApiLimiter->create($request->getClientIp()); + + // the argument of consume() is the number of tokens to consume + // and returns an object of type Limit + if (false === $anonymous_api_limiter->consume(1)->isAccepted()) { + throw new TooManyRequestsHttpException(); + } + + // you can also use the ensureAccepted() method - which throws a + // RateLimitExceededException if the limit has been reached + // $limiter->consume(1)->ensureAccepted(); + + // ... + } + + // ... + } + +.. note:: + + In a real application, instead of checking the rate limiter in all the API + controller methods, create an :doc:`event listener or subscriber ` + for the :ref:`kernel.request event ` + and check the rate limiter once for all requests. + +In other scenarios you may want instead to wait as long as needed until a new +token is available. In those cases, use the ``wait()`` method:: + + // src/Controller/ApiController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\RateLimiter\Limiter; + + class ApiController extends AbstractController + { + public function registerUser(Request $request, Limiter $authenticatedApiLimiter) + { + $apiKey = $request->headers->get('apikey'); + $limiter = $authenticatedApiLimiter->create($apiKey); + + // this blocks the application until the given number of tokens can be consumed + do { + $limit = $limiter->consume(1); + $limit->wait(); + } while (!$limit->isAccepted()); + + // ... + } + + // ... + } + +Rate Limiter Storage and Locking +-------------------------------- + +Rate limiters use the default cache and locking mechanisms defined in your +Symfony application. If you prefer to change that, use the ``lock`` and +``storage`` options: + +.. code-block:: yaml + + # config/packages/rate_limiter.yaml + framework: + rate_limiter: + anonymous_api_limiter: + # ... + # the value is the name of any cache pool defined in your application + cache_pool: 'app.redis_cache' + # or define a service implementing StorageInterface to use a different + # mechanism to store the limiter information + storage: 'App\RateLimiter\CustomRedisStorage' + # the value is the name of any lock defined in your application + lock: 'app.rate_limiter_lock' + +.. _`token bucket algorithm`: https://en.wikipedia.org/wiki/Token_bucket +.. _`PHP date relative formats`: https://www.php.net/datetime.formats.relative From 4919af7a2d2b0329a67ddcbd1f71e24001cf53c3 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Fri, 9 Oct 2020 09:31:37 +0200 Subject: [PATCH 0528/1519] Add Crawler assert functions --- testing/functional_tests_assertions.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/testing/functional_tests_assertions.rst b/testing/functional_tests_assertions.rst index 1f3b13d9763..4da642bc6dd 100644 --- a/testing/functional_tests_assertions.rst +++ b/testing/functional_tests_assertions.rst @@ -81,6 +81,10 @@ Crawler - ``assertPageTitleContains()`` - ``assertInputValueSame()`` - ``assertInputValueNotSame()`` +- ``assertCheckboxChecked()`` +- ``assertCheckboxNotChecked()`` +- ``assertFormValue()`` +- ``assertNoFormValue()`` Mailer ~~~~~~ From a3fcdd0eee777e2d409b3344e7925a172a4957cd Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 9 Oct 2020 13:01:03 +0200 Subject: [PATCH 0529/1519] Added the versionadded directive --- testing/functional_tests_assertions.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/testing/functional_tests_assertions.rst b/testing/functional_tests_assertions.rst index 4da642bc6dd..457d8c39021 100644 --- a/testing/functional_tests_assertions.rst +++ b/testing/functional_tests_assertions.rst @@ -86,6 +86,12 @@ Crawler - ``assertFormValue()`` - ``assertNoFormValue()`` +.. versionadded:: 5.2 + + The ``assertCheckboxChecked()``, ``assertCheckboxNotChecked()``, + ``assertFormValue()`` and ``assertNoFormValue()`` methods were introduced + in Symfony 5.2. + Mailer ~~~~~~ From f8449f5c8cb67c5b043525d57c7ff6eec45ba257 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Fri, 9 Oct 2020 09:48:36 +0200 Subject: [PATCH 0530/1519] Document Kernel::getBuildDir() --- reference/configuration/kernel.rst | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/reference/configuration/kernel.rst b/reference/configuration/kernel.rst index 5f52cd155e7..e0f83d71250 100644 --- a/reference/configuration/kernel.rst +++ b/reference/configuration/kernel.rst @@ -84,6 +84,7 @@ method to return the right project directory:: } } + Cache Directory ~~~~~~~~~~~~~~~ @@ -91,13 +92,35 @@ Cache Directory This returns the absolute path of the cache directory of your Symfony project. It's calculated automatically based on the current -:ref:`environment `. +:ref:`environment `. Data might be written to this path +at runtime. This value is exposed via the ``kernel.cache_dir`` configuration parameter and the :method:`Symfony\\Component\\HttpKernel\\Kernel::getCacheDir` method. To -change this setting, override the ``getCacheDir()`` method to return the right +change this setting, override the ``getCacheDir()`` method to return the correct cache directory. +Build Directory +~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``$this->getCacheDir()`` + +.. versionadded:: 5.2 + + The build directory feature was introduced in Symfony 5.2. + +This returns the absolute path of a build directory of your Symfony project. This +directory can be used to separate read-only cache (i.e. the compiled container) +from read-write cache (i.e. cache pools). Specify a non-default value when the +application is deployed in a read-only filesystem like a Docker container or AWS +Lambda. + +This value is exposed via the ``kernel.build_dir`` configuration parameter and +the :method:`Symfony\\Component\\HttpKernel\\Kernel::getBuildDir` method. To +change this setting, override the ``getBuildDir()`` method to return the correct +build directory. + + Log Directory ~~~~~~~~~~~~~ From ffcc05d030dfef0cec7bc4832c1ff6d380b7dbec Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 9 Oct 2020 13:06:03 +0200 Subject: [PATCH 0531/1519] Tweaks --- reference/configuration/kernel.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/reference/configuration/kernel.rst b/reference/configuration/kernel.rst index 740a8df17fd..27707807ed4 100644 --- a/reference/configuration/kernel.rst +++ b/reference/configuration/kernel.rst @@ -88,7 +88,6 @@ method to return the right project directory:: } } - Cache Directory ~~~~~~~~~~~~~~~ @@ -96,8 +95,8 @@ Cache Directory This returns the absolute path of the cache directory of your Symfony project. It's calculated automatically based on the current -:ref:`environment `. Data might be written to this path -at runtime. +:ref:`environment `. Data might be written to this +path at runtime. This value is exposed via the ``kernel.cache_dir`` configuration parameter and the :method:`Symfony\\Component\\HttpKernel\\Kernel::getCacheDir` method. To @@ -115,9 +114,9 @@ Build Directory This returns the absolute path of a build directory of your Symfony project. This directory can be used to separate read-only cache (i.e. the compiled container) -from read-write cache (i.e. cache pools). Specify a non-default value when the -application is deployed in a read-only filesystem like a Docker container or AWS -Lambda. +from read-write cache (i.e. :doc:`cache pools `). Specify a non-default +value when the application is deployed in a read-only filesystem like a Docker +container or AWS Lambda. This value is exposed via the ``kernel.build_dir`` configuration parameter and the :method:`Symfony\\Component\\HttpKernel\\Kernel::getBuildDir` method. To From 79f5dd6eedf3f24726d4bcae2776568c9fb92154 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 11 Oct 2020 10:15:10 +0200 Subject: [PATCH 0532/1519] Added docs about default_lifetime This will fix #14347 --- reference/configuration/framework.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index f6f11d7bd8f..f79160be10c 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -2847,9 +2847,14 @@ Can also be the service id of another cache pool where tags will be stored. default_lifetime """""""""""""""" -**type**: ``integer`` +**type**: ``integer`` | ``string`` -Default lifetime of your cache items in seconds. +Default lifetime of your cache items. Given an integer value to set the default +lifetime in seconds. A string value could be ISO 8601 time interval, like ``"PT5M"`` +or a PHP date expression that is accepted by ``strtotime()``, like ``"5 minutes"``. + +If no value is provided, the cache adapter will fallback to the default value on +the actual cache storage. provider """""""" From eb962cf77f79f1f24791a125176bd4eea6a1cb86 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sun, 11 Oct 2020 12:45:45 +0200 Subject: [PATCH 0533/1519] Typo --- reference/configuration/framework.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index f79160be10c..0e09a21c5cf 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -2849,7 +2849,7 @@ default_lifetime **type**: ``integer`` | ``string`` -Default lifetime of your cache items. Given an integer value to set the default +Default lifetime of your cache items. Give an integer value to set the default lifetime in seconds. A string value could be ISO 8601 time interval, like ``"PT5M"`` or a PHP date expression that is accepted by ``strtotime()``, like ``"5 minutes"``. From 3d01373f664c97ecd52ce11d88fdd10fcc3217af Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sun, 11 Oct 2020 13:11:00 +0200 Subject: [PATCH 0534/1519] [Monolog] Mention the SwitchUserTokenProcessor --- logging/processors.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/logging/processors.rst b/logging/processors.rst index e8ecf96593b..605c571b244 100644 --- a/logging/processors.rst +++ b/logging/processors.rst @@ -171,6 +171,14 @@ Symfony's MonologBridge provides processors that can be registered inside your a Adds information from the current user's token to the record namely username, roles and whether the user is authenticated. +:class:`Symfony\\Bridge\\Monolog\\Processor\\SwitchUserTokenProcessor` + Adds information about the user who is impersonating the logged in user, + namely username, roles and whether the user is authenticated. + + .. versionadded:: 5.2 + + The ``SwitchUserTokenProcessor`` was introduced in Symfony 5.2. + :class:`Symfony\\Bridge\\Monolog\\Processor\\WebProcessor` Overrides data from the request using the data inside Symfony's request object. From 4ca794e0e535f9347e05fb4999a93f179092a6a3 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sat, 12 Sep 2020 00:54:28 +0200 Subject: [PATCH 0535/1519] [Routing] Document the Route attribute --- _build/conf.py | 1 + best_practices.rst | 11 +- contributing/documentation/format.rst | 1 + routing.rst | 483 +++++++++++++++++++++++--- 4 files changed, 446 insertions(+), 50 deletions(-) diff --git a/_build/conf.py b/_build/conf.py index 49cc12581ad..071991c5411 100644 --- a/_build/conf.py +++ b/_build/conf.py @@ -111,6 +111,7 @@ lexers['markdown'] = TextLexer() lexers['php'] = PhpLexer(startinline=True) lexers['php-annotations'] = PhpLexer(startinline=True) +lexers['php-attributes'] = PhpLexer(startinline=True) lexers['php-standalone'] = PhpLexer(startinline=True) lexers['php-symfony'] = PhpLexer(startinline=True) lexers['rst'] = RstLexer() diff --git a/best_practices.rst b/best_practices.rst index 02434a7c812..f43d4798452 100644 --- a/best_practices.rst +++ b/best_practices.rst @@ -223,12 +223,13 @@ important parts of your application. .. _best-practice-controller-annotations: -Use Annotations to Configure Routing, Caching and Security -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Use Attributes or Annotations to Configure Routing, Caching and Security +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Using annotations for routing, caching and security simplifies configuration. -You don't need to browse several files created with different formats (YAML, XML, -PHP): all the configuration is just where you need it and it only uses one format. +Using attributes or annotations for routing, caching and security simplifies +configuration. You don't need to browse several files created with different +formats (YAML, XML, PHP): all the configuration is just where you need it and +it only uses one format. Don't Use Annotations to Configure the Controller Template ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/contributing/documentation/format.rst b/contributing/documentation/format.rst index 733e9e6f21f..2c465096f0b 100644 --- a/contributing/documentation/format.rst +++ b/contributing/documentation/format.rst @@ -104,6 +104,7 @@ Markup Format Use It to Display ``html+php`` PHP code blended with HTML ``ini`` INI ``php-annotations`` PHP Annotations +``php-attributes`` PHP Attributes =================== ====================================== Adding Links diff --git a/routing.rst b/routing.rst index 214b57574ae..832b5df2c53 100644 --- a/routing.rst +++ b/routing.rst @@ -15,22 +15,33 @@ provides other useful features, like generating SEO-friendly URLs (e.g. Creating Routes --------------- -Routes can be configured in YAML, XML, PHP or using annotations. All formats -provide the same features and performance, so choose your favorite. -:ref:`Symfony recommends annotations ` +Routes can be configured in YAML, XML, PHP or using either attributes or +annotations. All formats provide the same features and performance, so choose +your favorite. +:ref:`Symfony recommends attributes ` because it's convenient to put the route and controller in the same place. -Creating Routes as Annotations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Creating Routes as Attributes or Annotations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +On PHP 8, you can use native attributes to configure routes right away. On +PHP 7, where attributes are not available, you can use annotations instead, +provided by the Doctrine Annotations library. -Run this command once in your application to add support for annotations: +In case you want to use annotations instead of attributes, run this command +once in your application to enable them: .. code-block:: terminal $ composer require annotations -In addition to installing the needed dependencies, this command creates the -following configuration file: +.. versionadded:: 5.2 + + The ability to use PHP attributes to configure routes was introduced in + Symfony 5.2. Prior to this, Doctrine Annotations were the only way to + annotate controller actions with routing configuration. + +This command also creates the following configuration file: .. code-block:: yaml @@ -49,22 +60,43 @@ any PHP class stored in the ``src/Controller/`` directory. Suppose you want to define a route for the ``/blog`` URL in your application. To do so, create a :doc:`controller class ` like the following:: - // src/Controller/BlogController.php - namespace App\Controller; +.. configuration-block:: - use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; - use Symfony\Component\Routing\Annotation\Route; + .. code-block:: php-annotations - class BlogController extends AbstractController - { - /** - * @Route("/blog", name="blog_list") - */ - public function list() + // src/Controller/BlogController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class BlogController extends AbstractController { - // ... + /** + * @Route("/blog", name="blog_list") + */ + public function list() + { + // ... + } + } + + .. code-block:: php-attributes + + // src/Controller/BlogController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class BlogController extends AbstractController + { + #[Route('/blog', name: 'blog_list')] + public function list() + { + // ... + } } - } This configuration defines a route called ``blog_list`` that matches when the user requests the ``/blog`` URL. When the match occurs, the application runs @@ -182,6 +214,28 @@ Use the ``methods`` option to restrict the verbs each route should respond to: } } + .. code-block:: php-attributes + + // src/Controller/BlogApiController.php + namespace App\Controller; + + // ... + + class BlogApiController extends AbstractController + { + #[Route('/api/posts/{id}', methods: ['GET', 'HEAD'])] + public function show(int $id) + { + // ... return a JSON response with the post + } + + #[Route('/api/posts/{id}', methods: ['PUT'])] + public function edit(int $id) + { + // ... edit a post + } + } + .. code-block:: yaml # config/routes.yaml @@ -274,6 +328,29 @@ arbitrary matching logic: } } + .. code-block:: php-attributes + + // src/Controller/DefaultController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class DefaultController extends AbstractController + { + #[Route( + '/contact', + name: 'contact', + condition: "context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'", + )] + // expressions can also include config parameters: + // condition: "request.headers.get('User-Agent') matches '%app.allowed_browsers%'" + public function contact() + { + // ... + } + } + .. code-block:: yaml # config/routes.yaml @@ -424,6 +501,28 @@ defined as ``/blog/{slug}``: } } + .. code-block:: php-attributes + + // src/Controller/BlogController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class BlogController extends AbstractController + { + // ... + + #[Route('/blog/{slug}', name: 'blog_show')] + public function show(string $slug) + { + // $slug will equal the dynamic part of the URL + // e.g. at /blog/yay-routing, then $slug='yay-routing' + + // ... + } + } + .. code-block:: yaml # config/routes.yaml @@ -507,6 +606,29 @@ the ``{page}`` parameter using the ``requirements`` option: } } + .. code-block:: php-attributes + + // src/Controller/BlogController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class BlogController extends AbstractController + { + #[Route('/blog/{page}', name: 'blog_list', requirements: ['page' => '\d+'])] + public function list(int $page) + { + // ... + } + + #[Route('/blog/{slug}', name: 'blog_show')] + public function show($slug) + { + // ... + } + } + .. code-block:: yaml # config/routes.yaml @@ -610,6 +732,23 @@ concise, but it can decrease route readability when requirements are complex: } } + .. code-block:: php-attributes + + // src/Controller/BlogController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class BlogController extends AbstractController + { + #[Route('/blog/{page<\d+>}', name: 'blog_list')] + public function list(int $page) + { + // ... + } + } + .. code-block:: yaml # config/routes.yaml @@ -678,6 +817,23 @@ other configuration formats they are defined with the ``defaults`` option: } } + .. code-block:: php-attributes + + // src/Controller/BlogController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class BlogController extends AbstractController + { + #[Route('/blog/{page}', name: 'blog_list', requirements: ['page' => '\d+'])] + public function list(int $page = 1) + { + // ... + } + } + .. code-block:: yaml # config/routes.yaml @@ -764,6 +920,23 @@ parameter: } } + .. code-block:: php-attributes + + // src/Controller/BlogController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class BlogController extends AbstractController + { + #[Route('/blog/{page<\d+>?1}', name: 'blog_list')] + public function list(int $page) + { + // ... + } + } + .. code-block:: yaml # config/routes.yaml @@ -816,36 +989,67 @@ matched. A ``priority`` optional parameter is available in order to let you choose the order of your routes, and it is only available when using annotations. -.. code-block:: php-annotations +.. configuration-block:: - // src/Controller/BlogController.php - namespace App\Controller; + .. code-block:: php-annotations - use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; - use Symfony\Component\Routing\Annotation\Route; + // src/Controller/BlogController.php + namespace App\Controller; - class BlogController extends AbstractController - { - /** - * This route has a greedy pattern and is defined first. - * - * @Route("/blog/{slug}", name="blog_show") - */ - public function show(string $slug) + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class BlogController extends AbstractController { - // ... + /** + * This route has a greedy pattern and is defined first. + * + * @Route("/blog/{slug}", name="blog_show") + */ + public function show(string $slug) + { + // ... + } + + /** + * This route could not be matched without defining a higher priority than 0. + * + * @Route("/blog/list", name="blog_list", priority=2) + */ + public function list() + { + // ... + } } - /** - * This route could not be matched without defining a higher priority than 0. - * - * @Route("/blog/list", name="blog_list", priority=2) - */ - public function list() + .. code-block:: php-attributes + + // src/Controller/BlogController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class BlogController extends AbstractController { - // ... + /** + * This route has a greedy pattern and is defined first. + */ + #[Route('/blog/{slug}', name: 'blog_show')] + public function show(string $slug) + { + // ... + } + + /** + * This route could not be matched without defining a higher priority than 0. + */ + #[Route('/blog/list', name: 'blog_list', priority: 2)] + public function list() + { + // ... + } } - } The priority parameter expects an integer value. Routes with higher priority are sorted before routes with lower priority. The default value when it is not @@ -955,6 +1159,28 @@ and in route imports. Symfony defines some special attributes with the same name } } + .. code-block:: php-attributes + + // src/Controller/ArticleController.php + namespace App\Controller; + + // ... + class ArticleController extends AbstractController + { + #[Route( + path: '/articles/{_locale}/search.{_format}', + locale: 'en', + format: 'html', + requirements: [ + '_locale' => 'en|fr', + '_format' => 'html|xml', + ], + )] + public function search() + { + } + } + .. code-block:: yaml # config/routes.yaml @@ -1034,6 +1260,22 @@ the controllers of the routes: } } + .. code-block:: php-attributes + + // src/Controller/BlogController.php + namespace App\Controller; + + use Symfony\Component\Routing\Annotation\Route; + + class BlogController + { + #[Route('/blog/{page}', name: 'blog_index', defaults: ['page' => 1, 'title' => 'Hello world!'])] + public function index(int $page, string $title) + { + // ... + } + } + .. code-block:: yaml # config/routes.yaml @@ -1107,6 +1349,22 @@ A possible solution is to change the parameter requirements to be more permissiv } } + .. code-block:: php-attributes + + // src/Controller/DefaultController.php + namespace App\Controller; + + use Symfony\Component\Routing\Annotation\Route; + + class DefaultController + { + #[Route('/share/{token}', name: 'share', requirements: ['token' => '.+'])] + public function share($token) + { + // ... + } + } + .. code-block:: yaml # config/routes.yaml @@ -1171,9 +1429,10 @@ It's common for a group of routes to share some options (e.g. all routes related to the blog start with ``/blog``) That's why Symfony includes a feature to share route configuration. -When defining routes as annotations, put the common configuration in the -``@Route`` annotation of the controller class. In other routing formats, define -the common configuration using options when importing the routes. +When defining routes as attributes or annotations, put the common configuration +in the ``#[Route]`` attribute (or ``@Route`` annotation) of the controller +class. In other routing formats, define the common configuration using options +when importing the routes. .. configuration-block:: @@ -1206,6 +1465,29 @@ the common configuration using options when importing the routes. } } + .. code-block:: php-attributes + + // src/Controller/BlogController.php + namespace App\Controller; + + use Symfony\Component\Routing\Annotation\Route; + + #[Route('/blog', requirements: ['_locale' => 'en|es|fr'], name: 'blog_')] + class BlogController + { + #[Route('/{_locale}', name: 'index')] + public function index() + { + // ... + } + + #[Route('/{_locale}/posts/{slug}', name: 'show')] + public function show(Post $post) + { + // ... + } + } + .. code-block:: yaml # config/routes/annotations.yaml @@ -1515,6 +1797,29 @@ host name: } } + .. code-block:: php-attributes + + // src/Controller/MainController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class MainController extends AbstractController + { + #[Route('/', name: 'mobile_homepage', host: 'm.example.com')] + public function mobileHomepage() + { + // ... + } + + #[Route('/', name: 'homepage')] + public function homepage() + { + // ... + } + } + .. code-block:: yaml # config/routes.yaml @@ -1600,6 +1905,35 @@ multi-tenant applications) and these parameters can be validated too with } } + .. code-block:: php-attributes + + // src/Controller/MainController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class MainController extends AbstractController + { + #[Route( + '/', + name: 'mobile_homepage', + host: '{subdomain}.example.com', + defaults: ['subdomain' => 'm'], + requirements: ['subdomain' => 'm|mobile'], + )] + public function mobileHomepage() + { + // ... + } + + #[Route('/', name: 'homepage')] + public function homepage() + { + // ... + } + } + .. code-block:: yaml # config/routes.yaml @@ -1715,6 +2049,26 @@ avoids the need for duplicating routes, which also reduces the potential bugs: } } + .. code-block:: php-attributes + + // src/Controller/CompanyController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class CompanyController extends AbstractController + { + #[Route(path: [ + 'en' => '/about-us', + 'nl' => '/over-ons' + ], name: 'about_us')] + public function about() + { + // ... + } + } + .. code-block:: yaml # config/routes.yaml @@ -1754,6 +2108,11 @@ avoids the need for duplicating routes, which also reduces the potential bugs: ; }; +.. note:: + + When using PHP attributes for localized routes, you have to use the `path` + named parameter to specify the array of paths. + When a localized route is matched, Symfony uses the same locale automatically during the entire request. @@ -1849,6 +2208,23 @@ session shouldn't be used when matching a request: } } + .. code-block:: php-attributes + + // src/Controller/MainController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class MainController extends AbstractController + { + #[Route('/', name: 'homepage', stateless: true)] + public function homepage() + { + // ... + } + } + .. code-block:: yaml # config/routes.yaml @@ -2224,6 +2600,23 @@ each route explicitly: } } + .. code-block:: php-attributes + + // src/Controller/SecurityController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class SecurityController extends AbstractController + { + #[Route('/login', name: 'login', schemes: ['https'])] + public function login() + { + // ... + } + } + .. code-block:: yaml # config/routes.yaml From 8eccfeaa8192932bce9ecdbd607bad7c44d696e2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 12 Oct 2020 13:31:43 +0200 Subject: [PATCH 0536/1519] [RateLimiter] Minor fixes --- rate_limiter.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index 358a1d62c00..f7112373ff3 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -119,7 +119,7 @@ the number of requests to the API:: // the argument of consume() is the number of tokens to consume // and returns an object of type Limit - if (false === $anonymous_api_limiter->consume(1)->isAccepted()) { + if (false === $limiter->consume(1)->isAccepted()) { throw new TooManyRequestsHttpException(); } From 77625191c5c1f558a0ea7e3cfdb4ccb9381d758c Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 13 Oct 2020 10:57:06 +0200 Subject: [PATCH 0537/1519] fix markup --- routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routing.rst b/routing.rst index 832b5df2c53..e8107a51eaf 100644 --- a/routing.rst +++ b/routing.rst @@ -2110,7 +2110,7 @@ avoids the need for duplicating routes, which also reduces the potential bugs: .. note:: - When using PHP attributes for localized routes, you have to use the `path` + When using PHP attributes for localized routes, you have to use the ``path`` named parameter to specify the array of paths. When a localized route is matched, Symfony uses the same locale automatically From 9dd75a90d0ea067eadae91b8844ec44dcfcbb1ee Mon Sep 17 00:00:00 2001 From: Hamza Amrouche Date: Tue, 10 Mar 2020 17:01:41 +0100 Subject: [PATCH 0538/1519] feat: add amazon sqs to docs --- messenger.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/messenger.rst b/messenger.rst index 6107fcec87b..e22e2f02e21 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1151,6 +1151,35 @@ during a request:: :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\KernelTestCase` or :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\WebTestCase`. +Amazon SQS +~~~~~~~~~~ + +.. versionadded:: 5.1 + + The Amazon SQS transport has been added in Symfony 5.1 + Install it by running: + + .. code-block:: terminal + + $ composer require symfony/amazon-sqs-messenger + +The ``SQS`` transport configuration looks like this: + +.. code-block:: bash + + # .env + MESSENGER_TRANSPORT_DSN=sqs://guest:guest@sqs.eu-west-3.amazonaws.com/test?region=eu-west-3 + + +.. note:: + + By default, the transport will automatically create queue that are needed. That can be disabled. + +The transport has a number of other options, including ways to configure +the exchange, queues binding keys and more. See the documentation on +:class:`Symfony\\Component\\Messenger\\Transport\\AmazonSqs\\Connection`. + + Serializing Messages ~~~~~~~~~~~~~~~~~~~~ From 47dbe33f5f0c5565d67686cf02c02845b8fcf4a5 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 11 Oct 2020 22:36:05 +0200 Subject: [PATCH 0539/1519] Added SQS Messenger docs --- messenger.rst | 52 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/messenger.rst b/messenger.rst index e22e2f02e21..0c71adc23c5 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1168,17 +1168,54 @@ The ``SQS`` transport configuration looks like this: .. code-block:: bash # .env - MESSENGER_TRANSPORT_DSN=sqs://guest:guest@sqs.eu-west-3.amazonaws.com/test?region=eu-west-3 + MESSENGER_TRANSPORT_DSN=sqs://AKIAIOSFODNN7EXAMPLE:j17M97ffSVoKI0briFoo9a@sqs.eu-west-3.amazonaws.com/messages + #MESSENGER_TRANSPORT_DSN=sqs://localhost:9494/messages?sslmode=disable +.. note:: + + The transport will automatically create queues that are needed. This + can be disabled setting the "auto_setup" option to ``false``. + +A number of options can be configured via the DSN or via the ``options`` key +under the transport in ``messenger.yaml``: + +================== ===================================== ====================== + Option Description Default +================== ===================================== ====================== +endpoint Absolute URL to the SQS service https://sqs.eu-west-1.amazonaws.com +region Name of the AWS region eu-west-1 +queue_name Name of the queue messages +account Identifier of the AWS account The owner of the credentials +access_key AWS access key +secret_key AWS secret key +buffer_size Number of messages to prefetch 9 +wait_time `Long polling`_ duration in seconds 20 +poll_timeout Wait for new message duration in 0.1 + seconds +visibility_timeout Amount of seconds the message will Queue's configuration + not be visible (`Visibility Timeout`_) +auto_setup Whether the table should be created true + automatically during send / get. +================== ===================================== ====================== .. note:: - By default, the transport will automatically create queue that are needed. That can be disabled. - -The transport has a number of other options, including ways to configure -the exchange, queues binding keys and more. See the documentation on -:class:`Symfony\\Component\\Messenger\\Transport\\AmazonSqs\\Connection`. + The ``wait_time`` parameter define the maximum duration Amazon SQS should + wait until a message is available in a queue before sending a response. + It helps reducing the cost of using Amazon SQS by eliminating the number + of empty responses. + + The ``poll_timeout`` parameter define the duration the receiver should wait + before returning null. It avoids blocking other receivers from being called. + +.. note:: + + If the queue name is suffixed by ``.fifo``, AWS will creates a `FIFO queue`_ + Use the stamp :class:`Symfony\Component\Messenger\Bridge\AmazonSqs\Transport\AmazonSqsFifoStamp` + to define the ``Message group ID`` and the ``Message deduplication ID``. + FIFO queues don't support setting a delay per message, a value of ``delay: 0`` + is required in the retry strategy settings. Serializing Messages ~~~~~~~~~~~~~~~~~~~~ @@ -1753,3 +1790,6 @@ Learn more .. _`streams`: https://redis.io/topics/streams-intro .. _`Supervisor docs`: http://supervisord.org/ .. _`SymfonyCasts' message serializer tutorial`: https://symfonycasts.com/screencast/messenger/transport-serializer +.. _`Long polling`: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html +.. _`Visibility Timeout`: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html +.. _`FIFO queue': https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html From 689df8cf1142d0c00ffc5e8fdd5acb82e7fe3d37 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 11 Oct 2020 22:40:43 +0200 Subject: [PATCH 0540/1519] cs --- messenger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index 0c71adc23c5..c0c7b72477f 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1211,7 +1211,7 @@ auto_setup Whether the table should be created true .. note:: If the queue name is suffixed by ``.fifo``, AWS will creates a `FIFO queue`_ - Use the stamp :class:`Symfony\Component\Messenger\Bridge\AmazonSqs\Transport\AmazonSqsFifoStamp` + Use the stamp :class:`Symfony\\Component\\Messenger\\Bridge\\AmazonSqs\\Transport\\AmazonSqsFifoStamp` to define the ``Message group ID`` and the ``Message deduplication ID``. FIFO queues don't support setting a delay per message, a value of ``delay: 0`` From d2fdd03de2aa6ae6ee1eb4ff6d223a6be16442a2 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 11 Oct 2020 22:50:38 +0200 Subject: [PATCH 0541/1519] syntax --- messenger.rst | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/messenger.rst b/messenger.rst index c0c7b72477f..b8ff1bcb795 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1176,27 +1176,27 @@ The ``SQS`` transport configuration looks like this: The transport will automatically create queues that are needed. This can be disabled setting the "auto_setup" option to ``false``. -A number of options can be configured via the DSN or via the ``options`` key +A numbeXr of options can be configured via the DSN or via the ``options`` key under the transport in ``messenger.yaml``: -================== ===================================== ====================== - Option Description Default -================== ===================================== ====================== -endpoint Absolute URL to the SQS service https://sqs.eu-west-1.amazonaws.com -region Name of the AWS region eu-west-1 -queue_name Name of the queue messages -account Identifier of the AWS account The owner of the credentials +================== ====================================== ====================== + Option Description Default +================== ====================================== ====================== +endpoint Absolute URL to the SQS service https://sqs.eu-west-1.amazonaws.com +region Name of the AWS region eu-west-1 +queue_name Name of the queue messages +account Identifier of the AWS account The owner of the credentials access_key AWS access key secret_key AWS secret key -buffer_size Number of messages to prefetch 9 -wait_time `Long polling`_ duration in seconds 20 -poll_timeout Wait for new message duration in 0.1 +buffer_size Number of messages to prefetch 9 +wait_time `Long polling`_ duration in seconds 20 +poll_timeout Wait for new message duration in 0.1 seconds -visibility_timeout Amount of seconds the message will Queue's configuration +visibility_timeout Amount of seconds the message will Queue's configuration not be visible (`Visibility Timeout`_) -auto_setup Whether the table should be created true +auto_setup Whether the table should be created true automatically during send / get. -================== ===================================== ====================== +================== ====================================== ====================== .. note:: @@ -1210,7 +1210,7 @@ auto_setup Whether the table should be created true .. note:: - If the queue name is suffixed by ``.fifo``, AWS will creates a `FIFO queue`_ + If the queue name is suffixed by ``.fifo``, AWS will creates a `FIFO queue`_. Use the stamp :class:`Symfony\\Component\\Messenger\\Bridge\\AmazonSqs\\Transport\\AmazonSqsFifoStamp` to define the ``Message group ID`` and the ``Message deduplication ID``. From f56ddd3270f7c32538679ab3d4cba79672874448 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 11 Oct 2020 22:52:48 +0200 Subject: [PATCH 0542/1519] Syntax fix --- messenger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index b8ff1bcb795..d80edfd273d 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1792,4 +1792,4 @@ Learn more .. _`SymfonyCasts' message serializer tutorial`: https://symfonycasts.com/screencast/messenger/transport-serializer .. _`Long polling`: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html .. _`Visibility Timeout`: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html -.. _`FIFO queue': https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html +.. _`FIFO queue`: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html From 5fa1465dfeba211eff941a13184196c3d0b74c6c Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 11 Oct 2020 23:15:28 +0200 Subject: [PATCH 0543/1519] Typo --- messenger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index d80edfd273d..416f52c10a2 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1176,7 +1176,7 @@ The ``SQS`` transport configuration looks like this: The transport will automatically create queues that are needed. This can be disabled setting the "auto_setup" option to ``false``. -A numbeXr of options can be configured via the DSN or via the ``options`` key +A number of options can be configured via the DSN or via the ``options`` key under the transport in ``messenger.yaml``: ================== ====================================== ====================== From d198bb747ef0750ffe3c111a6d76fa89db4b1dbe Mon Sep 17 00:00:00 2001 From: Nyholm Date: Mon, 12 Oct 2020 08:21:55 +0200 Subject: [PATCH 0544/1519] minor --- messenger.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/messenger.rst b/messenger.rst index 416f52c10a2..5949732cdab 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1360,7 +1360,6 @@ by tagging the handler service with ``messenger.message_handler`` 'handles' => SmsNotification::class, ]); - Possible options to configure with tags are: * ``bus`` @@ -1661,7 +1660,6 @@ middleware and *only* include your own: ], ]); - .. note:: If a middleware service is abstract, a different instance of the service will From 7d530ac7227041614eea94ea347cfc3b397f65f6 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Mon, 12 Oct 2020 13:51:13 +0200 Subject: [PATCH 0545/1519] Typos --- messenger.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/messenger.rst b/messenger.rst index 5949732cdab..bbd1015903f 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1200,17 +1200,17 @@ auto_setup Whether the table should be created true .. note:: - The ``wait_time`` parameter define the maximum duration Amazon SQS should + The ``wait_time`` parameter defines the maximum duration Amazon SQS should wait until a message is available in a queue before sending a response. It helps reducing the cost of using Amazon SQS by eliminating the number of empty responses. - The ``poll_timeout`` parameter define the duration the receiver should wait + The ``poll_timeout`` parameter defines the duration the receiver should wait before returning null. It avoids blocking other receivers from being called. .. note:: - If the queue name is suffixed by ``.fifo``, AWS will creates a `FIFO queue`_. + If the queue name is suffixed by ``.fifo``, AWS will create a `FIFO queue`_. Use the stamp :class:`Symfony\\Component\\Messenger\\Bridge\\AmazonSqs\\Transport\\AmazonSqsFifoStamp` to define the ``Message group ID`` and the ``Message deduplication ID``. From cf4331b1d395aac5b81b637b064acde39e728059 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Mon, 12 Oct 2020 17:42:42 +0200 Subject: [PATCH 0546/1519] Sort alphabetically --- messenger.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/messenger.rst b/messenger.rst index bbd1015903f..387c99bd47f 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1182,20 +1182,20 @@ under the transport in ``messenger.yaml``: ================== ====================================== ====================== Option Description Default ================== ====================================== ====================== -endpoint Absolute URL to the SQS service https://sqs.eu-west-1.amazonaws.com -region Name of the AWS region eu-west-1 -queue_name Name of the queue messages -account Identifier of the AWS account The owner of the credentials access_key AWS access key -secret_key AWS secret key +account Identifier of the AWS account The owner of the credentials +auto_setup Whether the table should be created true + automatically during send / get. buffer_size Number of messages to prefetch 9 -wait_time `Long polling`_ duration in seconds 20 +endpoint Absolute URL to the SQS service https://sqs.eu-west-1.amazonaws.com poll_timeout Wait for new message duration in 0.1 seconds +queue_name Name of the queue messages +region Name of the AWS region eu-west-1 +secret_key AWS secret key visibility_timeout Amount of seconds the message will Queue's configuration not be visible (`Visibility Timeout`_) -auto_setup Whether the table should be created true - automatically during send / get. +wait_time `Long polling`_ duration in seconds 20 ================== ====================================== ====================== .. note:: From 23fd9b401c6b6014551e7ce423d694809b456ecd Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Tue, 13 Oct 2020 18:37:18 +0200 Subject: [PATCH 0547/1519] [#14391] Minor (mostly formatting) improvements --- messenger.rst | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/messenger.rst b/messenger.rst index 387c99bd47f..a5ee804a567 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1156,16 +1156,17 @@ Amazon SQS .. versionadded:: 5.1 - The Amazon SQS transport has been added in Symfony 5.1 - Install it by running: + The Amazon SQS transport as introduced in Symfony 5.1. - .. code-block:: terminal +Install Amazon SQS transport by running: - $ composer require symfony/amazon-sqs-messenger +.. code-block:: terminal + + $ composer require symfony/amazon-sqs-messenger The ``SQS`` transport configuration looks like this: -.. code-block:: bash +.. code-block:: env # .env MESSENGER_TRANSPORT_DSN=sqs://AKIAIOSFODNN7EXAMPLE:j17M97ffSVoKI0briFoo9a@sqs.eu-west-3.amazonaws.com/messages @@ -1174,29 +1175,29 @@ The ``SQS`` transport configuration looks like this: .. note:: The transport will automatically create queues that are needed. This - can be disabled setting the "auto_setup" option to ``false``. + can be disabled setting the ``auto_setup`` option to ``false``. A number of options can be configured via the DSN or via the ``options`` key under the transport in ``messenger.yaml``: -================== ====================================== ====================== - Option Description Default -================== ====================================== ====================== -access_key AWS access key -account Identifier of the AWS account The owner of the credentials -auto_setup Whether the table should be created true - automatically during send / get. -buffer_size Number of messages to prefetch 9 -endpoint Absolute URL to the SQS service https://sqs.eu-west-1.amazonaws.com -poll_timeout Wait for new message duration in 0.1 - seconds -queue_name Name of the queue messages -region Name of the AWS region eu-west-1 -secret_key AWS secret key -visibility_timeout Amount of seconds the message will Queue's configuration - not be visible (`Visibility Timeout`_) -wait_time `Long polling`_ duration in seconds 20 -================== ====================================== ====================== +====================== ====================================== =================================== + Option Description Default +====================== ====================================== =================================== +``access_key`` AWS access key +``account`` Identifier of the AWS account The owner of the credentials +``auto_setup`` Whether the table should be created ``true`` + automatically during send / get. +``buffer_size`` Number of messages to prefetch 9 +``endpoint`` Absolute URL to the SQS service https://sqs.eu-west-1.amazonaws.com +``poll_timeout`` Wait for new message duration in 0.1 + seconds +``queue_name`` Name of the queue messages +``region`` Name of the AWS region eu-west-1 +``secret_key`` AWS secret key +``visibility_timeout`` Amount of seconds the message will Queue's configuration + not be visible (`Visibility Timeout`_) +``wait_time`` `Long polling`_ duration in seconds 20 +====================== ====================================== =================================== .. note:: From 3c0372a0133b29b0fabb537bba15cc22a2cee1a3 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Tue, 13 Oct 2020 21:14:17 +0200 Subject: [PATCH 0548/1519] Use updated dependencies --- _build/.requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_build/.requirements.txt b/_build/.requirements.txt index 47f076e9403..26a019bfa6b 100644 --- a/_build/.requirements.txt +++ b/_build/.requirements.txt @@ -1,6 +1,6 @@ docutils==0.13.1 Pygments==2.2.0 sphinx==1.8.5 -git+https://github.com/fabpot/sphinx-php.git@v2.0.0#egg_name=sphinx-php +git+https://github.com/fabpot/sphinx-php.git@v2.0.2#egg_name=sphinx-php jsx-lexer===0.0.8 sphinx_rtd_theme==0.5.0 From d243017fc697e6a4a3f5cca557f6cac3051ba175 Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER Date: Tue, 13 Oct 2020 21:35:31 +0200 Subject: [PATCH 0549/1519] Fix link to acquireRead Should target SharedLockInterface instead of LockInterface --- components/lock.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lock.rst b/components/lock.rst index d34908c2777..518a01c9375 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -221,7 +221,7 @@ but an exclusive lock is needed for writing or modifying data. They are used for example for data structures that cannot be updated atomically and are invalid until the update is complete. -Use the :method:`Symfony\\Component\\Lock\\LockInterface::acquireRead` method +Use the :method:`Symfony\\Component\\Lock\\SharedLockInterface::acquireRead` method to acquire a read-only lock, and the existing :method:`Symfony\\Component\\Lock\\LockInterface::acquire` method to acquire a write lock:: From 41b79833f70e2fe75bbc63a0249d23142f7452b7 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Tue, 13 Oct 2020 10:55:37 +0200 Subject: [PATCH 0550/1519] [Routing] Better use of composer require --- routing.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/routing.rst b/routing.rst index 832b5df2c53..a051e446612 100644 --- a/routing.rst +++ b/routing.rst @@ -33,7 +33,7 @@ once in your application to enable them: .. code-block:: terminal - $ composer require annotations + $ composer require doctrine/annotations .. versionadded:: 5.2 @@ -1063,12 +1063,11 @@ integer acting as the user ID) into another value (e.g. the object that represents the user). This feature is called "param converter" and is only available when using annotations to define routes. -In case you didn't run this command before, run it now to add support for -annotations and "param converters": +To add support for "param converters" we need SensioFrameworkExtraBundle: .. code-block:: terminal - $ composer require annotations + $ composer require sensio/framework-extra-bundle Now, keep the previous route configuration, but change the arguments of the controller action. Instead of ``string $slug``, add ``BlogPost $post``:: From 701f704a73403ef5207c5df1bcfd6b9cec8550b3 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Mon, 12 Oct 2020 22:07:45 +0200 Subject: [PATCH 0551/1519] [DependencyInjection] Document the Required attribute. --- service_container/autowiring.rst | 111 +++++++++++++++++++++++-------- service_container/calls.rst | 2 +- 2 files changed, 85 insertions(+), 28 deletions(-) diff --git a/service_container/autowiring.rst b/service_container/autowiring.rst index 9c855152a9a..56a117f7b16 100644 --- a/service_container/autowiring.rst +++ b/service_container/autowiring.rst @@ -544,50 +544,107 @@ Autowiring other Methods (e.g. Setters and Public Typed Properties) When autowiring is enabled for a service, you can *also* configure the container to call methods on your class when it's instantiated. For example, suppose you want -to inject the ``logger`` service, and decide to use setter-injection:: +to inject the ``logger`` service, and decide to use setter-injection: - // src/Util/Rot13Transformer.php - namespace App\Util; +.. configuration-block:: - class Rot13Transformer - { - private $logger; + .. code-block:: php-annotations - /** - * @required - */ - public function setLogger(LoggerInterface $logger) + // src/Util/Rot13Transformer.php + namespace App\Util; + + class Rot13Transformer { - $this->logger = $logger; + private $logger; + + /** + * @required + */ + public function setLogger(LoggerInterface $logger) + { + $this->logger = $logger; + } + + public function transform($value) + { + $this->logger->info('Transforming '.$value); + // ... + } } - public function transform($value) + .. code-block:: php-attributes + + // src/Util/Rot13Transformer.php + namespace App\Util; + + use Symfony\Contracts\Service\Attribute\Required; + + class Rot13Transformer { - $this->logger->info('Transforming '.$value); - // ... + private $logger; + + #[Required] + public function setLogger(LoggerInterface $logger) + { + $this->logger = $logger; + } + + public function transform($value) + { + $this->logger->info('Transforming '.$value); + // ... + } } - } -Autowiring will automatically call *any* method with the ``@required`` annotation +Autowiring will automatically call *any* method with the ``#[Required]`` attribute above it, autowiring each argument. If you need to manually wire some of the arguments to a method, you can always explicitly :doc:`configure the method call `. -Despite property injection has some :ref:`drawbacks `, autowiring with ``@required`` annotation -can also be applied to public typed properties:: +If you need to stay compatible with PHP 7 and thus cannot use attributes, you can use +the ``@required`` annotation instead. - namespace App\Util; +.. versionadded:: 5.2 - class Rot13Transformer - { - /** @required */ - public LoggerInterface $logger; + The ``#[Required]`` attribute was introduced in Symfony 5.2. - public function transform($value) +Despite property injection has some :ref:`drawbacks `, autowiring with ``#[Required]`` +or ``@required`` can also be applied to public typed properties:: + +.. configuration-block:: + + .. code-block:: php-annotations + + namespace App\Util; + + class Rot13Transformer { - $this->logger->info('Transforming '.$value); - // ... + /** @required */ + public LoggerInterface $logger; + + public function transform($value) + { + $this->logger->info('Transforming '.$value); + // ... + } + } + + .. code-block:: php-attributes + + namespace App\Util; + + use Symfony\Contracts\Service\Attribute\Required; + + class Rot13Transformer + { + #[Required] + public LoggerInterface $logger; + + public function transform($value) + { + $this->logger->info('Transforming '.$value); + // ... + } } - } .. versionadded:: 5.1 diff --git a/service_container/calls.rst b/service_container/calls.rst index 11dea241613..df33cecc989 100644 --- a/service_container/calls.rst +++ b/service_container/calls.rst @@ -6,7 +6,7 @@ Service Method Calls and Setter Injection .. tip:: - If you're using autowiring, you can use ``@required`` to + If you're using autowiring, you can use ``#[Required]`` or ``@required`` to :ref:`automatically configure method calls `. Usually, you'll want to inject your dependencies via the constructor. But sometimes, From 0605be9875bda451c5d6cba839f695f1586f9094 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Wed, 14 Oct 2020 19:31:24 -0400 Subject: [PATCH 0552/1519] Add info() method sample --- components/options_resolver.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/options_resolver.rst b/components/options_resolver.rst index 075b42937a9..74569b9123e 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -811,7 +811,9 @@ method:: $resolver->define('host') ->required() ->default('smtp.example.org') - ->allowedTypes('string'); + ->allowedTypes('string') + ->info('The IP address or hostname'); + $resolver->define('transport') ->required() ->default('transport') From 2380052f6c33b21f41e0f0fcecc9f998b1cf7efe Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 15 Oct 2020 09:30:05 +0200 Subject: [PATCH 0553/1519] Adding docs for rate limit sliding window --- rate_limiter.rst | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index f7112373ff3..2abc25a1a5c 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -19,8 +19,8 @@ time, but you can use them for your own features too. Rate Limiting Strategies ------------------------ -Symfony's rate limiter implements two of the most common strategies to enforce -rate limits: **fixed window** and **token bucket**. +Symfony's rate limiter implements some of the most common strategies to enforce +rate limits: **fixed window**, **sliding window** and **token bucket**. Fixed Window Rate Limiter ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -35,6 +35,22 @@ could make the 4,999 requests in the last minute of some hour and another 5,000 requests during the first minute of the next hour, making 9,999 requests in total in two minutes and possibly overloading the server. +Sliding Window Rate Limiter +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The sliding window algorithm is gracefully handling the drawback from the fixed +window algorithm. To reduce bursts requests the rate limit is calculated based on +the current window and the previous window. + +For example: The limit is 5,000 requests per hour. If a user made 4,000 requests +the previous hour and 500 requests this hour. 15 minutes in to the current hour +(25% of the window) the hit count would be calculated as: 75% * 4,000 + 500 = 3,500. +At this point in time the user can only do 1,500 more requests. + +The math shows that the closer the last window is, the more will the hit count +of the last window effect the current limit. This will make sure that a user can +do 5.000 requests per hour but only if they are spread out evenly. + Token Bucket Rate Limiter ~~~~~~~~~~~~~~~~~~~~~~~~~ From 91a834dc86a31c2ec12a2b52c56da22a22bff029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sapone?= Date: Fri, 16 Oct 2020 11:12:01 +0200 Subject: [PATCH 0554/1519] [UID] Fix wrong use statement for generators --- components/uid.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index f1c569df97d..287789ac368 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -146,7 +146,7 @@ There's also a Doctrine generator to help autogenerate UUID values for the entity primary keys:: // there are generators for UUID V1 and V6 too - use Symfony\Bridge\Doctrine\Types\UuidV4Generator; + use Symfony\Bridge\Doctrine\IdGenerator\UuidV4Generator; /** * @ORM\Entity(repositoryClass="App\Repository\ProductRepository") @@ -261,7 +261,7 @@ special Doctrine types which convert to/from ULID objects automatically:: There's also a Doctrine generator to help autogenerate ULID values for the entity primary keys:: - use Symfony\Bridge\Doctrine\Types\UlidGenerator; + use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator; /** * @ORM\Entity(repositoryClass="App\Repository\ProductRepository") From 81d6877f020ab1e9f291dd7108082344366f0bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Fri, 16 Oct 2020 09:28:32 +0200 Subject: [PATCH 0555/1519] Replace LockInterface by LockFactory in DI --- lock.rst | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/lock.rst b/lock.rst index c3d5cb365e5..bacebc544b2 100644 --- a/lock.rst +++ b/lock.rst @@ -159,22 +159,23 @@ this behavior by using the ``lock`` key like: Locking a Resource ------------------ -To lock the default resource, autowire the lock using -:class:`Symfony\\Component\\Lock\\LockInterface` (service id ``lock``):: +To lock the default resource, autowire the lock factory using +:class:`Symfony\\Component\\Lock\\LockFactory` (service id ``lock.factory``):: // src/Controller/PdfController.php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; - use Symfony\Component\Lock\LockInterface; + use Symfony\Component\Lock\LockFactory; class PdfController extends AbstractController { /** * @Route("/download/terms-of-use.pdf") */ - public function downloadPdf(LockInterface $lock, MyPdfGeneratorService $pdf) + public function downloadPdf(LockFactory $factory, MyPdfGeneratorService $pdf) { + $lock = $factory->createLock('pdf-creation'); $lock->acquire(true); // heavy computation @@ -273,18 +274,12 @@ provides :ref:`named lock `:: ], ]); -Each name becomes a service where the service id suffixed by the name of the -lock (e.g. ``lock.invoice``). An autowiring alias is also created for each lock -using the camel case version of its name suffixed by ``Lock`` - e.g. ``invoice`` -can be injected automatically by naming the argument ``$invoiceLock`` and -type-hinting it with :class:`Symfony\\Component\\Lock\\LockInterface`. - -Symfony also provide a corresponding factory and store following the same rules -(e.g. ``invoice`` generates a ``lock.invoice.factory`` and -``lock.invoice.store``, both can be injected automatically by naming -respectively ``$invoiceLockFactory`` and ``$invoiceLockStore`` and type-hinted -with :class:`Symfony\\Component\\Lock\\LockFactory` and -:class:`Symfony\\Component\\Lock\\PersistingStoreInterface`) +Each name becomes a service where the service id is part of the name of the +lock (e.g. ``lock.invoice.factory``). An autowiring alias is also created for +each lock using the camel case version of its name suffixed by ``LockFactory`` +- e.g. ``invoice`` can be injected automatically by naming the argument +``$invoiceLockFactory`` and type-hinting it with +:class:`Symfony\\Component\\Lock\\LockFactory`. Blocking Store -------------- From b513c1593b6e43c52b218d906ea2e06127d2d14d Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sat, 17 Oct 2020 09:10:59 +0200 Subject: [PATCH 0556/1519] Fixed use statement --- reference/constraints/Compound.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/constraints/Compound.rst b/reference/constraints/Compound.rst index 8552058708c..6e0ab5db139 100644 --- a/reference/constraints/Compound.rst +++ b/reference/constraints/Compound.rst @@ -26,7 +26,7 @@ you can create your own named set or requirements to be reused consistently ever // src/Validator/Constraints/PasswordRequirements.php namespace App\Validator\Constraints; - use Symfony\Component\Validator\Compound; + use Symfony\Component\Validator\Constraints\Compound; use Symfony\Component\Validator\Constraints as Assert; /** From 48c5e90049fedbabaa7bab6622a02c76723fe684 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Fri, 16 Oct 2020 19:19:34 +0200 Subject: [PATCH 0557/1519] Fixed broken use statements --- migration.rst | 2 +- reference/constraints/Traverse.rst | 4 ++-- routing.rst | 2 +- translation.rst | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/migration.rst b/migration.rst index 6b71a07670b..fa8c2bfc24b 100644 --- a/migration.rst +++ b/migration.rst @@ -238,7 +238,7 @@ could look something like this:: // public/index.php use App\Kernel; use App\LegacyBridge; - use Symfony\Component\Debug\Debug; + use Symfony\Component\ErrorHandler\Debug; use Symfony\Component\HttpFoundation\Request; require dirname(__DIR__).'/vendor/autoload.php'; diff --git a/reference/constraints/Traverse.rst b/reference/constraints/Traverse.rst index 852f17cdd01..fd329bd38a3 100644 --- a/reference/constraints/Traverse.rst +++ b/reference/constraints/Traverse.rst @@ -26,8 +26,8 @@ that all have constraints on their properties. // src/Entity/BookCollection.php namespace App\Entity; - use Doctrine\Collections\ArrayCollection; - use Doctrine\Collections\Collection + use Doctrine\Common\Collections\ArrayCollection; + use Doctrine\Common\Collections\Collection use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; diff --git a/routing.rst b/routing.rst index c1c8a65e702..b4054a3137c 100644 --- a/routing.rst +++ b/routing.rst @@ -2247,7 +2247,7 @@ session shouldn't be used when matching a request: // config/routes.php use App\Controller\MainController; - use Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator\RoutingConfigurator; + use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; return function (RoutingConfigurator $routes) { $routes->add('homepage', '/') diff --git a/translation.rst b/translation.rst index fbf08ba14a1..1d6bdf5b7e2 100644 --- a/translation.rst +++ b/translation.rst @@ -307,10 +307,10 @@ parts of your application and mocking it in your tests. Instead of translating a string at the time of creation, you can use a "translatable object", which is an instance of the -:class:`Symfony\\Component\\Translation\\TranslatableMessage` class. This object stores +:class:`Symfony\\Component\\Translation\\Translatable` class. This object stores all the information needed to fully translate its contents when needed:: - use Symfony\Component\Translation\TranslatableMessage; + use Symfony\Component\Translation\Translatable; // the first argument is required and it's the original message $message = new TranslatableMessage('Symfony is great!'); From 0434fbbb582a11c7012522b2840000f18d7013b1 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 17 Oct 2020 13:07:01 +0200 Subject: [PATCH 0558/1519] Tweaks --- rate_limiter.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index 2abc25a1a5c..f0a16e9493e 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -33,23 +33,24 @@ Its main drawback is that resource usage is not evenly distributed in time and it can overload the server at the window edges. In the previous example, a user could make the 4,999 requests in the last minute of some hour and another 5,000 requests during the first minute of the next hour, making 9,999 requests in -total in two minutes and possibly overloading the server. +total in two minutes and possibly overloading the server. These periods of +excessive usage are called "bursts". Sliding Window Rate Limiter ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The sliding window algorithm is gracefully handling the drawback from the fixed -window algorithm. To reduce bursts requests the rate limit is calculated based on +The sliding window algorithm is an alternative to the fixed window algorithm +designed to reduce bursts. To do that, the rate limit is calculated based on the current window and the previous window. -For example: The limit is 5,000 requests per hour. If a user made 4,000 requests +For example: the limit is 5,000 requests per hour; a user made 4,000 requests the previous hour and 500 requests this hour. 15 minutes in to the current hour (25% of the window) the hit count would be calculated as: 75% * 4,000 + 500 = 3,500. At this point in time the user can only do 1,500 more requests. The math shows that the closer the last window is, the more will the hit count of the last window effect the current limit. This will make sure that a user can -do 5.000 requests per hour but only if they are spread out evenly. +do 5,000 requests per hour but only if they are spread out evenly. Token Bucket Rate Limiter ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -85,11 +86,12 @@ enforce different levels of service (free or paid): framework: rate_limiter: anonymous_api: - strategy: fixed_window + # use 'sliding_window' if you prefer that strategy + strategy: 'fixed_window' limit: 100 interval: '60 minutes' authenticated_api: - strategy: token_bucket + strategy: 'token_bucket' limit: 5000 rate: { interval: '15 minutes', amount: 500 } From 72ff90333cec11a25275b09c591e95560b3c00a7 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 17 Oct 2020 15:15:20 +0200 Subject: [PATCH 0559/1519] Document reserve() method and rename to RateLimiter --- rate_limiter.rst | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index f0a16e9493e..3849a502858 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -124,12 +124,13 @@ the number of requests to the API:: use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; - use Symfony\Component\RateLimiter\Limiter; + use Symfony\Component\RateLimiter\RateLimiter; class ApiController extends AbstractController { // the variable name must be: "rate limiter name" + "limiter" suffix - public function index(Limiter $anonymousApiLimiter) + // if you're using autowiring for your services + public function index(RateLimiter $anonymousApiLimiter) { // create a limiter based on a unique identifier of the client // (e.g. the client's IP address, a username/email, an API key, etc.) @@ -158,28 +159,33 @@ the number of requests to the API:: for the :ref:`kernel.request event ` and check the rate limiter once for all requests. -In other scenarios you may want instead to wait as long as needed until a new -token is available. In those cases, use the ``wait()`` method:: +Wait until a Token is Available +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Instead of dropping a request or process when the limit has been reached, +you might want to wait until a new token is available. This can be achieved +using the ``reserve()`` method:: // src/Controller/ApiController.php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\RateLimiter\Limiter; + use Symfony\Component\RateLimiter\RateLimiter; class ApiController extends AbstractController { - public function registerUser(Request $request, Limiter $authenticatedApiLimiter) + public function registerUser(Request $request, RateLimiter $authenticatedApiLimiter) { $apiKey = $request->headers->get('apikey'); $limiter = $authenticatedApiLimiter->create($apiKey); // this blocks the application until the given number of tokens can be consumed - do { - $limit = $limiter->consume(1); - $limit->wait(); - } while (!$limit->isAccepted()); + $limiter->reserve(1)->wait(); + + // optional, pass a maximum wait time (in seconds), a MaxWaitDurationExceededException + // is thrown if the process has to wait longer. E.g. to wait at most 20 seconds: + //$limiter->reserve(1, 20)->wait(); // ... } @@ -187,6 +193,25 @@ token is available. In those cases, use the ``wait()`` method:: // ... } +The ``reserve()`` method is able to reserve a token in the future. Only use +this method if you're planning to wait, otherwise you will block other +processes by reserving unused tokens. + +.. note:: + + Not all strategies allow reservering tokens in the future. These + strategies may throw an ``ReserveNotSupportedException`` when calling + ``reserve()``. + + In these cases, you can use ``consume()`` together with ``wait()``, but + there is no guarantee that a token is available after the wait:: + + // ... + do { + $limit = $limiter->consume(1); + $limit->wait(); + } while (!$limit->isAccepted()); + Rate Limiter Storage and Locking -------------------------------- From 8ed09166a92302078a684c4c6d9e2d0dd06e3ef7 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sun, 11 Oct 2020 13:47:27 +0200 Subject: [PATCH 0560/1519] Added login link documentation --- _images/security/login_link_email.png | Bin 0 -> 4301 bytes security/experimental_authenticators.rst | 2 + security/login_link.rst | 652 +++++++++++++++++++++++ 3 files changed, 654 insertions(+) create mode 100644 _images/security/login_link_email.png create mode 100644 security/login_link.rst diff --git a/_images/security/login_link_email.png b/_images/security/login_link_email.png new file mode 100644 index 0000000000000000000000000000000000000000..8331b878f68376279fc5f672eb3e3826761b5202 GIT binary patch literal 4301 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 +in your configuration to use this feature. + +Using the Login Link Authenticator +---------------------------------- + +This guide assumes you have setup security and have created a user object +in your application. Follow :doc:`the main security guide ` if +this is not yet the case. + +1) Configure the Login Link Authenticator +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The login link authenticator is configured using the ``login_link`` option +under the firewall. You must configure a ``check_route`` and +``signature_properties`` when enabling this authenticator: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + firewalls: + main: + login_link: + check_route: login_check + signature_properties: ['id'] + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + $container->loadFromExtension('security', [ + 'firewalls' => [ + 'main' => [ + 'login_link' => [ + 'check_route' => 'login_check', + ], + ], + ], + ]); + +The ``signature_properties`` are used to create a signed URL. This must +contain at least one property of your ``User`` object that uniquely +identifies this user (e.g. the user ID). Read more about this setting +:ref:`further down below `. + +The ``check_route`` must be an existing route and it will be used to +generate the login link that will authenticate the user. You don't need a +controller (or it can be empty) because the login link authenticator will +intercept requests to this route: + +.. configuration-block:: + + .. code-block:: php-annotations + + // src/Controller/SecurityController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class SecurityController extends AbstractController + { + /** + * @Route("/login_check", name="login_check") + */ + public function check() + { + throw new \LogicException('This code should never be reached'); + } + } + + .. code-block:: yaml + + # config/routes.yaml + + # ... + login_check: + path: /login_check + + .. code-block:: xml + + + + + + + + + + .. code-block:: php + + // config/routes.php + use App\Controller\DefaultController; + use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; + + return function (RoutingConfigurator $routes) { + // ... + $routes->add('login_check', '/login_check'); + }; + +2) Generate the Login Link +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Now that the authenticator is able to check the login links, you must +create a page where a user can request a login link and log in to your +website. + +The login link can be generated using the +:class:`Symfony\\Component\\Security\\Http\\LoginLink\\LoginLinkHandlerInterface`. +The correct login link handler is autowired for you when type-hinting for +this interface:: + + // src/Controller/SecurityController.php + namespace App\Controller; + + use App\Repository\UserRepository; + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\Routing\Annotation\Route; + use Symfony\Component\Security\Http\LoginLink\LoginLinkHandlerInterface; + + class SecurityController extends AbstractController + { + /** + * @Route("/login", name="login") + */ + public function requestLoginLink(LoginLinkHandlerInterface $loginLinkHandler, UserRepository $userRepository, Request $request) + { + // check if login form is submitted + if ($request->isMethod('POST')) { + // load the user in some way (e.g. using the form input) + $email = $request->request->get('email'); + $user = $userRepository->findOneBy(['email' => $email]); + + // create a login link for $user this returns an instance + // of LoginLinkDetails + $loginLinkDetails = $loginLinkHandler->createLoginLink($user); + $loginLink = $loginLinkDetails->getUrl(); + + // ... send the link and return a response (see next section) + } + + // if it's not submitted, render the "login" form + return $this->render('security/login.html.twig'); + } + + // ... + } + +.. code-block:: html+twig + + {# templates/security/login.html.twig #} + {% extends 'base.html.twig' %} + + {% block body %} +
+ + +
+ {% endblock %} + +In this controller, the user is submitting their e-mail address to the +controller. Based on this property, the correct user is loaded and a login +link is created using +:method:`Symfony\\Component\\Security\\Http\\LoginLink\\LoginLinkHandlerInterface::createLoginLink`. + +.. caution:: + + It is important to send this link to the user and **not show it directly**, + as that would allow anyone to login. For instance, use the + :doc:`mailer ` component to mail the login link to the user. + Or use the component to send an SMS to the + user's device. + +3) Send the Login Link to the User +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Now the link is created, it needs to be send to the user. Anyone with the +link is able to login as this user, so you need to make sure to send it to +a known device of them (e.g. using e-mail or SMS). + +You can send the link using any library or method. However the login link +authenticator provides integration with the :doc:`Notifier component `. +Use the special :class:`Symfony\\Component\\Security\\Http\\LoginLink\\LoginLinkNotification` +to create a notification and send it to the user's email address or phone +number:: + + // src/Controller/SecurityController.php + + // ... + use Symfony\Component\Notifier\NotifierInterface; + use Symfony\Component\Notifier\Recipient\Recipient; + use Symfony\Component\Security\Http\LoginLink\LoginLinkNotification; + + class SecurityController extends AbstractController + { + /** + * @Route("/login", name="login") + */ + public function requestLoginLink(NotifierInterface $notifier, LoginLinkHandlerInterface $loginLinkHandler, UserRepository $userRepository, Request $request) + { + if ($request->isMethod('POST')) { + $email = $request->request->get('email'); + $user = $userRepository->findOneBy(['email' => $email]); + + $loginLinkDetails = $loginLinkHandler->createLoginLink($user); + + // create a notification based on the login link details + $notification = new LoginLinkNotification( + $loginLinkDetails, + 'Welcome to MY WEBSITE!' // email subject + ); + // create a recipient for this user + $recipient = (new Recipient())->email($user->getEmail()); + + // send the notification to the user + $notifier->send($notification, $recipient); + + // render a "Login link is sent!" page + return $this->render('security/login_link_sent.html.twig'); + } + + return $this->render('security/login.html.twig'); + } + + // ... + } + +.. note:: + + This integration requires the :doc:`Notifier ` and + :doc:`Mailer ` components to be installed and configured. + Install all required packages using: + + .. code-block:: terminal + + $ composer require symfony/mailer symfony/notifier \ + symfony/twig-bundle twig/extra-bundle \ + twig/cssinliner-extra twig/inky-extra + +This will send an email like this to the user: + +.. image:: /_images/security/login_link_email.png + :align: center + +.. tip:: + + You can customize this e-mail template by extending the + ``LoginLinkNotification`` and configuring another ``htmlTemplate``:: + + // src/Notifier/CustomLoginLinkNotification + namespace App\Notifier; + + use Symfony\Component\Security\Http\LoginLink\LoginLinkNotification; + + class CustomLoginLinkNotification extends LoginLinkNotification + { + public function asEmailMessage(EmailRecipientInterface $recipient, string $transport = null): ?EmailMessage + { + $emailMessage = parent::asEmailMessage($recipient, $transport); + + // get the NotificationEmail object and override the template + $email = $emailMessage->getMessage(); + $email->htmlTemplate('emails/custom_login_link_email.html.twig'); + + return $emailMessage; + } + } + + Then, use this new ``CustomLoginLinkNotification`` in the controller + instead. + +Important Considerations +------------------------ + +Login links are a convenient way of authenticating users, but it is also +considered less secure than a traditional username and password form. It is +not recommended to use login links in security critical applications. + +However, the implementation in Symfony does have a couple extension points +to make the login links more secure. In this section, the most important +configuration decisions are discussed: + +* `Limit Login Link Lifetime`_ +* `Invalidate Login Links`_ +* `Only allow a Link to be used Once`_ + +Limit Login Link Lifetime +~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is important for login links to have a limited lifetime. This reduces +the risk that someone can intercept the link and use it to login as +somebody else. By default, Symfony defines a lifetime of 10 minutes (600 +seconds). You can customize this using the ``lifetime`` option: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + firewalls: + main: + login_link: + check_route: login_check + # lifetime in seconds + lifetime: 300 + + .. code-block:: xml + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + $container->loadFromExtension('security', [ + 'firewalls' => [ + 'main' => [ + 'login_link' => [ + 'check_route' => 'login_check', + // lifetime in seconds + 'lifetime' => 300, + ], + ], + ], + ]); + +.. _security-login-link-signature: + +Invalidate Login Links +~~~~~~~~~~~~~~~~~~~~~~ + +Symfony uses signed URLs to implement login links. The advantage of this is +that valid links do not have to be stored in a database. The signed URLs +allow Symfony to still invalidate already sent login links when important +information changes (e.g. a user's email address). + +The signed URL contains 3 parameters: + +``expires`` + The UNIX timestamp when the link expires. + +``user`` + The value returned from ``$user->getUsername()`` for this user. + +``hash`` + A hash of ``expires``, ``user`` and any configured signature + properties. Whenever these change, the hash changes and previous login + links are invalidated. + +You can add more properties to the ``hash`` by using the +``signature_properties`` option: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + firewalls: + main: + login_link: + check_route: login_check + signature_properties: [id, email] + + .. code-block:: xml + + + + + + + + + id + email + + + + + + .. code-block:: php + + // config/packages/security.php + $container->loadFromExtension('security', [ + 'firewalls' => [ + 'main' => [ + 'login_link' => [ + 'check_route' => 'login_check', + 'signature_properties' => ['id', 'email'], + ], + ], + ], + ]); + +The properties are fetched from the user object using the +:doc:`PropertyAccess component ` (e.g. using +``getEmail()`` or a public ``$email`` property in this example). + +.. tip:: + + You can also use the signature properties to add very advanced + invalidating logic to your login links. For instance, if you store a + ``$lastLinkRequestedAt`` property on your users that you update in the + ``requestLoginLink()`` controller, you can invalidate all login links + whenever a user requests a new link. + +Configure a Maximum Use of a Link +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is a common characteristic of login links to limit the number of times +it can be used. Symfony can support this by storing used login links in the +cache. Enable this support by setting the ``max_uses`` option: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + firewalls: + main: + login_link: + check_route: login_check + # only allow the link to be used 3 times + max_uses: 3 + + # optionally, configure the cache pool + #used_link_cache: 'cache.redis' + + .. code-block:: xml + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + $container->loadFromExtension('security', [ + 'firewalls' => [ + 'main' => [ + 'login_link' => [ + 'check_route' => 'login_check', + // only allow the link to be used 3 times + 'max_uses' => 3, + + // optionally, configure the cache pool + //'used_link_cache' => 'cache.redis', + ], + ], + ], + ]); + +Make sure there is enough space left in the cache, otherwise invalid links +can no longer be stored (and thus become valid again). Expired invalid +links are automatically removed from the cache. + +The cache pools are not cleared by the ``cache:clear`` command, but +removing ``var/cache/`` manually may remove the cache if the cache +component is configured to store its cache in that location. Read the +:doc:`/cache` guide for more information. + +Allow a Link to only be Used Once +................................. + +When setting ``max_uses`` to ``1``, you must take extra precautions to +make it work as expected. Email providers and browsers often load a +preview of the links, meaning that the link is already invalidated by +the preview loader. + +In order to solve this issue, first set the ``check_post_only`` option let +the authenticator only handle HTTP POST methods: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + firewalls: + main: + login_link: + check_route: login_check + check_post_only: true + max_uses: 1 + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + $container->loadFromExtension('security', [ + 'firewalls' => [ + 'main' => [ + 'login_link' => [ + 'check_route' => 'login_check', + 'check_post_only' => true, + 'max_uses' => 1, + ], + ], + ], + ]); + +Then, use the ``check_route`` controller to render a page that lets the +user create this POST request (e.g. by clicking a button):: + + // src/Controller/SecurityController.php + namespace App\Controller; + + // ... + use Symfony\Component\Routing\Generator\UrlGeneratorInterface; + + class SecurityController extends AbstractController + { + /** + * @Route("/login_check", name="login_check") + */ + public function check() + { + // get the login link query parameters + $expires = $request->query->get('expires'); + $username = $request->query->get('user'); + $hash = $request->query->get('hash'); + + // and render a template with the button + return $this->render('security/process_login_link.html.twig', [ + 'expires' => $expires, + 'user' => $username, + 'hash' => $hash, + ]); + } + } + +.. code-block:: html+twig + + {# templates/security/process_login_link.html.twig #} + {% extends 'base.html.twig' %} + + {% block body %} +

Hi! You are about to login to ...

+ + +
+ + + + + +
+ {% endblock %} From 2c8e1b940976cc4300aec04b8e50d498944dd3db Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 17 Oct 2020 16:53:25 +0200 Subject: [PATCH 0561/1519] Tweaks --- rate_limiter.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index 3849a502858..6fa7192945f 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -128,8 +128,8 @@ the number of requests to the API:: class ApiController extends AbstractController { - // the variable name must be: "rate limiter name" + "limiter" suffix - // if you're using autowiring for your services + // if you're using service autowiring, the variable name must be: + // "rate limiter name" (in camelCase) + "limiter" suffix public function index(RateLimiter $anonymousApiLimiter) { // create a limiter based on a unique identifier of the client @@ -199,8 +199,8 @@ processes by reserving unused tokens. .. note:: - Not all strategies allow reservering tokens in the future. These - strategies may throw an ``ReserveNotSupportedException`` when calling + Not all strategies allow reserving tokens in the future. These + strategies may throw a ``ReserveNotSupportedException`` when calling ``reserve()``. In these cases, you can use ``consume()`` together with ``wait()``, but From b8653ebb1ee6eb03ce18d42fc1eded0e2f950b59 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 17 Oct 2020 18:49:15 +0200 Subject: [PATCH 0562/1519] Reword the intro --- security/login_link.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/security/login_link.rst b/security/login_link.rst index 929091184de..b980dea5790 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -5,10 +5,14 @@ How to use Passwordless Login Link Authentication ================================================= -Login links, also called "magic links", allow users to log in without -passwords. Whenever a user wants to login, a login link is generated and -sent to the user (e.g. using an email). The user is logged in as soon as -they visit that link. +Login links, also called "magic links", are a passwordless authentication +mechanism. Whenever a user wants to login, a new link is generated and sent to +them (e.g. using an email). The link fully authenticates the user in the +application when clicking on it. + +This authentication method can help you eliminate most of the customer support +related to authentication (e.g. I forgot my password, how can I change or reset +my password, etc.) Login links are supported by Symfony when using the experimental authenticator system. You must From 0c6a78285c2cf275a3769203ab94518a9706be1d Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 17 Oct 2020 19:20:31 +0200 Subject: [PATCH 0563/1519] Added the versionadded directive --- components/options_resolver.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/options_resolver.rst b/components/options_resolver.rst index 74569b9123e..941d61de6c7 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -823,8 +823,7 @@ method:: .. versionadded:: 5.1 - The :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::define` method - was introduced in Symfony 5.1. + The ``define()`` and ``info()`` methods were introduced in Symfony 5.1. Performance Tweaks ~~~~~~~~~~~~~~~~~~ From f012726a03907a7d26536f293d4baeeb92db9164 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 17 Oct 2020 19:27:01 +0200 Subject: [PATCH 0564/1519] Fixed a broken reference --- security/login_link.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/login_link.rst b/security/login_link.rst index b980dea5790..3db4f34f8eb 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -325,7 +325,7 @@ configuration decisions are discussed: * `Limit Login Link Lifetime`_ * `Invalidate Login Links`_ -* `Only allow a Link to be used Once`_ +* `Allow a Link to only be Used Once`_ Limit Login Link Lifetime ~~~~~~~~~~~~~~~~~~~~~~~~~ From a93da4e4ff1cd4d0863ced455fb1848fb3c27f26 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Tue, 13 Oct 2020 20:17:10 +0200 Subject: [PATCH 0565/1519] Made all messenger transport look the same --- messenger.rst | 290 +++++++++++++++++++++++++------------------------- 1 file changed, 147 insertions(+), 143 deletions(-) diff --git a/messenger.rst b/messenger.rst index 5eb11cba839..04f0716f982 100644 --- a/messenger.rst +++ b/messenger.rst @@ -123,7 +123,7 @@ is capable of sending messages (e.g. to a queueing system) and then A transport is registered using a "DSN". Thanks to Messenger's Flex recipe, your ``.env`` file already has a few examples. -.. code-block:: bash +.. code-block:: env # MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages # MESSENGER_TRANSPORT_DSN=doctrine://default @@ -839,11 +839,71 @@ Transport Configuration ----------------------- Messenger supports a number of different transport types, each with their own -options. +options. Options can be passed to the transport via a DSN string or configuration. + +.. code-block:: env + + # .env + MESSENGER_TRANSPORT_DSN=amqp://localhost/%2f/messages?auto_setup=false + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/messenger.yaml + framework: + messenger: + transports: + my_transport: + dsn: "%env(MESSENGER_TRANSPORT_DSN)%" + options: + auto_setup: false + + .. code-block:: xml + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/messenger.php + $container->loadFromExtension('framework', [ + 'messenger' => [ + 'transports' => [ + 'my_transport' => [ + 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', + 'options' => [ + 'auto_setup' => false, + ] + ], + ], + ], + ]); + +Options defined under ``options`` take precedence over ones defined in the DSN. AMQP Transport ~~~~~~~~~~~~~~ +The AMQP transport uses the AMQP PHP extension to send messages to queues like +RabbitMQ. + .. versionadded:: 5.1 Starting from Symfony 5.1, the AMQP transport has moved to a separate package. @@ -853,9 +913,9 @@ AMQP Transport $ composer require symfony/amqp-messenger -The ``amqp`` transport configuration looks like this: +The AMQP transport DSN may looks like this: -.. code-block:: bash +.. code-block:: env # .env MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages @@ -867,7 +927,6 @@ The ``amqp`` transport configuration looks like this: The AMQPS protocol support was introduced in Symfony 5.2. -To use Symfony's built-in AMQP transport, you need the AMQP PHP extension. If you want to use TLS/SSL encrypted AMQP, you must also provide a CA certificate. Define the certificate path in the ``amqp.cacert`` PHP.ini setting (e.g. ``amqp.cacert = /etc/ssl/certs``) or in the ``cacert`` parameter of the @@ -886,6 +945,66 @@ The transport has a number of other options, including ways to configure the exchange, queues binding keys and more. See the documentation on :class:`Symfony\\Component\\Messenger\\Bridge\\Amqp\\Transport\\Connection`. +The transport has a number of options: + +============================================ ================================================= =================================== + Option Description Default +============================================ ================================================= =================================== +``auto_setup`` Whether the table should be created ``true`` + automatically during send / get. +``cacert`` Path to the CA cert file in PEM format. +``cert`` Path to the client certificate in PEM format. +``channel_max`` Specifies highest channel number that the server + permits. 0 means standard extension limit +``confirm_timeout`` Timeout in seconds for confirmation, if none + specified transport will not wait for message + confirmation. Note: 0 or greater seconds. May be + fractional. +``connect_timeout`` Connection timeout. Note: 0 or greater seconds. + May be fractional. +``frame_max`` The largest frame size that the server proposes + for the connection, including frame header and + end-byte. 0 means standard extension limit + (depends on librabbimq default frame size limit) +``heartbeat`` The delay, in seconds, of the connection + heartbeat that the server wants. 0 means the + server does not want a heartbeat. Note, + librabbitmq has limited heartbeat support, which + means heartbeats checked only during blocking + calls. +``host`` Hostname of the AMQP service +``key`` Path to the client key in PEM format. +``password`` Password to use to connect to the AMQP service +``persistent`` ``'false'`` +``port`` Port of the AMQP service +``prefetch_count`` +``read_timeout`` Timeout in for income activity. Note: 0 or + greater seconds. May be fractional. +``retry`` +``sasl_method`` +``user`` Username to use to connect the AMQP service +``verify`` Enable or disable peer verification. If peer + verification is enabled then the common name in + the server certificate must match the server + name. Peer verification is enabled by default. +``vhost`` Virtual Host to use with the AMQP service +``write_timeout`` Timeout in for outcome activity. Note: 0 or + greater seconds. May be fractional. +``delay[queue_name_pattern]`` Pattern to use to create the queues ``delay_%exchange_name%_%routing_key%_%delay%`` +``delay[exchange_name]`` Name of the exchange to be used for the ``delays`` + delayed/retried messages +``queues[name][arguments]`` Extra arguments +``queues[name][binding_arguments]`` Arguments to be used while binding the queue. +``queues[name][binding_keys]`` The binding keys (if any) to bind to this queue +``queues[name][flags]`` Queue flags ``AMQP_DURABLE`` +``exchange[arguments]`` +``exchange[default_publish_routing_key]`` Routing key to use when publishing, if none is + specified on the message +``exchange[flags]`` Exchange flags ``AMQP_DURABLE`` +``exchange[name]`` Name of the exchange +``exchange[type]`` Type of exchange ``fanout`` +============================================ ================================================= =================================== + You can also configure AMQP-specific settings on your message by adding :class:`Symfony\\Component\\Messenger\\Bridge\\Amqp\\Transport\\AmqpStamp` to your Envelope:: @@ -912,6 +1031,8 @@ your Envelope:: Doctrine Transport ~~~~~~~~~~~~~~~~~~ +The Doctrine transport can be used to store messages in a database table. + .. versionadded:: 5.1 Starting from Symfony 5.1, the Doctrine transport has moved to a separate package. @@ -921,9 +1042,9 @@ Doctrine Transport $ composer require symfony/doctrine-messenger -The Doctrine transport can be used to store messages in a database table. +The Doctrine transport DSN may looks like this: -.. code-block:: bash +.. code-block:: env # .env MESSENGER_TRANSPORT_DSN=doctrine://default @@ -942,65 +1063,6 @@ Or, to create the table yourself, set the ``auto_setup`` option to ``false`` and The transport has a number of options: -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/messenger.yaml - framework: - messenger: - transports: - async_priority_high: "%env(MESSENGER_TRANSPORT_DSN)%?queue_name=high_priority" - async_normal: - dsn: "%env(MESSENGER_TRANSPORT_DSN)%" - options: - queue_name: normal_priority - - .. code-block:: xml - - - - - - - - - - - - normal_priority - - - - - - - - .. code-block:: php - - // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'async_priority_high' => '%env(MESSENGER_TRANSPORT_DSN)%?queue_name=high_priority', - 'async_priority_low' => [ - 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', - 'options' => [ - 'queue_name' => 'normal_priority' - ] - ], - ], - ], - ]); - -Options defined under ``options`` take precedence over ones defined in the DSN. - ================== ===================================== ====================== Option Description Default ================== ===================================== ====================== @@ -1025,82 +1087,25 @@ Beanstalkd Transport The Beanstalkd transport was introduced in Symfony 5.2. -Install it by running: +The Beanstalkd transports sends messages directly to a Beanstalkd work queue. Install +it by running: .. code-block:: terminal $ composer require symfony/beanstalkd-messenger -.. code-block:: bash +The Beanstalkd transport DSN may looks like this: - # .env - MESSENGER_TRANSPORT_DSN=beanstalkd://localhost +.. code-block:: env -The format is ``beanstalkd://:?tube_name=&timeout=&ttr=``. + # .env + MESSENGER_TRANSPORT_DSN=beanstalkd://localhost:11300?tube_name=foo&timeout=4&ttr=120 -The ``port`` setting is optional and defaults to ``11300`` if not set. + # If no port, it will default to 11300 + MESSENGER_TRANSPORT_DSN=beanstalkd://localhost The transport has a number of options: -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/messenger.yaml - framework: - messenger: - transports: - async_priority_high: "%env(MESSENGER_TRANSPORT_DSN)%?tube_name=high_priority" - async_normal: - dsn: "%env(MESSENGER_TRANSPORT_DSN)%" - options: - tube_name: normal_priority - - .. code-block:: xml - - - - - - - - - - - - normal_priority - - - - - - - - .. code-block:: php - - // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'async_priority_high' => '%env(MESSENGER_TRANSPORT_DSN)%?tube_name=high_priority', - 'async_priority_low' => [ - 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', - 'options' => [ - 'tube_name' => 'normal_priority' - ] - ], - ], - ], - ]); - -Options defined under ``options`` take precedence over ones defined in the DSN. - ================== =================================== ====================== Option Description Default ================== =================================== ====================== @@ -1119,6 +1124,9 @@ ttr The message time to run before it Redis Transport ~~~~~~~~~~~~~~~ +The Redis transport uses `streams`_ to queue messages. This transport requires +the Redis PHP extension (>=4.3) and a running Redis server (^5.0). + .. versionadded:: 5.1 Starting from Symfony 5.1, the Redis transport has moved to a separate package. @@ -1128,9 +1136,9 @@ Redis Transport $ composer require symfony/redis-messenger -The Redis transport uses `streams`_ to queue messages. +The Redis transport DSN may looks like this: -.. code-block:: bash +.. code-block:: env # .env MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages @@ -1143,11 +1151,7 @@ The Redis transport uses `streams`_ to queue messages. The Unix socket DSN was introduced in Symfony 5.1. -To use the Redis transport, you will need the Redis PHP extension (>=4.3) and -a running Redis server (^5.0). - -A number of options can be configured via the DSN or via the ``options`` key -under the transport in ``messenger.yaml``: +The transport has a number of options: =================== ===================================== ========================= Option Description Default @@ -1275,27 +1279,27 @@ Amazon SQS The Amazon SQS transport as introduced in Symfony 5.1. -Install Amazon SQS transport by running: +The Amazon SQS transport is perfect for application hosted on AWS. Install it by +running: .. code-block:: terminal $ composer require symfony/amazon-sqs-messenger -The ``SQS`` transport configuration looks like this: +The SQS transport DSN may looks like this: .. code-block:: env # .env MESSENGER_TRANSPORT_DSN=sqs://AKIAIOSFODNN7EXAMPLE:j17M97ffSVoKI0briFoo9a@sqs.eu-west-3.amazonaws.com/messages - #MESSENGER_TRANSPORT_DSN=sqs://localhost:9494/messages?sslmode=disable + MESSENGER_TRANSPORT_DSN=sqs://localhost:9494/messages?sslmode=disable .. note:: The transport will automatically create queues that are needed. This can be disabled setting the ``auto_setup`` option to ``false``. -A number of options can be configured via the DSN or via the ``options`` key -under the transport in ``messenger.yaml``: +The transport has a number of options: ====================== ====================================== =================================== Option Description Default From fe40b48251b4fc43bbe50a7194759014a2858715 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 17 Oct 2020 19:44:49 +0200 Subject: [PATCH 0566/1519] Tweaks --- service_container/autowiring.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/service_container/autowiring.rst b/service_container/autowiring.rst index 56a117f7b16..4a2b606c538 100644 --- a/service_container/autowiring.rst +++ b/service_container/autowiring.rst @@ -600,15 +600,16 @@ Autowiring will automatically call *any* method with the ``#[Required]`` attribu above it, autowiring each argument. If you need to manually wire some of the arguments to a method, you can always explicitly :doc:`configure the method call `. -If you need to stay compatible with PHP 7 and thus cannot use attributes, you can use -the ``@required`` annotation instead. +If your PHP version doesn't support attributes (they were introduced in PHP 8), +you can use the ``@required`` annotation instead. .. versionadded:: 5.2 The ``#[Required]`` attribute was introduced in Symfony 5.2. -Despite property injection has some :ref:`drawbacks `, autowiring with ``#[Required]`` -or ``@required`` can also be applied to public typed properties:: +Despite property injection has some :ref:`drawbacks `, +autowiring with ``#[Required]`` or ``@required`` can also be applied to public +typed properties:: .. configuration-block:: From 8d1364ecfb4db767168dcd33dcb045971ffc4ff6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sun, 18 Oct 2020 10:20:10 +0200 Subject: [PATCH 0567/1519] Fixed some wrong class names --- translation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/translation.rst b/translation.rst index 1d6bdf5b7e2..238e80ee38c 100644 --- a/translation.rst +++ b/translation.rst @@ -313,10 +313,10 @@ all the information needed to fully translate its contents when needed:: use Symfony\Component\Translation\Translatable; // the first argument is required and it's the original message - $message = new TranslatableMessage('Symfony is great!'); + $message = new Translatable('Symfony is great!'); // the optional second argument defines the translation parameters and // the optional third argument is the translation domain - $status = new TranslatableMessage('order.status', ['%status%' => $order->getStatus()], 'store'); + $status = new Translatable('order.status', ['%status%' => $order->getStatus()], 'store'); Templates are now much simpler because you can pass translatable objects to the ``trans`` filter: From b5b0f71b1c560f2cc0a8bffbb231c5b88f18d08a Mon Sep 17 00:00:00 2001 From: Marvin Hinz <35603466+marvinhinz@users.noreply.github.com> Date: Sun, 18 Oct 2020 21:12:40 +0200 Subject: [PATCH 0568/1519] Fix spelling in framework.rst --- reference/configuration/framework.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 0e09a21c5cf..cdf5451d94a 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -770,7 +770,7 @@ service into your autowired classes. .. _reference-http-client-retry-failed: By enabling the optional ``retry_failed`` configuration, the HTTP client service -will automaticaly retry failed HTTP requests. +will automatically retry failed HTTP requests. .. code-block:: yaml From 19521c3a25b4d1afb3b4b8e9fe02014ac9312972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Tue, 20 Oct 2020 09:53:08 +0200 Subject: [PATCH 0569/1519] Fix documentation about RetryStrategy --- http_client.rst | 7 ++-- reference/configuration/framework.rst | 55 +++++++++------------------ 2 files changed, 22 insertions(+), 40 deletions(-) diff --git a/http_client.rst b/http_client.rst index a54e9b125a8..e0a9d6808e3 100644 --- a/http_client.rst +++ b/http_client.rst @@ -710,10 +710,9 @@ original HTTP client:: $client = new RetryableHttpClient(HttpClient::create()); The ``RetryableHttpClient`` uses a -:class:`Symfony\\Component\\HttpClient\\Retry\\RetryDeciderInterface` to -decide if the request should be retried, and a -:class:`Symfony\\Component\\HttpClient\\Retry\\RetryBackOffInterface` to -define the waiting time between each retry. +:class:`Symfony\\Component\\HttpClient\\Retry\\RetryStrategyInterface` to +decide if the request should be retried, and to define the waiting time between +each retry. HTTP Proxies ~~~~~~~~~~~~ diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index cdf5451d94a..a3d6e9fd95a 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -140,8 +140,7 @@ Configuration * :ref:`retry_failed ` - * `backoff_service`_ - * `decider_service`_ + * `retry_strategy`_ * :ref:`enabled ` * `delay`_ * `http_codes`_ @@ -157,8 +156,7 @@ Configuration * :ref:`retry_failed ` - * `backoff_service`_ - * `decider_service`_ + * `retry_strategy`_ * :ref:`enabled ` * `delay`_ * `http_codes`_ @@ -780,8 +778,7 @@ will automatically retry failed HTTP requests. http_client: # ... retry_failed: - # backoff_service: app.custom_backoff - # decider_service: app.custom_decider + # retry_strategy: app.custom_strategy http_codes: [429, 500] max_retries: 2 delay: 1000 @@ -826,21 +823,6 @@ in the `Microsoft NTLM authentication protocol`_. The value of this option must follow the format ``username:password``. This authentication mechanism requires using the cURL-based transport. -backoff_service -............... - -**type**: ``string`` - -.. versionadded:: 5.2 - - The ``backoff_service`` option was introduced in Symfony 5.2. - -The service id used to compute the time to wait between retries. By default, it -uses an instance of -:class:`Symfony\\Component\\HttpClient\\Retry\\ExponentialBackOff` configured -with ``delay``, ``max_delay``, ``multiplier`` and ``jitter`` options. This -class has to implement :class:`Symfony\\Component\\HttpClient\\Retry\\RetryBackOffInterface`. - base_uri ........ @@ -909,21 +891,6 @@ ciphers A list of the names of the ciphers allowed for the SSL/TLS connections. They can be separated by colons, commas or spaces (e.g. ``'RC4-SHA:TLS13-AES-128-GCM-SHA256'``). -decider_service -............... - -**type**: ``string`` - -.. versionadded:: 5.2 - - The ``decider_service`` option was introduced in Symfony 5.2. - -The service id used to decide if a request should be retried. By default, it -uses an instance of -:class:`Symfony\\Component\\HttpClient\\Retry\\HttpStatusCodeDecider` configured -with the ``http_codes`` option. This class has to implement -:class:`Symfony\\Component\\HttpClient\\Retry\\RetryDeciderInterface`. - delay ..... @@ -1124,6 +1091,22 @@ client and to make your tests easier. The value of this option is an associative array of ``domain => IP address`` (e.g ``['symfony.com' => '46.137.106.254', ...]``). +retry_strategy +............... + +**type**: ``string`` + +.. versionadded:: 5.2 + + The ``retry_strategy`` option was introduced in Symfony 5.2. + +The service is used to decide if a request should be retried and to compute the +time to wait between retries. By default, it uses an instance of +:class:`Symfony\\Component\\HttpClient\\Retry\\GenericRetryStrategy` configured +with ``http_codes``, ``delay``, ``max_delay``, ``multiplier`` and ``jitter`` +options. This class has to implement +:class:`Symfony\\Component\\HttpClient\\Retry\\RetryStrategyInterface`. + scope ..... From 09a9aa0d903f154e4c62654e2c652c7750a72c58 Mon Sep 17 00:00:00 2001 From: Ahmed TAILOULOUTE Date: Mon, 30 Dec 2019 08:44:27 +0100 Subject: [PATCH 0570/1519] Update typehints --- components/asset.rst | 4 ++-- configuration/env_var_processors.rst | 2 +- form/data_mappers.rst | 4 ++-- form/type_guesser.rst | 12 ++++++------ forms.rst | 2 +- frontend/custom_version_strategy.rst | 6 +++--- reference/dic_tags.rst | 4 ++-- security/access_control.rst | 2 +- security/custom_authentication_provider.rst | 2 +- security/user_provider.rst | 6 +++--- serializer/custom_encoders.rst | 8 ++++---- session/locale_sticky_session.rst | 2 +- 12 files changed, 27 insertions(+), 27 deletions(-) diff --git a/components/asset.rst b/components/asset.rst index 20b5ce20b2d..48e51754449 100644 --- a/components/asset.rst +++ b/components/asset.rst @@ -200,12 +200,12 @@ every day:: $this->version = date('Ymd'); } - public function getVersion($path) + public function getVersion(string $path) { return $this->version; } - public function applyVersion($path) + public function applyVersion(string $path) { return sprintf('%s?v=%s', $path, $this->getVersion($path)); } diff --git a/configuration/env_var_processors.rst b/configuration/env_var_processors.rst index b9782d270cd..464bf7af984 100644 --- a/configuration/env_var_processors.rst +++ b/configuration/env_var_processors.rst @@ -631,7 +631,7 @@ create a class that implements class LowercasingEnvVarProcessor implements EnvVarProcessorInterface { - public function getEnv($prefix, $name, \Closure $getEnv) + public function getEnv(string $prefix, string $name, \Closure $getEnv) { $env = $getEnv($name); diff --git a/form/data_mappers.rst b/form/data_mappers.rst index 15e66ce54b3..54081c09e47 100644 --- a/form/data_mappers.rst +++ b/form/data_mappers.rst @@ -98,7 +98,7 @@ in your form type:: /** * @param Color|null $viewData */ - public function mapDataToForms($viewData, $forms) + public function mapDataToForms($viewData, iterable $forms) { // there is no data yet, so nothing to prepopulate if (null === $viewData) { @@ -119,7 +119,7 @@ in your form type:: $forms['blue']->setData($viewData->getBlue()); } - public function mapFormsToData($forms, &$viewData) + public function mapFormsToData(iterable $forms, &$viewData) { /** @var FormInterface[] $forms */ $forms = iterator_to_array($forms); diff --git a/form/type_guesser.rst b/form/type_guesser.rst index f990aad4115..13f54999692 100644 --- a/form/type_guesser.rst +++ b/form/type_guesser.rst @@ -43,19 +43,19 @@ Start by creating the class and these methods. Next, you'll learn how to fill ea class PHPDocTypeGuesser implements FormTypeGuesserInterface { - public function guessType($class, $property) + public function guessType(string $class, string $property) { } - public function guessRequired($class, $property) + public function guessRequired(string $class, string $property) { } - public function guessMaxLength($class, $property) + public function guessMaxLength(string $class, string $property) { } - public function guessPattern($class, $property) + public function guessPattern(string $class, string $property) { } } @@ -94,7 +94,7 @@ With this knowledge, you can implement the ``guessType()`` method of the class PHPDocTypeGuesser implements FormTypeGuesserInterface { - public function guessType($class, $property) + public function guessType(string $class, string $property) { $annotations = $this->readPhpDocAnnotations($class, $property); @@ -129,7 +129,7 @@ With this knowledge, you can implement the ``guessType()`` method of the } } - protected function readPhpDocAnnotations($class, $property) + protected function readPhpDocAnnotations(string $class, string $property) { $reflectionProperty = new \ReflectionProperty($class, $property); $phpdoc = $reflectionProperty->getDocComment(); diff --git a/forms.rst b/forms.rst index 5867d2f07d1..ec5a04fcfc1 100644 --- a/forms.rst +++ b/forms.rst @@ -672,7 +672,7 @@ Set the ``label`` option on fields to define their labels explicitly:: ->add('dueDate', DateType::class, [ // set it to FALSE to not display the label for this field - 'label' => 'To Be Completed Before', + 'label' => 'To Be Completed Before', ]) .. tip:: diff --git a/frontend/custom_version_strategy.rst b/frontend/custom_version_strategy.rst index 6361ba632c0..0fe3f5ff987 100644 --- a/frontend/custom_version_strategy.rst +++ b/frontend/custom_version_strategy.rst @@ -71,13 +71,13 @@ version string:: * @param string $manifestPath * @param string|null $format */ - public function __construct($manifestPath, $format = null) + public function __construct(string $manifestPath, string $format = null) { $this->manifestPath = $manifestPath; $this->format = $format ?: '%s?%s'; } - public function getVersion($path) + public function getVersion(string $path) { if (!is_array($this->hashes)) { $this->hashes = $this->loadManifest(); @@ -86,7 +86,7 @@ version string:: return isset($this->hashes[$path]) ? $this->hashes[$path] : ''; } - public function applyVersion($path) + public function applyVersion(string $path) { $version = $this->getVersion($path); diff --git a/reference/dic_tags.rst b/reference/dic_tags.rst index f7f43dca376..0aca3c91777 100644 --- a/reference/dic_tags.rst +++ b/reference/dic_tags.rst @@ -410,7 +410,7 @@ service class:: class MyClearer implements CacheClearerInterface { - public function clear($cacheDirectory) + public function clear(string $cacheDirectory) { // clear your cache } @@ -1062,7 +1062,7 @@ required option: ``alias``, which defines the name of the extractor:: /** * Sets the prefix that should be used for new found messages. */ - public function setPrefix($prefix) + public function setPrefix(string $prefix) { $this->prefix = $prefix; } diff --git a/security/access_control.rst b/security/access_control.rst index 9b345b87a24..b02b9057424 100644 --- a/security/access_control.rst +++ b/security/access_control.rst @@ -92,7 +92,7 @@ Take the following ``access_control`` entries as an example: 'path' => '^/admin', 'roles' => 'ROLE_USER_METHOD', 'methods' => 'POST, PUT', - ] + ], ], ]); diff --git a/security/custom_authentication_provider.rst b/security/custom_authentication_provider.rst index 3199128b26a..4a0a5be4407 100644 --- a/security/custom_authentication_provider.rst +++ b/security/custom_authentication_provider.rst @@ -410,7 +410,7 @@ to service ids that may not exist yet: ``App\Security\Authentication\Provider\Ws - + diff --git a/security/user_provider.rst b/security/user_provider.rst index 000a7a49a38..5fcf19f3bf2 100644 --- a/security/user_provider.rst +++ b/security/user_provider.rst @@ -135,7 +135,7 @@ interface only requires one method: ``loadUserByUsername($username)``:: { // ... - public function loadUserByUsername($usernameOrEmail) + public function loadUserByUsername(string $usernameOrEmail) { $entityManager = $this->getEntityManager(); @@ -376,7 +376,7 @@ command will generate a nice skeleton to get you started:: * * @throws UsernameNotFoundException if the user is not found */ - public function loadUserByUsername($username) + public function loadUserByUsername(string $username) { // Load a User object from your data source or throw UsernameNotFoundException. // The $username argument may not actually be a username: @@ -412,7 +412,7 @@ command will generate a nice skeleton to get you started:: /** * Tells Symfony to use this provider for this User class. */ - public function supportsClass($class) + public function supportsClass(string $class) { return User::class === $class || is_subclass_of($class, User::class); } diff --git a/serializer/custom_encoders.rst b/serializer/custom_encoders.rst index 5bb78def4e4..e6bae859336 100644 --- a/serializer/custom_encoders.rst +++ b/serializer/custom_encoders.rst @@ -27,22 +27,22 @@ create your own encoder that uses the class YamlEncoder implements EncoderInterface, DecoderInterface { - public function encode($data, $format, array $context = []) + public function encode($data, string $format, array $context = []) { return Yaml::dump($data); } - public function supportsEncoding($format) + public function supportsEncoding(string $format) { return 'yaml' === $format; } - public function decode($data, $format, array $context = []) + public function decode(string $data, string $format, array $context = []) { return Yaml::parse($data); } - public function supportsDecoding($format) + public function supportsDecoding(string $format) { return 'yaml' === $format; } diff --git a/session/locale_sticky_session.rst b/session/locale_sticky_session.rst index f8caef23370..056f2a674cb 100644 --- a/session/locale_sticky_session.rst +++ b/session/locale_sticky_session.rst @@ -28,7 +28,7 @@ correct locale however you want:: { private $defaultLocale; - public function __construct($defaultLocale = 'en') + public function __construct(string $defaultLocale = 'en') { $this->defaultLocale = $defaultLocale; } From 010f62fc460e49461c5d3fb98f2aaceb636c813d Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Wed, 21 Oct 2020 15:49:46 +0200 Subject: [PATCH 0571/1519] Fix markup of configuration-block. --- routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routing.rst b/routing.rst index 53088f53a32..4588ba61cd2 100644 --- a/routing.rst +++ b/routing.rst @@ -58,7 +58,7 @@ This configuration tells Symfony to look for routes defined as annotations in any PHP class stored in the ``src/Controller/`` directory. Suppose you want to define a route for the ``/blog`` URL in your application. To -do so, create a :doc:`controller class ` like the following:: +do so, create a :doc:`controller class ` like the following: .. configuration-block:: From 0f91cc9f74a656da845b6a46b225a8351a83ccae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Tue, 20 Oct 2020 09:42:57 +0200 Subject: [PATCH 0572/1519] Add documentation for retry on idempotent methods --- http_client.rst | 8 +++++--- reference/configuration/framework.rst | 7 +++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/http_client.rst b/http_client.rst index e0a9d6808e3..5c899660b62 100644 --- a/http_client.rst +++ b/http_client.rst @@ -694,9 +694,10 @@ Retry Failed Requests Sometimes, requests fail because of network issues or temporary server errors. Symfony's HttpClient allows to retry failed requests automatically using the :ref:`retry_failed option `. When enabled, -each failed request with an HTTP status of ``423``, ``425``, ``429``, ``500``, -``502``, ``503``, ``504``, ``507``, or ``510`` is retried up to 3 times, with an -exponential delay between retries (first retry = 1 second; third retry: 4 seconds). +each failed request with an HTTP status of ``423``, ``425``, ``429``, ``502``, +``503`` or with an `idempotent method`_ and a HTTP status of ``500``, ``504``, +``507`` or ``510`` is retried up to 3 times, with an exponential delay between +retries (first retry = 1 second; third retry: 4 seconds). Check out the full list of configurable :ref:`retry_failed options ` to learn how to tweak each of them to fit your application needs. @@ -1609,3 +1610,4 @@ Then configure Symfony to use your callback: .. _`cURL options`: https://www.php.net/manual/en/function.curl-setopt.php .. _`Server-sent events`: https://html.spec.whatwg.org/multipage/server-sent-events.html .. _`EventSource`: https://www.w3.org/TR/eventsource/#eventsource +.. _`idempotent method`: https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods_and_web_applications diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index a3d6e9fd95a..b8b0a7887d6 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -779,7 +779,10 @@ will automatically retry failed HTTP requests. # ... retry_failed: # retry_strategy: app.custom_strategy - http_codes: [429, 500] + http_codes: + 0: ['GET', 'HEAD'] # retry network errors if request method is GET or HEAD + 429: true # retry all responses with 429 status code + 500: ['GET', 'HEAD'] max_retries: 2 delay: 1000 multiplier: 3 @@ -923,7 +926,7 @@ value must use the format ``['header-name' => 'value0, value1, ...']``. http_codes .......... -**type**: ``array`` **default**: ``[423, 425, 429, 500, 502, 503, 504, 507, 510]`` +**type**: ``array`` **default**: :method:`Symfony\\Component\\HttpClient\\Retry\\GenericRetryStrategy::DEFAULT_RETRY_STATUS_CODES` .. versionadded:: 5.2 From 689614433c04d186640f563d619c36adc43184c9 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 21 Oct 2020 20:14:08 +0200 Subject: [PATCH 0573/1519] Tweak --- http_client.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/http_client.rst b/http_client.rst index 5c899660b62..efc5a14e799 100644 --- a/http_client.rst +++ b/http_client.rst @@ -693,11 +693,13 @@ Retry Failed Requests Sometimes, requests fail because of network issues or temporary server errors. Symfony's HttpClient allows to retry failed requests automatically using the -:ref:`retry_failed option `. When enabled, -each failed request with an HTTP status of ``423``, ``425``, ``429``, ``502``, -``503`` or with an `idempotent method`_ and a HTTP status of ``500``, ``504``, -``507`` or ``510`` is retried up to 3 times, with an exponential delay between -retries (first retry = 1 second; third retry: 4 seconds). +:ref:`retry_failed option `. + +By default, failed requests are retried up to 3 times, with an exponential delay +between retries (first retry = 1 second; third retry: 4 seconds) and only for +the following HTTP status codes: ``423``, ``425``, ``429``, ``502`` and ``503`` +when using any HTTP method and ``500``, ``504``, ``507`` and ``510`` when using +an HTTP `idempotent method`_. Check out the full list of configurable :ref:`retry_failed options ` to learn how to tweak each of them to fit your application needs. From 9994e7b0dca329678cb7db549bbae7d256d9c7b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Wed, 21 Oct 2020 20:24:19 +0200 Subject: [PATCH 0574/1519] Use APP_RUNTIME_ENV to define secrets --- configuration/secrets.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configuration/secrets.rst b/configuration/secrets.rst index 696ce519682..ab49c052dff 100644 --- a/configuration/secrets.rst +++ b/configuration/secrets.rst @@ -48,7 +48,7 @@ running: .. code-block:: terminal - $ php bin/console secrets:generate-keys --env=prod + $ APP_RUNTIME_ENV=prod php bin/console secrets:generate-keys This will generate ``config/secrets/prod/prod.encrypt.public.php`` and ``config/secrets/prod/prod.decrypt.private.php``. @@ -78,7 +78,7 @@ Suppose you want to store your database password as a secret. By using the $ php bin/console secrets:set DATABASE_PASSWORD # set your production value - $ php bin/console secrets:set DATABASE_PASSWORD --env=prod + $ APP_RUNTIME_ENV=prod php bin/console secrets:set DATABASE_PASSWORD This will create a new file for the secret in ``config/secrets/dev`` and another in ``config/secrets/prod``. You can also set the secret in a few other ways: @@ -253,7 +253,7 @@ your secrets during deployment to the "local" vault: .. code-block:: terminal - $ php bin/console secrets:decrypt-to-local --force --env=prod + $ APP_RUNTIME_ENV=prod php bin/console secrets:decrypt-to-local --force This will write all the decrypted secrets into the ``.env.prod.local`` file. After doing this, the decryption key does *not* need to remain on the server(s). From 3781df649e39522eddbb612d452c661eb33f33d1 Mon Sep 17 00:00:00 2001 From: Guilhem Niot Date: Fri, 12 Jun 2020 13:46:50 +0200 Subject: [PATCH 0575/1519] [PropertyInfo] Document setting serializer_groups to null in the SerializerExtractor --- components/property_info.rst | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/components/property_info.rst b/components/property_info.rst index d67034b04fa..16aac3299e2 100644 --- a/components/property_info.rst +++ b/components/property_info.rst @@ -435,7 +435,18 @@ with the ``property_info`` service in the Symfony Framework:: $serializerExtractor = new SerializerExtractor($serializerClassMetadataFactory); // List information. - $serializerExtractor->getProperties($class); + $serializerExtractor->getProperties($class, ['serializer_groups' => ['mygroup']]); + +.. note:: + + The ``serializer_groups`` option must be provided in order to have a value different than ``null`` returned. + + If ``serializer_groups`` is set to ``null``, serializer groups metadata won't be checked but you will get only the properties + considered by the Serializer Component (notably the ``@Ignore`` annotation is taken into account). + +.. versionadded:: 5.2 + + Support for the ``null`` value in ``serializer_groups`` was introduced in Symfony 5.2. DoctrineExtractor ~~~~~~~~~~~~~~~~~ From d0abaf04aa169560fa7e791debbc82299991be0e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 22 Oct 2020 09:19:42 +0200 Subject: [PATCH 0576/1519] Tweaks --- components/property_info.rst | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/components/property_info.rst b/components/property_info.rst index 16aac3299e2..b6684d948d8 100644 --- a/components/property_info.rst +++ b/components/property_info.rst @@ -434,15 +434,12 @@ with the ``property_info`` service in the Symfony Framework:: ); $serializerExtractor = new SerializerExtractor($serializerClassMetadataFactory); - // List information. + // the `serializer_groups` option must be configured (may be set to null) $serializerExtractor->getProperties($class, ['serializer_groups' => ['mygroup']]); - -.. note:: - - The ``serializer_groups`` option must be provided in order to have a value different than ``null`` returned. - If ``serializer_groups`` is set to ``null``, serializer groups metadata won't be checked but you will get only the properties - considered by the Serializer Component (notably the ``@Ignore`` annotation is taken into account). +If ``serializer_groups`` is set to ``null``, serializer groups metadata won't be +checked but you will get only the properties considered by the Serializer +Component (notably the ``@Ignore`` annotation is taken into account). .. versionadded:: 5.2 From 3bc914cc2043612bfc97e1e9e7c78c95ef695e52 Mon Sep 17 00:00:00 2001 From: Rachid Hammaoui <37940572+makmaoui@users.noreply.github.com> Date: Fri, 14 Aug 2020 18:41:43 +0200 Subject: [PATCH 0577/1519] Fix wrong properties class Fix classname for query and cookies properties --- components/http_foundation.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index dad9990dd64..3a90611edbe 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -83,17 +83,19 @@ can be accessed via several public properties: Each property is a :class:`Symfony\\Component\\HttpFoundation\\ParameterBag` instance (or a sub-class of), which is a data holder class: -* ``request``: :class:`Symfony\\Component\\HttpFoundation\\ParameterBag`; +* ``request``: :class:`Symfony\\Component\\HttpFoundation\\ParameterBag` or + :class:`Symfony\\Component\\HttpFoundation\\InputBag` if the data is + coming from ``$_POST`` parameters; -* ``query``: :class:`Symfony\\Component\\HttpFoundation\\ParameterBag`; +* ``query``: :class:`Symfony\\Component\\HttpFoundation\\InputBag`; -* ``cookies``: :class:`Symfony\\Component\\HttpFoundation\\ParameterBag`; +* ``cookies``: :class:`Symfony\\Component\\HttpFoundation\\InputBag`; * ``attributes``: :class:`Symfony\\Component\\HttpFoundation\\ParameterBag`; -* ``files``: :class:`Symfony\\Component\\HttpFoundation\\FileBag`; +* ``files``: :class:`Symfony\\Component\\HttpFoundation\\FileBag`; -* ``server``: :class:`Symfony\\Component\\HttpFoundation\\ServerBag`; +* ``server``: :class:`Symfony\\Component\\HttpFoundation\\ServerBag`; * ``headers``: :class:`Symfony\\Component\\HttpFoundation\\HeaderBag`. From 9d189ef6b5e1c381923ac894ec3237ed45e620de Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 22 Oct 2020 11:23:38 +0200 Subject: [PATCH 0578/1519] [RateLimiter] Document the RateLimit object --- rate_limiter.rst | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/rate_limiter.rst b/rate_limiter.rst index 6fa7192945f..527357cc011 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -212,6 +212,50 @@ processes by reserving unused tokens. $limit->wait(); } while (!$limit->isAccepted()); +Exposing the Rate Limiter Status +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When using a rate limiter in APIs, it's common to include some standard HTTP +headers in the response to expose the limit status (e.g. remaining tokens, when +new tokens will be available, etc.) + +Use the :class:`Symfony\\Component\\RateLimiter\\RateLimit` object returned by +the ``consume()`` method (also available via the ``getRateLimit()`` method of +the :class:`Symfony\\Component\\RateLimiter\\Reservation` object returned by the +``reserve()`` method) to get the value of those HTTP headers:: + + // src/Controller/ApiController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\RateLimiter\RateLimiter; + + class ApiController extends AbstractController + { + public function index(RateLimiter $anonymousApiLimiter) + { + $limiter = $anonymousApiLimiter->create($request->getClientIp()); + $limit = $limiter->consume(); + $headers = [ + 'X-RateLimit-Remaining' => $limit->getRemainingTokens(), + 'X-RateLimit-Retry-After' => $limit->getRetryAfter()->getTimestamp(), + 'X-RateLimit-Limit' => $limit->getLimit(), + ]; + + if (false === $limit->isAccepted()) { + return new Response(null, Response::HTTP_TOO_MANY_REQUESTS, $headers); + } + + // ... + + $reponse = new Response('...'); + $response->headers->add($headers); + + return $response; + } + } + Rate Limiter Storage and Locking -------------------------------- From 809b7a0e63d9dfb743c6aaea9f6bda485bb3de2a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 22 Oct 2020 09:56:38 +0200 Subject: [PATCH 0579/1519] [Lock] Mention the priority policy of shared locks --- components/lock.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/lock.rst b/components/lock.rst index 518a01c9375..3a92184c85e 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -237,6 +237,11 @@ to acquire the lock in a blocking mode:: $lock = $factory->createLock('user'.$user->id); $lock->acquireRead(true); +.. note:: + + The `priority policy`_ of Symfony's shared locks depends on the underlying + store (e.g. Redis store prioritizes readers vs writers). + When a read-only lock is acquired with the method ``acquireRead()``, it's possible to **promote** the lock, and change it to write lock, by calling the ``acquire()`` method:: @@ -915,3 +920,4 @@ are still running. .. _`Replica Set Read and Write Semantics`: https://docs.mongodb.com/manual/applications/replication/ .. _`ZooKeeper`: https://zookeeper.apache.org/ .. _`readers–writer lock`: https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock +.. _`priority policy`: https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock#Priority_policies From 269f500c45bf4ae3654d5edb92825c9d4e0c66ae Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 22 Oct 2020 17:41:24 +0200 Subject: [PATCH 0580/1519] Added missing namespace --- security/experimental_authenticators.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index 83b3199d9ef..8a1b6081d84 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -472,6 +472,9 @@ the following badges are supported: For instance, if you want to add CSRF and password migration to your custom authenticator, you would initialize the passport like this:: + // src/Service/LoginAuthenticator.php + namespace App\Service; + // ... use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge; From e912f23b557bd56ed1c7c296f12b178f48e6dfb5 Mon Sep 17 00:00:00 2001 From: TavoNiievez <64917965+TavoNiievez@users.noreply.github.com> Date: Thu, 22 Oct 2020 13:54:00 -0500 Subject: [PATCH 0581/1519] Typo in impersonator role The correct role is 'IS_IMPERSONATOR'. --- components/security/authorization.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/security/authorization.rst b/components/security/authorization.rst index c074cf14b75..b884ce97ac0 100644 --- a/components/security/authorization.rst +++ b/components/security/authorization.rst @@ -114,12 +114,12 @@ user fully authenticated, or only based on a "remember-me" cookie, or even authenticated anonymously? It also supports the attributes ``IS_ANONYMOUS``, ``IS_REMEMBERED``, -``IS_IMPERSONATED`` to grant access based on a specific state of +``IS_IMPERSONATOR`` to grant access based on a specific state of authentication. .. versionadded:: 5.1 - The ``IS_ANONYMOUS``, ``IS_REMEMBERED`` and ``IS_IMPERSONATED`` + The ``IS_ANONYMOUS``, ``IS_REMEMBERED`` and ``IS_IMPERSONATOR`` attributes were introduced in Symfony 5.1. :: From c630bcb1739638120d1fc7bf2c62c0f14bc7ee1e Mon Sep 17 00:00:00 2001 From: Mathieu Piot Date: Fri, 17 Apr 2020 13:51:19 +0200 Subject: [PATCH 0582/1519] Add Discord notifier --- notifier.rst | 3 ++- notifier/chatters.rst | 53 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 9d0b5148553..d79933b7188 100644 --- a/notifier.rst +++ b/notifier.rst @@ -139,6 +139,7 @@ integration with these chat services: ========== ================================ =========================================================================== Service Package DSN ========== ================================ =========================================================================== +Discord ``symfony/discord-notifier`` ``discord://TOKEN@default?webhook_id=ID`` GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?threadKey=THREAD_KEY`` LinkedIn ``symfony/linked-in-notifier`` ``linkedin://TOKEN:USER_ID@default`` Mattermost ``symfony/mattermost-notifier`` ``mattermost://TOKEN@ENDPOINT?channel=CHANNEL`` @@ -156,7 +157,7 @@ Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:APIKEY@ENDPOINT?ch .. versionadded:: 5.2 - The GoogleChat, LinkedIn and Zulip integrations were introduced in Symfony 5.2. + The GoogleChat, LinkedIn, Zulip and Discord integrations were introduced in Symfony 5.2. Chatters are configured using the ``chatter_transports`` setting: diff --git a/notifier/chatters.rst b/notifier/chatters.rst index efbd040593e..b37d17c2040 100644 --- a/notifier/chatters.rst +++ b/notifier/chatters.rst @@ -99,3 +99,56 @@ some interactive options called `Block elements`_:: $chatter->send($chatMessage); .. _`Block elements`: https://api.slack.com/reference/block-kit/block-elements + +Adding Interactions to a Discord Message +-------------------------------------- + +With a Discord message, you can use the +:class:`Symfony\\Component\\Notifier\\Bridge\\Discord\\DiscordOptions` to add +some interactive options called `Embed elements`_:: + + use Symfony\Component\Notifier\Bridge\Discord\Block\DiscordEmbed; + use Symfony\Component\Notifier\Bridge\Discord\Block\DiscordFieldEmbedObject; + use Symfony\Component\Notifier\Bridge\Discord\Block\DiscordFooterEmbedObject; + use Symfony\Component\Notifier\Bridge\Discord\Block\DiscordMediaEmbedObject; + use Symfony\Component\Notifier\Bridge\Discord\DiscordOptions; + use Symfony\Component\Notifier\Message\ChatMessage; + + $chatMessage = new ChatMessage(''); + + // Create Discord Embed + $discordOptions = (new DiscordOptions()) + ->username('connor bot') + ->addEmbed((new DiscordEmbed()) + ->color(2021216) + ->title('New song added!') + ->thumbnail((new DiscordMediaEmbedObject()) + ->url('https://i.scdn.co/image/ab67616d0000b2735eb27502aa5cb1b4c9db426b')) + ->addField((new DiscordFieldEmbedObject()) + ->name('Track') + ->value('[Common Ground](https://open.spotify.com/track/36TYfGWUhIRlVjM8TxGUK6)') + ->inline(true) + ) + ->addField((new DiscordFieldEmbedObject()) + ->name('Artist') + ->value('Alasdair Fraser') + ->inline(true) + ) + ->addField((new DiscordFieldEmbedObject()) + ->name('Album') + ->value('Dawn Dance') + ->inline(true) + ) + ->footer((new DiscordFooterEmbedObject()) + ->text('Added ...') + ->iconUrl('https://upload.wikimedia.org/wikipedia/commons/thumb/1/19/Spotify_logo_without_text.svg/200px-Spotify_logo_without_text.svg.png') + ) + ) + ; + + // Add the custom options to the chat message and send the message + $chatMessage->options($discordOptions); + + $chatter->send($chatMessage); + +.. _`Embed elements`: https://discord.com/developers/docs/resources/webhook From bf6cca937f6c2e96a0e9a2deeeae0fc768b8a764 Mon Sep 17 00:00:00 2001 From: Baptiste Leduc Date: Fri, 23 Oct 2020 13:45:06 +0200 Subject: [PATCH 0583/1519] Non-standard adder/remover methods --- components/property_access.rst | 39 ++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/components/property_access.rst b/components/property_access.rst index df0f3d99b51..741d3023ad5 100644 --- a/components/property_access.rst +++ b/components/property_access.rst @@ -394,6 +394,45 @@ and ``removeChild()`` methods to access to the ``children`` property. If available, *adder* and *remover* methods have priority over a *setter* method. +Using non-standard adder/remover methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes, adder and remover methods don't use the standard ``add`` or ``remove`` prefix, like in this example:: + + // ... + class PeopleList + { + // ... + + public function joinPeople(string $people): void + { + $this->peoples[] = $people; + } + + public function leavePeople(string $people): void + { + foreach ($this->peoples as $id => $item) { + if ($people === $item) { + unset($this->peoples[$id]); + break; + } + } + } + } + + use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; + use Symfony\Component\PropertyAccess\PropertyAccessor; + + $list = new PeopleList(); + $reflectionExtractor = new ReflectionExtractor(null, null, ['join', 'leave']); + $propertyAccessor = new PropertyAccessor(false, false, null, true, $reflectionExtractor, $reflectionExtractor); + $propertyAccessor->setValue($person, 'peoples', ['kevin', 'wouter']); + + var_dump($person->getPeoples()); // ['kevin', 'wouter'] + +Instead of calling ``add()`` and ``remove()``, the PropertyAccess +component will call ``join()`` and ``leave()`` methods. + Checking Property Paths ----------------------- From 8fe20c33a49ba1bd21de5eb78477752e5c6fdd1b Mon Sep 17 00:00:00 2001 From: Toni Rudolf Date: Mon, 3 Feb 2020 17:24:10 +0100 Subject: [PATCH 0584/1519] Added redeliver_timeout and claim_interval options --- messenger.rst | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/messenger.rst b/messenger.rst index 54c7fb200a5..9917e5d7c28 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1038,9 +1038,9 @@ a running Redis server (^5.0). A number of options can be configured via the DSN or via the ``options`` key under the transport in ``messenger.yaml``: -================== ===================================== ========================= - Option Description Default -================== ===================================== ========================= +=================== ===================================== ================================= + Option Description Default +=================== ===================================== ================================= stream The Redis stream name messages group The Redis consumer group name symfony consumer Consumer name used in Redis consumer @@ -1056,7 +1056,23 @@ stream_max_entries The maximum number of entries which ``0`` (which means "n it to a large enough number to avoid losing pending messages tls Enable TLS support for the connection false -================== ===================================== ========================= +redeliver_timeout Timeout before retrying a pending ``3600`` + message which is owned by an + abandoned consumer (if a worker died + for some reason, this will occur, + eventually you should retry the + message) - in seconds. +claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) + messages should be checked for to + claim - in milliseconds +=================== ===================================== ================================= + +.. caution:: + + There should never be more than one `messenger:consume` command running with the same + config (stream, group and consumer name) to avoid having a message handled more than once. + Using the ``HOSTNAME`` as the consumer might often be a good idea. In case you are using + Kubernetes to orchestrate your containers, consider using a ``StatefulSet``. .. tip:: From d6988a76ee403c23382fd420dd60dcc69fb083f3 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Fri, 23 Oct 2020 15:05:47 +0200 Subject: [PATCH 0585/1519] [#12976] Minor syntax fix --- messenger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index 9917e5d7c28..78d09d50e9a 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1069,7 +1069,7 @@ claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) .. caution:: - There should never be more than one `messenger:consume` command running with the same + There should never be more than one ``messenger:consume`` command running with the same config (stream, group and consumer name) to avoid having a message handled more than once. Using the ``HOSTNAME`` as the consumer might often be a good idea. In case you are using Kubernetes to orchestrate your containers, consider using a ``StatefulSet``. From 08496685d725a48630e0a019e11188cd1c7c1c91 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Fri, 23 Oct 2020 15:08:55 +0200 Subject: [PATCH 0586/1519] [#12976] Added the new options to the versionadded directive --- messenger.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index 78d09d50e9a..3dce638cd70 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1083,7 +1083,8 @@ claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) .. versionadded:: 5.1 - The ``delete_after_ack`` option was introduced in Symfony 5.1. + The ``delete_after_ack``, ``redeliver_timeout`` and ``claim_interval`` + options were introduced in Symfony 5.1. In Memory Transport ~~~~~~~~~~~~~~~~~~~ From f79b26828e2bed575c0fbecf3860b9893103efe4 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Fri, 23 Oct 2020 15:14:37 +0200 Subject: [PATCH 0587/1519] Syntax fix --- notifier/chatters.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier/chatters.rst b/notifier/chatters.rst index b37d17c2040..9d03f83987c 100644 --- a/notifier/chatters.rst +++ b/notifier/chatters.rst @@ -101,7 +101,7 @@ some interactive options called `Block elements`_:: .. _`Block elements`: https://api.slack.com/reference/block-kit/block-elements Adding Interactions to a Discord Message --------------------------------------- +---------------------------------------- With a Discord message, you can use the :class:`Symfony\\Component\\Notifier\\Bridge\\Discord\\DiscordOptions` to add From 55a6ad049d3c17b4a9c651aa5ecdf4dab5bec5c2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 23 Oct 2020 15:24:54 +0200 Subject: [PATCH 0588/1519] Fixed a syntax issue --- messenger.rst | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/messenger.rst b/messenger.rst index f2c2a8b65be..7f74be71dd6 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1160,21 +1160,21 @@ under the transport in ``messenger.yaml``: =================== ===================================== ================================= Option Description Default =================== ===================================== ================================= -stream The Redis stream name messages -group The Redis consumer group name symfony -consumer Consumer name used in Redis consumer -auto_setup Create the Redis group automatically? true -auth The Redis password -delete_after_ack If ``true``, messages are deleted false - automatically after processing them -serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` - in Redis (the - ``Redis::OPT_SERIALIZER`` option) -stream_max_entries The maximum number of entries which ``0`` (which means "no trimming") - the stream will be trimmed to. Set - it to a large enough number to - avoid losing pending messages -tls Enable TLS support for the connection false +stream The Redis stream name messages +group The Redis consumer group name symfony +consumer Consumer name used in Redis consumer +auto_setup Create the Redis group automatically? true +auth The Redis password +delete_after_ack If ``true``, messages are deleted false + automatically after processing them +serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` + in Redis (the + ``Redis::OPT_SERIALIZER`` option) +stream_max_entries The maximum number of entries which ``0`` (which means "no trimming") + the stream will be trimmed to. Set + it to a large enough number to + avoid losing pending messages +tls Enable TLS support for the connection false redeliver_timeout Timeout before retrying a pending ``3600`` message which is owned by an abandoned consumer (if a worker died From 85b27e554a7e9b6a26e3358f51ca933eee90fec3 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Fri, 23 Oct 2020 13:46:16 +0200 Subject: [PATCH 0589/1519] [Messenger] Added Lazy option to redis --- messenger.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index 7f74be71dd6..6c2f2e35794 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1167,6 +1167,10 @@ auto_setup Create the Redis group automatically? true auth The Redis password delete_after_ack If ``true``, messages are deleted false automatically after processing them +delete_after_reject If ``true``, messages are deleted true + automatically if they are rejected +lazy Connect only when a connection is false + really needed serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` in Redis (the ``Redis::OPT_SERIALIZER`` option) @@ -1207,7 +1211,7 @@ claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) .. versionadded:: 5.2 - The ``delete_after_reject`` option was introduced in Symfony 5.2. + The ``delete_after_reject`` and ``lazy`` options were introduced in Symfony 5.2. In Memory Transport ~~~~~~~~~~~~~~~~~~~ From 2fcc6fe060af8fcdb7d7010130e535e548a6d919 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 25 Oct 2020 16:37:19 +0100 Subject: [PATCH 0590/1519] [RateLimit] Make sure we mention policy instead of limit --- rate_limiter.rst | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index 527357cc011..22a56168498 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -16,11 +16,11 @@ Symfony uses these rate limiters in built-in features like "login throttling", which limits how many failed login attempts a user can make in a given period of time, but you can use them for your own features too. -Rate Limiting Strategies ------------------------- +Rate Limiting Policies +---------------------- -Symfony's rate limiter implements some of the most common strategies to enforce -rate limits: **fixed window**, **sliding window** and **token bucket**. +Symfony's rate limiter implements some of the most common policies to enforce +rate limits: **fixed window**, **sliding window**, **token bucket**. Fixed Window Rate Limiter ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -86,12 +86,12 @@ enforce different levels of service (free or paid): framework: rate_limiter: anonymous_api: - # use 'sliding_window' if you prefer that strategy - strategy: 'fixed_window' + # use 'sliding_window' if you prefer that policy + policy: 'fixed_window' limit: 100 interval: '60 minutes' authenticated_api: - strategy: 'token_bucket' + policy: 'token_bucket' limit: 5000 rate: { interval: '15 minutes', amount: 500 } @@ -124,13 +124,13 @@ the number of requests to the API:: use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; - use Symfony\Component\RateLimiter\RateLimiter; + use Symfony\Component\RateLimiter\RateLimiterFactory; class ApiController extends AbstractController { // if you're using service autowiring, the variable name must be: // "rate limiter name" (in camelCase) + "limiter" suffix - public function index(RateLimiter $anonymousApiLimiter) + public function index(RateLimiterFactory $anonymousApiLimiter) { // create a limiter based on a unique identifier of the client // (e.g. the client's IP address, a username/email, an API key, etc.) @@ -171,11 +171,11 @@ using the ``reserve()`` method:: use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\RateLimiter\RateLimiter; + use Symfony\Component\RateLimiter\RateLimiterFactory; class ApiController extends AbstractController { - public function registerUser(Request $request, RateLimiter $authenticatedApiLimiter) + public function registerUser(Request $request, RateLimiterFactory $authenticatedApiLimiter) { $apiKey = $request->headers->get('apikey'); $limiter = $authenticatedApiLimiter->create($apiKey); @@ -229,11 +229,11 @@ the :class:`Symfony\\Component\\RateLimiter\\Reservation` object returned by the use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\RateLimiter\RateLimiter; + use Symfony\Component\RateLimiter\RateLimiterFactory; class ApiController extends AbstractController { - public function index(RateLimiter $anonymousApiLimiter) + public function index(RateLimiterFactory $anonymousApiLimiter) { $limiter = $anonymousApiLimiter->create($request->getClientIp()); $limit = $limiter->consume(); From 3e0c21cc3eb8b8ed493b982a2c0c3cc77afb76aa Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 25 Oct 2020 16:39:18 +0100 Subject: [PATCH 0591/1519] Update wrong use statement --- translation.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/translation.rst b/translation.rst index cb774e70f7a..4c4b4b9a07b 100644 --- a/translation.rst +++ b/translation.rst @@ -307,16 +307,16 @@ parts of your application and mocking it in your tests. Instead of translating a string at the time of creation, you can use a "translatable object", which is an instance of the -:class:`Symfony\\Component\\Translation\\Translatable` class. This object stores +:class:`Symfony\\Component\\Translation\\TranslatableMessage` class. This object stores all the information needed to fully translate its contents when needed:: - use Symfony\Component\Translation\Translatable; + use Symfony\Component\Translation\TranslatableMessage; // the first argument is required and it's the original message - $message = new Translatable('Symfony is great!'); + $message = new TranslatableMessage('Symfony is great!'); // the optional second argument defines the translation parameters and // the optional third argument is the translation domain - $status = new Translatable('order.status', ['%status%' => $order->getStatus()], 'store'); + $status = new TranslatableMessage('order.status', ['%status%' => $order->getStatus()], 'store'); Templates are now much simpler because you can pass translatable objects to the ``trans`` filter: From 464904fa2d95fca3f3759e9c61162d1d5d2579ef Mon Sep 17 00:00:00 2001 From: Francois CONTE Date: Sat, 24 Oct 2020 22:20:51 +0200 Subject: [PATCH 0592/1519] [Security] Update examples of Login Link --- security/login_link.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/login_link.rst b/security/login_link.rst index 3db4f34f8eb..b92dd694178 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -253,7 +253,7 @@ number:: 'Welcome to MY WEBSITE!' // email subject ); // create a recipient for this user - $recipient = (new Recipient())->email($user->getEmail()); + $recipient = new Recipient($user->getEmail()); // send the notification to the user $notifier->send($notification, $recipient); @@ -620,7 +620,7 @@ user create this POST request (e.g. by clicking a button):: /** * @Route("/login_check", name="login_check") */ - public function check() + public function check(Request $request) { // get the login link query parameters $expires = $request->query->get('expires'); From 1776c69a192042c6999fafc629a88f3c5d646ad0 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sun, 25 Oct 2020 23:53:32 +0100 Subject: [PATCH 0593/1519] [DependencyInjection] Fix markup of configuration-block --- service_container/autowiring.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service_container/autowiring.rst b/service_container/autowiring.rst index 4a2b606c538..e62f75f7513 100644 --- a/service_container/autowiring.rst +++ b/service_container/autowiring.rst @@ -609,7 +609,7 @@ you can use the ``@required`` annotation instead. Despite property injection has some :ref:`drawbacks `, autowiring with ``#[Required]`` or ``@required`` can also be applied to public -typed properties:: +typed properties: .. configuration-block:: From 5094d7f5e59a75b48279925822d58e16d538cb7d Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 26 Oct 2020 11:50:23 +0100 Subject: [PATCH 0594/1519] Fixed table margin --- messenger.rst | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/messenger.rst b/messenger.rst index 3dce638cd70..e9253431bd4 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1041,21 +1041,21 @@ under the transport in ``messenger.yaml``: =================== ===================================== ================================= Option Description Default =================== ===================================== ================================= -stream The Redis stream name messages -group The Redis consumer group name symfony -consumer Consumer name used in Redis consumer -auto_setup Create the Redis group automatically? true -auth The Redis password -delete_after_ack If ``true``, messages are deleted false - automatically after processing them -serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` - in Redis (the - ``Redis::OPT_SERIALIZER`` option) -stream_max_entries The maximum number of entries which ``0`` (which means "no trimming") - the stream will be trimmed to. Set - it to a large enough number to - avoid losing pending messages -tls Enable TLS support for the connection false +stream The Redis stream name messages +group The Redis consumer group name symfony +consumer Consumer name used in Redis consumer +auto_setup Create the Redis group automatically? true +auth The Redis password +delete_after_ack If ``true``, messages are deleted false + automatically after processing them +serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` + in Redis (the + ``Redis::OPT_SERIALIZER`` option) +stream_max_entries The maximum number of entries which ``0`` (which means "no trimming") + the stream will be trimmed to. Set + it to a large enough number to + avoid losing pending messages +tls Enable TLS support for the connection false redeliver_timeout Timeout before retrying a pending ``3600`` message which is owned by an abandoned consumer (if a worker died From 5a36f03d309624c8dd2d251d9db5a0c666e7c7df Mon Sep 17 00:00:00 2001 From: Wouter J Date: Fri, 30 Oct 2020 10:39:54 +0100 Subject: [PATCH 0595/1519] Fixed code block rendering --- components/process.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/process.rst b/components/process.rst index 8664ddead85..f89935036f1 100644 --- a/components/process.rst +++ b/components/process.rst @@ -394,7 +394,7 @@ Using a Prepared Command Line You can run a process by using a prepared command line with double quote variable notation. This allows you to use placeholders so that only the -parameterized values can be changed, but not the rest of the script: +parameterized values can be changed, but not the rest of the script:: use Symfony\Component\Process\Process; From 64058aa3c6a3da18112ac9d92e638137490783c0 Mon Sep 17 00:00:00 2001 From: freezy Date: Wed, 28 Oct 2020 14:15:13 +0100 Subject: [PATCH 0596/1519] Mention supported hex colors --- console/coloring.rst | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/console/coloring.rst b/console/coloring.rst index 3684d71709d..913805b5cea 100644 --- a/console/coloring.rst +++ b/console/coloring.rst @@ -40,13 +40,22 @@ It is possible to define your own styles using the use Symfony\Component\Console\Formatter\OutputFormatterStyle; // ... - $outputStyle = new OutputFormatterStyle('red', 'yellow', ['bold', 'blink']); + $outputStyle = new OutputFormatterStyle('red', '#ff0', ['bold', 'blink']); $output->getFormatter()->setStyle('fire', $outputStyle); $output->writeln('foo'); -Available foreground and background colors are: ``black``, ``red``, ``green``, -``yellow``, ``blue``, ``magenta``, ``cyan`` and ``white``. +Any hex color is supported for foreground and background colors. Besides that, these named colors are supported: +``black``, ``red``, ``green``, ``yellow``, ``blue``, ``magenta``, ``cyan`` and ``white``. + +.. versionadded:: 5.2 + + True (hex) color support was introduced in Symfony 5.2 + +.. note:: + + If the terminal doesn't support true colors, the nearest named color is used. + E.g. ``#c0392b`` is degraded to ``red`` or ``#f1c40f`` is degraded to ``yellow``. And available options are: ``bold``, ``underscore``, ``blink``, ``reverse`` (enables the "reverse video" mode where the background and foreground colors @@ -59,6 +68,9 @@ You can also set these colors and options directly inside the tag name:: // green text $output->writeln('foo'); + // red text + $output->writeln('foo'); + // black text on a cyan background $output->writeln('foo'); From dbed899b608229706ed88b84fb36d5e7a7ba7da1 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 25 Oct 2020 16:42:30 +0100 Subject: [PATCH 0597/1519] [Notifier][Discord] Use correct use statements --- notifier/chatters.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/notifier/chatters.rst b/notifier/chatters.rst index 9d03f83987c..7fe42a02f67 100644 --- a/notifier/chatters.rst +++ b/notifier/chatters.rst @@ -107,11 +107,11 @@ With a Discord message, you can use the :class:`Symfony\\Component\\Notifier\\Bridge\\Discord\\DiscordOptions` to add some interactive options called `Embed elements`_:: - use Symfony\Component\Notifier\Bridge\Discord\Block\DiscordEmbed; - use Symfony\Component\Notifier\Bridge\Discord\Block\DiscordFieldEmbedObject; - use Symfony\Component\Notifier\Bridge\Discord\Block\DiscordFooterEmbedObject; - use Symfony\Component\Notifier\Bridge\Discord\Block\DiscordMediaEmbedObject; use Symfony\Component\Notifier\Bridge\Discord\DiscordOptions; + use Symfony\Component\Notifier\Bridge\Discord\Embeds\DiscordEmbed; + use Symfony\Component\Notifier\Bridge\Discord\Embeds\DiscordFieldEmbedObject; + use Symfony\Component\Notifier\Bridge\Discord\Embeds\DiscordFooterEmbedObject; + use Symfony\Component\Notifier\Bridge\Discord\Embeds\DiscordMediaEmbedObject; use Symfony\Component\Notifier\Message\ChatMessage; $chatMessage = new ChatMessage(''); From 447065dc4fe6fb83fd658bf4ea1bd10c65821d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Wed, 4 Nov 2020 10:03:11 +0100 Subject: [PATCH 0598/1519] Add documentation about GetQueueUrl and DSN format in SQS transport --- messenger.rst | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/messenger.rst b/messenger.rst index 6c2f2e35794..2e41a0ca86f 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1300,7 +1300,7 @@ Amazon SQS .. versionadded:: 5.1 - The Amazon SQS transport as introduced in Symfony 5.1. + The Amazon SQS transport has been introduced in Symfony 5.1. The Amazon SQS transport is perfect for application hosted on AWS. Install it by running: @@ -1314,7 +1314,7 @@ The SQS transport DSN may looks like this: .. code-block:: env # .env - MESSENGER_TRANSPORT_DSN=sqs://AKIAIOSFODNN7EXAMPLE:j17M97ffSVoKI0briFoo9a@sqs.eu-west-3.amazonaws.com/messages + MESSENGER_TRANSPORT_DSN=https://AKIAIOSFODNN7EXAMPLE:j17M97ffSVoKI0briFoo9a@sqs.eu-west-3.amazonaws.com/123456789012/messages MESSENGER_TRANSPORT_DSN=sqs://localhost:9494/messages?sslmode=disable .. note:: @@ -1322,6 +1322,17 @@ The SQS transport DSN may looks like this: The transport will automatically create queues that are needed. This can be disabled setting the ``auto_setup`` option to ``false``. +.. tip:: + + Before sending or receiving a message, Symfony needs to convert the queue + name into an AWS queue URL by calling the ``GetQueueUrl`` API in AWS. This + extra API call can be avoided by providing a DSN which is the queue URL. + +.. versionadded:: 5.2 + + Providing a DSN equals to the queue URL to avoid call to ``GetQueueUrl`` + has been introduced in Symfony 5.2. + The transport has a number of options: ====================== ====================================== =================================== From 2a48c4410f659638d42c51c0e8388cfe7a177030 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 5 Nov 2020 10:26:53 +0100 Subject: [PATCH 0599/1519] Tweaks --- messenger.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/messenger.rst b/messenger.rst index 2e41a0ca86f..ac07b40c624 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1300,7 +1300,7 @@ Amazon SQS .. versionadded:: 5.1 - The Amazon SQS transport has been introduced in Symfony 5.1. + The Amazon SQS transport was introduced in Symfony 5.1. The Amazon SQS transport is perfect for application hosted on AWS. Install it by running: @@ -1328,10 +1328,9 @@ The SQS transport DSN may looks like this: name into an AWS queue URL by calling the ``GetQueueUrl`` API in AWS. This extra API call can be avoided by providing a DSN which is the queue URL. -.. versionadded:: 5.2 + .. versionadded:: 5.2 - Providing a DSN equals to the queue URL to avoid call to ``GetQueueUrl`` - has been introduced in Symfony 5.2. + The feature to provide the queue URL in the DSN was introduced in Symfony 5.2. The transport has a number of options: From 4bdab6fb8fc7f06eb05b3c5141a1ed415b1b035c Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER Date: Sun, 3 May 2020 21:36:09 +0200 Subject: [PATCH 0600/1519] Add wither behavior with PHP8 static return type --- service_container/calls.rst | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/service_container/calls.rst b/service_container/calls.rst index 11dea241613..8496caa724a 100644 --- a/service_container/calls.rst +++ b/service_container/calls.rst @@ -90,9 +90,6 @@ instead of mutating the object they were called on:: { private $logger; - /** - * @return static - */ public function withLogger(LoggerInterface $logger) { $new = clone $this; @@ -146,3 +143,19 @@ The configuration to tell the container it should do so would be like: $container->register(MessageGenerator::class) ->addMethodCall('withLogger', [new Reference('logger')], true); + +If autowire is enabled, you can also use annotations; with the previous exemple it would be:: + + /** + * @required + * @return static + */ + public function withLogger(LoggerInterface $logger) + { + $new = clone $this; + $new->logger = $logger; + + return $new; + } + +You can also leverage the PHP8 ``static`` return type instead of the ``@return static`` annotation. Note if you don't want a method with a PHP8 ``static`` return type and a ``@required`` annotation to behave as a wither, you can add a ``@return $this`` annotation to disable the *returns clone* feature. From 281d758f331081bf27e6046958169474b5bff53c Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Thu, 5 Nov 2020 16:12:49 +0100 Subject: [PATCH 0601/1519] [#13619] Moved text into a note and added versionadded --- service_container/calls.rst | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/service_container/calls.rst b/service_container/calls.rst index 8496caa724a..7f12a38ac4c 100644 --- a/service_container/calls.rst +++ b/service_container/calls.rst @@ -144,18 +144,30 @@ The configuration to tell the container it should do so would be like: $container->register(MessageGenerator::class) ->addMethodCall('withLogger', [new Reference('logger')], true); -If autowire is enabled, you can also use annotations; with the previous exemple it would be:: +.. tip:: - /** - * @required - * @return static - */ - public function withLogger(LoggerInterface $logger) - { - $new = clone $this; - $new->logger = $logger; + If autowire is enabled, you can also use annotations; with the previous + example it would be:: - return $new; - } + /** + * @required + * @return static + */ + public function withLogger(LoggerInterface $logger) + { + $new = clone $this; + $new->logger = $logger; + + return $new; + } + + You can also leverage the PHP 8 ``static`` return type instead of the + ``@return static`` annotation. If you don't want a method with a + PHP 8 ``static`` return type and a ``@required`` annotation to behave as + a wither, you can add a ``@return $this`` annotation to disable the + *returns clone* feature. + + .. versionadded:: 5.1 -You can also leverage the PHP8 ``static`` return type instead of the ``@return static`` annotation. Note if you don't want a method with a PHP8 ``static`` return type and a ``@required`` annotation to behave as a wither, you can add a ``@return $this`` annotation to disable the *returns clone* feature. + Support for the PHP 8 ``static`` return type was introduced in + Symfony 5.1. From adf1978d322bcf2977cdc7c5c8ce01a4b5402886 Mon Sep 17 00:00:00 2001 From: Maarten de Keizer Date: Sun, 8 Nov 2020 10:08:32 +0100 Subject: [PATCH 0602/1519] Correct case of suffix in example rate limiter The suffix should be with an uppercase (`limiter` -> `Limiter) --- rate_limiter.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index 22a56168498..f5473607fe7 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -129,7 +129,7 @@ the number of requests to the API:: class ApiController extends AbstractController { // if you're using service autowiring, the variable name must be: - // "rate limiter name" (in camelCase) + "limiter" suffix + // "rate limiter name" (in camelCase) + "Limiter" suffix public function index(RateLimiterFactory $anonymousApiLimiter) { // create a limiter based on a unique identifier of the client From bdbd7a697ea722e4a5e076b590d52e4472f06521 Mon Sep 17 00:00:00 2001 From: Yoann Chocteau Date: Mon, 9 Nov 2020 09:28:21 +0100 Subject: [PATCH 0603/1519] Update simple-example.rst Just a little typo, now we use ./styles and not ../css --- frontend/encore/simple-example.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/encore/simple-example.rst b/frontend/encore/simple-example.rst index 3d38686ce05..d0ed86a5922 100644 --- a/frontend/encore/simple-example.rst +++ b/frontend/encore/simple-example.rst @@ -17,7 +17,7 @@ application: it will *require* all of the dependencies it needs (e.g. jQuery or // assets/app.js // ... - import '../css/app.css'; + import './styles/app.css'; // var $ = require('jquery'); From cca746686382f80f3a9307915d92669e9c3c6d5e Mon Sep 17 00:00:00 2001 From: Romain Monteil Date: Thu, 5 Nov 2020 15:18:19 +0100 Subject: [PATCH 0604/1519] [Encore] Fix CSS path --- frontend/encore/installation.rst | 2 +- frontend/encore/simple-example.rst | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/encore/installation.rst b/frontend/encore/installation.rst index 8241dbcd0b2..bbd6469a1c3 100644 --- a/frontend/encore/installation.rst +++ b/frontend/encore/installation.rst @@ -143,7 +143,7 @@ Next, open the new ``assets/app.js`` file which contains some JavaScript code */ // any CSS you import will output into a single css file (app.css in this case) - import '../css/app.css'; + import './styles/app.css'; // Need jQuery? Install it with "yarn add jquery", then uncomment to import it. // import $ from 'jquery'; diff --git a/frontend/encore/simple-example.rst b/frontend/encore/simple-example.rst index d0ed86a5922..23c215b1105 100644 --- a/frontend/encore/simple-example.rst +++ b/frontend/encore/simple-example.rst @@ -19,7 +19,7 @@ application: it will *require* all of the dependencies it needs (e.g. jQuery or import './styles/app.css'; - // var $ = require('jquery'); + // import $ from 'jquery'; Encore's job (via Webpack) is simple: to read and follow *all* of the ``require()`` statements and create one final ``app.js`` (and ``app.css``) that contains *everything* @@ -204,8 +204,8 @@ To import values, use ``import``: .. code-block:: diff // assets/app.js - - require('../css/app.css'); - + import '../css/app.css'; + - require('../styles/app.css'); + + import './styles/app.css'; - var $ = require('jquery'); + import $ from 'jquery'; @@ -292,8 +292,8 @@ file to ``app.scss`` and update the ``import`` statement: .. code-block:: diff // assets/app.js - - import '../css/app.css'; - + import '../css/app.scss'; + - import './styles/app.css'; + + import './styles/app.scss'; Then, tell Encore to enable the Sass pre-processor: From 2c0cad0155fe7ec66b5f853388e40d6acb149b22 Mon Sep 17 00:00:00 2001 From: Youssef Benhssaien Date: Wed, 11 Nov 2020 08:34:42 +0100 Subject: [PATCH 0605/1519] Use int type instead integer Uses the same type hint `int` for all the page Used in `optimizations` config --- reference/configuration/twig.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst index e00d7f63958..055568b1f2e 100644 --- a/reference/configuration/twig.rst +++ b/reference/configuration/twig.rst @@ -269,7 +269,7 @@ every ``number_format`` filter call. decimals ........ -**type**: ``integer`` **default**: ``0`` +**type**: ``int`` **default**: ``0`` The number of decimals used to format numeric values when no specific number is passed as argument to the ``number_format`` filter. From 71b3d30cbc50f750479a4afce29148cb6f64f90e Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 12 Nov 2020 10:00:04 +0100 Subject: [PATCH 0606/1519] Minor: Fix namespace --- mailer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mailer.rst b/mailer.rst index a932050c049..dffbd25b3ed 100644 --- a/mailer.rst +++ b/mailer.rst @@ -605,7 +605,7 @@ arguments to the filter: .. code-block:: html+twig - {% apply inline_css(source('@css/email.css')) %} + {% apply inline_css(source('@styles/email.css')) %}

Welcome {{ username }}!

{# ... #} {% endapply %} From fc220753a708416e2f007f9317bae266b0ffee2e Mon Sep 17 00:00:00 2001 From: Youssef Benhssaien Date: Thu, 12 Nov 2020 12:04:48 +0100 Subject: [PATCH 0607/1519] Use integer typehint instead int --- reference/configuration/twig.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst index 055568b1f2e..100d168b792 100644 --- a/reference/configuration/twig.rst +++ b/reference/configuration/twig.rst @@ -269,7 +269,7 @@ every ``number_format`` filter call. decimals ........ -**type**: ``int`` **default**: ``0`` +**type**: ``integer`` **default**: ``0`` The number of decimals used to format numeric values when no specific number is passed as argument to the ``number_format`` filter. @@ -294,7 +294,7 @@ no specific character is passed as argument to the ``number_format`` filter. optimizations ~~~~~~~~~~~~~ -**type**: ``int`` **default**: ``-1`` +**type**: ``integer`` **default**: ``-1`` Twig includes an extension called ``optimizer`` which is enabled by default in Symfony applications. This extension analyzes the templates to optimize them From 120290daedd1f928c7c78d781d3911f4d754a60f Mon Sep 17 00:00:00 2001 From: Youssef BENHSSAIEN Date: Thu, 12 Nov 2020 14:16:44 +0100 Subject: [PATCH 0608/1519] Replace bool by boolean --- reference/configuration/framework.rst | 4 ++-- reference/constraints/AtLeastOneOf.rst | 2 +- reference/constraints/Hostname.rst | 2 +- reference/constraints/NotBlank.rst | 2 +- reference/constraints/Traverse.rst | 2 +- reference/forms/types/color.rst | 2 +- reference/forms/types/options/help_html.rst.inc | 2 +- reference/forms/types/options/label_html.rst.inc | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index d4058e76c82..c353f73f163 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -801,7 +801,7 @@ outgoing network interface. buffer ...... -**type**: ``bool`` | ``Closure`` +**type**: ``boolean`` | ``Closure`` Buffering the response means that you can access its content multiple times without performing the request again. Buffering is enabled by default when the @@ -2851,7 +2851,7 @@ Name of the workflow you want to create. audit_trail """"""""""" -**type**: ``bool`` +**type**: ``boolean`` If set to ``true``, the :class:`Symfony\\Component\\Workflow\\EventListener\\AuditTrailListener` will be enabled. diff --git a/reference/constraints/AtLeastOneOf.rst b/reference/constraints/AtLeastOneOf.rst index 6a48c44a4fd..b69894184d6 100644 --- a/reference/constraints/AtLeastOneOf.rst +++ b/reference/constraints/AtLeastOneOf.rst @@ -163,7 +163,7 @@ has to be satisfied in order for the validation to succeed. includeInternalMessages ~~~~~~~~~~~~~~~~~~~~~~~ -**type**: ``bool`` **default**: ``true`` +**type**: ``boolean`` **default**: ``true`` If set to ``true``, the message that is shown if the validation fails, will include the list of messages for the internal constraints. See option diff --git a/reference/constraints/Hostname.rst b/reference/constraints/Hostname.rst index 4cbe606ccb4..a08425f5fa2 100644 --- a/reference/constraints/Hostname.rst +++ b/reference/constraints/Hostname.rst @@ -117,7 +117,7 @@ Parameter Description ``requireTld`` ~~~~~~~~~~~~~~ -**type**: ``bool`` **default**: ``true`` +**type**: ``boolean`` **default**: ``true`` By default, hostnames are considered valid only when they are fully qualified and include their TLDs (top-level domain names). For instance, ``example.com`` diff --git a/reference/constraints/NotBlank.rst b/reference/constraints/NotBlank.rst index c3c16f21eae..a87b8696824 100644 --- a/reference/constraints/NotBlank.rst +++ b/reference/constraints/NotBlank.rst @@ -85,7 +85,7 @@ Options allowNull ~~~~~~~~~ -**type**: ``bool`` **default**: ``false`` +**type**: ``boolean`` **default**: ``false`` If set to ``true``, ``null`` values are considered valid and won't trigger a constraint violation. diff --git a/reference/constraints/Traverse.rst b/reference/constraints/Traverse.rst index 852f17cdd01..aea7e051ee1 100644 --- a/reference/constraints/Traverse.rst +++ b/reference/constraints/Traverse.rst @@ -146,7 +146,7 @@ The ``groups`` option is not available for this constraint. ``traverse`` ~~~~~~~~~~~~ -**type**: ``bool`` **default**: ``true`` +**type**: ``boolean`` **default**: ``true`` Instances of ``\Traversable`` are traversed by default, use this option to disable validating: diff --git a/reference/forms/types/color.rst b/reference/forms/types/color.rst index a290b31e673..5dfd61915ce 100644 --- a/reference/forms/types/color.rst +++ b/reference/forms/types/color.rst @@ -49,7 +49,7 @@ Field Options html5 ~~~~~ -**type**: ``bool`` **default**: ``false`` +**type**: ``boolean`` **default**: ``false`` .. versionadded:: 5.1 diff --git a/reference/forms/types/options/help_html.rst.inc b/reference/forms/types/options/help_html.rst.inc index 83bbe583ca6..2a5dccfb32e 100644 --- a/reference/forms/types/options/help_html.rst.inc +++ b/reference/forms/types/options/help_html.rst.inc @@ -1,7 +1,7 @@ help_html ~~~~~~~~~ -**type**: ``bool`` **default**: ``false`` +**type**: ``boolean`` **default**: ``false`` By default, the contents of the ``help`` option are escaped before rendering them in the template. Set this option to ``true`` to not escape them, which is diff --git a/reference/forms/types/options/label_html.rst.inc b/reference/forms/types/options/label_html.rst.inc index 06568ed08f4..a87ad4ab6db 100644 --- a/reference/forms/types/options/label_html.rst.inc +++ b/reference/forms/types/options/label_html.rst.inc @@ -1,7 +1,7 @@ ``label_html`` ~~~~~~~~~~~~~~ -**type**: ``bool`` **default**: ``false`` +**type**: ``boolean`` **default**: ``false`` .. versionadded:: 5.1 From df7682967fc887e516779ea015b4787728f69d6e Mon Sep 17 00:00:00 2001 From: Youssef Benhssaien Date: Wed, 11 Nov 2020 08:34:42 +0100 Subject: [PATCH 0609/1519] Use integer type instead of int & boolean instead of bool --- reference/configuration/framework.rst | 4 ++-- reference/configuration/twig.rst | 2 +- reference/constraints/AtLeastOneOf.rst | 2 +- reference/constraints/Hostname.rst | 2 +- reference/constraints/NotBlank.rst | 2 +- reference/constraints/Traverse.rst | 2 +- reference/forms/types/color.rst | 2 +- reference/forms/types/options/help_html.rst.inc | 2 +- reference/forms/types/options/label_html.rst.inc | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index d4058e76c82..c353f73f163 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -801,7 +801,7 @@ outgoing network interface. buffer ...... -**type**: ``bool`` | ``Closure`` +**type**: ``boolean`` | ``Closure`` Buffering the response means that you can access its content multiple times without performing the request again. Buffering is enabled by default when the @@ -2851,7 +2851,7 @@ Name of the workflow you want to create. audit_trail """"""""""" -**type**: ``bool`` +**type**: ``boolean`` If set to ``true``, the :class:`Symfony\\Component\\Workflow\\EventListener\\AuditTrailListener` will be enabled. diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst index e00d7f63958..100d168b792 100644 --- a/reference/configuration/twig.rst +++ b/reference/configuration/twig.rst @@ -294,7 +294,7 @@ no specific character is passed as argument to the ``number_format`` filter. optimizations ~~~~~~~~~~~~~ -**type**: ``int`` **default**: ``-1`` +**type**: ``integer`` **default**: ``-1`` Twig includes an extension called ``optimizer`` which is enabled by default in Symfony applications. This extension analyzes the templates to optimize them diff --git a/reference/constraints/AtLeastOneOf.rst b/reference/constraints/AtLeastOneOf.rst index 6a48c44a4fd..b69894184d6 100644 --- a/reference/constraints/AtLeastOneOf.rst +++ b/reference/constraints/AtLeastOneOf.rst @@ -163,7 +163,7 @@ has to be satisfied in order for the validation to succeed. includeInternalMessages ~~~~~~~~~~~~~~~~~~~~~~~ -**type**: ``bool`` **default**: ``true`` +**type**: ``boolean`` **default**: ``true`` If set to ``true``, the message that is shown if the validation fails, will include the list of messages for the internal constraints. See option diff --git a/reference/constraints/Hostname.rst b/reference/constraints/Hostname.rst index 4cbe606ccb4..a08425f5fa2 100644 --- a/reference/constraints/Hostname.rst +++ b/reference/constraints/Hostname.rst @@ -117,7 +117,7 @@ Parameter Description ``requireTld`` ~~~~~~~~~~~~~~ -**type**: ``bool`` **default**: ``true`` +**type**: ``boolean`` **default**: ``true`` By default, hostnames are considered valid only when they are fully qualified and include their TLDs (top-level domain names). For instance, ``example.com`` diff --git a/reference/constraints/NotBlank.rst b/reference/constraints/NotBlank.rst index c3c16f21eae..a87b8696824 100644 --- a/reference/constraints/NotBlank.rst +++ b/reference/constraints/NotBlank.rst @@ -85,7 +85,7 @@ Options allowNull ~~~~~~~~~ -**type**: ``bool`` **default**: ``false`` +**type**: ``boolean`` **default**: ``false`` If set to ``true``, ``null`` values are considered valid and won't trigger a constraint violation. diff --git a/reference/constraints/Traverse.rst b/reference/constraints/Traverse.rst index 852f17cdd01..aea7e051ee1 100644 --- a/reference/constraints/Traverse.rst +++ b/reference/constraints/Traverse.rst @@ -146,7 +146,7 @@ The ``groups`` option is not available for this constraint. ``traverse`` ~~~~~~~~~~~~ -**type**: ``bool`` **default**: ``true`` +**type**: ``boolean`` **default**: ``true`` Instances of ``\Traversable`` are traversed by default, use this option to disable validating: diff --git a/reference/forms/types/color.rst b/reference/forms/types/color.rst index a290b31e673..5dfd61915ce 100644 --- a/reference/forms/types/color.rst +++ b/reference/forms/types/color.rst @@ -49,7 +49,7 @@ Field Options html5 ~~~~~ -**type**: ``bool`` **default**: ``false`` +**type**: ``boolean`` **default**: ``false`` .. versionadded:: 5.1 diff --git a/reference/forms/types/options/help_html.rst.inc b/reference/forms/types/options/help_html.rst.inc index 83bbe583ca6..2a5dccfb32e 100644 --- a/reference/forms/types/options/help_html.rst.inc +++ b/reference/forms/types/options/help_html.rst.inc @@ -1,7 +1,7 @@ help_html ~~~~~~~~~ -**type**: ``bool`` **default**: ``false`` +**type**: ``boolean`` **default**: ``false`` By default, the contents of the ``help`` option are escaped before rendering them in the template. Set this option to ``true`` to not escape them, which is diff --git a/reference/forms/types/options/label_html.rst.inc b/reference/forms/types/options/label_html.rst.inc index 06568ed08f4..a87ad4ab6db 100644 --- a/reference/forms/types/options/label_html.rst.inc +++ b/reference/forms/types/options/label_html.rst.inc @@ -1,7 +1,7 @@ ``label_html`` ~~~~~~~~~~~~~~ -**type**: ``bool`` **default**: ``false`` +**type**: ``boolean`` **default**: ``false`` .. versionadded:: 5.1 From b781296cf0e084b00ee8f4f4aee78c7604c60099 Mon Sep 17 00:00:00 2001 From: wkania <57155526+wkania@users.noreply.github.com> Date: Sat, 14 Nov 2020 15:27:25 +0100 Subject: [PATCH 0610/1519] [Validator] Fix ExpressionLanguageSyntax example --- reference/constraints/ExpressionLanguageSyntax.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/reference/constraints/ExpressionLanguageSyntax.rst b/reference/constraints/ExpressionLanguageSyntax.rst index 2ca0355dfaf..18c465e8a9d 100644 --- a/reference/constraints/ExpressionLanguageSyntax.rst +++ b/reference/constraints/ExpressionLanguageSyntax.rst @@ -40,13 +40,13 @@ The following constraints ensure that: class Order { /** - * @Assert\ExpressionLanguageSyntax() + * @Assert\ExpressionLanguageSyntax */ protected $promotion; /** * @Assert\ExpressionLanguageSyntax( - * allowedVariables = ['user', 'shipping_centers'] + * allowedVariables={"user", "shipping_centers"} * ) */ protected $shippingOptions; @@ -77,7 +77,10 @@ The following constraints ensure that: - + From 3a439bddc1646c482f3f6f78894391c0153199da Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 16 Nov 2020 00:02:25 +0100 Subject: [PATCH 0611/1519] [#14011] Documented the NullToken usage --- security/experimental_authenticators.rst | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index d0813795b12..45c0edb882d 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -135,6 +135,42 @@ unauthenticated access (e.g. the login page): ], ]); +Granting Anonymous Users Access in a Custom Voter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.2 + + The ``NullToken`` class was introduced in Symfony 5.2. + +If you're using a :doc:`custom voter `, you can allow +anonymous users access by checking for a special +:class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\NullToken`. This token is used +in the voters to represent the unauthenticated access:: + + // src/Security/PostVoter.php + namespace App\Security; + + // ... + use Symfony\Component\Security\Core\Authentication\Token\NullToken; + use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + use Symfony\Component\Security\Core\Authorization\Voter\Voter; + + class PostVoter extends Voter + { + // ... + + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool + { + // ... + + if ($token instanceof NullToken) { + // the user is not authenticated, e.g. only allow them to + // see public posts + return $subject->isPublic(); + } + } + } + .. _authenticators-required-entry-point: Configuring the Authentication Entry Point From 0eae59cf1d7b3c8a02d6610127ea89115dd628dd Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 16 Nov 2020 00:12:03 +0100 Subject: [PATCH 0612/1519] Documented passport attributes --- security/experimental_authenticators.rst | 37 ++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index d0813795b12..0a713e6b0ca 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -502,3 +502,40 @@ authenticator, you would initialize the passport like this:: ]); } } + +.. tip:: + + Besides badges, passports can define attributes, which allows the + ``authenticate()`` method to store arbitrary information in the + passport to access it from other authenticator methods (e.g. + ``createAuthenticatedToken()``):: + + // ... + use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + + class LoginAuthenticator extends AbstractAuthenticator + { + // ... + + public function authenticate(Request $request): PassportInterface + { + // ... process the request + + $passport = new SelfValidatingPassport($username, []); + + // set a custom attribute (e.g. scope) + $passport->setAttribute('scope', $oauthScope); + + return $passport; + } + + public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface + { + // read the attribute value + return new CustomOauthToken($passport->getUser(), $passport->getAttribute('scope')); + } + } + +.. versionadded:: 5.2 + + Passport attributes were introduced in Symfony 5.2. From e5918146ca5fbd2d54a88965d0df26bd6880a49c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Wed, 4 Nov 2020 10:18:54 +0100 Subject: [PATCH 0613/1519] Remove deprecated HEADER_X_FORWARDED_ALL header --- deployment/proxies.rst | 12 ++++++++++-- migration.rst | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/deployment/proxies.rst b/deployment/proxies.rst index 12bf3f1cac1..a7e0aff99b2 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -35,15 +35,22 @@ and what headers your reverse proxy uses to send information:: ['192.0.0.1', '10.0.0.0/8'], // trust *all* "X-Forwarded-*" headers - Request::HEADER_X_FORWARDED_ALL + Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO // or, if your proxy instead uses the "Forwarded" header // Request::HEADER_FORWARDED - // or, if you're using AWS ELB + // or, if you're using a wellknown proxy // Request::HEADER_X_FORWARDED_AWS_ELB + // Request::HEADER_X_FORWARDED_TRAEFIK ); +.. caution:: + + Enabling the ``Request::HEADER_X_FORWARDED_HOST`` option exposes the + application to "`HTTP Host header attacks`_". Make sure the proxy really + send a ``x-forwarded-host`` header. + The Request object has several ``Request::HEADER_*`` constants that control exactly *which* headers from your reverse proxy are trusted. The argument is a bit field, so you can also pass your own value (e.g. ``0b00110``). @@ -114,3 +121,4 @@ In this case, you'll need to set the header ``X-Forwarded-Proto`` with the value .. _`security groups`: https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-groups.html .. _`CloudFront`: https://en.wikipedia.org/wiki/Amazon_CloudFront .. _`CloudFront IP ranges`: https://ip-ranges.amazonaws.com/ip-ranges.json +.. _`HTTP Host header attacks`: https://www.skeletonscribe.net/2013/05/practical-http-host-header-attacks.html diff --git a/migration.rst b/migration.rst index fa8c2bfc24b..5c786c103b9 100644 --- a/migration.rst +++ b/migration.rst @@ -262,7 +262,7 @@ could look something like this:: if ($trustedProxies = $_SERVER['TRUSTED_PROXIES'] ?? $_ENV['TRUSTED_PROXIES'] ?? false) { Request::setTrustedProxies( explode(',', $trustedProxies), - Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST + Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO ); } From 42c1ca4fe901ec3e7339f13b00ac7764f8dfada9 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 18 Nov 2020 10:54:34 +0100 Subject: [PATCH 0614/1519] Added a deprecation notice --- deployment/proxies.rst | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/deployment/proxies.rst b/deployment/proxies.rst index a7e0aff99b2..81c1f5c7826 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -40,16 +40,22 @@ and what headers your reverse proxy uses to send information:: // or, if your proxy instead uses the "Forwarded" header // Request::HEADER_FORWARDED - // or, if you're using a wellknown proxy + // or, if you're using a well-known proxy // Request::HEADER_X_FORWARDED_AWS_ELB // Request::HEADER_X_FORWARDED_TRAEFIK ); +.. deprecated:: 5.2 + + In previous Symfony versions, the above example used ``HEADER_X_FORWARDED_ALL`` + to trust all "X-Forwarded-*" headers, but that constant is deprecated since + Symfony 5.2 in favor of the individual ``HEADER_X_FORWARDED_*`` constants. + .. caution:: Enabling the ``Request::HEADER_X_FORWARDED_HOST`` option exposes the - application to "`HTTP Host header attacks`_". Make sure the proxy really - send a ``x-forwarded-host`` header. + application to `HTTP Host header attacks`_. Make sure the proxy really + sends an ``x-forwarded-host`` header. The Request object has several ``Request::HEADER_*`` constants that control exactly *which* headers from your reverse proxy are trusted. The argument is a bit field, From 163c6941e9b8cc0cc7fd2721e34b4445b86c5554 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 18 Nov 2020 11:27:44 +0100 Subject: [PATCH 0615/1519] Fixed a RST syntax issue --- deployment/proxies.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/proxies.rst b/deployment/proxies.rst index 81c1f5c7826..cae9e285648 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -48,7 +48,7 @@ and what headers your reverse proxy uses to send information:: .. deprecated:: 5.2 In previous Symfony versions, the above example used ``HEADER_X_FORWARDED_ALL`` - to trust all "X-Forwarded-*" headers, but that constant is deprecated since + to trust all "X-Forwarded-" headers, but that constant is deprecated since Symfony 5.2 in favor of the individual ``HEADER_X_FORWARDED_*`` constants. .. caution:: From 50f3ece07c22e16326616b0b420880d154bea37b Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Wed, 18 Nov 2020 17:03:01 +0100 Subject: [PATCH 0616/1519] Add little tip about PHPdocs --- messenger/multiple_buses.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/messenger/multiple_buses.rst b/messenger/multiple_buses.rst index 5136553dac2..6191bc0556c 100644 --- a/messenger/multiple_buses.rst +++ b/messenger/multiple_buses.rst @@ -249,4 +249,9 @@ You can also restrict the list to a specific bus by providing its name as argume handled by App\MessageHandler\MultipleBusesMessageHandler --------------------------------------------------------------------------------------- +.. tip:: + + Since Symfony 5.1, the command will also show the PHPDoc description of + the message and handler classes. + .. _article about CQRS: https://martinfowler.com/bliki/CQRS.html From 74de492ada02ece7221a55390825e013e3dedf42 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Thu, 19 Nov 2020 09:23:27 +0100 Subject: [PATCH 0617/1519] Fix strict_variables default value since Symfony 5 The default was changed in https://github.com/symfony/symfony/blob/494ef421c554a78b38c6779c4b7deb9a20d89923/UPGRADE-5.0.md#twigbundle --- reference/configuration/twig.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst index c7d77739b1c..5d5edd1d43c 100644 --- a/reference/configuration/twig.rst +++ b/reference/configuration/twig.rst @@ -363,7 +363,7 @@ Read more about :ref:`template directories and namespaces strict_variables ~~~~~~~~~~~~~~~~ -**type**: ``boolean`` **default**: ``false`` +**type**: ``boolean`` **default**: ``%kernel.debug%`` If set to ``true``, Symfony shows an exception whenever a Twig variable, attribute or method doesn't exist. If set to ``false`` these errors are ignored From 649a63397f9dc404294a037ef41deb48e92f3872 Mon Sep 17 00:00:00 2001 From: Timo Bakx Date: Fri, 20 Nov 2020 00:34:27 +0100 Subject: [PATCH 0618/1519] [Form] Documented legacy_error_messages --- forms.rst | 43 ++++++++++ reference/forms/types/birthday.rst | 86 ++++++++++---------- reference/forms/types/checkbox.rst | 63 ++++++++------- reference/forms/types/choice.rst | 99 ++++++++++++----------- reference/forms/types/collection.rst | 73 +++++++++-------- reference/forms/types/color.rst | 63 +++++++++------ reference/forms/types/country.rst | 85 +++++++++++--------- reference/forms/types/currency.rst | 81 ++++++++++--------- reference/forms/types/date.rst | 88 ++++++++++---------- reference/forms/types/dateinterval.rst | 94 ++++++++++++---------- reference/forms/types/datetime.rst | 106 +++++++++++++------------ reference/forms/types/email.rst | 59 ++++++++------ reference/forms/types/file.rst | 64 ++++++++------- reference/forms/types/form.rst | 94 +++++++++++----------- reference/forms/types/hidden.rst | 45 ++++++----- reference/forms/types/integer.rst | 69 ++++++++-------- reference/forms/types/language.rst | 87 ++++++++++---------- reference/forms/types/locale.rst | 83 ++++++++++--------- reference/forms/types/money.rst | 77 +++++++++--------- reference/forms/types/number.rst | 75 ++++++++--------- reference/forms/types/password.rst | 60 +++++++------- reference/forms/types/percent.rst | 75 ++++++++--------- reference/forms/types/radio.rst | 69 +++++++++------- reference/forms/types/range.rst | 57 +++++++------ reference/forms/types/repeated.rst | 63 ++++++++------- reference/forms/types/search.rst | 57 +++++++------ reference/forms/types/tel.rst | 59 ++++++++------ reference/forms/types/time.rst | 92 +++++++++++---------- reference/forms/types/timezone.rst | 85 +++++++++++--------- reference/forms/types/url.rst | 63 +++++++++------ reference/forms/types/week.rst | 74 +++++++++-------- 31 files changed, 1269 insertions(+), 1019 deletions(-) diff --git a/forms.rst b/forms.rst index ec5a04fcfc1..6e2c9ec5120 100644 --- a/forms.rst +++ b/forms.rst @@ -553,6 +553,49 @@ To see the second approach - adding constraints to the form - and to learn more about the validation constraints, please refer to the :doc:`Symfony validation documentation `. +.. versionadded:: 5.2 + + Validation messages for forms have been rewritten to be more user-friendly. + These newer messages can be enabled by setting the `legacy_error_messages` + option to "false". Details about these messages can be found in the corresponding + form type documentation. + + .. configuration-block:: + + .. code-block:: yaml + + # config/packages/framework.yaml + framework: + form: + legacy_error_messages: false + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // config/packages/framework.php + $container->loadFromExtension('framework', [ + 'form' => [ + 'legacy-error-messages' => false, + ], + ]); + + Other Common Form Features -------------------------- diff --git a/reference/forms/types/birthday.rst b/reference/forms/types/birthday.rst index 6299dbf1e09..127528bc774 100644 --- a/reference/forms/types/birthday.rst +++ b/reference/forms/types/birthday.rst @@ -14,51 +14,57 @@ This type is essentially the same as the :doc:`DateType `) | -+----------------------+-------------------------------------------------------------------------------+ -| Rendered as | can be three select boxes or 1 or 3 text boxes, based on the `widget`_ option | -+----------------------+-------------------------------------------------------------------------------+ -| Overridden options | - `years`_ | -+----------------------+-------------------------------------------------------------------------------+ -| Inherited options | from the :doc:`DateType `: | -| | | -| | - `choice_translation_domain`_ | -| | - `days`_ | -| | - `placeholder`_ | -| | - `format`_ | -| | - `input`_ | -| | - `input_format`_ | -| | - `model_timezone`_ | -| | - `months`_ | -| | - `view_timezone`_ | -| | - `widget`_ | -| | | -| | from the :doc:`FormType `: | -| | | -| | - `attr`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `inherit_data`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `mapped`_ | -| | - `row_attr`_ | -+----------------------+-------------------------------------------------------------------------------+ -| Parent type | :doc:`DateType ` | -+----------------------+-------------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\BirthdayType` | -+----------------------+-------------------------------------------------------------------------------+ ++---------------------------+-------------------------------------------------------------------------------+ +| Underlying Data Type | can be ``DateTime``, ``string``, ``timestamp``, or ``array`` | +| | (see the :ref:`input option `) | ++---------------------------+-------------------------------------------------------------------------------+ +| Rendered as | can be three select boxes or 1 or 3 text boxes, based on the `widget`_ option | ++---------------------------+-------------------------------------------------------------------------------+ +| Overridden options | - `invalid_message`_ | +| | - `years`_ | ++---------------------------+-------------------------------------------------------------------------------+ +| Inherited options | from the :doc:`DateType `: | +| | | +| | - `choice_translation_domain`_ | +| | - `days`_ | +| | - `placeholder`_ | +| | - `format`_ | +| | - `input`_ | +| | - `input_format`_ | +| | - `model_timezone`_ | +| | - `months`_ | +| | - `view_timezone`_ | +| | - `widget`_ | +| | | +| | from the :doc:`FormType `: | +| | | +| | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `inherit_data`_ | +| | - `invalid_message_parameters`_ | +| | - `mapped`_ | +| | - `row_attr`_ | ++---------------------------+-------------------------------------------------------------------------------+ +| Default `invalid_message` | Please enter a valid birthdate. | ++---------------------------+-------------------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+-------------------------------------------------------------------------------+ +| Parent type | :doc:`DateType ` | ++---------------------------+-------------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\BirthdayType` | ++---------------------------+-------------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc Overridden Options ------------------ +.. include:: /reference/forms/types/options/invalid_message.rst.inc + ``years`` ~~~~~~~~~ @@ -128,8 +134,6 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/inherit_data.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/mapped.rst.inc diff --git a/reference/forms/types/checkbox.rst b/reference/forms/types/checkbox.rst index aef03ef1e44..1463c542a1e 100644 --- a/reference/forms/types/checkbox.rst +++ b/reference/forms/types/checkbox.rst @@ -11,34 +11,39 @@ you can specify an array of values that, if submitted, will be evaluated to "false" as well (this differs from what HTTP defines, but can be handy if you want to handle submitted values like "0" or "false"). -+-------------+------------------------------------------------------------------------+ -| Rendered as | ``input`` ``checkbox`` field | -+-------------+------------------------------------------------------------------------+ -| Options | - `false_values`_ | -| | - `value`_ | -+-------------+------------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | - `empty_data`_ | -+-------------+------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CheckboxType` | -+-------------+------------------------------------------------------------------------+ ++---------------------------+------------------------------------------------------------------------+ +| Rendered as | ``input`` ``checkbox`` field | ++---------------------------+------------------------------------------------------------------------+ +| Options | - `false_values`_ | +| | - `value`_ | ++---------------------------+------------------------------------------------------------------------+ +| Overridden options | - `compound`_ | +| | - `empty_data`_ | +| | - `invalid_message`_ | ++---------------------------+------------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+------------------------------------------------------------------------+ +| Default `invalid_message` | The checkbox has an invalid value. | ++---------------------------+------------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+------------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CheckboxType` | ++---------------------------+------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -74,6 +79,8 @@ Overridden Options .. include:: /reference/forms/types/options/checkbox_empty_data.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/choice.rst b/reference/forms/types/choice.rst index 04efd2fe02c..d0c81a829bd 100644 --- a/reference/forms/types/choice.rst +++ b/reference/forms/types/choice.rst @@ -9,52 +9,57 @@ It can be rendered as a ``select`` tag, radio buttons, or checkboxes. To use this field, you must specify *either* ``choices`` or ``choice_loader`` option. -+-------------+------------------------------------------------------------------------------+ -| Rendered as | can be various tags (see below) | -+-------------+------------------------------------------------------------------------------+ -| Options | - `choices`_ | -| | - `choice_attr`_ | -| | - `choice_filter`_ | -| | - `choice_label`_ | -| | - `choice_loader`_ | -| | - `choice_name`_ | -| | - `choice_translation_domain`_ | -| | - `choice_value`_ | -| | - `expanded`_ | -| | - `group_by`_ | -| | - `multiple`_ | -| | - `placeholder`_ | -| | - `preferred_choices`_ | -+-------------+------------------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `trim`_ | -+-------------+------------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `by_reference`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `inherit_data`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `translation_domain`_ | -| | - `label_translation_parameters`_ | -| | - `attr_translation_parameters`_ | -| | - `help_translation_parameters`_ | -+-------------+------------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+------------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\ChoiceType` | -+-------------+------------------------------------------------------------------------------+ ++---------------------------+----------------------------------------------------------------------+ +| Rendered as | can be various tags (see below) | ++---------------------------+----------------------------------------------------------------------+ +| Options | - `choices`_ | +| | - `choice_attr`_ | +| | - `choice_filter`_ | +| | - `choice_label`_ | +| | - `choice_loader`_ | +| | - `choice_name`_ | +| | - `choice_translation_domain`_ | +| | - `choice_value`_ | +| | - `expanded`_ | +| | - `group_by`_ | +| | - `multiple`_ | +| | - `placeholder`_ | +| | - `preferred_choices`_ | ++---------------------------+----------------------------------------------------------------------+ +| Overridden options | - `compound`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `trim`_ | +| | - `invalid_message`_ | ++---------------------------+----------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `by_reference`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `inherit_data`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | +| | - `translation_domain`_ | +| | - `label_translation_parameters`_ | +| | - `attr_translation_parameters`_ | +| | - `help_translation_parameters`_ | ++---------------------------+----------------------------------------------------------------------+ +| Default `invalid_message` | The selected choice is invalid. | ++---------------------------+----------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+----------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\ChoiceType` | ++---------------------------+----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -272,6 +277,8 @@ the parent field (the form in most cases). .. include:: /reference/forms/types/options/choice_type_trim.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/collection.rst b/reference/forms/types/collection.rst index f3f0c8f4562..a30cc250f6f 100644 --- a/reference/forms/types/collection.rst +++ b/reference/forms/types/collection.rst @@ -11,37 +11,43 @@ forms, which is useful when creating forms that expose one-to-many relationships (e.g. a product from where you can manage many related product photos). -+-------------+-----------------------------------------------------------------------------+ -| Rendered as | depends on the `entry_type`_ option | -+-------------+-----------------------------------------------------------------------------+ -| Options | - `allow_add`_ | -| | - `allow_delete`_ | -| | - `delete_empty`_ | -| | - `entry_options`_ | -| | - `entry_type`_ | -| | - `prototype`_ | -| | - `prototype_data`_ | -| | - `prototype_name`_ | -+-------------+-----------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `by_reference`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+-----------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+-----------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CollectionType` | -+-------------+-----------------------------------------------------------------------------+ ++---------------------------+--------------------------------------------------------------------------+ +| Rendered as | depends on the `entry_type`_ option | ++---------------------------+--------------------------------------------------------------------------+ +| Options | - `allow_add`_ | +| | - `allow_delete`_ | +| | - `delete_empty`_ | +| | - `entry_options`_ | +| | - `entry_type`_ | +| | - `prototype`_ | +| | - `prototype_data`_ | +| | - `prototype_name`_ | ++---------------------------+--------------------------------------------------------------------------+ +| Overridden options | - `invalid_message`_ | ++---------------------------+--------------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `by_reference`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+--------------------------------------------------------------------------+ +| Default `invalid_message` | The collection is invalid. | ++---------------------------+--------------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+--------------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+--------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CollectionType` | ++---------------------------+--------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -396,6 +402,11 @@ If you have several collections in your form, or worse, nested collections you may want to change the placeholder so that unrelated placeholders are not replaced with the same value. +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/color.rst b/reference/forms/types/color.rst index 5dfd61915ce..f3d97c6cd1b 100644 --- a/reference/forms/types/color.rst +++ b/reference/forms/types/color.rst @@ -14,32 +14,38 @@ The value of the underlying ```` field is always a That's why it's not possible to select semi-transparent colors with this element. -+-------------+---------------------------------------------------------------------+ -| Rendered as | ``input`` ``color`` field (a text box) | -+-------------+---------------------------------------------------------------------+ -| Options | - `html5`_ | -+-------------+---------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `trim`_ | -+-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | -+-------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\ColorType` | -+-------------+---------------------------------------------------------------------+ ++---------------------------+---------------------------------------------------------------------+ +| Rendered as | ``input`` ``color`` field (a text box) | ++---------------------------+---------------------------------------------------------------------+ +| Options | - `html5`_ | ++---------------------------+---------------------------------------------------------------------+ +| Overridden options | - `invalid_message`_ | ++---------------------------+---------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | +| | - `trim`_ | ++---------------------------+---------------------------------------------------------------------+ +| Default `invalid_message` | Please select a valid color. | ++---------------------------+---------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+---------------------------------------------------------------------+ +| Parent type | :doc:`TextType ` | ++---------------------------+---------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\ColorType` | ++---------------------------+---------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -59,6 +65,11 @@ When this option is set to ``true``, the form type checks that its value matches the `HTML5 color format`_ (``/^#[0-9a-f]{6}$/i``). If it doesn't match it, you'll see the following error message: *"This value is not a valid HTML5 color"*. +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/country.rst b/reference/forms/types/country.rst index f4082e498e8..a2b1527764e 100644 --- a/reference/forms/types/country.rst +++ b/reference/forms/types/country.rst @@ -18,45 +18,50 @@ Unlike the ``ChoiceType``, you don't need to specify a ``choices`` option as the field type automatically uses all of the countries of the world. You *can* specify the option manually, but then you should just use the ``ChoiceType`` directly. -+-------------+-----------------------------------------------------------------------+ -| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | -+-------------+-----------------------------------------------------------------------+ -| Options | - `alpha3`_ | -| | - `choice_translation_locale`_ | -+-------------+-----------------------------------------------------------------------+ -| Overridden | - `choices`_ | -| options | - `choice_translation_domain`_ | -+-------------+-----------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType ` | -| options | | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `expanded`_ | -| | - `multiple`_ | -| | - `placeholder`_ | -| | - `preferred_choices`_ | -| | - `trim`_ | -| | | -| | from the :doc:`FormType ` | -| | | -| | - `attr`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+-----------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | -+-------------+-----------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CountryType` | -+-------------+-----------------------------------------------------------------------+ ++---------------------------+-----------------------------------------------------------------------+ +| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | ++---------------------------+-----------------------------------------------------------------------+ +| Options | - `alpha3`_ | +| | - `choice_translation_locale`_ | ++---------------------------+-----------------------------------------------------------------------+ +| Overridden options | - `choices`_ | +| | - `choice_translation_domain`_ | +| | - `invalid_message`_ | ++---------------------------+-----------------------------------------------------------------------+ +| Inherited options | from the :doc:`ChoiceType ` | +| | | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `expanded`_ | +| | - `multiple`_ | +| | - `placeholder`_ | +| | - `preferred_choices`_ | +| | - `trim`_ | +| | | +| | from the :doc:`FormType ` | +| | | +| | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+-----------------------------------------------------------------------+ +| Default `invalid_message` | Please select a valid country. | ++---------------------------+-----------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------+ +| Parent type | :doc:`ChoiceType ` | ++---------------------------+-----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CountryType` | ++---------------------------+-----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -92,6 +97,8 @@ The locale is used to translate the countries names. .. include:: /reference/forms/types/options/choice_translation_domain_disabled.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/currency.rst b/reference/forms/types/currency.rst index 77da0481942..e8628aa3edf 100644 --- a/reference/forms/types/currency.rst +++ b/reference/forms/types/currency.rst @@ -11,43 +11,48 @@ Unlike the ``ChoiceType``, you don't need to specify a ``choices`` option as the field type automatically uses a large list of currencies. You *can* specify the option manually, but then you should just use the ``ChoiceType`` directly. -+-------------+------------------------------------------------------------------------+ -| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | -+-------------+------------------------------------------------------------------------+ -| Options | - `choice_translation_locale`_ | -+-------------+------------------------------------------------------------------------+ -| Overridden | - `choices`_ | -| options | - `choice_translation_domain`_ | -+-------------+------------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType ` | -| options | | -| | - `error_bubbling`_ | -| | - `expanded`_ | -| | - `multiple`_ | -| | - `placeholder`_ | -| | - `preferred_choices`_ | -| | - `trim`_ | -| | | -| | from the :doc:`FormType ` type | -| | | -| | - `attr`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | -+-------------+------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CurrencyType` | -+-------------+------------------------------------------------------------------------+ ++---------------------------+------------------------------------------------------------------------+ +| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | ++---------------------------+------------------------------------------------------------------------+ +| Options | - `choice_translation_locale`_ | ++---------------------------+------------------------------------------------------------------------+ +| Overridden options | - `choices`_ | +| | - `choice_translation_domain`_ | +| | - `invalid_message`_ | ++---------------------------+------------------------------------------------------------------------+ +| Inherited options | from the :doc:`ChoiceType ` | +| | | +| | - `error_bubbling`_ | +| | - `expanded`_ | +| | - `multiple`_ | +| | - `placeholder`_ | +| | - `preferred_choices`_ | +| | - `trim`_ | +| | | +| | from the :doc:`FormType ` type | +| | | +| | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+------------------------------------------------------------------------+ +| Default `invalid_message` | Please select a valid currency. | ++---------------------------+------------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+------------------------------------------------------------------------+ +| Parent type | :doc:`ChoiceType ` | ++---------------------------+------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CurrencyType` | ++---------------------------+------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -73,6 +78,8 @@ The choices option defaults to all currencies. .. include:: /reference/forms/types/options/choice_translation_domain_disabled.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/date.rst b/reference/forms/types/date.rst index 582b5bef6ff..fa696007803 100644 --- a/reference/forms/types/date.rst +++ b/reference/forms/types/date.rst @@ -10,46 +10,50 @@ different HTML elements. This field can be rendered in a variety of different ways via the `widget`_ option and can understand a number of different input formats via the `input`_ option. -+----------------------+-----------------------------------------------------------------------------+ -| Underlying Data Type | can be ``DateTime``, string, timestamp, or array (see the ``input`` option) | -+----------------------+-----------------------------------------------------------------------------+ -| Rendered as | single text box or three select fields | -+----------------------+-----------------------------------------------------------------------------+ -| Options | - `days`_ | -| | - `placeholder`_ | -| | - `format`_ | -| | - `html5`_ | -| | - `input`_ | -| | - `input_format`_ | -| | - `model_timezone`_ | -| | - `months`_ | -| | - `view_timezone`_ | -| | - `widget`_ | -| | - `years`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Overridden options | - `by_reference`_ | -| | - `choice_translation_domain`_ | -| | - `compound`_ | -| | - `data_class`_ | -| | - `error_bubbling`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `inherit_data`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `mapped`_ | -| | - `row_attr`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+----------------------+-----------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateType` | -+----------------------+-----------------------------------------------------------------------------+ ++---------------------------+-----------------------------------------------------------------------------+ +| Underlying Data Type | can be ``DateTime``, string, timestamp, or array (see the ``input`` option) | ++---------------------------+-----------------------------------------------------------------------------+ +| Rendered as | single text box or three select fields | ++---------------------------+-----------------------------------------------------------------------------+ +| Options | - `days`_ | +| | - `placeholder`_ | +| | - `format`_ | +| | - `html5`_ | +| | - `input`_ | +| | - `input_format`_ | +| | - `model_timezone`_ | +| | - `months`_ | +| | - `view_timezone`_ | +| | - `widget`_ | +| | - `years`_ | ++---------------------------+-----------------------------------------------------------------------------+ +| Overridden options | - `by_reference`_ | +| | - `choice_translation_domain`_ | +| | - `compound`_ | +| | - `data_class`_ | +| | - `error_bubbling`_ | +| | - `invalid_message`_ | ++---------------------------+-----------------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `inherit_data`_ | +| | - `invalid_message_parameters`_ | +| | - `mapped`_ | +| | - `row_attr`_ | ++---------------------------+-----------------------------------------------------------------------------+ +| Default `invalid_message` | Please enter a valid date. | ++---------------------------+-----------------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+-----------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateType` | ++---------------------------+-----------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -210,6 +214,8 @@ The ``DateTime`` classes are treated as immutable objects. **default**: ``false`` +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -231,8 +237,6 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/inherit_data.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/mapped.rst.inc diff --git a/reference/forms/types/dateinterval.rst b/reference/forms/types/dateinterval.rst index 84986f93c87..69147d95bee 100644 --- a/reference/forms/types/dateinterval.rst +++ b/reference/forms/types/dateinterval.rst @@ -12,47 +12,52 @@ The field can be rendered in a variety of different ways (see `widget`_) and can give you a ``DateInterval`` object, an `ISO 8601`_ duration string (e.g. ``P1DT12H``) or an array (see `input`_). -+----------------------+----------------------------------------------------------------------------------+ -| Underlying Data Type | can be ``DateInterval``, string or array (see the ``input`` option) | -+----------------------+----------------------------------------------------------------------------------+ -| Rendered as | single text box, multiple text boxes or select fields - see the `widget`_ option | -+----------------------+----------------------------------------------------------------------------------+ -| Options | - `days`_ | -| | - `hours`_ | -| | - `minutes`_ | -| | - `months`_ | -| | - `seconds`_ | -| | - `weeks`_ | -| | - `input`_ | -| | - `labels`_ | -| | - `placeholder`_ | -| | - `widget`_ | -| | - `with_days`_ | -| | - `with_hours`_ | -| | - `with_invert`_ | -| | - `with_minutes`_ | -| | - `with_months`_ | -| | - `with_seconds`_ | -| | - `with_weeks`_ | -| | - `with_years`_ | -| | - `years`_ | -+----------------------+----------------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `inherit_data`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `mapped`_ | -| | - `row_attr`_ | -+----------------------+----------------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+----------------------+----------------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateIntervalType` | -+----------------------+----------------------------------------------------------------------------------+ ++---------------------------+----------------------------------------------------------------------------------+ +| Underlying Data Type | can be ``DateInterval``, string or array (see the ``input`` option) | ++---------------------------+----------------------------------------------------------------------------------+ +| Rendered as | single text box, multiple text boxes or select fields - see the `widget`_ option | ++---------------------------+----------------------------------------------------------------------------------+ +| Options | - `days`_ | +| | - `hours`_ | +| | - `minutes`_ | +| | - `months`_ | +| | - `seconds`_ | +| | - `weeks`_ | +| | - `input`_ | +| | - `labels`_ | +| | - `placeholder`_ | +| | - `widget`_ | +| | - `with_days`_ | +| | - `with_hours`_ | +| | - `with_invert`_ | +| | - `with_minutes`_ | +| | - `with_months`_ | +| | - `with_seconds`_ | +| | - `with_weeks`_ | +| | - `with_years`_ | +| | - `years`_ | ++---------------------------+----------------------------------------------------------------------------------+ +| Overridden options | - `invalid_message`_ | ++---------------------------+----------------------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `inherit_data`_ | +| | - `invalid_message_parameters`_ | +| | - `mapped`_ | +| | - `row_attr`_ | ++---------------------------+----------------------------------------------------------------------------------+ +| Default `invalid_message` | Please choose a valid date interval. | ++---------------------------+----------------------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+----------------------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+----------------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateIntervalType` | ++---------------------------+----------------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -333,6 +338,11 @@ when the ``widget`` option is set to ``choice``:: // values displayed to users range from 1 to 100 (both inclusive) 'years' => array_combine(range(1, 100), range(1, 100)), +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -352,8 +362,6 @@ These options inherit from the :doc:`form ` type: .. include:: /reference/forms/types/options/inherit_data.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/mapped.rst.inc diff --git a/reference/forms/types/datetime.rst b/reference/forms/types/datetime.rst index ad56b6e2d52..ca61be3e538 100644 --- a/reference/forms/types/datetime.rst +++ b/reference/forms/types/datetime.rst @@ -10,55 +10,59 @@ date and time (e.g. ``1984-06-05 12:15:30``). Can be rendered as a text input or select tags. The underlying format of the data can be a ``DateTime`` object, a string, a timestamp or an array. -+----------------------+-----------------------------------------------------------------------------+ -| Underlying Data Type | can be ``DateTime``, string, timestamp, or array (see the ``input`` option) | -+----------------------+-----------------------------------------------------------------------------+ -| Rendered as | single text box or three select fields | -+----------------------+-----------------------------------------------------------------------------+ -| Options | - `choice_translation_domain`_ | -| | - `date_format`_ | -| | - `date_label`_ | -| | - `date_widget`_ | -| | - `days`_ | -| | - `placeholder`_ | -| | - `format`_ | -| | - `hours`_ | -| | - `html5`_ | -| | - `input`_ | -| | - `input_format`_ | -| | - `minutes`_ | -| | - `model_timezone`_ | -| | - `months`_ | -| | - `seconds`_ | -| | - `time_label`_ | -| | - `time_widget`_ | -| | - `view_timezone`_ | -| | - `widget`_ | -| | - `with_minutes`_ | -| | - `with_seconds`_ | -| | - `years`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Overridden options | - `by_reference`_ | -| | - `compound`_ | -| | - `data_class`_ | -| | - `error_bubbling`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `inherit_data`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `mapped`_ | -| | - `row_attr`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+----------------------+-----------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateTimeType` | -+----------------------+-----------------------------------------------------------------------------+ ++---------------------------+-----------------------------------------------------------------------------+ +| Underlying Data Type | can be ``DateTime``, string, timestamp, or array (see the ``input`` option) | ++---------------------------+-----------------------------------------------------------------------------+ +| Rendered as | single text box or three select fields | ++---------------------------+-----------------------------------------------------------------------------+ +| Options | - `choice_translation_domain`_ | +| | - `date_format`_ | +| | - `date_label`_ | +| | - `date_widget`_ | +| | - `days`_ | +| | - `placeholder`_ | +| | - `format`_ | +| | - `hours`_ | +| | - `html5`_ | +| | - `input`_ | +| | - `input_format`_ | +| | - `minutes`_ | +| | - `model_timezone`_ | +| | - `months`_ | +| | - `seconds`_ | +| | - `time_label`_ | +| | - `time_widget`_ | +| | - `view_timezone`_ | +| | - `widget`_ | +| | - `with_minutes`_ | +| | - `with_seconds`_ | +| | - `years`_ | ++---------------------------+-----------------------------------------------------------------------------+ +| Overridden options | - `by_reference`_ | +| | - `compound`_ | +| | - `data_class`_ | +| | - `error_bubbling`_ | +| | - `invalid_message`_ | ++---------------------------+-----------------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `inherit_data`_ | +| | - `invalid_message_parameters`_ | +| | - `mapped`_ | +| | - `row_attr`_ | ++---------------------------+-----------------------------------------------------------------------------+ +| Default `invalid_message` | Please enter a valid date and time. | ++---------------------------+-----------------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+-----------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateTimeType` | ++---------------------------+-----------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -231,6 +235,8 @@ error_bubbling **default**: ``false`` +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -250,8 +256,6 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/inherit_data.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/mapped.rst.inc diff --git a/reference/forms/types/email.rst b/reference/forms/types/email.rst index 74eeaa95272..31d6f5db90b 100644 --- a/reference/forms/types/email.rst +++ b/reference/forms/types/email.rst @@ -7,33 +7,44 @@ EmailType Field The ``EmailType`` field is a text field that is rendered using the HTML5 ```` tag. -+-------------+---------------------------------------------------------------------+ -| Rendered as | ``input`` ``email`` field (a text box) | -+-------------+---------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `trim`_ | -+-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | -+-------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\EmailType` | -+-------------+---------------------------------------------------------------------+ ++---------------------------+---------------------------------------------------------------------+ +| Rendered as | ``input`` ``email`` field (a text box) | ++---------------------------+---------------------------------------------------------------------+ +| Overridden options | - `invalid_message`_ | ++---------------------------+---------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | +| | - `trim`_ | ++---------------------------+---------------------------------------------------------------------+ +| Default `invalid_message` | Please enter a valid email address. | ++---------------------------+---------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+---------------------------------------------------------------------+ +| Parent type | :doc:`TextType ` | ++---------------------------+---------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\EmailType` | ++---------------------------+---------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/file.rst b/reference/forms/types/file.rst index 66a18560577..f745c9bc1fd 100644 --- a/reference/forms/types/file.rst +++ b/reference/forms/types/file.rst @@ -6,33 +6,38 @@ FileType Field The ``FileType`` represents a file input in your form. -+-------------+---------------------------------------------------------------------+ -| Rendered as | ``input`` ``file`` field | -+-------------+---------------------------------------------------------------------+ -| Options | - `multiple`_ | -+-------------+---------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | - `data_class`_ | -| | - `empty_data`_ | -+-------------+---------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `disabled`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\FileType` | -+-------------+---------------------------------------------------------------------+ ++---------------------------+--------------------------------------------------------------------+ +| Rendered as | ``input`` ``file`` field | ++---------------------------+--------------------------------------------------------------------+ +| Options | - `multiple`_ | ++---------------------------+--------------------------------------------------------------------+ +| Overridden options | - `compound`_ | +| | - `data_class`_ | +| | - `empty_data`_ | +| | - `invalid_message`_ | ++---------------------------+--------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `disabled`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+--------------------------------------------------------------------+ +| Default `invalid_message` | Please select a valid file. | ++---------------------------+--------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+--------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+--------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\FileType` | ++---------------------------+--------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -120,6 +125,11 @@ This option sets the appropriate file-related data mapper to be used by the type This option determines what value the field will return when the submitted value is empty. +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/form.rst b/reference/forms/types/form.rst index 8a0c219f410..e406413bf37 100644 --- a/reference/forms/types/form.rst +++ b/reference/forms/types/form.rst @@ -7,51 +7,55 @@ FormType Field The ``FormType`` predefines a couple of options that are then available on all types for which ``FormType`` is the parent. -+-----------+--------------------------------------------------------------------+ -| Options | - `action`_ | -| | - `allow_extra_fields`_ | -| | - `by_reference`_ | -| | - `compound`_ | -| | - `constraints`_ | -| | - `data`_ | -| | - `data_class`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `extra_fields_message`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `help_translation_parameters`_ | -| | - `inherit_data`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `method`_ | -| | - `post_max_size_message`_ | -| | - `property_path`_ | -| | - `required`_ | -| | - `trim`_ | -| | - `validation_groups`_ | -+-----------+--------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `auto_initialize`_ | -| | - `block_name`_ | -| | - `block_prefix`_ | -| | - `disabled`_ | -| | - `label`_ | -| | - `label_html`_ | -| | - `row_attr`_ | -| | - `translation_domain`_ | -| | - `label_translation_parameters`_ | -| | - `attr_translation_parameters`_ | -+-----------+--------------------------------------------------------------------+ -| Parent | none | -+-----------+--------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\FormType` | -+-----------+--------------------------------------------------------------------+ ++---------------------------+--------------------------------------------------------------------+ +| Options | - `action`_ | +| | - `allow_extra_fields`_ | +| | - `by_reference`_ | +| | - `compound`_ | +| | - `constraints`_ | +| | - `data`_ | +| | - `data_class`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `extra_fields_message`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `help_translation_parameters`_ | +| | - `inherit_data`_ | +| | - `invalid_message`_ | +| | - `invalid_message_parameters`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `method`_ | +| | - `post_max_size_message`_ | +| | - `property_path`_ | +| | - `required`_ | +| | - `trim`_ | +| | - `validation_groups`_ | ++---------------------------+--------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `auto_initialize`_ | +| | - `block_name`_ | +| | - `block_prefix`_ | +| | - `disabled`_ | +| | - `label`_ | +| | - `label_html`_ | +| | - `row_attr`_ | +| | - `translation_domain`_ | +| | - `label_translation_parameters`_ | +| | - `attr_translation_parameters`_ | ++---------------------------+--------------------------------------------------------------------+ +| Default `invalid_message` | This value is not valid. | ++---------------------------+--------------------------------------------------------------------+ +| Legacy `invalid_message` | This value is not valid. | ++---------------------------+--------------------------------------------------------------------+ +| Parent | none | ++---------------------------+--------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\FormType` | ++---------------------------+--------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc diff --git a/reference/forms/types/hidden.rst b/reference/forms/types/hidden.rst index 1a74e107555..f0bddfa4260 100644 --- a/reference/forms/types/hidden.rst +++ b/reference/forms/types/hidden.rst @@ -6,25 +6,30 @@ HiddenType Field The hidden type represents a hidden input field. -+-------------+----------------------------------------------------------------------+ -| Rendered as | ``input`` ``hidden`` field | -+-------------+----------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | - `error_bubbling`_ | -| | - `required`_ | -+-------------+----------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `empty_data`_ | -| | - `error_mapping`_ | -| | - `mapped`_ | -| | - `property_path`_ | -| | - `row_attr`_ | -+-------------+----------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+----------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\HiddenType` | -+-------------+----------------------------------------------------------------------+ ++---------------------------+----------------------------------------------------------------------+ +| Rendered as | ``input`` ``hidden`` field | ++---------------------------+----------------------------------------------------------------------+ +| Overridden options | - `compound`_ | +| | - `error_bubbling`_ | +| | - `invalid_message`_ | +| | - `required`_ | ++---------------------------+----------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `empty_data`_ | +| | - `error_mapping`_ | +| | - `mapped`_ | +| | - `property_path`_ | +| | - `row_attr`_ | ++---------------------------+----------------------------------------------------------------------+ +| Default `invalid_message` | The hidden field is invalid. | ++---------------------------+----------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+----------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\HiddenType` | ++---------------------------+----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -40,6 +45,8 @@ Overridden Options Pass errors to the root form, otherwise they will not be visible. +.. include:: /reference/forms/types/options/invalid_message.rst.inc + ``required`` ~~~~~~~~~~~~ diff --git a/reference/forms/types/integer.rst b/reference/forms/types/integer.rst index fa5660158bc..7eb32abf7f9 100644 --- a/reference/forms/types/integer.rst +++ b/reference/forms/types/integer.rst @@ -13,37 +13,40 @@ This field has different options on how to handle input values that aren't integers. By default, all non-integer values (e.g. 6.78) will round down (e.g. 6). -+-------------+-----------------------------------------------------------------------+ -| Rendered as | ``input`` ``number`` field | -+-------------+-----------------------------------------------------------------------+ -| Options | - `grouping`_ | -| | - `rounding_mode`_ | -+-------------+-----------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | | -+-------------+-----------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+-----------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+-----------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\IntegerType` | -+-------------+-----------------------------------------------------------------------+ ++---------------------------+-----------------------------------------------------------------------+ +| Rendered as | ``input`` ``number`` field | ++---------------------------+-----------------------------------------------------------------------+ +| Options | - `grouping`_ | +| | - `rounding_mode`_ | ++---------------------------+-----------------------------------------------------------------------+ +| Overridden options | - `compound`_ | +| | - `invalid_message`_ | ++---------------------------+-----------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `invalid_message_parameters`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+-----------------------------------------------------------------------+ +| Default `invalid_message` | Please enter an integer. | ++---------------------------+-----------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+-----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\IntegerType` | ++---------------------------+-----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -86,6 +89,8 @@ Overridden Options .. include:: /reference/forms/types/options/compound_type.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -115,8 +120,6 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/help_html.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/label.rst.inc diff --git a/reference/forms/types/language.rst b/reference/forms/types/language.rst index 5fa38697701..420ab1b59a0 100644 --- a/reference/forms/types/language.rst +++ b/reference/forms/types/language.rst @@ -20,46 +20,51 @@ Unlike the ``ChoiceType``, you don't need to specify a ``choices`` option as the field type automatically uses a large list of languages. You *can* specify the option manually, but then you should just use the ``ChoiceType`` directly. -+-------------+------------------------------------------------------------------------+ -| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | -+-------------+------------------------------------------------------------------------+ -| Options | - `alpha3`_ | -| | - `choice_self_translation`_ | -| | - `choice_translation_locale`_ | -+-------------+------------------------------------------------------------------------+ -| Overridden | - `choices`_ | -| options | - `choice_translation_domain`_ | -+-------------+------------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType ` | -| options | | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `expanded`_ | -| | - `multiple`_ | -| | - `placeholder`_ | -| | - `preferred_choices`_ | -| | - `trim`_ | -| | | -| | from the :doc:`FormType ` | -| | | -| | - `attr`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | -+-------------+------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\LanguageType` | -+-------------+------------------------------------------------------------------------+ ++---------------------------+------------------------------------------------------------------------+ +| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | ++---------------------------+------------------------------------------------------------------------+ +| Options | - `alpha3`_ | +| | - `choice_self_translation`_ | +| | - `choice_translation_locale`_ | ++---------------------------+------------------------------------------------------------------------+ +| Overridden options | - `choices`_ | +| | - `choice_translation_domain`_ | +| | - `invalid_message`_ | ++---------------------------+------------------------------------------------------------------------+ +| Inherited options | from the :doc:`ChoiceType ` | +| | | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `expanded`_ | +| | - `multiple`_ | +| | - `placeholder`_ | +| | - `preferred_choices`_ | +| | - `trim`_ | +| | | +| | from the :doc:`FormType ` | +| | | +| | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+------------------------------------------------------------------------+ +| Default `invalid_message` | Please select a valid language. | ++---------------------------+------------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+------------------------------------------------------------------------+ +| Parent type | :doc:`ChoiceType ` | ++---------------------------+------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\LanguageType` | ++---------------------------+------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -114,6 +119,8 @@ The default locale is used to translate the languages names. .. include:: /reference/forms/types/options/choice_translation_domain_disabled.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/locale.rst b/reference/forms/types/locale.rst index 385cc4f6fd8..be6dde7e950 100644 --- a/reference/forms/types/locale.rst +++ b/reference/forms/types/locale.rst @@ -21,44 +21,49 @@ Unlike the ``ChoiceType``, you don't need to specify a ``choices`` option as the field type automatically uses a large list of locales. You *can* specify these options manually, but then you should just use the ``ChoiceType`` directly. -+-------------+------------------------------------------------------------------------+ -| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | -+-------------+------------------------------------------------------------------------+ -| Options | - `choice_translation_locale`_ | -+-------------+------------------------------------------------------------------------+ -| Overridden | - `choices`_ | -| options | - `choice_translation_domain`_ | -+-------------+------------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType ` | -| options | | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `expanded`_ | -| | - `multiple`_ | -| | - `placeholder`_ | -| | - `preferred_choices`_ | -| | - `trim`_ | -| | | -| | from the :doc:`FormType ` | -| | | -| | - `attr`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | -+-------------+------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\LocaleType` | -+-------------+------------------------------------------------------------------------+ ++---------------------------+----------------------------------------------------------------------+ +| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | ++---------------------------+----------------------------------------------------------------------+ +| Options | - `choice_translation_locale`_ | ++---------------------------+----------------------------------------------------------------------+ +| Overridden options | - `choices`_ | +| | - `choice_translation_domain`_ | +| | - `invalid_message`_ | ++---------------------------+----------------------------------------------------------------------+ +| Inherited options | from the :doc:`ChoiceType ` | +| | | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `expanded`_ | +| | - `multiple`_ | +| | - `placeholder`_ | +| | - `preferred_choices`_ | +| | - `trim`_ | +| | | +| | from the :doc:`FormType ` | +| | | +| | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+----------------------------------------------------------------------+ +| Default `invalid_message` | Please select a valid locale. | ++---------------------------+----------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+----------------------------------------------------------------------+ +| Parent type | :doc:`ChoiceType ` | ++---------------------------+----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\LocaleType` | ++---------------------------+----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -85,6 +90,8 @@ specify the language. .. include:: /reference/forms/types/options/choice_translation_domain_disabled.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/money.rst b/reference/forms/types/money.rst index bb91d0b08da..ca7a5aceac7 100644 --- a/reference/forms/types/money.rst +++ b/reference/forms/types/money.rst @@ -11,41 +11,44 @@ This field type allows you to specify a currency, whose symbol is rendered next to the text field. There are also several other options for customizing how the input and output of the data is handled. -+-------------+---------------------------------------------------------------------+ -| Rendered as | ``input`` ``text`` field | -+-------------+---------------------------------------------------------------------+ -| Options | - `currency`_ | -| | - `divisor`_ | -| | - `grouping`_ | -| | - `html5`_ | -| | - `rounding_mode`_ | -| | - `scale`_ | -+-------------+---------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | | -+-------------+---------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\MoneyType` | -+-------------+---------------------------------------------------------------------+ ++---------------------------+---------------------------------------------------------------------+ +| Rendered as | ``input`` ``text`` field | ++---------------------------+---------------------------------------------------------------------+ +| Options | - `currency`_ | +| | - `divisor`_ | +| | - `grouping`_ | +| | - `html5`_ | +| | - `rounding_mode`_ | +| | - `scale`_ | ++---------------------------+---------------------------------------------------------------------+ +| Overridden options | - `compound`_ | +| | - `invalid_message`_ | ++---------------------------+---------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `invalid_message_parameters`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+---------------------------------------------------------------------+ +| Default `invalid_message` | Please enter a valid money amount. | ++---------------------------+---------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+---------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+---------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\MoneyType` | ++---------------------------+---------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -122,6 +125,8 @@ Overridden Options .. include:: /reference/forms/types/options/compound_type.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -151,8 +156,6 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/help_html.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/label.rst.inc diff --git a/reference/forms/types/number.rst b/reference/forms/types/number.rst index 599d0efa4cd..319c84b951e 100644 --- a/reference/forms/types/number.rst +++ b/reference/forms/types/number.rst @@ -8,40 +8,43 @@ Renders an input text field and specializes in handling number input. This type offers different options for the scale, rounding and grouping that you want to use for your number. -+-------------+----------------------------------------------------------------------+ -| Rendered as | ``input`` ``text`` field | -+-------------+----------------------------------------------------------------------+ -| Options | - `grouping`_ | -| | - `html5`_ | -| | - `input`_ | -| | - `scale`_ | -| | - `rounding_mode`_ | -+-------------+----------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | | -+-------------+----------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+----------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+----------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\NumberType` | -+-------------+----------------------------------------------------------------------+ ++---------------------------+----------------------------------------------------------------------+ +| Rendered as | ``input`` ``text`` field | ++---------------------------+----------------------------------------------------------------------+ +| Options | - `grouping`_ | +| | - `html5`_ | +| | - `input`_ | +| | - `scale`_ | +| | - `rounding_mode`_ | ++---------------------------+----------------------------------------------------------------------+ +| Overridden options | - `compound`_ | +| | - `invalid_message`_ | ++---------------------------+----------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `invalid_message_parameters`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+----------------------------------------------------------------------+ +| Default `invalid_message` | Please enter a number. | ++---------------------------+----------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+----------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\NumberType` | ++---------------------------+----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -86,6 +89,8 @@ Overridden Options .. include:: /reference/forms/types/options/compound_type.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -115,8 +120,6 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/help_html.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/label.rst.inc diff --git a/reference/forms/types/password.rst b/reference/forms/types/password.rst index 37acff1a616..10b38a5ac8b 100644 --- a/reference/forms/types/password.rst +++ b/reference/forms/types/password.rst @@ -6,33 +6,37 @@ PasswordType Field The ``PasswordType`` field renders an input password text box. -+-------------+------------------------------------------------------------------------+ -| Rendered as | ``input`` ``password`` field | -+-------------+------------------------------------------------------------------------+ -| Options | - `always_empty`_ | -+-------------+------------------------------------------------------------------------+ -| Overridden | - `trim`_ | -| options | | -+-------------+------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | -+-------------+------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\PasswordType` | -+-------------+------------------------------------------------------------------------+ ++---------------------------+------------------------------------------------------------------------+ +| Rendered as | ``input`` ``password`` field | ++---------------------------+------------------------------------------------------------------------+ +| Options | - `always_empty`_ | ++---------------------------+------------------------------------------------------------------------+ +| Overridden options | - `invalid_message`_ | +| | - `trim`_ | ++---------------------------+------------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+------------------------------------------------------------------------+ +| Default `invalid_message` | The password is invalid. | ++---------------------------+------------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+------------------------------------------------------------------------+ +| Parent type | :doc:`TextType ` | ++---------------------------+------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\PasswordType` | ++---------------------------+------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -54,6 +58,8 @@ entered into the box, set this to false and submit the form. Overridden Options ------------------ +.. include:: /reference/forms/types/options/invalid_message.rst.inc + ``trim`` ~~~~~~~~ diff --git a/reference/forms/types/percent.rst b/reference/forms/types/percent.rst index 4b21f1f2856..3dd47e1d320 100644 --- a/reference/forms/types/percent.rst +++ b/reference/forms/types/percent.rst @@ -12,40 +12,43 @@ you can use this field out-of-the-box. If you store your data as a number When ``symbol`` is not ``false``, the field will render the given string after the input. -+-------------+-----------------------------------------------------------------------+ -| Rendered as | ``input`` ``text`` field | -+-------------+-----------------------------------------------------------------------+ -| Options | - `html5`_ | -| | - `rounding_mode`_ | -| | - `scale`_ | -| | - `symbol`_ | -| | - `type`_ | -+-------------+-----------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | | -+-------------+-----------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+-----------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+-----------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\PercentType` | -+-------------+-----------------------------------------------------------------------+ ++---------------------------+-----------------------------------------------------------------------+ +| Rendered as | ``input`` ``text`` field | ++---------------------------+-----------------------------------------------------------------------+ +| Options | - `html5`_ | +| | - `rounding_mode`_ | +| | - `scale`_ | +| | - `symbol`_ | +| | - `type`_ | ++---------------------------+-----------------------------------------------------------------------+ +| Overridden options | - `compound`_ | +| | - `invalid_message`_ | ++---------------------------+-----------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `invalid_message_parameters`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+-----------------------------------------------------------------------+ +| Default `invalid_message` | Please enter a percentage value. | ++---------------------------+-----------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+-----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\PercentType` | ++---------------------------+-----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -115,6 +118,8 @@ Overridden Options .. include:: /reference/forms/types/options/compound_type.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -144,8 +149,6 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/help_html.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/label.rst.inc diff --git a/reference/forms/types/radio.rst b/reference/forms/types/radio.rst index ae0d58d2fe4..579dab0bc1d 100644 --- a/reference/forms/types/radio.rst +++ b/reference/forms/types/radio.rst @@ -13,38 +13,49 @@ The ``RadioType`` isn't usually used directly. More commonly it's used internally by other types such as :doc:`ChoiceType `. If you want to have a boolean field, use :doc:`CheckboxType `. -+-------------+---------------------------------------------------------------------+ -| Rendered as | ``input`` ``radio`` field | -+-------------+---------------------------------------------------------------------+ -| Inherited | from the :doc:`CheckboxType `: | -| options | | -| | - `value`_ | -| | | -| | from the :doc:`FormType `: | -| | | -| | - `attr`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`CheckboxType ` | -+-------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RadioType` | -+-------------+---------------------------------------------------------------------+ ++---------------------------+---------------------------------------------------------------------+ +| Rendered as | ``input`` ``radio`` field | ++---------------------------+---------------------------------------------------------------------+ +| Overridden options | - `invalid_message`_ | ++---------------------------+---------------------------------------------------------------------+ +| Inherited options | from the :doc:`CheckboxType `: | +| | | +| | - `value`_ | +| | | +| | from the :doc:`FormType `: | +| | | +| | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+---------------------------------------------------------------------+ +| Default `invalid_message` | Please select a valid option. | ++---------------------------+---------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+---------------------------------------------------------------------+ +| Parent type | :doc:`CheckboxType ` | ++---------------------------+---------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RadioType` | ++---------------------------+---------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/range.rst b/reference/forms/types/range.rst index e328a1bbe97..ab3a0d15859 100644 --- a/reference/forms/types/range.rst +++ b/reference/forms/types/range.rst @@ -7,29 +7,35 @@ RangeType Field The ``RangeType`` field is a slider that is rendered using the HTML5 ```` tag. -+-------------+---------------------------------------------------------------------+ -| Rendered as | ``input`` ``range`` field (slider in HTML5 supported browser) | -+-------------+---------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `trim`_ | -+-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | -+-------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RangeType` | -+-------------+---------------------------------------------------------------------+ ++---------------------------+---------------------------------------------------------------------+ +| Rendered as | ``input`` ``range`` field (slider in HTML5 supported browser) | ++---------------------------+---------------------------------------------------------------------+ +| Overridden options | - `invalid_message`_ | ++---------------------------+---------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | +| | - `trim`_ | ++---------------------------+---------------------------------------------------------------------+ +| Default `invalid_message` | Please choose a valid range. | ++---------------------------+---------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+---------------------------------------------------------------------+ +| Parent type | :doc:`TextType ` | ++---------------------------+---------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RangeType` | ++---------------------------+---------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -48,6 +54,11 @@ Basic Usage ] ]); +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/repeated.rst b/reference/forms/types/repeated.rst index c78e6cc318e..7a9f6d9d9be 100644 --- a/reference/forms/types/repeated.rst +++ b/reference/forms/types/repeated.rst @@ -9,34 +9,37 @@ values must match (or a validation error is thrown). The most common use is when you need the user to repeat their password or email to verify accuracy. -+-------------+------------------------------------------------------------------------+ -| Rendered as | input ``text`` field by default, but see `type`_ option | -+-------------+------------------------------------------------------------------------+ -| Options | - `first_name`_ | -| | - `first_options`_ | -| | - `options`_ | -| | - `second_name`_ | -| | - `second_options`_ | -| | - `type`_ | -+-------------+------------------------------------------------------------------------+ -| Overridden | - `error_bubbling`_ | -| options | | -+-------------+------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `mapped`_ | -| | - `row_attr`_ | -+-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RepeatedType` | -+-------------+------------------------------------------------------------------------+ ++---------------------------+------------------------------------------------------------------------+ +| Rendered as | input ``text`` field by default, but see `type`_ option | ++---------------------------+------------------------------------------------------------------------+ +| Options | - `first_name`_ | +| | - `first_options`_ | +| | - `options`_ | +| | - `second_name`_ | +| | - `second_options`_ | +| | - `type`_ | ++---------------------------+------------------------------------------------------------------------+ +| Overridden options | - `error_bubbling`_ | +| | - `invalid_message`_ | ++---------------------------+------------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `invalid_message_parameters`_ | +| | - `mapped`_ | +| | - `row_attr`_ | ++---------------------------+------------------------------------------------------------------------+ +| Default `invalid_message` | The values do not match. | ++---------------------------+------------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+------------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RepeatedType` | ++---------------------------+------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -184,6 +187,8 @@ Overridden Options **default**: ``false`` +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -201,8 +206,6 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/help_html.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/mapped.rst.inc diff --git a/reference/forms/types/search.rst b/reference/forms/types/search.rst index e0f8233aa5b..f9c53733872 100644 --- a/reference/forms/types/search.rst +++ b/reference/forms/types/search.rst @@ -9,32 +9,43 @@ special functionality supported by some browsers. Read about the input search field at `DiveIntoHTML5.info`_ -+-------------+----------------------------------------------------------------------+ -| Rendered as | ``input search`` field | -+-------------+----------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `trim`_ | -+-------------+----------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | -+-------------+----------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\SearchType` | -+-------------+----------------------------------------------------------------------+ ++---------------------------+----------------------------------------------------------------------+ +| Rendered as | ``input search`` field | ++---------------------------+----------------------------------------------------------------------+ +| Overridden options | - `invalid_message`_ | ++---------------------------+----------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | +| | - `trim`_ | ++---------------------------+----------------------------------------------------------------------+ +| Default `invalid_message` | Please enter a valid search term. | ++---------------------------+----------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+----------------------------------------------------------------------+ +| Parent type | :doc:`TextType ` | ++---------------------------+----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\SearchType` | ++---------------------------+----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/tel.rst b/reference/forms/types/tel.rst index f6c19391ada..fc45434bc4e 100644 --- a/reference/forms/types/tel.rst +++ b/reference/forms/types/tel.rst @@ -13,33 +13,44 @@ Nevertheless, it may be useful to use this type in web applications because some browsers (e.g. smartphone browsers) adapt the input keyboard to make it easier to input phone numbers. -+-------------+---------------------------------------------------------------------+ -| Rendered as | ``input`` ``tel`` field (a text box) | -+-------------+---------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `trim`_ | -+-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | -+-------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TelType` | -+-------------+---------------------------------------------------------------------+ ++---------------------------+-------------------------------------------------------------------+ +| Rendered as | ``input`` ``tel`` field (a text box) | ++---------------------------+-------------------------------------------------------------------+ +| Overridden options | - `invalid_message`_ | ++---------------------------+-------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | +| | - `trim`_ | ++---------------------------+-------------------------------------------------------------------+ +| Default `invalid_message` | Please provide a valid phone number. | ++---------------------------+-------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+-------------------------------------------------------------------+ +| Parent type | :doc:`TextType ` | ++---------------------------+-------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TelType` | ++---------------------------+-------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/time.rst b/reference/forms/types/time.rst index 042e3e7da0c..08c3efb77f4 100644 --- a/reference/forms/types/time.rst +++ b/reference/forms/types/time.rst @@ -10,48 +10,52 @@ This can be rendered as a text field, a series of text fields (e.g. hour, minute, second) or a series of select fields. The underlying data can be stored as a ``DateTime`` object, a string, a timestamp or an array. -+----------------------+-----------------------------------------------------------------------------+ -| Underlying Data Type | can be ``DateTime``, string, timestamp, or array (see the ``input`` option) | -+----------------------+-----------------------------------------------------------------------------+ -| Rendered as | can be various tags (see below) | -+----------------------+-----------------------------------------------------------------------------+ -| Options | - `choice_translation_domain`_ | -| | - `placeholder`_ | -| | - `hours`_ | -| | - `html5`_ | -| | - `input`_ | -| | - `input_format`_ | -| | - `minutes`_ | -| | - `model_timezone`_ | -| | - `reference_date`_ | -| | - `seconds`_ | -| | - `view_timezone`_ | -| | - `widget`_ | -| | - `with_minutes`_ | -| | - `with_seconds`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Overridden options | - `by_reference`_ | -| | - `compound`_ | -| | - `data_class`_ | -| | - `error_bubbling`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `inherit_data`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `mapped`_ | -| | - `row_attr`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Parent type | FormType | -+----------------------+-----------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TimeType` | -+----------------------+-----------------------------------------------------------------------------+ ++---------------------------+-----------------------------------------------------------------------------+ +| Underlying Data Type | can be ``DateTime``, string, timestamp, or array (see the ``input`` option) | ++---------------------------+-----------------------------------------------------------------------------+ +| Rendered as | can be various tags (see below) | ++---------------------------+-----------------------------------------------------------------------------+ +| Options | - `choice_translation_domain`_ | +| | - `placeholder`_ | +| | - `hours`_ | +| | - `html5`_ | +| | - `input`_ | +| | - `input_format`_ | +| | - `minutes`_ | +| | - `model_timezone`_ | +| | - `reference_date`_ | +| | - `seconds`_ | +| | - `view_timezone`_ | +| | - `widget`_ | +| | - `with_minutes`_ | +| | - `with_seconds`_ | ++---------------------------+-----------------------------------------------------------------------------+ +| Overridden options | - `by_reference`_ | +| | - `compound`_ | +| | - `data_class`_ | +| | - `error_bubbling`_ | +| | - `invalid_message`_ | ++---------------------------+-----------------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `inherit_data`_ | +| | - `invalid_message_parameters`_ | +| | - `mapped`_ | +| | - `row_attr`_ | ++---------------------------+-----------------------------------------------------------------------------+ +| Default `invalid_message` | Please enter a valid time. | ++---------------------------+-----------------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------------+ +| Parent type | FormType | ++---------------------------+-----------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TimeType` | ++---------------------------+-----------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -220,6 +224,8 @@ error_bubbling **default**: ``false`` +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -241,8 +247,6 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/inherit_data.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/mapped.rst.inc diff --git a/reference/forms/types/timezone.rst b/reference/forms/types/timezone.rst index c18cdbaf339..64e17890de8 100644 --- a/reference/forms/types/timezone.rst +++ b/reference/forms/types/timezone.rst @@ -14,45 +14,50 @@ Unlike the ``ChoiceType``, you don't need to specify a ``choices`` option as the field type automatically uses a large list of timezones. You *can* specify the option manually, but then you should just use the ``ChoiceType`` directly. -+-------------+------------------------------------------------------------------------+ -| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | -+-------------+------------------------------------------------------------------------+ -| Options | - `input`_ | -| | - `intl`_ | -+-------------+------------------------------------------------------------------------+ -| Overridden | - `choices`_ | -| options | - `choice_translation_domain`_ | -+-------------+------------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType ` | -| options | | -| | - `expanded`_ | -| | - `multiple`_ | -| | - `placeholder`_ | -| | - `preferred_choices`_ | -| | - `trim`_ | -| | | -| | from the :doc:`FormType ` | -| | | -| | - `attr`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | -+-------------+------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TimezoneType` | -+-------------+------------------------------------------------------------------------+ ++---------------------------+------------------------------------------------------------------------+ +| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | ++---------------------------+------------------------------------------------------------------------+ +| Options | - `input`_ | +| | - `intl`_ | ++---------------------------+------------------------------------------------------------------------+ +| Overridden options | - `choices`_ | +| | - `choice_translation_domain`_ | +| | - `invalid_message`_ | ++---------------------------+------------------------------------------------------------------------+ +| Inherited options | from the :doc:`ChoiceType ` | +| | | +| | - `expanded`_ | +| | - `multiple`_ | +| | - `placeholder`_ | +| | - `preferred_choices`_ | +| | - `trim`_ | +| | | +| | from the :doc:`FormType ` | +| | | +| | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+------------------------------------------------------------------------+ +| Default `invalid_message` | Please select a valid timezone. | ++---------------------------+------------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+------------------------------------------------------------------------+ +| Parent type | :doc:`ChoiceType ` | ++---------------------------+------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TimezoneType` | ++---------------------------+------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -107,6 +112,8 @@ The Timezone type defaults the choices to all timezones returned by .. include:: /reference/forms/types/options/choice_translation_domain_disabled.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/url.rst b/reference/forms/types/url.rst index a03f1532021..e5f782ce088 100644 --- a/reference/forms/types/url.rst +++ b/reference/forms/types/url.rst @@ -8,32 +8,38 @@ The ``UrlType`` field is a text field that prepends the submitted value with a given protocol (e.g. ``http://``) if the submitted value doesn't already have a protocol. -+-------------+-------------------------------------------------------------------+ -| Rendered as | ``input url`` field | -+-------------+-------------------------------------------------------------------+ -| Options | - `default_protocol`_ | -+-------------+-------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `trim`_ | -+-------------+-------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | -+-------------+-------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\UrlType` | -+-------------+-------------------------------------------------------------------+ ++---------------------------+-------------------------------------------------------------------+ +| Rendered as | ``input url`` field | ++---------------------------+-------------------------------------------------------------------+ +| Options | - `default_protocol`_ | ++---------------------------+-------------------------------------------------------------------+ +| Overridden options | - `invalid_message`_ | ++---------------------------+-------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | +| | - `trim`_ | ++---------------------------+-------------------------------------------------------------------+ +| Default `invalid_message` | Please enter a valid URL. | ++---------------------------+-------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+-------------------------------------------------------------------+ +| Parent type | :doc:`TextType ` | ++---------------------------+-------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\UrlType` | ++---------------------------+-------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -49,6 +55,11 @@ If a value is submitted that doesn't begin with some protocol (e.g. ``http://``, ``ftp://``, etc), this protocol will be prepended to the string when the data is submitted to the form. +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/week.rst b/reference/forms/types/week.rst index 6967df09bb7..eb526c160af 100644 --- a/reference/forms/types/week.rst +++ b/reference/forms/types/week.rst @@ -10,39 +10,43 @@ This field type allows the user to modify data that represents a specific Can be rendered as a text input or select tags. The underlying format of the data can be a string or an array. -+----------------------+-----------------------------------------------------------------------------+ -| Underlying Data Type | can be a string, or array (see the ``input`` option) | -+----------------------+-----------------------------------------------------------------------------+ -| Rendered as | single text box, two text boxes or two select fields | -+----------------------+-----------------------------------------------------------------------------+ -| Options | - `choice_translation_domain`_ | -| | - `placeholder`_ | -| | - `html5`_ | -| | - `input`_ | -| | - `widget`_ | -| | - `weeks`_ | -| | - `years`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Overridden options | - `compound`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `inherit_data`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `mapped`_ | -| | - `row_attr`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+----------------------+-----------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\WeekType` | -+----------------------+-----------------------------------------------------------------------------+ ++---------------------------+--------------------------------------------------------------------+ +| Underlying Data Type | can be a string, or array (see the ``input`` option) | ++---------------------------+--------------------------------------------------------------------+ +| Rendered as | single text box, two text boxes or two select fields | ++---------------------------+--------------------------------------------------------------------+ +| Options | - `choice_translation_domain`_ | +| | - `placeholder`_ | +| | - `html5`_ | +| | - `input`_ | +| | - `widget`_ | +| | - `weeks`_ | +| | - `years`_ | ++---------------------------+--------------------------------------------------------------------+ +| Overridden options | - `compound`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `invalid_message`_ | ++---------------------------+--------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `inherit_data`_ | +| | - `invalid_message_parameters`_ | +| | - `mapped`_ | +| | - `row_attr`_ | ++---------------------------+--------------------------------------------------------------------+ +| Default `invalid_message` | Please enter a valid week. | ++---------------------------+--------------------------------------------------------------------+ +| Legacy `invalid_message` | The value {{ value }} is not valid. | ++---------------------------+--------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+--------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\WeekType` | ++---------------------------+--------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -138,6 +142,8 @@ error_bubbling **default**: ``false`` +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -157,8 +163,6 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/inherit_data.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/mapped.rst.inc From 289ca7c128f4c413f75a0606cc54f9833130e5c1 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Fri, 20 Nov 2020 10:08:28 +0100 Subject: [PATCH 0619/1519] Fix: DOCtor-RST build --- http_client.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/http_client.rst b/http_client.rst index 2fb102a0fcc..b46a3f7760d 100644 --- a/http_client.rst +++ b/http_client.rst @@ -1616,5 +1616,5 @@ Then configure Symfony to use your callback: .. _`amphp/http-client`: https://packagist.org/packages/amphp/http-client .. _`cURL options`: https://www.php.net/manual/en/function.curl-setopt.php .. _`Server-sent events`: https://html.spec.whatwg.org/multipage/server-sent-events.html -.. _`EventSource`: https://www.w3.org/TR/eventsource/#eventsource -.. _`idempotent method`: https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods_and_web_applications +.. _`EventSource`: https://www.w3.org/TR/eventsource/#eventsource +.. _`idempotent method`: https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods_and_web_applications From 12fff0cf5ec2a195709c5ac1ccbad8e04da6bef1 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Fri, 20 Nov 2020 09:45:20 +0100 Subject: [PATCH 0620/1519] Enhancement: New rule for DOCtor-RST --- .doctor-rst.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.doctor-rst.yaml b/.doctor-rst.yaml index 5c4fadeb132..94d88088d52 100644 --- a/.doctor-rst.yaml +++ b/.doctor-rst.yaml @@ -6,6 +6,7 @@ rules: composer_dev_option_not_at_the_end: ~ correct_code_block_directive_based_on_the_content: ~ deprecated_directive_should_have_version: ~ + ensure_exactly_one_space_between_link_definition_and_link: ~ ensure_order_of_code_blocks_in_configuration_block: ~ extend_abstract_controller: ~ extension_xlf_instead_of_xliff: ~ From 26dfa839ad7242522a97968096403c5801852424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Barray?= Date: Fri, 20 Nov 2020 14:01:55 +0100 Subject: [PATCH 0621/1519] [Messenger] Add mention about serialize in inMemory transport dsn --- messenger.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/messenger.rst b/messenger.rst index ac07b40c624..e5a4da76cf9 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1295,6 +1295,15 @@ during a request:: :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\KernelTestCase` or :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\WebTestCase`. +.. tip:: + + Using ``in-memory://?serialize=true`` as dsn will perform message serialization as real asynchronous transport will do. + Useful to test an additional layer, especially when you use your own message serializer. + +.. versionadded:: 5.3 + + The ``in-memory://?serialize=true`` dsn was introduced in Symfony 5.3. + Amazon SQS ~~~~~~~~~~ From 0ccfa6e913782c1788e08032ebfcf14968e72b96 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 20 Nov 2020 15:55:35 +0100 Subject: [PATCH 0622/1519] Tweaks --- forms.rst | 8 +++----- reference/forms/types/birthday.rst | 4 ++-- reference/forms/types/checkbox.rst | 4 ++-- reference/forms/types/choice.rst | 4 ++-- reference/forms/types/collection.rst | 4 ++-- reference/forms/types/color.rst | 4 ++-- reference/forms/types/country.rst | 4 ++-- reference/forms/types/currency.rst | 4 ++-- reference/forms/types/date.rst | 4 ++-- reference/forms/types/dateinterval.rst | 4 ++-- reference/forms/types/datetime.rst | 4 ++-- reference/forms/types/email.rst | 4 ++-- reference/forms/types/file.rst | 4 ++-- reference/forms/types/form.rst | 4 ++-- reference/forms/types/hidden.rst | 4 ++-- reference/forms/types/integer.rst | 4 ++-- reference/forms/types/language.rst | 4 ++-- reference/forms/types/locale.rst | 4 ++-- reference/forms/types/money.rst | 4 ++-- reference/forms/types/number.rst | 4 ++-- reference/forms/types/password.rst | 4 ++-- reference/forms/types/percent.rst | 4 ++-- reference/forms/types/radio.rst | 4 ++-- reference/forms/types/range.rst | 4 ++-- reference/forms/types/repeated.rst | 4 ++-- reference/forms/types/search.rst | 4 ++-- reference/forms/types/tel.rst | 4 ++-- reference/forms/types/time.rst | 4 ++-- reference/forms/types/timezone.rst | 4 ++-- reference/forms/types/url.rst | 4 ++-- reference/forms/types/week.rst | 4 ++-- 31 files changed, 63 insertions(+), 65 deletions(-) diff --git a/forms.rst b/forms.rst index 6e2c9ec5120..8635b8fedbd 100644 --- a/forms.rst +++ b/forms.rst @@ -555,10 +555,9 @@ learn more about the validation constraints, please refer to the .. versionadded:: 5.2 - Validation messages for forms have been rewritten to be more user-friendly. - These newer messages can be enabled by setting the `legacy_error_messages` - option to "false". Details about these messages can be found in the corresponding - form type documentation. + In Symfony 5.2, the form validation messages have been rewritten to be more + user-friendly. Set the ``legacy_error_messages`` option to ``false`` to + enable these new messages: .. configuration-block:: @@ -595,7 +594,6 @@ learn more about the validation constraints, please refer to the ], ]); - Other Common Form Features -------------------------- diff --git a/reference/forms/types/birthday.rst b/reference/forms/types/birthday.rst index 127528bc774..94cff698cb4 100644 --- a/reference/forms/types/birthday.rst +++ b/reference/forms/types/birthday.rst @@ -49,9 +49,9 @@ option defaults to 120 years ago to the current year. | | - `mapped`_ | | | - `row_attr`_ | +---------------------------+-------------------------------------------------------------------------------+ -| Default `invalid_message` | Please enter a valid birthdate. | +| Default invalid message | Please enter a valid birthdate. | +---------------------------+-------------------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+-------------------------------------------------------------------------------+ | Parent type | :doc:`DateType ` | +---------------------------+-------------------------------------------------------------------------------+ diff --git a/reference/forms/types/checkbox.rst b/reference/forms/types/checkbox.rst index 1463c542a1e..d4fdd17580c 100644 --- a/reference/forms/types/checkbox.rst +++ b/reference/forms/types/checkbox.rst @@ -36,9 +36,9 @@ if you want to handle submitted values like "0" or "false"). | | - `required`_ | | | - `row_attr`_ | +---------------------------+------------------------------------------------------------------------+ -| Default `invalid_message` | The checkbox has an invalid value. | +| Default invalid message | The checkbox has an invalid value. | +---------------------------+------------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+------------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +---------------------------+------------------------------------------------------------------------+ diff --git a/reference/forms/types/choice.rst b/reference/forms/types/choice.rst index d0c81a829bd..affcce9ab54 100644 --- a/reference/forms/types/choice.rst +++ b/reference/forms/types/choice.rst @@ -52,9 +52,9 @@ To use this field, you must specify *either* ``choices`` or ``choice_loader`` op | | - `attr_translation_parameters`_ | | | - `help_translation_parameters`_ | +---------------------------+----------------------------------------------------------------------+ -| Default `invalid_message` | The selected choice is invalid. | +| Default invalid message | The selected choice is invalid. | +---------------------------+----------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+----------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +---------------------------+----------------------------------------------------------------------+ diff --git a/reference/forms/types/collection.rst b/reference/forms/types/collection.rst index a30cc250f6f..9e1eb170933 100644 --- a/reference/forms/types/collection.rst +++ b/reference/forms/types/collection.rst @@ -40,9 +40,9 @@ photos). | | - `required`_ | | | - `row_attr`_ | +---------------------------+--------------------------------------------------------------------------+ -| Default `invalid_message` | The collection is invalid. | +| Default invalid message | The collection is invalid. | +---------------------------+--------------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+--------------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +---------------------------+--------------------------------------------------------------------------+ diff --git a/reference/forms/types/color.rst b/reference/forms/types/color.rst index f3d97c6cd1b..6bbc28da2a7 100644 --- a/reference/forms/types/color.rst +++ b/reference/forms/types/color.rst @@ -38,9 +38,9 @@ element. | | - `row_attr`_ | | | - `trim`_ | +---------------------------+---------------------------------------------------------------------+ -| Default `invalid_message` | Please select a valid color. | +| Default invalid message | Please select a valid color. | +---------------------------+---------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+---------------------------------------------------------------------+ | Parent type | :doc:`TextType ` | +---------------------------+---------------------------------------------------------------------+ diff --git a/reference/forms/types/country.rst b/reference/forms/types/country.rst index a2b1527764e..10cf652947a 100644 --- a/reference/forms/types/country.rst +++ b/reference/forms/types/country.rst @@ -54,9 +54,9 @@ the option manually, but then you should just use the ``ChoiceType`` directly. | | - `required`_ | | | - `row_attr`_ | +---------------------------+-----------------------------------------------------------------------+ -| Default `invalid_message` | Please select a valid country. | +| Default invalid message | Please select a valid country. | +---------------------------+-----------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+-----------------------------------------------------------------------+ | Parent type | :doc:`ChoiceType ` | +---------------------------+-----------------------------------------------------------------------+ diff --git a/reference/forms/types/currency.rst b/reference/forms/types/currency.rst index e8628aa3edf..e28b39c328a 100644 --- a/reference/forms/types/currency.rst +++ b/reference/forms/types/currency.rst @@ -45,9 +45,9 @@ manually, but then you should just use the ``ChoiceType`` directly. | | - `required`_ | | | - `row_attr`_ | +---------------------------+------------------------------------------------------------------------+ -| Default `invalid_message` | Please select a valid currency. | +| Default invalid message | Please select a valid currency. | +---------------------------+------------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+------------------------------------------------------------------------+ | Parent type | :doc:`ChoiceType ` | +---------------------------+------------------------------------------------------------------------+ diff --git a/reference/forms/types/date.rst b/reference/forms/types/date.rst index fa696007803..5a12ad24b9c 100644 --- a/reference/forms/types/date.rst +++ b/reference/forms/types/date.rst @@ -46,9 +46,9 @@ and can understand a number of different input formats via the `input`_ option. | | - `mapped`_ | | | - `row_attr`_ | +---------------------------+-----------------------------------------------------------------------------+ -| Default `invalid_message` | Please enter a valid date. | +| Default invalid message | Please enter a valid date. | +---------------------------+-----------------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+-----------------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +---------------------------+-----------------------------------------------------------------------------+ diff --git a/reference/forms/types/dateinterval.rst b/reference/forms/types/dateinterval.rst index 69147d95bee..5248ca88739 100644 --- a/reference/forms/types/dateinterval.rst +++ b/reference/forms/types/dateinterval.rst @@ -50,9 +50,9 @@ or an array (see `input`_). | | - `mapped`_ | | | - `row_attr`_ | +---------------------------+----------------------------------------------------------------------------------+ -| Default `invalid_message` | Please choose a valid date interval. | +| Default invalid message | Please choose a valid date interval. | +---------------------------+----------------------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+----------------------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +---------------------------+----------------------------------------------------------------------------------+ diff --git a/reference/forms/types/datetime.rst b/reference/forms/types/datetime.rst index ca61be3e538..e742048fd24 100644 --- a/reference/forms/types/datetime.rst +++ b/reference/forms/types/datetime.rst @@ -55,9 +55,9 @@ the data can be a ``DateTime`` object, a string, a timestamp or an array. | | - `mapped`_ | | | - `row_attr`_ | +---------------------------+-----------------------------------------------------------------------------+ -| Default `invalid_message` | Please enter a valid date and time. | +| Default invalid message | Please enter a valid date and time. | +---------------------------+-----------------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+-----------------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +---------------------------+-----------------------------------------------------------------------------+ diff --git a/reference/forms/types/email.rst b/reference/forms/types/email.rst index 31d6f5db90b..3dfe77db44f 100644 --- a/reference/forms/types/email.rst +++ b/reference/forms/types/email.rst @@ -29,9 +29,9 @@ The ``EmailType`` field is a text field that is rendered using the HTML5 | | - `row_attr`_ | | | - `trim`_ | +---------------------------+---------------------------------------------------------------------+ -| Default `invalid_message` | Please enter a valid email address. | +| Default invalid message | Please enter a valid email address. | +---------------------------+---------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+---------------------------------------------------------------------+ | Parent type | :doc:`TextType ` | +---------------------------+---------------------------------------------------------------------+ diff --git a/reference/forms/types/file.rst b/reference/forms/types/file.rst index f745c9bc1fd..50bc55fee88 100644 --- a/reference/forms/types/file.rst +++ b/reference/forms/types/file.rst @@ -30,9 +30,9 @@ The ``FileType`` represents a file input in your form. | | - `required`_ | | | - `row_attr`_ | +---------------------------+--------------------------------------------------------------------+ -| Default `invalid_message` | Please select a valid file. | +| Default invalid message | Please select a valid file. | +---------------------------+--------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+--------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +---------------------------+--------------------------------------------------------------------+ diff --git a/reference/forms/types/form.rst b/reference/forms/types/form.rst index e406413bf37..9e1a5d47227 100644 --- a/reference/forms/types/form.rst +++ b/reference/forms/types/form.rst @@ -48,9 +48,9 @@ on all types for which ``FormType`` is the parent. | | - `label_translation_parameters`_ | | | - `attr_translation_parameters`_ | +---------------------------+--------------------------------------------------------------------+ -| Default `invalid_message` | This value is not valid. | +| Default invalid message | This value is not valid. | +---------------------------+--------------------------------------------------------------------+ -| Legacy `invalid_message` | This value is not valid. | +| Legacy invalid message | This value is not valid. | +---------------------------+--------------------------------------------------------------------+ | Parent | none | +---------------------------+--------------------------------------------------------------------+ diff --git a/reference/forms/types/hidden.rst b/reference/forms/types/hidden.rst index f0bddfa4260..00e858303bf 100644 --- a/reference/forms/types/hidden.rst +++ b/reference/forms/types/hidden.rst @@ -22,9 +22,9 @@ The hidden type represents a hidden input field. | | - `property_path`_ | | | - `row_attr`_ | +---------------------------+----------------------------------------------------------------------+ -| Default `invalid_message` | The hidden field is invalid. | +| Default invalid message | The hidden field is invalid. | +---------------------------+----------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+----------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +---------------------------+----------------------------------------------------------------------+ diff --git a/reference/forms/types/integer.rst b/reference/forms/types/integer.rst index 7eb32abf7f9..db774ec2ce9 100644 --- a/reference/forms/types/integer.rst +++ b/reference/forms/types/integer.rst @@ -39,9 +39,9 @@ integers. By default, all non-integer values (e.g. 6.78) will round down | | - `required`_ | | | - `row_attr`_ | +---------------------------+-----------------------------------------------------------------------+ -| Default `invalid_message` | Please enter an integer. | +| Default invalid message | Please enter an integer. | +---------------------------+-----------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+-----------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +---------------------------+-----------------------------------------------------------------------+ diff --git a/reference/forms/types/language.rst b/reference/forms/types/language.rst index 420ab1b59a0..f74016d1a0c 100644 --- a/reference/forms/types/language.rst +++ b/reference/forms/types/language.rst @@ -57,9 +57,9 @@ manually, but then you should just use the ``ChoiceType`` directly. | | - `required`_ | | | - `row_attr`_ | +---------------------------+------------------------------------------------------------------------+ -| Default `invalid_message` | Please select a valid language. | +| Default invalid message | Please select a valid language. | +---------------------------+------------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+------------------------------------------------------------------------+ | Parent type | :doc:`ChoiceType ` | +---------------------------+------------------------------------------------------------------------+ diff --git a/reference/forms/types/locale.rst b/reference/forms/types/locale.rst index be6dde7e950..bab466d262f 100644 --- a/reference/forms/types/locale.rst +++ b/reference/forms/types/locale.rst @@ -56,9 +56,9 @@ manually, but then you should just use the ``ChoiceType`` directly. | | - `required`_ | | | - `row_attr`_ | +---------------------------+----------------------------------------------------------------------+ -| Default `invalid_message` | Please select a valid locale. | +| Default invalid message | Please select a valid locale. | +---------------------------+----------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+----------------------------------------------------------------------+ | Parent type | :doc:`ChoiceType ` | +---------------------------+----------------------------------------------------------------------+ diff --git a/reference/forms/types/money.rst b/reference/forms/types/money.rst index ca7a5aceac7..162d8543b20 100644 --- a/reference/forms/types/money.rst +++ b/reference/forms/types/money.rst @@ -41,9 +41,9 @@ how the input and output of the data is handled. | | - `required`_ | | | - `row_attr`_ | +---------------------------+---------------------------------------------------------------------+ -| Default `invalid_message` | Please enter a valid money amount. | +| Default invalid message | Please enter a valid money amount. | +---------------------------+---------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+---------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +---------------------------+---------------------------------------------------------------------+ diff --git a/reference/forms/types/number.rst b/reference/forms/types/number.rst index 319c84b951e..99d80628d33 100644 --- a/reference/forms/types/number.rst +++ b/reference/forms/types/number.rst @@ -37,9 +37,9 @@ that you want to use for your number. | | - `required`_ | | | - `row_attr`_ | +---------------------------+----------------------------------------------------------------------+ -| Default `invalid_message` | Please enter a number. | +| Default invalid message | Please enter a number. | +---------------------------+----------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+----------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +---------------------------+----------------------------------------------------------------------+ diff --git a/reference/forms/types/password.rst b/reference/forms/types/password.rst index 10b38a5ac8b..18be51b396f 100644 --- a/reference/forms/types/password.rst +++ b/reference/forms/types/password.rst @@ -29,9 +29,9 @@ The ``PasswordType`` field renders an input password text box. | | - `required`_ | | | - `row_attr`_ | +---------------------------+------------------------------------------------------------------------+ -| Default `invalid_message` | The password is invalid. | +| Default invalid message | The password is invalid. | +---------------------------+------------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+------------------------------------------------------------------------+ | Parent type | :doc:`TextType ` | +---------------------------+------------------------------------------------------------------------+ diff --git a/reference/forms/types/percent.rst b/reference/forms/types/percent.rst index 3dd47e1d320..36ffdcc1e1b 100644 --- a/reference/forms/types/percent.rst +++ b/reference/forms/types/percent.rst @@ -41,9 +41,9 @@ the input. | | - `required`_ | | | - `row_attr`_ | +---------------------------+-----------------------------------------------------------------------+ -| Default `invalid_message` | Please enter a percentage value. | +| Default invalid message | Please enter a percentage value. | +---------------------------+-----------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+-----------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +---------------------------+-----------------------------------------------------------------------+ diff --git a/reference/forms/types/radio.rst b/reference/forms/types/radio.rst index 579dab0bc1d..93fbe3ecfd9 100644 --- a/reference/forms/types/radio.rst +++ b/reference/forms/types/radio.rst @@ -40,9 +40,9 @@ If you want to have a boolean field, use :doc:`CheckboxType ` | +---------------------------+---------------------------------------------------------------------+ diff --git a/reference/forms/types/range.rst b/reference/forms/types/range.rst index ab3a0d15859..f8284f1b7eb 100644 --- a/reference/forms/types/range.rst +++ b/reference/forms/types/range.rst @@ -28,9 +28,9 @@ The ``RangeType`` field is a slider that is rendered using the HTML5 | | - `row_attr`_ | | | - `trim`_ | +---------------------------+---------------------------------------------------------------------+ -| Default `invalid_message` | Please choose a valid range. | +| Default invalid message | Please choose a valid range. | +---------------------------+---------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+---------------------------------------------------------------------+ | Parent type | :doc:`TextType ` | +---------------------------+---------------------------------------------------------------------+ diff --git a/reference/forms/types/repeated.rst b/reference/forms/types/repeated.rst index 7a9f6d9d9be..8c36c64ddd5 100644 --- a/reference/forms/types/repeated.rst +++ b/reference/forms/types/repeated.rst @@ -32,9 +32,9 @@ accuracy. | | - `mapped`_ | | | - `row_attr`_ | +---------------------------+------------------------------------------------------------------------+ -| Default `invalid_message` | The values do not match. | +| Default invalid message | The values do not match. | +---------------------------+------------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+------------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +---------------------------+------------------------------------------------------------------------+ diff --git a/reference/forms/types/search.rst b/reference/forms/types/search.rst index f9c53733872..d6dceeb0264 100644 --- a/reference/forms/types/search.rst +++ b/reference/forms/types/search.rst @@ -30,9 +30,9 @@ Read about the input search field at `DiveIntoHTML5.info`_ | | - `row_attr`_ | | | - `trim`_ | +---------------------------+----------------------------------------------------------------------+ -| Default `invalid_message` | Please enter a valid search term. | +| Default invalid message | Please enter a valid search term. | +---------------------------+----------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+----------------------------------------------------------------------+ | Parent type | :doc:`TextType ` | +---------------------------+----------------------------------------------------------------------+ diff --git a/reference/forms/types/tel.rst b/reference/forms/types/tel.rst index fc45434bc4e..19847431dd3 100644 --- a/reference/forms/types/tel.rst +++ b/reference/forms/types/tel.rst @@ -35,9 +35,9 @@ to input phone numbers. | | - `row_attr`_ | | | - `trim`_ | +---------------------------+-------------------------------------------------------------------+ -| Default `invalid_message` | Please provide a valid phone number. | +| Default invalid message | Please provide a valid phone number. | +---------------------------+-------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+-------------------------------------------------------------------+ | Parent type | :doc:`TextType ` | +---------------------------+-------------------------------------------------------------------+ diff --git a/reference/forms/types/time.rst b/reference/forms/types/time.rst index 08c3efb77f4..cac168d569e 100644 --- a/reference/forms/types/time.rst +++ b/reference/forms/types/time.rst @@ -48,9 +48,9 @@ stored as a ``DateTime`` object, a string, a timestamp or an array. | | - `mapped`_ | | | - `row_attr`_ | +---------------------------+-----------------------------------------------------------------------------+ -| Default `invalid_message` | Please enter a valid time. | +| Default invalid message | Please enter a valid time. | +---------------------------+-----------------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+-----------------------------------------------------------------------------+ | Parent type | FormType | +---------------------------+-----------------------------------------------------------------------------+ diff --git a/reference/forms/types/timezone.rst b/reference/forms/types/timezone.rst index 64e17890de8..987f26c9036 100644 --- a/reference/forms/types/timezone.rst +++ b/reference/forms/types/timezone.rst @@ -50,9 +50,9 @@ manually, but then you should just use the ``ChoiceType`` directly. | | - `required`_ | | | - `row_attr`_ | +---------------------------+------------------------------------------------------------------------+ -| Default `invalid_message` | Please select a valid timezone. | +| Default invalid message | Please select a valid timezone. | +---------------------------+------------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+------------------------------------------------------------------------+ | Parent type | :doc:`ChoiceType ` | +---------------------------+------------------------------------------------------------------------+ diff --git a/reference/forms/types/url.rst b/reference/forms/types/url.rst index e5f782ce088..13f425f1d70 100644 --- a/reference/forms/types/url.rst +++ b/reference/forms/types/url.rst @@ -32,9 +32,9 @@ have a protocol. | | - `row_attr`_ | | | - `trim`_ | +---------------------------+-------------------------------------------------------------------+ -| Default `invalid_message` | Please enter a valid URL. | +| Default invalid message | Please enter a valid URL. | +---------------------------+-------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+-------------------------------------------------------------------+ | Parent type | :doc:`TextType ` | +---------------------------+-------------------------------------------------------------------+ diff --git a/reference/forms/types/week.rst b/reference/forms/types/week.rst index eb526c160af..99762f803e3 100644 --- a/reference/forms/types/week.rst +++ b/reference/forms/types/week.rst @@ -39,9 +39,9 @@ the data can be a string or an array. | | - `mapped`_ | | | - `row_attr`_ | +---------------------------+--------------------------------------------------------------------+ -| Default `invalid_message` | Please enter a valid week. | +| Default invalid message | Please enter a valid week. | +---------------------------+--------------------------------------------------------------------+ -| Legacy `invalid_message` | The value {{ value }} is not valid. | +| Legacy invalid message | The value {{ value }} is not valid. | +---------------------------+--------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +---------------------------+--------------------------------------------------------------------+ From 676403e7020add302de8df03e7f37c87211ea4d8 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 21 Nov 2020 20:42:54 +0100 Subject: [PATCH 0623/1519] Removed 4.3 versionadded directive --- reference/configuration/framework.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 9086078e30f..5d3f3cf1fde 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -2797,10 +2797,6 @@ Name of the lock you want to create. mailer ~~~~~~ -.. versionadded:: 4.3 - - The ``mailer`` settings were introduced in Symfony 4.3. - .. _mailer-dsn: dsn From 1da6b0b5e30017e126228a94893ce505ccbeb270 Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER Date: Mon, 17 Aug 2020 09:10:48 +0200 Subject: [PATCH 0624/1519] Complete documentation about mailer integration --- mailer.rst | 4 +++- reference/configuration/framework.rst | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/mailer.rst b/mailer.rst index ac768b09cde..8cab1b50659 100644 --- a/mailer.rst +++ b/mailer.rst @@ -46,6 +46,7 @@ over SMTP by configuring the DSN in your ``.env`` file (the ``user``, xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> + @@ -55,6 +56,7 @@ over SMTP by configuring the DSN in your ``.env`` file (the ``user``, // config/packages/mailer.php use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; + return static function (ContainerConfigurator $containerConfigurator): void { $containerConfigurator->extension('framework', [ 'mailer' => [ @@ -83,7 +85,7 @@ sendmail ``sendmail://default`` Mailer uses the local se Using a 3rd Party Transport ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Instead of using your own SMTP server, you can send emails via a 3rd party +Instead of using your own SMTP server or sendmail binary, you can send emails via a 3rd party provider. Mailer supports several - install whichever you want: ================== ============================================= diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 3174485f516..8fc30e2712a 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -155,6 +155,7 @@ Configuration * :ref:`dsn ` * `transports`_ + * `message_bus`_ * `envelope`_ * `sender`_ @@ -846,6 +847,8 @@ can be separated by colons, commas or spaces (e.g. ``'RC4-SHA:TLS13-AES-128-GCM- .. _http-headers: +.. _http-headers: + headers ....... @@ -2813,6 +2816,18 @@ transports A :ref:`list of DSN ` that can be used by the mailer. A transport name is the key and the dsn is the value. +message_bus +........... + +.. versionadded:: 5.1 + + The ``message_bus`` option was introduced in Symfony 5.1. + +**type**: ``string`` **default**: ``null`` or default bus if Messenger component is installed + +Service identifier of the message bus to use when using the +:doc:`Messenger component ` (e.g. ``messenger.default_bus``). + envelope ........ @@ -2867,6 +2882,7 @@ recipients set in the code. // config/packages/mailer.php namespace Symfony\Component\DependencyInjection\Loader\Configurator; + return static function (ContainerConfigurator $containerConfigurator): void { $containerConfigurator->extension('framework', [ 'mailer' => [ From a389dfb123e3bd9b6024399e21067c40822944ff Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER Date: Mon, 17 Aug 2020 09:10:48 +0200 Subject: [PATCH 0625/1519] Complete documentation about mailer integration --- mailer.rst | 20 +++++++++++++------- reference/configuration/framework.rst | 18 ++++++++++++++++-- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/mailer.rst b/mailer.rst index 200064fbbef..60575fed9e9 100644 --- a/mailer.rst +++ b/mailer.rst @@ -73,14 +73,20 @@ over SMTP by configuring the DSN in your ``.env`` file (the ``user``, Using Built-in Transports ~~~~~~~~~~~~~~~~~~~~~~~~~ -============ ======================================== ============================== +.. versionadded:: 5.2 + + The native protocol was introduced in Symfony 5.2. + +============ ======================================== ============================================================== DSN protocol Example Description -============ ======================================== ============================== -smtp ``smtp://user:pass@smtp.example.com:25`` Mailer uses an SMTP server to - send emails -sendmail ``sendmail://default`` Mailer uses the local sendmail - binary to send emails -============ ======================================== ============================== +============ ======================================== ============================================================== +smtp ``smtp://user:pass@smtp.example.com:25`` Mailer uses an SMTP server to send emails +sendmail ``sendmail://default`` Mailer uses the local sendmail binary to send emails +native ``native://default`` Mailer uses the sendmail binary and options configured + in the ``sendmail_path`` setting of ``php.ini``. On Windows + hosts, Mailer fallbacks to ``smtp`` and ``smtp_port`` + ``php.ini`` settings when ``sendmail_path`` is not configured. +============ ======================================== ============================================================== Using a 3rd Party Transport ~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 38388ad21f9..fdc11499c4b 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -184,6 +184,8 @@ Configuration * `sender`_ * `recipients`_ + * :ref:`headers ` + * `php_errors`_ * `log`_ @@ -927,8 +929,6 @@ This setting is automatically set to true when one of the child settings is conf .. _http-headers: -.. _http-headers: - headers ....... @@ -3091,6 +3091,20 @@ recipients set in the code. ]); }; +.. _mailer-headers: + +headers +....... + +.. versionadded:: 5.2 + + The ``headers`` mailer option was introduced in Symfony 5.2. + +**type**: ``array`` + +Headers to add to emails. The key (``name`` attribute in xml format) is the +header name and value the header value. + workflows ~~~~~~~~~ From 6b04c5f824e178cb6b0d9575b2068a0c56839c7e Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 21 Nov 2020 21:09:19 +0100 Subject: [PATCH 0626/1519] Removed duplicated line --- reference/configuration/framework.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 8fc30e2712a..0780b49b0b9 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -847,8 +847,6 @@ can be separated by colons, commas or spaces (e.g. ``'RC4-SHA:TLS13-AES-128-GCM- .. _http-headers: -.. _http-headers: - headers ....... From 034727f94ce8f1247d3ea7c18ff1bb2730522a41 Mon Sep 17 00:00:00 2001 From: Timo Bakx Date: Sat, 21 Nov 2020 18:34:04 +0100 Subject: [PATCH 0627/1519] [Form] Fixed the layout in the forms page by moving the configuration tabs outside the versionadded block. --- forms.rst | 65 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/forms.rst b/forms.rst index f7acdd18fe2..832a11ca075 100644 --- a/forms.rst +++ b/forms.rst @@ -560,46 +560,51 @@ To see the second approach - adding constraints to the form - and to learn more about the validation constraints, please refer to the :doc:`Symfony validation documentation `. +Form Validation Messages +~~~~~~~~~~~~~~~~~~~~~~~~ + .. versionadded:: 5.2 - In Symfony 5.2, the form validation messages have been rewritten to be more - user-friendly. Set the ``legacy_error_messages`` option to ``false`` to - enable these new messages: + The ``framework.form.legacy_error_messages`` option was introduced in Symfony 5.2 - .. configuration-block:: +The form validation messages have been rewritten to be more user-friendly. +To enable these new messages set the ``legacy_error_messages`` option in ``framework``, +``form`` to ``false``: + +.. configuration-block:: - .. code-block:: yaml + .. code-block:: yaml - # config/packages/framework.yaml - framework: - form: - legacy_error_messages: false + # config/packages/framework.yaml + framework: + form: + legacy_error_messages: false - .. code-block:: xml + .. code-block:: xml - - - + + + - - - - + + + + - .. code-block:: php + .. code-block:: php - // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'form' => [ - 'legacy-error-messages' => false, - ], - ]); + // config/packages/framework.php + $container->loadFromExtension('framework', [ + 'form' => [ + 'legacy_error_messages' => false, + ], + ]); Other Common Form Features -------------------------- From c4b9fc43192dbec06c0646b18b9afa529537f664 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 21 Nov 2020 23:11:15 +0100 Subject: [PATCH 0628/1519] [#14589] Reworded form error messages paragraph --- forms.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/forms.rst b/forms.rst index 832a11ca075..f6935d3d107 100644 --- a/forms.rst +++ b/forms.rst @@ -565,11 +565,11 @@ Form Validation Messages .. versionadded:: 5.2 - The ``framework.form.legacy_error_messages`` option was introduced in Symfony 5.2 + The ``legacy_error_messages`` option was introduced in Symfony 5.2 -The form validation messages have been rewritten to be more user-friendly. -To enable these new messages set the ``legacy_error_messages`` option in ``framework``, -``form`` to ``false``: +The form types have default error messages that are more clear and +user-friendly than the ones provided by the validation constraints. To enable +these new messages set the ``legacy_error_messages`` option to ``false``: .. configuration-block:: From b6777219bd16a04857f4cf3570a852fca5def089 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 21 Nov 2020 23:14:00 +0100 Subject: [PATCH 0629/1519] Fixed build --- reference/configuration/framework.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 5d9459ce97d..fdc11499c4b 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -927,6 +927,8 @@ enabled Whether to enable the support for retry failed HTTP request or not. This setting is automatically set to true when one of the child settings is configured. +.. _http-headers: + headers ....... From 07230432e2a85a77ca575abb771e597b06b1ad28 Mon Sep 17 00:00:00 2001 From: Matthieu DANET Date: Tue, 24 Nov 2020 10:35:10 +0100 Subject: [PATCH 0630/1519] Fix wrong key name --- reference/forms/types/options/choice_attr.rst.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/forms/types/options/choice_attr.rst.inc b/reference/forms/types/options/choice_attr.rst.inc index b26f2099023..5a0add4f195 100644 --- a/reference/forms/types/options/choice_attr.rst.inc +++ b/reference/forms/types/options/choice_attr.rst.inc @@ -49,7 +49,7 @@ If an array, the keys of the ``choices`` array must be used as keys:: // ... $builder->add('choices', ChoiceType::class, [ - 'choice_label' => ChoiceList::attr($this, function (?Category $category) { + 'choice_attr' => ChoiceList::attr($this, function (?Category $category) { return $category ? ['data-uuid' => $category->getUuid()] : []; }), ]); From 67eb42f6599876ae05c8b17cc7c25792350de662 Mon Sep 17 00:00:00 2001 From: Pierre du Plessis Date: Tue, 24 Nov 2020 21:11:35 +0200 Subject: [PATCH 0631/1519] Fix package name for OvhCloud notifier --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 9737df6395e..573ad0d942c 100644 --- a/notifier.rst +++ b/notifier.rst @@ -59,7 +59,7 @@ Service Package DSN ========== ================================ ==================================================== FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` -OvhCloud ``symfony/ovhcloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` +OvhCloud ``symfony/ovh-cloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` ========== ================================ ==================================================== From def35a7da9d49d627906d69aac68e0d597ceba4a Mon Sep 17 00:00:00 2001 From: Nyholm Date: Mon, 23 Nov 2020 15:29:56 +0100 Subject: [PATCH 0632/1519] [Notifier] Add better example for Slack DSN --- notifier.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/notifier.rst b/notifier.rst index 9737df6395e..cad35611ec0 100644 --- a/notifier.rst +++ b/notifier.rst @@ -149,6 +149,8 @@ Chatters are configured using the ``chatter_transports`` setting: # .env SLACK_DSN=slack://default/ID + # If your slack webhook looks like "https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX" then use: + SLACK_DSN=slack://default/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX .. configuration-block:: From cf8af6af4ab5f541b8f7bb155434cc769a1d301d Mon Sep 17 00:00:00 2001 From: Quentin Dequippe Date: Thu, 26 Nov 2020 09:54:54 +0100 Subject: [PATCH 0633/1519] Update messenger.rst --- messenger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index e9253431bd4..2f33d850cbc 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1202,7 +1202,7 @@ under the transport in ``messenger.yaml``: ====================== ====================================== =================================== ``access_key`` AWS access key ``account`` Identifier of the AWS account The owner of the credentials -``auto_setup`` Whether the table should be created ``true`` +``auto_setup`` Whether the queue should be created ``true`` automatically during send / get. ``buffer_size`` Number of messages to prefetch 9 ``endpoint`` Absolute URL to the SQS service https://sqs.eu-west-1.amazonaws.com From 89828678a7443848962d380b31980e22d893c75b Mon Sep 17 00:00:00 2001 From: gary houbre Date: Fri, 27 Nov 2020 12:49:56 +0100 Subject: [PATCH 0634/1519] Added Invalid Constant --- console.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/console.rst b/console.rst index 34dc50003f9..246ae474d48 100644 --- a/console.rst +++ b/console.rst @@ -57,6 +57,10 @@ want a command to create a user:: // or return this if some error happened during the execution // (it's equivalent to returning int(1)) // return Command::FAILURE; + + // or return this if there was invalid value during the execution + // (it's equivalent to returning int(2)) + // return Command::INVALID } } @@ -65,6 +69,10 @@ want a command to create a user:: The ``Command::SUCCESS`` and ``Command::FAILURE`` constants were introduced in Symfony 5.1. +.. versionadded:: 5.3 + + The ``Command::INVALID`` constants was introduced in Symfony 5.3 + Configuring the Command ----------------------- From d41389ad85d4812423919a7c8c1f8163006c1f38 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 27 Nov 2020 13:34:18 +0100 Subject: [PATCH 0635/1519] Tweak --- console.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/console.rst b/console.rst index 246ae474d48..58708719974 100644 --- a/console.rst +++ b/console.rst @@ -58,8 +58,8 @@ want a command to create a user:: // (it's equivalent to returning int(1)) // return Command::FAILURE; - // or return this if there was invalid value during the execution - // (it's equivalent to returning int(2)) + // or return this to indicate incorrect command usage; e.g. invalid options + // or missing arguments (it's equivalent to returning int(2)) // return Command::INVALID } } @@ -71,7 +71,7 @@ want a command to create a user:: .. versionadded:: 5.3 - The ``Command::INVALID`` constants was introduced in Symfony 5.3 + The ``Command::INVALID`` constant was introduced in Symfony 5.3 Configuring the Command ----------------------- From 36b60ac475fccea62f7ef338de5e26b9f2c7ed77 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Mon, 30 Nov 2020 16:43:45 +0100 Subject: [PATCH 0636/1519] [Security] Minor typo --- security/experimental_authenticators.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index 8a1b6081d84..c86622ba84d 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -337,7 +337,7 @@ The authenticator can be enabled using the ``custom_authenticators`` setting: - App\Security\ApiKeyAuthenticator # don't forget to also configure the entry_point if the - # authenticator implements AuthenticatorEntryPointInterface + # authenticator implements AuthenticationEntryPointInterface # entry_point: App\Security\CustomFormLoginAuthenticator .. code-block:: xml @@ -409,7 +409,7 @@ well as other pieces of information, like whether a password should be checked or if "remember me" functionality should be enabled. The default -:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Passport`. +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Passport` requires a user object and credentials. The following credential classes are supported by default: From 3c48f6898c6bf47849306e558c55158c98755da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Schlu=CC=88ter?= Date: Thu, 3 Dec 2020 11:24:58 +0100 Subject: [PATCH 0637/1519] [Notifier] Update information for slack on actual implementation --- notifier.rst | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/notifier.rst b/notifier.rst index a3bb15f2232..3145bce544c 100644 --- a/notifier.rst +++ b/notifier.rst @@ -145,29 +145,26 @@ GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_T LinkedIn ``symfony/linked-in-notifier`` ``linkedin://TOKEN:USER_ID@default`` Mattermost ``symfony/mattermost-notifier`` ``mattermost://TOKEN@ENDPOINT?channel=CHANNEL`` RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` -Slack ``symfony/slack-notifier`` ``slack://default/ID`` +Slack ``symfony/slack-notifier`` ``slack://TOKEN@default?channel=CHANNEL`` Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:APIKEY@ENDPOINT?channel=CHANNEL`` ========== ================================ =========================================================================== .. versionadded:: 5.1 - The Mattermost and RocketChat integrations were introduced in Symfony - 5.1. The Slack DSN changed in Symfony 5.1 to use Slack Incoming - Webhooks instead of legacy tokens. + The Mattermost and RocketChat integrations were introduced in Symfony 5.1. .. versionadded:: 5.2 The GoogleChat, LinkedIn, Zulip and Discord integrations were introduced in Symfony 5.2. + The Slack DSN changed in Symfony 5.2 to use Slack Web API again same as in 5.0. Chatters are configured using the ``chatter_transports`` setting: .. code-block:: bash # .env - SLACK_DSN=slack://default/ID - # If your slack webhook looks like "https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX" then use: - SLACK_DSN=slack://default/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX + SLACK_DSN=slack://TOKEN@default?channel=CHANNEL .. configuration-block:: From 9695d7ef573a24ad440c3b291bdd291fad83f390 Mon Sep 17 00:00:00 2001 From: Timo Bakx Date: Thu, 3 Dec 2020 22:24:10 +0100 Subject: [PATCH 0638/1519] [Debug] Added option to specify the event dispatcher in debug:event-dispatcher --- event_dispatcher.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/event_dispatcher.rst b/event_dispatcher.rst index 55e99a8da34..03630c2e5f0 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -322,6 +322,18 @@ its name: $ php bin/console debug:event-dispatcher kernel.exception +For the :doc:`new experimental Security ` +an event dispatcher per firewall was added. You can get the registered listeners +for a particular event dispatcher by using the ``--dispatcher`` option: + +.. code-block:: terminal + + $ php bin/console debug:event-dispatcher --dispatcher=security.event_dispatcher.main + +.. versionadded:: 5.3 + + The ``dispatcher`` option was introduced in Symfony 5.3. + Learn more ---------- From 4677e42c58bf87f72dd75150eb41f852acf7a576 Mon Sep 17 00:00:00 2001 From: Valentin Udaltsov Date: Sat, 5 Dec 2020 21:54:21 +0300 Subject: [PATCH 0639/1519] Changed iterable $forms to Traversable in the data mapper implementation example --- form/data_mappers.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/form/data_mappers.rst b/form/data_mappers.rst index f10d74813b0..24ff0716f5f 100644 --- a/form/data_mappers.rst +++ b/form/data_mappers.rst @@ -98,7 +98,7 @@ in your form type:: /** * @param Color|null $viewData */ - public function mapDataToForms($viewData, iterable $forms): void + public function mapDataToForms($viewData, \Traversable $forms): void { // there is no data yet, so nothing to prepopulate if (null === $viewData) { @@ -119,7 +119,7 @@ in your form type:: $forms['blue']->setData($viewData->getBlue()); } - public function mapFormsToData(iterable $forms, &$viewData): void + public function mapFormsToData(\Traversable $forms, &$viewData): void { /** @var FormInterface[] $forms */ $forms = iterator_to_array($forms); From 4e4924e22d2a53d39be593d31e895947b1d8e892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Schl=C3=A4pfer?= Date: Sat, 5 Dec 2020 16:45:37 +0100 Subject: [PATCH 0640/1519] [Cache] Document cache encryption using SodiumMarshaller --- cache.rst | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/cache.rst b/cache.rst index 58e3cd0b816..20d9af8999e 100644 --- a/cache.rst +++ b/cache.rst @@ -714,3 +714,86 @@ Clear all caches everywhere: .. code-block:: terminal $ php bin/console cache:pool:clear cache.global_clearer + +Encrypting the Cache +-------------------- + +.. versionadded:: 5.1 + + :class:`Symfony\\Component\\Cache\\Marshaller\\SodiumMarshaller` has been + introduced in Symfony 5.1. + +To encrypt the cache using ``libsodium``, you can use the +:class:`Symfony\\Component\\Cache\\Marshaller\\SodiumMarshaller`. + +.. note:: + + This will encrypt the values of the cache items, but not the cache keys. Be + careful not the leak sensitive data in the keys. + +Generate a key: + +.. code-block:: terminal + + $ php -r 'echo base64_encode(sodium_crypto_box_keypair());' + +And add it to your :doc:`secret store ` as +``CACHE_DECRYPTION_KEY`` and enable the ``SodiumMarshaller``: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/cache.yaml + services: + Symfony\Component\Cache\Marshaller\SodiumMarshaller: + decorates: cache.default_marshaller + arguments: + - ['%env(base64:CACHE_DECRYPTION_KEY)%'] + # use multiple keys in order to rotate them + #- ['%env(base64:CACHE_DECRYPTION_KEY)%', '%env(base64:OLD_CACHE_DECRYPTION_KEY)%'] + - '@Symfony\Component\Cache\Marshaller\SodiumMarshaller.inner' + + .. code-block:: xml + + + + + + + + redis://localhost + + env(base64:CACHE_DECRYPTION_KEY) + + + + + + + + + .. code-block:: php + + // config/packages/cache.php + use Symfony\Component\Cache\Marshaller\SodiumMarshaller; + + $container->register(SodiumMarshaller::class) + ->decorate('cache.default_marshaller') + ->addArgument(['env(base64:CACHE_DECRYPTION_KEY)']) + // use multiple keys in order to rotate them + // ->addArgument(['env(base64:CACHE_DECRYPTION_KEY)', 'env(base64:OLD_CACHE_DECRYPTION_KEY)']) + ->addArgument(service('@Symfony\Component\Cache\Marshaller\SodiumMarshaller.inner')); + +To rotate your encryption keys but still be able to read existing cache entries, +add the old encryption key to the service arguments. The first key will be used +for reading and writing, and the additional key(s) will only be used for reading. + +Once all cache items encrypted with the old key have expired, you can remove +`OLD_CACHE_DECRYPTION_KEY` completely. From 54fdf7a0771a2ea5a49886bd6cda6a7595d76742 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sun, 6 Dec 2020 12:16:03 +0100 Subject: [PATCH 0641/1519] [#14658] Minor tweaks to cache encryption section --- cache.rst | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/cache.rst b/cache.rst index 20d9af8999e..5f31c495e4b 100644 --- a/cache.rst +++ b/cache.rst @@ -720,31 +720,28 @@ Encrypting the Cache .. versionadded:: 5.1 - :class:`Symfony\\Component\\Cache\\Marshaller\\SodiumMarshaller` has been - introduced in Symfony 5.1. + The :class:`Symfony\\Component\\Cache\\Marshaller\\SodiumMarshaller` + class was introduced in Symfony 5.1. To encrypt the cache using ``libsodium``, you can use the :class:`Symfony\\Component\\Cache\\Marshaller\\SodiumMarshaller`. -.. note:: - - This will encrypt the values of the cache items, but not the cache keys. Be - careful not the leak sensitive data in the keys. - -Generate a key: +First, you need to generate a secure key and add it to your :doc:`secret +store ` as ``CACHE_DECRYPTION_KEY``: .. code-block:: terminal $ php -r 'echo base64_encode(sodium_crypto_box_keypair());' -And add it to your :doc:`secret store ` as -``CACHE_DECRYPTION_KEY`` and enable the ``SodiumMarshaller``: +Then, register the ``SodiumMarshaller`` service using this key: .. configuration-block:: .. code-block:: yaml # config/packages/cache.yaml + + # ... services: Symfony\Component\Cache\Marshaller\SodiumMarshaller: decorates: cache.default_marshaller @@ -766,13 +763,14 @@ And add it to your :doc:`secret store ` as http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> + + - redis://localhost env(base64:CACHE_DECRYPTION_KEY) - + @@ -783,17 +781,22 @@ And add it to your :doc:`secret store ` as // config/packages/cache.php use Symfony\Component\Cache\Marshaller\SodiumMarshaller; + use Symfony\Component\DependencyInjection\ChildDefinition; + use Symfony\Component\DependencyInjection\Reference; - $container->register(SodiumMarshaller::class) - ->decorate('cache.default_marshaller') + // ... + $container->setDefinition(SodiumMarshaller::class, new ChildDefinition('cache.default_marshaller')) ->addArgument(['env(base64:CACHE_DECRYPTION_KEY)']) // use multiple keys in order to rotate them - // ->addArgument(['env(base64:CACHE_DECRYPTION_KEY)', 'env(base64:OLD_CACHE_DECRYPTION_KEY)']) - ->addArgument(service('@Symfony\Component\Cache\Marshaller\SodiumMarshaller.inner')); + //->addArgument(['env(base64:CACHE_DECRYPTION_KEY)', 'env(base64:OLD_CACHE_DECRYPTION_KEY)']) + ->addArgument(new Reference(SodiumMarshaller::class.'.inner')); -To rotate your encryption keys but still be able to read existing cache entries, -add the old encryption key to the service arguments. The first key will be used -for reading and writing, and the additional key(s) will only be used for reading. +.. caution:: + + This will encrypt the values of the cache items, but not the cache keys. Be + careful not the leak sensitive data in the keys. -Once all cache items encrypted with the old key have expired, you can remove -`OLD_CACHE_DECRYPTION_KEY` completely. +When configuring multiple keys, the first key will be used for reading and +writing, and the additional key(s) will only be used for reading. Once all +cache items encrypted with the old key have expired, you can remove +``OLD_CACHE_DECRYPTION_KEY`` completely. From e60cd0edd2ebd14a577ab18a9d404835c79dd2d2 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Fri, 4 Dec 2020 11:51:53 +0100 Subject: [PATCH 0642/1519] Added config reference for router.default_uri --- reference/configuration/framework.rst | 9 +++++++++ routing.rst | 2 ++ 2 files changed, 11 insertions(+) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 0780b49b0b9..833329a8d44 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -190,6 +190,7 @@ Configuration * `router`_ + * `default_uri`_ * `http_port`_ * `https_port`_ * `resource`_ @@ -1145,6 +1146,14 @@ The type of the resource to hint the loaders about the format. This isn't needed when you use the default routers with the expected file extensions (``.xml``, ``.yaml``, ``.php``). +default_uri +........... + +**type**: ``string`` + +The default URI used to generate URLs in a non-HTTP context (see +:ref:`Generating URLs in Commands `). + http_port ......... diff --git a/routing.rst b/routing.rst index e8f5bb91b83..ec6de557b5d 100644 --- a/routing.rst +++ b/routing.rst @@ -2055,6 +2055,8 @@ If you need to generate URLs dynamically or if you are using pure JavaScript code, this solution doesn't work. In those cases, consider using the `FOSJsRoutingBundle`_. +.. _router-generate-urls-commands: + Generating URLs in Commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 2ed719f9b47fdc5e87a3253d19f7a1f853de0c15 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 7 Dec 2020 08:24:35 +0100 Subject: [PATCH 0643/1519] Added the versionadded directive --- reference/configuration/framework.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 833329a8d44..0e61184b6be 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1151,6 +1151,10 @@ default_uri **type**: ``string`` +.. versionadded:: 5.1 + + The ``default_uri`` option was introduced in Symfony 5.1. + The default URI used to generate URLs in a non-HTTP context (see :ref:`Generating URLs in Commands `). From e68926ff9c76c82081de84c515d71e85280e07d2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 7 Dec 2020 08:27:54 +0100 Subject: [PATCH 0644/1519] Reword --- event_dispatcher.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/event_dispatcher.rst b/event_dispatcher.rst index 03630c2e5f0..ed6740cc162 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -322,9 +322,9 @@ its name: $ php bin/console debug:event-dispatcher kernel.exception -For the :doc:`new experimental Security ` -an event dispatcher per firewall was added. You can get the registered listeners -for a particular event dispatcher by using the ``--dispatcher`` option: +The :doc:`new experimental Security ` +system adds an event dispatcher per firewall. Use the ``--dispatcher`` option to +get the registered listeners for a particular event dispatcher: .. code-block:: terminal From 3f0bf94b2a5a93df1950fa06588777032e4f02c3 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sat, 5 Dec 2020 17:28:42 +0100 Subject: [PATCH 0645/1519] [EventDispatcher] Show partial matching for debug:event-dispatcher --- event_dispatcher.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/event_dispatcher.rst b/event_dispatcher.rst index ed6740cc162..038a405b10b 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -322,6 +322,17 @@ its name: $ php bin/console debug:event-dispatcher kernel.exception +or can get everything which partial matches the event name: + +.. code-block:: terminal + + $ php bin/console debug:event-dispatcher kernel // matches "kernel.exception", "kernel.response" etc. + $ php bin/console debug:event-dispatcher Security // matches "Symfony\Component\Security\Http\Event\CheckPassportEvent" + +.. versionadded:: 5.3 + + The ability to match partial event names was introduced in Symfony 5.3. + The :doc:`new experimental Security ` system adds an event dispatcher per firewall. Use the ``--dispatcher`` option to get the registered listeners for a particular event dispatcher: From bd44d05db34f5c9b624cadbbdbd042e34bf23e10 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 7 Dec 2020 12:03:43 +0100 Subject: [PATCH 0646/1519] minor --- notifier/chatters.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/notifier/chatters.rst b/notifier/chatters.rst index 40e9cea2096..1183de984d7 100644 --- a/notifier/chatters.rst +++ b/notifier/chatters.rst @@ -46,9 +46,9 @@ you to send messages to chat services like Slack or Telegram:: Adding Interactions to a Slack Message -------------------------------------- -With a Slack message, you can use the -:class:`Symfony\\Component\\Notifier\\Bridge\\Slack\\SlackOptions` to add -some interactive options called `Block elements`_:: +With a Slack message, you can use the +:class:`Symfony\\Component\\Notifier\\Bridge\\Slack\\SlackOptions` class +to add some interactive options called `Block elements`_:: use Symfony\Component\Notifier\Bridge\Slack\Block\SlackActionsBlock; use Symfony\Component\Notifier\Bridge\Slack\Block\SlackDividerBlock; From f62f89a054c59166adf51375501b120691b04bf7 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 7 Dec 2020 12:04:43 +0100 Subject: [PATCH 0647/1519] minor --- notifier/chatters.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notifier/chatters.rst b/notifier/chatters.rst index 50f3e5bc20f..4a10ad109d2 100644 --- a/notifier/chatters.rst +++ b/notifier/chatters.rst @@ -104,8 +104,8 @@ Adding Interactions to a Discord Message ---------------------------------------- With a Discord message, you can use the -:class:`Symfony\\Component\\Notifier\\Bridge\\Discord\\DiscordOptions` to add -some interactive options called `Embed elements`_:: +:class:`Symfony\\Component\\Notifier\\Bridge\\Discord\\DiscordOptions` class +to add some interactive options called `Embed elements`_:: use Symfony\Component\Notifier\Bridge\Discord\DiscordOptions; use Symfony\Component\Notifier\Bridge\Discord\Embeds\DiscordEmbed; From 25c651959497529779d3d2ec7ca0dae8744dd2c1 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 7 Dec 2020 12:10:03 +0100 Subject: [PATCH 0648/1519] Use constant over int. refs #14648 --- console/lockable_trait.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/console/lockable_trait.rst b/console/lockable_trait.rst index 7745874a764..9c77073d087 100644 --- a/console/lockable_trait.rst +++ b/console/lockable_trait.rst @@ -38,8 +38,8 @@ that adds two convenient methods to lock and release commands:: // if not released explicitly, Symfony releases the lock // automatically when the execution of the command ends $this->release(); - - return 0; + + return Command:SUCCESS; } } From 4239d4eb515786acdc698f302bc36339007a0ef5 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 7 Dec 2020 15:08:01 +0100 Subject: [PATCH 0649/1519] minor --- console.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console.rst b/console.rst index 25dd6b76924..18f39f1edd4 100644 --- a/console.rst +++ b/console.rst @@ -45,7 +45,7 @@ want a command to create a user:: protected function execute(InputInterface $input, OutputInterface $output) { - // ... put here the code to to create the user + // ... put here the code to create the user // this method must return an integer number with the "exit status code" // of the command. You can also use these constants to make code more readable From 46d1f1ae56fbb04df4ff050e6efa9673fb5165de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Renan=20Gon=C3=A7alves?= Date: Mon, 7 Dec 2020 15:34:33 +0100 Subject: [PATCH 0650/1519] Support Redis Sentinel mode when using phpredis/phpredis extension See https://github.com/symfony/symfony/pull/39363 --- components/cache/adapters/redis_adapter.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/cache/adapters/redis_adapter.rst b/components/cache/adapters/redis_adapter.rst index 64bf7ab9e4c..7846cde5200 100644 --- a/components/cache/adapters/redis_adapter.rst +++ b/components/cache/adapters/redis_adapter.rst @@ -95,8 +95,8 @@ Below are common examples of valid DSNs showing a combination of available value ); `Redis Sentinel`_, which provides high availability for Redis, is also supported -when using the Predis library. Use the ``redis_sentinel`` parameter to set the -name of your service group:: +when using the PHP Redis Extension v5.2+ or the Predis library. Use the ``redis_sentinel`` +parameter to set the name of your service group:: RedisAdapter::createConnection( 'redis:?host[redis1:26379]&host[redis2:26379]&host[redis3:26379]&redis_sentinel=mymaster' From fb8dea5501e50386f7ed9d7e9d83750055a75540 Mon Sep 17 00:00:00 2001 From: Florent <73140597+flovrent@users.noreply.github.com> Date: Mon, 7 Dec 2020 16:52:47 +0100 Subject: [PATCH 0651/1519] Update mercure.rst --- mercure.rst | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/mercure.rst b/mercure.rst index 8c0f52f8039..9222ddc68c5 100644 --- a/mercure.rst +++ b/mercure.rst @@ -408,7 +408,7 @@ And here is the controller:: // src/Controller/DiscoverController.php namespace App\Controller; - use Lcobucci\JWT\Builder; + use Lcobucci\JWT\Configuration; use Lcobucci\JWT\Signer\Hmac\Sha256; use Lcobucci\JWT\Signer\Key; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -423,11 +423,14 @@ And here is the controller:: { $hubUrl = $this->getParameter('mercure.default_hub'); $this->addLink($request, new Link('mercure', $hubUrl)); - - $token = (new Builder()) - // set other appropriate JWT claims, such as an expiration date - ->withClaim('mercure', ['subscribe' => ["http://example.com/books/1"]]) // can also be a URI template, or * - ->getToken(new Sha256(), new Key($this->getParameter('mercure_secret_key'))); // don't forget to set this parameter! Test value: !ChangeMe! + + $key = Key\InMemory::plainText('mercure_secret_key'); // don't forget to set this parameter! Test value: !ChangeMe! + $configuration = Configuration::forSymmetricSigner(new Sha256(), $key); + + $token = $configuration->builder() + ->withClaim('mercure', ['subscribe' => ["http://example.com/books/1"]]) // can also be a URI template, or * + ->getToken($configuration->signer(), $configuration->signingKey()) + ->toString(); $response = $this->json(['@id' => '/demo/books/1', 'availability' => 'https://schema.org/InStock']); $cookie = Cookie::create('mercureAuthorization') From 8c21f36cb139d30907404fa831fe1cd8e499fccf Mon Sep 17 00:00:00 2001 From: Julien Falque Date: Wed, 29 Jul 2020 18:35:18 +0200 Subject: [PATCH 0652/1519] Document routing inline requirements and defaults for host --- routing.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/routing.rst b/routing.rst index d879feac6e3..39cb575ed8d 100644 --- a/routing.rst +++ b/routing.rst @@ -790,6 +790,11 @@ concise, but it can decrease route readability when requirements are complex: // ... }; +.. versionadded:: 5.2 + + Since Symfony 5.2, inline parameter requirements are also supported in the + host. Before Symfony 5.2, they were supported in the path only. + Optional Parameters ~~~~~~~~~~~~~~~~~~~ @@ -984,6 +989,11 @@ parameter: To give a ``null`` default value to any parameter, add nothing after the ``?`` character (e.g. ``/blog/{page?}``). +.. versionadded:: 5.2 + + Since Symfony 5.2, inline parameter default values are also supported in + the host. Before Symfony 5.2, they were supported in the path only. + Priority Parameter ~~~~~~~~~~~~~~~~~~ From d232aa9f524045720b2d6d1b114440911a3470c8 Mon Sep 17 00:00:00 2001 From: Peter Bottenberg Date: Fri, 30 Oct 2020 17:55:57 +0100 Subject: [PATCH 0653/1519] [Notifier] Add documentation for telegram options --- notifier/chatters.rst | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/notifier/chatters.rst b/notifier/chatters.rst index 9d03f83987c..764f05320a8 100644 --- a/notifier/chatters.rst +++ b/notifier/chatters.rst @@ -98,8 +98,6 @@ some interactive options called `Block elements`_:: $chatter->send($chatMessage); -.. _`Block elements`: https://api.slack.com/reference/block-kit/block-elements - Adding Interactions to a Discord Message ---------------------------------------- @@ -151,4 +149,38 @@ some interactive options called `Embed elements`_:: $chatter->send($chatMessage); +Adding Interactions to a Telegram Message +----------------------------------------- + +With a Telegram message, you can use the +:class:`Symfony\\Component\\Notifier\\Bridge\\Telegram\\TelegramOptions` class +to add `message options`_:: + + use Symfony\Component\Notifier\Bridge\Telegram\Reply\Markup\Button\InlineKeyboardButton; + use Symfony\Component\Notifier\Bridge\Telegram\Reply\Markup\InlineKeyboardMarkup; + use Symfony\Component\Notifier\Bridge\Telegram\TelegramOptions; + use Symfony\Component\Notifier\Message\ChatMessage; + + $chatMessage = new ChatMessage(''); + + // Create Telegram options + $telegramOptions = (new TelegramOptions()) + ->chatId('@symfonynotifierdev') + ->parseMode('MarkdownV2') + ->disableWebPagePreview(true) + ->disableNotification(true) + ->replyMarkup((new InlineKeyboardMarkup()) + ->inlineKeyboard([ + (new InlineKeyboardButton('Visit symfony.com')) + ->url('https://symfony.com/'), + ]) + ); + + // Add the custom options to the chat message and send the message + $chatMessage->options($telegramOptions); + + $chatter->send($chatMessage); + +.. _`Block elements`: https://api.slack.com/reference/block-kit/block-elements .. _`Embed elements`: https://discord.com/developers/docs/resources/webhook +.. _`message options`: https://core.telegram.org/bots/api From 8cf987fceb64f0974e0e289a190f9951b1d2d01c Mon Sep 17 00:00:00 2001 From: Steven DUBOIS Date: Mon, 7 Dec 2020 18:09:06 +0100 Subject: [PATCH 0654/1519] Update experimental_authenticators : add UserBadge --- security/experimental_authenticators.rst | 36 +++++++++++++----------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index 382469c4566..2870eab1830 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -295,8 +295,8 @@ method that fits most use-cases:: use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; - use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; + use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface; use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport; @@ -328,14 +328,7 @@ method that fits most use-cases:: throw new CustomUserMessageAuthenticationException('No API token provided'); } - $user = $this->entityManager->getRepository(User::class) - ->findOneBy(['apiToken' => $apiToken]) - ; - if (null === $user) { - throw new UsernameNotFoundException(); - } - - return new SelfValidatingPassport($user); + return new SelfValidatingPassport(new UserBadge($apiToken)); } public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response @@ -472,12 +465,23 @@ are supported by default: $apiToken )); -.. note:: - If you don't need any credentials to be checked (e.g. a JWT token), you - can use the - :class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\SelfValidatingPassport`. - This class only requires a user and optionally `Passport Badges`_. +Self Validating Passport +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If you don't need any credentials to be checked (e.g. a JWT token), you can use the +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\SelfValidatingPassport`. +This class only requires a ``UserBadge`` object and optionally `Passport Badges`_. + +You can also pass a user loader to the ``UserBadge``. This callable receives the +``$userIdentifier`` as argument and must return a ``UserInterface`` object +(otherwise a ``UsernameNotFoundException`` is thrown). If this is not set, +the default user provider will be used with ``$userIdentifier`` as username:: + + // ... + return new SelfValidatingPassport(new UserBadge($email, function ($username) { + return $this->userRepository->findOneBy(['email' => $username]); + }); + Passport Badges ~~~~~~~~~~~~~~~ @@ -547,7 +551,7 @@ authenticator, you would initialize the passport like this:: ``createAuthenticatedToken()``):: // ... - use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; class LoginAuthenticator extends AbstractAuthenticator { @@ -557,7 +561,7 @@ authenticator, you would initialize the passport like this:: { // ... process the request - $passport = new SelfValidatingPassport($username, []); + $passport = new SelfValidatingPassport(new UserBadge($username), []); // set a custom attribute (e.g. scope) $passport->setAttribute('scope', $oauthScope); From 01cb2b0937d849aeffff344ead36626aaa93d4ea Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Tue, 8 Dec 2020 15:20:20 +0100 Subject: [PATCH 0655/1519] [#14672] Updated more docs related to the UserBadge --- security/experimental_authenticators.rst | 88 ++++++++++++++++-------- 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index 2870eab1830..35aa1c9c205 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -435,23 +435,61 @@ into a security Security Passports ~~~~~~~~~~~~~~~~~~ +.. versionadded:: 5.2 + + The ``UserBadge`` was introduced in Symfony 5.2. Prior to 5.2, the user + instance was provided directly to the passport. + A passport is an object that contains the user that will be authenticated as well as other pieces of information, like whether a password should be checked or if "remember me" functionality should be enabled. The default :class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Passport` -requires a user object and credentials. The following credential classes -are supported by default: +requires a user and credentials. + +Use the +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\UserBadge` +to attach the user to the passport. The ``UserBadge`` requires a user +identifier (e.g. the username or email), which is used to load the user +using :ref:`the user provider `:: + + use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; + + // ... + $passport = new Passport(new UserBadge($email), $credentials); + +.. note:: + You can optionally pass a user loader as second argument to the + ``UserBadge``. This callable receives the ``$userIdentifier`` + and must return a ``UserInterface`` object (otherwise a + ``UsernameNotFoundException`` is thrown):: + + // ... + $passport = new Passport( + new UserBadge($email, function ($userIdentifier) { + return $this->userRepository->findOneBy(['email' => $userIdentifier]); + }), + $credentials + ); + +The following credential classes are supported by default: :class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Credentials\\PasswordCredentials` This requires a plaintext ``$password``, which is validated using the - :ref:`password encoder configured for the user `. + :ref:`password encoder configured for the user `:: + + use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials; + + // ... + return new Passport($user, new PasswordCredentials($plaintextPassword)); :class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Credentials\\CustomCredentials` Allows a custom closure to check credentials:: + use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\CustomCredentials; + // ... return new Passport($user, new CustomCredentials( // If this function returns anything else than `true`, the credentials @@ -467,21 +505,13 @@ are supported by default: Self Validating Passport -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If you don't need any credentials to be checked (e.g. a JWT token), you can use the -:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\SelfValidatingPassport`. -This class only requires a ``UserBadge`` object and optionally `Passport Badges`_. - -You can also pass a user loader to the ``UserBadge``. This callable receives the -``$userIdentifier`` as argument and must return a ``UserInterface`` object -(otherwise a ``UsernameNotFoundException`` is thrown). If this is not set, -the default user provider will be used with ``$userIdentifier`` as username:: - - // ... - return new SelfValidatingPassport(new UserBadge($email, function ($username) { - return $this->userRepository->findOneBy(['email' => $username]); - }); +........................ +If you don't need any credentials to be checked (e.g. when using API +tokens), you can use the +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\SelfValidatingPassport`. +This class only requires a ``UserBadge`` object and optionally `Passport +Badges`_. Passport Badges ~~~~~~~~~~~~~~~ @@ -511,8 +541,13 @@ the following badges are supported: initiated). This skips the :doc:`pre-authentication user checker `. -For instance, if you want to add CSRF and password migration to your custom -authenticator, you would initialize the passport like this:: +.. versionadded:: 5.2 + + Since 5.2, the ``PasswordUpgradeBadge`` is automatically added to + the passport if the passport has ``PasswordCredentials``. + +For instance, if you want to add CSRF to your custom authenticator, you +would initialize the passport like this:: // src/Service/LoginAuthenticator.php namespace App\Service; @@ -520,7 +555,7 @@ authenticator, you would initialize the passport like this:: // ... use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge; - use Symfony\Component\Security\Http\Authenticator\Passport\Badge\PasswordUpgradeBadge; + use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Passport; use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface; @@ -532,14 +567,13 @@ authenticator, you would initialize the passport like this:: $username = $request->request->get('username'); $csrfToken = $request->request->get('csrf_token'); - // ... get the $user from the $username and validate no - // parameter is empty + // ... validate no parameter is empty - return new Passport($user, new PasswordCredentials($password), [ - // $this->userRepository must implement PasswordUpgraderInterface - new PasswordUpgradeBadge($password, $this->userRepository), - new CsrfTokenBadge('login', $csrfToken), - ]); + return new Passport( + new UserBadge($user), + new PasswordCredentials($password), + [new CsrfTokenBadge('login', $csrfToken)] + ); } } From 1ae411bfcd845af42b14bcd61295f2851009c38b Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Wed, 9 Dec 2020 11:39:05 +0100 Subject: [PATCH 0656/1519] [#14671] Added example of inline host defaults/requirements --- routing.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/routing.rst b/routing.rst index 39cb575ed8d..bcd6daec811 100644 --- a/routing.rst +++ b/routing.rst @@ -790,11 +790,6 @@ concise, but it can decrease route readability when requirements are complex: // ... }; -.. versionadded:: 5.2 - - Since Symfony 5.2, inline parameter requirements are also supported in the - host. Before Symfony 5.2, they were supported in the path only. - Optional Parameters ~~~~~~~~~~~~~~~~~~~ @@ -989,11 +984,6 @@ parameter: To give a ``null`` default value to any parameter, add nothing after the ``?`` character (e.g. ``/blog/{page?}``). -.. versionadded:: 5.2 - - Since Symfony 5.2, inline parameter default values are also supported in - the host. Before Symfony 5.2, they were supported in the path only. - Priority Parameter ~~~~~~~~~~~~~~~~~~ @@ -2046,6 +2036,16 @@ these routes. // ['HTTP_HOST' => 'm.' . $client->getContainer()->getParameter('domain')] ); +.. tip:: + + You can also use the inline defaults and requirements format in the + ``host`` option: ``{subdomain?m}.example.com`` + +.. versionadded:: 5.2 + + Inline parameter default values support in hosts were introduced in + Symfony 5.2. Prior to Symfony 5.2, they were supported in the path only. + .. _i18n-routing: Localized Routes (i18n) From 6fc13f253eda907f73ef2ededdbb77a3a3521e3f Mon Sep 17 00:00:00 2001 From: Alexander Frolov Date: Wed, 9 Dec 2020 13:00:18 -0500 Subject: [PATCH 0657/1519] Update setup page for Symfony 5.2 - drop dev Since 5.2 is already released there is no reason to point to `next` version When merged, fixes #14663 --- setup.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.rst b/setup.rst index 8e8f7c5610e..dbcb153dac7 100644 --- a/setup.rst +++ b/setup.rst @@ -50,10 +50,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_name --version=next --full + $ symfony new my_project_name --full # run this if you are building a microservice, console application or API - $ symfony new my_project_name --version=next + $ symfony new my_project_name The only difference between these two commands is the number of packages installed by default. The ``--full`` option installs all the packages that you @@ -65,10 +65,10 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/website-skeleton:"5.2.x@dev" my_project_name + $ composer create-project symfony/website-skeleton my_project_name # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton:"5.2.x@dev" my_project_name + $ composer create-project symfony/skeleton my_project_name No matter which command you run to create the Symfony application. All of them will create a new ``my_project_name/`` directory, download some dependencies From 2773a4168977aa98371a578759a78df7ae15037c Mon Sep 17 00:00:00 2001 From: Alexander Frolov Date: Wed, 9 Dec 2020 13:07:12 -0500 Subject: [PATCH 0658/1519] Update setup page for Symfony 5.1 - add version Since 5.2 is now the current version it makes sense to add version to `symfony` and `composer create-project` example commands --- setup.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.rst b/setup.rst index dbcb153dac7..5ad11c5b693 100644 --- a/setup.rst +++ b/setup.rst @@ -50,10 +50,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_name --full + $ symfony new my_project_name --version=5.1 --full # run this if you are building a microservice, console application or API - $ symfony new my_project_name + $ symfony new my_project_name --version=5.1 The only difference between these two commands is the number of packages installed by default. The ``--full`` option installs all the packages that you @@ -65,10 +65,10 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/website-skeleton my_project_name + $ composer create-project symfony/website-skeleton:"5.1.*" my_project_name # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton my_project_name + $ composer create-project symfony/skeleton:"5.1.*" my_project_name No matter which command you run to create the Symfony application. All of them will create a new ``my_project_name/`` directory, download some dependencies From 8e39f4592c1094898a3abc50728e72c30d2509d9 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Thu, 10 Dec 2020 12:39:49 +0100 Subject: [PATCH 0659/1519] Updated Composer commands to install 5.3@dev --- setup.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.rst b/setup.rst index dbcb153dac7..0433e8af360 100644 --- a/setup.rst +++ b/setup.rst @@ -50,10 +50,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_name --full + $ symfony new my_project_name --version=next --full # run this if you are building a microservice, console application or API - $ symfony new my_project_name + $ symfony new my_project_name --version=next The only difference between these two commands is the number of packages installed by default. The ``--full`` option installs all the packages that you @@ -65,10 +65,10 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/website-skeleton my_project_name + $ composer create-project symfony/website-skeleton:"5.3.x@dev' my_project_name # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton my_project_name + $ composer create-project symfony/skeleton:"5.3.x@dev' my_project_name No matter which command you run to create the Symfony application. All of them will create a new ``my_project_name/`` directory, download some dependencies From f7ae0fa09d5d4680b12b03cb4112912e98090133 Mon Sep 17 00:00:00 2001 From: Pierre du Plessis Date: Fri, 11 Dec 2020 10:31:38 +0200 Subject: [PATCH 0660/1519] Fix config keys for rate limiter The `lock` and `storage` keys have been updated to `lock_factory` and `storage_service` respectively. --- rate_limiter.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index f5473607fe7..403aa9c462f 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -260,8 +260,8 @@ Rate Limiter Storage and Locking -------------------------------- Rate limiters use the default cache and locking mechanisms defined in your -Symfony application. If you prefer to change that, use the ``lock`` and -``storage`` options: +Symfony application. If you prefer to change that, use the ``lock_factory`` and +``storage_service`` options: .. code-block:: yaml @@ -274,9 +274,9 @@ Symfony application. If you prefer to change that, use the ``lock`` and cache_pool: 'app.redis_cache' # or define a service implementing StorageInterface to use a different # mechanism to store the limiter information - storage: 'App\RateLimiter\CustomRedisStorage' + storage_service: 'App\RateLimiter\CustomRedisStorage' # the value is the name of any lock defined in your application - lock: 'app.rate_limiter_lock' + lock_factory: 'app.rate_limiter_lock' .. _`token bucket algorithm`: https://en.wikipedia.org/wiki/Token_bucket .. _`PHP date relative formats`: https://www.php.net/datetime.formats.relative From 25e530fba5ce6cb43abbdd0e04aabc1392451e0e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 11 Dec 2020 16:02:44 +0100 Subject: [PATCH 0661/1519] Fixed code syntax of previous change --- mercure.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mercure.rst b/mercure.rst index 9222ddc68c5..c533c07fad7 100644 --- a/mercure.rst +++ b/mercure.rst @@ -428,9 +428,9 @@ And here is the controller:: $configuration = Configuration::forSymmetricSigner(new Sha256(), $key); $token = $configuration->builder() - ->withClaim('mercure', ['subscribe' => ["http://example.com/books/1"]]) // can also be a URI template, or * - ->getToken($configuration->signer(), $configuration->signingKey()) - ->toString(); + ->withClaim('mercure', ['subscribe' => ["http://example.com/books/1"]]) // can also be a URI template, or * + ->getToken($configuration->signer(), $configuration->signingKey()) + ->toString(); $response = $this->json(['@id' => '/demo/books/1', 'availability' => 'https://schema.org/InStock']); $cookie = Cookie::create('mercureAuthorization') From 0406cc4c0b38ceb54ec1c43eb3a46c3a227ddaa8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 11 Dec 2020 17:34:55 +0100 Subject: [PATCH 0662/1519] [Uid] Mention the Doctrine type hinting of UUID/ULID values --- components/uid.rst | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/components/uid.rst b/components/uid.rst index 287789ac368..e5888c66b88 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -168,6 +168,35 @@ entity primary keys:: The UUID types and generators were introduced in Symfony 5.2. +When using built-in Doctrine repository methods (e.g. ``findOneBy()``), Doctrine +knows how to convert these UUID types to build the SQL query +(e.g. ``->findOneBy(['user' => $user->getUuid()])``). However, when using DQL +queries or building the query yourself, you'll need to set ``uuid`` as the type +of the UUID parameters:: + + // src/Repository/ProductRepository.php + + // ... + class ProductRepository extends ServiceEntityRepository + { + // ... + + public function findUserProducts(User $user): array + { + $qb = $this->createQueryBuilder('p') + // ... + // add 'uuid' as the third argument to tell Doctrine that this is an UUID + ->setParameter('user', $user->getUuid(), 'uuid') + + // alternatively, you can convert it to a value compatible with + // the type inferred by Doctrine + ->setParameter('user', $user->getUuid()->toBinary()) + ; + + // ... + } + } + ULIDs ----- @@ -283,6 +312,35 @@ entity primary keys:: The ULID types and generator were introduced in Symfony 5.2. +When using built-in Doctrine repository methods (e.g. ``findOneBy()``), Doctrine +knows how to convert these ULID types to build the SQL query +(e.g. ``->findOneBy(['user' => $user->getUlid()])``). However, when using DQL +queries or building the query yourself, you'll need to set ``ulid`` as the type +of the ULID parameters:: + + // src/Repository/ProductRepository.php + + // ... + class ProductRepository extends ServiceEntityRepository + { + // ... + + public function findUserProducts(User $user): array + { + $qb = $this->createQueryBuilder('p') + // ... + // add 'ulid' as the third argument to tell Doctrine that this is an ULID + ->setParameter('user', $user->getUlid(), 'ulid') + + // alternatively, you can convert it to a value compatible with + // the type inferred by Doctrine + ->setParameter('user', $user->getUlid()->toBinary()) + ; + + // ... + } + } + .. _`unique identifiers`: https://en.wikipedia.org/wiki/UID .. _`UUIDs`: https://en.wikipedia.org/wiki/Universally_unique_identifier .. _`ULIDs`: https://github.com/ulid/spec From 4f0ff7eaad978853b220f2956b96e6061244bf93 Mon Sep 17 00:00:00 2001 From: Adamo Crespi Date: Sat, 12 Dec 2020 13:46:23 +0100 Subject: [PATCH 0663/1519] Update normalizers.rst It was indicated a wrong class. The class `Symfony\Component\Serializer\Normalizer\NormalizableInterface` was not mentioned in the part that tells about how to normalize an object that implements the interface. --- serializer/normalizers.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/serializer/normalizers.rst b/serializer/normalizers.rst index 002cc02a433..78cc103d763 100644 --- a/serializer/normalizers.rst +++ b/serializer/normalizers.rst @@ -36,10 +36,10 @@ Symfony includes the following normalizers but you can also transform :phpclass:`SplFileInfo` objects in `Data URIs`_ * :class:`Symfony\\Component\\Serializer\\Normalizer\\CustomNormalizer` to normalize PHP object using an object that implements + :class:`Symfony\\Component\\Serializer\\Normalizer\\NormalizableInterface`; * :class:`Symfony\\Component\\Serializer\\Normalizer\\FormErrorNormalizer` for objects implementing the :class:`Symfony\\Component\\Form\\FormInterface` to - normalize form errors. - :class:`Symfony\\Component\\Serializer\\Normalizer\\NormalizableInterface`; + normalize form errors; * :class:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer` to normalize PHP object using the getter and setter methods of the object; * :class:`Symfony\\Component\\Serializer\\Normalizer\\PropertyNormalizer` to From 586503b66bbb23c27f218d0082c6b6f4b2a81e7c Mon Sep 17 00:00:00 2001 From: Volodymyr Stelmakh Date: Sat, 12 Dec 2020 15:14:57 +0100 Subject: [PATCH 0664/1519] fix method name typo in tip --- components/semaphore.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/semaphore.rst b/components/semaphore.rst index 5f26c781164..ebae3df89e8 100644 --- a/components/semaphore.rst +++ b/components/semaphore.rst @@ -76,6 +76,6 @@ already acquired. If you don't release the semaphore explicitly, it will be released automatically on instance destruction. In some cases, it can be useful to lock a resource across several requests. To disable the automatic release - behavior, set the fifth argument of the ``createLock()`` method to ``false``. + behavior, set the fifth argument of the ``createSemaphore()`` method to ``false``. .. _`semaphores`: https://en.wikipedia.org/wiki/Semaphore_(programming) From 912c86df25f7bc10f929f85b285093b010c53ca1 Mon Sep 17 00:00:00 2001 From: Christoph Wieseke Date: Tue, 15 Dec 2020 15:51:52 +0100 Subject: [PATCH 0665/1519] [PropertyAccess] fixed typos for feature enable/disable fixed typos in comments for feature enable/disable --- components/property_access.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/property_access.rst b/components/property_access.rst index d7890e13c5e..4069719cf41 100644 --- a/components/property_access.rst +++ b/components/property_access.rst @@ -519,10 +519,10 @@ configured to enable extra features. To do that you could use the $propertyAccessorBuilder->enableMagicSet(); // enables magic __set $propertyAccessorBuilder->enableMagicMethods(); // enables magic __get, __set and __call - $propertyAccessorBuilder->disableMagicCall(); // enables magic __call - $propertyAccessorBuilder->disableMagicGet(); // enables magic __get - $propertyAccessorBuilder->disableMagicSet(); // enables magic __set - $propertyAccessorBuilder->disableMagicMethods(); // enables magic __get, __set and __call + $propertyAccessorBuilder->disableMagicCall(); // disables magic __call + $propertyAccessorBuilder->disableMagicGet(); // disables magic __get + $propertyAccessorBuilder->disableMagicSet(); // disables magic __set + $propertyAccessorBuilder->disableMagicMethods(); // disables magic __get, __set and __call // checks if magic __call, __get or __set handling are enabled $propertyAccessorBuilder->isMagicCallEnabled(); // true or false From 7bf71ce65e972e466826e9046318b404e3031318 Mon Sep 17 00:00:00 2001 From: MrYamous Date: Wed, 16 Dec 2020 23:26:59 +0100 Subject: [PATCH 0666/1519] Remove UuidBinary/UlidBinary usages from documentation --- components/uid.rst | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index e5888c66b88..fef72839f52 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -115,7 +115,7 @@ UUID objects created with the ``Uuid`` class can use the following methods Storing UUIDs in Databases ~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can store UUID values as any other regular string/binary values in the database. +You can store UUID values as any other regular string values in the database. However, if you :doc:`use Doctrine `, it's more convenient to use the special Doctrine types which convert to/from UUID objects automatically:: @@ -134,14 +134,13 @@ special Doctrine types which convert to/from UUID objects automatically:: */ private $someProperty; - /** - * @ORM\Column(type="uuid_binary") - */ - private $anotherProperty; - // ... } +.. versionadded:: 5.2 + + The UuidBinary type has been removed in Symfony 5.2. + There's also a Doctrine generator to help autogenerate UUID values for the entity primary keys:: @@ -260,7 +259,7 @@ ULID objects created with the ``Ulid`` class can use the following methods:: Storing ULIDs in Databases ~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can store ULID values as any other regular string/binary values in the database. +You can store ULID values as any other regular string values in the database. However, if you :doc:`use Doctrine `, it's more convenient to use the special Doctrine types which convert to/from ULID objects automatically:: @@ -279,14 +278,13 @@ special Doctrine types which convert to/from ULID objects automatically:: */ private $someProperty; - /** - * @ORM\Column(type="ulid_binary") - */ - private $anotherProperty; - // ... } +.. versionadded:: 5.2 + + The UlidBinary type has been removed in Symfony 5.2. + There's also a Doctrine generator to help autogenerate ULID values for the entity primary keys:: From 41285f0382e1056edb115c4b55c3f816aec73843 Mon Sep 17 00:00:00 2001 From: Oleksandr Barabolia Date: Mon, 16 Nov 2020 19:42:41 +0200 Subject: [PATCH 0667/1519] [Notifier] add iqsms bridge support in doc --- notifier.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/notifier.rst b/notifier.rst index b626a79ac39..9fdb9a435a8 100644 --- a/notifier.rst +++ b/notifier.rst @@ -60,6 +60,7 @@ Service Package DSN Esendex ``symfony/esendex-notifier`` ``esendex://USER_NAME:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM`` FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` Infobip ``symfony/infobip-notifier`` ``infobip://TOKEN@default?from=FROM`` +Iqsms ``symfony/iqsms-notifier`` ``iqsms://LOGIN:PASSWORD@default?from=FROM`` Mobyt ``symfony/mobyt-notifier`` ``mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM`` Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` OvhCloud ``symfony/ovhcloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` @@ -77,6 +78,10 @@ Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from= The Smsapi, Infobip, Mobyt, Esendex and Sendinblue integrations were introduced in Symfony 5.2. +.. versionadded:: 5.3 + + The Iqsms integration was introduced in Symfony 5.3. + To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: From ddd13674681771b2ea316f90eb6a9134a99c990e Mon Sep 17 00:00:00 2001 From: Fouad <48414048+ltlsquare@users.noreply.github.com> Date: Fri, 18 Dec 2020 11:13:39 +0400 Subject: [PATCH 0668/1519] Update uid.rst Uuid::fromString(); should not be instantiated as "new". The Ulid section is correct the uuid section contains this error. Especially confusing when you are just starting with this newly implemented functionality. --- components/uid.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/uid.rst b/components/uid.rst index c8eee0ece94..9a097a3e675 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -71,7 +71,7 @@ Converting UUIDs Use these methods to transform the UUID object into different bases:: - $uuid = new Uuid::fromString('d9e7a184-5d5b-11ea-a62a-3499710062d0'); + $uuid = Uuid::fromString('d9e7a184-5d5b-11ea-a62a-3499710062d0'); $uuid->toBinary(); // string(16) "..." (binary contents can't be printed) $uuid->toBase32(); // string(26) "6SWYGR8QAV27NACAHMK5RG0RPG" From efea74512cbe0f140de4a6e9409c0221f759a838 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Fri, 18 Dec 2020 11:37:52 +0100 Subject: [PATCH 0669/1519] Update DSN --- notifier.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notifier.rst b/notifier.rst index 3145bce544c..4a587019e57 100644 --- a/notifier.rst +++ b/notifier.rst @@ -59,7 +59,7 @@ Service Package DSN ========== ================================ ==================================================== Esendex ``symfony/esendex-notifier`` ``esendex://USER_NAME:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM`` FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` -Infobip ``symfony/infobip-notifier`` ``infobip://TOKEN@default?from=FROM`` +Infobip ``symfony/infobip-notifier`` ``infobip://ACCESS_TOKEN@HOST?from=FROM`` Mobyt ``symfony/mobyt-notifier`` ``mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM`` Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` OvhCloud ``symfony/ovh-cloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` @@ -147,7 +147,7 @@ Mattermost ``symfony/mattermost-notifier`` ``mattermost://TOKEN@ENDPOINT?chan RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` Slack ``symfony/slack-notifier`` ``slack://TOKEN@default?channel=CHANNEL`` Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` -Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:APIKEY@ENDPOINT?channel=CHANNEL`` +Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:TOKEN@HOST?channel=CHANNEL`` ========== ================================ =========================================================================== .. versionadded:: 5.1 From facf002bb506ca6b811d72797f03ae21498d665e Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Fri, 18 Dec 2020 11:44:54 +0100 Subject: [PATCH 0670/1519] Update DSN --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 3f7d7008de9..c5e8181c22a 100644 --- a/notifier.rst +++ b/notifier.rst @@ -131,7 +131,7 @@ integration with these chat services: ========== ================================ ============================================ Service Package DSN ========== ================================ ============================================ -Mattermost ``symfony/mattermost-notifier`` ``mattermost://TOKEN@ENDPOINT?channel=CHANNEL`` +Mattermost ``symfony/mattermost-notifier`` ``mattermost://ACCESS_TOKEN@HOST/PATH?channel=CHANNEL`` RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` Slack ``symfony/slack-notifier`` ``slack://default/ID`` Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` From dc29127bf23aba45b1ec6cec5b0444fd05fe7139 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 18 Dec 2020 15:16:26 +0100 Subject: [PATCH 0671/1519] Tweaks --- components/uid.rst | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index b0fd455add0..ccf372ddd96 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -115,9 +115,8 @@ UUID objects created with the ``Uuid`` class can use the following methods Storing UUIDs in Databases ~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can store UUID values as any other regular string values in the database. -However, if you :doc:`use Doctrine `, it's more convenient to use the -special Doctrine types which convert to/from UUID objects automatically:: +If you :doc:`use Doctrine `, consider using the ``uuid`` Doctrine +type, which converts to/from UUID objects automatically:: // src/Entity/Product.php namespace App\Entity; @@ -137,10 +136,6 @@ special Doctrine types which convert to/from UUID objects automatically:: // ... } -.. versionadded:: 5.2 - - The UuidBinary type has been removed in Symfony 5.2. - There's also a Doctrine generator to help autogenerate UUID values for the entity primary keys:: @@ -165,7 +160,7 @@ entity primary keys:: .. versionadded:: 5.2 - The UUID types and generators were introduced in Symfony 5.2. + The UUID type and generators were introduced in Symfony 5.2. When using built-in Doctrine repository methods (e.g. ``findOneBy()``), Doctrine knows how to convert these UUID types to build the SQL query @@ -259,9 +254,8 @@ ULID objects created with the ``Ulid`` class can use the following methods:: Storing ULIDs in Databases ~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can store ULID values as any other regular string values in the database. -However, if you :doc:`use Doctrine `, it's more convenient to use the -special Doctrine types which convert to/from ULID objects automatically:: +If you :doc:`use Doctrine `, consider using the ``ulid`` Doctrine +type, which converts to/from ULID objects automatically:: // src/Entity/Product.php namespace App\Entity; @@ -281,10 +275,6 @@ special Doctrine types which convert to/from ULID objects automatically:: // ... } -.. versionadded:: 5.2 - - The UlidBinary type has been removed in Symfony 5.2. - There's also a Doctrine generator to help autogenerate ULID values for the entity primary keys:: @@ -308,7 +298,7 @@ entity primary keys:: .. versionadded:: 5.2 - The ULID types and generator were introduced in Symfony 5.2. + The ULID type and generator were introduced in Symfony 5.2. When using built-in Doctrine repository methods (e.g. ``findOneBy()``), Doctrine knows how to convert these ULID types to build the SQL query From 4629dba683293de46b4d8a1ae5ca9ec81f394f3f Mon Sep 17 00:00:00 2001 From: Dale Nash Date: Fri, 18 Dec 2020 15:10:56 +0000 Subject: [PATCH 0672/1519] Update setup.rst Fix incorrect quotation mark type --- setup.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.rst b/setup.rst index 5700c2b8878..30ef0375f20 100644 --- a/setup.rst +++ b/setup.rst @@ -65,10 +65,10 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/website-skeleton:"5.3.x@dev' my_project_name + $ composer create-project symfony/website-skeleton:"5.3.x@dev" my_project_name # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton:"5.3.x@dev' my_project_name + $ composer create-project symfony/skeleton:"5.3.x@dev" my_project_name No matter which command you run to create the Symfony application. All of them will create a new ``my_project_name/`` directory, download some dependencies From 8250dc71f0cec24f3cc2b7a29431684265e10eca Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Fri, 18 Dec 2020 16:20:45 +0100 Subject: [PATCH 0673/1519] Fix build --- notifier.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 7e50df6c212..10a0a5490aa 100644 --- a/notifier.rst +++ b/notifier.rst @@ -144,7 +144,6 @@ integration with these chat services: ========== ================================ =========================================================================== Service Package DSN -<<<<<<< HEAD ========== ================================ =========================================================================== Discord ``symfony/discord-notifier`` ``discord://TOKEN@default?webhook_id=ID`` GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?threadKey=THREAD_KEY`` From 8af100d63a63d2bf22c99117f686d64e1b963ea3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 18 Dec 2020 17:31:00 +0100 Subject: [PATCH 0674/1519] Mention that Symfony only loads YAML routes by default --- routing.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/routing.rst b/routing.rst index ec6de557b5d..a7d5be18fb6 100644 --- a/routing.rst +++ b/routing.rst @@ -147,6 +147,12 @@ the ``BlogController``: ; }; +.. versionadded:: 5.1 + + Starting from Symfony 5.1, by default Symfony only loads the routes defined + in YAML format. If you define routes in XML and/or PHP formats, update the + ``src/Kernel.php`` file to add support for the ``.xml`` and ``.php`` file extensions. + .. _routing-matching-http-methods: Matching HTTP Methods From 58bcabbd13cfc3f0611736f5d8cf67cc103ae8e4 Mon Sep 17 00:00:00 2001 From: Gawain Lynch Date: Sat, 19 Dec 2020 04:01:02 +0100 Subject: [PATCH 0675/1519] Correct annotation for ULID type --- components/uid.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/uid.rst b/components/uid.rst index ccf372ddd96..bdeb252bb65 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -287,7 +287,7 @@ entity primary keys:: { /** * @ORM\Id - * @ORM\Column(type="uuid", unique=true) + * @ORM\Column(type="ulid", unique=true) * @ORM\GeneratedValue(strategy="CUSTOM") * @ORM\CustomIdGenerator(class=UlidGenerator::class) */ From 63a4e504fb2e1685618690ebb0348ce8e76366b0 Mon Sep 17 00:00:00 2001 From: Gawain Lynch Date: Sat, 19 Dec 2020 04:14:46 +0100 Subject: [PATCH 0676/1519] Remove merge conflict header --- notifier.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 057545d1b71..62052eb96dc 100644 --- a/notifier.rst +++ b/notifier.rst @@ -139,7 +139,6 @@ integration with these chat services: ========== ================================ =========================================================================== Service Package DSN -<<<<<<< HEAD ========== ================================ =========================================================================== Discord ``symfony/discord-notifier`` ``discord://TOKEN@default?webhook_id=ID`` GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?threadKey=THREAD_KEY`` From d1314646d993de107ed220142630ad99eff8bbab Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 21 Dec 2020 09:30:48 +0100 Subject: [PATCH 0677/1519] Removed unnecessary versionadded directives --- service_container/service_subscribers_locators.rst | 9 --------- 1 file changed, 9 deletions(-) diff --git a/service_container/service_subscribers_locators.rst b/service_container/service_subscribers_locators.rst index 8a3f9ec3852..051a0ab592c 100644 --- a/service_container/service_subscribers_locators.rst +++ b/service_container/service_subscribers_locators.rst @@ -300,15 +300,6 @@ argument of type ``service_locator``: ])]); }; -.. versionadded:: 4.2 - - The ability to add services without specifying an array key was introduced - in Symfony 4.2. - -.. versionadded:: 4.2 - - The ``service_locator`` argument type was introduced in Symfony 4.2. - As shown in the previous sections, the constructor of the ``CommandBus`` class must type-hint its argument with ``ContainerInterface``. Then, you can get any of the service locator services via their ID (e.g. ``$this->locator->get('App\FooCommand')``). From a490d10189aad87f89a7e18a0939451276143be1 Mon Sep 17 00:00:00 2001 From: Hugo Sales Date: Sun, 21 Jun 2020 15:49:19 +0000 Subject: [PATCH 0678/1519] Add documentation for pull #37371 --- translation/message_format.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/translation/message_format.rst b/translation/message_format.rst index 81bc8320975..e744ab8f757 100644 --- a/translation/message_format.rst +++ b/translation/message_format.rst @@ -165,6 +165,21 @@ you to use literal text in the select statements: #. Inside this block, ``{organizer_name}`` starts "code" mode again, allowing ``organizer_name`` to be processed as variable. +Additionally, it's possible to write the message directly in code:: + + $invitation = '{organizer_gender, select, + female {{organizer_name} has invited you for her party!} + male {{organizer_name} has invited you for his party!} + other {{organizer_name} have invited you for their party!} + }'; + // prints "Ryan has invited you for his party!" + echo $translator->trans($invitation, [ + 'organizer_name' => 'Ryan', + 'organizer_gender' => 'male', + ]); + +This can be used to create a wrapper. + .. tip:: While it might seem more logical to only put ``her``, ``his`` or ``their`` From 064bb18c88def6b3d1eab4a771076c4d3fa12366 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 22 Dec 2020 17:21:14 +0100 Subject: [PATCH 0679/1519] Tweaks --- translation/message_format.rst | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/translation/message_format.rst b/translation/message_format.rst index e744ab8f757..0a0742e16d0 100644 --- a/translation/message_format.rst +++ b/translation/message_format.rst @@ -165,21 +165,6 @@ you to use literal text in the select statements: #. Inside this block, ``{organizer_name}`` starts "code" mode again, allowing ``organizer_name`` to be processed as variable. -Additionally, it's possible to write the message directly in code:: - - $invitation = '{organizer_gender, select, - female {{organizer_name} has invited you for her party!} - male {{organizer_name} has invited you for his party!} - other {{organizer_name} have invited you for their party!} - }'; - // prints "Ryan has invited you for his party!" - echo $translator->trans($invitation, [ - 'organizer_name' => 'Ryan', - 'organizer_gender' => 'male', - ]); - -This can be used to create a wrapper. - .. tip:: While it might seem more logical to only put ``her``, ``his`` or ``their`` @@ -188,6 +173,22 @@ This can be used to create a wrapper. readable for translators and, as you can see in the ``other`` case, other parts of the sentence might be influenced by the variables. +.. tip:: + + It's possible to translate ICU MessageFormat messages directly in code, + without having to define them in any file:: + + $invitation = '{organizer_gender, select, + female {{organizer_name} has invited you for her party!} + male {{organizer_name} has invited you for his party!} + other {{organizer_name} have invited you for their party!} + }'; + + // prints "Ryan has invited you for his party!" + echo $translator->trans($invitation, [ + 'organizer_name' => 'Ryan', + 'organizer_gender' => 'male', + ]); .. _component-translation-pluralization: From c521f8e54355bce0baa93a66f20a9a3ff1b8edb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Wed, 23 Dec 2020 09:59:35 +0100 Subject: [PATCH 0680/1519] Remove experimental from notifier --- notifier.rst | 3 +-- notifier/chatters.rst | 3 +-- notifier/texters.rst | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/notifier.rst b/notifier.rst index 10a0a5490aa..c7c84eb5977 100644 --- a/notifier.rst +++ b/notifier.rst @@ -6,8 +6,7 @@ Creating and Sending Notifications .. versionadded:: 5.0 - The Notifier component was introduced in Symfony 5.0 as an - :doc:`experimental feature `. + The Notifier component was introduced in Symfony 5.0. Installation ------------ diff --git a/notifier/chatters.rst b/notifier/chatters.rst index da11c8858b9..ffeb6e0dc5e 100644 --- a/notifier/chatters.rst +++ b/notifier/chatters.rst @@ -6,8 +6,7 @@ How to send Chat Messages .. versionadded:: 5.0 - The Notifier component was introduced in Symfony 5.0 as an - :doc:`experimental feature `. + The Notifier component was introduced in Symfony 5.0. The :class:`Symfony\\Component\\Notifier\\ChatterInterface` class allows you to send messages to chat services like Slack or Telegram:: diff --git a/notifier/texters.rst b/notifier/texters.rst index eb663b13726..4cf9b6f2de2 100644 --- a/notifier/texters.rst +++ b/notifier/texters.rst @@ -6,8 +6,7 @@ How to send SMS Messages .. versionadded:: 5.0 - The Notifier component was introduced in Symfony 5.0 as an - :doc:`experimental feature `. + The Notifier component was introduced in Symfony 5.0. The :class:`Symfony\\Component\\Notifier\\TexterInterface` class allows you to send SMS messages:: From 275b6e97ba7edd5eff2d38230d5300270a1d9868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Wed, 23 Dec 2020 11:46:38 +0100 Subject: [PATCH 0681/1519] Restore version-added in string --- components/string.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/string.rst b/components/string.rst index 7d2ec49a198..83d73140095 100644 --- a/components/string.rst +++ b/components/string.rst @@ -8,6 +8,10 @@ The String Component The String component provides a single object-oriented API to work with three "unit systems" of strings: bytes, code points and grapheme clusters. +.. versionadded:: 5.0 + + The String component was introduced in Symfony 5.0. + Installation ------------ From b885099d7b7812fa134008cdb00b786da9d775e5 Mon Sep 17 00:00:00 2001 From: Alexander Dubovskoy Date: Wed, 23 Dec 2020 17:48:32 +0300 Subject: [PATCH 0682/1519] Update lockable_trait.rst Misprint has been fixed: added ":" --- console/lockable_trait.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/lockable_trait.rst b/console/lockable_trait.rst index 9c77073d087..54f6e4b051d 100644 --- a/console/lockable_trait.rst +++ b/console/lockable_trait.rst @@ -39,7 +39,7 @@ that adds two convenient methods to lock and release commands:: // automatically when the execution of the command ends $this->release(); - return Command:SUCCESS; + return Command::SUCCESS; } } From c39447ab9ddd33dcd0a68b43eb65f70d23188f17 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 27 Dec 2020 11:30:56 +0100 Subject: [PATCH 0683/1519] [RateLimiter] Adding config reference for policy and lock_factory --- rate_limiter.rst | 2 ++ reference/configuration/framework.rst | 36 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/rate_limiter.rst b/rate_limiter.rst index 403aa9c462f..63e073a1e92 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -16,6 +16,8 @@ Symfony uses these rate limiters in built-in features like "login throttling", which limits how many failed login attempts a user can make in a given period of time, but you can use them for your own features too. +.. _rate-limiter-policies: + Rate Limiting Policies ---------------------- diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 4bc44ad1f17..cc00ae83c6f 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -211,6 +211,13 @@ Configuration * :ref:`enabled ` +* `rate_limiter`_: + + * :ref:`name ` + + * `lock_factory`_ + * `policy`_ + * `request`_: * `formats`_ @@ -1220,6 +1227,35 @@ dsn The DSN where to store the profiling information. +rate_limiter +~~~~~~~~~~~~ + +.. _reference-rate-limiter-name: + +name +.... + +**type**: ``prototype`` + +Name of the rate limiter you want to create. + +lock_factory +"""""""""""" + +**type**: ``string`` **default:** ``lock.factory`` + +The service that is used to create a lock. The service has to implement the +:class:`Symfony\\Component\\Lock\\LockFactoryInterface`. + +policy +"""""" + +**type**: ``string`` **required** + +The name of the rate limiting algorithm to use. Example names are ``fixed_window``, +``sliding_window`` and ``no_limit``. See :ref:`Rate Limiter Policies `) +for more information. + request ~~~~~~~ From 95d52ea6af091519b911a655db42bcc725ebe67c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 28 Dec 2020 15:24:00 +0100 Subject: [PATCH 0684/1519] Tweak --- reference/configuration/framework.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index a3bbbe2d7fa..8a126514b9b 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1250,8 +1250,8 @@ lock_factory **type**: ``string`` **default:** ``lock.factory`` -The service that is used to create a lock. The service has to implement the -:class:`Symfony\\Component\\Lock\\LockFactoryInterface`. +The service that is used to create a lock. The service has to be an instance of +the :class:`Symfony\\Component\\Lock\\LockFactory` class. policy """""" From 3a7985f90472d45a282e82d8ce30de955f3dfa24 Mon Sep 17 00:00:00 2001 From: MrYamous Date: Mon, 28 Dec 2020 02:09:18 +0100 Subject: [PATCH 0685/1519] Update rounding mode defintion integer type --- reference/forms/types/integer.rst | 45 +++++++++++++++++++------------ 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/reference/forms/types/integer.rst b/reference/forms/types/integer.rst index fa5660158bc..80a946a33fd 100644 --- a/reference/forms/types/integer.rst +++ b/reference/forms/types/integer.rst @@ -55,31 +55,42 @@ Field Options ``rounding_mode`` ~~~~~~~~~~~~~~~~~ -**type**: ``integer`` **default**: ``IntegerToLocalizedStringTransformer::ROUND_DOWN`` +**type**: ``integer`` **default**: ``\NumberFormatter::ROUND_HALFUP`` -By default, if the user enters a non-integer number, it will be rounded -down. There are several other rounding methods and each is a constant -on the :class:`Symfony\\Component\\Form\\Extension\\Core\\DataTransformer\\IntegerToLocalizedStringTransformer`: +By default, if the users enters a non-integer number, it will be rounded +down. You have several configurable options for that rounding. Each option +is a constant on the :phpclass:`NumberFormatter` class: -* ``IntegerToLocalizedStringTransformer::ROUND_DOWN`` Round towards zero. +* ``\NumberFormatter::ROUND_DOWN`` Round towards zero. It + rounds ``1.4`` to ``1`` and ``-1.4`` to ``-1``. -* ``IntegerToLocalizedStringTransformer::ROUND_FLOOR`` Round towards negative - infinity. +* ``\NumberFormatter::ROUND_FLOOR`` Round towards negative + infinity. It rounds ``1.4`` to ``1`` and ``-1.4`` to ``-2``. -* ``IntegerToLocalizedStringTransformer::ROUND_UP`` Round away from zero. +* ``\NumberFormatter::ROUND_UP`` Round away from zero. It + rounds ``1.4`` to ``2`` and ``-1.4`` to ``-2``. -* ``IntegerToLocalizedStringTransformer::ROUND_CEILING`` Round towards - positive infinity. +* ``\NumberFormatter::ROUND_CEILING`` Round towards positive + infinity. It rounds ``1.4`` to ``2`` and ``-1.4`` to ``-1``. -* ``IntegerToLocalizedStringTransformer::ROUND_HALF_DOWN`` Round towards the - "nearest neighbor". If both neighbors are equidistant, round down. +* ``\NumberFormatter::ROUND_HALFDOWN`` Round towards the + "nearest neighbor". If both neighbors are equidistant, round down. It rounds + ``2.5`` and ``1.6`` to ``2``, ``1.5`` and ``1.4`` to ``1``. -* ``IntegerToLocalizedStringTransformer::ROUND_HALF_EVEN`` Round towards the - "nearest neighbor". If both neighbors are equidistant, round towards the - even neighbor. +* ``\NumberFormatter::ROUND_HALFEVEN`` Round towards the + "nearest neighbor". If both neighbors are equidistant, round towards the even + neighbor. It rounds ``2.5``, ``1.6`` and ``1.5`` to ``2`` and ``1.4`` to ``1``. + +* ``\NumberFormatter::ROUND_HALFUP`` Round towards the + "nearest neighbor". If both neighbors are equidistant, round up. It rounds + ``2.5`` to ``3``, ``1.6`` and ``1.5`` to ``2`` and ``1.4`` to ``1``. + +.. deprecated:: 5.1 + + In Symfony versions prior to 5.1, these constants were also defined as aliases + in the :class:`Symfony\\Component\\Form\\Extension\\Core\\DataTransformer\\IntegerToLocalizedStringTransformer` + class, but they are now deprecated in favor of the :phpclass:`NumberFormatter` constants. -* ``IntegerToLocalizedStringTransformer::ROUND_HALF_UP`` Round towards the - "nearest neighbor". If both neighbors are equidistant, round up. Overridden Options ------------------ From 9436d6337ca5b5d62b86059c72fa3846597046a7 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 28 Dec 2020 15:56:15 +0100 Subject: [PATCH 0686/1519] Tweaks --- reference/forms/types/integer.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/reference/forms/types/integer.rst b/reference/forms/types/integer.rst index 80a946a33fd..984aa45ed89 100644 --- a/reference/forms/types/integer.rst +++ b/reference/forms/types/integer.rst @@ -57,7 +57,7 @@ Field Options **type**: ``integer`` **default**: ``\NumberFormatter::ROUND_HALFUP`` -By default, if the users enters a non-integer number, it will be rounded +By default, if the user enters a non-integer number, it will be rounded down. You have several configurable options for that rounding. Each option is a constant on the :phpclass:`NumberFormatter` class: @@ -88,10 +88,9 @@ is a constant on the :phpclass:`NumberFormatter` class: .. deprecated:: 5.1 In Symfony versions prior to 5.1, these constants were also defined as aliases - in the :class:`Symfony\\Component\\Form\\Extension\\Core\\DataTransformer\\IntegerToLocalizedStringTransformer` + in the :class:`Symfony\\Component\\Form\\Extension\\Core\\DataTransformer\\NumberToLocalizedStringTransformer` class, but they are now deprecated in favor of the :phpclass:`NumberFormatter` constants. - Overridden Options ------------------ From 11e670134ae75a228f572279e85fb3f0842b0965 Mon Sep 17 00:00:00 2001 From: MrYamous Date: Tue, 29 Dec 2020 19:03:34 +0100 Subject: [PATCH 0687/1519] Add Firebase notifier to documentation --- notifier.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index c5e8181c22a..c5415b465a8 100644 --- a/notifier.rst +++ b/notifier.rst @@ -131,6 +131,7 @@ integration with these chat services: ========== ================================ ============================================ Service Package DSN ========== ================================ ============================================ +Firebase ``symfony/firebase-notifier`` ``firebase://USERNAME:PASSWORD@default`` Mattermost ``symfony/mattermost-notifier`` ``mattermost://ACCESS_TOKEN@HOST/PATH?channel=CHANNEL`` RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` Slack ``symfony/slack-notifier`` ``slack://default/ID`` @@ -139,7 +140,7 @@ Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel .. versionadded:: 5.1 - The Mattermost and RocketChat integrations were introduced in Symfony + The Firebase, Mattermost and RocketChat integrations were introduced in Symfony 5.1. The Slack DSN changed in Symfony 5.1 to use Slack Incoming Webhooks instead of legacy tokens. From f06a712d602844862cb0be976b9f31f6294b599d Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Wed, 30 Dec 2020 14:27:00 +0100 Subject: [PATCH 0688/1519] Allow to configure trusted proxies and headers using config options --- deployment/proxies.rst | 126 +++++++++++++++++++------- reference/configuration/framework.rst | 23 ++++- 2 files changed, 113 insertions(+), 36 deletions(-) diff --git a/deployment/proxies.rst b/deployment/proxies.rst index cae9e285648..15725b67007 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -22,28 +22,69 @@ Solution: ``setTrustedProxies()`` --------------------------------- To fix this, you need to tell Symfony which reverse proxy IP addresses to trust -and what headers your reverse proxy uses to send information:: - - // public/index.php - - // ... - $request = Request::createFromGlobals(); - - // tell Symfony about your reverse proxy - Request::setTrustedProxies( - // the IP address (or range) of your proxy - ['192.0.0.1', '10.0.0.0/8'], - - // trust *all* "X-Forwarded-*" headers - Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO - - // or, if your proxy instead uses the "Forwarded" header - // Request::HEADER_FORWARDED - - // or, if you're using a well-known proxy - // Request::HEADER_X_FORWARDED_AWS_ELB - // Request::HEADER_X_FORWARDED_TRAEFIK - ); +and what headers your reverse proxy uses to send information: + +.. configuration-block:: + + .. config-block:: yaml + + # config/packages/framework.yaml + framework: + # ... + // the IP address (or range) of your proxy + trusted_proxies: '192.0.0.1,10.0.0.0/8' + // trust *all* "X-Forwarded-*" headers (the ! prefix means to not trust those headers) + trusted_headers: ['x-forwarded-all', '!x-forwarded-host', '!x-forwarded-prefix'] + // or, if your proxy instead uses the "Forwarded" header + trusted_headers: ['forwarded', '!x-forwarded-host', '!x-forwarded-prefix'] + // or, if you're using a wellknown proxy + trusted_headers: [!php/const Symfony\\Component\\HttpFoundation\\Request::HEADER_X_FORWARDED_AWS_ELB, '!x-forwarded-host', '!x-forwarded-prefix'] + trusted_headers: [!php/const Symfony\\Component\\HttpFoundation\\Request::HEADER_X_FORWARDED_TRAEFIK, '!x-forwarded-host', '!x-forwarded-prefix'] + + .. config-block:: xml + + + + + + + + 192.0.0.1,10.0.0.0/8 + + + x-forwarded-all + !x-forwarded-host + !x-forwarded-prefix + + + forwarded + !x-forwarded-host + !x-forwarded-prefix + + + + .. config-block:: php + + // config/packages/framework.php + use Symfony\Component\HttpFoundation\Request; + + $container->loadFromExtension('framework', [ + // the IP address (or range) of your proxy + 'trusted_proxies' => '192.0.0.1,10.0.0.0/8', + // trust *all* "X-Forwarded-*" headers (the ! prefix means to not trust those headers) + 'trusted_headers' => ['x-forwarded-all', '!x-forwarded-host', '!x-forwarded-prefix'], + // or, if your proxy instead uses the "Forwarded" header + 'trusted_headers' => ['forwarded', '!x-forwarded-host', '!x-forwarded-prefix'], + // or, if you're using a wellknown proxy + 'trusted_headers' => [Request::HEADER_X_FORWARDED_AWS_ELB, '!x-forwarded-host', '!x-forwarded-prefix'], + 'trusted_headers' => [Request::HEADER_X_FORWARDED_TRAEFIK, '!x-forwarded-host', '!x-forwarded-prefix'], + ]); .. deprecated:: 5.2 @@ -61,6 +102,13 @@ The Request object has several ``Request::HEADER_*`` constants that control exac *which* headers from your reverse proxy are trusted. The argument is a bit field, so you can also pass your own value (e.g. ``0b00110``). +.. versionadded:: 5.2 + + The feature to configure trusted proxies and headers with ``trusted_proxies`` + and ``trusted_headers`` options was introduced in Symfony 5.2. In earlier + Symfony versions you needed to use the ``Request::setTrustedProxies()`` + method in the ``public/index.php`` file. + But what if the IP of my Reverse Proxy Changes Constantly! ---------------------------------------------------------- @@ -74,17 +122,17 @@ In this case, you'll need to - *very carefully* - trust *all* proxies. #. Once you've guaranteed that traffic will only come from your trusted reverse proxies, configure Symfony to *always* trust incoming request:: - // public/index.php + .. config-block:: yaml - // ... - Request::setTrustedProxies( - // trust *all* requests (the 'REMOTE_ADDR' string is replaced at - // run time by $_SERVER['REMOTE_ADDR']) - ['127.0.0.1', 'REMOTE_ADDR'], + # config/packages/framework.yaml + framework: + # ... + // trust *all* requests (the 'REMOTE_ADDR' string is replaced at + // run time by $_SERVER['REMOTE_ADDR']) + trusted_proxies: '127.0.0.1,REMOTE_ADDR' - // if you're using ELB, otherwise use a constant from above - Request::HEADER_X_FORWARDED_AWS_ELB - ); + // if you're using ELB, otherwise use another Request::HEADER-* constant + trusted_headers: [!php/const Symfony\\Component\\HttpFoundation\\Request::HEADER_X_FORWARDED_AWS_ELB, '!x-forwarded-host', '!x-forwarded-prefix'] That's it! It's critical that you prevent traffic from all non-trusted sources. If you allow outside traffic, they could "spoof" their true IP address and @@ -100,6 +148,12 @@ other information. # .env TRUSTED_PROXIES=127.0.0.1,REMOTE_ADDR + .. config-block:: yaml + + # config/packages/framework.yaml + framework: + # ... + trusted_proxies: '%env(TRUSTED_PROXIES)%' If you are also using a reverse proxy on top of your load balancer (e.g. `CloudFront`_), calling ``$request->server->get('REMOTE_ADDR')`` won't be @@ -111,11 +165,13 @@ trusted proxies. Custom Headers When Using a Reverse Proxy ----------------------------------------- -Some reverse proxies (like `CloudFront`_ with ``CloudFront-Forwarded-Proto``) may force you to use a custom header. -For instance you have ``Custom-Forwarded-Proto`` instead of ``X-Forwarded-Proto``. +Some reverse proxies (like `CloudFront`_ with ``CloudFront-Forwarded-Proto``) +may force you to use a custom header. For instance you have +``Custom-Forwarded-Proto`` instead of ``X-Forwarded-Proto``. -In this case, you'll need to set the header ``X-Forwarded-Proto`` with the value of -``Custom-Forwarded-Proto`` early enough in your application, i.e. before handling the request:: +In this case, you'll need to set the header ``X-Forwarded-Proto`` with the value +of ``Custom-Forwarded-Proto`` early enough in your application, i.e. before +handling the request:: // public/index.php diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index df964b6d0ba..3a26887300e 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -284,6 +284,7 @@ Configuration * `logging`_ * :ref:`paths ` +* `trusted_headers`_ * `trusted_hosts`_ * `trusted_proxies`_ * `validation`_ @@ -380,12 +381,32 @@ named ``kernel.http_method_override``. $request = Request::createFromGlobals(); // ... +.. _reference-framework-trusted-headers: + +trusted_headers +~~~~~~~~~~~~~~~ + +.. versionadded:: 5.2 + + The ``trusted_headers`` option was introduced in Symfony 5.2. + +The ``trusted_headers`` option is needed to configure which client information +should be trusted (e.g. their host) when running Symfony behind a load balancer +or a reverse proxy. See :doc:`/deployment/proxies`. + .. _reference-framework-trusted-proxies: trusted_proxies ~~~~~~~~~~~~~~~ -The ``trusted_proxies`` option was removed in Symfony 3.3. See :doc:`/deployment/proxies`. +.. versionadded:: 5.2 + + The ``trusted_headers`` option was reintroduced in Symfony 5.2 (it had been + removed in Symfony 3.3). + +The ``trusted_proxies`` option is needed to get precise information about the +client (e.g. their IP address) when running Symfony behind a load balancer or a +reverse proxy. See :doc:`/deployment/proxies`. ide ~~~ From 20695d48b693257a6d5fb765210426f4d1144af2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 30 Dec 2020 17:39:09 +0100 Subject: [PATCH 0689/1519] Fixed a RST syntax issue --- profiler/data_collector.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/profiler/data_collector.rst b/profiler/data_collector.rst index 276d1e88324..6e53fd5203d 100644 --- a/profiler/data_collector.rst +++ b/profiler/data_collector.rst @@ -96,7 +96,7 @@ template that includes some specific blocks. First, add the ``getTemplate()`` method in your data collector class to return the path of the Twig template to use. Then, add some *getters* to give the -template access to the collected information:::: +template access to the collected information:: // src/DataCollector/RequestCollector.php namespace App\DataCollector; From bff0f52a22e35b1893836ce0c4ab3e9f2bac3510 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 30 Dec 2020 17:44:32 +0100 Subject: [PATCH 0690/1519] Fixed RST syntax issue --- deployment/proxies.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deployment/proxies.rst b/deployment/proxies.rst index 15725b67007..95112ca616c 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -26,7 +26,7 @@ and what headers your reverse proxy uses to send information: .. configuration-block:: - .. config-block:: yaml + .. code-block:: yaml # config/packages/framework.yaml framework: @@ -41,7 +41,7 @@ and what headers your reverse proxy uses to send information: trusted_headers: [!php/const Symfony\\Component\\HttpFoundation\\Request::HEADER_X_FORWARDED_AWS_ELB, '!x-forwarded-host', '!x-forwarded-prefix'] trusted_headers: [!php/const Symfony\\Component\\HttpFoundation\\Request::HEADER_X_FORWARDED_TRAEFIK, '!x-forwarded-host', '!x-forwarded-prefix'] - .. config-block:: xml + .. code-block:: xml @@ -69,7 +69,7 @@ and what headers your reverse proxy uses to send information: - .. config-block:: php + .. code-block:: php // config/packages/framework.php use Symfony\Component\HttpFoundation\Request; From 156ac65df5e08fa6786dd4365da2a37bbb0008ac Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 30 Dec 2020 17:50:50 +0100 Subject: [PATCH 0691/1519] Fixed more RST syntax issues --- deployment/proxies.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deployment/proxies.rst b/deployment/proxies.rst index 95112ca616c..f0e9eca9db2 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -120,9 +120,9 @@ In this case, you'll need to - *very carefully* - trust *all* proxies. other than your load balancers. For AWS, this can be done with `security groups`_. #. Once you've guaranteed that traffic will only come from your trusted reverse - proxies, configure Symfony to *always* trust incoming request:: + proxies, configure Symfony to *always* trust incoming request: - .. config-block:: yaml + .. code-block:: yaml # config/packages/framework.yaml framework: @@ -148,7 +148,7 @@ other information. # .env TRUSTED_PROXIES=127.0.0.1,REMOTE_ADDR - .. config-block:: yaml + .. code-block:: yaml # config/packages/framework.yaml framework: From ce3bbd6a657835d8fd6e7a020bd675c78b8eb289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pipa?= Date: Fri, 1 Jan 2021 20:40:33 +0100 Subject: [PATCH 0692/1519] Fix PostgreSqlStore code sample formatting --- components/lock.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/lock.rst b/components/lock.rst index 97de11d0701..3f96ef89586 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -465,7 +465,8 @@ PostgreSqlStore The PostgreSqlStore uses `Advisory Locks`_ provided by PostgreSQL. It requires a `PDO`_ connection, a `Doctrine DBAL Connection`_, or a -`Data Source Name (DSN)`_. It supports native blocking, as well as sharing locks. +`Data Source Name (DSN)`_. It supports native blocking, as well as sharing +locks:: use Symfony\Component\Lock\Store\PostgreSqlStore; From 2931e978d17d6e5cc9738df7d06629cb3a76e82d Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 3 Jan 2021 10:33:54 +0100 Subject: [PATCH 0693/1519] document the ancestors() method --- components/dom_crawler.rst | 8 ++++++-- testing.rst | 8 ++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/components/dom_crawler.rst b/components/dom_crawler.rst index 55b5d8bc23f..7f2b28ad582 100644 --- a/components/dom_crawler.rst +++ b/components/dom_crawler.rst @@ -187,10 +187,14 @@ Get the same level nodes after or before the current selection:: $crawler->filter('body > p')->nextAll(); $crawler->filter('body > p')->previousAll(); -Get all the child or parent nodes:: +Get all the child or ancestor nodes:: $crawler->filter('body')->children(); - $crawler->filter('body > p')->parents(); + $crawler->filter('body > p')->ancestors(); + +.. versionadded:: 5.3 + + The ``ancestors()`` method was introduced in Symfony 5.3. Get all the direct child nodes matching a CSS selector:: diff --git a/testing.rst b/testing.rst index 2c0535eddfa..261786ff108 100644 --- a/testing.rst +++ b/testing.rst @@ -713,7 +713,7 @@ selects the last one on the page, and then selects its immediate parent element: $newCrawler = $crawler->filter('input[type=submit]') ->last() - ->parents() + ->ancestors() ->first() ; @@ -735,8 +735,8 @@ Many other methods are also available: All following siblings. ``previousAll()`` All preceding siblings. -``parents()`` - Returns the parent nodes. +``ancestors()`` + Returns the ancestor nodes. ``children()`` Returns children nodes. ``reduce($lambda)`` @@ -766,7 +766,7 @@ Extracting Information The Crawler can extract information from the nodes:: use Symfony\Component\DomCrawler\Crawler; - + // returns the attribute value for the first node $crawler->attr('class'); From f872201e9febf6fb2078065d0ff380992e3b4862 Mon Sep 17 00:00:00 2001 From: Gordon Franke Date: Tue, 5 Jan 2021 21:09:48 +0100 Subject: [PATCH 0694/1519] doc: copy paste trusted_headers vs trusted_proxies --- reference/configuration/framework.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 3a26887300e..c46b2a469f0 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -401,7 +401,7 @@ trusted_proxies .. versionadded:: 5.2 - The ``trusted_headers`` option was reintroduced in Symfony 5.2 (it had been + The ``trusted_proxies`` option was reintroduced in Symfony 5.2 (it had been removed in Symfony 3.3). The ``trusted_proxies`` option is needed to get precise information about the From 0f25dd3cce6ac600bfc7682b09300ebddbea6fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Tue, 5 Jan 2021 17:02:57 +0100 Subject: [PATCH 0695/1519] Add documenation for Console Negatable option --- console/input.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/console/input.rst b/console/input.rst index ecb7d6e72c3..8bd42ae6c85 100644 --- a/console/input.rst +++ b/console/input.rst @@ -199,7 +199,7 @@ separation at all (e.g. ``-i 5`` or ``-i5``). this situation, always place options after the command name, or avoid using a space to separate the option name from its value. -There are four option variants you can use: +There are five option variants you can use: ``InputOption::VALUE_IS_ARRAY`` This option accepts multiple values (e.g. ``--dir=/foo --dir=/bar``); @@ -216,6 +216,14 @@ There are four option variants you can use: This option may or may not have a value (e.g. ``--yell`` or ``--yell=loud``). +``InputOption::VALUE_NEGATABLE`` + Accept either the flag (e.g. ``--yell``) or its negation (e.g. + ``--no-yell``). + +.. versionadded:: 5.3 + + The ``InputOption::VALUE_NEGATABLE`` constant was introduced in Symfony 5.3. + You can combine ``VALUE_IS_ARRAY`` with ``VALUE_REQUIRED`` or ``VALUE_OPTIONAL`` like this:: From 66d5f497c4e871af5b27db6c23f4fce63193f330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20K=C3=A4fer?= Date: Mon, 16 Nov 2020 23:20:42 +0100 Subject: [PATCH 0696/1519] [PHPUnitBridge] Add deprecation log file option --- components/phpunit_bridge.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 8be5ef90bb7..ed1fbb5a0b2 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -350,6 +350,16 @@ the compiling and warming up of the container: The ``--deprecations`` option was introduced in Symfony 5.1. +Log Deprecations +~~~~~~~~~~~~~~~~ + +For turning the verbose output off and write it to a log file instead you can use +``SYMFONY_DEPRECATIONS_HELPER='logFile=/path/deprecations.log'``. + +.. versionadded:: 5.3 + + The ``logFile`` option was introduced in Symfony 5.3. + Write Assertions about Deprecations ----------------------------------- From 10f752227da6bca24795534111bd1233d6539995 Mon Sep 17 00:00:00 2001 From: Jacek Date: Tue, 5 Jan 2021 22:47:02 +0100 Subject: [PATCH 0697/1519] Remove unused imports and properties --- security/experimental_authenticators.rst | 9 --------- 1 file changed, 9 deletions(-) diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index 35aa1c9c205..c84f36ed51d 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -287,8 +287,6 @@ method that fits most use-cases:: // src/Security/ApiKeyAuthenticator.php namespace App\Security; - use App\Entity\User; - use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -302,13 +300,6 @@ method that fits most use-cases:: class ApiKeyAuthenticator extends AbstractAuthenticator { - private $entityManager; - - public function __construct(EntityManagerInterface $entityManager) - { - $this->entityManager = $entityManager; - } - /** * Called on every request to decide if this authenticator should be * used for the request. Returning `false` will cause this authenticator From f3fdf986f270448d8eba3542bd61c24506ab0724 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 7 Jan 2021 17:31:36 +0100 Subject: [PATCH 0698/1519] [FrameworkBundle] Document assertResponseFormatSame() --- testing/functional_tests_assertions.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/testing/functional_tests_assertions.rst b/testing/functional_tests_assertions.rst index 457d8c39021..0e190f0ed90 100644 --- a/testing/functional_tests_assertions.rst +++ b/testing/functional_tests_assertions.rst @@ -39,6 +39,12 @@ Response - ``assertResponseHasCookie()`` - ``assertResponseNotHasCookie()`` - ``assertResponseCookieValueSame()`` +- ``assertResponseFormatSame()`` (the response format is the value returned by + the :method:`Symfony\Component\HttpFoundation\Response::getFormat` method). + +.. versionadded:: 5.3 + + The ``assertResponseFormatSame()`` method was introduced in Symfony 5.3. Request ~~~~~~~ From f60b89a7253d76358b9e109b24e3833e5226c132 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Fri, 8 Jan 2021 09:24:49 +0100 Subject: [PATCH 0699/1519] Make DOCtor happy --- testing/functional_tests_assertions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/functional_tests_assertions.rst b/testing/functional_tests_assertions.rst index 0e190f0ed90..56f6a1d4c8c 100644 --- a/testing/functional_tests_assertions.rst +++ b/testing/functional_tests_assertions.rst @@ -40,7 +40,7 @@ Response - ``assertResponseNotHasCookie()`` - ``assertResponseCookieValueSame()`` - ``assertResponseFormatSame()`` (the response format is the value returned by - the :method:`Symfony\Component\HttpFoundation\Response::getFormat` method). + the :method:`Symfony\\Component\\HttpFoundation\\Response::getFormat` method). .. versionadded:: 5.3 From d70cd24c15efa79977a2dba363fd7ab1ba1bba63 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 8 Jan 2021 10:04:16 +0100 Subject: [PATCH 0700/1519] [Ldap] Document the case-insensitive attribute names --- components/ldap.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/ldap.rst b/components/ldap.rst index d7cb6ed17cd..89fb39cb8e8 100644 --- a/components/ldap.rst +++ b/components/ldap.rst @@ -142,6 +142,9 @@ delete existing ones:: $phoneNumber = $entry->getAttribute('phoneNumber'); $isContractor = $entry->hasAttribute('contractorCompany'); + // attribute names in getAttribute() and hasAttribute() methods are case-sensitive + // pass FALSE as the second method argument to make them case-insensitive + $isContractor = $entry->hasAttribute('contractorCompany', false); $entry->setAttribute('email', ['fabpot@symfony.com']); $entryManager->update($entry); @@ -153,6 +156,11 @@ delete existing ones:: // Removing an existing entry $entryManager->remove(new Entry('cn=Test User,dc=symfony,dc=com')); +.. versionadded:: 5.3 + + The option to make attribute names case-insensitive in ``getAttribute()`` + and ``hasAttribute()`` was introduce in Symfony 5.3. + Batch Updating ______________ From 202820162b46d4b6ee88eb02a2155b043f1f7c77 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 8 Jan 2021 10:25:50 +0100 Subject: [PATCH 0701/1519] [Yaml] Documented the github output format for the linter --- translation/lint.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/translation/lint.rst b/translation/lint.rst index d9129a79108..14693f32826 100644 --- a/translation/lint.rst +++ b/translation/lint.rst @@ -33,6 +33,17 @@ The linter results can be exported to JSON using the ``--format`` option: $ php bin/console lint:yaml translations/ --format=json $ php bin/console lint:xliff translations/ --format=json +When running the YAML linter inside `GitHub Actions`_, the output is automatically +adapted to the format required by GitHub, but you can force that format too: + +.. code-block:: terminal + + $ php bin/console lint:yaml translations/ --format=github + +.. versionadded:: 5.3 + + The ``github`` output format was introduced in Symfony 5.3. + .. tip:: The Yaml component provides a stand-alone ``yaml-lint`` binary allowing @@ -45,3 +56,5 @@ The linter results can be exported to JSON using the ``--format`` option: .. versionadded:: 5.1 The ``yaml-lint`` binary was introduced in Symfony 5.1. + +.. _`GitHub Actions`: https://docs.github.com/en/free-pro-team@latest/actions From c3cadab18f3bccd1f5f2a313c0f607292c981960 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 8 Jan 2021 10:33:15 +0100 Subject: [PATCH 0702/1519] [BrowserKit] Document the jsonRequest() method --- components/browser_kit.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/components/browser_kit.rst b/components/browser_kit.rst index b73783f95e0..475c84b9365 100644 --- a/components/browser_kit.rst +++ b/components/browser_kit.rst @@ -80,6 +80,20 @@ The value returned by the ``request()`` method is an instance of the :doc:`DomCrawler component `, which allows accessing and traversing HTML elements programmatically. +The :method:`Symfony\\Component\\BrowserKit\\AbstractBrowser::jsonRequest` method, +which defines the same arguments as the ``request()`` method, is a shortcut to +convert the request parameters into a JSON string and set the needed HTTP headers:: + + use Acme\Client; + + $client = new Client(); + // this encodes parameters as JSON and sets the required CONTENT_TYPE and HTTP_ACCEPT headers + $crawler = $client->jsonRequest('GET', '/', ['some_parameter' => 'some_value']); + +.. versionadded:: 5.3 + + The ``jsonRequest()`` method was introduced in Symfony 5.3. + The :method:`Symfony\\Component\\BrowserKit\\AbstractBrowser::xmlHttpRequest` method, which defines the same arguments as the ``request()`` method, is a shortcut to make AJAX requests:: From 83af9a124100c7264cbc25eba7f0cf27bffa7e56 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 8 Jan 2021 11:07:10 +0100 Subject: [PATCH 0703/1519] [PhpUnitBridge] Document the deprecation baseline file --- components/phpunit_bridge.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index fea473f1229..289346547c7 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -289,6 +289,36 @@ Here is a summary that should help you pick the right configuration: | | cannot afford to use one of the modes above. | +------------------------+-----------------------------------------------------+ +Baseline Deprecations +..................... + +If your application has some deprecations that you can't fix for some reasons, +you can tell Symfony to ignore them. The trick is to create a file with the +allowed deprecations and define it as the "deprecation baseline". Deprecations +inside that file are ignore but the rest of deprecations are still reported. + +First, generate the file with the allowed deprecations (run the same command +whenever you want to update the existing file): + +.. code-block:: terminal + + $ SYMFONY_DEPRECATIONS_HELPER='generateBaseline=true&baselineFile=tests/allowed.json' ./vendor/bin/simple-phpunit + +This command stores all the deprecations reported while running tests in the +given file and encoded in JSON. The file path defined in ``baselineFile`` can +be absolute or relative to your project root. + +Then, you can run the following command to use that file and ignore those deprecations: + +.. code-block:: terminal + + $ SYMFONY_DEPRECATIONS_HELPER='baselineFile=tests/allowed.json' ./vendor/bin/simple-phpunit + +.. versionadded:: 5.2 + + The ``baselineFile`` and ``generateBaseline`` options were introduced in + Symfony 5.2. + Disabling the Verbose Output ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From f156e727eb81fa57b2a58da29a0fea9046650625 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 8 Jan 2021 11:25:48 +0100 Subject: [PATCH 0704/1519] [Messenger] Documented AMQP confirm_timeout option --- messenger.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/messenger.rst b/messenger.rst index e4d1179da8a..c92bda6733b 100644 --- a/messenger.rst +++ b/messenger.rst @@ -962,6 +962,9 @@ The transport has a number of options: fractional. ``connect_timeout`` Connection timeout. Note: 0 or greater seconds. May be fractional. +``confirm_timeout`` Number of seconds to wait for message sending + confirmation. If not specified, transport won't + wait for confirmation. May be fractional. ``frame_max`` The largest frame size that the server proposes for the connection, including frame header and end-byte. 0 means standard extension limit @@ -1005,6 +1008,10 @@ The transport has a number of options: ``exchange[type]`` Type of exchange ``fanout`` ============================================ ================================================= =================================== +.. versionadded:: 5.2 + + The ``confirm_timeout`` option was introduced in Symfony 5.2. + You can also configure AMQP-specific settings on your message by adding :class:`Symfony\\Component\\Messenger\\Bridge\\Amqp\\Transport\\AmqpStamp` to your Envelope:: From 71e65a1185b787909d76186ea7593d2ed3922dad Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 8 Jan 2021 11:18:16 +0100 Subject: [PATCH 0705/1519] [Messenger] Mention the WorkerMessageRetriedEvent --- messenger.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/messenger.rst b/messenger.rst index e4d1179da8a..f0e2d742450 100644 --- a/messenger.rst +++ b/messenger.rst @@ -716,6 +716,15 @@ this is configurable for each transport: ], ]); +.. tip:: + + Symfony triggers a :class:`Symfony\\Component\\Messenger\\Event\\WorkerMessageRetriedEvent` + when a message is retried so you can run your own logic. + + .. versionadded:: 5.2 + + The ``WorkerMessageRetriedEvent`` class was introduced in Symfony 5.2. + Avoiding Retrying ~~~~~~~~~~~~~~~~~ From a6f97ce0638f14a3014cb9fd10b6599c40284735 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 8 Jan 2021 10:39:07 +0100 Subject: [PATCH 0706/1519] [Messenger] Document the debug option of Amazon SQS --- messenger.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/messenger.rst b/messenger.rst index e4d1179da8a..ee274146158 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1342,6 +1342,8 @@ The transport has a number of options: ``auto_setup`` Whether the queue should be created ``true`` automatically during send / get. ``buffer_size`` Number of messages to prefetch 9 +``debug`` If ``true`` it logs all HTTP requests ``false`` + and responses (it impacts performance) ``endpoint`` Absolute URL to the SQS service https://sqs.eu-west-1.amazonaws.com ``poll_timeout`` Wait for new message duration in 0.1 seconds @@ -1353,6 +1355,10 @@ The transport has a number of options: ``wait_time`` `Long polling`_ duration in seconds 20 ====================== ====================================== =================================== +.. versionadded:: 5.3 + + The ``debug`` option was introduced in Symfony 5.3. + .. note:: The ``wait_time`` parameter defines the maximum duration Amazon SQS should From 790d1ecb6aefb9f4104399f6b7a6913a2d748259 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 8 Jan 2021 15:42:55 +0100 Subject: [PATCH 0707/1519] Restored some wrongly removed contents --- testing/http_authentication.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/testing/http_authentication.rst b/testing/http_authentication.rst index 134f2ad3fb7..a55ae639e0b 100644 --- a/testing/http_authentication.rst +++ b/testing/http_authentication.rst @@ -10,4 +10,8 @@ How to Simulate HTTP Authentication in a Functional Test ease testing secured applications. See :ref:`testing_logging_in_users` for more information about this. + If you are still using an older version of Symfony, view + `previous versions of this article`_ for information on how to simulate + HTTP authentication. + .. _previous versions of this article: https://symfony.com/doc/5.0/testing/http_authentication.html From c20126a152577edf25f60d69ff129245a23de82b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 8 Jan 2021 16:17:29 +0100 Subject: [PATCH 0708/1519] Tweaks --- workflow.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow.rst b/workflow.rst index ac0451d473d..750d6a2ca5e 100644 --- a/workflow.rst +++ b/workflow.rst @@ -791,7 +791,7 @@ of domain logic in your templates: Returns an array with all the transitions enabled for the given object. ``workflow_transition()`` - Returns a specific transitions enabled for the given object and transition name. + Returns a specific transition enabled for the given object and transition name. ``workflow_marked_places()`` Returns an array with the place names of the given marking. From abd7460c0c7b09056ff532296d2168347dc623ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20MARTIN?= Date: Mon, 4 Jan 2021 11:41:12 +0100 Subject: [PATCH 0709/1519] Add Octopush in SMS channel --- notifier.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index be67884c1b2..966124b01bb 100644 --- a/notifier.rst +++ b/notifier.rst @@ -62,6 +62,7 @@ Infobip ``symfony/infobip-notifier`` ``infobip://ACCESS_TOKEN@HOST?from Iqsms ``symfony/iqsms-notifier`` ``iqsms://LOGIN:PASSWORD@default?from=FROM`` Mobyt ``symfony/mobyt-notifier`` ``mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM`` Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` +Octopush ``symfony/octopush-notifier`` ``octopush://USERLOGIN:APIKEY@default?from=FROM&type=TYPE`` OvhCloud ``symfony/ovh-cloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` Sendinblue ``symfony/sendinblue-notifier`` ``sendinblue://API_KEY@default?sender=PHONE`` Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` @@ -79,7 +80,7 @@ Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from= .. versionadded:: 5.3 - The Iqsms integration was introduced in Symfony 5.3. + The Iqsms and Octopush integrations were introduced in Symfony 5.3. To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: From 0470b00dac4042ba82b4be1a628a3018151b629b Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Mon, 18 May 2020 11:53:54 +0200 Subject: [PATCH 0710/1519] Add choice_translation_parameters option --- reference/forms/types/choice.rst | 3 + .../choice_translation_parameters.rst.inc | 80 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 reference/forms/types/options/choice_translation_parameters.rst.inc diff --git a/reference/forms/types/choice.rst b/reference/forms/types/choice.rst index affcce9ab54..d01d90f262d 100644 --- a/reference/forms/types/choice.rst +++ b/reference/forms/types/choice.rst @@ -19,6 +19,7 @@ To use this field, you must specify *either* ``choices`` or ``choice_loader`` op | | - `choice_loader`_ | | | - `choice_name`_ | | | - `choice_translation_domain`_ | +| | - `choice_translation_parameters`_ | | | - `choice_value`_ | | | - `expanded`_ | | | - `group_by`_ | @@ -232,6 +233,8 @@ correct types will be assigned to the model. .. include:: /reference/forms/types/options/choice_translation_domain_enabled.rst.inc +.. include:: /reference/forms/types/options/choice_translation_parameters.rst.inc + .. include:: /reference/forms/types/options/choice_value.rst.inc .. include:: /reference/forms/types/options/expanded.rst.inc diff --git a/reference/forms/types/options/choice_translation_parameters.rst.inc b/reference/forms/types/options/choice_translation_parameters.rst.inc new file mode 100644 index 00000000000..32e66393383 --- /dev/null +++ b/reference/forms/types/options/choice_translation_parameters.rst.inc @@ -0,0 +1,80 @@ +choice_translation_parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``array``, ``callable``, ``string`` or :class:`Symfony\\Component\\PropertyAccess\\PropertyPath` **default**: ``[]`` + +The choice values are translated before displaying it, so it can contain +:ref:`translation placeholders `. +This option defines the values used to replace those placeholders. This can be +an associative array where the keys match the choice keys and the values +are the attributes for each choice, a callable or a property path +(just like `choice_label`_). + +Given this translation message: + +.. configuration-block:: + + .. code-block:: yaml + + # translations/messages.en.yaml + form.order.yes: 'I confirm my order to the company %company%' + form.order.no: 'I cancel my order' + + .. code-block:: xml + + + + + + + + form.order.yes + I confirm my order to the company %company% + + + form.order.no + I cancel my order + + + + + + .. code-block:: php + + // translations/messages.fr.php + return [ + 'form.order.yes' => "I confirm my order to the company %company%", + 'form.order.no' => "I cancel my order", + ]; + +You can specify the placeholder values as follows:: + + $builder->add('id', null, [ + 'choice' => [ + 'form.order.yes' => true, + 'form.order.no' => false, + ], + 'choice_translation_parameters' => function ($choice, $key, $value) { + if (false === $choice) { + return []; + } + + return ['%company%' => 'ACME Inc.'] + }, + ]); + +If an array, the keys of the ``choices`` array must be used as keys:: + + $builder->add('id', null, [ + 'choice' => [ + 'form.order.yes' => true, + 'form.order.no' => false, + ], + 'choice_translation_parameters' => [ + 'form.order.yes' => ['%company%' => 'ACME Inc.'], + 'form.order.no' => [], + ], + ]); + +The translation parameters of child fields are merged with the same option of +their parents, so children can reuse and/or override any of the parent placeholders. From 89d3122981d023c5e373044528f900a0f063814c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 7 Jan 2021 17:36:22 +0100 Subject: [PATCH 0711/1519] [Messenger] Deprecated the prefetch_count option --- messenger.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/messenger.rst b/messenger.rst index e4d1179da8a..9f28fca4e1d 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1005,6 +1005,11 @@ The transport has a number of options: ``exchange[type]`` Type of exchange ``fanout`` ============================================ ================================================= =================================== +.. deprecated:: 5.3 + + The ``prefetch_count`` option was deprecated in Symfony 5.3 because it has + no effect on the AMQP Messenger transport. + You can also configure AMQP-specific settings on your message by adding :class:`Symfony\\Component\\Messenger\\Bridge\\Amqp\\Transport\\AmqpStamp` to your Envelope:: From d44c038f925c4cab693995ecf1531206128353a5 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 11 Jan 2021 10:02:07 +0100 Subject: [PATCH 0712/1519] Removed 4.2 versionadded directive --- components/serializer.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/components/serializer.rst b/components/serializer.rst index ca89cdb58ca..c062fef80c5 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -946,11 +946,6 @@ Option Description generated XML ============================== ================================================= ========================== -.. versionadded:: 4.2 - - The ``decoder_ignored_node_types`` and ``encoder_ignored_node_types`` - options were introduced in Symfony 4.2. - The ``YamlEncoder`` ~~~~~~~~~~~~~~~~~~~ From 8961ebdd978cc42fbf0a1a98d5432b2a5d439a87 Mon Sep 17 00:00:00 2001 From: Sebastian Paczkowski <74934099+sebpacz@users.noreply.github.com> Date: Mon, 11 Jan 2021 22:45:11 +0100 Subject: [PATCH 0713/1519] [Mailer] Update Twig namespace The examples shown in the "Using External CSS Files" section use/define a Twig namespace called styles, not css. I checked git history and branch 4.4 doesn't have this issue. --- mailer.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mailer.rst b/mailer.rst index 2bbc58d04a5..fbb84dbdd20 100644 --- a/mailer.rst +++ b/mailer.rst @@ -663,7 +663,7 @@ arguments to the filter: You can pass unlimited number of arguments to ``inline_css()`` to load multiple CSS files. For this example to work, you also need to define a new Twig namespace -called ``css`` that points to the directory where ``email.css`` lives: +called ``styles`` that points to the directory where ``email.css`` lives: .. _mailer-css-namespace: @@ -786,11 +786,11 @@ You can combine all filters to create complex email messages: .. code-block:: twig - {% apply inky_to_html|inline_css(source('@css/foundation-emails.css')) %} + {% apply inky_to_html|inline_css(source('@styles/foundation-emails.css')) %} {# ... #} {% endapply %} -This makes use of the :ref:`css Twig namespace ` we created +This makes use of the :ref:`styles Twig namespace ` we created earlier. You could, for example, `download the foundation-emails.css file`_ directly from GitHub and save it in ``assets/styles``. From 5f70432f366e62bdced954c95ef94aa86baa4de2 Mon Sep 17 00:00:00 2001 From: Piergiuseppe Longo Date: Thu, 22 Oct 2020 19:48:29 +0200 Subject: [PATCH 0714/1519] [Notifier] Add gatewayapi-notifier --- notifier.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 966124b01bb..56543824d46 100644 --- a/notifier.rst +++ b/notifier.rst @@ -58,6 +58,7 @@ Service Package DSN ========== ================================ ==================================================== Esendex ``symfony/esendex-notifier`` ``esendex://USER_NAME:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM`` FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` +GatewayApi ``symfony/gatewayapi-notifier`` ``gatewayapi://TOKEN@default?from=FROM`` Infobip ``symfony/infobip-notifier`` ``infobip://ACCESS_TOKEN@HOST?from=FROM`` Iqsms ``symfony/iqsms-notifier`` ``iqsms://LOGIN:PASSWORD@default?from=FROM`` Mobyt ``symfony/mobyt-notifier`` ``mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM`` @@ -80,7 +81,7 @@ Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from= .. versionadded:: 5.3 - The Iqsms and Octopush integrations were introduced in Symfony 5.3. + The Iqsms, GatewayApi and Octopush integrations were introduced in Symfony 5.3. To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: From 7cb4c17cb976950e1a91b22f5d69261d3b1fc3b1 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 14 Jan 2021 14:06:07 +0100 Subject: [PATCH 0715/1519] Sync with README from the bridge --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index ca6f17ed9a9..d328084c0b8 100644 --- a/notifier.rst +++ b/notifier.rst @@ -59,7 +59,7 @@ Service Package DSN ========== ================================ ==================================================== Esendex ``symfony/esendex-notifier`` ``esendex://USER_NAME:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM`` FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` -Infobip ``symfony/infobip-notifier`` ``infobip://ACCESS_TOKEN@HOST?from=FROM`` +Infobip ``symfony/infobip-notifier`` ``infobip://AUTH_TOKEN@HOST?from=FROM`` Mobyt ``symfony/mobyt-notifier`` ``mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM`` Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` OvhCloud ``symfony/ovh-cloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` From 058dfaaf96a6fe3b255b4076a172afaf50542df1 Mon Sep 17 00:00:00 2001 From: Quentin Dequippe Date: Wed, 23 Dec 2020 15:04:21 +0100 Subject: [PATCH 0716/1519] [Notifier] Add AllMySms service to list --- notifier.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index e6f2c653996..c27eb8ae51b 100644 --- a/notifier.rst +++ b/notifier.rst @@ -56,6 +56,7 @@ with a couple popular SMS services: ========== ================================ ==================================================== Service Package DSN ========== ================================ ==================================================== +AllMySms ``symfony/allmysms-notifier`` ``allmysms://LOGIN:APIKEY@default?from=FROM`` Esendex ``symfony/esendex-notifier`` ``esendex://USER_NAME:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM`` FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` GatewayApi ``symfony/gatewayapi-notifier`` ``gatewayapi://TOKEN@default?from=FROM`` @@ -81,7 +82,8 @@ Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from= .. versionadded:: 5.3 - The Iqsms, GatewayApi and Octopush integrations were introduced in Symfony 5.3. + The Iqsms, GatewayApi, Octopush and AllMySms integrations were introduced in Symfony 5.3. + To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: From debedc3af64757a7ff87e64d643b92f549b465e7 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Fri, 15 Jan 2021 07:58:55 +0100 Subject: [PATCH 0717/1519] Rename threadKey to thread_key --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index c27eb8ae51b..da02d2a585d 100644 --- a/notifier.rst +++ b/notifier.rst @@ -150,7 +150,7 @@ Service Package DSN ========== ================================ =========================================================================== Discord ``symfony/discord-notifier`` ``discord://TOKEN@default?webhook_id=ID`` Firebase ``symfony/firebase-notifier`` ``firebase://USERNAME:PASSWORD@default`` -GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?threadKey=THREAD_KEY`` +GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?thread_key=THREAD_KEY`` LinkedIn ``symfony/linked-in-notifier`` ``linkedin://TOKEN:USER_ID@default`` Mattermost ``symfony/mattermost-notifier`` ``mattermost://ACCESS_TOKEN@HOST/PATH?channel=CHANNEL`` RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` From ebdf28d811a8de05d691ed1cfb0c12d302f6fbec Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 7 Jan 2021 18:35:17 +0100 Subject: [PATCH 0718/1519] [Serializer] Add UidNormalizer normalization formats --- components/serializer.rst | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/components/serializer.rst b/components/serializer.rst index 73637fcf1a1..68a7f90f7c7 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -829,21 +829,25 @@ The Serializer component provides several built-in normalizers: :class:`Symfony\\Component\\Serializer\\Normalizer\\UidNormalizer` This normalizer converts objects that implement - :class:`Symfony\\Component\\Uid\\AbstractUid` into strings. Also it can - denormalize ``uuid`` or ``ulid`` strings to :class:`Symfony\\Component\\Uid\\Uuid` - or :class:`Symfony\\Component\\Uid\\Ulid`. + :class:`Symfony\\Component\\Uid\\AbstractUid` into strings. + The default normalization format for objects that implement :class:`Symfony\\Component\\Uid\\Uuid` + is the `RFC 4122`_ format (example: ``d9e7a184-5d5b-11ea-a62a-3499710062d0``). + The default normalization format for objects that implement :class:`Symfony\\Component\\Uid\\Ulid` + is the Base 32 format (example: ``01E439TP9XJZ9RPFH3T1PYBCR8``). + You can change the string format by setting the serializer context option + ``UidNormalizer::NORMALIZATION_FORMAT_KEY`` to ``UidNormalizer::NORMALIZATION_FORMAT_BASE_58``, + ``UidNormalizer::NORMALIZATION_FORMAT_BASE_32`` or ``UidNormalizer::NORMALIZATION_FORMAT_RFC_4122``. + + Also it can denormalize ``uuid`` or ``ulid`` strings to :class:`Symfony\\Component\\Uid\\Uuid` + or :class:`Symfony\\Component\\Uid\\Ulid`. The format does not matter. .. versionadded:: 5.2 The ``UidNormalizer`` was introduced in Symfony 5.2. -.. note:: - - You can also create your own Normalizer to use another structure. Read more at - :doc:`/serializer/custom_normalizer`. +.. versionadded:: 5.3 -All these normalizers are enabled by default when using the Serializer component -in a Symfony application. + The ``UidNormalizer`` normalization formats were introduced in Symfony 5.3. .. _component-serializer-encoders: @@ -1616,3 +1620,4 @@ Learn more .. _`Value Objects`: https://en.wikipedia.org/wiki/Value_object .. _`API Platform`: https://api-platform.com .. _`list of PHP timezones`: https://www.php.net/manual/en/timezones.php +.. _`RFC 4122`: https://tools.ietf.org/html/rfc4122 From 2755910b95f049af2339920d5f84581b5ea23dc5 Mon Sep 17 00:00:00 2001 From: Sebastian Paczkowski <74934099+sebpacz@users.noreply.github.com> Date: Fri, 15 Jan 2021 21:14:17 +0100 Subject: [PATCH 0719/1519] [Lock] Use .inner instead of decorating_service_id + '.inner' --- lock.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lock.rst b/lock.rst index a8334a12fa8..728eb85b659 100644 --- a/lock.rst +++ b/lock.rst @@ -293,4 +293,4 @@ you can do it by :doc:`decorating the store Date: Tue, 8 Dec 2020 17:11:20 +0100 Subject: [PATCH 0720/1519] [Notifier] Add Mercure notifier documentation --- notifier.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/notifier.rst b/notifier.rst index da02d2a585d..73bdf4d86ed 100644 --- a/notifier.rst +++ b/notifier.rst @@ -153,6 +153,7 @@ Firebase ``symfony/firebase-notifier`` ``firebase://USERNAME:PASSWORD@def GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?thread_key=THREAD_KEY`` LinkedIn ``symfony/linked-in-notifier`` ``linkedin://TOKEN:USER_ID@default`` Mattermost ``symfony/mattermost-notifier`` ``mattermost://ACCESS_TOKEN@HOST/PATH?channel=CHANNEL`` +Mercure ``symfony/mercure-notifier`` ``mercure://PUBLISHER_SERVICE_ID?topic=TOPIC`` RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` Slack ``symfony/slack-notifier`` ``slack://TOKEN@default?channel=CHANNEL`` Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` @@ -170,6 +171,10 @@ Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:TOKEN@HOST?channel The GoogleChat, LinkedIn, Zulip and Discord integrations were introduced in Symfony 5.2. The Slack DSN changed in Symfony 5.2 to use Slack Web API again same as in 5.0. +.. versionadded:: 5.3 + + The Mercure integration was introduced in Symfony 5.3. + Chatters are configured using the ``chatter_transports`` setting: .. code-block:: bash From 9df0164ebdc1d62d200142b26126a19d2188b466 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 17 Jan 2021 09:45:42 +0100 Subject: [PATCH 0721/1519] deprecate the NamespacedAttributeBag class --- components/http_foundation/sessions.rst | 10 ++++++++++ session.rst | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/components/http_foundation/sessions.rst b/components/http_foundation/sessions.rst index 9c9479e3e5e..5756a38fc58 100644 --- a/components/http_foundation/sessions.rst +++ b/components/http_foundation/sessions.rst @@ -169,6 +169,11 @@ and "Remember Me" login settings or other user based state information. :class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\NamespacedAttributeBag` This implementation allows for attributes to be stored in a structured namespace. + .. deprecated:: 5.3 + + The ``NamespacedAttributeBag`` class is deprecated since Symfony 5.3. + If you need this feature, you will have to implement the class yourself. + :class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface` has the API @@ -237,6 +242,11 @@ So any processing of this might quickly get ugly, even adding a token to the arr $tokens['c'] = $value; $session->set('tokens', $tokens); +.. deprecated:: 5.3 + + The ``NamespacedAttributeBag`` class is deprecated since Symfony 5.3. + If you need this feature, you will have to implement the class yourself. + With structured namespacing, the key can be translated to the array structure like this using a namespace character (which defaults to ``/``):: diff --git a/session.rst b/session.rst index 47e8cc3d269..394cfece78b 100644 --- a/session.rst +++ b/session.rst @@ -167,6 +167,11 @@ By default, session attributes are key-value pairs managed with the :class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBag` class. +.. deprecated:: 5.3 + + The ``NamespacedAttributeBag`` class is deprecated since Symfony 5.3. + If you need this feature, you will have to implement the class yourself. + If your application needs are complex, you may prefer to use :ref:`namespaced session attributes ` which are managed with the :class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\NamespacedAttributeBag` From b11628ac41a4119918b51b38f6c8572704967507 Mon Sep 17 00:00:00 2001 From: Miky Mikolaj Date: Sun, 17 Jan 2021 17:34:39 +0100 Subject: [PATCH 0722/1519] getId(): ?Uuid missing // need test getId: ?Ulid I added all code as in example, but i had still issue with api-platform that getId() field is wrong defined... I have no experience with ULID !!! Please test my solution for This solved my issue.. and now i am able create, update or delete record without any other issues. I think that this will save lot of time for new users... because fist i thinked that must be public function getId(): ?UuidV4Generator { return $this->id; } but with this my code was still broken... now i know that there must be if you change primary identifier from Int to Uuid use Symfony\Component\Uid\Uuid; public function getId(): ?Uuid { return $this->id; } .... also i think need to done the section of Uuid and Ulid for private $someProperty; getter and setter --- components/uid.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/components/uid.rst b/components/uid.rst index bdeb252bb65..a7fb95d5d2f 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -141,6 +141,7 @@ entity primary keys:: // there are generators for UUID V1 and V6 too use Symfony\Bridge\Doctrine\IdGenerator\UuidV4Generator; + use Symfony\Component\Uid\Uuid; /** * @ORM\Entity(repositoryClass="App\Repository\ProductRepository") @@ -156,6 +157,13 @@ entity primary keys:: private $id; // ... + + public function getId(): ?Uuid + { + return $this->id; + } + + // ... } .. versionadded:: 5.2 @@ -279,6 +287,7 @@ There's also a Doctrine generator to help autogenerate ULID values for the entity primary keys:: use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator; + use Symfony\Component\Uid\Ulid; /** * @ORM\Entity(repositoryClass="App\Repository\ProductRepository") @@ -294,6 +303,14 @@ entity primary keys:: private $id; // ... + + public function getId(): ?Ulid + { + return $this->id; + } + + // ... + } .. versionadded:: 5.2 From b9fe645c2f413143b434d8169b74a518e7b70c40 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 18 Jan 2021 10:05:15 +0100 Subject: [PATCH 0723/1519] expand code example to clarify usage of the UserRepository --- security/experimental_authenticators.rst | 32 +++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index c84f36ed51d..eb0ffa098e0 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -457,13 +457,33 @@ using :ref:`the user provider `:: and must return a ``UserInterface`` object (otherwise a ``UsernameNotFoundException`` is thrown):: + // src/Security/CustomAuthenticator.php + namespace App\Security; + + use App\Repository\UserRepository; // ... - $passport = new Passport( - new UserBadge($email, function ($userIdentifier) { - return $this->userRepository->findOneBy(['email' => $userIdentifier]); - }), - $credentials - ); + + class CustomAuthenticator extends AbstractAuthenticator + { + private $userRepository; + + public function __construct(UserRepository $userRepository) + { + $this->userRepository = $userRepository; + } + + public function authenticate(Request $request): PassportInterface + { + // ... + + return new Passport( + new UserBadge($email, function ($userIdentifier) { + return $this->userRepository->findOneBy(['email' => $userIdentifier]); + }), + $credentials + ); + } + } The following credential classes are supported by default: From d75a175462ff9f8ac8ee411d66ff59d7ad6e6690 Mon Sep 17 00:00:00 2001 From: Boris Sondagh Date: Mon, 18 Jan 2021 15:27:48 +0100 Subject: [PATCH 0724/1519] Update best_practices.rst --- bundles/best_practices.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bundles/best_practices.rst b/bundles/best_practices.rst index 696c9da58ff..80e13b8b10b 100644 --- a/bundles/best_practices.rst +++ b/bundles/best_practices.rst @@ -25,6 +25,7 @@ namespace short name, which must end with ``Bundle``. A namespace becomes a bundle as soon as you add a bundle class to it. The bundle class name must follow these rules: +* Extend Symfony\Component\HttpKernel\Bundle\Bundle * Use only alphanumeric characters and underscores; * Use a StudlyCaps name (i.e. camelCase with an uppercase first letter); * Use a descriptive and short name (no more than two words); @@ -41,9 +42,6 @@ Namespace Bundle Class Name ``Acme\BlogBundle`` AcmeBlogBundle ========================== ================== -By convention, the ``getName()`` method of the bundle class should return the -class name. - .. note:: If you share your bundle publicly, you must use the bundle class name as From 7c0db224906e62a43283971d6eac064588159623 Mon Sep 17 00:00:00 2001 From: Christopher Date: Tue, 19 Jan 2021 11:12:38 +0000 Subject: [PATCH 0725/1519] Added missing Dotenv use --- migration.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/migration.rst b/migration.rst index 6b71a07670b..ec42dfd4a33 100644 --- a/migration.rst +++ b/migration.rst @@ -239,6 +239,7 @@ could look something like this:: use App\Kernel; use App\LegacyBridge; use Symfony\Component\Debug\Debug; + use Symfony\Component\Dotenv\Dotenv; use Symfony\Component\HttpFoundation\Request; require dirname(__DIR__).'/vendor/autoload.php'; From b2be224760b653cfb0aa6f7e0d45e62c27ee0b2f Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 19 Jan 2021 09:08:55 +0100 Subject: [PATCH 0726/1519] Use Sf4 + Sf5 instead of Sf3 for bundle best practices --- bundles/best_practices.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bundles/best_practices.rst b/bundles/best_practices.rst index 696c9da58ff..c9dab120c53 100644 --- a/bundles/best_practices.rst +++ b/bundles/best_practices.rst @@ -181,15 +181,15 @@ A bundle should at least test: * All supported major Symfony versions (e.g. both ``4.x`` and ``5.x`` if support is claimed for both). -Thus, a bundle supporting PHP 7.3, 7.4 and 8.0, and Symfony 3.4 and 4.x should +Thus, a bundle supporting PHP 7.3, 7.4 and 8.0, and Symfony 4.4 and 5.x should have at least this test matrix: =========== =============== =================== PHP version Symfony version Composer flags =========== =============== =================== -7.3 ``3.*`` ``--prefer-lowest`` -7.4 ``4.*`` -8.0 ``4.*`` +7.3 ``4.*`` ``--prefer-lowest`` +7.4 ``5.*`` +8.0 ``5.*`` =========== =============== =================== .. tip:: From 26e88f7da3322a594b9eccbdce021bb6cf6fd4d4 Mon Sep 17 00:00:00 2001 From: Christin Gruber Date: Wed, 20 Jan 2021 17:26:23 +0100 Subject: [PATCH 0727/1519] Add symfony/gitter-notifier docs --- notifier.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 73bdf4d86ed..a2072e79c13 100644 --- a/notifier.rst +++ b/notifier.rst @@ -150,6 +150,7 @@ Service Package DSN ========== ================================ =========================================================================== Discord ``symfony/discord-notifier`` ``discord://TOKEN@default?webhook_id=ID`` Firebase ``symfony/firebase-notifier`` ``firebase://USERNAME:PASSWORD@default`` +Gitter ``symfony/gitter-notifier`` ``GITTER_DSN=gitter://TOKEN@default?room_id=ROOM_ID`` GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?thread_key=THREAD_KEY`` LinkedIn ``symfony/linked-in-notifier`` ``linkedin://TOKEN:USER_ID@default`` Mattermost ``symfony/mattermost-notifier`` ``mattermost://ACCESS_TOKEN@HOST/PATH?channel=CHANNEL`` @@ -173,7 +174,7 @@ Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:TOKEN@HOST?channel .. versionadded:: 5.3 - The Mercure integration was introduced in Symfony 5.3. + The Gitter and Mercure integrations were introduced in Symfony 5.3. Chatters are configured using the ``chatter_transports`` setting: From 748bd54c675fbe0aeb6c01f385c5e68d002d1157 Mon Sep 17 00:00:00 2001 From: Wojciech Kania Date: Sat, 14 Nov 2020 15:37:16 +0100 Subject: [PATCH 0728/1519] [Validator] Document constraints as php 8 Attributes --- reference/constraints/Bic.rst | 13 +++ reference/constraints/Blank.rst | 13 +++ reference/constraints/Callback.rst | 30 +++++++ reference/constraints/CardScheme.rst | 16 ++++ reference/constraints/Choice.rst | 45 ++++++++++ reference/constraints/Count.rst | 18 ++++ reference/constraints/Country.rst | 13 +++ reference/constraints/Currency.rst | 13 +++ reference/constraints/Date.rst | 13 +++ reference/constraints/DateTime.rst | 16 ++++ reference/constraints/DivisibleBy.rst | 18 ++++ reference/constraints/Email.rst | 15 ++++ reference/constraints/EqualTo.rst | 18 ++++ reference/constraints/Expression.rst | 54 ++++++++++++ .../constraints/ExpressionLanguageSyntax.rst | 18 ++++ reference/constraints/File.rst | 17 ++++ reference/constraints/GreaterThan.rst | 57 +++++++++++++ reference/constraints/GreaterThanOrEqual.rst | 57 +++++++++++++ reference/constraints/Hostname.rst | 13 +++ reference/constraints/Iban.rst | 15 ++++ reference/constraints/IdenticalTo.rst | 18 ++++ reference/constraints/Image.rst | 34 ++++++++ reference/constraints/Ip.rst | 13 +++ reference/constraints/IsFalse.rst | 18 ++++ reference/constraints/IsNull.rst | 13 +++ reference/constraints/IsTrue.rst | 18 ++++ reference/constraints/Isbn.rst | 16 ++++ reference/constraints/Isin.rst | 13 +++ reference/constraints/Issn.rst | 13 +++ reference/constraints/Json.rst | 15 ++++ reference/constraints/Language.rst | 13 +++ reference/constraints/Length.rst | 19 +++++ reference/constraints/LessThan.rst | 57 +++++++++++++ reference/constraints/LessThanOrEqual.rst | 57 +++++++++++++ reference/constraints/Locale.rst | 15 ++++ reference/constraints/Luhn.rst | 13 +++ reference/constraints/Negative.rst | 13 +++ reference/constraints/NegativeOrZero.rst | 13 +++ reference/constraints/NotBlank.rst | 13 +++ .../constraints/NotCompromisedPassword.rst | 13 +++ reference/constraints/NotEqualTo.rst | 18 ++++ reference/constraints/NotIdenticalTo.rst | 18 ++++ reference/constraints/NotNull.rst | 13 +++ reference/constraints/Positive.rst | 13 +++ reference/constraints/PositiveOrZero.rst | 13 +++ reference/constraints/Range.rst | 65 +++++++++++++++ reference/constraints/Regex.rst | 46 +++++++++++ reference/constraints/Time.rst | 16 ++++ reference/constraints/Timezone.rst | 13 +++ reference/constraints/Traverse.rst | 82 +++++++++++++++++++ reference/constraints/Type.rst | 25 ++++++ reference/constraints/Ulid.rst | 13 +++ reference/constraints/Unique.rst | 13 +++ reference/constraints/UniqueEntity.rst | 54 ++++++++++++ reference/constraints/Url.rst | 58 +++++++++++++ reference/constraints/UserPassword.rst | 15 ++++ reference/constraints/Uuid.rst | 13 +++ reference/constraints/Valid.rst | 47 +++++++++++ 58 files changed, 1404 insertions(+) diff --git a/reference/constraints/Bic.rst b/reference/constraints/Bic.rst index 029a322e294..076cbf29b6c 100644 --- a/reference/constraints/Bic.rst +++ b/reference/constraints/Bic.rst @@ -41,6 +41,19 @@ will contain a Business Identifier Code (BIC). protected $businessIdentifierCode; } + .. code-block:: php-attributes + + // src/Entity/Transaction.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Transaction + { + #[Assert\Bic] + protected $businessIdentifierCode; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Blank.rst b/reference/constraints/Blank.rst index 8a5ba13671a..fbbd693e013 100644 --- a/reference/constraints/Blank.rst +++ b/reference/constraints/Blank.rst @@ -45,6 +45,19 @@ of an ``Author`` class were blank, you could do the following: protected $firstName; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Blank] + protected $firstName; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Callback.rst b/reference/constraints/Callback.rst index 6985f3953e1..d15337ba9b5 100644 --- a/reference/constraints/Callback.rst +++ b/reference/constraints/Callback.rst @@ -50,6 +50,23 @@ Configuration } } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Context\ExecutionContextInterface; + + class Author + { + #[Assert\Callback] + public function validate(ExecutionContextInterface $context, $payload) + { + // ... + } + } + .. code-block:: yaml # config/validator/validation.yaml @@ -178,6 +195,19 @@ You can then use the following configuration to invoke this validator: { } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Acme\Validator; + use Symfony\Component\Validator\Constraints as Assert; + + #[Assert\Callback([Validator::class, 'validate'])] + class Author + { + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/CardScheme.rst b/reference/constraints/CardScheme.rst index 64d6157e2c8..d93224e1a5a 100644 --- a/reference/constraints/CardScheme.rst +++ b/reference/constraints/CardScheme.rst @@ -41,6 +41,22 @@ on an object that will contain a credit card number. protected $cardNumber; } + .. code-block:: php-attributes + + // src/Entity/Transaction.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Transaction + { + #[Assert\CardScheme( + schemes: [Assert\CardScheme::VISA], + message: 'Your credit card number is invalid.', + )] + protected $cardNumber; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Choice.rst b/reference/constraints/Choice.rst index fd8481d6152..4afa6b516d9 100644 --- a/reference/constraints/Choice.rst +++ b/reference/constraints/Choice.rst @@ -58,6 +58,24 @@ If your valid choice list is simple, you can pass them in directly via the protected $genre; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + const GENRES = ['fiction', 'non-fiction']; + + #[Assert\Choice(['New York', 'Berlin', 'Tokyo'])] + protected $city; + + #[Assert\Choice(choices: Author::GENRES, message: 'Choose a valid genre.')] + protected $genre; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -160,6 +178,19 @@ constraint. protected $genre; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Choice(callback: 'getGenres')] + protected $genre; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -225,6 +256,20 @@ you can pass the class name and the method as an array. protected $genre; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use App\Entity\Genre + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Choice(callback: [Genre::class, 'getGenres'])] + protected $genre; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Count.rst b/reference/constraints/Count.rst index 4ce4691c6c9..c40294a8684 100644 --- a/reference/constraints/Count.rst +++ b/reference/constraints/Count.rst @@ -47,6 +47,24 @@ you might add the following: protected $emails = []; } + .. code-block:: php-attributes + + // src/Entity/Participant.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Participant + { + #[Assert\Count( + min: 1, + max: 5, + minMessage: 'You must specify at least one email', + maxMessage: 'You cannot specify more than {{ limit }} emails', + )] + protected $emails = []; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Country.rst b/reference/constraints/Country.rst index 744de6dd0fb..62bf38bf2ba 100644 --- a/reference/constraints/Country.rst +++ b/reference/constraints/Country.rst @@ -33,6 +33,19 @@ Basic Usage protected $country; } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class User + { + #[Assert\Country] + protected $country; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Currency.rst b/reference/constraints/Currency.rst index 651af1b1a92..e481c0ce01d 100644 --- a/reference/constraints/Currency.rst +++ b/reference/constraints/Currency.rst @@ -35,6 +35,19 @@ a valid currency, you could do the following: protected $currency; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\Currency] + protected $currency; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Date.rst b/reference/constraints/Date.rst index 4b1e99c3ed1..7376195960a 100644 --- a/reference/constraints/Date.rst +++ b/reference/constraints/Date.rst @@ -34,6 +34,19 @@ Basic Usage protected $birthday; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Date] + protected $birthday; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/DateTime.rst b/reference/constraints/DateTime.rst index 582f93aeac8..7e5501b5515 100644 --- a/reference/constraints/DateTime.rst +++ b/reference/constraints/DateTime.rst @@ -35,6 +35,22 @@ Basic Usage protected $createdAt; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + /** + * @var string A "Y-m-d H:i:s" formatted value + */ + #[Assert\DateTime] + protected $createdAt; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/DivisibleBy.rst b/reference/constraints/DivisibleBy.rst index 4503959aa57..d08e22c241c 100644 --- a/reference/constraints/DivisibleBy.rst +++ b/reference/constraints/DivisibleBy.rst @@ -53,6 +53,24 @@ The following constraints ensure that: protected $quantity; } + .. code-block:: php-attributes + + // src/Entity/Item.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Item + { + #[Assert\DivisibleBy(0.25)] + protected $weight; + + #[Assert\DivisibleBy( + value: 5, + )] + protected $quantity; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Email.rst b/reference/constraints/Email.rst index 468051004a0..fd2f2576a90 100644 --- a/reference/constraints/Email.rst +++ b/reference/constraints/Email.rst @@ -37,6 +37,21 @@ Basic Usage protected $email; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Email( + message: 'The email {{ value }} is not a valid email.', + )] + protected $email; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/EqualTo.rst b/reference/constraints/EqualTo.rst index 153d13a3098..75d80043cda 100644 --- a/reference/constraints/EqualTo.rst +++ b/reference/constraints/EqualTo.rst @@ -52,6 +52,24 @@ and that the ``age`` is ``20``, you could do the following: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\EqualTo("Mary")] + protected $firstName; + + #[Assert\EqualTo( + value: 20, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Expression.rst b/reference/constraints/Expression.rst index 2ed816f3a03..264ae3b02fc 100644 --- a/reference/constraints/Expression.rst +++ b/reference/constraints/Expression.rst @@ -78,6 +78,22 @@ One way to accomplish this is with the Expression constraint: // ... } + .. code-block:: php-attributes + + // src/Model/BlogPost.php + namespace App\Model; + + use Symfony\Component\Validator\Constraints as Assert; + + #[Assert\Expression( + "this.getCategory() in ['php', 'symfony'] or !this.isTechnicalPost()", + message: 'If this is a tech post, the category should be either php or symfony!', + )] + class BlogPost + { + // ... + } + .. code-block:: yaml # config/validator/validation.yaml @@ -163,6 +179,26 @@ more about the expression language syntax, see // ... } + .. code-block:: php-attributes + + // src/Model/BlogPost.php + namespace App\Model; + + use Symfony\Component\Validator\Constraints as Assert; + + class BlogPost + { + // ... + + #[Assert\Expression( + "this.getCategory() in ['php', 'symfony'] or value == false", + message: 'If this is a tech post, the category should be either php or symfony!', + )] + private $isTechnicalPost; + + // ... + } + .. code-block:: yaml # config/validator/validation.yaml @@ -299,6 +335,24 @@ type (numeric, boolean, strings, null, etc.) // ... } + .. code-block:: php-attributes + + // src/Model/Analysis.php + namespace App\Model; + + use Symfony\Component\Validator\Constraints as Assert; + + class Analysis + { + #[Assert\Expression( + 'value + error_margin < threshold', + values: ['error_margin' => 0.25, 'threshold' => 1.5], + )] + private $metric; + + // ... + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/ExpressionLanguageSyntax.rst b/reference/constraints/ExpressionLanguageSyntax.rst index 2ca0355dfaf..218d68d4f69 100644 --- a/reference/constraints/ExpressionLanguageSyntax.rst +++ b/reference/constraints/ExpressionLanguageSyntax.rst @@ -52,6 +52,24 @@ The following constraints ensure that: protected $shippingOptions; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\ExpressionLanguageSyntax] + protected $promotion; + + #[Assert\ExpressionLanguageSyntax( + allowedVariables: ['user', 'shipping_centers'], + )] + protected $shippingOptions; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/File.rst b/reference/constraints/File.rst index f1a27ac8f20..7bce9dce533 100644 --- a/reference/constraints/File.rst +++ b/reference/constraints/File.rst @@ -93,6 +93,23 @@ below a certain file size and a valid PDF, add the following: protected $bioFile; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\File( + maxSize: '1024k', + mimeTypes: ['application/pdf', 'application/x-pdf'], + mimeTypesMessage: 'Please upload a valid PDF', + )] + protected $bioFile; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/GreaterThan.rst b/reference/constraints/GreaterThan.rst index d27017fdbe5..617fc71f2a0 100644 --- a/reference/constraints/GreaterThan.rst +++ b/reference/constraints/GreaterThan.rst @@ -49,6 +49,24 @@ The following constraints ensure that: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\GreaterThan(5)] + protected $siblings; + + #[Assert\GreaterThan( + value: 18, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -126,6 +144,19 @@ that a date must at least be the next day: protected $deliveryDate; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\GreaterThan('today')] + protected $deliveryDate; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -185,6 +216,19 @@ dates. If you want to fix the timezone, append it to the date string: protected $deliveryDate; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\GreaterThan('today UTC')] + protected $deliveryDate; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -245,6 +289,19 @@ current time: protected $deliveryDate; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\GreaterThan('+5 hours')] + protected $deliveryDate; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/GreaterThanOrEqual.rst b/reference/constraints/GreaterThanOrEqual.rst index 8a054e6bbb9..c09d4e250e0 100644 --- a/reference/constraints/GreaterThanOrEqual.rst +++ b/reference/constraints/GreaterThanOrEqual.rst @@ -48,6 +48,24 @@ The following constraints ensure that: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\GreaterThanOrEqual(5)] + protected $siblings; + + #[Assert\GreaterThanOrEqual( + value: 18, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -125,6 +143,19 @@ that a date must at least be the current day: protected $deliveryDate; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\GreaterThanOrEqual('today')] + protected $deliveryDate; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -184,6 +215,19 @@ dates. If you want to fix the timezone, append it to the date string: protected $deliveryDate; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\GreaterThanOrEqual('today UTC')] + protected $deliveryDate; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -244,6 +288,19 @@ current time: protected $deliveryDate; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\GreaterThanOrEqual('+5 hours')] + protected $deliveryDate; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Hostname.rst b/reference/constraints/Hostname.rst index 9e67fb3c8fc..7b6cf07af21 100644 --- a/reference/constraints/Hostname.rst +++ b/reference/constraints/Hostname.rst @@ -42,6 +42,19 @@ will contain a host name. protected $name; } + .. code-block:: php-attributes + + // src/Entity/ServerSettings.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class ServerSettings + { + #[Assert\Hostname(message: 'The server name must be a valid hostname.')] + protected $name; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Iban.rst b/reference/constraints/Iban.rst index 709270f7b12..dcd60e3f408 100644 --- a/reference/constraints/Iban.rst +++ b/reference/constraints/Iban.rst @@ -40,6 +40,21 @@ will contain an International Bank Account Number. protected $bankAccountNumber; } + .. code-block:: php-attributes + + // src/Entity/Transaction.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Transaction + { + #[Assert\Iban( + message: 'This is not a valid International Bank Account Number (IBAN).', + )] + protected $bankAccountNumber; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/IdenticalTo.rst b/reference/constraints/IdenticalTo.rst index 10f1fb52342..7dc71b475f0 100644 --- a/reference/constraints/IdenticalTo.rst +++ b/reference/constraints/IdenticalTo.rst @@ -54,6 +54,24 @@ The following constraints ensure that: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\IdenticalTo("Mary")] + protected $firstName; + + #[Assert\IdenticalTo( + value: 20, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Image.rst b/reference/constraints/Image.rst index e8b492bf4ae..5ffded599b5 100644 --- a/reference/constraints/Image.rst +++ b/reference/constraints/Image.rst @@ -100,6 +100,24 @@ that it is between a certain size, add the following: protected $headshot; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Image( + minWidth: 200, + maxWidth: 400, + minHeight: 200, + maxHeight: 400, + )] + protected $headshot; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -180,6 +198,22 @@ following code: protected $headshot; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Image( + allowLandscape: false, + allowPortrait: false, + )] + protected $headshot; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Ip.rst b/reference/constraints/Ip.rst index 9d744d54c09..3686d6bfc41 100644 --- a/reference/constraints/Ip.rst +++ b/reference/constraints/Ip.rst @@ -36,6 +36,19 @@ Basic Usage protected $ipAddress; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Ip] + protected $ipAddress; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/IsFalse.rst b/reference/constraints/IsFalse.rst index 17881aa9a75..07f25396c66 100644 --- a/reference/constraints/IsFalse.rst +++ b/reference/constraints/IsFalse.rst @@ -58,6 +58,24 @@ method returns **false**: } } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\IsFalse( + message: "You've entered an invalid state." + )] + public function isStateInvalid() + { + // ... + } + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/IsNull.rst b/reference/constraints/IsNull.rst index 252c23d934b..6fcd1e462ad 100644 --- a/reference/constraints/IsNull.rst +++ b/reference/constraints/IsNull.rst @@ -39,6 +39,19 @@ of an ``Author`` class exactly equal to ``null``, you could do the following: protected $firstName; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\IsNull] + protected $firstName; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/IsTrue.rst b/reference/constraints/IsTrue.rst index 2698ad233e9..dea5d9c5468 100644 --- a/reference/constraints/IsTrue.rst +++ b/reference/constraints/IsTrue.rst @@ -60,6 +60,24 @@ Then you can validate this method with ``IsTrue`` as follows: } } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + protected $token; + + #[Assert\IsTrue(message: 'The token is invalid.')] + public function isTokenValid() + { + return $this->token == $this->generateToken(); + } + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Isbn.rst b/reference/constraints/Isbn.rst index e30d4e96040..fa042eb131e 100644 --- a/reference/constraints/Isbn.rst +++ b/reference/constraints/Isbn.rst @@ -43,6 +43,22 @@ on an object that will contain an ISBN. protected $isbn; } + .. code-block:: php-attributes + + // src/Entity/Book.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Book + { + #[Assert\Isbn( + type: Assert\Isbn::ISBN_10, + message: 'This value is not valid.', + )] + protected $isbn; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Isin.rst b/reference/constraints/Isin.rst index c646f33a53a..3efab915437 100644 --- a/reference/constraints/Isin.rst +++ b/reference/constraints/Isin.rst @@ -33,6 +33,19 @@ Basic Usage protected $isin; } + .. code-block:: php-attributes + + // src/Entity/UnitAccount.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class UnitAccount + { + #[Assert\Isin] + protected $isin; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Issn.rst b/reference/constraints/Issn.rst index 6cc5734aaa2..8b8d0826610 100644 --- a/reference/constraints/Issn.rst +++ b/reference/constraints/Issn.rst @@ -35,6 +35,19 @@ Basic Usage protected $issn; } + .. code-block:: php-attributes + + // src/Entity/Journal.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Journal + { + #[Assert\Issn] + protected $issn; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Json.rst b/reference/constraints/Json.rst index 6e8318077da..cd1abf69d6c 100644 --- a/reference/constraints/Json.rst +++ b/reference/constraints/Json.rst @@ -35,6 +35,21 @@ The ``Json`` constraint can be applied to a property or a "getter" method: private $chapters; } + .. code-block:: php-attributes + + // src/Entity/Book.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Book + { + #[Assert\Json( + message: "You've entered an invalid Json." + )] + private $chapters; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Language.rst b/reference/constraints/Language.rst index dac3e2819db..0d9522dc882 100644 --- a/reference/constraints/Language.rst +++ b/reference/constraints/Language.rst @@ -34,6 +34,19 @@ Basic Usage protected $preferredLanguage; } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class User + { + #[Assert\Language] + protected $preferredLanguage; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Length.rst b/reference/constraints/Length.rst index 365aedfb585..13800f7daea 100644 --- a/reference/constraints/Length.rst +++ b/reference/constraints/Length.rst @@ -48,6 +48,25 @@ and "50", you might add the following: protected $firstName; } + .. code-block:: php-attributes + + // src/Entity/Participant.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Participant + { + #[Assert\Length( + min: 2, + max: 50, + minMessage: 'Your first name must be at least {{ limit }} characters long', + maxMessage: 'Your first name cannot be longer than {{ limit }} characters', + )] + protected $firstName; + } + + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/LessThan.rst b/reference/constraints/LessThan.rst index abd0aab721c..495d3f4356a 100644 --- a/reference/constraints/LessThan.rst +++ b/reference/constraints/LessThan.rst @@ -49,6 +49,24 @@ The following constraints ensure that: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThan(5)] + protected $siblings; + + #[Assert\LessThan( + value: 80, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -126,6 +144,19 @@ that a date must be in the past like this: protected $dateOfBirth; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThan('today')] + protected $dateOfBirth; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -185,6 +216,19 @@ dates. If you want to fix the timezone, append it to the date string: protected $dateOfBirth; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThan('today UTC')] + protected $dateOfBirth; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -244,6 +288,19 @@ can check that a person must be at least 18 years old like this: protected $dateOfBirth; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThan('-18 years')] + protected $dateOfBirth; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/LessThanOrEqual.rst b/reference/constraints/LessThanOrEqual.rst index 42ec3e939e5..47d06cfc601 100644 --- a/reference/constraints/LessThanOrEqual.rst +++ b/reference/constraints/LessThanOrEqual.rst @@ -48,6 +48,24 @@ The following constraints ensure that: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThanOrEqual(5)] + protected $siblings; + + #[Assert\LessThanOrEqual( + value: 80, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -125,6 +143,19 @@ that a date must be today or in the past like this: protected $dateOfBirth; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThanOrEqual('today')] + protected $dateOfBirth; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -184,6 +215,19 @@ dates. If you want to fix the timezone, append it to the date string: protected $dateOfBirth; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThanOrEqual('today UTC')] + protected $dateOfBirth; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -243,6 +287,19 @@ can check that a person must be at least 18 years old like this: protected $dateOfBirth; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThanOrEqual('-18 years')] + protected $dateOfBirth; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Locale.rst b/reference/constraints/Locale.rst index f5f381629e3..936cfd24089 100644 --- a/reference/constraints/Locale.rst +++ b/reference/constraints/Locale.rst @@ -43,6 +43,21 @@ Basic Usage protected $locale; } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class User + { + #[Assert\Locale( + canonicalize: true, + )] + protected $locale; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Luhn.rst b/reference/constraints/Luhn.rst index 2bee41d5f2c..24eb9b91947 100644 --- a/reference/constraints/Luhn.rst +++ b/reference/constraints/Luhn.rst @@ -37,6 +37,19 @@ will contain a credit card number. protected $cardNumber; } + .. code-block:: php-attributes + + // src/Entity/Transaction.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Transaction + { + #[Assert\Luhn(message: 'Please check your credit card number.')] + protected $cardNumber; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Negative.rst b/reference/constraints/Negative.rst index 7468b4bfc4a..0ee0bdcf3ea 100644 --- a/reference/constraints/Negative.rst +++ b/reference/constraints/Negative.rst @@ -37,6 +37,19 @@ The following constraint ensures that the ``withdraw`` of a bank account protected $withdraw; } + .. code-block:: php-attributes + + // src/Entity/TransferItem.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class TransferItem + { + #[Assert\Negative] + protected $withdraw; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/NegativeOrZero.rst b/reference/constraints/NegativeOrZero.rst index f010acda0b1..8559a57babf 100644 --- a/reference/constraints/NegativeOrZero.rst +++ b/reference/constraints/NegativeOrZero.rst @@ -36,6 +36,19 @@ is a negative number or equal to zero: protected $level; } + .. code-block:: php-attributes + + // src/Entity/TransferItem.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class UnderGroundGarage + { + #[Assert\NegativeOrZero] + protected $level; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/NotBlank.rst b/reference/constraints/NotBlank.rst index f5711e001c3..2d302f5fc20 100644 --- a/reference/constraints/NotBlank.rst +++ b/reference/constraints/NotBlank.rst @@ -40,6 +40,19 @@ class were not blank, you could do the following: protected $firstName; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\NotBlank] + protected $firstName; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/NotCompromisedPassword.rst b/reference/constraints/NotCompromisedPassword.rst index bcd1c61b560..236dfbf5d9b 100644 --- a/reference/constraints/NotCompromisedPassword.rst +++ b/reference/constraints/NotCompromisedPassword.rst @@ -38,6 +38,19 @@ The following constraint ensures that the ``rawPassword`` property of the protected $rawPassword; } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class User + { + #[Assert\NotCompromisedPassword] + protected $rawPassword; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/NotEqualTo.rst b/reference/constraints/NotEqualTo.rst index e1436657ae8..ec5fa5000b5 100644 --- a/reference/constraints/NotEqualTo.rst +++ b/reference/constraints/NotEqualTo.rst @@ -53,6 +53,24 @@ the following: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\NotEqualTo('Mary')] + protected $firstName; + + #[Assert\NotEqualTo( + value: 15, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/NotIdenticalTo.rst b/reference/constraints/NotIdenticalTo.rst index 66ccb871670..ab96bde3806 100644 --- a/reference/constraints/NotIdenticalTo.rst +++ b/reference/constraints/NotIdenticalTo.rst @@ -54,6 +54,24 @@ The following constraints ensure that: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\NotIdenticalTo('Mary')] + protected $firstName; + + #[Assert\NotIdenticalTo( + value: 15, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/NotNull.rst b/reference/constraints/NotNull.rst index 56d088c4cba..ccf8839434d 100644 --- a/reference/constraints/NotNull.rst +++ b/reference/constraints/NotNull.rst @@ -37,6 +37,19 @@ class were not strictly equal to ``null``, you would: protected $firstName; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\NotNull] + protected $firstName; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Positive.rst b/reference/constraints/Positive.rst index af76f205e53..6e5d80c9250 100644 --- a/reference/constraints/Positive.rst +++ b/reference/constraints/Positive.rst @@ -37,6 +37,19 @@ positive number (greater than zero): protected $income; } + .. code-block:: php-attributes + + // src/Entity/Employee.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Employee + { + #[Assert\Positive] + protected $income; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/PositiveOrZero.rst b/reference/constraints/PositiveOrZero.rst index ea762e78f90..08435c2054f 100644 --- a/reference/constraints/PositiveOrZero.rst +++ b/reference/constraints/PositiveOrZero.rst @@ -36,6 +36,19 @@ is positive or zero: protected $siblings; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\PositiveOrZero] + protected $siblings; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Range.rst b/reference/constraints/Range.rst index d5b473362dd..c499187ee66 100644 --- a/reference/constraints/Range.rst +++ b/reference/constraints/Range.rst @@ -47,6 +47,23 @@ you might add the following: protected $height; } + .. code-block:: php-attributes + + // src/Entity/Participant.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Participant + { + #[Assert\Range( + min: 120, + max: 180, + notInRangeMessage: 'You must be between {{ min }}cm and {{ max }}cm tall to enter', + )] + protected $height; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -125,6 +142,22 @@ date must lie within the current year like this: protected $startDate; } + .. code-block:: php-attributes + + // src/Entity/Event.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Event + { + #[Assert\Range( + min: 'first day of January', + max: 'first day of January next year', + )] + protected $startDate; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -195,6 +228,22 @@ dates. If you want to fix the timezone, append it to the date string: protected $startDate; } + .. code-block:: php-attributes + + // src/Entity/Event.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Event + { + #[Assert\Range( + min: 'first day of January UTC', + max: 'first day of January next year UTC', + )] + protected $startDate; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -265,6 +314,22 @@ can check that a delivery date starts within the next five hours like this: protected $deliveryDate; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\Range( + min: 'now', + max: '+5 hours', + )] + protected $deliveryDate; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Regex.rst b/reference/constraints/Regex.rst index 642a1fc180d..a6217c892f7 100644 --- a/reference/constraints/Regex.rst +++ b/reference/constraints/Regex.rst @@ -41,6 +41,19 @@ more word characters at the beginning of your string: protected $description; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Regex('/^\w+/')] + protected $description; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -110,6 +123,23 @@ it a custom message: protected $firstName; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Regex( + pattern: '/\d/', + match: false, + message: 'Your name cannot contain a number', + )] + protected $firstName; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -203,6 +233,22 @@ need to specify the HTML5 compatible pattern in the ``htmlPattern`` option: protected $name; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Regex( + pattern: '/^[a-z]+$/i', + match: '^[a-zA-Z]+$' + )] + protected $name; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Time.rst b/reference/constraints/Time.rst index e94613e1f6f..fb8a9b337fb 100644 --- a/reference/constraints/Time.rst +++ b/reference/constraints/Time.rst @@ -37,6 +37,22 @@ of the day when the event starts: protected $startsAt; } + .. code-block:: php-attributes + + // src/Entity/Event.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Event + { + /** + * @var string A "H:i:s" formatted value + */ + #[Assert\Time] + protected $startsAt; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index 98ca73c156a..36ebdd0b86b 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -38,6 +38,19 @@ string which contains any of the `PHP timezone identifiers`_ (e.g. ``America/New protected $timezone; } + .. code-block:: php-attributes + + // src/Entity/UserSettings.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class UserSettings + { + #[Assert\Timezone] + protected $timezone; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Traverse.rst b/reference/constraints/Traverse.rst index fd329bd38a3..9301afc445a 100644 --- a/reference/constraints/Traverse.rst +++ b/reference/constraints/Traverse.rst @@ -89,6 +89,73 @@ that all have constraints on their properties. } } + .. code-block:: php-attributes + + // src/Entity/BookCollection.php + namespace App\Entity; + + use Doctrine\Common\Collections\ArrayCollection; + use Doctrine\Common\Collections\Collection + use Doctrine\ORM\Mapping as ORM; + use Symfony\Component\Validator\Constraints as Assert; + + /** + * @ORM\Entity + */ + #[Assert\Traverse] + class BookCollection implements \IteratorAggregate + { + /** + * @var string + * + * @ORM\Column + */ + #[Assert\NotBlank] + protected $name = ''; + + /** + * @var Collection|Book[] + * + * @ORM\ManyToMany(targetEntity="App\Entity\Book") + */ + protected $books; + + // some other properties + + public function __construct() + { + $this->books = new ArrayCollection(); + } + + // ... setter for name, adder and remover for books + + // the name can be validated by calling the getter + public function getName(): string + { + return $this->name; + } + + /** + * @return \Generator|Book[] The books for a given author + */ + public function getBooksForAuthor(Author $author): iterable + { + foreach ($this->books as $book) { + if ($book->isAuthoredBy($author)) { + yield $book; + } + } + } + + // neither the method above nor any other specific getter + // could be used to validated all nested books; + // this object needs to be traversed to call the iterator + public function getIterator() + { + return $this->books->getIterator(); + } + } + .. code-block:: yaml # config/validator/validation.yaml @@ -168,6 +235,21 @@ disable validating: // ... } + .. code-block:: php-attributes + + // src/Entity/BookCollection.php + + // ... same as above + + /** + * ... + */ + #[Assert\Traverse(false)] + class BookCollection implements \IteratorAggregate + { + // ... + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Type.rst b/reference/constraints/Type.rst index 1962dffa284..61189e7f989 100644 --- a/reference/constraints/Type.rst +++ b/reference/constraints/Type.rst @@ -59,6 +59,31 @@ This will check if ``id`` is an instance of ``Ramsey\Uuid\UuidInterface``, protected $accessCode; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Type('Ramsey\Uuid\UuidInterface')] + protected $id; + + #[Assert\Type('string')] + protected $firstName; + + #[Assert\Type( + type: 'integer', + message: 'The value {{ value }} is not a valid {{ type }}.', + )] + protected $age; + + #[Assert\Type(type: ['alpha', 'digit'])] + protected $accessCode; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Ulid.rst b/reference/constraints/Ulid.rst index 7bcae08e961..92315089350 100644 --- a/reference/constraints/Ulid.rst +++ b/reference/constraints/Ulid.rst @@ -37,6 +37,19 @@ Basic Usage protected $identifier; } + .. code-block:: php-attributes + + // src/Entity/File.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class File + { + #[Assert\Ulid] + protected $identifier; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Unique.rst b/reference/constraints/Unique.rst index 97cb6ff8602..497156ed9b4 100644 --- a/reference/constraints/Unique.rst +++ b/reference/constraints/Unique.rst @@ -50,6 +50,19 @@ strings: protected $contactEmails; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\Unique] + protected $contactEmails; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/UniqueEntity.rst b/reference/constraints/UniqueEntity.rst index 2bf2533f57e..c76a31e6a4c 100644 --- a/reference/constraints/UniqueEntity.rst +++ b/reference/constraints/UniqueEntity.rst @@ -59,6 +59,31 @@ between all of the rows in your user table: protected $email; } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Doctrine\ORM\Mapping as ORM; + + // DON'T forget the following use statement!!! + use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; + + use Symfony\Component\Validator\Constraints as Assert; + + /** + * @ORM\Entity + */ + #[UniqueEntity('email')] + class User + { + /** + * @ORM\Column(name="email", type="string", length=255, unique=true) + */ + #[Assert\Email] + protected $email; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -188,6 +213,35 @@ Consider this example: public $port; } + .. code-block:: php-attributes + + // src/Entity/Service.php + namespace App\Entity; + + use Doctrine\ORM\Mapping as ORM; + use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; + + /** + * @ORM\Entity + */ + #[UniqueEntity( + fields: ['host', 'port'], + errorPath: 'port', + message: 'This port is already in use on that host.', + )] + class Service + { + /** + * @ORM\ManyToOne(targetEntity="App\Entity\Host") + */ + public $host; + + /** + * @ORM\Column(type="integer") + */ + public $port; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Url.rst b/reference/constraints/Url.rst index 5f4ac23245f..91714131294 100644 --- a/reference/constraints/Url.rst +++ b/reference/constraints/Url.rst @@ -35,6 +35,19 @@ Basic Usage protected $bioUrl; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Url] + protected $bioUrl; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -124,6 +137,21 @@ Parameter Description protected $bioUrl; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Url( + message: 'The url {{ value }} is not a valid url', + )] + protected $bioUrl; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -200,6 +228,21 @@ the ``ftp://`` type URLs to be valid, redefine the ``protocols`` array, listing protected $bioUrl; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Url( + protocols: ['http', 'https', 'ftp'], + )] + protected $bioUrl; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -275,6 +318,21 @@ also relative URLs that contain no protocol (e.g. ``//example.com``). protected $bioUrl; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Url( + relativeProtocol: true, + )] + protected $bioUrl; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/UserPassword.rst b/reference/constraints/UserPassword.rst index 9655380bf95..03c992e66e6 100644 --- a/reference/constraints/UserPassword.rst +++ b/reference/constraints/UserPassword.rst @@ -51,6 +51,21 @@ the user's current password: protected $oldPassword; } + .. code-block:: php-attributes + + // src/Form/Model/ChangePassword.php + namespace App\Form\Model; + + use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert; + + class ChangePassword + { + #[SecurityAssert\UserPassword( + message: 'Wrong value for your current password', + )] + protected $oldPassword; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Uuid.rst b/reference/constraints/Uuid.rst index 427a373f788..c7b2d94900b 100644 --- a/reference/constraints/Uuid.rst +++ b/reference/constraints/Uuid.rst @@ -38,6 +38,19 @@ Basic Usage protected $identifier; } + .. code-block:: php-attributes + + // src/Entity/File.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class File + { + #[Assert\Uuid] + protected $identifier; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Valid.rst b/reference/constraints/Valid.rst index 1cb992128ac..8378f34cbec 100644 --- a/reference/constraints/Valid.rst +++ b/reference/constraints/Valid.rst @@ -87,6 +87,40 @@ stores an ``Address`` instance in the ``$address`` property:: protected $address; } + .. code-block:: php-attributes + + // src/Entity/Address.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Address + { + #[Assert\NotBlank] + protected $street; + + #[Assert\NotBlank] + #[Assert\Length(max: 5)] + protected $zipCode; + } + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\NotBlank] + #[Assert\Length(min: 4)] + protected $firstName; + + #[Assert\NotBlank] + protected $lastName; + + protected $address; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -196,6 +230,19 @@ an invalid address. To prevent that, add the ``Valid`` constraint to the protected $address; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Valid] + protected $address; + } + .. code-block:: yaml # config/validator/validation.yaml From b703a22e5c286c2a1f10369d97a00ede143e590b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 22 Jan 2021 16:59:27 +0100 Subject: [PATCH 0729/1519] Tweaks --- components/phpunit_bridge.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 289346547c7..674c5d1c519 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -302,17 +302,16 @@ whenever you want to update the existing file): .. code-block:: terminal - $ SYMFONY_DEPRECATIONS_HELPER='generateBaseline=true&baselineFile=tests/allowed.json' ./vendor/bin/simple-phpunit + $ SYMFONY_DEPRECATIONS_HELPER='generateBaseline=true&baselineFile=./tests/allowed.json' ./vendor/bin/simple-phpunit This command stores all the deprecations reported while running tests in the -given file and encoded in JSON. The file path defined in ``baselineFile`` can -be absolute or relative to your project root. +given file path and encoded in JSON. Then, you can run the following command to use that file and ignore those deprecations: .. code-block:: terminal - $ SYMFONY_DEPRECATIONS_HELPER='baselineFile=tests/allowed.json' ./vendor/bin/simple-phpunit + $ SYMFONY_DEPRECATIONS_HELPER='baselineFile=./tests/allowed.json' ./vendor/bin/simple-phpunit .. versionadded:: 5.2 From 78c0441a5b370c6789e0f399bbc896ef86d542c4 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 22 Jan 2021 17:31:27 +0100 Subject: [PATCH 0730/1519] Tweaks --- messenger.rst | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/messenger.rst b/messenger.rst index e73498c6c84..edd43cd7881 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1309,6 +1309,16 @@ during a request:: } } +The transport has a number of options: + +``serialize`` (boolean, default: ``false``) + Whether to serialize messages or not. This is useful to test an additional + layer, especially when you use your own message serializer. + +.. versionadded:: 5.3 + + The ``serialize`` option was introduced in Symfony 5.3. + .. note:: All ``in-memory`` transports will be reset automatically after each test **in** @@ -1316,15 +1326,6 @@ during a request:: :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\KernelTestCase` or :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\WebTestCase`. -.. tip:: - - Using ``in-memory://?serialize=true`` as dsn will perform message serialization as real asynchronous transport will do. - Useful to test an additional layer, especially when you use your own message serializer. - -.. versionadded:: 5.3 - - The ``in-memory://?serialize=true`` dsn was introduced in Symfony 5.3. - Amazon SQS ~~~~~~~~~~ From 9db655a618a1421fe879ab215b9396b6324fe882 Mon Sep 17 00:00:00 2001 From: Wojciech Kania Date: Sat, 23 Jan 2021 11:08:47 +0100 Subject: [PATCH 0731/1519] [Validator] Use constant instead of magic string --- reference/constraints/CardScheme.rst | 2 +- reference/constraints/Isbn.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/constraints/CardScheme.rst b/reference/constraints/CardScheme.rst index d93224e1a5a..1a196970525 100644 --- a/reference/constraints/CardScheme.rst +++ b/reference/constraints/CardScheme.rst @@ -101,7 +101,7 @@ on an object that will contain a credit card number. { $metadata->addPropertyConstraint('cardNumber', new Assert\CardScheme([ 'schemes' => [ - 'VISA', + Assert\CardScheme::VISA, ], 'message' => 'Your credit card number is invalid.', ])); diff --git a/reference/constraints/Isbn.rst b/reference/constraints/Isbn.rst index 2865ceffafe..9bfab789825 100644 --- a/reference/constraints/Isbn.rst +++ b/reference/constraints/Isbn.rst @@ -100,7 +100,7 @@ on an object that will contain an ISBN. public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('isbn', new Assert\Isbn([ - 'type' => 'isbn10', + 'type' => Assert\Isbn::ISBN_10, 'message' => 'This value is not valid.', ])); } From 0b715dee94dab45fca4c414153427c40b5254335 Mon Sep 17 00:00:00 2001 From: wkania <57155526+wkania@users.noreply.github.com> Date: Sun, 24 Jan 2021 19:08:00 +0100 Subject: [PATCH 0732/1519] [Validator] Use single quotes for string --- reference/constraints/Sequentially.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/constraints/Sequentially.rst b/reference/constraints/Sequentially.rst index 39424a6c523..21e088ba689 100644 --- a/reference/constraints/Sequentially.rst +++ b/reference/constraints/Sequentially.rst @@ -120,7 +120,7 @@ You can validate each of these constraints sequentially to solve these issues: { $metadata->addPropertyConstraint('address', new Assert\Sequentially([ new Assert\NotNull(), - new Assert\Type("string"), + new Assert\Type('string'), new Assert\Length(['min' => 10]), new Assert\Regex(self::ADDRESS_REGEX), new AcmeAssert\Geolocalizable(), From a423947869694a15b914431373643a1b25b62b73 Mon Sep 17 00:00:00 2001 From: wkania <57155526+wkania@users.noreply.github.com> Date: Sun, 24 Jan 2021 19:33:51 +0100 Subject: [PATCH 0733/1519] [Validator] Change the example to be consistent with the rest Other examples do not use key 'value'. --- reference/constraints/AtLeastOneOf.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/constraints/AtLeastOneOf.rst b/reference/constraints/AtLeastOneOf.rst index b69894184d6..fb29a86f8d8 100644 --- a/reference/constraints/AtLeastOneOf.rst +++ b/reference/constraints/AtLeastOneOf.rst @@ -141,7 +141,7 @@ The following constraints ensure that: new Assert\Count(['min' => 3]), new Assert\All([ 'constraints' => [ - new Assert\GreaterThanOrEqual(['value' => 5]), + new Assert\GreaterThanOrEqual(5), ], ]), ], From a1c303bfb4dbd0586763ad4f8232673d5b042f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Sat, 23 Jan 2021 21:37:54 +0100 Subject: [PATCH 0734/1519] Add documentation about breach --- security/csrf.rst | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/security/csrf.rst b/security/csrf.rst index ac8e840c978..7058fb88478 100644 --- a/security/csrf.rst +++ b/security/csrf.rst @@ -85,7 +85,7 @@ this can be customized on a form-by-form basis:: // src/Form/TaskType.php namespace App\Form; - + // ... use App\Entity\Task; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -162,4 +162,19 @@ to check its validity:: } } +CSRF Tokens and Compression Side-Channel Attacks +------------------------------------------------ + +`BREACH`_ and `CRIME`_ are security exploits against HTTPS when using HTTP +compression. Attacker can leverage information leaked by compression to recover +targeted parts of the plaintext. To mitigate these attacks, and prevent an +attacker from guessing the CSRF tokens, a random mask is prepended to the token +and used to scramble it. + +.. versionadded:: 5.3 + + The randomization of tokens was introduced in Symfony 5.3 + .. _`Cross-site request forgery`: https://en.wikipedia.org/wiki/Cross-site_request_forgery +.. _`BREACH`: https://en.wikipedia.org/wiki/BREACH +.. _`CRIME`: https://en.wikipedia.org/wiki/CRIME From 56add0114806c646c7a78b2ee85a52ae86f32eae Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 25 Jan 2021 17:38:42 +0100 Subject: [PATCH 0735/1519] [Notifier] Add clickatell Fix #14880. --- notifier.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index a2072e79c13..7231080d47e 100644 --- a/notifier.rst +++ b/notifier.rst @@ -57,6 +57,7 @@ with a couple popular SMS services: Service Package DSN ========== ================================ ==================================================== AllMySms ``symfony/allmysms-notifier`` ``allmysms://LOGIN:APIKEY@default?from=FROM`` +Clickatell ``symfony/clickatell-notifier`` ``clickatell://ACCESS_TOKEN@default?from=FROM`` Esendex ``symfony/esendex-notifier`` ``esendex://USER_NAME:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM`` FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` GatewayApi ``symfony/gatewayapi-notifier`` ``gatewayapi://TOKEN@default?from=FROM`` @@ -82,7 +83,8 @@ Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from= .. versionadded:: 5.3 - The Iqsms, GatewayApi, Octopush and AllMySms integrations were introduced in Symfony 5.3. + The Iqsms, GatewayApi, Octopush, AllMySms and Clickatell integrations were + introduced in Symfony 5.3. To enable a texter, add the correct DSN in your ``.env`` file and From 0770446f44fc64ce450dc7780f4dd0c02d5011d1 Mon Sep 17 00:00:00 2001 From: Frankie Wittevrongel Date: Tue, 26 Jan 2021 12:44:07 +0000 Subject: [PATCH 0736/1519] Add bright colors to console. --- console/coloring.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/console/coloring.rst b/console/coloring.rst index 913805b5cea..9412511e11f 100644 --- a/console/coloring.rst +++ b/console/coloring.rst @@ -46,7 +46,9 @@ It is possible to define your own styles using the $output->writeln('foo'); Any hex color is supported for foreground and background colors. Besides that, these named colors are supported: -``black``, ``red``, ``green``, ``yellow``, ``blue``, ``magenta``, ``cyan`` and ``white``. +``black``, ``red``, ``green``, ``yellow``, ``blue``, ``magenta``, ``cyan``, ``white``, +``gray``, ``bright-red``, ``bright-green``, ``bright-yellow``, ``bright-blue``, +``bright-magenta``, ``bright-cyan`` and ``bright-white``. .. versionadded:: 5.2 From ff3b2443c29f6fe91c71bbd38b0aed269d96c5d3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 26 Jan 2021 16:52:46 +0100 Subject: [PATCH 0737/1519] Minor tweak --- security/csrf.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/csrf.rst b/security/csrf.rst index 7058fb88478..47b9396d285 100644 --- a/security/csrf.rst +++ b/security/csrf.rst @@ -166,7 +166,7 @@ CSRF Tokens and Compression Side-Channel Attacks ------------------------------------------------ `BREACH`_ and `CRIME`_ are security exploits against HTTPS when using HTTP -compression. Attacker can leverage information leaked by compression to recover +compression. Attackers can leverage information leaked by compression to recover targeted parts of the plaintext. To mitigate these attacks, and prevent an attacker from guessing the CSRF tokens, a random mask is prepended to the token and used to scramble it. From 55c567603856bc0e353e774645b3a047d84b8177 Mon Sep 17 00:00:00 2001 From: Yoann Renard Date: Thu, 21 Jan 2021 22:15:50 +0100 Subject: [PATCH 0738/1519] [Validator] Use PHP attributes when creating custom validation constraints --- validation/custom_constraint.rst | 72 +++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/validation/custom_constraint.rst b/validation/custom_constraint.rst index c6c588452c4..9cecde12b8a 100644 --- a/validation/custom_constraint.rst +++ b/validation/custom_constraint.rst @@ -12,20 +12,43 @@ alphanumeric characters. Creating the Constraint Class ----------------------------- -First you need to create a Constraint class and extend :class:`Symfony\\Component\\Validator\\Constraint`:: +First you need to create a Constraint class and extend :class:`Symfony\\Component\\Validator\\Constraint`: - // src/Validator/ContainsAlphanumeric.php - namespace App\Validator; +.. configuration-block:: - use Symfony\Component\Validator\Constraint; + .. code-block:: php-annotations - /** - * @Annotation - */ - class ContainsAlphanumeric extends Constraint - { - public $message = 'The string "{{ string }}" contains an illegal character: it can only contain letters or numbers.'; - } + // src/Validator/ContainsAlphanumeric.php + namespace App\Validator; + + use Symfony\Component\Validator\Constraint; + + /** + * @Annotation + */ + class ContainsAlphanumeric extends Constraint + { + public $message = 'The string "{{ string }}" contains an illegal character: it can only contain letters or numbers.'; + } + + .. code-block:: php-attributes + + // src/Validator/ContainsAlphanumeric.php + namespace App\Validator; + + use Symfony\Component\Validator\Constraint; + + #[\Attribute] + class ContainsAlphanumeric extends Constraint + { + public $message = 'The string "{{ string }}" contains an illegal character: it can only contain letters or numbers.'; + } + +.. versionadded:: 5.2 + + The ability to use PHP attributes to configure constraints was introduced in + Symfony 5.2. Prior to this, Doctrine Annotations were the only way to + annotate constraints. .. note:: @@ -128,6 +151,25 @@ You can use custom validators like the ones provided by Symfony itself: // ... } + .. code-block:: php-attributes + + // src/Entity/AcmeEntity.php + namespace App\Entity; + + use App\Validator as AcmeAssert; + use Symfony\Component\Validator\Constraints as Assert; + + class AcmeEntity + { + // ... + + #[Assert\NotBlank] + #[AcmeAssert\ContainsAlphanumeric] + protected $name; + + // ... + } + .. code-block:: yaml # config/validator/validation.yaml @@ -241,6 +283,14 @@ not to the property: // ... } + .. code-block:: php-attributes + + #[AcmeAssert\ProtocolClass] + class AcmeEntity + { + // ... + } + .. code-block:: yaml # config/validator/validation.yaml From e73e9231bd9276372171857720037376849596d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Michael=20O=2E=20Hegg=C3=B8?= Date: Wed, 27 Jan 2021 22:10:28 +0100 Subject: [PATCH 0739/1519] [Messenger] More on unique Redis consumer names --- messenger.rst | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/messenger.rst b/messenger.rst index 45499c14490..733365c3800 100644 --- a/messenger.rst +++ b/messenger.rst @@ -619,7 +619,18 @@ times: process_name=%(program_name)s_%(process_num)02d Change the ``async`` argument to use the name of your transport (or transports) -and ``user`` to the Unix user on your server. Next, tell Supervisor to read your +and ``user`` to the Unix user on your server. + +If you use the Redis Transport, note that each worker needs a unique consumer name to +avoid the same message being handled by multiple workers. One way to achieve this is +to set an environment variable in the Supervisor configuration file, which you can +then refer to in `messenger.yaml` (see Redis section above): + +.. code-block:: ini + + environment=MESSENGER_CONSUMER_NAME=%(program_name)s_%(process_num)02d + +Next, tell Supervisor to read your config and start your workers: .. code-block:: terminal @@ -1209,9 +1220,13 @@ claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) .. caution:: There should never be more than one ``messenger:consume`` command running with the same - config (stream, group and consumer name) to avoid having a message handled more than once. - Using the ``HOSTNAME`` as the consumer might often be a good idea. In case you are using - Kubernetes to orchestrate your containers, consider using a ``StatefulSet``. + combination of ``stream``, ``group`` and ``consumer``, or messages could end up being + handled more than once. If you run multiple queue workers, ``consumer` can be set to an + environment variable (like ``%env(MESSENGER_CONSUMER_NAME)%`)` set by Supervisor + (example below) or whatever service used to manage the worker processes. + In a container environment, the ``HOSTNAME`` can be used as the consumer name, since + there is only one worker per container/host. If using Kubernetes to orchestrate the + containers, consider using a ``StatefulSet`` to have stable names. .. tip:: From f0e6261484a12c68f8b500ac9495ccf602c13b38 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 28 Jan 2021 07:57:37 +0100 Subject: [PATCH 0740/1519] Remove experimental for UID Fix #14890 --- components/uid.rst | 15 +++++++-------- notifier.rst | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index a7fb95d5d2f..076946c7756 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -10,8 +10,7 @@ The UID Component .. versionadded:: 5.1 - The UID component was introduced in Symfony 5.1 as an - :doc:`experimental feature `. + The UID component was introduced in Symfony 5.1. Installation ------------ @@ -157,12 +156,12 @@ entity primary keys:: private $id; // ... - + public function getId(): ?Uuid { return $this->id; } - + // ... } @@ -287,7 +286,7 @@ There's also a Doctrine generator to help autogenerate ULID values for the entity primary keys:: use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator; - use Symfony\Component\Uid\Ulid; + use Symfony\Component\Uid\Ulid; /** * @ORM\Entity(repositoryClass="App\Repository\ProductRepository") @@ -303,14 +302,14 @@ entity primary keys:: private $id; // ... - + public function getId(): ?Ulid { return $this->id; } - + // ... - + } .. versionadded:: 5.2 diff --git a/notifier.rst b/notifier.rst index 7231080d47e..6845900b11b 100644 --- a/notifier.rst +++ b/notifier.rst @@ -16,7 +16,7 @@ the users (e.g. SMS, Slack messages, emails, push notifications, etc.). The Notifier component in Symfony is an abstraction on top of all these channels. It provides a dynamic way to manage how the messages are sent. Get the Notifier installed using: - +uid .. code-block:: terminal $ composer require symfony/notifier From 1c6c658627db640955982e8e2aad1265924e97b2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 28 Jan 2021 08:54:34 +0100 Subject: [PATCH 0741/1519] Removed unneeded text --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 6845900b11b..7231080d47e 100644 --- a/notifier.rst +++ b/notifier.rst @@ -16,7 +16,7 @@ the users (e.g. SMS, Slack messages, emails, push notifications, etc.). The Notifier component in Symfony is an abstraction on top of all these channels. It provides a dynamic way to manage how the messages are sent. Get the Notifier installed using: -uid + .. code-block:: terminal $ composer require symfony/notifier From 5ff7cc7486530647a46951b6189bee23717f09f7 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 28 Jan 2021 09:06:50 +0100 Subject: [PATCH 0742/1519] Remove experimental mention in lowest branch Follows #14891 --- components/uid.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index 9a097a3e675..b0ba7259b87 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -10,8 +10,7 @@ The UID Component .. versionadded:: 5.1 - The UID component was introduced in Symfony 5.1 as an - :doc:`experimental feature `. + The UID component was introduced in Symfony 5.1. Installation ------------ From d0c1a24752df5048a3910e67985884da8a41e618 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 28 Jan 2021 09:15:02 +0100 Subject: [PATCH 0743/1519] [Uid] Document the getDateTime() method --- components/uid.rst | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index 076946c7756..adda64b8029 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -96,9 +96,9 @@ UUID objects created with the ``Uuid`` class can use the following methods $uuid = Uuid::v4(); $uuid instanceof UuidV4; // true - // getting the UUID time (it's only available in certain UUID types) + // getting the UUID datetime (it's only available in certain UUID types) $uuid = Uuid::v1(); - $uuid->getTime(); // e.g. float(1584111384.2613) + $uuid->getDateTime(); // returns a \DateTimeImmutable instance // comparing UUIDs and checking for equality $uuid1 = Uuid::v1(); @@ -111,6 +111,11 @@ UUID objects created with the ``Uuid`` class can use the following methods // * int < 0 if $uuid1 is less than $uuid4 $uuid1->compare($uuid4); // e.g. int(4) +.. versionadded:: 5.3 + + The ``getDateTime()`` method was introduced in Symfony 5.3. In previous + versions it was called ``getTime()``. + Storing UUIDs in Databases ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -250,14 +255,19 @@ ULID objects created with the ``Ulid`` class can use the following methods:: // checking if a given value is valid as ULID $isValid = Ulid::isValid($ulidValue); // true or false - // getting the ULID time - $ulid1->getTime(); // e.g. float(1584111384.2613) + // getting the ULID datetime + $ulid1->getDateTime(); // returns a \DateTimeImmutable instance // comparing ULIDs and checking for equality $ulid1->equals($ulid2); // false // this method returns $ulid1 <=> $ulid2 $ulid1->compare($ulid2); // e.g. int(-1) +.. versionadded:: 5.3 + + The ``getDateTime()`` method was introduced in Symfony 5.3. In previous + versions it was called ``getTime()``. + Storing ULIDs in Databases ~~~~~~~~~~~~~~~~~~~~~~~~~~ From 1b61792e5e7ce891264f80b6c466efc3a0a7825b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 28 Jan 2021 09:20:38 +0100 Subject: [PATCH 0744/1519] [Uid] Mentioned the Uuid::NAMESPACE_* constants --- components/uid.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/components/uid.rst b/components/uid.rst index 076946c7756..51f8b4021a2 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -53,11 +53,22 @@ to create each type of UUID:: $uuid = Uuid::v3($namespace, $name); // $uuid is an instance of Symfony\Component\Uid\UuidV3 $uuid = Uuid::v5($namespace, $name); // $uuid is an instance of Symfony\Component\Uid\UuidV5 + // the namespaces defined by RFC 4122 are available as constants + // (see https://tools.ietf.org/html/rfc4122#appendix-C) + $uuid = Uuid::v3(Uuid::NAMESPACE_DNS, $name); + $uuid = Uuid::v3(Uuid::NAMESPACE_URL, $name); + $uuid = Uuid::v3(Uuid::NAMESPACE_OID, $name); + $uuid = Uuid::v3(Uuid::NAMESPACE_X500, $name); + // UUID type 6 is not part of the UUID standard. It's lexicographically sortable // (like ULIDs) and contains a 60-bit timestamp and 63 extra unique bits. // It's defined in http://gh.peabody.io/uuidv6/ $uuid = Uuid::v6(); // $uuid is an instance of Symfony\Component\Uid\UuidV6 +.. versionadded:: 5.3 + + The ``Uuid::NAMESPACE_*`` constants were introduced in Symfony 5.3. + If your UUID is generated by another system, use the ``fromString()`` method to create an object and make use of the utilities available for Symfony UUIDs:: From 70fe3795c8bb33fcabe016f5a2a8c91cd158f803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Thu, 28 Jan 2021 15:41:22 +0100 Subject: [PATCH 0745/1519] Mark semaphore exeperimental --- components/semaphore.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/semaphore.rst b/components/semaphore.rst index ebae3df89e8..614c38a6bd9 100644 --- a/components/semaphore.rst +++ b/components/semaphore.rst @@ -10,7 +10,8 @@ The Semaphore Component .. versionadded:: 5.2 - The Semaphore Component was introduced in Symfony 5.2. + The Semaphore Component was introduced in Symfony 5.2 as an + :doc:`experimental feature `. Installation ------------ From be512a89aa9fc34116b51d2ae8c1fce74ec88eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Thu, 28 Jan 2021 19:20:54 +0100 Subject: [PATCH 0746/1519] Update documentation for deprecated session service --- components/http_foundation.rst | 3 +- controller.rst | 2 +- logging/processors.rst | 23 +++++++------ quick_tour/the_architecture.rst | 3 -- security/access_denied_handler.rst | 7 ++-- security/form_login_setup.rst | 10 +----- service_container.rst | 8 +---- session.rst | 55 +++++++++++++++++++++--------- session/locale_sticky_session.rst | 10 +++--- 9 files changed, 64 insertions(+), 57 deletions(-) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 23d8e9a6809..e00f9dabb7b 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -247,7 +247,8 @@ Accessing the Session ~~~~~~~~~~~~~~~~~~~~~ If you have a session attached to the request, you can access it via the -:method:`Symfony\\Component\\HttpFoundation\\Request::getSession` method; +:method:`Symfony\\Component\\HttpFoundation\\Request::getSession` method or the +:method:`Symfony\\Component\\HttpFoundation\\RequestStack::getSession` method; the :method:`Symfony\\Component\\HttpFoundation\\Request::hasPreviousSession` method tells you if the request contains a session which was started in one of diff --git a/controller.rst b/controller.rst index 212d0a2b509..a5017452832 100644 --- a/controller.rst +++ b/controller.rst @@ -394,7 +394,7 @@ Request object. Managing the Session -------------------- -Symfony provides a session service that you can use to store information +Symfony provides a session object that you can use to store information about the user between requests. Session is enabled by default, but will only be started if you read or write from it. diff --git a/logging/processors.rst b/logging/processors.rst index 8ba965327b2..c0a3eb33bbf 100644 --- a/logging/processors.rst +++ b/logging/processors.rst @@ -19,30 +19,33 @@ using a processor:: // src/Logger/SessionRequestProcessor.php namespace App\Logger; - use Symfony\Component\HttpFoundation\Session\SessionInterface; + use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException; + use Symfony\Component\HttpFoundation\RequestStack; class SessionRequestProcessor { - private $session; - private $sessionId; + private $requestStack; - public function __construct(SessionInterface $session) + public function __construct(RequestStack $requestStack) { - $this->session = $session; + $this->requestStack = $requestStack; } // this method is called for each log record; optimize it to not hurt performance public function __invoke(array $record) { - if (!$this->session->isStarted()) { + try { + $session = $requestStack->getSession(); + } catch (SessionNotFoundException $e) { + return; + } + if (!$session->isStarted()) { return $record; } - if (!$this->sessionId) { - $this->sessionId = substr($this->session->getId(), 0, 8) ?: '????????'; - } + $sessionId = substr($session->getId(), 0, 8) ?: '????????'; - $record['extra']['token'] = $this->sessionId.'-'.substr(uniqid('', true), -8); + $record['extra']['token'] = $sessionId.'-'.substr(uniqid('', true), -8); return $record; } diff --git a/quick_tour/the_architecture.rst b/quick_tour/the_architecture.rst index d88bb5d32ed..e3b388a0bc4 100644 --- a/quick_tour/the_architecture.rst +++ b/quick_tour/the_architecture.rst @@ -72,9 +72,6 @@ What other possible classes or interfaces could you use? Find out by running: Request stack that controls the lifecycle of requests. Symfony\Component\HttpFoundation\RequestStack (request_stack) - Interface for the session. - Symfony\Component\HttpFoundation\Session\SessionInterface (session) - RouterInterface is the interface that all Router classes must implement. Symfony\Component\Routing\RouterInterface (router.default) diff --git a/security/access_denied_handler.rst b/security/access_denied_handler.rst index 42ee7fe5dd9..2a7566fafed 100644 --- a/security/access_denied_handler.rst +++ b/security/access_denied_handler.rst @@ -28,7 +28,6 @@ unauthenticated user tries to access a protected resource:: use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; @@ -36,18 +35,16 @@ unauthenticated user tries to access a protected resource:: class AuthenticationEntryPoint implements AuthenticationEntryPointInterface { private $urlGenerator; - private $session; - public function __construct(UrlGeneratorInterface $urlGenerator, SessionInterface $session) + public function __construct(UrlGeneratorInterface $urlGenerator) { $this->urlGenerator = $urlGenerator; - $this->session = $session; } public function start(Request $request, AuthenticationException $authException = null): RedirectResponse { // add a custom flash message and redirect to the login page - $this->session->getFlashBag()->add('note', 'You have to login in order to access this page.'); + $request->getSession()->getFlashBag()->add('note', 'You have to login in order to access this page.'); return new RedirectResponse($this->urlGenerator->generate('security_login')); } diff --git a/security/form_login_setup.rst b/security/form_login_setup.rst index c7ea359c459..1d269eba380 100644 --- a/security/form_login_setup.rst +++ b/security/form_login_setup.rst @@ -477,7 +477,6 @@ whenever the user browses a page:: namespace App\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; - use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Security\Http\Util\TargetPathTrait; @@ -486,13 +485,6 @@ whenever the user browses a page:: { use TargetPathTrait; - private $session; - - public function __construct(SessionInterface $session) - { - $this->session = $session; - } - public function onKernelRequest(RequestEvent $event): void { $request = $event->getRequest(); @@ -504,7 +496,7 @@ whenever the user browses a page:: return; } - $this->saveTargetPath($this->session, 'main', $request->getUri()); + $this->saveTargetPath($request->getSession(), 'main', $request->getUri()); } public static function getSubscribedEvents() diff --git a/service_container.rst b/service_container.rst index e3db328033b..98fb5e61318 100644 --- a/service_container.rst +++ b/service_container.rst @@ -62,9 +62,6 @@ What other services are available? Find out by running: Request stack that controls the lifecycle of requests. Symfony\Component\HttpFoundation\RequestStack (request_stack) - Interface for the session. - Symfony\Component\HttpFoundation\Session\SessionInterface (session) - RouterInterface is the interface that all Router classes must implement. Symfony\Component\Routing\RouterInterface (router.default) @@ -80,7 +77,7 @@ in the container. .. tip:: There are actually *many* more services in the container, and each service has - a unique id in the container, like ``session`` or ``router.default``. For a full + a unique id in the container, like ``request_stack`` or ``router.default``. For a full list, you can run ``php bin/console debug:container``. But most of the time, you won't need to worry about this. See :ref:`services-wire-specific-service`. See :doc:`/service_container/debug`. @@ -283,9 +280,6 @@ type-hints by running: Request stack that controls the lifecycle of requests. Symfony\Component\HttpFoundation\RequestStack (request_stack) - Interface for the session. - Symfony\Component\HttpFoundation\Session\SessionInterface (session) - RouterInterface is the interface that all Router classes must implement. Symfony\Component\Routing\RouterInterface (router.default) diff --git a/session.rst b/session.rst index 394cfece78b..3ccf47460b6 100644 --- a/session.rst +++ b/session.rst @@ -127,25 +127,26 @@ Check out the Symfony config reference to learn more about the other available Basic Usage ----------- -Symfony provides a session service that is injected in your services and +The sessions is available througth the Request and the RequestStack. +Symfony provides a request_stack service that is injected in your services and controllers if you type-hint an argument with -:class:`Symfony\\Component\\HttpFoundation\\Session\\SessionInterface`:: +:class:`Symfony\\Component\\HttpFoundation\\RequestStack`:: - use Symfony\Component\HttpFoundation\Session\SessionInterface; + use Symfony\Component\HttpFoundation\RequestStack; class SomeService { - private $session; + private $requestStack; - public function __construct(SessionInterface $session) + public function __construct(RequestStack $requestStack) { - $this->session = $session; + $this->requestStack = $requestStack; } public function someMethod() { // stores an attribute in the session for later reuse - $this->session->set('attribute-name', 'attribute-value'); + $this->requestStack->getSession()->set('attribute-name', 'attribute-value'); // gets an attribute by name $foo = $this->session->get('foo'); @@ -157,10 +158,10 @@ controllers if you type-hint an argument with } } -.. tip:: +.. deprecated:: 5.3 - Every ``SessionInterface`` implementation is supported. If you have your - own implementation, type-hint this in the argument instead. + The ``SessionInterface`` and ``session`` service are deprecated since + Symfony 5.3. Inject a request stack instead. Stored attributes remain in the session for the remainder of that user's session. By default, session attributes are key-value pairs managed with the @@ -175,22 +176,44 @@ class. If your application needs are complex, you may prefer to use :ref:`namespaced session attributes ` which are managed with the :class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\NamespacedAttributeBag` -class. Before using them, override the ``session`` service definition to replace -the default ``AttributeBag`` by the ``NamespacedAttributeBag``: +class. Before using them, override the ``session_listener`` service definition to build +your ``Session`` object with the default ``AttributeBag`` by the ``NamespacedAttributeBag``: .. configuration-block:: .. code-block:: yaml # config/services.yaml - session: - public: true - class: Symfony\Component\HttpFoundation\Session\Session - arguments: ['@session.storage', '@session.namespacedattributebag'] + session_listener: + autoconfigure: true + class: App\EventListener\SessionListener + arguments: + - !service_locator + logger: '@?logger' + session_collector: '@?data_collector.request.session_collector' + session_storage: '@session.storage' + session_attributes: '@session.namespacedattributebag' + - '%kernel.debug%' session.namespacedattributebag: class: Symfony\Component\HttpFoundation\Session\Attribute\NamespacedAttributeBag +.. code-block:: php + + namespace App\EventListener; + + use Symfony\Component\HttpFoundation\Session\Session; + use Symfony\Component\HttpFoundation\Session\SessionInterface; + use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener; + + class SessionListener extends AbstractSessionListener + { + protected function getSession(): ?SessionInterface + { + return new Session($this->container->get('session_storage'), $this->container->get('session_attributes')); + } + } + .. _session-avoid-start: Avoid Starting Sessions for Anonymous Users diff --git a/session/locale_sticky_session.rst b/session/locale_sticky_session.rst index 056f2a674cb..13d620381aa 100644 --- a/session/locale_sticky_session.rst +++ b/session/locale_sticky_session.rst @@ -146,7 +146,7 @@ event:: namespace App\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; - use Symfony\Component\HttpFoundation\Session\SessionInterface; + use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\SecurityEvents; @@ -156,11 +156,11 @@ event:: */ class UserLocaleSubscriber implements EventSubscriberInterface { - private $session; + private $requestStack; - public function __construct(SessionInterface $session) + public function __construct(RequestStack $requestStack) { - $this->session = $session; + $this->requestStack = $requestStack; } public function onInteractiveLogin(InteractiveLoginEvent $event) @@ -168,7 +168,7 @@ event:: $user = $event->getAuthenticationToken()->getUser(); if (null !== $user->getLocale()) { - $this->session->set('_locale', $user->getLocale()); + $this->requestStack->getSession()->set('_locale', $user->getLocale()); } } From 98ebace2ecae3d409ce8e229b066fd9da21f5cd9 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 29 Jan 2021 10:04:23 +0100 Subject: [PATCH 0747/1519] Tweak --- session.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/session.rst b/session.rst index 3ccf47460b6..da265d739b9 100644 --- a/session.rst +++ b/session.rst @@ -160,8 +160,9 @@ controllers if you type-hint an argument with .. deprecated:: 5.3 - The ``SessionInterface`` and ``session`` service are deprecated since - Symfony 5.3. Inject a request stack instead. + The ``SessionInterface`` and ``session`` service were deprecated in + Symfony 5.3. Instead, inject the ``RequestStack`` service to get the session + object of the current request. Stored attributes remain in the session for the remainder of that user's session. By default, session attributes are key-value pairs managed with the From 8673801703a7ca8625357234a43e645bb9c49d6b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 29 Jan 2021 10:16:07 +0100 Subject: [PATCH 0748/1519] Added the versionadded directive --- console/coloring.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/console/coloring.rst b/console/coloring.rst index 9412511e11f..7e77a090b25 100644 --- a/console/coloring.rst +++ b/console/coloring.rst @@ -54,6 +54,10 @@ Any hex color is supported for foreground and background colors. Besides that, t True (hex) color support was introduced in Symfony 5.2 +.. versionadded:: 5.3 + + Support for bright colors was introduced in Symfony 5.3. + .. note:: If the terminal doesn't support true colors, the nearest named color is used. From 9d03c8f616eb9b9b473a51c7e8c0647e616a440f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 29 Jan 2021 10:19:15 +0100 Subject: [PATCH 0749/1519] [Semaphore] The component is no longer experimental in Symfony 5.3. --- components/semaphore.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/semaphore.rst b/components/semaphore.rst index 614c38a6bd9..ebae3df89e8 100644 --- a/components/semaphore.rst +++ b/components/semaphore.rst @@ -10,8 +10,7 @@ The Semaphore Component .. versionadded:: 5.2 - The Semaphore Component was introduced in Symfony 5.2 as an - :doc:`experimental feature `. + The Semaphore Component was introduced in Symfony 5.2. Installation ------------ From 36a5c1a2820bdcd9bd3aa65bb2774d99228c0495 Mon Sep 17 00:00:00 2001 From: Jon Green Date: Sun, 3 Jan 2021 17:22:23 +0000 Subject: [PATCH 0750/1519] [String] Feature 39178 Documentation update for [String] Feature 39178 "AsciiSlugger's symbolsMap should apply to all locales for a language". --- components/string.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/string.rst b/components/string.rst index 97988fc0970..48f17f0b3e9 100644 --- a/components/string.rst +++ b/components/string.rst @@ -477,6 +477,12 @@ that only includes safe ASCII characters:: $slug = $slugger->slug('10% or 5€'); // $slug = '10-percent-or-5-euro' + // if there is no symbols map for your locale (e.g. 'en_GB') then the parent locale's symbols map + // will be used instead (i.e. 'en') + $slugger = new AsciiSlugger('en_GB', ['en' => ['%' => 'percent', '€' => 'euro']]); + $slug = $slugger->slug('10% or 5€'); + // $slug = '10-percent-or-5-euro' + // for more dynamic substitutions, pass a PHP closure instead of an array $slugger = new AsciiSlugger('en', function ($string, $locale) { return str_replace('❤️', 'love', $string); @@ -490,6 +496,10 @@ that only includes safe ASCII characters:: The feature to use a PHP closure to define substitutions was introduced in Symfony 5.2. +.. versionadded:: 5.3 + + The feature to fallback to the parent locale's symbols map was introduced in Symfony 5.3. + The separator between words is a dash (``-``) by default, but you can define another separator as the second argument:: From 1cdb6cb9079f5c0e2b709ab90294b08218b50831 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 17 Oct 2020 15:19:01 +0200 Subject: [PATCH 0751/1519] Added limiter diagrams --- _images/rate_limiter/fixed_window.svg | 84 ++++++++++++++++++ _images/rate_limiter/sliding_window.svg | 65 ++++++++++++++ _images/rate_limiter/token_bucket.svg | 83 +++++++++++++++++ _images/sources/rate_limiter/fixed_window.dia | Bin 0 -> 2356 bytes .../sources/rate_limiter/sliding_window.dia | Bin 0 -> 2190 bytes _images/sources/rate_limiter/token_bucket.dia | Bin 0 -> 2752 bytes rate_limiter.rst | 52 +++++++++-- 7 files changed, 275 insertions(+), 9 deletions(-) create mode 100644 _images/rate_limiter/fixed_window.svg create mode 100644 _images/rate_limiter/sliding_window.svg create mode 100644 _images/rate_limiter/token_bucket.svg create mode 100644 _images/sources/rate_limiter/fixed_window.dia create mode 100644 _images/sources/rate_limiter/sliding_window.dia create mode 100644 _images/sources/rate_limiter/token_bucket.dia diff --git a/_images/rate_limiter/fixed_window.svg b/_images/rate_limiter/fixed_window.svg new file mode 100644 index 00000000000..83d5f6e79ac --- /dev/null +++ b/_images/rate_limiter/fixed_window.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + 10:00 + + + 10:30 + + + 11:00 + + + 11:30 + + + 12:00 + + + + + + + + 12:30 + + + 13:00 + + + + + + + + + + + + + + + + + + + + + + 1 hour window + + + 1 hour window + + + + + + 1 hour window + + + + + 13:15 + + + diff --git a/_images/rate_limiter/sliding_window.svg b/_images/rate_limiter/sliding_window.svg new file mode 100644 index 00000000000..2c565615441 --- /dev/null +++ b/_images/rate_limiter/sliding_window.svg @@ -0,0 +1,65 @@ + + + + + + + + + + 10:00 + + + 10:30 + + + 11:00 + + + 11:30 + + + 12:00 + + + + + + 12:30 + + + 13:00 + + + + + + + + + + + + + + + + + + + + + + 1 hour window + + + + + + 13:15 + + + + + + diff --git a/_images/rate_limiter/token_bucket.svg b/_images/rate_limiter/token_bucket.svg new file mode 100644 index 00000000000..29d6fc8f103 --- /dev/null +++ b/_images/rate_limiter/token_bucket.svg @@ -0,0 +1,83 @@ + + + + 10:00 + + + 10:30 + + + 11:00 + + + 11:30 + + + 12:00 + + + + + + + + 12:30 + + + 13:00 + + + + + + + + + + + + + + + + + + + + + + + + + + + 13:15 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/sources/rate_limiter/fixed_window.dia b/_images/sources/rate_limiter/fixed_window.dia new file mode 100644 index 0000000000000000000000000000000000000000..16282a2dcce2dc3cf58a40be13992366c2a10f48 GIT binary patch literal 2356 zcmV-43Cs2$iwFP!000021MQt#liD~I$KUfQT;#ReSQp>Y=}ygT)$BfO?WQW3=PrTO z;2C2xwrRpV>}OxuTpElG23hKuI#eYAB6KYI==VRCb>z=qe#|1{m8V&l#E%1HS_6Z} z<0J^<$>ZSn@4wx9gD+1XJ_jNDB>qfNHZ#O8;;i`eIGE=7{L^r_TrSOMm9acY%_v-$ z86Wic8q{$)<2J2Fra^oaQ zQsb3HkAsgdo7Z5tsc3jm(}~*WY{Ew=XMZ+VZi$!gUsw5@r`3vQ^CSyJk$g2jD$-C- z@%LVtO{q*2iYHGWf1w}OhqU?Pt**KQZ8Vb4SUL&gV>_aEqIFkb)592x?y!B&w_NI? zZJ%6jZlu>-q}N=k*IbxA&yzGyS(qQ293@G_S-iIT!lH~{ZzvnHNch;Pc1bkjCCu}r zqXw+M-VL`)hwdZ|gVQ7TphQD0!Akraj@6!%Wfi5qx!R{ZoJ{i*)n8ZlC`kjJo;!BSMArI+sBadA zb(xU@0M9j-f9J>jC00Z{%b&A+74fP89xrC=+Ua#w&sh*0M$1R%<4RY``Hy^XCN8Oz zY3k(iqVb?y<@&PW>hc86o5K4f&g%>n-y1I?P>xpOcvzebjPiVxtXu!|Up#u{c{pbK zY`^>njs{=tIq|H+7nL)5NZ~qcQEU>|zN03k)NB_=J6JP38uAfa+iYNencpCF$gpCF$d$tQ74 z5KrymiDktTJF2A<+or#fPHbArrBkXwAe0=WGHr)uDTxmABI@shKu*vHen=r&p8rkFmn|i^ffAVC;#jnN!PG5QY zQvA=izZNXzHJI|`?y~zDtYFUKr*J|+xiq(JEv`ZN}WH#`jlR-okP+IQIu$a6U7H` zqWyvsfyHwg;Y0vVx3_o>$tOp78s<*D-Q1~v3v;I)%$>reGh8~urL*cw=YNZHR=0bl zblMp%(|jCL^-dzf1hpTiYm&m)mDY-#w4Zq#9Bl*MqE$74kSo=6F;>R&>M_(kOyK>& z*^#rk-RxWAsNL=j-xXWFJ&1S31(BuP)v9f3D&m5hwR5vB@<7~TU}MFJAZ}r!*cr(a zZ#>n0R@12FQZ7KPrMLOrYn_7oc{5n>iia9o7IfZwoa~57fL?Q1bw4mwB7p&4NyqP%A8~p(fsGf!a}< znu-9_TDqC^jRJ}^K&>!RLQTBU0kyhDHJ1XYwe>c?n}wiCp+n{oh>tB001yD}0?^T37)1F_7-jVD+(7g%)nNdCi2eco0RL{_PrAwGB+7F+ zOZfY@0DlkQ5AcV`AK?Ekn;;SS2QT|~*44N3+NL}a&mnjBmWe%zy>jWcgNS=4Xw#Fe zMvSQ#_r@}egJcO?j_7&@bJaCrzmZ;UhD797D>|mF8dHRrUIkOWi4gGsQ-GQ$^@4JXM6iQ$^r%8s<{ra{4EjOLe_7^0`{;|}Zrn`uBa`fdM<%&_dt?%_A>h&#a5?bEq@OP0T7Qn% ail)*r;5Ny=tVAN~(zH@RP^pI)w3?7e? zAdJTky+6NwzN5X5k2fEJki8dw#wnW`;u~>Re0u0j@_hEb-(M^iX0*&$o}^|J&drSX z|7B6c`l3+3_jqF%yA=d1XT`PkRhH*zIGpF)h}o1s^oDHoeViuqIOwfPt;>y)C`pZH z7CrRdJ*{88{<@<6UQMsmK4W7(OgZ~rU%4e-zJFQeGoBt+Je?(3D2n9E*-??2dWyey z%B)LeqEI}3eD@Q1x4NbEg_pXjZnRcNK4s}RjF07r-icOSVVl&pZP6W$PkqZH9@_Lt zb8$nx;v&7`QoZ8BY%ojGJY`{iEOMA65ohsA>Jy7Hez~A*#3G?%ueD2}8BbxJCoMH# zb$L77nhxD@8V0YA+`SStwFFD?Z#Yu>Ocr5~PX<3;dnT4?JF)_n>I6K8SvZV%RU5)M zmsYDy^~-juKU9R$R=j*&Qt?)`)f%IKa)&#Y7^Cq#40v`zr}xX$)HGQa>!0fP!*Y^c z6NK3;V$0W?a9F6OE*9sZKpD$;pqQ93o89Hf-2pDDB<1P61wqO1FFwlEikc(~4Gk)! zjFLDO%@N+{-7FEKHPdV!R+kPu)l#fbGM=t)_0x-wYOHCqZoRQ?0Nc65M0=h$pLX

^@POa0-qFbJ>flzQUI2+@d{l z*Y#GNfZ_14{ZA_gj zQT2p}<4N9n-NPgeczWu_EfZO*7b3oekc;fg#Dzkm)4{%>s+yDq!P9W~Vyc=6DMtUG zV(xdEGfkujXO<7Ld>QdW0X&{hSGAMNs-CeR*msqWp2vk+n)4rd?}SrwP^PYv%NgTd zxr51N&D8Q0me=|ANt{;+Dy|z(!b^^p;(l11^^Ed)l$=|A^;aG}^E@1}U9LC3gQLM$ z`An#_{~~fi_X%8yEG&>kOhSm|%E>w$k+rKCmbE)7FA*hNr*S;x)sOUL=%6#DR9fRY z*RcO$E9;EsS7CwzmIlIhek%sT&WhIBcp_QjX*0pc4|9^BK>%C>^<;RzA##ez5<9C*($>NwKKPU4v_KR0o^9JvRAWV-p58X=4)wHeCsuu=Jt>(!eHc?Xn5m z-C`30zeyjPs`L@q)JZlGX*LlZY{GkNa=OMQ@SF6pi2$3fgiVe#n>-zCa`)IoyTv9O z{3eZT@_3c0 zMxJ-;m>2Gxik@Mo_!NYrT;-m%WS5<@XKk6j>v@6;*dY{C4^gUc7aN%eduYDI=B%zw z?NV65ocXJp+Q%enBIGHIqBDdH?SSwr*g3b3Lc}V=L>u*B6wU^dBn|%&c9=!4Htrx6 zsIeG9$70u6nUHKgEaGW-@8V8so&R17F-4wg{tFrIn*Ye8o#($~mtDkvLUi(<0RMsi z!2b^LpGx!JQSbi?85{rKy#oJVvde(~z<=OB@c;6)XsK?Pr`VDVyC+%95*6 z)r5pw$Ml_h@vg9kmU2})Y*Sqk57g{DHIt6;w%uYs!&RJpB7_t&iljIy-cZ$gR?(>X zQXW9

    3WvpyqF&=Ieo)e-_kyfLb$cbK6Oh zQVF#}!U}5QoffDawW+QMKVO*EK#l5w8a)eY6rk2j+w6AYc~nBJkg$T9c&7zwM{TMr0#G|s&7?O9 z2+{zxLP!ZU@kR&Ksv1>a3ZQnbwvl$?fRsWFZ=r@YK@FdV8V0CclnP-x?c_pZ<(bg7 z>2EWkiHW+N35_8S0`edr4+8Qa-Y^f&cH2pW#>&&6OZczTpgRqJsSdjc{s^grKd>HH z53KJ3>%Df8p0VO1wg?uOVN1nQyBadwF8jd`5;mA`k05Agp1Mo&i9%1>w&*Eo0 zt&0OV&RyZB)Wx@VmT6OBQ>SqM5yDjX&Q?dx7BMDbw`{s4b~|C_^KJ~71Cu;J!!Hr$AH4I6GgY`B2|00RI9K-vJTK1XcH)5n|D2k~c| QvgzZ^e}s1x_UWns01%r;Gynhq literal 0 HcmV?d00001 diff --git a/_images/sources/rate_limiter/token_bucket.dia b/_images/sources/rate_limiter/token_bucket.dia new file mode 100644 index 0000000000000000000000000000000000000000..16761971337dbf6890ce0d2255b6d7c75bb125ca GIT binary patch literal 2752 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 literal 0 HcmV?d00001 diff --git a/rate_limiter.rst b/rate_limiter.rst index 63e073a1e92..1d54faba331 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -28,22 +28,44 @@ Fixed Window Rate Limiter ~~~~~~~~~~~~~~~~~~~~~~~~~ This is the simplest technique and it's based on setting a limit for a given -interval of time. For example: 5,000 requests per hour or 3 login attempts -every 15 minutes. +interval of time (e.g. 5,000 requests per hour or 3 login attempts every 15 +minutes). + +In the diagram below, the limit is set to "5 tokens per hour". Each window +starts at the first hit (i.e. 10:15, 11:30 and 12:30). As soon as there are +5 hits (the blue squares) in a window, all others will be rejected (red +squares). + +.. raw:: html + + Its main drawback is that resource usage is not evenly distributed in time and -it can overload the server at the window edges. In the previous example, a user -could make the 4,999 requests in the last minute of some hour and another 5,000 -requests during the first minute of the next hour, making 9,999 requests in -total in two minutes and possibly overloading the server. These periods of -excessive usage are called "bursts". +it can overload the server at the window edges. In the previous example, +there are 6 accepted requests between 11:00 and 12:00. + +This is more significant with bigger limits. For instance, with 5,000 requests +per hour, a user could make the 4,999 requests in the last minute of some +hour and another 5,000 requests during the first minute of the next hour, +making 9,999 requests in total in two minutes and possibly overloading the +server. These periods of excessive usage are called "bursts". Sliding Window Rate Limiter ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The sliding window algorithm is an alternative to the fixed window algorithm -designed to reduce bursts. To do that, the rate limit is calculated based on -the current window and the previous window. +designed to reduce bursts. This is the same example as above, but then +using a 1 hour window that slides over the timeline: + +.. raw:: html + + + +As you can see, this removes the edges of the window and would prevent the +6th request at 11:45. + +To achieve this, the rate limit is approximated based on the current window and +the previous window. For example: the limit is 5,000 requests per hour; a user made 4,000 requests the previous hour and 500 requests this hour. 15 minutes in to the current hour @@ -66,6 +88,18 @@ continuously updating budget of resource usage. It roughly works like this: * If the bucket still contains tokens, the event is allowed; otherwise, it's denied; * If the bucket is at full capacity, new tokens are discarded. +The below diagram shows a token bucket of size 4 that is filled with a rate +of 1 token per 15 minutes: + +.. raw:: html + + + +This algorithm handles more complex back-off algorithm to manage bursts. +For instance, it can allow a user to try a password 5 times and then only +allow 1 every 15 minutes (unless the user waits 75 minutes and they will be +allowed 5 tries again). + Installation ------------ From dab721b1c22f3d6dbdc0bcdaed9252fa8fcfa450 Mon Sep 17 00:00:00 2001 From: Sebastian Paczkowski <74934099+sebpacz@users.noreply.github.com> Date: Fri, 29 Jan 2021 19:33:12 +0100 Subject: [PATCH 0752/1519] [Console] Update comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The info() method was introduced in Symfony 5.2. I updated comments that were probably copied from the success() method example. --- console/style.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/console/style.rst b/console/style.rst index a8cdad20004..66db35011b1 100644 --- a/console/style.rst +++ b/console/style.rst @@ -331,12 +331,12 @@ Result Methods It's meant to be used once to display the final result of executing the given command, without showing the result as a successful or failed one:: - // use simple strings for short success messages + // use simple strings for short info messages $io->info('Lorem ipsum dolor sit amet'); // ... - // consider using arrays when displaying long success messages + // consider using arrays when displaying long info messages $io->info([ 'Lorem ipsum dolor sit amet', 'Consectetur adipiscing elit', From 5c64519c3e3e75abfa37fed52626f6a6d2c492e9 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 30 Jan 2021 15:56:52 +0100 Subject: [PATCH 0753/1519] Fixed image path --- rate_limiter.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index 1d54faba331..4b6fc27d4ab 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -38,7 +38,7 @@ squares). .. raw:: html - + Its main drawback is that resource usage is not evenly distributed in time and it can overload the server at the window edges. In the previous example, @@ -59,7 +59,7 @@ using a 1 hour window that slides over the timeline: .. raw:: html - + As you can see, this removes the edges of the window and would prevent the 6th request at 11:45. @@ -93,7 +93,7 @@ of 1 token per 15 minutes: .. raw:: html - + This algorithm handles more complex back-off algorithm to manage bursts. For instance, it can allow a user to try a password 5 times and then only From 79a2112445af415940e317284b59572b3bad6e18 Mon Sep 17 00:00:00 2001 From: Albert Casademont Date: Mon, 1 Feb 2021 17:24:47 +0100 Subject: [PATCH 0754/1519] Docs for the new SYMFONY_PHPUNIT_REQUIRE env variable Code PR: https://github.com/symfony/symfony/pull/40059 --- components/phpunit_bridge.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index dedb70c20d3..871b7035f9d 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -930,6 +930,18 @@ If you have installed the bridge through Composer, you can run it by calling e.g then set the ``SYMFONY_PHPUNIT_REMOVE`` env var to ``symfony/yaml``. It's also possible to set this env var in the ``phpunit.xml.dist`` file. + +.. tip:: + + It is also possible to require additional packages that will be installed along + the rest of the needed PHPUnit packages using the ``SYMFONY_PHPUNIT_REQUIRE`` + env variable. This is specially useful for installing PHPUnit plugins without + having to add them to your main ``composer.json`` file. + +.. versionadded:: 5.3 + + The ``SYMFONY_PHPUNIT_REQUIRE`` env variable was introduced in + Symfony 5.3. Code Coverage Listener ---------------------- From 1bb5c085463299c25a10c1007e4d5a5bc443b7d6 Mon Sep 17 00:00:00 2001 From: Dale Nash Date: Tue, 2 Feb 2021 10:30:23 +0000 Subject: [PATCH 0755/1519] Update conventions page to show correct function --- contributing/code/conventions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributing/code/conventions.rst b/contributing/code/conventions.rst index d2325f5fc8b..18ea420b841 100644 --- a/contributing/code/conventions.rst +++ b/contributing/code/conventions.rst @@ -167,7 +167,7 @@ A deprecation must also be triggered to help people with the migration trigger_deprecation('symfony/package-name', '5.1', 'The "%s" class is deprecated, use "%s" instead.', Deprecated::class, Replacement::class); -When deprecating a whole class the ``trigger_error()`` call should be placed +When deprecating a whole class the ``trigger_deprecation()`` call should be placed after the use declarations, like in this example from `ServiceRouterLoader`_:: namespace Symfony\Component\Routing\Loader\DependencyInjection; From edb9b438bf2ae9ed91ddffff914d1be5d11706b3 Mon Sep 17 00:00:00 2001 From: James Hemery Date: Sat, 23 Jan 2021 01:47:38 +0100 Subject: [PATCH 0756/1519] [Notifier] Add SpotHit bridge --- notifier.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/notifier.rst b/notifier.rst index 7231080d47e..0e55317c31f 100644 --- a/notifier.rst +++ b/notifier.rst @@ -70,6 +70,7 @@ OvhCloud ``symfony/ovh-cloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLI Sendinblue ``symfony/sendinblue-notifier`` ``sendinblue://API_KEY@default?sender=PHONE`` Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` Smsapi ``symfony/smsapi-notifier`` ``smsapi://TOKEN@default?from=FROM`` +SpotHit ``symfony/spothit-notifier`` ``spothit://TOKEN@default?from=FROM`` Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` ========== ================================ ==================================================== @@ -83,8 +84,8 @@ Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from= .. versionadded:: 5.3 - The Iqsms, GatewayApi, Octopush, AllMySms and Clickatell integrations were - introduced in Symfony 5.3. + The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell and SpotHit integrations + were introduced in Symfony 5.3. To enable a texter, add the correct DSN in your ``.env`` file and From 77007c183940332c255b1a066d1058a960439994 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Wed, 3 Feb 2021 09:11:30 +0100 Subject: [PATCH 0757/1519] message consume command --queue parameter Feature introduced in https://github.com/symfony/symfony/pull/38973 --- messenger.rst | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/messenger.rst b/messenger.rst index edd43cd7881..32fab4e0a41 100644 --- a/messenger.rst +++ b/messenger.rst @@ -587,6 +587,29 @@ to handle messages in a priority order: The worker will always first look for messages waiting on ``async_priority_high``. If there are none, *then* it will consume messages from ``async_priority_low``. +.. _messenger-limit-queues: + +Limit Consuming to Specific Queues +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some transports (notably AMQP) have the concept of exchanges and queues. A Symfony +transport is always bound to an exchange. By default, the worker consumes from all +queues attached to the exchange of the specified transport. However, there are use +cases to want a worker to only consume from specific queues. + +You can limit the worker to only process messages from specific queues: + +.. code-block:: terminal + + $ php bin/console messenger:consume my_transport --queues=fasttrack + +To allow using the ``queues`` option, the receiver must implement the +:class:`Symfony\\Component\\Messenger\\Transport\\Receiver\\QueueReceiverInterface`. + +.. versionadded:: 5.3 + + Limiting the worker to specific queues was introduced in Symfony 5.3. + .. _messenger-supervisor: Supervisor Configuration @@ -950,6 +973,11 @@ it in the ``port`` parameter of the DSN (e.g. ``amqps://localhost?cacert=/etc/ss binding keys that are needed. That can be disabled, but some functionality may not work correctly (like delayed queues). +.. note:: + + With Symfony 5.3 or newer, you can limit the consumer of an AMQP transport to only + process messages from some queues of an exchange. See :ref:`messenger-limit-queues`. + The transport has a number of other options, including ways to configure the exchange, queues binding keys and more. See the documentation on :class:`Symfony\\Component\\Messenger\\Bridge\\Amqp\\Transport\\Connection`. From 88a52da1bf59fc71c5ac8b7366549d5c9862f5f2 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Tue, 2 Feb 2021 17:18:40 +0100 Subject: [PATCH 0758/1519] [RateLimiter][Security] Document login throttling and clarify DoS protection --- rate_limiter.rst | 11 +++++ security.rst | 109 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/rate_limiter.rst b/rate_limiter.rst index 4b6fc27d4ab..99617f20d59 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -16,6 +16,14 @@ Symfony uses these rate limiters in built-in features like "login throttling", which limits how many failed login attempts a user can make in a given period of time, but you can use them for your own features too. +.. caution:: + + By definition, the Symfony rate limiters require Symfony to be booted + in a PHP process. This makes them not useful to protect against `DoS attacks`_. + Such protections must consume the least resources possible. Consider + using `Apache mod_ratelimit`_, `NGINX rate limiting`_ or proxies (like + AWS or Cloudflare) to prevent your server from being overwhelmed. + .. _rate-limiter-policies: Rate Limiting Policies @@ -314,5 +322,8 @@ Symfony application. If you prefer to change that, use the ``lock_factory`` and # the value is the name of any lock defined in your application lock_factory: 'app.rate_limiter_lock' +.. _`DoS attacks`: https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html +.. _`Apache mod_ratelimit`: https://httpd.apache.org/docs/current/mod/mod_ratelimit.html +.. _`NGINX rate limiting`: https://www.nginx.com/blog/rate-limiting-nginx/ .. _`token bucket algorithm`: https://en.wikipedia.org/wiki/Token_bucket .. _`PHP date relative formats`: https://www.php.net/datetime.formats.relative diff --git a/security.rst b/security.rst index de13f7db4f6..3b9341a07d6 100644 --- a/security.rst +++ b/security.rst @@ -469,6 +469,113 @@ here are a few common use-cases: * :doc:`/security/guard_authentication` – see this for the most detailed description of authenticators and how they work +Limiting Login Attempts +~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.2 + + Login throttling was introduced in Symfony 5.2. + +Symfony provides basic protection against `brute force login attacks`_ if +you're using the :doc:`experimental authenticators `. +You must enable this using the ``login_throttling`` setting: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + enable_authenticator_manager: true + + firewalls: + # ... + + main: + # ... + + # by default, the feature allows 5 login attempts per minute + login_throttling: null + + # configure the maximum login attempts (per minute) + login_throttling: + max_attempts: 3 + + # use a custom rate limiter via its service ID + login_throttling: + limiter: app.my_login_rate_limiter + + .. code-block:: xml + + + + + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + $container->loadFromExtension('security', [ + 'enable_authenticator_manager' => true, + + 'firewalls' => [ + // ... + + 'main' => [ + // by default, the feature allows 5 login attempts per minute + 'login_throttling' => null, + + // configure the maximum login attempts (per minute) + 'login_throttling' => [ + 'max_attempts' => 3, + ], + + // use a custom rate limiter via its service ID + 'login_throttling' => [ + 'limiter' => 'app.my_login_rate_limiter', + ], + ], + ], + ]); + +By default, login attempts are limited on ``max_attempts`` (default: 5) +failed requests for ``IP address + username`` and ``5 * max_attempts`` +failed requests for ``IP address``. The second limit protects against an +attacker using multiple usernames from bypassing the first limit, without +distrupting normal users on big networks (such as offices). + +If you need a more complex limiting algorithm, create a class that implements +:class:`Symfony\\Component\\HttpFoundation\\RateLimiter\\RequestRateLimiterInterface` +and set the ``limiter`` option to its service ID. + +.. tip:: + + Limiting the failed login attempts is only one basic protection against + brute force attacks. The `OWASP Brute Force Attacks`_ guidelines mention + several other protections that you should consider depending on the + level of protection required. + .. _`security-authorization`: .. _denying-access-roles-and-other-authorization: @@ -1257,5 +1364,7 @@ Authorization (Denying Access) .. _`FrameworkExtraBundle documentation`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html .. _`HWIOAuthBundle`: https://github.com/hwi/HWIOAuthBundle +.. _`OWASP Brute Force Attacks`: https://owasp.org/www-community/controls/Blocking_Brute_Force_Attacks +.. _`brute force login attacks`: https://owasp.org/www-community/controls/Blocking_Brute_Force_Attacks .. _`Symfony Security screencast series`: https://symfonycasts.com/screencast/symfony-security .. _`MakerBundle`: https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html From a85f968a3d22fae4657ef89f7cabbbea4043969c Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 28 Jan 2021 11:27:20 -0500 Subject: [PATCH 0759/1519] updating Encore docs for 1.0 --- .doctor-rst.yaml | 1 + _build/redirection_map | 1 + frontend.rst | 1 - frontend/encore/advanced-config.rst | 8 +- frontend/encore/copy-files.rst | 2 +- frontend/encore/dev-server.rst | 109 ++++++++++++++-------------- frontend/encore/installation.rst | 2 +- frontend/encore/shared-entry.rst | 42 ----------- frontend/encore/simple-example.rst | 48 ++---------- frontend/encore/split-chunks.rst | 13 ++-- frontend/encore/url-loader.rst | 47 ++++-------- frontend/encore/vuejs.rst | 4 +- 12 files changed, 92 insertions(+), 186 deletions(-) delete mode 100644 frontend/encore/shared-entry.rst diff --git a/.doctor-rst.yaml b/.doctor-rst.yaml index a568b014eab..61b56614a29 100644 --- a/.doctor-rst.yaml +++ b/.doctor-rst.yaml @@ -88,6 +88,7 @@ whitelist: - '.. versionadded:: 1.3' # MakerBundle - '.. versionadded:: 1.8' # MakerBundle - '.. versionadded:: 1.6' # Flex in setup/upgrade_minor.rst + - '.. versionadded:: 1.0.0' # Encore - '0 => 123' # assertion for var_dumper - components/var_dumper.rst - '1 => "foo"' # assertion for var_dumper - components/var_dumper.rst - '123,' # assertion for var_dumper - components/var_dumper.rst diff --git a/_build/redirection_map b/_build/redirection_map index de584707346..402057bdd18 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -511,3 +511,4 @@ /messenger/message-recorder messenger/dispatch_after_current_bus /components/stopwatch https://github.com/symfony/stopwatch /service_container/3.3-di-changes https://symfony.com/doc/3.4/service_container/3.3-di-changes.html +/frontend/encore/shared-entry /frontend/encore/split-chunks diff --git a/frontend.rst b/frontend.rst index 47d3111dd33..b95f0aa216e 100644 --- a/frontend.rst +++ b/frontend.rst @@ -61,7 +61,6 @@ Optimizing * :doc:`Using a CDN ` * :doc:`/frontend/encore/code-splitting` * :doc:`/frontend/encore/split-chunks` -* :doc:`Creating a "Shared" entry for re-used modules ` * :doc:`/frontend/encore/url-loader` Guides diff --git a/frontend/encore/advanced-config.rst b/frontend/encore/advanced-config.rst index 86bdb812b94..75abf94f481 100644 --- a/frontend/encore/advanced-config.rst +++ b/frontend/encore/advanced-config.rst @@ -12,12 +12,12 @@ To do that, modify the config after fetching it from Encore: // webpack.config.js - var Encore = require('@symfony/webpack-encore'); + const Encore = require('@symfony/webpack-encore'); // ... all Encore config here // fetch the config, then modify it! - var config = Encore.getWebpackConfig(); + const config = Encore.getWebpackConfig(); // add an extension config.resolve.extensions.push('json'); @@ -208,8 +208,8 @@ The following code is equivalent: The following loaders are configurable with ``configureLoaderRule()``: - ``javascript`` (alias ``js``) - ``css`` - - ``images`` - - ``fonts`` + - ``images`` (but use ``configureImageRule()`` instead) + - ``fonts`` (but use ``configureFontRule()`` instead) - ``sass`` (alias ``scss``) - ``less`` - ``stylus`` diff --git a/frontend/encore/copy-files.rst b/frontend/encore/copy-files.rst index 7ea5a541622..28e8f26d80a 100644 --- a/frontend/encore/copy-files.rst +++ b/frontend/encore/copy-files.rst @@ -16,7 +16,7 @@ To reference an image tag from inside a JavaScript file, *require* the file: // returns the final, public path to this file // path is relative to this file - e.g. assets/images/logo.png - const logoPath = require('../images/logo.png'); + import logoPath from '../images/logo.png'; let html = `ACME logo`; diff --git a/frontend/encore/dev-server.rst b/frontend/encore/dev-server.rst index 4d0904125cb..b5683109092 100644 --- a/frontend/encore/dev-server.rst +++ b/frontend/encore/dev-server.rst @@ -8,31 +8,16 @@ While developing, instead of using ``yarn encore dev --watch``, you can use the $ yarn encore dev-server -This builds and serves the front-end assets from a new server. This server runs at -``localhost:8080`` by default, meaning your build assets are available at ``localhost:8080/build``. -This server does not actually write the files to disk; instead it servers them from memory, +This builds and serves the front-end assets from a new server. This server runs at +``localhost:8080`` by default, meaning your build assets are available at ``localhost:8080/build``. +This server does not actually write the files to disk; instead it servers them from memory, allowing for hot module reloading. -As a consequence, the ``link`` and ``script`` tags need to point to the new server. If you're using the -``encore_entry_script_tags()`` and ``encore_entry_link_tags()`` Twig shortcuts (or are -:ref:`processing your assets through entrypoints.json ` in some other way), +As a consequence, the ``link`` and ``script`` tags need to point to the new server. If you're using the +``encore_entry_script_tags()`` and ``encore_entry_link_tags()`` Twig shortcuts (or are +:ref:`processing your assets through entrypoints.json ` in some other way), you're done: the paths in your templates will automatically point to the dev server. -Enabling HTTPS using the Symfony Web Server -------------------------------------------- - -If you're using the :doc:`Symfony web server ` locally with HTTPS, -you'll need to also tell the dev-server to use HTTPS. To do this, you can reuse the Symfony web -server SSL certificate: - -.. code-block:: terminal - - # Unix-based systems - $ yarn dev-server --https --pfx=$HOME/.symfony/certs/default.p12 - - # Windows - $ encore dev-server --https --pfx=%UserProfile%\.symfony\certs\default.p12 - dev-server Options ------------------ @@ -66,53 +51,65 @@ method in your ``webpack.config.js`` file: The ``Encore.configureDevServerOptions()`` method was introduced in Encore 0.28.4. -Hot Module Replacement HMR --------------------------- +Enabling HTTPS using the Symfony Web Server +------------------------------------------- + +If you're using the :doc:`Symfony web server ` locally with HTTPS, +you'll need to also tell the dev-server to use HTTPS. To do this, you can reuse the Symfony web +server SSL certificate: + +.. code-block:: javascript -Encore *does* support `HMR`_ for :doc:`Vue.js `, but -does *not* work for styles anywhere at this time. To activate it, pass the ``--hot`` -option: + // webpack.config.js + // ... + const path = require('path'); + + Encore + // ... + + .configureDevServerOptions(options => { + options.https = { + pfx: path.join(process.env.HOME, '.symfony/certs/default.p12'), + } + }) + +Then make sure you run the ``dev-server`` with the ``--https`` option: .. code-block:: terminal - $ ./node_modules/.bin/encore dev-server --hot + $ yarn encore dev-server --https -If you want to use SSL with self-signed certificates, add the ``--https``, -``--pfx=``, and ``--allowed-hosts`` options to the ``dev-server`` command in -the ``package.json`` file: +CORS Issues +----------- -.. code-block:: diff +If you experience issues related to CORS (Cross Origin Resource Sharing), set +the ``firewall`` option: - { - ... - "scripts": { - - "dev-server": "encore dev-server", - + "dev-server": "encore dev-server --https --pfx=$HOME/.symfony/certs/default.p12 --allowed-hosts=mydomain.wip", - ... - } - } +.. code-block:: javascript -If you experience issues related to CORS (Cross Origin Resource Sharing), add -the ``--disable-host-check`` and ``--port`` options to the ``dev-server`` -command in the ``package.json`` file: + // webpack.config.js + // ... + + Encore + // ... -.. code-block:: diff + .configureDevServerOptions(options => { + options.firewall = false; + }) - { - ... - "scripts": { - - "dev-server": "encore dev-server", - + "dev-server": "encore dev-server --port 8080 --disable-host-check", - ... - } - } +Hot Module Replacement HMR +-------------------------- -.. caution:: +Hot module replacement is a superpower of the ``dev-server`` where styles and +(in some cases) JavaScript can automatically update without needing to reload +your page. HMR works automatically with CSS (as long as you're using the +``dev-server`` and Encore 1.0 or higher) but only works with some JavaScript +(like :doc:`Vue.js `). - Beware that `it's not recommended to disable host checking`_ in general, but - here it's required to solve the CORS issue. +.. versionadded:: 1.0.0 + Before Encore 1.0, you needed to pass a ``--hot`` flag at the command line + to enable HMR. You also needed to disable CSS extraction to enable HMR for + CSS. That is no longer needed. .. _`webpack-dev-server`: https://webpack.js.org/configuration/dev-server/ -.. _`HMR`: https://webpack.js.org/concepts/hot-module-replacement/ -.. _`it's not recommended to disable host checking`: https://webpack.js.org/configuration/dev-server/#devserverdisablehostcheck diff --git a/frontend/encore/installation.rst b/frontend/encore/installation.rst index bbd6469a1c3..ef77cfe71ed 100644 --- a/frontend/encore/installation.rst +++ b/frontend/encore/installation.rst @@ -54,7 +54,7 @@ is the main config file for both Webpack and Webpack Encore: .. code-block:: javascript - var Encore = require('@symfony/webpack-encore'); + const Encore = require('@symfony/webpack-encore'); // Manually configure the runtime environment if not already configured yet by the "encore" command. // It's useful when you use tools that rely on webpack.config.js file. diff --git a/frontend/encore/shared-entry.rst b/frontend/encore/shared-entry.rst deleted file mode 100644 index a2c2d08ea2a..00000000000 --- a/frontend/encore/shared-entry.rst +++ /dev/null @@ -1,42 +0,0 @@ -Creating a Shared Commons Entry -=============================== - -.. caution:: - - While this method still works, see :doc:`/frontend/encore/split-chunks` for - the preferred solution to sharing assets between multiple entry files. - -Suppose you have multiple entry files and *each* requires ``jquery``. In this -case, *each* output file will contain jQuery, slowing down your user's experience. -To solve this, you can *extract* the common libraries to a "shared" entry file -that's included on every page. - -Suppose you already have an entry called ``app`` that's included on every page. -Update your code to use ``createSharedEntry()``: - -.. code-block:: diff - - Encore - // ... - - .addEntry('app', './assets/app.js') - + .createSharedEntry('app', './assets/app.js') - .addEntry('homepage', './assets/homepage.js') - .addEntry('blog', './assets/blog.js') - .addEntry('store', './assets/store.js') - -Before making this change, if both ``app.js`` and ``store.js`` require ``jquery``, -then ``jquery`` would be packaged into *both* files, which is wasteful. By making -``app.js`` your "shared" entry, *any* code required by ``app.js`` (like jQuery) will -*no longer* be packaged into any other files. The same is true for any CSS. - -Because ``app.js`` contains all the common code that other entry files depend on, -its script (and link) tag must be on every page. - -.. tip:: - - The ``app.js`` file works best when its contents are changed *rarely* - and you're using :ref:`long-term caching `. Why? - If ``app.js`` contains application code that *frequently* changes, then - (when using versioning), its filename hash will frequently change. This means - your users won't enjoy the benefits of long-term caching for this file (which - is generally quite large). diff --git a/frontend/encore/simple-example.rst b/frontend/encore/simple-example.rst index dd93a31cf37..cda018f36e8 100644 --- a/frontend/encore/simple-example.rst +++ b/frontend/encore/simple-example.rst @@ -19,8 +19,6 @@ application: it will *require* all of the dependencies it needs (e.g. jQuery or import './styles/app.css'; - // import $ from 'jquery'; - Encore's job (via Webpack) is simple: to read and follow *all* of the ``require()`` statements and create one final ``app.js`` (and ``app.css``) that contains *everything* your app needs. Encore can do a lot more: minify files, pre-process Sass/LESS, @@ -35,7 +33,7 @@ of your project. It already holds the basic config you need: .. code-block:: javascript // webpack.config.js - var Encore = require('@symfony/webpack-encore'); + const Encore = require('@symfony/webpack-encore'); Encore // directory where compiled assets will be stored @@ -130,6 +128,8 @@ filename(s) to render. This file is *especially* useful because you can :doc:`enable versioning ` or :doc:`point assets to a CDN ` without making *any* changes to your template: the paths in ``entrypoints.json`` will always be the final, correct paths. +And if you use :doc:`splitEntryChunks() ` (where Webpack splits the output into even +more files), all the necessary ``script`` and ``link`` tags will render automatically. If you're *not* using Symfony, you can ignore the ``entrypoints.json`` file and point to the final, built file directly. ``entrypoints.json`` is only required for @@ -147,13 +147,13 @@ some optional features. Requiring JavaScript Modules ---------------------------- -Webpack is a module bundler, which means that you can ``require`` other JavaScript +Webpack is a module bundler, which means that you can ``import`` other JavaScript files. First, create a file that exports a function: .. code-block:: javascript // assets/greet.js - module.exports = function(name) { + export default function(name) { return `Yo yo ${name} - welcome to Encore!`; }; @@ -163,7 +163,7 @@ We'll use jQuery to print this message on the page. Install it via: $ yarn add jquery --dev -Great! Use ``require()`` to import ``jquery`` and ``greet.js``: +Great! Use ``import`` to import ``jquery`` and ``greet.js``: .. code-block:: diff @@ -171,11 +171,11 @@ Great! Use ``require()`` to import ``jquery`` and ``greet.js``: // ... + // loads the jquery package from node_modules - + var $ = require('jquery'); + + import jquery from 'jquery'; + // import the function from greet.js (the .js extension is optional) + // ./ (or ../) means to look for a local file - + var greet = require('./greet'); + + import greet from './greet'; + $(document).ready(function() { + $('body').prepend('

    '+greet('jill')+'

    '); @@ -185,37 +185,6 @@ That's it! If you previously ran ``encore dev --watch``, your final, built files have already been updated: jQuery and ``greet.js`` have been automatically added to the output file (``app.js``). Refresh to see the message! -The import and export Statements --------------------------------- - -Instead of using ``require()`` and ``module.exports`` like shown above, JavaScript -provides an alternate syntax based on the `ECMAScript 6 modules`_ that includes -the ability to use dynamic imports. - -To export values using the alternate syntax, use ``export``: - -.. code-block:: diff - - // assets/greet.js - - module.exports = function(name) { - + export default function(name) { - return `Yo yo ${name} - welcome to Encore!`; - }; - -To import values, use ``import``: - -.. code-block:: diff - - // assets/app.js - - require('../styles/app.css'); - + import './styles/app.css'; - - - var $ = require('jquery'); - + import $ from 'jquery'; - - - var greet = require('./greet'); - + import greet from './greet'; - .. _multiple-javascript-entries: Page-Specific JavaScript or CSS (Multiple Entries) @@ -357,5 +326,4 @@ Encore supports many more features! For a full list of what you can do, see `Encore's index.js file`_. Or, go back to :ref:`list of Encore articles `. .. _`Encore's index.js file`: https://github.com/symfony/webpack-encore/blob/master/index.js -.. _`ECMAScript 6 modules`: https://hacks.mozilla.org/2015/08/es6-in-depth-modules/ .. _`WebpackEncoreBundle Configuration`: https://github.com/symfony/webpack-encore-bundle#configuration diff --git a/frontend/encore/split-chunks.rst b/frontend/encore/split-chunks.rst index 0205537b7d0..5569a9731f3 100644 --- a/frontend/encore/split-chunks.rst +++ b/frontend/encore/split-chunks.rst @@ -23,9 +23,10 @@ To enable this, call ``splitEntryChunks()``: Now, each output file (e.g. ``homepage.js``) *may* be split into multiple file -(e.g. ``homepage.js``, ``vendor~homepage.js``). This means that you *may* need to -include *multiple* ``script`` tags (or ``link`` tags for CSS) in your template. -Encore creates an :ref:`entrypoints.json ` +(e.g. ``homepage.js`` & ``vendors-node_modules_jquery_dist_jquery_js.js`` - the +filename of the second will be less obvious when you build for production). This +means that you *may* need to include *multiple* ``script`` tags (or ``link`` tags +for CSS) in your template. Encore creates an :ref:`entrypoints.json ` file that lists exactly which CSS and JavaScript files are needed for each entry. If you're using the ``encore_entry_link_tags()`` and ``encore_entry_script_tags()`` @@ -37,9 +38,9 @@ tags as needed: {# May now render multiple script tags: - - - + + + #} {{ encore_entry_script_tags('homepage') }} diff --git a/frontend/encore/url-loader.rst b/frontend/encore/url-loader.rst index 976cd6974d8..9567960c99d 100644 --- a/frontend/encore/url-loader.rst +++ b/frontend/encore/url-loader.rst @@ -1,18 +1,11 @@ -Inlining files in CSS with Webpack URL Loader -============================================= +Inlining Images & Fronts in CSS +=============================== A simple technique to improve the performance of web applications is to reduce the number of HTTP requests inlining small files as base64 encoded URLs in the generated CSS files. -Webpack Encore provides this feature via Webpack's `URL Loader`_ plugin, but -it's disabled by default. First, add the URL loader to your project: - -.. code-block:: terminal - - $ yarn add url-loader --dev - -Then enable it in your ``webpack.config.js``: +You can enable this in ``webpack.config.js`` for images, fonts or both: .. code-block:: javascript @@ -21,31 +14,19 @@ Then enable it in your ``webpack.config.js``: Encore // ... - .configureUrlLoader({ - fonts: { limit: 4096 }, - images: { limit: 4096 } + .configureImageRule({ + // tell Webpack it should consider inlining + type: 'asset', + //maxSize: 4 * 1024, // 4 kb - the default is 8kb }) - ; - -The ``limit`` option defines the maximum size in bytes of the inlined files. In -the previous example, font and image files having a size below or equal to 4 KB -will be inlined and the rest of files will be processed as usual. - -You can also use all the other options supported by the `URL Loader`_. If you -want to disable this loader for either images or fonts, remove the corresponding -key from the object that is passed to the ``configureUrlLoader()`` method: - -.. code-block:: javascript - - // webpack.config.js - // ... - Encore - // ... - .configureUrlLoader({ - // 'fonts' is not defined, so only images will be inlined - images: { limit: 4096 } + .configureFontRule({ + type: 'asset', + //maxSize: 4 * 1024 }) ; -.. _`URL Loader`: https://github.com/webpack-contrib/url-loader +This leverages Webpack `Asset Modules`_. You can read more about this and the +configuration there. + +.. _`Asset Modules`: https://webpack.js.org/guides/asset-modules/ diff --git a/frontend/encore/vuejs.rst b/frontend/encore/vuejs.rst index 3d10eedcd41..eb8e2793c82 100644 --- a/frontend/encore/vuejs.rst +++ b/frontend/encore/vuejs.rst @@ -65,11 +65,11 @@ Hot Module Replacement (HMR) The ``vue-loader`` supports hot module replacement: just update your code and watch your Vue.js app update *without* a browser refresh! To activate it, use the -``dev-server`` with the ``--hot`` option: +``dev-server``: .. code-block:: terminal - $ yarn encore dev-server --hot + $ yarn encore dev-server That's it! Change one of your ``.vue`` files and watch your browser update. But note: this does *not* currently work for *style* changes in a ``.vue`` file. Seeing From 47d7639fa796d47fab5492d8a912c51f58536e35 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 4 Feb 2021 19:28:08 -0500 Subject: [PATCH 0760/1519] re-adding warning about host check --- frontend/encore/dev-server.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/encore/dev-server.rst b/frontend/encore/dev-server.rst index b5683109092..3edd2d8ef83 100644 --- a/frontend/encore/dev-server.rst +++ b/frontend/encore/dev-server.rst @@ -97,6 +97,9 @@ the ``firewall`` option: options.firewall = false; }) +Beware that `it's not recommended to disable the firewall`_ in general, but +here it's required to solve the CORS issue. + Hot Module Replacement HMR -------------------------- @@ -113,3 +116,4 @@ your page. HMR works automatically with CSS (as long as you're using the CSS. That is no longer needed. .. _`webpack-dev-server`: https://webpack.js.org/configuration/dev-server/ +.. _`it's not recommended to disable the firewall`: https://webpack.js.org/configuration/dev-server/#devserverdisablehostcheck \ No newline at end of file From 77ace60dd9145a36b813aa4ce51af35f39d17097 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 5 Feb 2021 13:02:25 +0100 Subject: [PATCH 0761/1519] Removed the "roles" variable --- security/expressions.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/security/expressions.rst b/security/expressions.rst index 0740512ed04..cfdf006466c 100644 --- a/security/expressions.rst +++ b/security/expressions.rst @@ -38,10 +38,6 @@ Inside the expression, you have access to a number of variables: ``user`` The user object (or the string ``anon`` if you're not authenticated). -``roles`` - The array of roles the user has. This array includes any roles granted - indirectly via the :ref:`role hierarchy ` but it - does not include the ``IS_AUTHENTICATED_*`` attributes (see the functions below). ``role_names`` An array with the string representation of the roles the user has. This array includes any roles granted indirectly via the :ref:`role hierarchy ` but it From a32dd60d073d24bbfb2a6934e85a66842b10d1c9 Mon Sep 17 00:00:00 2001 From: Wojciech Kania Date: Sat, 6 Feb 2021 12:26:54 +0100 Subject: [PATCH 0762/1519] [Validator] Use single quotes for a string --- reference/constraints/EqualTo.rst | 2 +- reference/constraints/IdenticalTo.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/constraints/EqualTo.rst b/reference/constraints/EqualTo.rst index 75d80043cda..a4721a086c3 100644 --- a/reference/constraints/EqualTo.rst +++ b/reference/constraints/EqualTo.rst @@ -61,7 +61,7 @@ and that the ``age`` is ``20``, you could do the following: class Person { - #[Assert\EqualTo("Mary")] + #[Assert\EqualTo('Mary')] protected $firstName; #[Assert\EqualTo( diff --git a/reference/constraints/IdenticalTo.rst b/reference/constraints/IdenticalTo.rst index 7dc71b475f0..27ba84e59fe 100644 --- a/reference/constraints/IdenticalTo.rst +++ b/reference/constraints/IdenticalTo.rst @@ -63,7 +63,7 @@ The following constraints ensure that: class Person { - #[Assert\IdenticalTo("Mary")] + #[Assert\IdenticalTo('Mary')] protected $firstName; #[Assert\IdenticalTo( From 35467b97d09033f2d2f0fc777fe335f25340f55f Mon Sep 17 00:00:00 2001 From: wkania Date: Sat, 6 Feb 2021 13:06:50 +0100 Subject: [PATCH 0763/1519] [Validator] Add a missing dot The other two issues end with a dot. --- reference/constraints/Sequentially.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/constraints/Sequentially.rst b/reference/constraints/Sequentially.rst index 21e088ba689..da7bd16f4b2 100644 --- a/reference/constraints/Sequentially.rst +++ b/reference/constraints/Sequentially.rst @@ -35,7 +35,7 @@ In such situations, you may encounter three issues: * the ``Length`` or ``Regex`` constraints may fail hard with a :class:`Symfony\\Component\\Validator\\Exception\\UnexpectedValueException` exception if the actual value is not a string, as enforced by ``Type``. -* you may end with multiple error messages for the same property +* you may end with multiple error messages for the same property. * you may perform a useless and heavy external call to geolocalize the address, while the format isn't valid. From 7332254b3eff85db5f5aac8cce574b28eec72ac0 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 4 Feb 2021 21:20:10 -0500 Subject: [PATCH 0764/1519] Adding notes related to the dev-server https fix in Encore --- frontend/encore/dev-server.rst | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/frontend/encore/dev-server.rst b/frontend/encore/dev-server.rst index 3edd2d8ef83..b1f72e5996b 100644 --- a/frontend/encore/dev-server.rst +++ b/frontend/encore/dev-server.rst @@ -21,12 +21,18 @@ you're done: the paths in your templates will automatically point to the dev ser dev-server Options ------------------ +.. caution:: + + Encore uses ``webpack-dev-server`` version 4, which at the time of Encore's + 1.0 release was still in beta and was not documented. See the `4.0 CHANGELOG`_ + for changes. + The ``dev-server`` command supports all the options defined by `webpack-dev-server`_. You can set these options via command line options: .. code-block:: terminal - $ yarn encore dev-server --https --port 9000 + $ yarn encore dev-server --port 9000 You can also set these options using the ``Encore.configureDevServerOptions()`` method in your ``webpack.config.js`` file: @@ -58,26 +64,27 @@ If you're using the :doc:`Symfony web server ` locally wi you'll need to also tell the dev-server to use HTTPS. To do this, you can reuse the Symfony web server SSL certificate: -.. code-block:: javascript +.. code-block:: diff // webpack.config.js // ... - const path = require('path'); + + const path = require('path'); Encore // ... - .configureDevServerOptions(options => { - options.https = { - pfx: path.join(process.env.HOME, '.symfony/certs/default.p12'), - } - }) + + .configureDevServerOptions(options => { + + options.https = { + + pfx: path.join(process.env.HOME, '.symfony/certs/default.p12'), + + } + + }) -Then make sure you run the ``dev-server`` with the ``--https`` option: -.. code-block:: terminal +.. caution:: - $ yarn encore dev-server --https + Make sure to **not** pass the ``--https`` flag at the command line when + running ``encore dev-server``. This flag was required before 1.0, but now + will cause your config to be overridden. CORS Issues ----------- @@ -116,4 +123,5 @@ your page. HMR works automatically with CSS (as long as you're using the CSS. That is no longer needed. .. _`webpack-dev-server`: https://webpack.js.org/configuration/dev-server/ -.. _`it's not recommended to disable the firewall`: https://webpack.js.org/configuration/dev-server/#devserverdisablehostcheck \ No newline at end of file +.. _`it's not recommended to disable the firewall`: https://webpack.js.org/configuration/dev-server/#devserverdisablehostcheck +.. _`4.0 CHANGELOG`: https://github.com/webpack/webpack-dev-server/blob/master/CHANGELOG.md#400-beta0-2020-11-27 From 6b35baff53bc705452250cee5d2d24640a915024 Mon Sep 17 00:00:00 2001 From: Thibault RICHARD Date: Sun, 7 Feb 2021 14:46:17 +0100 Subject: [PATCH 0765/1519] Document the way to configure emails globally --- mailer.rst | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/mailer.rst b/mailer.rst index 9c9c1451add..89be86382a4 100644 --- a/mailer.rst +++ b/mailer.rst @@ -320,8 +320,7 @@ both strings or address objects:: .. tip:: Instead of calling ``->from()`` *every* time you create a new email, you can - create an :doc:`event subscriber ` and listen to the - :class:`Symfony\\Component\\Mailer\\Event\\MessageEvent` event to set the + :ref:`configure emails globally ` to set the same ``From`` email to all messages. .. note:: @@ -373,6 +372,12 @@ header, etc.) but most of the times you'll set text headers:: // ... ; +.. tip:: + + Instead of calling ``->addTextHeader()`` *every* time you create a new email, you can + :ref:`configure emails globally ` to set the same + headers to all sent emails. + Message Contents ~~~~~~~~~~~~~~~~ @@ -448,6 +453,75 @@ images inside the HTML contents:: ->html(' ... ...') ; +.. _mailer-configure-email-globally: + +Configuring Emails Globally +--------------------------- + +Instead of calling ``->from()`` on each Email you create, you can configure this +value globally so that it is set on all sent emails. The same is true with ``->to()`` +and headers. + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/dev/mailer.yaml + framework: + mailer: + envelope: + sender: 'fabien@example.com' + recipients: ['foo@example.com', 'bar@example.com'] + headers: + from: 'Fabien ' + bcc: 'baz@example.com' + X-Custom-Header: 'foobar' + + .. code-block:: xml + + + + + + + + + + fabien@example.com + foo@example.com + bar@example.com + + Fabien <fabien@example.com> + baz@example.com + foobar + + + + + .. code-block:: php + + // config/packages/mailer.php + $container->loadFromExtension('framework', [ + // ... + 'mailer' => [ + 'envelope' => [ + 'sender' => 'fabien@example.com', + 'recipients' => ['foo@example.com', 'bar@example.com'], + ], + 'headers' => [ + 'from' => 'Fabien ', + 'bcc' => 'baz@example.com', + 'X-Custom-Header' => 'foobar', + ], + ], + ]); + + Handling Sending Failures ------------------------- From 4c041bc7374cfa66cedc172efd6acd4857db1704 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 8 Feb 2021 09:11:38 +0100 Subject: [PATCH 0766/1519] Added the versionadded directive --- mailer.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mailer.rst b/mailer.rst index 89be86382a4..ed2e0ccf041 100644 --- a/mailer.rst +++ b/mailer.rst @@ -521,6 +521,9 @@ and headers. ], ]); +.. versionadded:: 5.2 + + The ``headers`` option was introduced in Symfony 5.2. Handling Sending Failures ------------------------- From eee0223c0de7d0c036ed9fe5872d2127888fb7d6 Mon Sep 17 00:00:00 2001 From: Sebastian Paczkowski <74934099+sebpacz@users.noreply.github.com> Date: Tue, 9 Feb 2021 20:01:01 +0100 Subject: [PATCH 0767/1519] [Messenger][CS] Add missing comma in PHP configuration --- messenger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index a6e64d8f94e..8a527c43c65 100644 --- a/messenger.rst +++ b/messenger.rst @@ -899,7 +899,7 @@ options. Options can be passed to the transport via a DSN string or configuratio 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', 'options' => [ 'auto_setup' => false, - ] + ], ], ], ], From 5df61fdfc234a4c956e3329fd9bced53c2d2d00f Mon Sep 17 00:00:00 2001 From: wkania Date: Tue, 9 Feb 2021 20:15:55 +0100 Subject: [PATCH 0768/1519] [Validator] Add a missing namespace and use --- validation/custom_constraint.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/validation/custom_constraint.rst b/validation/custom_constraint.rst index 9cecde12b8a..468342ea5bd 100644 --- a/validation/custom_constraint.rst +++ b/validation/custom_constraint.rst @@ -285,6 +285,11 @@ not to the property: .. code-block:: php-attributes + // src/Entity/AcmeEntity.php + namespace App\Entity; + + use App\Validator as AcmeAssert; + #[AcmeAssert\ProtocolClass] class AcmeEntity { From c8ad12291ffac5f8d58e8318b3b4048c4bb14b4c Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Wed, 10 Feb 2021 07:03:56 -0500 Subject: [PATCH 0769/1519] updating config for postcss-loader v4 --- frontend/encore/postcss.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/encore/postcss.rst b/frontend/encore/postcss.rst index 76c6e8d67e9..d2322b14032 100644 --- a/frontend/encore/postcss.rst +++ b/frontend/encore/postcss.rst @@ -43,13 +43,14 @@ You can also pass options to the `postcss-loader`_ by passing a callback: .. code-block:: diff // webpack.config.js + + const path = require('path'); Encore // ... + .enablePostCssLoader((options) => { - + options.config = { + + options.postcssOptions = { + // the directory where the postcss.config.js file is stored - + path: 'path/to/config' + + config: path.resolve(__dirname, 'sub-dir', 'custom.config.js'), + }; + }) ; From 0fcfccadc6d0a323321437af607f91bf817f4068 Mon Sep 17 00:00:00 2001 From: Sebastian Paczkowski <74934099+sebpacz@users.noreply.github.com> Date: Wed, 10 Feb 2021 18:56:31 +0100 Subject: [PATCH 0770/1519] [Messenger] Remove duplicated AMQP transport option The confirm_timeout option (introduced in Symfony 5.2) has been documented twice. I left the first version which is closest to the documentation available in the Symfony\Component\Messenger\Bridge\Amqp\Transport\Connection class. --- messenger.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/messenger.rst b/messenger.rst index 625a1bfb743..49058d4d3e4 100644 --- a/messenger.rst +++ b/messenger.rst @@ -971,9 +971,6 @@ The transport has a number of options: fractional. ``connect_timeout`` Connection timeout. Note: 0 or greater seconds. May be fractional. -``confirm_timeout`` Number of seconds to wait for message sending - confirmation. If not specified, transport won't - wait for confirmation. May be fractional. ``frame_max`` The largest frame size that the server proposes for the connection, including frame header and end-byte. 0 means standard extension limit From 78a6c7764bb30d4682cc7f32854840358e6fafb3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 11 Feb 2021 09:23:49 +0100 Subject: [PATCH 0771/1519] Minor tweak --- messenger.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/messenger.rst b/messenger.rst index 49058d4d3e4..0e69f3e11ff 100644 --- a/messenger.rst +++ b/messenger.rst @@ -965,8 +965,8 @@ The transport has a number of options: ``cert`` Path to the client certificate in PEM format. ``channel_max`` Specifies highest channel number that the server permits. 0 means standard extension limit -``confirm_timeout`` Timeout in seconds for confirmation, if none - specified transport will not wait for message +``confirm_timeout`` Timeout in seconds for confirmation; if none + specified, transport will not wait for message confirmation. Note: 0 or greater seconds. May be fractional. ``connect_timeout`` Connection timeout. Note: 0 or greater seconds. From 6c790bc5bfc91573cd166c722f51e9ec7ea5dae2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 11 Feb 2021 11:17:36 +0100 Subject: [PATCH 0772/1519] [Form] Document the new Uuid and Ulid form types --- components/uid.rst | 4 ++ reference/forms/types.rst | 3 + reference/forms/types/map.rst.inc | 6 ++ reference/forms/types/ulid.rst | 98 +++++++++++++++++++++++++++++++ reference/forms/types/uuid.rst | 98 +++++++++++++++++++++++++++++++ 5 files changed, 209 insertions(+) create mode 100644 reference/forms/types/ulid.rst create mode 100644 reference/forms/types/uuid.rst diff --git a/components/uid.rst b/components/uid.rst index e84b7296fad..49ccac839a7 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -21,6 +21,8 @@ Installation .. include:: /components/require_autoload.rst.inc +.. _uuid: + UUIDs ----- @@ -214,6 +216,8 @@ of the UUID parameters:: } } +.. _ulid: + ULIDs ----- diff --git a/reference/forms/types.rst b/reference/forms/types.rst index 49d769c8967..61ff1b5bf86 100644 --- a/reference/forms/types.rst +++ b/reference/forms/types.rst @@ -41,6 +41,9 @@ Form Types Reference types/file types/radio + types/uuid + types/ulid + types/collection types/repeated diff --git a/reference/forms/types/map.rst.inc b/reference/forms/types/map.rst.inc index 4036f2f7dce..8171c836a4d 100644 --- a/reference/forms/types/map.rst.inc +++ b/reference/forms/types/map.rst.inc @@ -43,6 +43,12 @@ Other Fields * :doc:`FileType ` * :doc:`RadioType ` +UID Fields +~~~~~~~~~~ + +* :doc:`UuidType ` +* :doc:`UlidType ` + Field Groups ~~~~~~~~~~~~ diff --git a/reference/forms/types/ulid.rst b/reference/forms/types/ulid.rst new file mode 100644 index 00000000000..26ffa1856e2 --- /dev/null +++ b/reference/forms/types/ulid.rst @@ -0,0 +1,98 @@ +.. index:: + single: Forms; Fields; UuidType + +UlidType Field +============== + +.. versionadded:: 5.3 + + The ``UlidType`` field was introduced in Symfony 5.3. + +Renders an input text field with the ULID string value and transforms it back to +a proper :ref:`Ulid object ` when submitting the form. + ++---------------------------+-----------------------------------------------------------------------+ +| Rendered as | ``input`` ``text`` field | ++---------------------------+-----------------------------------------------------------------------+ +| Options | (none) | ++---------------------------+-----------------------------------------------------------------------+ +| Overridden options | - `compound`_ | +| | - `invalid_message`_ | ++---------------------------+-----------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `invalid_message_parameters`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+-----------------------------------------------------------------------+ +| Default invalid message | Please enter a valid ULID. | ++---------------------------+-----------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+-----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\UlidType` | ++---------------------------+-----------------------------------------------------------------------+ + +.. include:: /reference/forms/types/options/_debug_form.rst.inc + +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/compound_type.rst.inc + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + +Inherited Options +----------------- + +These options inherit from the :doc:`FormType `: + +.. include:: /reference/forms/types/options/attr.rst.inc + +.. include:: /reference/forms/types/options/data.rst.inc + +.. include:: /reference/forms/types/options/disabled.rst.inc + +.. include:: /reference/forms/types/options/empty_data.rst.inc + :end-before: DEFAULT_PLACEHOLDER + +The default value is ``''`` (the empty string). + +.. include:: /reference/forms/types/options/empty_data.rst.inc + :start-after: DEFAULT_PLACEHOLDER + +.. include:: /reference/forms/types/options/error_bubbling.rst.inc + +.. include:: /reference/forms/types/options/error_mapping.rst.inc + +.. include:: /reference/forms/types/options/help.rst.inc + +.. include:: /reference/forms/types/options/help_attr.rst.inc + +.. include:: /reference/forms/types/options/help_html.rst.inc + +.. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc + +.. include:: /reference/forms/types/options/label.rst.inc + +.. include:: /reference/forms/types/options/label_attr.rst.inc + +.. include:: /reference/forms/types/options/label_format.rst.inc + +.. include:: /reference/forms/types/options/mapped.rst.inc + +.. include:: /reference/forms/types/options/required.rst.inc + +.. include:: /reference/forms/types/options/row_attr.rst.inc diff --git a/reference/forms/types/uuid.rst b/reference/forms/types/uuid.rst new file mode 100644 index 00000000000..dd478140ba9 --- /dev/null +++ b/reference/forms/types/uuid.rst @@ -0,0 +1,98 @@ +.. index:: + single: Forms; Fields; UuidType + +UuidType Field +============== + +.. versionadded:: 5.3 + + The ``UuidType`` field was introduced in Symfony 5.3. + +Renders an input text field with the UUID string value and transforms it back to +a proper :ref:`Uuid object ` when submitting the form. + ++---------------------------+-----------------------------------------------------------------------+ +| Rendered as | ``input`` ``text`` field | ++---------------------------+-----------------------------------------------------------------------+ +| Options | (none) | ++---------------------------+-----------------------------------------------------------------------+ +| Overridden options | - `compound`_ | +| | - `invalid_message`_ | ++---------------------------+-----------------------------------------------------------------------+ +| Inherited options | - `attr`_ | +| | - `data`_ | +| | - `disabled`_ | +| | - `empty_data`_ | +| | - `error_bubbling`_ | +| | - `error_mapping`_ | +| | - `help`_ | +| | - `help_attr`_ | +| | - `help_html`_ | +| | - `invalid_message_parameters`_ | +| | - `label`_ | +| | - `label_attr`_ | +| | - `label_format`_ | +| | - `mapped`_ | +| | - `required`_ | +| | - `row_attr`_ | ++---------------------------+-----------------------------------------------------------------------+ +| Default invalid message | Please enter a valid UUID. | ++---------------------------+-----------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+-----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\UuidType` | ++---------------------------+-----------------------------------------------------------------------+ + +.. include:: /reference/forms/types/options/_debug_form.rst.inc + +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/compound_type.rst.inc + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + +Inherited Options +----------------- + +These options inherit from the :doc:`FormType `: + +.. include:: /reference/forms/types/options/attr.rst.inc + +.. include:: /reference/forms/types/options/data.rst.inc + +.. include:: /reference/forms/types/options/disabled.rst.inc + +.. include:: /reference/forms/types/options/empty_data.rst.inc + :end-before: DEFAULT_PLACEHOLDER + +The default value is ``''`` (the empty string). + +.. include:: /reference/forms/types/options/empty_data.rst.inc + :start-after: DEFAULT_PLACEHOLDER + +.. include:: /reference/forms/types/options/error_bubbling.rst.inc + +.. include:: /reference/forms/types/options/error_mapping.rst.inc + +.. include:: /reference/forms/types/options/help.rst.inc + +.. include:: /reference/forms/types/options/help_attr.rst.inc + +.. include:: /reference/forms/types/options/help_html.rst.inc + +.. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc + +.. include:: /reference/forms/types/options/label.rst.inc + +.. include:: /reference/forms/types/options/label_attr.rst.inc + +.. include:: /reference/forms/types/options/label_format.rst.inc + +.. include:: /reference/forms/types/options/mapped.rst.inc + +.. include:: /reference/forms/types/options/required.rst.inc + +.. include:: /reference/forms/types/options/row_attr.rst.inc From 37319d7f4e3b82b866d43ba2bb448a5a4f11d8e3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 11 Feb 2021 12:10:35 +0100 Subject: [PATCH 0773/1519] [Messenger] Fixed the MESSENGER_TRANSPORT_DSN example --- messenger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index 0e69f3e11ff..281c31fa235 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1327,7 +1327,7 @@ The SQS transport DSN may looks like this: .. code-block:: env # .env - MESSENGER_TRANSPORT_DSN=https://AKIAIOSFODNN7EXAMPLE:j17M97ffSVoKI0briFoo9a@sqs.eu-west-3.amazonaws.com/123456789012/messages + MESSENGER_TRANSPORT_DSN=https://sqs.eu-west-3.amazonaws.com/123456789012/messages?access_key= AKIAIOSFODNN7EXAMPLE&secret_key=j17M97ffSVoKI0briFoo9a MESSENGER_TRANSPORT_DSN=sqs://localhost:9494/messages?sslmode=disable .. note:: From 243d84b030e6fbbc09bdc447bd01c6f49fc7d777 Mon Sep 17 00:00:00 2001 From: Johann Pardanaud Date: Thu, 11 Feb 2021 16:33:02 +0100 Subject: [PATCH 0774/1519] [Messenger] Document DSN format for Redis Cluster --- messenger.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/messenger.rst b/messenger.rst index c53044e588d..edcd236f2c3 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1190,6 +1190,8 @@ The Redis transport DSN may looks like this: MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages # Full DSN Example MESSENGER_TRANSPORT_DSN=redis://password@localhost:6379/messages/symfony/consumer?auto_setup=true&serializer=1&stream_max_entries=0&dbindex=0 + # Redis Cluster Example + MESSENGER_TRANSPORT_DSN=redis://host-01:6379,redis://host-02:6379,redis://host-03:6379,redis://host-04:6379 # Unix Socket Example MESSENGER_TRANSPORT_DSN=redis:///var/run/redis.sock From 756b7734d676a1edc47611899a56d7e1a9726d1d Mon Sep 17 00:00:00 2001 From: Sebastian Paczkowski <74934099+sebpacz@users.noreply.github.com> Date: Fri, 12 Feb 2021 06:49:37 +0100 Subject: [PATCH 0775/1519] [Messenger] Fix grammar issue --- messenger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index 0e69f3e11ff..d4929f1659d 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1100,7 +1100,7 @@ Beanstalkd Transport The Beanstalkd transport was introduced in Symfony 5.2. -The Beanstalkd transports sends messages directly to a Beanstalkd work queue. Install +The Beanstalkd transport sends messages directly to a Beanstalkd work queue. Install it by running: .. code-block:: terminal From 5e1aaeca8f25fcdfb4c2b0fc0262450ffdc21bcc Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 12 Feb 2021 09:45:29 +0100 Subject: [PATCH 0776/1519] fix the trusted proxies configuration --- deployment/proxies.rst | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/deployment/proxies.rst b/deployment/proxies.rst index 95d1ddfd0c9..9b6821e3f79 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -33,13 +33,13 @@ and what headers your reverse proxy uses to send information: # ... // the IP address (or range) of your proxy trusted_proxies: '192.0.0.1,10.0.0.0/8' - // trust *all* "X-Forwarded-*" headers (the ! prefix means to not trust those headers) - trusted_headers: ['x-forwarded-all', '!x-forwarded-host', '!x-forwarded-prefix'] + // trust *all* "X-Forwarded-*" headers + trusted_headers: ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port'] // or, if your proxy instead uses the "Forwarded" header - trusted_headers: ['forwarded', '!x-forwarded-host', '!x-forwarded-prefix'] + trusted_headers: ['forwarded'] // or, if you're using a wellknown proxy - trusted_headers: [!php/const Symfony\\Component\\HttpFoundation\\Request::HEADER_X_FORWARDED_AWS_ELB, '!x-forwarded-host', '!x-forwarded-prefix'] - trusted_headers: [!php/const Symfony\\Component\\HttpFoundation\\Request::HEADER_X_FORWARDED_TRAEFIK, '!x-forwarded-host', '!x-forwarded-prefix'] + trusted_headers: [!php/const Symfony\\Component\\HttpFoundation\\Request::HEADER_X_FORWARDED_AWS_ELB] + trusted_headers: [!php/const Symfony\\Component\\HttpFoundation\\Request::HEADER_X_FORWARDED_TRAEFIK] .. code-block:: xml @@ -57,15 +57,14 @@ and what headers your reverse proxy uses to send information: 192.0.0.1,10.0.0.0/8 - - x-forwarded-all - !x-forwarded-host - !x-forwarded-prefix + + x-forwarded-for + x-forwarded-host + x-forwarded-proto + x-forwarded-port forwarded - !x-forwarded-host - !x-forwarded-prefix @@ -78,12 +77,12 @@ and what headers your reverse proxy uses to send information: // the IP address (or range) of your proxy 'trusted_proxies' => '192.0.0.1,10.0.0.0/8', // trust *all* "X-Forwarded-*" headers (the ! prefix means to not trust those headers) - 'trusted_headers' => ['x-forwarded-all', '!x-forwarded-host', '!x-forwarded-prefix'], + 'trusted_headers' => ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port'], // or, if your proxy instead uses the "Forwarded" header - 'trusted_headers' => ['forwarded', '!x-forwarded-host', '!x-forwarded-prefix'], + 'trusted_headers' => ['forwarded'], // or, if you're using a wellknown proxy - 'trusted_headers' => [Request::HEADER_X_FORWARDED_AWS_ELB, '!x-forwarded-host', '!x-forwarded-prefix'], - 'trusted_headers' => [Request::HEADER_X_FORWARDED_TRAEFIK, '!x-forwarded-host', '!x-forwarded-prefix'], + 'trusted_headers' => [Request::HEADER_X_FORWARDED_AWS_ELB], + 'trusted_headers' => [Request::HEADER_X_FORWARDED_TRAEFIK], ]); .. deprecated:: 5.2 From 7a2f7df69762aa244639dd3e130cc2516277f64d Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 11 Feb 2021 10:51:03 +0100 Subject: [PATCH 0777/1519] [Uid] Removed Uuuid generator classes --- components/uid.rst | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index e84b7296fad..b63d829d03a 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -151,29 +151,32 @@ type, which converts to/from UUID objects automatically:: // ... } -There's also a Doctrine generator to help autogenerate UUID values for the -entity primary keys:: +.. versionadded:: 5.2 - // there are generators for UUID V1 and V6 too - use Symfony\Bridge\Doctrine\IdGenerator\UuidV4Generator; - use Symfony\Component\Uid\Uuid; + The UUID type was introduced in Symfony 5.2. - /** - * @ORM\Entity(repositoryClass="App\Repository\ProductRepository") - */ - class Product +There is no generator to assign UUIDs automatically as the value of your entity +primary keys, but you can use instead the following:: + + namespace App\Entity; + + use Doctrine\ORM\Mapping as ORM; + // ... + + class User implements UserInterface { /** * @ORM\Id - * @ORM\Column(type="uuid", unique=true) - * @ORM\GeneratedValue(strategy="CUSTOM") - * @ORM\CustomIdGenerator(class=UuidV4Generator::class) + * @ORM\Column(type="ulid", unique=true) */ private $id; - // ... + public function __construct() + { + $this->id = new Ulid(); + } - public function getId(): ?Uuid + public function getId(): Ulid { return $this->id; } @@ -181,10 +184,6 @@ entity primary keys:: // ... } -.. versionadded:: 5.2 - - The UUID type and generators were introduced in Symfony 5.2. - When using built-in Doctrine repository methods (e.g. ``findOneBy()``), Doctrine knows how to convert these UUID types to build the SQL query (e.g. ``->findOneBy(['user' => $user->getUuid()])``). However, when using DQL From 18393893867e6c2ad575f33775bdf0e4f102ea38 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 12 Feb 2021 15:41:40 +0100 Subject: [PATCH 0778/1519] Tweaks --- components/uid.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index b63d829d03a..1bd3fcb2b56 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -156,27 +156,28 @@ type, which converts to/from UUID objects automatically:: The UUID type was introduced in Symfony 5.2. There is no generator to assign UUIDs automatically as the value of your entity -primary keys, but you can use instead the following:: +primary keys, but you can use the following:: namespace App\Entity; use Doctrine\ORM\Mapping as ORM; + use Symfony\Component\Uid\Uuid; // ... class User implements UserInterface { /** * @ORM\Id - * @ORM\Column(type="ulid", unique=true) + * @ORM\Column(type="uuid", unique=true) */ private $id; public function __construct() { - $this->id = new Ulid(); + $this->id = Uuid::v4(); } - public function getId(): Ulid + public function getId(): Uuid { return $this->id; } From 6f212d9854638822dc016e7a540113157533e1d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Sat, 13 Feb 2021 16:17:56 +0100 Subject: [PATCH 0779/1519] Add documentation for RouterContextMiddleware --- messenger.rst | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/messenger.rst b/messenger.rst index edd43cd7881..eda3d7b16d3 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1954,6 +1954,67 @@ may want to use: ], ]); +Other Middlewares +~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.3 + + The ``router_context`` middleware were introduced in Symfony 5.3. + +When the consumer needs to build an absolute URL, for instance: rendering a +template with links, it needs the initial's request context in order to +retrieves the domain and information needed to build the URL. This can be +achieved by declaring the ``router_context`` middleware in the bus. + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/messenger.yaml + framework: + messenger: + buses: + command_bus: + middleware: + - router_context + + .. code-block:: xml + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/messenger.php + $container->loadFromExtension('framework', [ + 'messenger' => [ + 'buses' => [ + 'command_bus' => [ + 'middleware' => [ + 'router_context', + ], + ], + ], + ], + ]); + + Messenger Events ~~~~~~~~~~~~~~~~ From feb165e67b54d3f46adce3cc7915afb7a5b835cc Mon Sep 17 00:00:00 2001 From: wkania Date: Sun, 14 Feb 2021 10:18:19 +0100 Subject: [PATCH 0780/1519] [Validator] Use import instead of FQCN --- reference/constraints/Type.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/reference/constraints/Type.rst b/reference/constraints/Type.rst index 61189e7f989..a8920e655dd 100644 --- a/reference/constraints/Type.rst +++ b/reference/constraints/Type.rst @@ -64,11 +64,12 @@ This will check if ``id`` is an instance of ``Ramsey\Uuid\UuidInterface``, // src/Entity/Author.php namespace App\Entity; + use Ramsey\Uuid\UuidInterface; use Symfony\Component\Validator\Constraints as Assert; class Author { - #[Assert\Type('Ramsey\Uuid\UuidInterface')] + #[Assert\Type(UuidInterface::class)] protected $id; #[Assert\Type('string')] From d9b0a1dc6f7b1bb1cd9d5ef6939b5cc17ebec660 Mon Sep 17 00:00:00 2001 From: wkania Date: Sun, 14 Feb 2021 11:06:38 +0100 Subject: [PATCH 0781/1519] [Validator] Add PHP Attributes example to Compound --- reference/constraints/Compound.rst | 90 +++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 19 deletions(-) diff --git a/reference/constraints/Compound.rst b/reference/constraints/Compound.rst index 6e0ab5db139..a43899e7c24 100644 --- a/reference/constraints/Compound.rst +++ b/reference/constraints/Compound.rst @@ -23,27 +23,66 @@ Basic Usage Suppose that you have different places where a user password must be validated, you can create your own named set or requirements to be reused consistently everywhere:: - // src/Validator/Constraints/PasswordRequirements.php - namespace App\Validator\Constraints; - - use Symfony\Component\Validator\Constraints\Compound; - use Symfony\Component\Validator\Constraints as Assert; - - /** - * @Annotation - */ - class PasswordRequirements extends Compound - { - protected function getConstraints(array $options): array +.. configuration-block:: + + .. code-block:: php-annotations + + // src/Validator/Constraints/PasswordRequirements.php + namespace App\Validator\Constraints; + + use Symfony\Component\Validator\Constraints\Compound; + use Symfony\Component\Validator\Constraints as Assert; + + /** + * @Annotation + */ + class PasswordRequirements extends Compound { - return [ - new Assert\NotBlank(), - new Assert\Type('string'), - new Assert\Length(['min' => 12]), - new Assert\NotCompromisedPassword(), - ]; + protected function getConstraints(array $options): array + { + return [ + new Assert\NotBlank(), + new Assert\Type('string'), + new Assert\Length(['min' => 12]), + new Assert\NotCompromisedPassword(), + ]; + } } - } + + .. code-block:: php-attributes + + // src/Validator/Constraints/PasswordRequirements.php + namespace App\Validator\Constraints; + + use Symfony\Component\Validator\Constraints\Compound; + use Symfony\Component\Validator\Constraints as Assert; + + #[\Attribute] + class PasswordRequirements extends Compound + { + protected function getConstraints(array $options): array + { + return [ + new Assert\NotBlank(), + new Assert\Type('string'), + new Assert\Length(['min' => 12]), + new Assert\NotCompromisedPassword(), + ]; + } + } + +.. versionadded:: 5.2 + + The ability to use PHP attributes to configure constraints was introduced in + Symfony 5.2. Prior to this, Doctrine Annotations were the only way to + annotate constraints. + +.. note:: + + The ``@Annotation`` or ``#[\Attribute]`` annotation is necessary for this new constraint in + order to make it available for use in classes via annotations. + Options for your constraint are represented as public properties on the + constraint class. You can now use it anywhere you need it: @@ -64,6 +103,19 @@ You can now use it anywhere you need it: public $password; } + .. code-block:: php-attributes + + // src/User/RegisterUser.php + namespace App\User; + + use App\Validator\Constraints as AcmeAssert; + + class RegisterUser + { + #[AcmeAssert\PasswordRequirements] + public $password; + } + .. code-block:: yaml # config/validator/validation.yaml From 1a71a9c7f20a18ff78293c947a877b48874f027a Mon Sep 17 00:00:00 2001 From: wkania Date: Sun, 14 Feb 2021 11:13:43 +0100 Subject: [PATCH 0782/1519] [Validator] Add PHP Attribute as an annotation option in the description --- validation/custom_constraint.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validation/custom_constraint.rst b/validation/custom_constraint.rst index 8aaca8eb96a..d0d1c27d6f4 100644 --- a/validation/custom_constraint.rst +++ b/validation/custom_constraint.rst @@ -52,7 +52,7 @@ First you need to create a Constraint class and extend :class:`Symfony\\Componen .. note:: - The ``@Annotation`` annotation is necessary for this new constraint in + The ``@Annotation`` or ``#[\Attribute]`` annotation is necessary for this new constraint in order to make it available for use in classes via annotations. Options for your constraint are represented as public properties on the constraint class. From 4a3a9875df8846279ff62157f0182dad4d639a7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Sun, 14 Feb 2021 15:27:24 +0100 Subject: [PATCH 0783/1519] Update documentation for deprecated "session.storage" service --- reference/configuration/framework.rst | 21 ++++++++----- session.rst | 44 +++++++++++++++++++-------- session/php_bridge.rst | 10 +++--- 3 files changed, 49 insertions(+), 26 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index d3baf76260a..b13f9f870f7 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -269,7 +269,7 @@ Configuration * `save_path`_ * `sid_length`_ * `sid_bits_per_character`_ - * `storage_id`_ + * `storage_factory_id`_ * `use_cookies`_ * `test`_ @@ -1443,19 +1443,24 @@ errors. session ~~~~~~~ -storage_id -.......... +storage_factory_id +.................. -**type**: ``string`` **default**: ``'session.storage.native'`` +**type**: ``string`` **default**: ``'session.storage.factory.native'`` -The service ID used for storing the session. The ``session.storage`` service -alias will be set to this service. The class has to implement -:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorageInterface`. +The service ID used for creatig the ``SessionStorageInterface`` that will store +the session. The ``session.storage.factory`` service alias will be set to this +service. The class has to implement +:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorageFactoryInterface`. To see a list of all available storages, run: .. code-block:: terminal - $ php bin/console debug:container session.storage. + $ php bin/console debug:container session.storage.factory. + +.. versionadded:: 5.3 + + The ``storage_factory_id`` option was introduced in Symfony 5.3. .. _config-framework-session-handler-id: diff --git a/session.rst b/session.rst index 2727c3d617d..5a3fb69c09b 100644 --- a/session.rst +++ b/session.rst @@ -185,33 +185,51 @@ your ``Session`` object with the default ``AttributeBag`` by the ``NamespacedAtt .. code-block:: yaml # config/services.yaml - session_listener: + session.factory: autoconfigure: true - class: App\EventListener\SessionListener + class: App\Session\SessionFactory arguments: - - !service_locator - logger: '@?logger' - session_collector: '@?data_collector.request.session_collector' - session_storage: '@session.storage' - session_attributes: '@session.namespacedattributebag' - - '%kernel.debug%' + - '@request_stack' + - '@session.storage.factory' + - ['@session_listener', 'onSessionUsage'] + - '@session.namespacedattributebag' session.namespacedattributebag: class: Symfony\Component\HttpFoundation\Session\Attribute\NamespacedAttributeBag .. code-block:: php - namespace App\EventListener; + namespace App\Session; + use Symfony\Component\HttpFoundation\RequestStack; + use Symfony\Component\HttpFoundation\Session\Attribute\NamespacedAttributeBag; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Session\SessionInterface; - use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener; + use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageFactoryInterface; - class SessionListener extends AbstractSessionListener + class SessionFactory { - protected function getSession(): ?SessionInterface + private $requestStack; + private $storageFactory; + private $usageReporter; + private $sessionAttributes; + + public function __construct(RequestStack $requestStack, SessionStorageFactoryInterface $storageFactory, callable $usageReporter, NamespacedAttributeBag $sessionAttributes) + { + $this->requestStack = $requestStack; + $this->storageFactory = $storageFactory; + $this->usageReporter = $usageReporter; + $this->sessionAttributes = $sessionAttributes; + } + + public function createSession(): SessionInterface { - return new Session($this->container->get('session_storage'), $this->container->get('session_attributes')); + return new Session( + $this->storageFactory->createStorage($this->requestStack->getMasterRequest()), + $this->sessionAttributes, + null, + $this->usageReporter + ); } } diff --git a/session/php_bridge.rst b/session/php_bridge.rst index 42c8644e2a7..ba7fc53d41a 100644 --- a/session/php_bridge.rst +++ b/session/php_bridge.rst @@ -18,7 +18,7 @@ for the ``handler_id``: # config/packages/framework.yaml framework: session: - storage_id: session.storage.php_bridge + storage_factory_id: session.storage.factory.php_bridge handler_id: ~ .. code-block:: xml @@ -32,7 +32,7 @@ for the ``handler_id``: https://symfony.com/schema/dic/services/services-1.0.xsd"> - @@ -43,7 +43,7 @@ for the ``handler_id``: // config/packages/framework.php $container->loadFromExtension('framework', [ 'session' => [ - 'storage_id' => 'session.storage.php_bridge', + 'storage_factory_id' => 'session.storage.factory.php_bridge', 'handler_id' => null, ], ]); @@ -60,7 +60,7 @@ the example below: # config/packages/framework.yaml framework: session: - storage_id: session.storage.php_bridge + storage_factory_id: session.storage.factory.php_bridge handler_id: session.handler.native_file .. code-block:: xml @@ -85,7 +85,7 @@ the example below: // config/packages/framework.php $container->loadFromExtension('framework', [ 'session' => [ - 'storage_id' => 'session.storage.php_bridge', + 'storage_factory_id' => 'session.storage.factory.php_bridge', 'handler_id' => 'session.storage.native_file', ], ]); From 3ff812d799a3abdfc64f72956fe0fa0bd2c955fd Mon Sep 17 00:00:00 2001 From: Beno!t POLASZEK Date: Sun, 14 Feb 2021 10:42:34 +0100 Subject: [PATCH 0784/1519] [DependencyInjection] Negated (not:) env var processor --- configuration/env_var_processors.rst | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/configuration/env_var_processors.rst b/configuration/env_var_processors.rst index 407b5137fbc..2b42559911f 100644 --- a/configuration/env_var_processors.rst +++ b/configuration/env_var_processors.rst @@ -136,6 +136,46 @@ Symfony provides the following env var processors: 'http_method_override' => '%env(bool:HTTP_METHOD_OVERRIDE)%', ]); +``env(not:FOO)`` + + .. versionadded:: 5.3 + + The ``not:`` env var processor was introduced in Symfony 5.3. + + Casts ``FOO`` to a bool (just as ``env(bool:...)`` does) except it returns the inverted value + (falsy values are returned as ``true``, truthy values are returned as ``false``): + + .. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + parameters: + safe_for_production: '%env(not:APP_DEBUG)%' + + .. code-block:: xml + + + + + + + %env(not:APP_DEBUG)% + + + + + .. code-block:: php + + // config/services.php + $container->setParameter('safe_for_production', '%env(not:APP_DEBUG)%'); + ``env(int:FOO)`` Casts ``FOO`` to an int. From 7512515581be517ef92af7198eecedfea440242f Mon Sep 17 00:00:00 2001 From: Timo Bakx Date: Sun, 14 Feb 2021 17:07:14 +0100 Subject: [PATCH 0785/1519] [Security] Added debug:firewall command --- reference/configuration/security.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index d4a37758798..3c7980c153f 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -472,6 +472,26 @@ depend on the authentication mechanism, which can be any of these: http_digest: # ... +You can view actual information about the firewalls in your application with +the ``debug:firewall`` command: + +.. code-block:: terminal + + # displays a list of firewalls currently configured for your application + $ php bin/console debug:firewall + + # displays the details of a specific firewall + $ php bin/console debug:firewall main + + # displays the details of a specific firewall, including detailed information + # about the event listeners for the firewall + $ php bin/console debug:firewall main --include-listeners + +.. versionadded:: 5.3 + + The ``debug:firewall`` command was introduced in Symfony 5.3. + + .. _reference-security-firewall-form-login: ``form_login`` Authentication From 8a614ebc3df768f427f3e514488256172dc67b86 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 15 Feb 2021 09:13:56 +0100 Subject: [PATCH 0786/1519] Minor reword --- validation/custom_constraint.rst | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/validation/custom_constraint.rst b/validation/custom_constraint.rst index d0d1c27d6f4..5f85cb9092e 100644 --- a/validation/custom_constraint.rst +++ b/validation/custom_constraint.rst @@ -44,19 +44,16 @@ First you need to create a Constraint class and extend :class:`Symfony\\Componen public $message = 'The string "{{ string }}" contains an illegal character: it can only contain letters or numbers.'; } +Add ``@Annotation`` or ``#[\Attribute]`` to the constraint class if you want to +use it as an annotation/attribute in other classes. If the constraint has +configuration options, define them as public properties on the constraint class. + .. versionadded:: 5.2 The ability to use PHP attributes to configure constraints was introduced in Symfony 5.2. Prior to this, Doctrine Annotations were the only way to annotate constraints. -.. note:: - - The ``@Annotation`` or ``#[\Attribute]`` annotation is necessary for this new constraint in - order to make it available for use in classes via annotations. - Options for your constraint are represented as public properties on the - constraint class. - Creating the Validator itself ----------------------------- From c2a3742020fc3e683f108dcd09722bdaafb781c9 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 15 Feb 2021 09:43:41 +0100 Subject: [PATCH 0787/1519] Tweak --- reference/configuration/framework.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index b13f9f870f7..5c0989c8afc 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1448,9 +1448,9 @@ storage_factory_id **type**: ``string`` **default**: ``'session.storage.factory.native'`` -The service ID used for creatig the ``SessionStorageInterface`` that will store -the session. The ``session.storage.factory`` service alias will be set to this -service. The class has to implement +The service ID used for creating the ``SessionStorageInterface`` that stores +the session. This service is available in the Symfony application via the +``session.storage.factory`` service alias. The class has to implement :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorageFactoryInterface`. To see a list of all available storages, run: From d6a73143447ae1f5446d3d24e814f3dbcc0191d8 Mon Sep 17 00:00:00 2001 From: Sebastian Paczkowski <74934099+sebpacz@users.noreply.github.com> Date: Mon, 15 Feb 2021 07:10:34 +0100 Subject: [PATCH 0788/1519] [Messenger] Remove duplicated Redis transport requirements The Redis transport requirements has been presented twice. I mean the following sentences: "This transport requires the Redis PHP extension (>=4.3) and a running Redis server (^5.0)." and "To use the Redis transport, you will need the Redis PHP extension (>=4.3) and a running Redis server (^5.0).". --- messenger.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/messenger.rst b/messenger.rst index c2773c0c674..19736f3df4b 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1164,9 +1164,6 @@ The Redis transport DSN may looks like this: The Unix socket DSN was introduced in Symfony 5.1. -To use the Redis transport, you will need the Redis PHP extension (>=4.3) and -a running Redis server (^5.0). - A number of options can be configured via the DSN or via the ``options`` key under the transport in ``messenger.yaml``: From d101f1ce537efcb613f019cbddba4ef5e148fd0a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 15 Feb 2021 09:48:24 +0100 Subject: [PATCH 0789/1519] Added a previous reference --- reference/configuration/framework.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 5c0989c8afc..d9772a772cc 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1443,6 +1443,8 @@ errors. session ~~~~~~~ +.. _storage_id: + storage_factory_id .................. From 915b0d57ae5a1fa0c7c8f8cd047824e6b2160247 Mon Sep 17 00:00:00 2001 From: Nicolas Hart Date: Mon, 15 Feb 2021 12:08:27 +0100 Subject: [PATCH 0790/1519] [Encore] fix typo fronts instead of fonts --- frontend/encore/url-loader.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/encore/url-loader.rst b/frontend/encore/url-loader.rst index 9567960c99d..ff8be75aedc 100644 --- a/frontend/encore/url-loader.rst +++ b/frontend/encore/url-loader.rst @@ -1,4 +1,4 @@ -Inlining Images & Fronts in CSS +Inlining Images & Fonts in CSS =============================== A simple technique to improve the performance of web applications is to reduce From 77744242d2ac155c265ad2bc785c31adfb5819cc Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 15 Feb 2021 12:28:58 +0100 Subject: [PATCH 0791/1519] Fix length of underline --- frontend/encore/url-loader.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/encore/url-loader.rst b/frontend/encore/url-loader.rst index ff8be75aedc..5e89234f295 100644 --- a/frontend/encore/url-loader.rst +++ b/frontend/encore/url-loader.rst @@ -1,5 +1,5 @@ Inlining Images & Fonts in CSS -=============================== +============================== A simple technique to improve the performance of web applications is to reduce the number of HTTP requests inlining small files as base64 encoded URLs in the From fa054e6fb06380a198f9301272797bb273df154b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Sat, 13 Feb 2021 16:26:35 +0100 Subject: [PATCH 0792/1519] [Doctrine] Add documentation about doctrine.event_subscriber priority --- doctrine/events.rst | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/doctrine/events.rst b/doctrine/events.rst index 3eea84aff4f..16c51734411 100644 --- a/doctrine/events.rst +++ b/doctrine/events.rst @@ -166,7 +166,7 @@ with the ``doctrine.event_listener`` tag: # this is the only required option for the lifecycle listener tag event: 'postPersist' - # listeners can define their priority in case multiple listeners are associated + # listeners can define their priority in case multiple subscribers or listeners are associated # to the same event (default priority = 0; higher numbers = listener is run earlier) priority: 500 @@ -184,7 +184,7 @@ with the ``doctrine.event_listener`` tag: @@ -213,7 +213,7 @@ with the ``doctrine.event_listener`` tag: // this is the only required option for the lifecycle listener tag 'event' => 'postPersist', - // listeners can define their priority in case multiple listeners are associated + // listeners can define their priority in case multiple subscribers or listeners are associated // to the same event (default priority = 0; higher numbers = listener is run earlier) 'priority' => 500, @@ -428,7 +428,14 @@ with the ``doctrine.event_subscriber`` tag: App\EventListener\DatabaseActivitySubscriber: tags: - - { name: 'doctrine.event_subscriber' } + - name: 'doctrine.event_subscriber' + + # subscribers can define their priority in case multiple subscribers or listeners are associated + # to the same event (default priority = 0; higher numbers = listener is run earlier) + priority: 500 + + # you can also restrict listeners to a specific Doctrine connection + connection: 'default' .. code-block:: xml @@ -439,8 +446,15 @@ with the ``doctrine.event_subscriber`` tag: + - + + + @@ -456,7 +470,14 @@ with the ``doctrine.event_subscriber`` tag: $services = $configurator->services(); $services->set(DatabaseActivitySubscriber::class) - ->tag('doctrine.event_subscriber') + ->tag('doctrine.event_subscriber'[ + // subscribers can define their priority in case multiple subscribers or listeners are associated + // to the same event (default priority = 0; higher numbers = listener is run earlier) + 'priority' => 500, + + # you can also restrict listeners to a specific Doctrine connection + 'connection' => 'default', + ]) ; }; @@ -505,6 +526,10 @@ can do it in the service configuration: ; }; +.. versionadded:: 5.3 + + Handling priority for subscribers alongside listeners has been introduced in Symfony 5.3. + .. tip:: Symfony loads (and instantiates) Doctrine subscribers whenever the From 2c082536f083677436f835f675d40f1cc898736d Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 15 Feb 2021 13:10:56 +0100 Subject: [PATCH 0793/1519] Tweak --- doctrine/events.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doctrine/events.rst b/doctrine/events.rst index 16c51734411..bce3b6873e9 100644 --- a/doctrine/events.rst +++ b/doctrine/events.rst @@ -528,7 +528,7 @@ can do it in the service configuration: .. versionadded:: 5.3 - Handling priority for subscribers alongside listeners has been introduced in Symfony 5.3. + Subscriber priority was introduced in Symfony 5.3. .. tip:: From b920cfd7cd37500b2733b6754fc26e6dc94c7ce2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 16 Feb 2021 15:18:31 +0100 Subject: [PATCH 0794/1519] Tweak --- reference/constraints/Compound.rst | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/reference/constraints/Compound.rst b/reference/constraints/Compound.rst index a43899e7c24..53ce70c6df2 100644 --- a/reference/constraints/Compound.rst +++ b/reference/constraints/Compound.rst @@ -71,19 +71,16 @@ you can create your own named set or requirements to be reused consistently ever } } +Add ``@Annotation`` or ``#[\Attribute]`` to the constraint class if you want to +use it as an annotation/attribute in other classes. If the constraint has +configuration options, define them as public properties on the constraint class. + .. versionadded:: 5.2 The ability to use PHP attributes to configure constraints was introduced in Symfony 5.2. Prior to this, Doctrine Annotations were the only way to annotate constraints. -.. note:: - - The ``@Annotation`` or ``#[\Attribute]`` annotation is necessary for this new constraint in - order to make it available for use in classes via annotations. - Options for your constraint are represented as public properties on the - constraint class. - You can now use it anywhere you need it: .. configuration-block:: From 294972523d69eeb78e89ba96b579f9ce2652de1e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 16 Feb 2021 17:17:02 +0100 Subject: [PATCH 0795/1519] Reword --- messenger.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/messenger.rst b/messenger.rst index b8819c33c4a..17f894fd0e5 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1981,12 +1981,12 @@ Other Middlewares .. versionadded:: 5.3 - The ``router_context`` middleware were introduced in Symfony 5.3. + The ``router_context`` middleware was introduced in Symfony 5.3. -When the consumer needs to build an absolute URL, for instance: rendering a -template with links, it needs the initial's request context in order to -retrieves the domain and information needed to build the URL. This can be -achieved by declaring the ``router_context`` middleware in the bus. +Add the ``router_context`` middleware if you need to generate absolute URLs in +the consumer (e.g. render a template with links). This middleware stores the +original request context (i.e. the host, the HTTP port, etc.) which is needed +when building absolute URLs. .. configuration-block:: From 462f27fcedade2bfc6b2542d70b48be6ee383517 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 17 Feb 2021 09:05:23 +0100 Subject: [PATCH 0796/1519] Minor fix --- messenger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index 2cd18d823bd..f3610db7a00 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1324,7 +1324,7 @@ The SQS transport DSN may looks like this: .. code-block:: env # .env - MESSENGER_TRANSPORT_DSN=https://sqs.eu-west-3.amazonaws.com/123456789012/messages?access_key= AKIAIOSFODNN7EXAMPLE&secret_key=j17M97ffSVoKI0briFoo9a + MESSENGER_TRANSPORT_DSN=https://sqs.eu-west-3.amazonaws.com/123456789012/messages?access_key=AKIAIOSFODNN7EXAMPLE&secret_key=j17M97ffSVoKI0briFoo9a MESSENGER_TRANSPORT_DSN=sqs://localhost:9494/messages?sslmode=disable .. note:: From dca6cf4a5aee042b33929f9fc1e9a50562d34191 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 17 Feb 2021 09:52:54 +0100 Subject: [PATCH 0797/1519] [Security] bcrypt is the new default hasher for native/auto --- best_practices.rst | 2 +- security.rst | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/best_practices.rst b/best_practices.rst index 5f137d492c1..be3486e355b 100644 --- a/best_practices.rst +++ b/best_practices.rst @@ -368,7 +368,7 @@ Use the ``auto`` Password Hasher The :ref:`auto password hasher ` automatically selects the best possible encoder/hasher depending on your PHP installation. -Currently, it tries to use ``sodium`` by default and falls back to ``bcrypt``. +Starting from Symfony 5.3, the default auto hasher is ``bcrypt``. Use Voters to Implement Fine-grained Security Restrictions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/security.rst b/security.rst index 3b9341a07d6..c91db7be29a 100644 --- a/security.rst +++ b/security.rst @@ -219,9 +219,8 @@ command will pre-configure this for you: encoders: # use your user class name here App\Entity\User: - # Use native password encoder - # This value auto-selects the best possible hashing algorithm - # (i.e. Sodium when available). + # Use native password encoder, which auto-selects the best + # possible hashing algorithm (starting from Symfony 5.3 this is "bcrypt") algorithm: auto .. code-block:: xml From 2de6e69f9d628cca316fa5549e4a50d51201dd84 Mon Sep 17 00:00:00 2001 From: Tamcy Date: Thu, 18 Feb 2021 13:29:18 +0800 Subject: [PATCH 0798/1519] Update the default `cookie_secure` value The default and special `cookie_secure` value should be `'auto'`, not `null`. --- reference/configuration/framework.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index d3baf76260a..2636bee4a2b 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1589,10 +1589,10 @@ The possible values for this option are: cookie_secure ............. -**type**: ``boolean`` or ``null`` **default**: ``null`` +**type**: ``boolean`` or ``'auto'`` **default**: ``'auto'`` This determines whether cookies should only be sent over secure connections. In -addition to ``true`` and ``false``, there's a special ``null`` value that +addition to ``true`` and ``false``, there's a special ``'auto'`` value that means ``true`` for HTTPS requests and ``false`` for HTTP requests. cookie_httponly From 564378a49437963665578bd389209d803f56213c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 18 Feb 2021 16:08:32 +0100 Subject: [PATCH 0799/1519] Removed an unnecessary versionadded directive --- bundles/best_practices.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/bundles/best_practices.rst b/bundles/best_practices.rst index 29d8008b896..bf0138ddec8 100644 --- a/bundles/best_practices.rst +++ b/bundles/best_practices.rst @@ -82,11 +82,6 @@ The following is the recommended directory structure of an AcmeBlogBundle: ├── LICENSE └── README.md -.. versionadded:: 4.4 - - This directory convention was introduced in Symfony 4.4 and can be used only - when requiring ``symfony/http-kernel`` 4.4 or superior. - This directory structure requires to configure the bundle path to its root directory as follows:: From fd8791b7b1e379118b5c7920dfbfa8ca7fb6dba2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 19 Feb 2021 17:31:22 +0100 Subject: [PATCH 0800/1519] Updated the example of PHP attributes --- reference/constraints/Type.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reference/constraints/Type.rst b/reference/constraints/Type.rst index c557c26fe7c..ab56be81276 100644 --- a/reference/constraints/Type.rst +++ b/reference/constraints/Type.rst @@ -64,13 +64,13 @@ This will check if ``emailAddress`` is an instance of ``Symfony\Component\Mime\A // src/Entity/Author.php namespace App\Entity; - use Ramsey\Uuid\UuidInterface; + use Symfony\Component\Mime\Address; use Symfony\Component\Validator\Constraints as Assert; class Author { - #[Assert\Type(UuidInterface::class)] - protected $id; + #[Assert\Type(Address::class)] + protected $emailAddress; #[Assert\Type('string')] protected $firstName; From f4dbec46fff2b37f062d0221bf05efd36e20b015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20TAMARELLE?= Date: Thu, 1 Oct 2020 01:28:00 +0200 Subject: [PATCH 0801/1519] [Framework] Add tag assets.package --- reference/dic_tags.rst | 52 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/reference/dic_tags.rst b/reference/dic_tags.rst index 0aca3c91777..2e4c7e5b339 100644 --- a/reference/dic_tags.rst +++ b/reference/dic_tags.rst @@ -12,6 +12,7 @@ application there could be more tags available provided by third-party bundles: Tag Name Usage ======================================== ======================================================================== `auto_alias`_ Define aliases based on the value of container parameters +`assets.package`_ Add an asset package `console.command`_ Add a command `container.hot_path`_ Add to list of always needed services `container.no_preload`_ Remove a class from the list of classes preloaded by PHP @@ -50,6 +51,57 @@ Tag Name Usage `validator.initializer`_ Register a service that initializes objects before validation ======================================== ======================================================================== +assets.package +-------------- + +**Purpose**: Add an asset package to the application + +This is an alternative way to declare a package in :doc:`/components/asset`. + +The name of the package is set in this order: +* first, the `package` attribute of the tag +* then, the value returned by the static method `getDefaultPackageName()` if defined +* finally, the service name + +.. configuration-block:: + + .. code-block:: yaml + + services: + App\Assets\AvatarPackage: + tags: + - { name: assets.package, package: avatars } + + .. code-block:: xml + + + + + + + + + + + + .. code-block:: php + + use App\Assets\AvatarPackage; + + $container + ->register(AvatarPackage::class) + ->addTag('assets.package', ['package' => 'avatars']) + ; + +Now you can use the ``avatars`` package in your templates: + +.. code-block:: html+twig + + + auto_alias ---------- From 3799eb4872da9f0730fc827386558bce3178d0ab Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 19 Feb 2021 17:44:53 +0100 Subject: [PATCH 0802/1519] Tweaks --- components/asset.rst | 2 ++ reference/dic_tags.rst | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/components/asset.rst b/components/asset.rst index 48e51754449..5044ef2dab9 100644 --- a/components/asset.rst +++ b/components/asset.rst @@ -51,6 +51,8 @@ Installation Usage ----- +.. _asset-packages: + Asset Packages ~~~~~~~~~~~~~~ diff --git a/reference/dic_tags.rst b/reference/dic_tags.rst index 2e4c7e5b339..81a9cc93704 100644 --- a/reference/dic_tags.rst +++ b/reference/dic_tags.rst @@ -56,12 +56,16 @@ assets.package **Purpose**: Add an asset package to the application -This is an alternative way to declare a package in :doc:`/components/asset`. +.. versionadded:: 5.3 + The ``assets.package`` tag was introduced in Symfony 5.3. + +This is an alternative way to declare an :ref:`asset package `. The name of the package is set in this order: -* first, the `package` attribute of the tag -* then, the value returned by the static method `getDefaultPackageName()` if defined -* finally, the service name + +* first, the ``package`` attribute of the tag; +* then, the value returned by the static method ``getDefaultPackageName()`` if defined; +* finally, the service name. .. configuration-block:: From 6280192b77dab7650921154c3d583d68b8a68fab Mon Sep 17 00:00:00 2001 From: wkania Date: Thu, 18 Feb 2021 21:17:26 +0100 Subject: [PATCH 0803/1519] [Form] Add PHP Attributes example to forms --- forms.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/forms.rst b/forms.rst index 42bdedc9658..e80ad65da71 100644 --- a/forms.rst +++ b/forms.rst @@ -507,6 +507,23 @@ object. protected $dueDate; } + .. code-block:: php-attributes + + // src/Entity/Task.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Task + { + #[Assert\NotBlank] + public $task; + + #[Assert\NotBlank] + #[Assert\Type(\DateTime::class)] + protected $dueDate; + } + .. code-block:: yaml # config/validator/validation.yaml From 2abb9aac37ef9db5ed95bfb112bbcfa960ac95ef Mon Sep 17 00:00:00 2001 From: Wojciech Kania Date: Sat, 20 Feb 2021 18:02:11 +0100 Subject: [PATCH 0804/1519] [Security] Add PHP Attribute example to controller --- security.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/security.rst b/security.rst index 3b9341a07d6..18d0344f42e 100644 --- a/security.rst +++ b/security.rst @@ -1089,6 +1089,24 @@ Next, you'll need to create a route for this URL (but not a controller): } } + .. code-block:: php-attributes + + // src/Controller/SecurityController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class SecurityController extends AbstractController + { + #[Route('/logout', name: 'app_logout', methods: ['GET'])] + public function logout() + { + // controller can be blank: it will never be executed! + throw new \Exception('Don\'t forget to activate logout in security.yaml'); + } + } + .. code-block:: yaml # config/routes.yaml From 832436bfc788fbb809a3d6c669dbbd9eec94a4ba Mon Sep 17 00:00:00 2001 From: Wojciech Kania Date: Sat, 20 Feb 2021 18:41:02 +0100 Subject: [PATCH 0805/1519] [Routing] Add PHP Attribute route example to the controller --- controller/service.rst | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/controller/service.rst b/controller/service.rst index f8048e09def..2c592518608 100644 --- a/controller/service.rst +++ b/controller/service.rst @@ -41,6 +41,22 @@ a service like: ``App\Controller\HelloController::index``: } } + .. code-block:: php-attributes + + // src/Controller/HelloController.php + namespace App\Controller; + + use Symfony\Component\Routing\Annotation\Route; + + class HelloController + { + #[Route('/hello', name: 'hello', methods: ['GET'])] + public function index() + { + // ... + } + } + .. code-block:: yaml # config/routes.yaml @@ -105,6 +121,23 @@ which is a common practice when following the `ADR pattern`_ } } + .. code-block:: php-attributes + + // src/Controller/Hello.php + namespace App\Controller; + + use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\Routing\Annotation\Route; + + #[Route('/hello/{name}', name: 'hello')] + class Hello + { + public function __invoke($name = 'World') + { + return new Response(sprintf('Hello %s!', $name)); + } + } + .. code-block:: yaml # config/routes.yaml From fd02abef74ebdcbc2a94f6212dda8e9908ad554c Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 21 Feb 2021 18:24:01 +0100 Subject: [PATCH 0806/1519] remove unsupported trusted header config values --- deployment/proxies.rst | 9 --------- 1 file changed, 9 deletions(-) diff --git a/deployment/proxies.rst b/deployment/proxies.rst index 9b6821e3f79..5f24a69a418 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -37,9 +37,6 @@ and what headers your reverse proxy uses to send information: trusted_headers: ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port'] // or, if your proxy instead uses the "Forwarded" header trusted_headers: ['forwarded'] - // or, if you're using a wellknown proxy - trusted_headers: [!php/const Symfony\\Component\\HttpFoundation\\Request::HEADER_X_FORWARDED_AWS_ELB] - trusted_headers: [!php/const Symfony\\Component\\HttpFoundation\\Request::HEADER_X_FORWARDED_TRAEFIK] .. code-block:: xml @@ -80,9 +77,6 @@ and what headers your reverse proxy uses to send information: 'trusted_headers' => ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port'], // or, if your proxy instead uses the "Forwarded" header 'trusted_headers' => ['forwarded'], - // or, if you're using a wellknown proxy - 'trusted_headers' => [Request::HEADER_X_FORWARDED_AWS_ELB], - 'trusted_headers' => [Request::HEADER_X_FORWARDED_TRAEFIK], ]); .. deprecated:: 5.2 @@ -135,9 +129,6 @@ In this case, you'll need to - *very carefully* - trust *all* proxies. // run time by $_SERVER['REMOTE_ADDR']) trusted_proxies: '127.0.0.1,REMOTE_ADDR' - // if you're using ELB, otherwise use another Request::HEADER-* constant - trusted_headers: [!php/const Symfony\\Component\\HttpFoundation\\Request::HEADER_X_FORWARDED_AWS_ELB, '!x-forwarded-host', '!x-forwarded-prefix'] - That's it! It's critical that you prevent traffic from all non-trusted sources. If you allow outside traffic, they could "spoof" their true IP address and other information. From 6f8ff2502089924952031b58307335dc77bda687 Mon Sep 17 00:00:00 2001 From: Wojciech Kania Date: Mon, 22 Feb 2021 20:30:14 +0100 Subject: [PATCH 0807/1519] [Validator] Add PHP Attributes to severity and translation examples --- validation/severity.rst | 19 +++++++++++++++++++ validation/translations.rst | 13 +++++++++++++ 2 files changed, 32 insertions(+) diff --git a/validation/severity.rst b/validation/severity.rst index 7a8c22298fd..7df7746c7f2 100644 --- a/validation/severity.rst +++ b/validation/severity.rst @@ -50,6 +50,25 @@ Use the ``payload`` option to configure the error level for each constraint: protected $bankAccountNumber; } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class User + { + #[Assert\NotBlank(payload: ['severity' => 'error'])] + protected $username; + + #[Assert\NotBlank(payload: ['severity' => 'error'])] + protected $password; + + #[Assert\Iban(payload: ['severity' => 'warning'])] + protected $bankAccountNumber; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/validation/translations.rst b/validation/translations.rst index 5c22f9362c3..c251c986b3b 100644 --- a/validation/translations.rst +++ b/validation/translations.rst @@ -40,6 +40,19 @@ property is not empty, add the following: public $name; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\NotBlank(message: 'author.name.not_blank')] + public $name; + } + .. code-block:: yaml # config/validator/validation.yaml From dde96698a2fc6307c6eb02557476d3d8713049ba Mon Sep 17 00:00:00 2001 From: Kolja Zuelsdorf Date: Tue, 23 Feb 2021 21:59:11 +0100 Subject: [PATCH 0808/1519] Fixed small typo --- testing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing.rst b/testing.rst index 8fd666c8f96..8cc56e61b20 100644 --- a/testing.rst +++ b/testing.rst @@ -607,7 +607,7 @@ submitting a login form - make a test very slow. For this reason, Symfony provides a ``loginUser()`` method to simulate logging in in your functional tests. -Instead of login in with real users, it's recommended to create a user only for +Instead of logging in with real users, it's recommended to create a user only for tests. You can do that with Doctrine :ref:`data fixtures `, to load the testing users only in the test database. From 1859757418b7731cecc099fa9518e32008623370 Mon Sep 17 00:00:00 2001 From: Pierre Boissinot Date: Wed, 24 Feb 2021 21:45:59 +0100 Subject: [PATCH 0809/1519] doc(mailer): add Sendinblue to transports supporting tags and metadata --- mailer.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/mailer.rst b/mailer.rst index ea83e0a4f46..08a10c59e03 100644 --- a/mailer.rst +++ b/mailer.rst @@ -1209,6 +1209,7 @@ The following transports currently support tags and metadata: * Postmark * Mailgun * MailChimp +* Sendinblue Development & Debugging ----------------------- From 126cf24a33a440396f8e7d7ffb961131272add0b Mon Sep 17 00:00:00 2001 From: Nyholm Date: Tue, 2 Mar 2021 20:05:19 +0100 Subject: [PATCH 0810/1519] [Cache] Adding about marshallers --- components/cache.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/components/cache.rst b/components/cache.rst index a620206682f..35002831be8 100644 --- a/components/cache.rst +++ b/components/cache.rst @@ -192,6 +192,25 @@ Now you can create, retrieve, update and delete items using this cache pool:: For a list of all of the supported adapters, see :doc:`/components/cache/cache_pools`. +Serializing Data +---------------- + +When an item is stored in the cache, it is serialised to a string. It is a class +implementing :class:`Symfony\\Component\\Cache\\Marshaller\\MarshallerInterface` +that is responsible for serializing and unserializing. Or to be technically correct: +to ``marshall()`` and to ``unmarshall()``. + +The :class:`Symfony\\Component\\Cache\\Marshaller\\DefaultMarshaller` is using PHP's +``serialize()`` or ``igbinary_serialize()`` if the Igbinary extension is installed. +There are other marshallers that will encrypt or compress the data before storing it:: + + use Symfony\Component\Cache\Adapter\RedisAdapter; + use Symfony\Component\Cache\DefaultMarshaller; + use Symfony\Component\Cache\DeflateMarshaller; + + $marshaller = new DeflateMarshaller(new DefaultMarshaller()); + $cache = new RedisAdapter(new \Redis(), 'namespace', 0, $marshaller); + Advanced Usage -------------- From 90ce1b2040cd92c02bade2adf1a8edbaf923e3d3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 5 Mar 2021 13:09:24 +0100 Subject: [PATCH 0811/1519] Updates --- components/cache.rst | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/components/cache.rst b/components/cache.rst index 35002831be8..16c1f8a7691 100644 --- a/components/cache.rst +++ b/components/cache.rst @@ -192,17 +192,26 @@ Now you can create, retrieve, update and delete items using this cache pool:: For a list of all of the supported adapters, see :doc:`/components/cache/cache_pools`. -Serializing Data ----------------- +Marshalling (Serializing) Data +------------------------------ -When an item is stored in the cache, it is serialised to a string. It is a class -implementing :class:`Symfony\\Component\\Cache\\Marshaller\\MarshallerInterface` -that is responsible for serializing and unserializing. Or to be technically correct: -to ``marshall()`` and to ``unmarshall()``. +.. note:: + + `Marshalling`_ and `serializing`_ are similar concepts. Serializing is the + process of translating an object state into a format that can be stored + (e.g. in a file). Marshalling is the process of translating both the object + state and its codebase into a format that can be stored or transmitted. + + Unmarshalling an object produces a copy of the original object, possibly by + automatically loading the class definitions of the object. + +Symfony uses *marshallers* (classes which implement +:class:`Symfony\\Component\\Cache\\Marshaller\\MarshallerInterface`) to process +the cache items before storing them. -The :class:`Symfony\\Component\\Cache\\Marshaller\\DefaultMarshaller` is using PHP's -``serialize()`` or ``igbinary_serialize()`` if the Igbinary extension is installed. -There are other marshallers that will encrypt or compress the data before storing it:: +The :class:`Symfony\\Component\\Cache\\Marshaller\\DefaultMarshaller` uses PHP's +``serialize()`` or ``igbinary_serialize()`` if the `Igbinary extension`_ is installed. +There are other *marshallers* that can encrypt or compress the data before storing it:: use Symfony\Component\Cache\Adapter\RedisAdapter; use Symfony\Component\Cache\DefaultMarshaller; @@ -224,3 +233,6 @@ Advanced Usage .. _`Cache Contracts`: https://github.com/symfony/contracts/blob/master/Cache/CacheInterface.php .. _`Stampede prevention`: https://en.wikipedia.org/wiki/Cache_stampede .. _Probabilistic early expiration: https://en.wikipedia.org/wiki/Cache_stampede#Probabilistic_early_expiration +.. _`Marshalling`: https://en.wikipedia.org/wiki/Marshalling_(computer_science) +.. _`serializing`: https://en.wikipedia.org/wiki/Serialization +.. _`Igbinary extension`: https://github.com/igbinary/igbinary From 8a2e8d77bc4442e02dad895e1b63226968f586cf Mon Sep 17 00:00:00 2001 From: Wojciech Kania Date: Sat, 6 Mar 2021 09:47:47 +0100 Subject: [PATCH 0812/1519] [Validator] Add PHP Attributes to validation groups --- validation/groups.rst | 21 +++++++++++ validation/sequence_provider.rst | 65 +++++++++++++++++++++++++++++++- 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/validation/groups.rst b/validation/groups.rst index 7681f583a08..70dcc975655 100644 --- a/validation/groups.rst +++ b/validation/groups.rst @@ -42,6 +42,27 @@ user registers and when a user updates their contact information later: private $city; } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Security\Core\User\UserInterface; + use Symfony\Component\Validator\Constraints as Assert; + + class User implements UserInterface + { + #[Assert\Email(groups: ['registration'])] + private $email; + + #[Assert\NotBlank(groups: ['registration'])] + #[Assert\Length(min: 7, groups: ['registration'])] + private $password; + + #[Assert\Length(min: 2)] + private $city; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/validation/sequence_provider.rst b/validation/sequence_provider.rst index 503c50f67e5..699711b661d 100644 --- a/validation/sequence_provider.rst +++ b/validation/sequence_provider.rst @@ -47,6 +47,33 @@ username and the password are different only if all other validation passes } } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Security\Core\User\UserInterface; + use Symfony\Component\Validator\Constraints as Assert; + + #[Assert\GroupSequence(['User', 'Strict'])] + class User implements UserInterface + { + #[Assert\NotBlank] + private $username; + + #[Assert\NotBlank] + private $password; + + #[Assert\IsTrue( + message: 'The password cannot match your username', + groups: ['Strict'], + )] + public function isPasswordSafe() + { + return ($this->username !== $this->password); + } + } + .. code-block:: yaml # config/validator/validation.yaml @@ -151,7 +178,7 @@ You can also define a group sequence in the ``validation_groups`` form option:: // src/Form/MyType.php namespace App\Form; - + use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Validator\Constraints\GroupSequence; @@ -204,6 +231,27 @@ entity and a new constraint group called ``Premium``: // ... } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class User + { + #[Assert\NotBlank] + private $name; + + #[Assert\CardScheme( + schemes: [Assert\CardScheme::VISA], + groups: ['Premium'], + )] + private $creditCard; + + // ... + } + .. code-block:: yaml # config/validator/validation.yaml @@ -263,7 +311,7 @@ entity and a new constraint group called ``Premium``: { $metadata->addPropertyConstraint('name', new Assert\NotBlank()); $metadata->addPropertyConstraint('creditCard', new Assert\CardScheme([ - 'schemes' => ['VISA'], + 'schemes' => [Assert\CardScheme::VISA], 'groups' => ['Premium'], ])); } @@ -319,6 +367,19 @@ provides a sequence of groups to be validated: // ... } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + // ... + + #[Assert\GroupSequenceProvider] + class User implements GroupSequenceProviderInterface + { + // ... + } + .. code-block:: yaml # config/validator/validation.yaml From 72fcddd507da0b2f21cfa384182273ccdcef152e Mon Sep 17 00:00:00 2001 From: Wojciech Kania Date: Sat, 6 Mar 2021 14:15:39 +0100 Subject: [PATCH 0813/1519] [Validator] Add PHP Attributes to validation page --- validation.rst | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/validation.rst b/validation.rst index b0b74525734..0ad5a3108ec 100644 --- a/validation.rst +++ b/validation.rst @@ -68,6 +68,20 @@ following: private $name; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + // ... + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\NotBlank] + private $name; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -351,6 +365,25 @@ literature genre mostly associated with the author, which can be set to either // ... } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + // ... + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Choice( + choices: ['fiction', 'non-fiction'], + message: 'Choose a valid genre.', + )] + private $genre; + + // ... + } + .. code-block:: yaml # config/validator/validation.yaml @@ -437,6 +470,22 @@ options can be specified in this way. // ... } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + // ... + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Choice(['fiction', 'non-fiction'])] + private $genre; + + // ... + } + .. code-block:: yaml # config/validator/validation.yaml @@ -559,6 +608,20 @@ class to have at least 3 characters. private $firstName; } + .. code-block:: php-attributes + + // src/Entity/Author.php + + // ... + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\NotBlank] + #[Assert\Length(min: 3)] + private $firstName; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -655,6 +718,23 @@ this method must return ``true``: } } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + // ... + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\IsTrue(message: 'The password cannot match your first name')] + public function isPasswordSafe() + { + // ... return true or false + } + } + .. code-block:: yaml # config/validator/validation.yaml From b5adc53d63bc0104ae25466c38aa4ea2be77ac3e Mon Sep 17 00:00:00 2001 From: Samuel NELA Date: Sat, 6 Mar 2021 23:40:02 +0100 Subject: [PATCH 0814/1519] [Uid] Fix typos --- components/uid.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index 366ad1bcec6..6a73666f511 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -186,7 +186,7 @@ of the UUID parameters:: { $qb = $this->createQueryBuilder('p') // ... - // add 'uuid' as the third argument to tell Doctrine that this is an UUID + // add 'uuid' as the third argument to tell Doctrine that this is a UUID ->setParameter('user', $user->getUuid(), 'uuid') // alternatively, you can convert it to a value compatible with @@ -333,7 +333,7 @@ of the ULID parameters:: { $qb = $this->createQueryBuilder('p') // ... - // add 'ulid' as the third argument to tell Doctrine that this is an ULID + // add 'ulid' as the third argument to tell Doctrine that this is a ULID ->setParameter('user', $user->getUlid(), 'ulid') // alternatively, you can convert it to a value compatible with From c5101c7d2b0ec56444bd35dd76c3019ab674fc5d Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 9 Mar 2021 11:09:09 +0100 Subject: [PATCH 0815/1519] [PropertyAccess] use bitwise instead of boolean flags --- components/property_access.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/property_access.rst b/components/property_access.rst index a1ae83ab406..fdb678c1c3e 100644 --- a/components/property_access.rst +++ b/components/property_access.rst @@ -435,7 +435,7 @@ Sometimes, adder and remover methods don't use the standard ``add`` or ``remove` $list = new PeopleList(); $reflectionExtractor = new ReflectionExtractor(null, null, ['join', 'leave']); - $propertyAccessor = new PropertyAccessor(false, false, null, true, $reflectionExtractor, $reflectionExtractor); + $propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, false, null, true, $reflectionExtractor, $reflectionExtractor); $propertyAccessor->setValue($person, 'peoples', ['kevin', 'wouter']); var_dump($person->getPeoples()); // ['kevin', 'wouter'] From a9cb63d242d7047c226cf2431ed1a407fbf84d0a Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 9 Mar 2021 11:03:50 +0100 Subject: [PATCH 0816/1519] =?UTF-8?q?[PropertyAccess]=C2=A0do=20not=20pass?= =?UTF-8?q?=20boolean=20constructor=20flags?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/property_access.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/property_access.rst b/components/property_access.rst index fdb678c1c3e..9d3f4e355fc 100644 --- a/components/property_access.rst +++ b/components/property_access.rst @@ -435,7 +435,7 @@ Sometimes, adder and remover methods don't use the standard ``add`` or ``remove` $list = new PeopleList(); $reflectionExtractor = new ReflectionExtractor(null, null, ['join', 'leave']); - $propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, false, null, true, $reflectionExtractor, $reflectionExtractor); + $propertyAccessor = new PropertyAccessor(PropertyAccessor::DISALLOW_MAGIC_METHODS, PropertyAccessor::THROW_ON_INVALID_PROPERTY_PATH, null, $reflectionExtractor, $reflectionExtractor); $propertyAccessor->setValue($person, 'peoples', ['kevin', 'wouter']); var_dump($person->getPeoples()); // ['kevin', 'wouter'] From 607eb2599d09cb3f34f98af79dbcc08ee000e3c1 Mon Sep 17 00:00:00 2001 From: Rob Meijer Date: Tue, 9 Mar 2021 19:44:35 +0000 Subject: [PATCH 0817/1519] [Rate Limiter] Typo in Rate Limiter Status example --- rate_limiter.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index 99617f20d59..6982f88cae4 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -293,7 +293,7 @@ the :class:`Symfony\\Component\\RateLimiter\\Reservation` object returned by the // ... - $reponse = new Response('...'); + $response = new Response('...'); $response->headers->add($headers); return $response; From 95ca723c985cb5db4e52a6b394aa7e0b818b1836 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 11 Mar 2021 13:12:02 +0100 Subject: [PATCH 0818/1519] Minor: Sort alphabetically --- mailer.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mailer.rst b/mailer.rst index 08a10c59e03..7cef0ee2668 100644 --- a/mailer.rst +++ b/mailer.rst @@ -1206,9 +1206,9 @@ If your transport does not support tags and metadata, they will be added as cust The following transports currently support tags and metadata: -* Postmark -* Mailgun * MailChimp +* Mailgun +* Postmark * Sendinblue Development & Debugging From 2d924e8363900bf0a2b0f6be2604696472e6db9f Mon Sep 17 00:00:00 2001 From: Thibault RICHARD Date: Sun, 28 Feb 2021 23:25:47 +0100 Subject: [PATCH 0819/1519] [Mailer] Configuration of the message_bus to use --- mailer.rst | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/mailer.rst b/mailer.rst index 9c9c1451add..39f2cb42081 100644 --- a/mailer.rst +++ b/mailer.rst @@ -1094,6 +1094,52 @@ you have a transport called ``async``, you can route the message there: Thanks to this, instead of being delivered immediately, messages will be sent to the transport to be handled later (see :ref:`messenger-worker`). +You can configure which bus is used to dispatch the message using the ``message_bus`` option. +You can also set this to ``false`` to call the Mailer transport directly and +disable asynchronous delivery. + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/mailer.yaml + framework: + mailer: + message_bus: app.another_bus + + .. code-block:: xml + + + + + + + + + + + + .. code-block:: php + + // config/packages/mailer.php + $container->loadFromExtension('framework', [ + 'mailer' => [ + 'message_bus' => 'app.another_bus', + ], + ]); + +.. versionadded:: 5.1 + + The `message_bus` option was introduced in Symfony 5.1. + Adding Tags and Metadata to Emails ---------------------------------- From 1b476a17e54a229bda2ade9732471aa2d1e78978 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 11 Mar 2021 14:06:48 +0100 Subject: [PATCH 0820/1519] minor --- mailer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mailer.rst b/mailer.rst index c25a4246eb1..8f98d9b766f 100644 --- a/mailer.rst +++ b/mailer.rst @@ -1218,7 +1218,7 @@ disable asynchronous delivery. .. versionadded:: 5.1 - The `message_bus` option was introduced in Symfony 5.1. + The ``message_bus`` option was introduced in Symfony 5.1. Adding Tags and Metadata to Emails ---------------------------------- From 068b20e5bb83ebd9f5c15cca2004ebe60db8c4bb Mon Sep 17 00:00:00 2001 From: Wojciech Kania Date: Sun, 14 Mar 2021 11:06:51 +0100 Subject: [PATCH 0821/1519] [Serializer] Add PHP Attributes to serializer examples --- components/serializer.rst | 84 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/components/serializer.rst b/components/serializer.rst index c484a9ed170..5f32da7c468 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -315,6 +315,26 @@ Then, create your groups definition: // ... } + .. code-block:: php-attributes + + namespace Acme; + + use Symfony\Component\Serializer\Annotation\Groups; + + class MyObj + { + #[Groups(['group1', 'group2'])] + public $foo; + + #[Groups(['group3'])] + public function getBar() // is* methods are also supported + { + return $this->bar; + } + + // ... + } + .. code-block:: yaml Acme\MyObj: @@ -437,6 +457,20 @@ Option 1: Using ``@Ignore`` Annotation public $bar; } + .. code-block:: php-attributes + + namespace App\Model; + + use Symfony\Component\Serializer\Annotation\Ignore; + + class MyClass + { + public $foo; + + #[Ignore] + public $bar; + } + .. code-block:: yaml App\Model\MyClass: @@ -658,6 +692,25 @@ defines a ``Person`` entity with a ``firstName`` property: // ... } + .. code-block:: php-attributes + + namespace App\Entity; + + use Symfony\Component\Serializer\Annotation\SerializedName; + + class Person + { + #[SerializedName('customer_name')] + private $firstName; + + public function __construct($firstName) + { + $this->firstName = $firstName; + } + + // ... + } + .. code-block:: yaml App\Entity\Person: @@ -1214,6 +1267,20 @@ Here, we set it to 2 for the ``$child`` property: // ... } + .. code-block:: php-attributes + + namespace Acme; + + use Symfony\Component\Serializer\Annotation\MaxDepth; + + class MyObj + { + #[MaxDepth(2)] + public $child; + + // ... + } + .. code-block:: yaml Acme\MyObj: @@ -1524,6 +1591,23 @@ and ``BitBucketCodeRepository`` classes: // ... } + .. code-block:: php-attributes + + namespace App; + + use App\BitBucketCodeRepository; + use App\GitHubCodeRepository; + use Symfony\Component\Serializer\Annotation\DiscriminatorMap; + + #[DiscriminatorMap(typeProperty: 'type', mapping: [ + 'github' => GitHubCodeRepository::class, + 'bitbucket' => BitBucketCodeRepository::class, + ])] + interface CodeRepository + { + // ... + } + .. code-block:: yaml App\CodeRepository: From 8c0f61ce423e02bd0f0cec10fdbf5fc8474f049b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sun, 14 Mar 2021 13:01:51 +0100 Subject: [PATCH 0822/1519] [Validator] Fixed a minor RST syntax issue --- reference/constraints/Compound.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/constraints/Compound.rst b/reference/constraints/Compound.rst index 53ce70c6df2..95d9ba10789 100644 --- a/reference/constraints/Compound.rst +++ b/reference/constraints/Compound.rst @@ -21,7 +21,7 @@ Basic Usage ----------- Suppose that you have different places where a user password must be validated, -you can create your own named set or requirements to be reused consistently everywhere:: +you can create your own named set or requirements to be reused consistently everywhere: .. configuration-block:: From c9cff9fa76541ca82a240048f3aae48e4c2d25fa Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 16 Mar 2021 09:27:56 +0100 Subject: [PATCH 0823/1519] Remove caution. refs #15106 --- mailer.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mailer.rst b/mailer.rst index bbb7ab9305c..8f98d9b766f 100644 --- a/mailer.rst +++ b/mailer.rst @@ -174,11 +174,6 @@ party provider: For example, the DSN ``ses+smtp://ABC1234:abc+12/345@default`` should be configured as ``ses+smtp://ABC1234:abc%2B12%2F345@default`` -.. caution:: - - Symfony 4.4 only supports Amazon SES signature version 3 which has been - deprecated. You need to use ``symfony/amazon-mailer`` 5.1 or newer. - .. note:: When using SMTP, the default timeout for sending a message before throwing an From 61dc76568fe769311e98b76df8682b190df34e41 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Wed, 17 Mar 2021 10:18:54 +0100 Subject: [PATCH 0824/1519] Use UserBadge in all passports --- security/experimental_authenticators.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index eb0ffa098e0..269aefe01a0 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -494,7 +494,7 @@ The following credential classes are supported by default: use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials; // ... - return new Passport($user, new PasswordCredentials($plaintextPassword)); + return new Passport(new UserBadge($email), new PasswordCredentials($plaintextPassword)); :class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Credentials\\CustomCredentials` Allows a custom closure to check credentials:: @@ -502,7 +502,7 @@ The following credential classes are supported by default: use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\CustomCredentials; // ... - return new Passport($user, new CustomCredentials( + return new Passport(new UserBadge($email), new CustomCredentials( // If this function returns anything else than `true`, the credentials // are marked as invalid. // The $credentials parameter is equal to the next argument of this class @@ -581,7 +581,7 @@ would initialize the passport like this:: // ... validate no parameter is empty return new Passport( - new UserBadge($user), + new UserBadge($email), new PasswordCredentials($password), [new CsrfTokenBadge('login', $csrfToken)] ); From 316da38f2444913392161afa202e95e5be3edca3 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 17 Mar 2021 11:33:49 +0100 Subject: [PATCH 0825/1519] Fix DSN --- mailer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mailer.rst b/mailer.rst index 8f98d9b766f..15c3d48ddcf 100644 --- a/mailer.rst +++ b/mailer.rst @@ -165,7 +165,7 @@ party provider: Mailjet mailjet+smtp://ACCESS_KEY:SECRET_KEY@default n/a mailjet+api://ACCESS_KEY:SECRET_KEY@default Postmark postmark+smtp://ID:ID@default n/a postmark+api://KEY@default Sendgrid sendgrid+smtp://apikey:KEY@default n/a sendgrid+api://KEY@default - Sendinblue sendinblue+smtp://apikey:USERNAME:PASSWORD@default n/a sendinblue+api://KEY@default + Sendinblue sendinblue+smtp://USERNAME:PASSWORD@default n/a sendinblue+api://KEY@default ==================== ==================================================== =========================================== ======================================== .. caution:: From b66dd5f27581c0cf7df1e66966b28c502f29eb51 Mon Sep 17 00:00:00 2001 From: cedric lombardot Date: Wed, 17 Mar 2021 16:51:14 +0100 Subject: [PATCH 0826/1519] Fix to use yaml syntax --- deployment/proxies.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deployment/proxies.rst b/deployment/proxies.rst index 5f24a69a418..a51aa1c8889 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -31,11 +31,11 @@ and what headers your reverse proxy uses to send information: # config/packages/framework.yaml framework: # ... - // the IP address (or range) of your proxy + # the IP address (or range) of your proxy trusted_proxies: '192.0.0.1,10.0.0.0/8' - // trust *all* "X-Forwarded-*" headers + # trust *all* "X-Forwarded-*" headers trusted_headers: ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port'] - // or, if your proxy instead uses the "Forwarded" header + # or, if your proxy instead uses the "Forwarded" header trusted_headers: ['forwarded'] .. code-block:: xml From 019a8c82fa800777a7ea85dafe26cfccfdd9d9a7 Mon Sep 17 00:00:00 2001 From: cedric lombardot Date: Sat, 20 Mar 2021 11:42:29 +0100 Subject: [PATCH 0827/1519] Fix yaml syntax --- deployment/proxies.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deployment/proxies.rst b/deployment/proxies.rst index a51aa1c8889..49aa04c8361 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -125,8 +125,8 @@ In this case, you'll need to - *very carefully* - trust *all* proxies. # config/packages/framework.yaml framework: # ... - // trust *all* requests (the 'REMOTE_ADDR' string is replaced at - // run time by $_SERVER['REMOTE_ADDR']) + # trust *all* requests (the 'REMOTE_ADDR' string is replaced at + # run time by $_SERVER['REMOTE_ADDR']) trusted_proxies: '127.0.0.1,REMOTE_ADDR' That's it! It's critical that you prevent traffic from all non-trusted sources. From 7bbfe94d3a8a6e1d7743491fd7dd3fa97b04b979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4dlich?= <1880467+jschaedl@users.noreply.github.com> Date: Sun, 21 Mar 2021 14:09:17 +0100 Subject: [PATCH 0828/1519] Remove SentMessage paragraph The Notifier's `send` method does not return a `SentMessage` object: https://github.com/symfony/symfony/blob/5.2/src/Symfony/Component/Notifier/NotifierInterface.php#L26 Only the Chatter and Texter classes `send` methods returns a `SendMessage`. --- notifier.rst | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/notifier.rst b/notifier.rst index d328084c0b8..0c8309aec71 100644 --- a/notifier.rst +++ b/notifier.rst @@ -380,7 +380,7 @@ To send a notification, autowire the ); // Send the notification to the recipient - $sentMessage = $notifier->send($notification, $recipient); + $notifier->send($notification, $recipient); // ... } @@ -391,14 +391,6 @@ channels. The channels specify which channel (or transport) should be used to send the notification. For instance, ``['email', 'sms']`` will send both an email and sms notification to the user. -The ``send()`` method used to send the notification returns a variable of type -:class:`Symfony\\Component\\Notifier\\Message\\SentMessage` which provides -information such as the message ID and the original message contents. - -.. versionadded:: 5.2 - - The ``SentMessage`` class was introduced in Symfony 5.2. - The default notification also has a ``content()`` and ``emoji()`` method to set the notification content and icon. From 485637c22d154f26a2ad3d3f5605e5e244c9ec64 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 24 Mar 2021 12:31:06 +0100 Subject: [PATCH 0829/1519] Minor tweak --- mailer.rst | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/mailer.rst b/mailer.rst index cda5c1fb646..b632449c4b5 100644 --- a/mailer.rst +++ b/mailer.rst @@ -155,11 +155,10 @@ transport, but you can force to use one: This table shows the full list of available DSN formats for each third party provider: -<<<<<<< HEAD ==================== ==================================================== =========================================== ======================================== Provider SMTP HTTP API ==================== ==================================================== =========================================== ======================================== - Amazon SES ses+smtp://ACCESS_KEY:SECRET_KEY@default ses+https://ACCESS_KEY:SECRET_KEY@default ses+api://ACCESS_KEY:SECRET_KEY@default + Amazon SES ses+smtp://USERNAME:PASSWORD@default ses+https://ACCESS_KEY:SECRET_KEY@default ses+api://ACCESS_KEY:SECRET_KEY@default Google Gmail gmail+smtp://USERNAME:PASSWORD@default n/a n/a Mailchimp Mandrill mandrill+smtp://USERNAME:PASSWORD@default mandrill+https://KEY@default mandrill+api://KEY@default Mailgun mailgun+smtp://USERNAME:PASSWORD@default mailgun+https://KEY:DOMAIN@default mailgun+api://KEY:DOMAIN@default @@ -168,18 +167,7 @@ party provider: Sendgrid sendgrid+smtp://KEY@default n/a sendgrid+api://KEY@default Sendinblue sendinblue+smtp://USERNAME:PASSWORD@default n/a sendinblue+api://KEY@default ==================== ==================================================== =========================================== ======================================== -======= -==================== ========================================== =========================================== ======================================== - Provider SMTP HTTP API -==================== ========================================== =========================================== ======================================== - Amazon SES ses+smtp://USERNAME:PASSWORD@default ses+https://ACCESS_KEY:SECRET_KEY@default ses+api://ACCESS_KEY:SECRET_KEY@default - Google Gmail gmail+smtp://USERNAME:PASSWORD@default n/a n/a - Mailchimp Mandrill mandrill+smtp://USERNAME:PASSWORD@default mandrill+https://KEY@default mandrill+api://KEY@default - Mailgun mailgun+smtp://USERNAME:PASSWORD@default mailgun+https://KEY:DOMAIN@default mailgun+api://KEY:DOMAIN@default - Postmark postmark+smtp://ID@default n/a postmark+api://KEY@default - Sendgrid sendgrid+smtp://KEY@default n/a sendgrid+api://KEY@default -==================== ========================================== =========================================== ======================================== ->>>>>>> 4.4 + .. caution:: From 8aaf4776218a914da649cff13f4ffc712e445236 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 24 Mar 2021 12:31:15 +0100 Subject: [PATCH 0830/1519] Revert minor tweak --- mailer.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/mailer.rst b/mailer.rst index b632449c4b5..721e2144654 100644 --- a/mailer.rst +++ b/mailer.rst @@ -168,7 +168,6 @@ party provider: Sendinblue sendinblue+smtp://USERNAME:PASSWORD@default n/a sendinblue+api://KEY@default ==================== ==================================================== =========================================== ======================================== - .. caution:: If your credentials contain special characters, you must URL-encode them. From f749e254733b9ccfbe342646fad1d38b5e196ada Mon Sep 17 00:00:00 2001 From: KalleV Date: Thu, 25 Mar 2021 11:59:45 -0400 Subject: [PATCH 0831/1519] docs(http-client): fix default retry_failed configuration example The framework bundle configuration validation requires the top-level http client retry_failed configuration to be nested under default_options or scoped_clients. See: https://github.com/symfony/framework-bundle/blob/1f977bb1b790f915b22462e511b039fb761280b3/DependencyInjection/Configuration.php#L1414 --- reference/configuration/framework.rst | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 6458d77328a..5ea8a8cee0a 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -831,17 +831,18 @@ will automatically retry failed HTTP requests. # ... http_client: # ... - retry_failed: - # retry_strategy: app.custom_strategy - http_codes: - 0: ['GET', 'HEAD'] # retry network errors if request method is GET or HEAD - 429: true # retry all responses with 429 status code - 500: ['GET', 'HEAD'] - max_retries: 2 - delay: 1000 - multiplier: 3 - max_delay: 5000 - jitter: 0.3 + default_options: + retry_failed: + # retry_strategy: app.custom_strategy + http_codes: + 0: ['GET', 'HEAD'] # retry network errors if request method is GET or HEAD + 429: true # retry all responses with 429 status code + 500: ['GET', 'HEAD'] + max_retries: 2 + delay: 1000 + multiplier: 3 + max_delay: 5000 + jitter: 0.3 scoped_clients: my_api.client: From 1cc3689e8a8e896e4959807302b8f6f28911c61a Mon Sep 17 00:00:00 2001 From: Ivan Gantsev Date: Fri, 26 Mar 2021 10:57:52 +0300 Subject: [PATCH 0832/1519] Update rate_limiter.rst Inject HttpFoundation $request in action of controller --- rate_limiter.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index 6982f88cae4..22e78fa6c39 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -167,6 +167,7 @@ the number of requests to the API:: namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; use Symfony\Component\RateLimiter\RateLimiterFactory; @@ -174,7 +175,7 @@ the number of requests to the API:: { // if you're using service autowiring, the variable name must be: // "rate limiter name" (in camelCase) + "Limiter" suffix - public function index(RateLimiterFactory $anonymousApiLimiter) + public function index(Request $request, RateLimiterFactory $anonymousApiLimiter) { // create a limiter based on a unique identifier of the client // (e.g. the client's IP address, a username/email, an API key, etc.) @@ -272,12 +273,13 @@ the :class:`Symfony\\Component\\RateLimiter\\Reservation` object returned by the namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\RateLimiter\RateLimiterFactory; class ApiController extends AbstractController { - public function index(RateLimiterFactory $anonymousApiLimiter) + public function index(Request $request, RateLimiterFactory $anonymousApiLimiter) { $limiter = $anonymousApiLimiter->create($request->getClientIp()); $limit = $limiter->consume(); From 20436fc6026621885009e6b951e14b9b43027e9d Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 26 Mar 2021 14:07:27 +0100 Subject: [PATCH 0833/1519] rename master request to main request --- components/http_kernel.rst | 12 ++++++------ create_framework/http_kernel_httpkernelinterface.rst | 4 ++-- event_dispatcher.rst | 8 ++++---- http_cache.rst | 2 +- http_cache/esi.rst | 2 +- reference/configuration/framework.rst | 8 ++++---- reference/events.rst | 6 +++--- security/form_login_setup.rst | 2 +- session.rst | 2 +- 9 files changed, 23 insertions(+), 23 deletions(-) diff --git a/components/http_kernel.rst b/components/http_kernel.rst index c0da0fd6cfa..4dcf0ff6aa3 100644 --- a/components/http_kernel.rst +++ b/components/http_kernel.rst @@ -65,7 +65,7 @@ that system:: */ public function handle( Request $request, - int $type = self::MASTER_REQUEST, + int $type = self::MAIN_REQUEST, bool $catch = true ); } @@ -701,12 +701,12 @@ argument as follows:: This creates another full request-response cycle where this new ``Request`` is transformed into a ``Response``. The only difference internally is that some -listeners (e.g. security) may only act upon the master request. Each listener +listeners (e.g. security) may only act upon the main request. Each listener is passed some sub-class of :class:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent`, -whose :method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::isMasterRequest` -can be used to check if the current request is a "master" or "sub" request. +whose :method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::isMainRequest` +can be used to check if the current request is a "main" or "sub" request. -For example, a listener that only needs to act on the master request may +For example, a listener that only needs to act on the main request may look like this:: use Symfony\Component\HttpKernel\Event\RequestEvent; @@ -714,7 +714,7 @@ look like this:: public function onKernelRequest(RequestEvent $event) { - if (!$event->isMasterRequest()) { + if (!$event->isMainRequest()) { return; } diff --git a/create_framework/http_kernel_httpkernelinterface.rst b/create_framework/http_kernel_httpkernelinterface.rst index a5c46c8daaa..29ddcc9c124 100644 --- a/create_framework/http_kernel_httpkernelinterface.rst +++ b/create_framework/http_kernel_httpkernelinterface.rst @@ -16,7 +16,7 @@ goal by making our framework implement ``HttpKernelInterface``:: */ public function handle( Request $request, - $type = self::MASTER_REQUEST, + $type = self::MAIN_REQUEST, $catch = true ); } @@ -39,7 +39,7 @@ Update your framework so that it implements this interface:: public function handle( Request $request, - $type = HttpKernelInterface::MASTER_REQUEST, + $type = HttpKernelInterface::MAIN_REQUEST, $catch = true ) { // ... diff --git a/event_dispatcher.rst b/event_dispatcher.rst index 038a405b10b..450f23cf698 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -206,10 +206,10 @@ the ``EventSubscriber`` directory. Symfony takes care of the rest. Request Events, Checking Types ------------------------------ -A single page can make several requests (one master request, and then multiple +A single page can make several requests (one main request, and then multiple sub-requests - typically when :ref:`embedding controllers in templates `). For the core Symfony events, you might need to check to see if the event is for -a "master" request or a "sub request":: +a "main" request or a "sub request":: // src/EventListener/RequestListener.php namespace App\EventListener; @@ -220,8 +220,8 @@ a "master" request or a "sub request":: { public function onKernelRequest(RequestEvent $event) { - if (!$event->isMasterRequest()) { - // don't do anything if it's not the master request + if (!$event->isMainRequest()) { + // don't do anything if it's not the main request return; } diff --git a/http_cache.rst b/http_cache.rst index 9a9c7e414d3..35620d1cd76 100644 --- a/http_cache.rst +++ b/http_cache.rst @@ -155,7 +155,7 @@ header to the response. You can also use the ``trace_level`` config option and set it to either ``none``, ``short`` or ``full`` to add this information. -``short`` will add the information for the master request only. +``short`` will add the information for the main request only. It's written in a concise way that makes it easy to record the information in your server log files. For example, in Apache you can use ``%{X-Symfony-Cache}o`` in ``LogFormat`` format statements. diff --git a/http_cache/esi.rst b/http_cache/esi.rst index b23b19eda36..6108df41f49 100644 --- a/http_cache/esi.rst +++ b/http_cache/esi.rst @@ -161,7 +161,7 @@ used ``render()``. contains the ``ESI/1.0`` string anywhere. The embedded action can now specify its own caching rules entirely independently -of the master page:: +of the main page:: // src/Controller/NewsController.php namespace App\Controller; diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 9e03d3d05bd..15180619b77 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -197,7 +197,7 @@ Configuration * :ref:`dsn ` * :ref:`enabled ` * `only_exceptions`_ - * `only_master_requests`_ + * `only_main_requests`_ * `property_access`_ @@ -1244,12 +1244,12 @@ only_exceptions When this is set to ``true``, the profiler will only be enabled when an exception is thrown during the handling of the request. -only_master_requests -.................... +only_main_requests +.................. **type**: ``boolean`` **default**: ``false`` -When this is set to ``true``, the profiler will only be enabled on the master +When this is set to ``true``, the profiler will only be enabled on the main requests (and not on the subrequests). .. _profiler-dsn: diff --git a/reference/events.rst b/reference/events.rst index c55bfdcc824..75694ab1097 100644 --- a/reference/events.rst +++ b/reference/events.rst @@ -15,7 +15,7 @@ Each event dispatched by the HttpKernel component is a subclass of following information: :method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::getRequestType` - Returns the *type* of the request (``HttpKernelInterface::MASTER_REQUEST`` + Returns the *type* of the request (``HttpKernelInterface::MAIN_REQUEST`` or ``HttpKernelInterface::SUB_REQUEST``). :method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::getKernel` @@ -24,8 +24,8 @@ following information: :method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::getRequest` Returns the current ``Request`` being handled. -:method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::isMasterRequest` - Checks if this is a master request. +:method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::isMainRequest` + Checks if this is a main request. .. _kernel-core-request: diff --git a/security/form_login_setup.rst b/security/form_login_setup.rst index 3aa01ef0972..3bc9cb94d10 100644 --- a/security/form_login_setup.rst +++ b/security/form_login_setup.rst @@ -489,7 +489,7 @@ whenever the user browses a page:: { $request = $event->getRequest(); if ( - !$event->isMasterRequest() + !$event->isMainRequest() || $request->isXmlHttpRequest() || 'app_login' === $request->attributes->get('_route') ) { diff --git a/session.rst b/session.rst index 5a3fb69c09b..0caba75894f 100644 --- a/session.rst +++ b/session.rst @@ -225,7 +225,7 @@ your ``Session`` object with the default ``AttributeBag`` by the ``NamespacedAtt public function createSession(): SessionInterface { return new Session( - $this->storageFactory->createStorage($this->requestStack->getMasterRequest()), + $this->storageFactory->createStorage($this->requestStack->getMainRequest()), $this->sessionAttributes, null, $this->usageReporter From dcb14d2989024578b2414761c5c9df15e798b3c3 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 26 Mar 2021 15:14:38 +0100 Subject: [PATCH 0834/1519] rename User to InMemoryUser --- components/security/authentication.rst | 6 +++--- security/user_provider.rst | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/components/security/authentication.rst b/components/security/authentication.rst index 8761e87915a..0b0e2d97f95 100644 --- a/components/security/authentication.rst +++ b/components/security/authentication.rst @@ -175,14 +175,14 @@ receives an array of encoders:: use Acme\Entity\LegacyUser; use Symfony\Component\Security\Core\Encoder\EncoderFactory; use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder; - use Symfony\Component\Security\Core\User\User; + use Symfony\Component\Security\Core\User\InMemoryUser; $defaultEncoder = new MessageDigestPasswordEncoder('sha512', true, 5000); $weakEncoder = new MessageDigestPasswordEncoder('md5', true, 1); $encoders = [ - User::class => $defaultEncoder, - LegacyUser::class => $weakEncoder, + InMemoryUser::class => $defaultEncoder, + LegacyUser::class => $weakEncoder, // ... ]; $encoderFactory = new EncoderFactory($encoders); diff --git a/security/user_provider.rst b/security/user_provider.rst index 00e7c5a58d8..491eb57e256 100644 --- a/security/user_provider.rst +++ b/security/user_provider.rst @@ -138,7 +138,7 @@ interface only requires one method: ``loadUserByUsername($username)``:: public function loadUserByUsername(string $usernameOrEmail) { $entityManager = $this->getEntityManager(); - + return $entityManager->createQuery( 'SELECT u FROM App\Entity\User u @@ -231,7 +231,7 @@ users will encode their passwords: # ... encoders: # this internal class is used by Symfony to represent in-memory users - Symfony\Component\Security\Core\User\User: 'auto' + Symfony\Component\Security\Core\User\InMemoryUser: 'auto' .. code-block:: xml @@ -249,7 +249,7 @@ users will encode their passwords: - @@ -260,7 +260,7 @@ users will encode their passwords: // config/packages/security.php // this internal class is used by Symfony to represent in-memory users - use Symfony\Component\Security\Core\User\User; + use Symfony\Component\Security\Core\User\InMemoryUser; $container->loadFromExtension('security', [ // ... @@ -417,7 +417,7 @@ command will generate a nice skeleton to get you started:: { return User::class === $class || is_subclass_of($class, User::class); } - + /** * Upgrades the encoded password of a user, typically for using a better hash algorithm. */ From 92072d936ca519203685c3eb1ace602adff68ad6 Mon Sep 17 00:00:00 2001 From: Andrii Popov Date: Fri, 19 Mar 2021 09:03:37 +0200 Subject: [PATCH 0835/1519] [Validator] Add normalizer option to Unique constraint --- reference/constraints/Unique.rst | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/reference/constraints/Unique.rst b/reference/constraints/Unique.rst index eb7b4727491..f673d2d817b 100644 --- a/reference/constraints/Unique.rst +++ b/reference/constraints/Unique.rst @@ -2,8 +2,9 @@ Unique ====== Validates that all the elements of the given collection are unique (none of them -is present more than once). Elements are compared strictly, so ``'7'`` and ``7`` -are considered different elements (a string and an integer, respectively). +is present more than once). By default elements are compared strictly, +so ``'7'`` and ``7`` are considered different elements (a string and an integer, respectively). +If you want any other comparison logic to be applied, use the `normalizer`_ option. .. seealso:: @@ -21,6 +22,7 @@ are considered different elements (a string and an integer, respectively). Applies to :ref:`property or method ` Options - `groups`_ - `message`_ + - `normalizer`_ - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Unique` Validator :class:`Symfony\\Component\\Validator\\Constraints\\UniqueValidator` @@ -123,4 +125,22 @@ Parameter Description ``{{ value }}`` The current (invalid) value ============================= ================================================ +``normalizer`` +~~~~~~~~~~~~~~ + +**type**: a `PHP callable`_ **default**: ``null`` + +.. versionadded:: 5.3 + + The ``normalizer`` option was introduced in Symfony 5.3. + +This option allows to define the PHP callable applied to each element of the given collection before +checking if the collection is valid. + +For example, you may want to pass the ``'trim'`` string to apply the +:phpfunction:`trim` PHP function to each element of the collection in order to ignore leading and trailing +whitespace during validation. + .. include:: /reference/constraints/_payload-option.rst.inc + +.. _`PHP callable`: https://www.php.net/callable From 3862669e610854ea302c5859f8755f563741dedf Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 27 Mar 2021 20:03:16 +0100 Subject: [PATCH 0836/1519] Minor tweaks --- reference/constraints/Unique.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/reference/constraints/Unique.rst b/reference/constraints/Unique.rst index 3be82ed5da5..6b6d363acf1 100644 --- a/reference/constraints/Unique.rst +++ b/reference/constraints/Unique.rst @@ -4,7 +4,7 @@ Unique Validates that all the elements of the given collection are unique (none of them is present more than once). By default elements are compared strictly, so ``'7'`` and ``7`` are considered different elements (a string and an integer, respectively). -If you want any other comparison logic to be applied, use the `normalizer`_ option. +If you want to apply any other comparison logic, use the `normalizer`_ option. .. seealso:: @@ -134,12 +134,12 @@ Parameter Description The ``normalizer`` option was introduced in Symfony 5.3. -This option allows to define the PHP callable applied to each element of the given collection before -checking if the collection is valid. +This option defined the PHP callable applied to each element of the given +collection before checking if the collection is valid. -For example, you may want to pass the ``'trim'`` string to apply the -:phpfunction:`trim` PHP function to each element of the collection in order to ignore leading and trailing -whitespace during validation. +For example, you can pass the ``'trim'`` string to apply the :phpfunction:`trim` +PHP function to each element of the collection in order to ignore leading and +trailing whitespace during validation. .. include:: /reference/constraints/_payload-option.rst.inc From 337e25169c2a369e2a102144c3d5d11a02f3259b Mon Sep 17 00:00:00 2001 From: James Hemery Date: Sat, 23 Jan 2021 02:35:30 +0100 Subject: [PATCH 0837/1519] [Notifier] [FakeSms] Add the bridge --- notifier.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/notifier.rst b/notifier.rst index 023361051c2..72afd815ac3 100644 --- a/notifier.rst +++ b/notifier.rst @@ -59,6 +59,7 @@ Service Package DSN AllMySms ``symfony/allmysms-notifier`` ``allmysms://LOGIN:APIKEY@default?from=FROM`` Clickatell ``symfony/clickatell-notifier`` ``clickatell://ACCESS_TOKEN@default?from=FROM`` Esendex ``symfony/esendex-notifier`` ``esendex://USER_NAME:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM`` +FakeSms ``symfony/fake-sms-notifier`` ``fakesms+email://MAILER_SERVICE_ID?to=TO&from=FROM`` FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` GatewayApi ``symfony/gatewayapi-notifier`` ``gatewayapi://TOKEN@default?from=FROM`` Infobip ``symfony/infobip-notifier`` ``infobip://AUTH_TOKEN@HOST?from=FROM`` @@ -84,9 +85,8 @@ Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from= .. versionadded:: 5.3 - The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell and SpotHit integrations - were introduced in Symfony 5.3. - + The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell, SpotHit and FakeSms + integrations were introduced in Symfony 5.3. To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: From bf9e574c1ad2a0507639eee8a6285bf5f1776b15 Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Wed, 31 Mar 2021 18:18:21 +0200 Subject: [PATCH 0838/1519] Rewording Priority Parameter Important part: Explaining how to do it in YAML and XML, to make clear that `priority` is not *limited* to annotations/attributes - but simply not necessary in YAML/XML :-) Closes https://github.com/symfony/symfony-docs/issues/13367 --- routing.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/routing.rst b/routing.rst index bf971924311..97df5e57787 100644 --- a/routing.rst +++ b/routing.rst @@ -997,11 +997,10 @@ Priority Parameter The ``priority`` parameter was introduced in Symfony 5.1 -When defining a greedy pattern that matches many routes, this may be at the -beginning of your routing collection and prevents any route defined after to be -matched. -A ``priority`` optional parameter is available in order to let you choose the -order of your routes, and it is only available when using annotations. +Symfony evaluates routes in the order they are defined. So a routing pattern +that matches many routes might prevent subsequent routes to be matched. In YAML +and XML you can control the order by moving the routes up or down inside the file. +For annotations and attributes, there is an optional ``priority`` parameter: .. configuration-block:: From af96b342256b1683aed3fcd0c648bb05110dba5c Mon Sep 17 00:00:00 2001 From: Mathias Arlaud Date: Thu, 1 Apr 2021 16:27:39 +0200 Subject: [PATCH 0839/1519] Update doc for mercure 0.5 --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 72afd815ac3..45507e1784a 100644 --- a/notifier.rst +++ b/notifier.rst @@ -157,7 +157,7 @@ Gitter ``symfony/gitter-notifier`` ``GITTER_DSN=gitter://TOKEN@defaul GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?thread_key=THREAD_KEY`` LinkedIn ``symfony/linked-in-notifier`` ``linkedin://TOKEN:USER_ID@default`` Mattermost ``symfony/mattermost-notifier`` ``mattermost://ACCESS_TOKEN@HOST/PATH?channel=CHANNEL`` -Mercure ``symfony/mercure-notifier`` ``mercure://PUBLISHER_SERVICE_ID?topic=TOPIC`` +Mercure ``symfony/mercure-notifier`` ``mercure://HUB_ID?topic=TOPIC`` RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` Slack ``symfony/slack-notifier`` ``slack://TOKEN@default?channel=CHANNEL`` Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` From 7eb064ca248c04d46d69dc168a62d0f84393c5c4 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Fri, 2 Apr 2021 14:56:31 +0200 Subject: [PATCH 0840/1519] [Lock] Remove tip about the RetryTillSaveStore --- reference/configuration/framework.rst | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 6458d77328a..d107cf804df 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -3090,18 +3090,6 @@ name Name of the lock you want to create. -.. tip:: - - If you want to use the `RetryTillSaveStore` for :ref:`non-blocking locks `, - you can do it by :doc:`decorating the store ` service: - - .. code-block:: yaml - - lock.invoice.retry_till_save.store: - class: Symfony\Component\Lock\Store\RetryTillSaveStore - decorates: lock.invoice.store - arguments: ['@.inner', 100, 50] - mailer ~~~~~~ From 9e9796bd7a04c18269531e64dae8367bd00634ad Mon Sep 17 00:00:00 2001 From: Felipy Amorim Date: Sun, 4 Apr 2021 21:41:28 -0300 Subject: [PATCH 0841/1519] remove namespace unused --- security/user_checkers.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/security/user_checkers.rst b/security/user_checkers.rst index b215191e680..a1662298276 100644 --- a/security/user_checkers.rst +++ b/security/user_checkers.rst @@ -24,7 +24,6 @@ displayed to the user:: namespace App\Security; use App\Entity\User as AppUser; - use App\Exception\AccountDeletedException; use Symfony\Component\Security\Core\Exception\AccountExpiredException; use Symfony\Component\Security\Core\Exception\CustomUserMessageAccountStatusException; use Symfony\Component\Security\Core\User\UserCheckerInterface; From 3fe341f6c733e4d3c40d1dd44d802c5d300c8c80 Mon Sep 17 00:00:00 2001 From: Vasilij Dusko | CREATION Date: Thu, 1 Apr 2021 16:36:38 +0300 Subject: [PATCH 0842/1519] [Notifier] [LightSMS] add docs --- notifier.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 72afd815ac3..e23c85aeefa 100644 --- a/notifier.rst +++ b/notifier.rst @@ -64,6 +64,7 @@ FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@defa GatewayApi ``symfony/gatewayapi-notifier`` ``gatewayapi://TOKEN@default?from=FROM`` Infobip ``symfony/infobip-notifier`` ``infobip://AUTH_TOKEN@HOST?from=FROM`` Iqsms ``symfony/iqsms-notifier`` ``iqsms://LOGIN:PASSWORD@default?from=FROM`` +LightSMS ``symfony/lightsms-notifier`` ``lightsms://LOGIN:TOKEN@default?from=PHONE`` Mobyt ``symfony/mobyt-notifier`` ``mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM`` Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` Octopush ``symfony/octopush-notifier`` ``octopush://USERLOGIN:APIKEY@default?from=FROM&type=TYPE`` @@ -85,7 +86,7 @@ Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from= .. versionadded:: 5.3 - The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell, SpotHit and FakeSms + The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell, SpotHit, FakeSms and LightSMS integrations were introduced in Symfony 5.3. To enable a texter, add the correct DSN in your ``.env`` file and From 018d50ba322d5e58990918b226f0363dd0fcf541 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 31 Mar 2021 09:17:13 +0200 Subject: [PATCH 0843/1519] [Notifier][FakeChat] add docs --- notifier.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index e23c85aeefa..459f7d406b7 100644 --- a/notifier.rst +++ b/notifier.rst @@ -153,6 +153,7 @@ integration with these chat services: Service Package DSN ========== ================================ =========================================================================== Discord ``symfony/discord-notifier`` ``discord://TOKEN@default?webhook_id=ID`` +FakeChat ``symfony/fake-chat-notifier`` ``fakechat+email://MAILER_SERVICE_ID?to=TO&from=FROM`` Firebase ``symfony/firebase-notifier`` ``firebase://USERNAME:PASSWORD@default`` Gitter ``symfony/gitter-notifier`` ``GITTER_DSN=gitter://TOKEN@default?room_id=ROOM_ID`` GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?thread_key=THREAD_KEY`` @@ -178,7 +179,7 @@ Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:TOKEN@HOST?channel .. versionadded:: 5.3 - The Gitter and Mercure integrations were introduced in Symfony 5.3. + The Gitter, Mercure and FakeChat integrations were introduced in Symfony 5.3. Chatters are configured using the ``chatter_transports`` setting: From 09b1c98830c5712052824df30375788a2eb37881 Mon Sep 17 00:00:00 2001 From: Guillaume Sarramegna <13528732+sarramegnag@users.noreply.github.com> Date: Tue, 30 Mar 2021 19:14:37 +0200 Subject: [PATCH 0844/1519] Standardize built-in normalizers lists --- serializer/normalizers.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/serializer/normalizers.rst b/serializer/normalizers.rst index 50352e29c85..224fb809bcc 100644 --- a/serializer/normalizers.rst +++ b/serializer/normalizers.rst @@ -27,13 +27,13 @@ Symfony includes the following normalizers but you can also * :class:`Symfony\\Component\\Serializer\\Normalizer\\ObjectNormalizer` to normalize PHP object using the :doc:`PropertyAccess component `; * :class:`Symfony\\Component\\Serializer\\Normalizer\\DateTimeZoneNormalizer` - for :phpclass:`DateTimeZone` objects + for :phpclass:`DateTimeZone` objects; * :class:`Symfony\\Component\\Serializer\\Normalizer\\DateTimeNormalizer` for - objects implementing the :phpclass:`DateTimeInterface` interface + objects implementing the :phpclass:`DateTimeInterface` interface; * :class:`Symfony\\Component\\Serializer\\Normalizer\\DateIntervalNormalizer` - for :phpclass:`DateInterval` objects + for :phpclass:`DateInterval` objects; * :class:`Symfony\\Component\\Serializer\\Normalizer\\DataUriNormalizer` to - transform :phpclass:`SplFileInfo` objects in `Data URIs`_ + transform :phpclass:`SplFileInfo` objects in `Data URIs`_; * :class:`Symfony\\Component\\Serializer\\Normalizer\\CustomNormalizer` to normalize PHP object using an object that implements :class:`Symfony\\Component\\Serializer\\Normalizer\\NormalizableInterface`; @@ -43,11 +43,13 @@ Symfony includes the following normalizers but you can also * :class:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer` to normalize PHP object using the getter and setter methods of the object; * :class:`Symfony\\Component\\Serializer\\Normalizer\\PropertyNormalizer` to - normalize PHP object using `PHP reflection`_. -* :class:`Symfony\\Component\\Serializer\\Normalizer\\ConstraintViolationListNormalizer` for objects implementing the :class:`Symfony\\Component\\Validator\\ConstraintViolationListInterface` interface + normalize PHP object using `PHP reflection`_; +* :class:`Symfony\\Component\\Serializer\\Normalizer\\ConstraintViolationListNormalizer` for objects implementing the :class:`Symfony\\Component\\Validator\\ConstraintViolationListInterface` interface; * :class:`Symfony\\Component\\Serializer\\Normalizer\\ProblemNormalizer` for :class:`Symfony\\Component\\ErrorHandler\\Exception\\FlattenException` objects * :class:`Symfony\\Component\\Serializer\\Normalizer\\JsonSerializableNormalizer` - to deal with objects implementing the :phpclass:`JsonSerializable` interface + to deal with objects implementing the :phpclass:`JsonSerializable` interface; +* :class:`Symfony\\Component\\Serializer\\Normalizer\\UidNormalizer` converts objects that implement :class:`Symfony\\Component\\Uid\\AbstractUid` into strings and denormalizes uuid or ulid strings to :class:`Symfony\\Component\\Uid\\Uuid` or :class:`Symfony\\Component\\Uid\\Ulid`. + .. _`Data URIs`: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs .. _`PHP reflection`: https://php.net/manual/en/book.reflection.php From 7388cc941f0c6bf084ecfe4de2cfb025fc00047b Mon Sep 17 00:00:00 2001 From: Nyholm Date: Tue, 9 Mar 2021 18:34:08 +0100 Subject: [PATCH 0845/1519] Init Runtime docs --- components/runtime.rst | 417 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 417 insertions(+) create mode 100644 components/runtime.rst diff --git a/components/runtime.rst b/components/runtime.rst new file mode 100644 index 00000000000..760b10397a4 --- /dev/null +++ b/components/runtime.rst @@ -0,0 +1,417 @@ +.. index:: + single: Runtime + single: Components; Runtime + +The Runtime Component +====================== + + The Runtime Component decouples the bootstrapping logic from any global state + to make sure the application can run with runtimes like PHP-FPM, ReactPHP, + Swoole etc without any changes. + +Installation +------------ + +.. code-block:: terminal + + $ composer require symfony/runtime + +.. include:: /components/require_autoload.rst.inc + +Usage +----- + +The Runtime component allows you to write front-controllers in a generic way +and with use of configuration you may change the behavior. Let's consider the +``public/index.php`` as an example. It will return a callable which will create +and return the application:: + + handle(Request::createFromGlobals())->send()``. + +To make a console application, the same bootstrap code would look like:: + + #!/usr/bin/env php + setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('Hello World'); + }); + + return $command; + }; + +``:class:`Symfony\\Component\\Console\\Application``` + Useful with console applications with more than one command. This will use the + :class:`Symfony\\Component\\Runtime\\Runner\\Symfony\\ConsoleApplicationRunner``.:: + + setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('Hello World'); + }); + + $app = new Application(); + $app->add($command); + $app->setDefaultCommand('hello', true); + + return $app; + }; + +``:class:`Symfony\\Component\\Runtime\\RunnerInterface``` + The ``RuntimeInterface`` is a way to use a custom application with the + generic Runtime.:: + + '/var/task', + ]; + + require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; + + // ... + +The second way to pass an option to ``SymfonyRuntime::__construct()`` is to use +``extra.runtime.options`` in ``composer.json``. + +.. code-block:: json + + { + "require": { + "...": "..." + }, + "extra": { + "runtime": { + "options": { + "project_dir": "/var/task" + } + } + } + } + +.. note:: + + The environment variable ``APP_DEBUG`` has special support to easily + turn on and off debugging. + +Creating Your Own Runtime +------------------------- + +This is an advanced topic that describes the internals of the Runtime component. + +Using the runtime component will benefit maintainers because the bootstrap logic +could be versioned as a part of a normal package. If the application author decides +to use this component, the package maintainer of the Runtime class will have more +control and can fix bugs and add features. + +-- note:: + + Before Symfony 5.3, the boostrap logic was part of a Flex recipe. Since recipes + are rarely updated by users, bug patches would rarely be installed. + +The Runtime component is designed to be totally generic and able to run any application +outside of the global state in 6 steps: + + 1. The main entry point returns a callable (A) that wraps the application + 2. Callable (A) is passed to ``RuntimeInterface::getResolver()``, which returns a + ``ResolverInterface``. This resolver returns an array with the callable (A) + (or something that decorates the callable (A)) at index 0, and all its resolved + arguments at index 1. + 3. The callable A is invoked with its arguments, it will return an object that + represents the application (B). + 4. That object (B) is passed to ``RuntimeInterface::getRunner()``, which returns a + ``RunnerInterface``: an instance that knows how to "run" the object (B). + 5. The ``RunnerInterface::run($objectB)`` is executed and it returns the exit status + code as `int`. + 6. The PHP engine is exited with this status code. + +When creating a new runtime, there are two things to consider: First, what arguments +will the end user use? Second, what will the user's application look like? + +To create a runtime for ReactPHP, we see that no special arguments are typically +required. We will use the standard arguments provided by :class:`Symfony\\Component\\Runtime\\GenericRuntime` +by extending tha class. But a ReactPHP application will need some special logic +to run. That logic is added in a new class implementing :class:`Symfony\\Component\\Runtime\\RunnerInterface`:: + + use Psr\Http\Message\ServerRequestInterface; + use Symfony\Component\Runtime\RunnerInterface; + + class ReactPHPRunner implements RunnerInterface + { + private $application; + private $port; + + public function __construct(RequestHandlerInterface $application, int $port) + { + $this->application = $application; + $this->port = $port; + } + + public function run(): int + { + $application = $this->application; + $loop = \React\EventLoop\Factory::create(); + + $server = new \React\Http\Server($loop, function (ServerRequestInterface $request) use ($application) { + return $application->handle($request); + }); + + $socket = new \React\Socket\Server($this->port, $loop); + $server->listen($socket); + + $loop->run(); + + return 0; + } + } + +Now we should create a new :class:`Symfony\\Component\\Runtime\\RuntimeInterface` +that is using our ``ReactPHPRunner``:: + + use Symfony\Component\Runtime\GenericRuntime; + use Symfony\Component\Runtime\RunnerInterface; + + class ReactPHPRuntime extends GenericRuntime + { + private $port; + + public function __construct(array $options) + { + $this->port = $options['port'] ?? 8080; + parent::__construct($options); + } + + public function getRunner(?object $application): RunnerInterface + { + if ($application instanceof RequestHandlerInterface) { + return new ReactPHPRunner($application, $this->port); + } + + return parent::getRunner($application); + } + } + +The end user will now be able to create front controller like:: + + require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; + + return function (array $context) { + return new Psr15Application(); + }; + + From 06414b72271a50303eaf138a8bc7c50b4ab0fdc2 Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Fri, 12 Mar 2021 11:47:32 +0100 Subject: [PATCH 0846/1519] Apply suggestions from code review Co-authored-by: Oskar Stark --- components/runtime.rst | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/components/runtime.rst b/components/runtime.rst index 760b10397a4..86e3814ee0c 100644 --- a/components/runtime.rst +++ b/components/runtime.rst @@ -65,7 +65,7 @@ Selecting Runtimes The default Runtime is :class:`Symfony\\Component\\Runtime\\SymfonyRuntime`, it works excellent on most applications running with a webserver like Nginx and Apache, and PHP-FPM. You may change Runtime to :class:`Symfony\\Component\\Runtime\\GenericRuntime` -or a custom Runtime for Swoole or Aws Lambda. This can be done by specifying the +or a custom Runtime for Swoole or AWS Lambda. This can be done by specifying the Runtime class in the ``APP_RUNTIME`` environment variable or to specify the ``extra.runtime.class`` in ``composer.json``. @@ -82,8 +82,8 @@ Runtime class in the ``APP_RUNTIME`` environment variable or to specify the } } -Using SymfonyRuntime --------------------- +Using the SymfonyRuntime +------------------------ The :class:`Symfony\\Component\\Runtime\\RuntimeInterface` has two methods. One to get an instance of :class:`Symfony\\Component\\Runtime\\ResolverInterface` @@ -309,8 +309,8 @@ The second way to pass an option to ``SymfonyRuntime::__construct()`` is to use The environment variable ``APP_DEBUG`` has special support to easily turn on and off debugging. -Creating Your Own Runtime -------------------------- +Create Your Own Runtime +----------------------- This is an advanced topic that describes the internals of the Runtime component. @@ -319,7 +319,7 @@ could be versioned as a part of a normal package. If the application author deci to use this component, the package maintainer of the Runtime class will have more control and can fix bugs and add features. --- note:: +.. note:: Before Symfony 5.3, the boostrap logic was part of a Flex recipe. Since recipes are rarely updated by users, bug patches would rarely be installed. @@ -413,5 +413,3 @@ The end user will now be able to create front controller like:: return function (array $context) { return new Psr15Application(); }; - - From e7bacf17fae9eee8223b24a302bd1695ffefe913 Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Tue, 16 Mar 2021 08:57:48 +0100 Subject: [PATCH 0847/1519] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ondřej Frei <37588173+freiondrej@users.noreply.github.com> --- components/runtime.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/runtime.rst b/components/runtime.rst index 86e3814ee0c..9c868bdc05b 100644 --- a/components/runtime.rst +++ b/components/runtime.rst @@ -41,7 +41,7 @@ the autoload files since the component includes a composer plugin. The ``autoloa will instantiate a :class:`Symfony\\Component\\Runtime\\RuntimeInterface`, its job is to take the callable and resolve the arguments (``array $context``). Then it calls the callable to get the application ``App\Kernel``. At last it will run the application, -ie calling ``$kernel->handle(Request::createFromGlobals())->send()``. +i.e. calling ``$kernel->handle(Request::createFromGlobals())->send()``. To make a console application, the same bootstrap code would look like:: From 76de97372b3fde4f2472b836542649bdef30a1fe Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 5 Apr 2021 14:22:59 +0200 Subject: [PATCH 0848/1519] [#15081] Finish the new Runtime docs --- .doctor-rst.yaml | 1 + components/runtime.rst | 287 ++++++++++++++++++++++++++--------------- 2 files changed, 182 insertions(+), 106 deletions(-) diff --git a/.doctor-rst.yaml b/.doctor-rst.yaml index 61b56614a29..388147a8281 100644 --- a/.doctor-rst.yaml +++ b/.doctor-rst.yaml @@ -101,3 +101,4 @@ whitelist: - 'provides a ``loginUser()`` method to simulate logging in in your functional' - '.. code-block:: twig' - '.. versionadded:: 3.6' # MonologBundle + - '// bin/console' diff --git a/components/runtime.rst b/components/runtime.rst index 9c868bdc05b..ae962dd18cb 100644 --- a/components/runtime.rst +++ b/components/runtime.rst @@ -7,7 +7,11 @@ The Runtime Component The Runtime Component decouples the bootstrapping logic from any global state to make sure the application can run with runtimes like PHP-FPM, ReactPHP, - Swoole etc without any changes. + Swoole, etc. without any changes. + +.. versionadded:: 5.3 + + The Runtime component was introduced in Symfony 5.3. Installation ------------ @@ -21,10 +25,10 @@ Installation Usage ----- -The Runtime component allows you to write front-controllers in a generic way -and with use of configuration you may change the behavior. Let's consider the -``public/index.php`` as an example. It will return a callable which will create -and return the application:: +The Runtime component abstracts most bootstrapping logic as so-called +*runtimes*, allowing you to write front-controllers in a generic way. +For instance, the Runtime component allows Symfony's ``public/index.php`` +to look like this:: handle(Request::createFromGlobals())->send()``. +So how does this front-controller work? At first, the special +``autoload_runtime.php`` is automatically created by the Composer plugin in +the component. This file runs the following logic: + +#. It instantiates a :class:`Symfony\\Component\\Runtime\\RuntimeInterface`; +#. The callable (returned in the file) is passed to the Runtime, whose job + is to resolve the arguments (in this example: ``array $content``); +#. Then, this callable is called to get the application (``App\Kernel``); +#. At last, the Runtime is used to run the application (i.e. calling + ``$kernel->handle(Request::createFromGlobals())->send()``). -To make a console application, the same bootstrap code would look like:: +To make a console application, the bootstrap code would look like:: #!/usr/bin/env php application; - $loop = \React\EventLoop\Factory::create(); + $loop = ReactFactory::create(); - $server = new \React\Http\Server($loop, function (ServerRequestInterface $request) use ($application) { - return $application->handle($request); - }); + // configure ReactPHP to correctly handle the PSR-15 application + $server = new ReactHttpServer( + $loop, + function (ServerRequestInterface $request) use ($application) { + return $application->handle($request); + } + ); - $socket = new \React\Socket\Server($this->port, $loop); + // start the ReactPHP server + $socket = new ReactSocketServer($this->port, $loop); $server->listen($socket); $loop->run(); @@ -380,8 +448,8 @@ to run. That logic is added in a new class implementing :class:`Symfony\\Compone } } -Now we should create a new :class:`Symfony\\Component\\Runtime\\RuntimeInterface` -that is using our ``ReactPHPRunner``:: +By extending the ``GenericRuntime``, you make sure that the application is +always using this ``ReactPHPRunner``:: use Symfony\Component\Runtime\GenericRuntime; use Symfony\Component\Runtime\RunnerInterface; @@ -402,14 +470,21 @@ that is using our ``ReactPHPRunner``:: return new ReactPHPRunner($application, $this->port); } + // if it's not a PSR-15 application, use the GenericRuntime to + // run the application (see "Resolvable Applications" above) return parent::getRunner($application); } } The end user will now be able to create front controller like:: + Date: Mon, 5 Apr 2021 18:55:04 +0200 Subject: [PATCH 0849/1519] Apply suggestions from code review Co-authored-by: Denis Brumann --- components/runtime.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/runtime.rst b/components/runtime.rst index ae962dd18cb..dc745adb5c6 100644 --- a/components/runtime.rst +++ b/components/runtime.rst @@ -45,7 +45,7 @@ So how does this front-controller work? At first, the special the component. This file runs the following logic: #. It instantiates a :class:`Symfony\\Component\\Runtime\\RuntimeInterface`; -#. The callable (returned in the file) is passed to the Runtime, whose job +#. The callable (returned by ``public/index.php``) is passed to the Runtime, whose job is to resolve the arguments (in this example: ``array $content``); #. Then, this callable is called to get the application (``App\Kernel``); #. At last, the Runtime is used to run the application (i.e. calling @@ -107,7 +107,7 @@ Use the ``APP_RUNTIME`` environment variable or by specifying the Using the Runtime ----------------- -A Runtime is resposible for passing arguments into the closure and run the +A Runtime is responsible for passing arguments into the closure and run the application returned by the closure. The :class:`Symfony\\Component\\Runtime\\SymfonyRuntime` and :class:`Symfony\\Component\\Runtime\\GenericRuntime` supports a number of arguments and different applications that you can use in your @@ -245,7 +245,7 @@ The ``GenericRuntime`` and ``SymfonyRuntime`` also support these generic applications: :class:`Symfony\\Component\\Runtime\\RunnerInterface` - The ``RuntimeInterface`` is a way to use a custom application with the + The ``RunnerInterface`` is a way to use a custom application with the generic Runtime:: Date: Wed, 7 Apr 2021 15:03:44 +0200 Subject: [PATCH 0850/1519] Fixed invalid configuration-block --- components/runtime.rst | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/components/runtime.rst b/components/runtime.rst index dc745adb5c6..75c84b0fe17 100644 --- a/components/runtime.rst +++ b/components/runtime.rst @@ -85,24 +85,18 @@ integrate with Swoole or AWS Lambda). Use the ``APP_RUNTIME`` environment variable or by specifying the ``extra.runtime.class`` in ``composer.json`` to change the Runtime class: -.. configuration-block:: - - .. code-block:: json +.. code-block:: json - { - "require": { - "...": "..." - }, - "extra": { - "runtime": { - "class": "Symfony\\Component\\Runtime\\GenericRuntime" - } + { + "require": { + "...": "..." + }, + "extra": { + "runtime": { + "class": "Symfony\\Component\\Runtime\\GenericRuntime" } } - - .. code-block:: env - - APP_RUNTIME="Symfony\\Component\\Runtime\\GenericRuntime" + } Using the Runtime ----------------- From 5a8ce041c96a52be437f4333cf36c9b0c2c716ef Mon Sep 17 00:00:00 2001 From: Carlos Pereira De Amorim Date: Thu, 9 Jul 2020 12:50:34 +0200 Subject: [PATCH 0851/1519] Added explaination on context in events and initial marking --- workflow.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/workflow.rst b/workflow.rst index 048ea2c003a..bd36eb49014 100644 --- a/workflow.rst +++ b/workflow.rst @@ -381,11 +381,36 @@ order: * ``workflow.[workflow name].announce`` * ``workflow.[workflow name].announce.[transition name]`` + You can avoid triggering those events by using the context:: + + $workflow->apply($subject, $transitionName, [Workflow::DISABLE_ANNOUNCE_EVENT => true]); + + .. versionadded:: 5.1 + + The ``Workflow::DISABLE_ANNOUNCE_EVENT`` constant was introduced in Symfony 5.1. + + .. versionadded:: 5.2 + + In Symfony 5.2, the context is accessible in all events:: + + // $context must be an array + $context = ['context_key' => 'context_value']; + $workflow->apply($subject, $transitionName, $context); + + // in an event listener + $context = $event->getContext(); // returns ['context'] + .. note:: The leaving and entering events are triggered even for transitions that stay in same place. +.. note:: + + If you initialize the marking by calling ``$workflow->getMarking($object);``, + then the ``workflow.[workflow_name].entered.[initial_place_name]`` event will + be called with the default context (``Workflow::DEFAULT_INITIAL_CONTEXT``). + Here is an example of how to enable logging for every time a "blog_publishing" workflow leaves a place:: From 61c6a2efe64af747ffcb825e26fdc45d281c37e5 Mon Sep 17 00:00:00 2001 From: Andrius Date: Mon, 14 Dec 2020 00:18:28 +0200 Subject: [PATCH 0852/1519] Update login_link.rst --- security/login_link.rst | 82 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/security/login_link.rst b/security/login_link.rst index b92dd694178..e43edbd7a22 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -654,3 +654,85 @@ user create this POST request (e.g. by clicking a button):: {% endblock %} + +Customizing the Success Handler +............................... + +To customize, how the success handler behaves, create your own ``AuthenticationSuccessHandler``:: + + // src/Security/Authentication/AuthenticationSuccessHandler.php + namespace App\Security\Authentication; + + use Symfony\Component\HttpFoundation\JsonResponse; + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; + + class AuthenticationSuccessHandler implements AuthenticationSuccessHandlerInterface + { + public function onAuthenticationSuccess(Request $request, TokenInterface $token): JsonResponse + { + // Example use case: Create API token for Guard Authentication. + $user = $token->getUser(); // Returns string|\Stringable|UserInterface - depends on your implementation. + + $userApiToken = $user->getApiToken(); + + return new JsonResponse(['apiToken' => 'userApiToken']); + } + } + +Modify the configuration and use your handler for the ``success_handler`` key: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + firewalls: + main: + login_link: + check_route: login_check + lifetime: 600 + max_uses: 1 + success_handler: App\Security\Authentication\AuthenticationSuccessHandler + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + $container->loadFromExtension('security', [ + 'firewalls' => [ + 'main' => [ + 'login_link' => [ + 'check_route' => 'login_check', + 'lifetime' => 600, + 'max_uses' => 1, + 'success_handler' => 'App\Security\Authentication\AuthenticationSuccessHandler', + ], + ], + ], + ]); From 8680b94bd703f414735f25c18b3515a3915bcf8b Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Wed, 7 Apr 2021 16:56:32 +0200 Subject: [PATCH 0853/1519] [#14700] Minor rewording --- security/login_link.rst | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/security/login_link.rst b/security/login_link.rst index e43edbd7a22..d3c7b0e4c23 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -656,9 +656,12 @@ user create this POST request (e.g. by clicking a button):: {% endblock %} Customizing the Success Handler -............................... +------------------------------- -To customize, how the success handler behaves, create your own ``AuthenticationSuccessHandler``:: +Sometimes, the default success handling does not fit your use-case (e.g. +when you need to generate and return an API key). To customize how the +success handler behaves, create your own +:class:`Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface`:: // src/Security/Authentication/AuthenticationSuccessHandler.php namespace App\Security\Authentication; @@ -672,16 +675,14 @@ To customize, how the success handler behaves, create your own ``AuthenticationS { public function onAuthenticationSuccess(Request $request, TokenInterface $token): JsonResponse { - // Example use case: Create API token for Guard Authentication. - $user = $token->getUser(); // Returns string|\Stringable|UserInterface - depends on your implementation. - + $user = $token->getUser(); $userApiToken = $user->getApiToken(); return new JsonResponse(['apiToken' => 'userApiToken']); } } -Modify the configuration and use your handler for the ``success_handler`` key: +Then, configure this service ID as the ``success_handler``: .. configuration-block:: @@ -715,7 +716,7 @@ Modify the configuration and use your handler for the ``success_handler`` key: check-post-only="true" max-uses="1" lifetime="600" - success_handler="App\Security\Authentication\AuthenticationSuccessHandler" + success-handler="App\Security\Authentication\AuthenticationSuccessHandler" /> @@ -724,6 +725,8 @@ Modify the configuration and use your handler for the ``success_handler`` key: .. code-block:: php // config/packages/security.php + use App\Security\Authentication\AuthenticationSuccessHandler; + $container->loadFromExtension('security', [ 'firewalls' => [ 'main' => [ @@ -731,7 +734,7 @@ Modify the configuration and use your handler for the ``success_handler`` key: 'check_route' => 'login_check', 'lifetime' => 600, 'max_uses' => 1, - 'success_handler' => 'App\Security\Authentication\AuthenticationSuccessHandler', + 'success_handler' => AuthenticationSuccessHandler::class, ], ], ], From 1834da9e971aa71870ba2fc66417d0f4ae05fc24 Mon Sep 17 00:00:00 2001 From: Sebastian Paczkowski <74934099+sebpacz@users.noreply.github.com> Date: Tue, 23 Feb 2021 18:57:23 +0100 Subject: [PATCH 0854/1519] Update data_collector.rst I removed the DataCollector class import because it has been replaced with the AbstractDataCollector class. --- profiler/data_collector.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/profiler/data_collector.rst b/profiler/data_collector.rst index 6e53fd5203d..ef377c47974 100644 --- a/profiler/data_collector.rst +++ b/profiler/data_collector.rst @@ -31,7 +31,6 @@ request:: use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\HttpKernel\DataCollector\DataCollector; class RequestCollector extends AbstractDataCollector { From 55edd4857e5023321ba0143bb7b1dcc27ad8870c Mon Sep 17 00:00:00 2001 From: Thibault RICHARD Date: Sun, 28 Feb 2021 18:27:21 +0100 Subject: [PATCH 0855/1519] [Messenger] Add options for PostgreSQL LISTEN/NOTIFY support --- messenger.rst | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/messenger.rst b/messenger.rst index abf45612374..ee98b1f2e84 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1074,6 +1074,12 @@ a table named ``messenger_messages``. Or, to create the table yourself, set the ``auto_setup`` option to ``false`` and :ref:`generate a migration `. +.. caution:: + + The datetime property of the messages stored in the database uses the + timezone of the current system. This may cause issues if multiple machines + with different timezone configuration use the same storage. + The transport has a number of options: ================== ===================================== ====================== @@ -1093,11 +1099,28 @@ auto_setup Whether the table should be created automatically during send / get. true ================== ===================================== ====================== -.. caution:: +.. versionadded:: 5.1 - The datetime property of the messages stored in the database uses the - timezone of the current system. This may cause issues if multiple machines - with different timezone configuration use the same storage. + The ability to leverage PostgreSQL's LISTEN/NOTIFY was introduced + in Symfony 5.1. + +When using PostgreSQL, you have access to the following options to leverage +the `LISTEN/NOTIFY`_ feature. This allow for a more performant approach +than the default polling behavior of the Doctrine transport because +PostgreSQL will directly notify the workers when a new message is inserted +in the table. + +======================= ===================================== ====================== +Option Description Default +======================= ===================================== ====================== +use_notify Whether to use LISTEN/NOTIFY. true +check_delayed_interval The interval to check for delayed 1000 + messages, in milliseconds. + Set to 0 to disable checks. +get_notify_timeout The length of time to wait for a 0 + response when calling + ``PDO::pgsqlGetNotify```, in milliseconds. +======================= ========================================== ====================== Beanstalkd Transport ~~~~~~~~~~~~~~~~~~~~ @@ -1971,3 +1994,4 @@ Learn more .. _`Long polling`: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html .. _`Visibility Timeout`: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html .. _`FIFO queue`: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html +.. _`LISTEN/NOTIFY`: https://www.postgresql.org/docs/current/sql-notify.html From bd0073371144f4664597be836ecd523529edd5cb Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Wed, 7 Apr 2021 17:23:37 +0200 Subject: [PATCH 0856/1519] Fixed table markup --- messenger.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/messenger.rst b/messenger.rst index ee98b1f2e84..c97efd5210f 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1110,9 +1110,9 @@ than the default polling behavior of the Doctrine transport because PostgreSQL will directly notify the workers when a new message is inserted in the table. -======================= ===================================== ====================== +======================= ========================================== ====================== Option Description Default -======================= ===================================== ====================== +======================= ========================================== ====================== use_notify Whether to use LISTEN/NOTIFY. true check_delayed_interval The interval to check for delayed 1000 messages, in milliseconds. From 91096d5fbb61cb3209e97524732191062bc11a9e Mon Sep 17 00:00:00 2001 From: Jesse Rushlow Date: Fri, 26 Feb 2021 19:05:50 -0500 Subject: [PATCH 0857/1519] Add serialize reference --- reference/twig_reference.rst | 23 +++++++++++++++++++++++ serializer.rst | 13 +++++++++++++ 2 files changed, 36 insertions(+) diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 270c9c678c8..e4991845096 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -558,6 +558,29 @@ project's root directory: If the given file path is out of the project directory, a ``null`` value will be returned. +serialize +~~~~~~~~~ + +.. code-block:: twig + + {{ object|serialize(format = 'json', context = []) }} + +``object`` + **type**: ``mixed`` + +``format`` *(optional)* + **type**: ``string`` + +``context`` *(optional)* + **type**: ``array`` + +.. versionadded:: 5.3 + + The ``serialize`` filter was introduced in Symfony 5.3. + +Accepts any data that can be serialized by the :doc:`Serializer component ` +and returns a serialized string in the specified ``format``. + .. _reference-twig-tags: Tags diff --git a/serializer.rst b/serializer.rst index b4dd7e03d52..7d526ae46bc 100644 --- a/serializer.rst +++ b/serializer.rst @@ -41,6 +41,19 @@ you need it or it can be used in a controller:: } } +Or you can use the ``serialize`` Twig filter in a template: + +.. code-block:: twig + + {{ object|serialize(format = 'json') }} + +See the :doc:`twig reference ` for +more information. + +.. versionadded:: 5.3 + + A ``serialize`` filter was introduced in Symfony 5.3 that uses the Serializer component. + Adding Normalizers and Encoders ------------------------------- From 77089fa264786081748cd1d90c331784c2882b50 Mon Sep 17 00:00:00 2001 From: Nate Wiebe Date: Fri, 5 Mar 2021 15:35:03 -0500 Subject: [PATCH 0858/1519] Update docs relating to translation extraction --- translation.rst | 5 +++++ translation/debug.rst | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/translation.rst b/translation.rst index 8153d000531..b8e61251893 100644 --- a/translation.rst +++ b/translation.rst @@ -292,6 +292,8 @@ To manage these situations, Symfony follows the `ICU MessageFormat`_ syntax by using PHP's :phpclass:`MessageFormatter` class. Read more about this in :doc:`/translation/message_format`. +.. _translatable-objects: + Translatable Objects -------------------- @@ -386,6 +388,9 @@ The ``translation:update`` command looks for missing translations in: :ref:`twig.paths ` config options); * Any PHP file/class that injects or :doc:`autowires ` the ``translator`` service and makes calls to the ``trans()`` method. +* Any PHP file/class stored in the ``src/`` directory that creates + :ref:`translatable-objects` using the constructor or the ``t()`` method or calls + the ``trans()`` method. .. _translation-resource-locations: diff --git a/translation/debug.rst b/translation/debug.rst index 74e52783245..c511d7c9777 100644 --- a/translation/debug.rst +++ b/translation/debug.rst @@ -19,9 +19,10 @@ command helps you to find these missing or unused translation messages templates .. caution:: - The extractors can't find messages translated outside templates, like form - labels or controllers. Dynamic translations using variables or expressions - in templates are not detected either: + The extractors can't find messages translated outside templates (like form + labels or controllers) unless using :ref:`translatable-objects` or calling + the ``trans()`` method on a translator. Dynamic translations using variables + or expressions in templates are not detected either: .. code-block:: twig From dc9e6134441517ba520d30c060aeb70ed17e4a85 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Wed, 7 Apr 2021 17:50:50 +0200 Subject: [PATCH 0859/1519] [#15063] Added versionaddeds --- translation.rst | 5 +++++ translation/debug.rst | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/translation.rst b/translation.rst index b1e1cb619c0..4330e171c0a 100644 --- a/translation.rst +++ b/translation.rst @@ -468,6 +468,11 @@ The ``translation:update`` command looks for missing translations in: :ref:`translatable-objects` using the constructor or the ``t()`` method or calls the ``trans()`` method. +.. versionadded:: 5.3 + + Support for extracting Translatable objects has been introduced in + Symfony 5.3. + .. _translation-resource-locations: Translation Resource/File Names and Locations diff --git a/translation/debug.rst b/translation/debug.rst index c511d7c9777..cc14945dc9d 100644 --- a/translation/debug.rst +++ b/translation/debug.rst @@ -21,8 +21,9 @@ command helps you to find these missing or unused translation messages templates The extractors can't find messages translated outside templates (like form labels or controllers) unless using :ref:`translatable-objects` or calling - the ``trans()`` method on a translator. Dynamic translations using variables - or expressions in templates are not detected either: + the ``trans()`` method on a translator (since Symfony 5.3). Dynamic + translations using variables or expressions in templates are not + detected either: .. code-block:: twig From bdb8a80215972b4b85cbb957fb70241e9391f3e8 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 8 Apr 2021 11:48:23 +0200 Subject: [PATCH 0860/1519] Rename LightSms package Follows https://github.com/symfony/symfony/pull/40736 --- notifier.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notifier.rst b/notifier.rst index b5c9d8eda80..488ed973a5a 100644 --- a/notifier.rst +++ b/notifier.rst @@ -64,7 +64,7 @@ FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@defa GatewayApi ``symfony/gatewayapi-notifier`` ``gatewayapi://TOKEN@default?from=FROM`` Infobip ``symfony/infobip-notifier`` ``infobip://AUTH_TOKEN@HOST?from=FROM`` Iqsms ``symfony/iqsms-notifier`` ``iqsms://LOGIN:PASSWORD@default?from=FROM`` -LightSMS ``symfony/lightsms-notifier`` ``lightsms://LOGIN:TOKEN@default?from=PHONE`` +LightSms ``symfony/light-sms-notifier`` ``lightsms://LOGIN:TOKEN@default?from=PHONE`` Mobyt ``symfony/mobyt-notifier`` ``mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM`` Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` Octopush ``symfony/octopush-notifier`` ``octopush://USERLOGIN:APIKEY@default?from=FROM&type=TYPE`` @@ -86,7 +86,7 @@ Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from= .. versionadded:: 5.3 - The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell, SpotHit, FakeSms and LightSMS + The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell, SpotHit, FakeSms and LightSms integrations were introduced in Symfony 5.3. To enable a texter, add the correct DSN in your ``.env`` file and From 2204e13626a8a06c78654de002601355b616f134 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 8 Apr 2021 12:34:13 +0200 Subject: [PATCH 0861/1519] Remove variable --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index b5c9d8eda80..987afd08f8a 100644 --- a/notifier.rst +++ b/notifier.rst @@ -155,7 +155,7 @@ Service Package DSN Discord ``symfony/discord-notifier`` ``discord://TOKEN@default?webhook_id=ID`` FakeChat ``symfony/fake-chat-notifier`` ``fakechat+email://MAILER_SERVICE_ID?to=TO&from=FROM`` Firebase ``symfony/firebase-notifier`` ``firebase://USERNAME:PASSWORD@default`` -Gitter ``symfony/gitter-notifier`` ``GITTER_DSN=gitter://TOKEN@default?room_id=ROOM_ID`` +Gitter ``symfony/gitter-notifier`` ``gitter://TOKEN@default?room_id=ROOM_ID`` GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?thread_key=THREAD_KEY`` LinkedIn ``symfony/linked-in-notifier`` ``linkedin://TOKEN:USER_ID@default`` Mattermost ``symfony/mattermost-notifier`` ``mattermost://ACCESS_TOKEN@HOST/PATH?channel=CHANNEL`` From 9e1e0a906038a705bfe377706b95656873120df7 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 6 Apr 2021 14:23:37 +0200 Subject: [PATCH 0862/1519] [Notifier] Add MicrosoftTeams --- notifier.rst | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/notifier.rst b/notifier.rst index e07794be445..b260b58b58a 100644 --- a/notifier.rst +++ b/notifier.rst @@ -149,22 +149,23 @@ The chat channel is used to send chat messages to users by using :class:`Symfony\\Component\\Notifier\\Chatter` classes. Symfony provides integration with these chat services: -========== ================================ =========================================================================== -Service Package DSN -========== ================================ =========================================================================== -Discord ``symfony/discord-notifier`` ``discord://TOKEN@default?webhook_id=ID`` -FakeChat ``symfony/fake-chat-notifier`` ``fakechat+email://MAILER_SERVICE_ID?to=TO&from=FROM`` -Firebase ``symfony/firebase-notifier`` ``firebase://USERNAME:PASSWORD@default`` -Gitter ``symfony/gitter-notifier`` ``gitter://TOKEN@default?room_id=ROOM_ID`` -GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?thread_key=THREAD_KEY`` -LinkedIn ``symfony/linked-in-notifier`` ``linkedin://TOKEN:USER_ID@default`` -Mattermost ``symfony/mattermost-notifier`` ``mattermost://ACCESS_TOKEN@HOST/PATH?channel=CHANNEL`` -Mercure ``symfony/mercure-notifier`` ``mercure://HUB_ID?topic=TOPIC`` -RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` -Slack ``symfony/slack-notifier`` ``slack://TOKEN@default?channel=CHANNEL`` -Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` -Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:TOKEN@HOST?channel=CHANNEL`` -========== ================================ =========================================================================== +============== ==================================== =========================================================================== +Service Package DSN +============== ==================================== =========================================================================== +Discord ``symfony/discord-notifier`` ``discord://TOKEN@default?webhook_id=ID`` +FakeChat ``symfony/fake-chat-notifier`` ``fakechat+email://MAILER_SERVICE_ID?to=TO&from=FROM`` +Firebase ``symfony/firebase-notifier`` ``firebase://USERNAME:PASSWORD@default`` +Gitter ``symfony/gitter-notifier`` ``gitter://TOKEN@default?room_id=ROOM_ID`` +GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?thread_key=THREAD_KEY`` +LinkedIn ``symfony/linked-in-notifier`` ``linkedin://TOKEN:USER_ID@default`` +Mattermost ``symfony/mattermost-notifier`` ``mattermost://ACCESS_TOKEN@HOST/PATH?channel=CHANNEL`` +Mercure ``symfony/mercure-notifier`` ``mercure://HUB_ID?topic=TOPIC`` +MicrosoftTeams ``symfony/microsoft-teams-notifier`` ``microsoftteams://default/PATH`` +RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` +Slack ``symfony/slack-notifier`` ``slack://TOKEN@default?channel=CHANNEL`` +Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` +Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:TOKEN@HOST?channel=CHANNEL`` +============== ==================================== =========================================================================== .. versionadded:: 5.1 @@ -179,7 +180,7 @@ Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:TOKEN@HOST?channel .. versionadded:: 5.3 - The Gitter, Mercure and FakeChat integrations were introduced in Symfony 5.3. + The Gitter, Mercure, FakeChat and Microsoft Teams integrations were introduced in Symfony 5.3. Chatters are configured using the ``chatter_transports`` setting: From f68ec043011cc63df61541f5758dd70b198117e5 Mon Sep 17 00:00:00 2001 From: Matthew Setter Date: Thu, 8 Apr 2021 09:54:26 +0200 Subject: [PATCH 0863/1519] Corrected minor grammar mistake in the routing docs --- routing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routing.rst b/routing.rst index bf971924311..bd3697451a4 100644 --- a/routing.rst +++ b/routing.rst @@ -2216,8 +2216,8 @@ Stateless Routes The ``stateless`` option was introduced in Symfony 5.1. Sometimes, when an HTTP response should be cached, it is important to ensure -that can happen. However, whenever session is started during a request, Symfony -turns the response into a private non-cacheable response. +that can happen. However, whenever a session is started during a request, +Symfony turns the response into a private non-cacheable response. For details, see :doc:`/http_cache`. From c8deb3d013d486e99016d0918cd125180dcac555 Mon Sep 17 00:00:00 2001 From: Cristoforo Cervino Date: Tue, 16 Mar 2021 14:19:06 +0100 Subject: [PATCH 0864/1519] add form_attr option doc --- reference/forms/types/form.rst | 3 +++ .../forms/types/options/form_attr.rst.inc | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 reference/forms/types/options/form_attr.rst.inc diff --git a/reference/forms/types/form.rst b/reference/forms/types/form.rst index 9e1a5d47227..43a5a398bdf 100644 --- a/reference/forms/types/form.rst +++ b/reference/forms/types/form.rst @@ -19,6 +19,7 @@ on all types for which ``FormType`` is the parent. | | - `error_bubbling`_ | | | - `error_mapping`_ | | | - `extra_fields_message`_ | +| | - `form_attr`_ | | | - `help`_ | | | - `help_attr`_ | | | - `help_html`_ | @@ -116,6 +117,8 @@ The actual default value of this option depends on other field options: .. include:: /reference/forms/types/options/extra_fields_message.rst.inc +.. include:: /reference/forms/types/options/form_attr.rst.inc + .. include:: /reference/forms/types/options/help.rst.inc .. include:: /reference/forms/types/options/help_attr.rst.inc diff --git a/reference/forms/types/options/form_attr.rst.inc b/reference/forms/types/options/form_attr.rst.inc new file mode 100644 index 00000000000..bb6cb1ca4fd --- /dev/null +++ b/reference/forms/types/options/form_attr.rst.inc @@ -0,0 +1,20 @@ +``form_attr`` +~~~~~~~~~~~~~ + +**type**: ``boolean`` or ``string`` **default**: ``false`` + +When ``true`` and used on a form element, it adds a `"form" attribute`_ to its HTML field representation with +its HTML form id. By doing this, a form element can be rendered outside the HTML form while still working as expected:: + + $builder->add('body', TextareaType::class, [ + 'form_attr' => true, + ]); + +This can be useful when you need to solve nested form problems. +You can also set this to ``true`` on a root form to automatically set the "form" attribute on all its children. + +.. note:: + + When the root form has no ID, ``form_attr`` is required to be a string identifier to be used as the form ID. + +.. _`"form" attribute`: https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fae-form From d0d10f6f8b7faf5c1a19aa6dc2da0a671fcce427 Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Sat, 3 Apr 2021 19:04:59 +0200 Subject: [PATCH 0865/1519] Adding typehint ...from https://symfony.com/doc/current/security/guard_authentication.html#the-guard-authenticator-methods --- security/guard_authentication.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/guard_authentication.rst b/security/guard_authentication.rst index 6949d008d8d..4a406239aed 100644 --- a/security/guard_authentication.rst +++ b/security/guard_authentication.rst @@ -187,7 +187,7 @@ This requires you to implement several methods:: return true; } - public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) + public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey) { // on success, let the request continue return null; From 5cdeedc73d7b32d48fce220b5bea5f57395658bc Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Fri, 9 Apr 2021 08:55:04 +0200 Subject: [PATCH 0866/1519] Fix: Build --- security/login_link.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/login_link.rst b/security/login_link.rst index d3c7b0e4c23..456cfc706c6 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -661,7 +661,7 @@ Customizing the Success Handler Sometimes, the default success handling does not fit your use-case (e.g. when you need to generate and return an API key). To customize how the success handler behaves, create your own -:class:`Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface`:: +:class:`Symfony\\Component\\Security\\Http\\Authentication\\AuthenticationSuccessHandlerInterface`:: // src/Security/Authentication/AuthenticationSuccessHandler.php namespace App\Security\Authentication; From 3833bbac0e74d4a948e4bcd0cc80b0a42ddc65c3 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 8 Apr 2021 14:40:46 +0200 Subject: [PATCH 0867/1519] [Notifier] [FakeSms] [FakeChat] Update DSN --- notifier.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notifier.rst b/notifier.rst index b260b58b58a..305c433f53d 100644 --- a/notifier.rst +++ b/notifier.rst @@ -59,7 +59,7 @@ Service Package DSN AllMySms ``symfony/allmysms-notifier`` ``allmysms://LOGIN:APIKEY@default?from=FROM`` Clickatell ``symfony/clickatell-notifier`` ``clickatell://ACCESS_TOKEN@default?from=FROM`` Esendex ``symfony/esendex-notifier`` ``esendex://USER_NAME:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM`` -FakeSms ``symfony/fake-sms-notifier`` ``fakesms+email://MAILER_SERVICE_ID?to=TO&from=FROM`` +FakeSms ``symfony/fake-sms-notifier`` ``fakesms+email://default?to=TO&from=FROM`` FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` GatewayApi ``symfony/gatewayapi-notifier`` ``gatewayapi://TOKEN@default?from=FROM`` Infobip ``symfony/infobip-notifier`` ``infobip://AUTH_TOKEN@HOST?from=FROM`` @@ -153,7 +153,7 @@ integration with these chat services: Service Package DSN ============== ==================================== =========================================================================== Discord ``symfony/discord-notifier`` ``discord://TOKEN@default?webhook_id=ID`` -FakeChat ``symfony/fake-chat-notifier`` ``fakechat+email://MAILER_SERVICE_ID?to=TO&from=FROM`` +FakeChat ``symfony/fake-chat-notifier`` ``fakechat+email://default?to=TO&from=FROM`` Firebase ``symfony/firebase-notifier`` ``firebase://USERNAME:PASSWORD@default`` Gitter ``symfony/gitter-notifier`` ``gitter://TOKEN@default?room_id=ROOM_ID`` GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?thread_key=THREAD_KEY`` From 9a69cac3322dc410d4bbfb2a5f53d33f332de1d7 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 25 Feb 2021 09:01:54 +0100 Subject: [PATCH 0868/1519] [Intl] Remove documentation about deprecated code --- components/intl.rst | 34 ++++------------------------------ 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/components/intl.rst b/components/intl.rst index cb120034615..5331097be01 100644 --- a/components/intl.rst +++ b/components/intl.rst @@ -6,12 +6,11 @@ The Intl Component ================== This component provides access to the localization data of the `ICU library`_. - It also provides a PHP replacement layer for the C `intl extension`_. .. caution:: The replacement layer is limited to the ``en`` locale. If you want to use - other locales, you should `install the intl extension`_. There is no conflict + other locales, you should `install the intl extension`_. There is no conflict between the two because, even if you use the extension, this package can still be useful to access the ICU data. @@ -30,30 +29,6 @@ Installation .. include:: /components/require_autoload.rst.inc -If you install the component via Composer, the following classes and functions -of the intl extension will be automatically provided if the intl extension is -not loaded: - -* :phpclass:`Collator` -* :phpclass:`IntlDateFormatter` -* :phpclass:`Locale` -* :phpclass:`NumberFormatter` -* :phpfunction:`intl_error_name` -* :phpfunction:`intl_is_failure` -* :phpfunction:`intl_get_error_code` -* :phpfunction:`intl_get_error_message` - -When the intl extension is not available, the following classes are used to -replace the intl classes: - -* :class:`Symfony\\Component\\Intl\\Collator\\Collator` -* :class:`Symfony\\Component\\Intl\\DateFormatter\\IntlDateFormatter` -* :class:`Symfony\\Component\\Intl\\Locale\\Locale` -* :class:`Symfony\\Component\\Intl\\NumberFormatter\\NumberFormatter` -* :class:`Symfony\\Component\\Intl\\Globals\\IntlGlobals` - -Composer automatically exposes these classes in the global namespace. - Accessing ICU Data ------------------ @@ -211,9 +186,9 @@ Locales ~~~~~~~ A locale is the combination of a language, a region and some parameters that -define the interface preferences of the user. For example, "Chinese" is the -language and ``zh_Hans_MO`` is the locale for "Chinese" (language) + "Simplified" -(script) + "Macau SAR China" (region). The ``Locales`` class provides access to +define the interface preferences of the user. For example, "Chinese" is the +language and ``zh_Hans_MO`` is the locale for "Chinese" (language) + "Simplified" +(script) + "Macau SAR China" (region). The ``Locales`` class provides access to the name of all locales:: use Symfony\Component\Intl\Locales; @@ -375,7 +350,6 @@ Learn more /reference/forms/types/locale /reference/forms/types/timezone -.. _intl extension: https://www.php.net/manual/en/book.intl.php .. _install the intl extension: https://www.php.net/manual/en/intl.setup.php .. _ICU library: http://site.icu-project.org/ .. _`Unicode ISO 15924 Registry`: https://www.unicode.org/iso15924/iso15924-codes.html From f9c37de16ef72f750eac88ec93feb9c1a6f893ca Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 9 Apr 2021 10:38:39 +0200 Subject: [PATCH 0869/1519] [Serializer] Document the csv_end_of_line option --- components/serializer.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/serializer.rst b/components/serializer.rst index 580f55aa613..6eac8eebd51 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -984,6 +984,8 @@ Option Description D ``csv_delimiter`` Sets the field delimiter separating values (one ``,`` character only) ``csv_enclosure`` Sets the field enclosure (one character only) ``"`` +``csv_end_of_line`` Sets the character(s) used to mark the end of each ``\n`` + line in the CSV file ``csv_escape_char`` Sets the escape character (at most one character) empty string ``csv_key_separator`` Sets the separator for array's keys during its ``.`` flattening @@ -1000,6 +1002,10 @@ Option Description D ``output_utf8_bom`` Outputs special `UTF-8 BOM`_ along with encoded data ``false`` ======================= ===================================================== ========================== +.. versionadded:: 5.3 + + The ``csv_end_of_line`` option was introduced in Symfony 5.3. + The ``XmlEncoder`` ~~~~~~~~~~~~~~~~~~ From 2a39702c83eb46fc496f487bb1955639a737a119 Mon Sep 17 00:00:00 2001 From: Sebastian Paczkowski <74934099+sebpacz@users.noreply.github.com> Date: Sun, 11 Apr 2021 13:23:04 +0200 Subject: [PATCH 0870/1519] [HttpFoundation] Minor fixes --- components/http_foundation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 3699eb17258..410fcd2272a 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -190,7 +190,7 @@ Finally, the raw data sent with the request body can be accessed using $content = $request->getContent(); -For instance, this may be useful to process a XML string sent to the +For instance, this may be useful to process an XML string sent to the application by a remote service using the HTTP POST method. If the request body is a JSON string, it can be accessed using @@ -519,7 +519,7 @@ call:: 's_maxage' => 600, 'immutable' => true, 'last_modified' => new \DateTime(), - 'etag' => 'abcdef' + 'etag' => 'abcdef', ]); .. versionadded:: 5.1 From a9890170c674d9be585c043ab628913eac1cbd28 Mon Sep 17 00:00:00 2001 From: Anatoly Pashin Date: Mon, 12 Apr 2021 16:48:28 +1000 Subject: [PATCH 0871/1519] [Runtime] Fix typo --- components/runtime.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/runtime.rst b/components/runtime.rst index 75c84b0fe17..2bdad2e38f5 100644 --- a/components/runtime.rst +++ b/components/runtime.rst @@ -142,7 +142,7 @@ The following arguments are supported by the ``SymfonyRuntime``: ``Command::setCode()``). And these arguments are supported by both the ``SymfonyRuntime`` and -``GenerGenericRuntime`` (both type and variable name are important): +``GenericRuntime`` (both type and variable name are important): ``array $context`` This is the same as ``$_SERVER`` + ``$_ENV``. From 24c07cc105ebc887db74e92b654057a3b165a56f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 9 Apr 2021 10:57:10 +0200 Subject: [PATCH 0872/1519] [Security] Document the login_throttling.interval option --- security.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/security.rst b/security.rst index 3b1c81f8b20..13153307ad1 100644 --- a/security.rst +++ b/security.rst @@ -500,6 +500,11 @@ You must enable this using the ``login_throttling`` setting: login_throttling: max_attempts: 3 + # configure the maximum login attempts in a custom period of time + login_throttling: + max_attempts: 3 + interval: '15 minutes' + # use a custom rate limiter via its service ID login_throttling: limiter: app.my_login_rate_limiter @@ -526,6 +531,9 @@ You must enable this using the ``login_throttling`` setting: + + + @@ -550,6 +558,12 @@ You must enable this using the ``login_throttling`` setting: 'max_attempts' => 3, ], + // configure the maximum login attempts in a custom period of time + 'login_throttling' => [ + 'max_attempts' => 3, + 'interval' => '15 minutes', + ], + // use a custom rate limiter via its service ID 'login_throttling' => [ 'limiter' => 'app.my_login_rate_limiter', @@ -558,6 +572,10 @@ You must enable this using the ``login_throttling`` setting: ], ]); +.. versionadded:: 5.3 + + The ``login_throttling.interval`` option was introduced in Symfony 5.3. + By default, login attempts are limited on ``max_attempts`` (default: 5) failed requests for ``IP address + username`` and ``5 * max_attempts`` failed requests for ``IP address``. The second limit protects against an From 98b620676a23275b4bb12823398bab2fa1a8b9a4 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 9 Apr 2021 13:05:33 +0200 Subject: [PATCH 0873/1519] [Uid] Document the ::from() methods for UUIDs and ULIDs --- components/uid.rst | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index 1bf66021fe1..b262768195a 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -71,12 +71,20 @@ to create each type of UUID:: The ``Uuid::NAMESPACE_*`` constants were introduced in Symfony 5.3. -If your UUID is generated by another system, use the ``fromString()`` method to -create an object and make use of the utilities available for Symfony UUIDs:: +If your UUID value is already generated in another format, use any of the +following methods to create a ``Uuid`` object from it:: - // this value is generated somewhere else (can also be in binary format) - $uuidValue = 'd9e7a184-5d5b-11ea-a62a-3499710062d0'; - $uuid = Uuid::fromString($uuidValue); + // all the following examples would generate the same Uuid object + $uuid = Uuid::fromString('d9e7a184-5d5b-11ea-a62a-3499710062d0'); + $uuid = Uuid::fromBinary("\xd9\xe7\xa1\x84\x5d\x5b\x11\xea\xa6\x2a\x34\x99\x71\x00\x62\xd0"); + $uuid = Uuid::fromBase32('6SWYGR8QAV27NACAHMK5RG0RPG'); + $uuid = Uuid::fromBase58('TuetYWNHhmuSQ3xPoVLv9M'); + $uuid = Uuid::fromRfc4122('d9e7a184-5d5b-11ea-a62a-3499710062d0'); + +.. versionadded:: 5.3 + + The ``fromBinary()``, ``fromBase32()``, ``fromBase58()`` and ``fromRfc4122()`` + methods were introduced in Symfony 5.3. Converting UUIDs ~~~~~~~~~~~~~~~~ @@ -85,7 +93,7 @@ Use these methods to transform the UUID object into different bases:: $uuid = Uuid::fromString('d9e7a184-5d5b-11ea-a62a-3499710062d0'); - $uuid->toBinary(); // string(16) "..." (binary contents can't be printed) + $uuid->toBinary(); // string(16) "\xd9\xe7\xa1\x84\x5d\x5b\x11\xea\xa6\x2a\x34\x99\x71\x00\x62\xd0" $uuid->toBase32(); // string(26) "6SWYGR8QAV27NACAHMK5RG0RPG" $uuid->toBase58(); // string(22) "TuetYWNHhmuSQ3xPoVLv9M" $uuid->toRfc4122(); // string(36) "d9e7a184-5d5b-11ea-a62a-3499710062d0" @@ -238,12 +246,20 @@ Instantiate the ``Ulid`` class to generate a random ULID value:: $ulid = new Ulid(); // e.g. 01AN4Z07BY79KA1307SR9X4MV3 -If your ULID is generated by another system, use the ``fromString()`` method to -create an object and make use of the utilities available for Symfony ULIDs:: +If your ULID value is already generated in another format, use any of the +following methods to create a ``Ulid`` object from it:: + + // all the following examples would generate the same Ulid object + $ulid = Ulid::fromString('01E439TP9XJZ9RPFH3T1PYBCR8'); + $ulid = Ulid::fromBinary("\x01\x71\x06\x9d\x59\x3d\x97\xd3\x8b\x3e\x23\xd0\x6d\xe5\xb3\x08"); + $ulid = Ulid::fromBase32('01E439TP9XJZ9RPFH3T1PYBCR8'); + $ulid = Ulid::fromBase58('1BKocMc5BnrVcuq2ti4Eqm'); + $ulid = Ulid::fromRfc4122('0171069d-593d-97d3-8b3e-23d06de5b308'); + +.. versionadded:: 5.3 - // this value is generated somewhere else (can also be in binary format) - $ulidValue = '01E439TP9XJZ9RPFH3T1PYBCR8'; - $ulid = Ulid::fromString($ulidValue); + The ``fromBinary()``, ``fromBase32()``, ``fromBase58()`` and ``fromRfc4122()`` + methods were introduced in Symfony 5.3. Converting ULIDs ~~~~~~~~~~~~~~~~ @@ -252,7 +268,7 @@ Use these methods to transform the ULID object into different bases:: $ulid = Ulid::fromString('01E439TP9XJZ9RPFH3T1PYBCR8'); - $ulid->toBinary(); // string(16) "..." (binary contents can't be printed) + $ulid->toBinary(); // string(16) "\x01\x71\x06\x9d\x59\x3d\x97\xd3\x8b\x3e\x23\xd0\x6d\xe5\xb3\x08" $ulid->toBase32(); // string(26) "01E439TP9XJZ9RPFH3T1PYBCR8" $ulid->toBase58(); // string(22) "1BKocMc5BnrVcuq2ti4Eqm" $ulid->toRfc4122(); // string(36) "0171069d-593d-97d3-8b3e-23d06de5b308" From 8daccd39555d4db035625b0c4e25f55059efb929 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 9 Apr 2021 16:52:54 +0200 Subject: [PATCH 0874/1519] [HttpFoundation] Document the unix_socket and charset options for MySQL PdoSessionHandler --- session/database.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/session/database.rst b/session/database.rst index 01c663911e1..dffed5562e7 100644 --- a/session/database.rst +++ b/session/database.rst @@ -234,6 +234,16 @@ first register a new handler service with your database credentials: ; }; +.. tip:: + + When using MySQL as the database, the DSN defined in ``DATABASE_URL`` can + contain the ``charset`` and ``unix_socket`` options as query string parameters. + + .. versionadded:: 5.3 + + The support for ``charset`` and ``unix_socket`` options was introduced + in Symfony 5.3. + Next, use the :ref:`handler_id ` configuration option to tell Symfony to use this service as the session handler: From 0354465e71fd3b72c649f68d2a3f40b8ad0bc162 Mon Sep 17 00:00:00 2001 From: Linus Karlsson Date: Mon, 12 Apr 2021 10:59:28 +0200 Subject: [PATCH 0875/1519] Update table in lock component --- components/lock.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lock.rst b/components/lock.rst index 4200adcd817..dfb3962464c 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -357,7 +357,7 @@ Store Scope Blocking Expiring Sharing :ref:`MemcachedStore ` remote no yes no :ref:`MongoDbStore ` remote no yes no :ref:`PdoStore ` remote no yes no -:ref:`PostgreSqlStore ` remote yes yes yes +:ref:`PostgreSqlStore ` remote yes no yes :ref:`RedisStore ` remote no yes yes :ref:`SemaphoreStore ` local yes no no :ref:`ZookeeperStore ` remote no no no From a7cf4b344ddf31729e6b310848317d4cd8d15685 Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Mon, 12 Apr 2021 13:20:30 +0200 Subject: [PATCH 0876/1519] Updated link to v5.2 version --- configuration/dot-env-changes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configuration/dot-env-changes.rst b/configuration/dot-env-changes.rst index bed01ea766a..6679600e908 100644 --- a/configuration/dot-env-changes.rst +++ b/configuration/dot-env-changes.rst @@ -85,7 +85,7 @@ changes can be made to any Symfony 3.4 or higher app: and update your `phpunit.xml.dist file`_ so it loads the ``tests/bootstrap.php`` file. -.. _`public/index.php`: https://github.com/symfony/recipes/blob/master/symfony/framework-bundle/5.1/public/index.php +.. _`public/index.php`: https://github.com/symfony/recipes/blob/master/symfony/framework-bundle/5.2/public/index.php .. _`bin/console`: https://github.com/symfony/recipes/blob/master/symfony/console/5.1/bin/console .. _`comment on the top of .env`: https://github.com/symfony/recipes/blob/master/symfony/flex/1.0/.env .. _`create a new .env.test`: https://github.com/symfony/recipes/blob/master/symfony/phpunit-bridge/3.3/.env.test From f0853efdf4a695e53e924aada965b5879b5c72c8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 12 Apr 2021 13:43:33 +0200 Subject: [PATCH 0877/1519] Fixed RST syntax issue --- security/login_link.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/login_link.rst b/security/login_link.rst index d3c7b0e4c23..456cfc706c6 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -661,7 +661,7 @@ Customizing the Success Handler Sometimes, the default success handling does not fit your use-case (e.g. when you need to generate and return an API key). To customize how the success handler behaves, create your own -:class:`Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface`:: +:class:`Symfony\\Component\\Security\\Http\\Authentication\\AuthenticationSuccessHandlerInterface`:: // src/Security/Authentication/AuthenticationSuccessHandler.php namespace App\Security\Authentication; From d39b47767c9f8085e3e199f8d88f87d104fe7ad0 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 7 Apr 2021 15:18:01 +0200 Subject: [PATCH 0878/1519] Docs for Slack options field() method Closes #13398 --- _images/notifier/slack/field-method.png | Bin 0 -> 17302 bytes notifier/chatters.rst | 38 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 _images/notifier/slack/field-method.png diff --git a/_images/notifier/slack/field-method.png b/_images/notifier/slack/field-method.png new file mode 100644 index 0000000000000000000000000000000000000000..d77a60e6a2e920910686cfd06702d68360050bf6 GIT binary patch literal 17302 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 R>dW5(N{GpdmI~|o{SO+qaeM#( literal 0 HcmV?d00001 diff --git a/notifier/chatters.rst b/notifier/chatters.rst index da11c8858b9..318ed8c74d7 100644 --- a/notifier/chatters.rst +++ b/notifier/chatters.rst @@ -98,6 +98,44 @@ to add some interactive options called `Block elements`_:: $chatter->send($chatMessage); +Adding Fields and Values to a Slack Message +------------------------------------------- + +To add fields and values to your message you can use the +:method:`SlackSectionBlock::field() ` method:: + + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackDividerBlock; + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackSectionBlock; + use Symfony\Component\Notifier\Bridge\Slack\SlackOptions; + use Symfony\Component\Notifier\Message\ChatMessage; + + $chatMessage = new ChatMessage('Symfony Feature'); + + $options = (new SlackOptions()) + ->block((new SlackSectionBlock())->text('My message')) + ->block(new SlackDividerBlock()) + ->block( + (new SlackSectionBlock()) + ->field('*Max Rating*') + ->field('5.0') + ->field('*Min Rating*') + ->field('1.0') + ); + + // Add the custom options to the chat message and send the message + $chatMessage->options($options); + + $chatter->send($chatMessage); + +The result will be something like: + +.. image:: /_images/notifier/slack/field-method.png + :align: center + +.. versionadded:: 5.1 + + The `field()` method was introduced in Symfony 5.1. + Adding Interactions to a Discord Message ---------------------------------------- From 3780af231b78da570d6d1bf757b9206c29e1cc7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl?= <50833583+Mis0u@users.noreply.github.com> Date: Tue, 13 Apr 2021 14:08:16 +0200 Subject: [PATCH 0879/1519] Update login_link.rst I propose this change to manage the case of the link is invalid --- security/login_link.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/security/login_link.rst b/security/login_link.rst index 456cfc706c6..f7f5e36751e 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -739,3 +739,5 @@ Then, configure this service ID as the ``success_handler``: ], ], ]); + +If you want to manage the failure for example the link is expires, use 'failure_handler' and implements "AuthenticationFailureHandlerInterface" instand of "AuthenticationSuccessHandlerInterface" From b7340c7e7633177d37230bda2923bf3b1cb1d01d Mon Sep 17 00:00:00 2001 From: Stefan Graupner Date: Sun, 14 Mar 2021 15:38:24 +0100 Subject: [PATCH 0880/1519] [Workflow] Add info about MermaidDumper [Workflow] rst syntax fixes --- .../components/workflow/blogpost_mermaid.png | Bin 0 -> 24123 bytes workflow/dumping-workflows.rst | 20 +++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 _images/components/workflow/blogpost_mermaid.png diff --git a/_images/components/workflow/blogpost_mermaid.png b/_images/components/workflow/blogpost_mermaid.png new file mode 100644 index 0000000000000000000000000000000000000000..b0ffbc984c9dc40ef086aa3cc2f0029ca974a284 GIT binary patch literal 24123 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 Date: Tue, 13 Apr 2021 19:10:06 +0200 Subject: [PATCH 0881/1519] Fix typo in handler success customization part. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backslashes were missing. Reading was difficult, especially at the end of that very complete page 😅 . --- security/login_link.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/security/login_link.rst b/security/login_link.rst index 456cfc706c6..34705d28983 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -660,8 +660,10 @@ Customizing the Success Handler Sometimes, the default success handling does not fit your use-case (e.g. when you need to generate and return an API key). To customize how the -success handler behaves, create your own -:class:`Symfony\\Component\\Security\\Http\\Authentication\\AuthenticationSuccessHandlerInterface`:: +success handler behaves, create your own that must implement +:class:`Symfony\\Component\\Security\\Http\\Authentication\\AuthenticationSuccessHandlerInterface`. + +.. code-block:: php // src/Security/Authentication/AuthenticationSuccessHandler.php namespace App\Security\Authentication; From 1b1f8ffbcf7287e28aad88f0911c9819ca5cefab Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 14 Apr 2021 08:59:25 +0200 Subject: [PATCH 0882/1519] Minor reword --- security/login_link.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/security/login_link.rst b/security/login_link.rst index 34705d28983..4e1bfa2d3da 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -660,10 +660,8 @@ Customizing the Success Handler Sometimes, the default success handling does not fit your use-case (e.g. when you need to generate and return an API key). To customize how the -success handler behaves, create your own that must implement -:class:`Symfony\\Component\\Security\\Http\\Authentication\\AuthenticationSuccessHandlerInterface`. - -.. code-block:: php +success handler behaves, create your own handler as a class that implements +:class:`Symfony\\Component\\Security\\Http\\Authentication\\AuthenticationSuccessHandlerInterface`:: // src/Security/Authentication/AuthenticationSuccessHandler.php namespace App\Security\Authentication; From 96bc3ab94cbbd525274dcb22d9b87e3922519983 Mon Sep 17 00:00:00 2001 From: Vasilij Dusko Date: Sun, 11 Apr 2021 10:08:04 +0300 Subject: [PATCH 0883/1519] [Notifier] [SmsBiuras] add docs --- notifier.rst | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/notifier.rst b/notifier.rst index 305c433f53d..006c0256b87 100644 --- a/notifier.rst +++ b/notifier.rst @@ -53,28 +53,29 @@ to send SMS messages to mobile phones. This feature requires subscribing to a third-party service that sends SMS messages. Symfony provides integration with a couple popular SMS services: -========== ================================ ==================================================== -Service Package DSN -========== ================================ ==================================================== -AllMySms ``symfony/allmysms-notifier`` ``allmysms://LOGIN:APIKEY@default?from=FROM`` -Clickatell ``symfony/clickatell-notifier`` ``clickatell://ACCESS_TOKEN@default?from=FROM`` -Esendex ``symfony/esendex-notifier`` ``esendex://USER_NAME:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM`` -FakeSms ``symfony/fake-sms-notifier`` ``fakesms+email://default?to=TO&from=FROM`` -FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` -GatewayApi ``symfony/gatewayapi-notifier`` ``gatewayapi://TOKEN@default?from=FROM`` -Infobip ``symfony/infobip-notifier`` ``infobip://AUTH_TOKEN@HOST?from=FROM`` -Iqsms ``symfony/iqsms-notifier`` ``iqsms://LOGIN:PASSWORD@default?from=FROM`` -LightSms ``symfony/light-sms-notifier`` ``lightsms://LOGIN:TOKEN@default?from=PHONE`` -Mobyt ``symfony/mobyt-notifier`` ``mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM`` -Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` -Octopush ``symfony/octopush-notifier`` ``octopush://USERLOGIN:APIKEY@default?from=FROM&type=TYPE`` -OvhCloud ``symfony/ovh-cloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` -Sendinblue ``symfony/sendinblue-notifier`` ``sendinblue://API_KEY@default?sender=PHONE`` -Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` -Smsapi ``symfony/smsapi-notifier`` ``smsapi://TOKEN@default?from=FROM`` -SpotHit ``symfony/spothit-notifier`` ``spothit://TOKEN@default?from=FROM`` -Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` -========== ================================ ==================================================== +============== ==================================== =========================================================================== +Service Package DSN +============== ==================================== =========================================================================== +AllMySms ``symfony/allmysms-notifier`` ``allmysms://LOGIN:APIKEY@default?from=FROM`` +Clickatell ``symfony/clickatell-notifier`` ``clickatell://ACCESS_TOKEN@default?from=FROM`` +Esendex ``symfony/esendex-notifier`` ``esendex://USER_NAME:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM`` +FakeSms ``symfony/fake-sms-notifier`` ``fakesms+email://MAILER_SERVICE_ID?to=TO&from=FROM`` +FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` +GatewayApi ``symfony/gatewayapi-notifier`` ``gatewayapi://TOKEN@default?from=FROM`` +Infobip ``symfony/infobip-notifier`` ``infobip://AUTH_TOKEN@HOST?from=FROM`` +Iqsms ``symfony/iqsms-notifier`` ``iqsms://LOGIN:PASSWORD@default?from=FROM`` +LightSms ``symfony/light-sms-notifier`` ``lightsms://LOGIN:TOKEN@default?from=PHONE`` +Mobyt ``symfony/mobyt-notifier`` ``mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM`` +Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` +Octopush ``symfony/octopush-notifier`` ``octopush://USERLOGIN:APIKEY@default?from=FROM&type=TYPE`` +OvhCloud ``symfony/ovh-cloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` +Sendinblue ``symfony/sendinblue-notifier`` ``sendinblue://API_KEY@default?sender=PHONE`` +Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` +Smsapi ``symfony/smsapi-notifier`` ``smsapi://TOKEN@default?from=FROM`` +SmsBiuras ``symfony/sms-biuras-notifier`` ``smsbiuras://UID:API_KEY@default?from=FROM&test_mode=0`` +SpotHit ``symfony/spothit-notifier`` ``spothit://TOKEN@default?from=FROM`` +Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` +============== ==================================== =========================================================================== .. versionadded:: 5.1 From eb3accd083240339e36f2574291e678036b8acb2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 14 Apr 2021 11:10:36 +0200 Subject: [PATCH 0884/1519] Added SmsBiuras to the versionadded directive --- notifier.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notifier.rst b/notifier.rst index 006c0256b87..c8226fd5c81 100644 --- a/notifier.rst +++ b/notifier.rst @@ -87,8 +87,8 @@ Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@defau .. versionadded:: 5.3 - The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell, SpotHit, FakeSms and LightSms - integrations were introduced in Symfony 5.3. + The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell, SpotHit, FakeSms, LightSms, + and SmsBiuras integrations were introduced in Symfony 5.3. To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: From 4836e5d7e52f0970193f8ed06913e19b3a03686e Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Wed, 14 Apr 2021 15:35:45 +0200 Subject: [PATCH 0885/1519] Added link to https://symfony.com/doc/current/mailer.html#configuring-emails-globally --- reference/configuration/framework.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 1545f586bf9..3d82c643511 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -3207,6 +3207,10 @@ headers Headers to add to emails. The key (``name`` attribute in xml format) is the header name and value the header value. +.. seealso:: + + For more information, see :ref:`Configuring Emails Globally ` + web_link ~~~~~~~~ From 96ffaa6e9fb14f8b7785291365348994d0acdf7e Mon Sep 17 00:00:00 2001 From: Ivan Yivoff Date: Mon, 28 Dec 2020 08:47:37 +0100 Subject: [PATCH 0886/1519] Update performance.rst --- performance.rst | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/performance.rst b/performance.rst index b632ee0a227..d710d982449 100644 --- a/performance.rst +++ b/performance.rst @@ -106,8 +106,16 @@ make them available to all requests until the server is restarted, improving performance significantly. During container compilation (e.g. when running the ``cache:clear`` command), -Symfony generates a file called ``preload.php`` in the ``config/`` directory -with the list of classes to preload. +Symfony generates a file with the list of classes to preload in the +``var/cache`` directory. + +Rather than use this file directly, when installing with Flex the Framework +Bundle recipe will create a file called ``preload.php`` in the ``config/`` +directory, which you can use safely, since it includes safeguards in case the +cache has not been warmed beforehand. + +If this file is missing, you can reinstall the recipe by executing +``composer recipes:install symfony/framework-bundle --force -v``. The only requirement is that you need to set both ``container.dumper.inline_factories`` and ``container.dumper.inline_class_loader`` parameters to ``true``. Then, you From 975137a2580d96cad44d1af54b10dccb072d5577 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 14 Apr 2021 18:00:47 +0200 Subject: [PATCH 0887/1519] Rewords --- performance.rst | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/performance.rst b/performance.rst index 2be82670b1b..a1fc408918b 100644 --- a/performance.rst +++ b/performance.rst @@ -107,23 +107,18 @@ performance significantly. During container compilation (e.g. when running the ``cache:clear`` command), Symfony generates a file with the list of classes to preload in the -``var/cache`` directory. - -Rather than use this file directly, when installing with Flex the Framework -Bundle recipe will create a file called ``preload.php`` in the ``config/`` -directory, which you can use safely, since it includes safeguards in case the -cache has not been warmed beforehand. - -If this file is missing, you can reinstall the recipe by executing -``composer recipes:install symfony/framework-bundle --force -v``. - -You can configure PHP to use this preload file: +``var/cache/`` directory. Rather than use this file directly, use the +``config/preload.php`` file that is created when +:doc:`using Symfony Flex in your project `: .. code-block:: ini ; php.ini opcache.preload=/path/to/project/config/preload.php +If this file is missing, run this command to reinstall the Symfony Flex recipe: +``composer recipes:install symfony/framework-bundle --force -v``. + Use the :ref:`container.preload ` and :ref:`container.no_preload ` service tags to define which classes should or should not be preloaded by PHP. From c0a3fdd459fc397e27dbc2df59378e651e64ac1b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 9 Apr 2021 16:40:12 +0200 Subject: [PATCH 0888/1519] [Intl] Document getCashFractionDigits() and getCashRoundingIncrement() --- components/intl.rst | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/components/intl.rst b/components/intl.rst index 1260945a27c..b690482f276 100644 --- a/components/intl.rst +++ b/components/intl.rst @@ -262,15 +262,45 @@ as some of their information (symbol, fraction digits, etc.):: $symbol = Currencies::getSymbol('INR'); // => '₹' - $fractionDigits = Currencies::getFractionDigits('INR'); - // => 2 +The fraction digits methods return the number of decimal digits to display when +formatting numbers with this currency. Depending on the currency, this value +can change if the number is used in cash transactions or in other scenarios +(e.g. accounting):: - $roundingIncrement = Currencies::getRoundingIncrement('INR'); - // => 0 + // Indian rupee defines the same value for both + $fractionDigits = Currencies::getFractionDigits('INR'); // returns: 2 + $cashFractionDigits = Currencies::getCashFractionDigits('INR'); // returns: 2 -All methods (except for ``getFractionDigits()`` and ``getRoundingIncrement()``) -accept the translation locale as the last, optional parameter, which defaults to -the current default locale:: + // Swedish krona defines different values + $fractionDigits = Currencies::getFractionDigits('SEK'); // returns: 2 + $cashFractionDigits = Currencies::getCashFractionDigits('SEK'); // returns: 0 + +.. versionadded:: 5.3 + + The ``getCashFractionDigits()`` method was introduced in Symfony 5.3. + +Some currencies require to round numbers to the nearest increment of some value +(e.g. 5 cents). This increment might be different if numbers are formatted for +cash transactions or other scenarios (e.g. accounting):: + + // Indian rupee defines the same value for both + $roundingIncrement = Currencies::getRoundingIncrement('INR'); // returns: 0 + $cashRoundingIncrement = Currencies::getCashRoundingIncrement('INR'); // returns: 0 + + // Canadian dollar defines different values because they have eliminated + // the smaller coins (1-cent and 2-cent) and prices in cash must be rounded to + // 5 cents (e.g. if price is 7.42 you pay 7.40; if price is 7.48 you pay 7.50) + $roundingIncrement = Currencies::getRoundingIncrement('CAD'); // returns: 0 + $cashRoundingIncrement = Currencies::getCashRoundingIncrement('CAD'); // returns: 5 + +.. versionadded:: 5.3 + + The ``getCashRoundingIncrement()`` method was introduced in Symfony 5.3. + +All methods (except for ``getFractionDigits()``, ``getCashFractionDigits()``, +``getRoundingIncrement()`` and ``getCashRoundingIncrement()``) accept the +translation locale as the last, optional parameter, which defaults to the +current default locale:: $currencies = Currencies::getNames('de'); // => ['AFN' => 'Afghanischer Afghani', 'EGP' => 'Ägyptisches Pfund', ...] From ee5ee00fa7005ab3b0ec5cbdbcfd60558734f6f1 Mon Sep 17 00:00:00 2001 From: Vasilij Dusko | CREATION Date: Thu, 1 Apr 2021 17:50:22 +0300 Subject: [PATCH 0889/1519] * notifier.rst - message bird --- notifier.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notifier.rst b/notifier.rst index c8226fd5c81..276fceac5ee 100644 --- a/notifier.rst +++ b/notifier.rst @@ -65,6 +65,7 @@ GatewayApi ``symfony/gatewayapi-notifier`` ``gatewayapi://TOKEN@defau Infobip ``symfony/infobip-notifier`` ``infobip://AUTH_TOKEN@HOST?from=FROM`` Iqsms ``symfony/iqsms-notifier`` ``iqsms://LOGIN:PASSWORD@default?from=FROM`` LightSms ``symfony/light-sms-notifier`` ``lightsms://LOGIN:TOKEN@default?from=PHONE`` +MessageBird ``symfony/message-bird-notifier`` ``messagebird://TOKEN@default?from=FROM`` Mobyt ``symfony/mobyt-notifier`` ``mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM`` Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` Octopush ``symfony/octopush-notifier`` ``octopush://USERLOGIN:APIKEY@default?from=FROM&type=TYPE`` @@ -87,8 +88,7 @@ Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@defau .. versionadded:: 5.3 - The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell, SpotHit, FakeSms, LightSms, - and SmsBiuras integrations were introduced in Symfony 5.3. + The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell, SpotHit, FakeSms, LightSms, SmsBiuras, and MessageBird integrations were introduced in Symfony 5.3. To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: From 1d3e66a9a51d11602995be9fd28b519d1dfdc6b0 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Fri, 16 Apr 2021 10:00:58 +0200 Subject: [PATCH 0890/1519] minor --- notifier.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 276fceac5ee..5bbd12252a2 100644 --- a/notifier.rst +++ b/notifier.rst @@ -88,7 +88,8 @@ Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@defau .. versionadded:: 5.3 - The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell, SpotHit, FakeSms, LightSms, SmsBiuras, and MessageBird integrations were introduced in Symfony 5.3. + The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell, SpotHit, FakeSms, LightSms, SmsBiuras + and MessageBird integrations were introduced in Symfony 5.3. To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: From 5b427af35e0150f388bd02a030a71681757a3c5a Mon Sep 17 00:00:00 2001 From: Nyholm Date: Fri, 2 Apr 2021 12:55:28 +0200 Subject: [PATCH 0891/1519] [Config] Add docs for ConfigBuilders --- configuration.rst | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/configuration.rst b/configuration.rst index 5d4354d562b..0de52977451 100644 --- a/configuration.rst +++ b/configuration.rst @@ -71,8 +71,8 @@ readable. These are the main advantages and disadvantages of each format: and validation for it. :doc:`Learn the YAML syntax `; * **XML**:autocompleted/validated by most IDEs and is parsed natively by PHP, but sometimes it generates configuration considered too verbose. `Learn the XML syntax`_; -* **PHP**: very powerful and it allows you to create dynamic configuration, but the - resulting configuration is less readable than the other formats. +* **PHP**: very powerful and it allows you to create dynamic configuration with + arrays or a :ref:`ConfigBuilder `. Importing Configuration Files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -914,6 +914,41 @@ parameters at once by type-hinting any of its constructor arguments with the } } +.. _config-config-builder: + +Using PHP ConfigBuilders +------------------------ + +Writing PHP config is sometimes difficult because you end up with large nested arrays +and you have no help from your favorite IDE. A way to address this is to use "ConfigBuilders". +They are objects that will help you build these arrays. + +.. versionadded:: 5.3 + + The "ConfigBuilders" was added in Symfony 5.3 as an :doc:`experimental feature `. + +The ConfigBuilders are automatically generated in your ``kernel.build_dir`` for +every bundle. By convention they all live in the namespace ``Symfony\Config``.:: + + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->pattern('^/*') + ->lazy(true) + ->anonymous(); + + $security + ->roleHierarchy('ROLE_ADMIN', ['ROLE_USER']) + ->roleHierarchy('ROLE_SUPER_ADMIN', ['ROLE_ADMIN', 'ROLE_ALLOWED_TO_SWITCH']) + ->accessControl() + ->path('^/user') + ->role('ROLE_USER'); + + $security->accessControl(['path' => '^/admin', 'roles' => 'ROLE_ADMIN']); + }; + Keep Going! ----------- From 6a55e20d79ed05c02076563d3da4ebaa58b25627 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 16 Apr 2021 16:00:16 +0200 Subject: [PATCH 0892/1519] Minor tweak --- configuration.rst | 18 +++++++++++------- reference/configuration/kernel.rst | 3 ++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/configuration.rst b/configuration.rst index 35b6bc8129f..fbd36889577 100644 --- a/configuration.rst +++ b/configuration.rst @@ -919,16 +919,20 @@ parameters at once by type-hinting any of its constructor arguments with the Using PHP ConfigBuilders ------------------------ -Writing PHP config is sometimes difficult because you end up with large nested arrays -and you have no help from your favorite IDE. A way to address this is to use "ConfigBuilders". -They are objects that will help you build these arrays. - .. versionadded:: 5.3 - The "ConfigBuilders" was added in Symfony 5.3 as an :doc:`experimental feature `. + The "ConfigBuilders" feature was introduced in Symfony 5.3 as an + :doc:`experimental feature `. + +Writing PHP config is sometimes difficult because you end up with large nested +arrays and you have no autocompletion help from your favorite IDE. A way to +address this is to use "ConfigBuilders". They are objects that will help you +build these arrays. -The ConfigBuilders are automatically generated in your ``kernel.build_dir`` for -every bundle. By convention they all live in the namespace ``Symfony\Config``.:: +Symfony generates the ConfigBuilder classes automatically in the +:ref:`kernel build directory ` for all the +bundles installed in your application. By convention they all live in the +namespace ``Symfony\Config``:: // config/packages/security.php use Symfony\Config\SecurityConfig; diff --git a/reference/configuration/kernel.rst b/reference/configuration/kernel.rst index 6e05536e525..10e87ca1a67 100644 --- a/reference/configuration/kernel.rst +++ b/reference/configuration/kernel.rst @@ -103,6 +103,8 @@ the :method:`Symfony\\Component\\HttpKernel\\Kernel::getCacheDir` method. To change this setting, override the ``getCacheDir()`` method to return the correct cache directory. +.. _configuration-kernel-build-directory: + Build Directory ~~~~~~~~~~~~~~~ @@ -123,7 +125,6 @@ the :method:`Symfony\\Component\\HttpKernel\\Kernel::getBuildDir` method. To change this setting, override the ``getBuildDir()`` method to return the correct build directory. - Log Directory ~~~~~~~~~~~~~ From 6479f2f2df8473f640ab8537a3c5bd7951846803 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 16 Apr 2021 16:16:07 +0200 Subject: [PATCH 0893/1519] Added the "versionadded" comments --- components/security/authentication.rst | 2 ++ security/user_provider.rst | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/components/security/authentication.rst b/components/security/authentication.rst index 0b0e2d97f95..18b780b6d84 100644 --- a/components/security/authentication.rst +++ b/components/security/authentication.rst @@ -130,6 +130,8 @@ password was valid:: use Symfony\Component\Security\Core\User\InMemoryUserProvider; use Symfony\Component\Security\Core\User\UserChecker; + // The 'InMemoryUser' class was introduced in Symfony 5.3. + // In previous versions it was called 'User' $userProvider = new InMemoryUserProvider( [ 'admin' => [ diff --git a/security/user_provider.rst b/security/user_provider.rst index 491eb57e256..5cef2533e12 100644 --- a/security/user_provider.rst +++ b/security/user_provider.rst @@ -231,6 +231,8 @@ users will encode their passwords: # ... encoders: # this internal class is used by Symfony to represent in-memory users + # (the 'InMemoryUser' class was introduced in Symfony 5.3. + # In previous versions it was called 'User') Symfony\Component\Security\Core\User\InMemoryUser: 'auto' .. code-block:: xml @@ -249,6 +251,8 @@ users will encode their passwords: + @@ -260,6 +264,8 @@ users will encode their passwords: // config/packages/security.php // this internal class is used by Symfony to represent in-memory users + // (the 'InMemoryUser' class was introduced in Symfony 5.3. + // In previous versions it was called 'User') use Symfony\Component\Security\Core\User\InMemoryUser; $container->loadFromExtension('security', [ From c975d5d029f1210cdb5810431e07d7e5ce03e7a2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 16 Apr 2021 16:51:11 +0200 Subject: [PATCH 0894/1519] Minor reword --- routing.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/routing.rst b/routing.rst index 1d9e9b08746..0551b44eaf4 100644 --- a/routing.rst +++ b/routing.rst @@ -997,10 +997,12 @@ Priority Parameter The ``priority`` parameter was introduced in Symfony 5.1 -Symfony evaluates routes in the order they are defined. So a routing pattern -that matches many routes might prevent subsequent routes to be matched. In YAML -and XML you can control the order by moving the routes up or down inside the file. -For annotations and attributes, there is an optional ``priority`` parameter: +Symfony evaluates routes in the order they are defined. If the path of a route +matches many different patterns, it might prevent other routes from being +matched. In YAML and XML you can move the route definitions up or down in the +configuration file to control their priority. In routes defined as PHP +annotations or attributes this is much harder to do, so you can set the +optional ``priority`` parameter in those routes to control their priority: .. configuration-block:: From eb0c8a45546687b0d81ebbb7f90aacd33b5396a7 Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER Date: Sun, 18 Apr 2021 14:19:50 +0200 Subject: [PATCH 0895/1519] Calling enableAnnotationMapping without argument is deprecated First argument must be set to true. --- components/validator/resources.rst | 11 ++++++----- form/unit_testing.rst | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/components/validator/resources.rst b/components/validator/resources.rst index 7f9b02fb544..91809ec7097 100644 --- a/components/validator/resources.rst +++ b/components/validator/resources.rst @@ -106,14 +106,14 @@ prefixed classes included in doc block comments (``/** ... */``). For example:: } To enable the annotation loader, call the -:method:`Symfony\\Component\\Validator\\ValidatorBuilder::enableAnnotationMapping` -method. It takes an optional annotation reader instance, which defaults to -``Doctrine\Common\Annotations\AnnotationReader``:: +:method:`Symfony\\Component\\Validator\\ValidatorBuilder::enableAnnotationMapping` method. +``addDefaultDoctrineAnnotationReader`` must also be called to use ``Doctrine\Common\Annotations\AnnotationReader``:: use Symfony\Component\Validator\Validation; $validator = Validation::createValidatorBuilder() - ->enableAnnotationMapping() + ->enableAnnotationMapping(true) + ->addDefaultDoctrineAnnotationReader() ->getValidator(); To disable the annotation loader after it was enabled, call @@ -134,7 +134,8 @@ multiple mappings:: use Symfony\Component\Validator\Validation; $validator = Validation::createValidatorBuilder() - ->enableAnnotationMapping() + ->enableAnnotationMapping(true) + ->addDefaultDoctrineAnnotationReader() ->addMethodMapping('loadValidatorMetadata') ->addXmlMapping('validator/validation.xml') ->getValidator(); diff --git a/form/unit_testing.rst b/form/unit_testing.rst index 33ef7bd4ca4..376a1f88315 100644 --- a/form/unit_testing.rst +++ b/form/unit_testing.rst @@ -219,7 +219,8 @@ allows you to return a list of extensions to register:: // or if you also need to read constraints from annotations $validator = Validation::createValidatorBuilder() - ->enableAnnotationMapping() + ->enableAnnotationMapping(true) + ->addDefaultDoctrineAnnotationReader() ->getValidator(); return [ From 3857676cabe1ed7b8ad5d99f0e66a00a9256eb3d Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 19 Apr 2021 09:18:22 +0200 Subject: [PATCH 0896/1519] remove 4.x versionadded directive --- testing.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/testing.rst b/testing.rst index 4033a72db5c..31428c41845 100644 --- a/testing.rst +++ b/testing.rst @@ -843,12 +843,6 @@ useful test assertions:: // ...or check that the response is a redirect to any URL $this->assertResponseRedirects(); -.. versionadded:: 4.3 - - The ``assertResponseHeaderSame()``, ``assertResponseIsSuccessful()``, - ``assertResponseStatusCodeSame()``, ``assertResponseRedirects()`` and other - related methods were introduced in Symfony 4.3. - .. index:: single: Tests; Crawler From 5ab1233b6ecf36217b0c7aac890d8fec4f692c3e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 20 Apr 2021 15:46:23 +0200 Subject: [PATCH 0897/1519] Minor tweaks --- http_client.rst | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/http_client.rst b/http_client.rst index fbe80fd2b23..5133ba74a65 100644 --- a/http_client.rst +++ b/http_client.rst @@ -1498,7 +1498,8 @@ This allows using them where native PHP streams are needed:: Extensibility ------------- -In order to extend the behavior of a base HTTP client, decoration is the way to go:: +If you want to extend the behavior of a base HTTP client, you can use +:doc:`service decoration `:: class MyExtendedHttpClient implements HttpClientInterface { @@ -1511,11 +1512,11 @@ In order to extend the behavior of a base HTTP client, decoration is the way to public function request(string $method, string $url, array $options = []): ResponseInterface { - // do what you want here with $method, $url and/or $options + // process and/or change the $method, $url and/or $options as needed + $response = $this->decoratedClient->request($method, $url, $options); - $response = $this->decoratedClient->request(); - - //!\ calling any method on $response here would break async, see below for a better way + // if you call here any method on $response, the HTTP request + // won't be async; see below for a better way return $response; } @@ -1526,13 +1527,13 @@ In order to extend the behavior of a base HTTP client, decoration is the way to } } -A decorator like this one is suited for use cases where processing the -requests' arguments is enough. +A decorator like this one is useful in cases where processing the requests' +arguments is enough. By decorating the ``on_progress`` option, you can +even implement basic monitoring of the response. However, since calling +responses' methods forces synchronous operations, doing so inside ``request()`` +will break async. -By decorating the ``on_progress`` option, one can -even implement basic monitoring of the response. But since calling responses' -methods forces synchronous operations, doing so in ``request()`` breaks async. -The solution then is to also decorate the response object itself. +The solution is to also decorate the response object itself. :class:`Symfony\\Component\\HttpClient\\TraceableHttpClient` and :class:`Symfony\\Component\\HttpClient\\Response\\TraceableResponse` are good examples as a starting point. @@ -1551,10 +1552,9 @@ processing the stream of chunks as they come back from the network:: public function request(string $method, string $url, array $options = []): ResponseInterface { - // do what you want here with $method, $url and/or $options + // process and/or change the $method, $url and/or $options as needed $passthru = function (ChunkInterface $chunk, AsyncContext $context) { - // do what you want with chunks, e.g. split them // in smaller chunks, group them, skip some, etc. @@ -1571,19 +1571,19 @@ it shall return an :class:`Symfony\\Component\\HttpClient\\Response\\AsyncResponse`. The custom processing of chunks should happen in ``$passthru``: this generator -is where you need to write your logic. It will be called for each chunk yielded by -the underlying client. A ``$passthru`` that does nothing would just ``yield $chunk;``. -Of course, you could also yield a modified chunk, split the chunk into many +is where you need to write your logic. It will be called for each chunk yielded +by the underlying client. A ``$passthru`` that does nothing would just ``yield +$chunk;``. You could also yield a modified chunk, split the chunk into many ones by yielding several times, or even skip a chunk altogether by issuing a ``return;`` instead of yielding. In order to control the stream, the chunk passthru receives an :class:`Symfony\\Component\\HttpClient\\Response\\AsyncContext` as second argument. This context object has methods to read the current state of the -response. It also allows altering the response stream with methods to create new -chunks of content, pause the stream, cancel the stream, change the info of the -response, replace the current request by another one or change the chunk passthru -itself. +response. It also allows altering the response stream with methods to create +new chunks of content, pause the stream, cancel the stream, change the info of +the response, replace the current request by another one or change the chunk +passthru itself. Checking the test cases implemented in :class:`Symfony\\Component\\HttpClient\\Response\\Tests\\AsyncDecoratorTraitTest` @@ -1594,10 +1594,10 @@ Here are the use cases that it simulates: * send a preflight request, e.g. for authentication needs; * issue subrequests and include their content in the main response's body. -The logic in :class:`Symfony\\Component\\HttpClient\\Response\\AsyncResponse` has -many safety checks that will throw a ``LogicException`` if the chunk passthru -doesn't behave correctly; e.g. if a chunk is yielded after an ``isLast()`` one, -or if a content chunk is yielded before an ``isFirst()`` one, etc. +The logic in :class:`Symfony\\Component\\HttpClient\\Response\\AsyncResponse` +has many safety checks that will throw a ``LogicException`` if the chunk +passthru doesn't behave correctly; e.g. if a chunk is yielded after an ``isLast()`` +one, or if a content chunk is yielded before an ``isFirst()`` one, etc. Testing HTTP Clients and Responses ---------------------------------- From e4c5aefeed892bf49ac2801fda0d683bc6459fc9 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 20 Apr 2021 16:17:45 +0200 Subject: [PATCH 0898/1519] Tweaks --- event_dispatcher.rst | 2 ++ reference/configuration/framework.rst | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/event_dispatcher.rst b/event_dispatcher.rst index 450f23cf698..be7fe590e79 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -220,6 +220,8 @@ a "main" request or a "sub request":: { public function onKernelRequest(RequestEvent $event) { + // The isMainRequest() method was introduced in Symfony 5.3. + // In previous versions it was called isMasterRequest() if (!$event->isMainRequest()) { // don't do anything if it's not the main request return; diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 415acd6cb69..8dedb6d3ddc 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1247,11 +1247,18 @@ only_exceptions When this is set to ``true``, the profiler will only be enabled when an exception is thrown during the handling of the request. +.. _only_master_requests: + only_main_requests .................. **type**: ``boolean`` **default**: ``false`` +.. versionadded:: 5.3 + + The ``only_main_requests`` option was introduced in Symfony 5.3. In previous + versions it was called ``only_master_requests``. + When this is set to ``true``, the profiler will only be enabled on the main requests (and not on the subrequests). From 017ecd7f08cd8a8861edddf42b5291ddae1fa65f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 20 Apr 2021 16:49:40 +0200 Subject: [PATCH 0899/1519] Tweak --- components/validator/resources.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/validator/resources.rst b/components/validator/resources.rst index 91809ec7097..c807ec1e540 100644 --- a/components/validator/resources.rst +++ b/components/validator/resources.rst @@ -106,8 +106,9 @@ prefixed classes included in doc block comments (``/** ... */``). For example:: } To enable the annotation loader, call the -:method:`Symfony\\Component\\Validator\\ValidatorBuilder::enableAnnotationMapping` method. -``addDefaultDoctrineAnnotationReader`` must also be called to use ``Doctrine\Common\Annotations\AnnotationReader``:: +:method:`Symfony\\Component\\Validator\\ValidatorBuilder::enableAnnotationMapping` method +and then call ``addDefaultDoctrineAnnotationReader()`` to use Doctrine's +annotation reader:: use Symfony\Component\Validator\Validation; From 2b0c05cc6eda6f7a7f21bdec448be5af8367e894 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 9 Apr 2021 10:04:17 +0200 Subject: [PATCH 0900/1519] [Uid] Document the methods to generate and inspect UIDs --- components/uid.rst | 110 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/components/uid.rst b/components/uid.rst index 1bf66021fe1..f86e68ee129 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -370,6 +370,116 @@ of the ULID parameters:: } } +Generating and Inspecting UUIDs/ULIDs in the Console +---------------------------------------------------- + +.. versionadded:: 5.3 + + The commands to inspect and generate UUIDs/ULIDs were introduced in Symfony 5.3. + +This component provides several commands to generate and inspect UUIDs/ULIDs in +the console. They are not enabled by default, so you must add the following +configuration in your application before using these commands: + +.. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + Symfony\Component\Uid\Command\GenerateUlidCommand: ~ + Symfony\Component\Uid\Command\GenerateUuidCommand: ~ + Symfony\Component\Uid\Command\InspectUlidCommand: ~ + Symfony\Component\Uid\Command\InspectUuidCommand: ~ + + .. code-block:: xml + + + + + + + + + + + + + + + + .. code-block:: php + + // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use Symfony\Component\Uid\Command\GenerateUlidCommand; + use Symfony\Component\Uid\Command\GenerateUuidCommand; + use Symfony\Component\Uid\Command\InspectUlidCommand; + use Symfony\Component\Uid\Command\InspectUuidCommand; + + return static function (ContainerConfigurator $configurator): void { + // ... + + $services + ->set(GenerateUlidCommand::class) + ->set(GenerateUuidCommand::class) + ->set(InspectUlidCommand::class) + ->set(InspectUuidCommand::class); + }; + +Now you can generate UUIDs/ULIDs as follows (add the ``--help`` option to the +commands to learn about all their options): + +.. code-block:: terminal + + # generate 1 random-based UUID + $ php bin/console uuid:generate --random-based + + # generate 1 time-based UUID with a specific node + $ php bin/console uuid:generate --time-based=now --node=fb3502dc-137e-4849-8886-ac90d07f64a7 + + # generate 2 UUIDs and output them in base58 format + $ php bin/console uuid:generate --count=2 --format=base58 + + # generate 1 ULID with the current time as the timestamp + $ php bin/console ulid:generate + + # generate 1 ULID with a specific timestamp + $ php bin/console ulid:generate --time="2021-02-02 14:00:00" + + # generate 2 ULIDs and ouput them in RFC4122 format + $ php bin/console ulid:generate --count=2 --format=rfc4122 + +In addition to generating new UIDs, you can also inspect them with the following +commands to show all the information for a given UID: + +.. code-block:: terminal + + $ php bin/console uuid:inspect d0a3a023-f515-4fe0-915c-575e63693998 + ---------------------- -------------------------------------- + Label Value + ---------------------- -------------------------------------- + Version 4 + Canonical (RFC 4122) d0a3a023-f515-4fe0-915c-575e63693998 + Base 58 SmHvuofV4GCF7QW543rDD9 + Base 32 6GMEG27X8N9ZG92Q2QBSHPJECR + ---------------------- -------------------------------------- + + $ php bin/console ulid:inspect 01F2TTCSYK1PDRH73Z41BN1C4X + --------------------- -------------------------------------- + Label Value + --------------------- -------------------------------------- + Canonical (Base 32) 01F2TTCSYK1PDRH73Z41BN1C4X + Base 58 1BYGm16jS4kX3VYCysKKq6 + RFC 4122 0178b5a6-67d3-0d9b-889c-7f205750b09d + --------------------- -------------------------------------- + Timestamp 2021-04-09 08:01:24.947 + --------------------- -------------------------------------- + .. _`unique identifiers`: https://en.wikipedia.org/wiki/UID .. _`UUIDs`: https://en.wikipedia.org/wiki/Universally_unique_identifier .. _`ULIDs`: https://github.com/ulid/spec From d784895ac3995c4999b0e5a31554d709cd8417e7 Mon Sep 17 00:00:00 2001 From: Hugo Monteiro Date: Sat, 4 Apr 2020 19:28:30 +0100 Subject: [PATCH 0901/1519] [Messenger] Multiple failed transports --- messenger.rst | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/messenger.rst b/messenger.rst index 77e0ae8f8e2..ae53e5d734b 100644 --- a/messenger.rst +++ b/messenger.rst @@ -865,6 +865,110 @@ If the message fails again, it will be re-sent back to the failure transport due to the normal :ref:`retry rules `. Once the max retry has been hit, the message will be discarded permanently. +Multiple Failed Transports +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes it is not enough to have a single, global ``failed transport`` configured +because some messages are more important than others. In those cases, you can +override the failure transport for only specific transports: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/messenger.yaml + framework: + messenger: + # after retrying, messages will be sent to the "failed" transport + # by default if no "failed_transport" is configured inside a transport + failure_transport: failed_default + + transports: + async_priority_high: + dsn: '%env(MESSENGER_TRANSPORT_DSN)%' + failure_transport: failed_high_priority + + # since no failed transport is configured, the one used will be + # the global "failure_transport" set + async_priority_low: + dsn: 'doctrine://default?queue_name=async_priority_low' + + failed_default: 'doctrine://default?queue_name=failed_default' + failed_high_priority: 'doctrine://default?queue_name=failed_high_priority' + + .. code-block:: xml + + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/messenger.php + $container->loadFromExtension('framework', [ + 'messenger' => [ + // after retrying, messages will be sent to the "failed" transport + // by default if no "failure_transport" is configured inside a transport + 'failure_transport' => 'failed_default', + + 'transports' => [ + 'async_priority_high' => [ + 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', + 'failure_transport' => 'failed_high_priority' + ], + // since no failed transport is configured, the one used will be + // the global failure_transport set + 'async_priority_low' => [ + 'dsn' => 'doctrine://default?queue_name=async_priority_low', + ], + 'failed_default' => [ + 'dsn' => 'doctrine://default?queue_name=failed_default', + ], + 'failed_high_priority' => [ + 'dsn' => 'doctrine://default?queue_name=failed_high_priority', + ], + ], + ], + ]); + +If there is no ``failure_transport`` defined globally or on the transport level, +the messages will be discarded after the number of retries. + +The failed commands have an optional option ``--transport`` to specify +the ``failure_transport`` configured at the transport level. + +.. code-block:: terminal + + # see all messages in "failure_transport" transport + $ php bin/console messenger:failed:show --transport=failure_transport + + # retry specific messages from "failure_transport" + $ php bin/console messenger:failed:retry 20 30 --transport=failure_transport --force + + # remove a message without retrying it from "failure_transport" + $ php bin/console messenger:failed:remove 20 --transport=failure_transport + .. _messenger-transports-config: Transport Configuration From 496a282b76a5e1cb1d9031794ae8f83814e33c6a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 20 Apr 2021 17:59:15 +0200 Subject: [PATCH 0902/1519] Added the versionadded directive --- messenger.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/messenger.rst b/messenger.rst index 2cb3361c483..4a68b0dc2a7 100644 --- a/messenger.rst +++ b/messenger.rst @@ -875,6 +875,10 @@ retry has been hit, the message will be discarded permanently. Multiple Failed Transports ~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. versionadded:: 5.3 + + The possibility to use multiple failed transports was introduced in Symfony 5.3. + Sometimes it is not enough to have a single, global ``failed transport`` configured because some messages are more important than others. In those cases, you can override the failure transport for only specific transports: From 8680173ac5339cbecdaab3444f3425551e627ab7 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Mon, 19 Apr 2021 18:08:33 +0200 Subject: [PATCH 0903/1519] Start using ConfigBuilder --- forms.rst | 20 ++++++++++---------- routing.rst | 11 +++++------ serializer.rst | 11 +++++------ session.rst | 32 ++++++++++++++++++-------------- templates.rst | 38 +++++++++++++++++++++----------------- 5 files changed, 59 insertions(+), 53 deletions(-) diff --git a/forms.rst b/forms.rst index c5e41222104..b6c63773452 100644 --- a/forms.rst +++ b/forms.rst @@ -345,13 +345,13 @@ can set this option to generate forms compatible with the Bootstrap 4 CSS framew .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ - 'form_themes' => [ - 'bootstrap_4_layout.html.twig', - ], + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { + $twig->formThemes(['bootstrap_4_layout.html.twig']); // ... - ]); + }; The :ref:`built-in Symfony form themes ` include Bootstrap 3 and 4 as well as Foundation 5 and 6. You can also @@ -627,11 +627,11 @@ these new messages set the ``legacy_error_messages`` option to ``false``: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'form' => [ - 'legacy_error_messages' => false, - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->form()->legacyErrorMessages(false); + }; Other Common Form Features -------------------------- diff --git a/routing.rst b/routing.rst index 9aad1ac3c58..487d2ecc587 100644 --- a/routing.rst +++ b/routing.rst @@ -2508,12 +2508,11 @@ The solution is to configure the ``default_uri`` option to define the .. code-block:: php // config/packages/routing.php - $container->loadFromExtension('framework', [ - 'router' => [ - // ... - 'default_uri' => "https://example.org/my/path/", - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->router()->defaultUri('https://example.org/my/path/'); + }; .. versionadded:: 5.1 diff --git a/serializer.rst b/serializer.rst index 980bf5708ab..8cae58c5838 100644 --- a/serializer.rst +++ b/serializer.rst @@ -259,12 +259,11 @@ value: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - // ... - 'serializer' => [ - 'name_converter' => 'serializer.name_converter.camel_case_to_snake_case', - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->serializer()->nameConverter('serializer.name_converter.camel_case_to_snake_case'); + }; Going Further with the Serializer --------------------------------- diff --git a/session.rst b/session.rst index 5a3fb69c09b..8f3fba95b30 100644 --- a/session.rst +++ b/session.rst @@ -55,18 +55,20 @@ sessions, check their default configuration: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'session' => [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->session() // enables the support of sessions in the app - 'enabled' => true, + ->enabled(true) // ID of the service used for session storage // NULL means that Symfony uses PHP default session mechanism - 'handler_id' => null, + ->handlerId(null) // improves the security of the cookies used for sessions - 'cookie_secure' => 'auto', - 'cookie_samesite' => 'lax', - ], - ]); + ->cookieSecure('auto') + ->cookieSamesite('lax') + ; + }; Setting the ``handler_id`` config option to ``null`` means that Symfony will use the native PHP session mechanism. The session metadata files will be stored @@ -112,13 +114,15 @@ session metadata files: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'session' => [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->session() // ... - 'handler_id' => 'session.handler.native_file', - 'save_path' => '%kernel.project_dir%/var/sessions/%kernel.environment%', - ], - ]); + ->handlerId('session.handler.native_file') + ->savePath('%kernel.project_dir%/var/sessions/%kernel.environment%') + ; + }; Check out the Symfony config reference to learn more about the other available :ref:`Session configuration options `. You can also diff --git a/templates.rst b/templates.rst index 9f1f5233b34..af18a438484 100644 --- a/templates.rst +++ b/templates.rst @@ -824,10 +824,12 @@ template fragments. Configure that special URL in the ``fragments`` option: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'fragments' => ['path' => '/_fragment'], - ]); + $framework->fragments()->path('/_fragment'); + }; .. caution:: @@ -1043,15 +1045,16 @@ the ``value`` is the Twig namespace, which is explained later: .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { // ... - 'paths' => [ - // directories are relative to the project root dir (but you - // can also use absolute directories) - 'email/default/templates' => null, - 'backend/templates' => null, - ], - ]); + + // directories are relative to the project root dir (but you + // can also use absolute directories) + $twig->path('email/default/templates', null); + $twig->path('backend/templates', null); + }; When rendering a template, Symfony looks for it first in the ``twig.paths`` directories that don't define a namespace and then falls back to the default @@ -1098,13 +1101,14 @@ configuration to define a namespace for each template directory: .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { // ... - 'paths' => [ - 'email/default/templates' => 'email', - 'backend/templates' => 'admin', - ], - ]); + + $twig->path('email/default/templates', 'email'); + $twig->path('backend/templates', 'admin'); + }; Now, if you render the ``layout.html.twig`` template, Symfony will render the ``templates/layout.html.twig`` file. Use the special syntax ``@`` + namespace to From 4933d453413a9c523abec68fd8a0df04c8f25d11 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Tue, 2 Mar 2021 15:04:43 +0100 Subject: [PATCH 0904/1519] [RateLimiter][Security] More precisely document advanced rate limiter configuration --- cache.rst | 2 + lock.rst | 2 + rate_limiter.rst | 243 ++++++++++++++++++++++++++++++++++++++++------- security.rst | 144 ++++++++++++++++++++++++++-- 4 files changed, 347 insertions(+), 44 deletions(-) diff --git a/cache.rst b/cache.rst index a5e20950c03..ee32fcc2db2 100644 --- a/cache.rst +++ b/cache.rst @@ -183,6 +183,8 @@ will create pools with service IDs that follow the pattern ``cache.[type]``. ], ]); +.. _cache-create-pools: + Creating Custom (Namespaced) Pools ---------------------------------- diff --git a/lock.rst b/lock.rst index 6a62c558fd7..db987f1d20e 100644 --- a/lock.rst +++ b/lock.rst @@ -228,6 +228,8 @@ processes asking for the same ``$version``:: } } +.. _lock-named-locks: + Named Lock ---------- diff --git a/rate_limiter.rst b/rate_limiter.rst index 99617f20d59..1f900547ea7 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -124,20 +124,74 @@ Configuration The following example creates two different rate limiters for an API service, to enforce different levels of service (free or paid): -.. code-block:: yaml - - # config/packages/rate_limiter.yaml - framework: - rate_limiter: - anonymous_api: - # use 'sliding_window' if you prefer that policy - policy: 'fixed_window' - limit: 100 - interval: '60 minutes' - authenticated_api: - policy: 'token_bucket' - limit: 5000 - rate: { interval: '15 minutes', amount: 500 } +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/rate_limiter.yaml + framework: + rate_limiter: + anonymous_api: + # use 'sliding_window' if you prefer that policy + policy: 'fixed_window' + limit: 100 + interval: '60 minutes' + authenticated_api: + policy: 'token_bucket' + limit: 5000 + rate: { interval: '15 minutes', amount: 500 } + + .. code-block:: xml + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/rate_limiter.php + $container->loadFromExtension('framework', [ + rate_limiter' => [ + 'anonymous_api' => [ + // use 'sliding_window' if you prefer that policy + 'policy' => 'fixed_window', + 'limit' => 100, + 'interval' => '60 minutes', + ], + 'authenticated_api' => [ + 'policy' => 'token_bucket', + 'limit' => 5000, + 'rate' => [ 'interval' => '15 minutes', 'amount' => 500 ], + ], + ], + ]); .. note:: @@ -300,27 +354,146 @@ the :class:`Symfony\\Component\\RateLimiter\\Reservation` object returned by the } } -Rate Limiter Storage and Locking --------------------------------- - -Rate limiters use the default cache and locking mechanisms defined in your -Symfony application. If you prefer to change that, use the ``lock_factory`` and -``storage_service`` options: - -.. code-block:: yaml - - # config/packages/rate_limiter.yaml - framework: - rate_limiter: - anonymous_api_limiter: - # ... - # the value is the name of any cache pool defined in your application - cache_pool: 'app.redis_cache' - # or define a service implementing StorageInterface to use a different - # mechanism to store the limiter information - storage_service: 'App\RateLimiter\CustomRedisStorage' - # the value is the name of any lock defined in your application - lock_factory: 'app.rate_limiter_lock' +Storing Rate Limiter State: Caching +----------------------------------- + +All rate limiter policies require to store the state of the rate limiter +(e.g. how many hits were already made in the current time window). This +state is stored by default using the :doc:`Cache component `. + +The default cache pool used by all limiters is ``cache.rate_limiter``. You +can modify this cache pool by :ref:`defining a "rate_limiter" pool `. + +You can also override the pool for a specific limiter using the ``cache_pool`` +option: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/rate_limiter.yaml + framework: + rate_limiter: + anonymous_api: + # ... + + # use the "cache.anonymous_rate_limiter" cache pool + cache_pool: 'cache.anonymous_rate_limiter' + + .. code-block:: xml + + + + + + + + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/rate_limiter.php + $container->loadFromExtension('framework', [ + rate_limiter' => [ + 'anonymous_api' => [ + // ... + + // use the "lock.rate_limiter.factory" for this limiter + 'lock_factory' => 'lock.rate_limiter.factory', + ], + ], + ]); .. _`DoS attacks`: https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html .. _`Apache mod_ratelimit`: https://httpd.apache.org/docs/current/mod/mod_ratelimit.html diff --git a/security.rst b/security.rst index 3b9341a07d6..ea7896e8040 100644 --- a/security.rst +++ b/security.rst @@ -550,11 +550,6 @@ You must enable this using the ``login_throttling`` setting: 'login_throttling' => [ 'max_attempts' => 3, ], - - // use a custom rate limiter via its service ID - 'login_throttling' => [ - 'limiter' => 'app.my_login_rate_limiter', - ], ], ], ]); @@ -565,10 +560,6 @@ failed requests for ``IP address``. The second limit protects against an attacker using multiple usernames from bypassing the first limit, without distrupting normal users on big networks (such as offices). -If you need a more complex limiting algorithm, create a class that implements -:class:`Symfony\\Component\\HttpFoundation\\RateLimiter\\RequestRateLimiterInterface` -and set the ``limiter`` option to its service ID. - .. tip:: Limiting the failed login attempts is only one basic protection against @@ -576,6 +567,141 @@ and set the ``limiter`` option to its service ID. several other protections that you should consider depending on the level of protection required. +If you need a more complex limiting algorithm, create a class that implements +:class:`Symfony\\Component\\HttpFoundation\\RateLimiter\\RequestRateLimiterInterface` +(or use +:class:`Symfony\\Component\\Security\\Http\\RateLimiter\\DefaultLoginRateLimiter`) +and set the ``limiter`` option to its service ID: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + framework: + rate_limiter: + # define 2 rate limiters (one for username+IP, the other for IP) + username_ip_login: + policy: token_bucket + limit: 5 + rate: { interval: '5 minutes' } + + ip_login: + policy: sliding_window + limit: 50 + interval: '15 minutes' + + services: + # our custom login rate limiter + app.login_rate_limiter: + class: Symfony\Component\Security\Http\RateLimiter\DefaultLoginRateLimiter + arguments: + # globalFactory is the limiter for IP + $globalFactory: '@limiter.ip_login' + # localFactory is the limiter for username+IP + $localFactory: '@limiter.username_ip_login' + + security: + firewalls: + main: + # use a custom rate limiter via its service ID + login_throttling: + limiter: app.login_rate_limiter + + .. code-block:: xml + + + + + + + + + + + + + + + + + + + + + + <1-- 2nd argument is the limiter for username+IP --> + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Component\DependencyInjection\Reference; + use Symfony\Component\Security\Http\RateLimiter\DefaultLoginRateLimiter; + + $container->loadFromExtension('framework', [ + 'rate_limiter' => [ + // define 2 rate limiters (one for username+IP, the other for IP) + 'username_ip_login' => [ + 'policy' => 'token_bucket', + 'limit' => 5, + 'rate' => [ 'interval' => '5 minutes' ], + ], + 'ip_login' => [ + 'policy' => 'sliding_window', + 'limit' => 50, + 'interval' => '15 minutes', + ], + ], + ]); + + $container->register('app.login_rate_limiter', DefaultLoginRateLimiter::class) + ->setArguments([ + // 1st argument is the limiter for IP + new Reference('limiter.ip_login'), + // 2nd argument is the limiter for username+IP + new Reference('limiter.username_ip_login'), + ]); + + $container->loadFromExtension('security', [ + 'firewalls' => [ + 'main' => [ + // use a custom rate limiter via its service ID + 'login_throttling' => + 'limiter' => 'app.login_rate_limiter', + ], + ], + ], + ]); + .. _`security-authorization`: .. _denying-access-roles-and-other-authorization: From 5a67b62fbc7d2f592f0200371e1a20f8b9eab104 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 21 Apr 2021 10:07:05 +0200 Subject: [PATCH 0905/1519] Minor rewords --- rate_limiter.rst | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index 67bf6b00070..c95b96161a4 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -356,18 +356,15 @@ the :class:`Symfony\\Component\\RateLimiter\\Reservation` object returned by the } } -Storing Rate Limiter State: Caching ------------------------------------ +Storing Rate Limiter State +-------------------------- -All rate limiter policies require to store the state of the rate limiter -(e.g. how many hits were already made in the current time window). This -state is stored by default using the :doc:`Cache component `. +All rate limiter policies require to store their state(e.g. how many hits were +already made in the current time window). By default, all limiters use the +``cache.rate_limiter`` cache pool created with the :doc:`Cache component `. -The default cache pool used by all limiters is ``cache.rate_limiter``. You -can modify this cache pool by :ref:`defining a "rate_limiter" pool `. - -You can also override the pool for a specific limiter using the ``cache_pool`` -option: +Use the ``cache_pool`` option to override the cache used by a specific limiter +(or even :ref:`create a new cache pool ` for it): .. configuration-block:: @@ -428,19 +425,19 @@ option: Instead of using the Cache component, you can also implement a custom storage. Create a PHP class that implements the :class:`Symfony\\Component\\RateLimiter\\Storage\\StorageInterface` and - set the ``storage_service`` setting of each limiter to the service ID + use the ``storage_service`` setting of each limiter to the service ID of this class. Using Locks to Prevent Race Conditions -------------------------------------- -Rate limiting can be affected by race conditions, if the same limiter is -applied to simultaneous requests (e.g. 3 servers of the same client call -the same API). To prevent these race conditions, the rate limiting -operations are protected using :doc:`locks `. +`Race conditions`_ can happen when the same rate limiter is used by multiple +simultaneous requests (e.g. three servers of a company hitting your API at the +same time). Rate limiters use :doc:`locks ` to protect their operations +against these race conditions. -By default, the global lock (configured by ``framework.lock``) is used. You -can use a specific :ref:`named lock ` via the +By default, Symfony uses the global lock configured by ``framework.lock``), but +you can use a specific :ref:`named lock ` via the ``lock_factory`` option: .. configuration-block:: @@ -502,3 +499,4 @@ can use a specific :ref:`named lock ` via the .. _`NGINX rate limiting`: https://www.nginx.com/blog/rate-limiting-nginx/ .. _`token bucket algorithm`: https://en.wikipedia.org/wiki/Token_bucket .. _`PHP date relative formats`: https://www.php.net/datetime.formats.relative +.. _`Race conditions`: https://en.wikipedia.org/wiki/Race_condition From 830b1f366d979e06bb6572a6c02540239b355060 Mon Sep 17 00:00:00 2001 From: roromix <16560617+roromix@users.noreply.github.com> Date: Sun, 28 Mar 2021 13:28:32 +0200 Subject: [PATCH 0906/1519] [Security] Customize generated Login Link --- security/login_link.rst | 48 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/security/login_link.rst b/security/login_link.rst index 4e1bfa2d3da..b4dc13444f0 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -739,3 +739,51 @@ Then, configure this service ID as the ``success_handler``: ], ], ]); + +Customize generated Login Link +------------------------------ + +.. versionadded:: 5.3 + + The possibility to customize the login link was introduced in Symfony 5.3. + +In some use cases it may be useful to customize the Login Link. In addition +to the ``UserInterface``, it is therefore possible to pass a ``Request`` to the ``createLoginLink`` +method. In this example, our route is localized with the user locale which may +be different from the current locale:: + + // src/Controller/SecurityController.php + namespace App\Controller; + + // ... + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\Security\Http\LoginLink\LoginLinkHandlerInterface; + + class SecurityController extends AbstractController + { + /** + * @Route("/login", name="login") + */ + public function requestLoginLink(LoginLinkHandlerInterface $loginLinkHandler, Request $request) + { + // check if login form is submitted + if ($request->isMethod('POST')) { + // ... load the user in some way + + // clone and customize Request + $userRequest = clone $request; + $userRequest->setLocale($user->getLocale() ?? $request->getDefaultLocale()); + + // create a login link for $user this returns an instance + // of LoginLinkDetails + $loginLinkDetails = $loginLinkHandler->createLoginLink($user, $userRequest); + $loginLink = $loginLinkDetails->getUrl(); + + // ... + } + + return $this->render('security/login.html.twig'); + } + + // ... + } From fd2958d5d1ae4ed7a6ab3f82058f5d86155d99d8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 21 Apr 2021 10:45:50 +0200 Subject: [PATCH 0907/1519] Tweaks --- security/login_link.rst | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/security/login_link.rst b/security/login_link.rst index b4dc13444f0..fb35b5885bd 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -740,17 +740,16 @@ Then, configure this service ID as the ``success_handler``: ], ]); -Customize generated Login Link ------------------------------- +Customizing the Login Link +-------------------------- .. versionadded:: 5.3 The possibility to customize the login link was introduced in Symfony 5.3. -In some use cases it may be useful to customize the Login Link. In addition -to the ``UserInterface``, it is therefore possible to pass a ``Request`` to the ``createLoginLink`` -method. In this example, our route is localized with the user locale which may -be different from the current locale:: +The ``createLoginLink()`` method accepts a second optional argument to pass the +``Request`` object used when generating the login link. This allows to customize +features such as the locale used to generate the link:: // src/Controller/SecurityController.php namespace App\Controller; @@ -774,8 +773,7 @@ be different from the current locale:: $userRequest = clone $request; $userRequest->setLocale($user->getLocale() ?? $request->getDefaultLocale()); - // create a login link for $user this returns an instance - // of LoginLinkDetails + // create a login link for $user (this returns an instance of LoginLinkDetails) $loginLinkDetails = $loginLinkHandler->createLoginLink($user, $userRequest); $loginLink = $loginLinkDetails->getUrl(); From 2382264aef232f28068efe4416575c7035eb831b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 21 Apr 2021 11:04:03 +0200 Subject: [PATCH 0908/1519] Reword --- security/login_link.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/security/login_link.rst b/security/login_link.rst index e1205e53a31..bc23d8c5817 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -740,4 +740,8 @@ Then, configure this service ID as the ``success_handler``: ], ]); -If you want to manage the failure for example the link is expires, use 'failure_handler' and implements "AuthenticationFailureHandlerInterface" instand of "AuthenticationSuccessHandlerInterface" +.. tip:: + + If you want to customize the default failure handling, use the + ``failure_handler`` option and create a class that implements + :class:`Symfony\\Component\\Security\\Http\\Authentication\\AuthenticationFailureHandlerInterface`. From aa7e3dde80f058c31d0abef0957582e5ea06e35f Mon Sep 17 00:00:00 2001 From: Nyholm Date: Wed, 21 Apr 2021 11:43:34 +0200 Subject: [PATCH 0909/1519] Fixed syntax errors on 5.x --- doctrine/events.rst | 4 +--- rate_limiter.rst | 8 ++++---- security.rst | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/doctrine/events.rst b/doctrine/events.rst index d130ce210e3..abe574a1867 100644 --- a/doctrine/events.rst +++ b/doctrine/events.rst @@ -454,8 +454,6 @@ with the ``doctrine.event_subscriber`` tag: - - @@ -475,7 +473,7 @@ with the ``doctrine.event_subscriber`` tag: // to the same event (default priority = 0; higher numbers = listener is run earlier) 'priority' => 500, - # you can also restrict listeners to a specific Doctrine connection + // you can also restrict listeners to a specific Doctrine connection 'connection' => 'default', ]) ; diff --git a/rate_limiter.rst b/rate_limiter.rst index c95b96161a4..2ab832d7031 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -178,7 +178,7 @@ enforce different levels of service (free or paid): // config/packages/rate_limiter.php $container->loadFromExtension('framework', [ - rate_limiter' => [ + 'rate_limiter' => [ 'anonymous_api' => [ // use 'sliding_window' if you prefer that policy 'policy' => 'fixed_window', @@ -401,7 +401,7 @@ Use the ``cache_pool`` option to override the cache used by a specific limiter cache-pool="cache.anonymous_rate_limiter" /> - @@ -410,7 +410,7 @@ Use the ``cache_pool`` option to override the cache used by a specific limiter // config/packages/rate_limiter.php $container->loadFromExtension('framework', [ - rate_limiter' => [ + 'rate_limiter' => [ 'anonymous_api' => [ // ... @@ -484,7 +484,7 @@ you can use a specific :ref:`named lock ` via the // config/packages/rate_limiter.php $container->loadFromExtension('framework', [ - rate_limiter' => [ + 'rate_limiter' => [ 'anonymous_api' => [ // ... diff --git a/security.rst b/security.rst index 1bf3cf2408e..e2a355a0217 100644 --- a/security.rst +++ b/security.rst @@ -712,7 +712,7 @@ and set the ``limiter`` option to its service ID: 'firewalls' => [ 'main' => [ // use a custom rate limiter via its service ID - 'login_throttling' => + 'login_throttling' => [ 'limiter' => 'app.login_rate_limiter', ], ], From 6a5957c8dc3b2ceeffeee88f5d9c1d3534f5d6be Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 21 Apr 2021 11:54:42 +0200 Subject: [PATCH 0910/1519] Fixed a XML code example --- security.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security.rst b/security.rst index d98506c8ee2..70928a65fd5 100644 --- a/security.rst +++ b/security.rst @@ -648,7 +648,7 @@ and set the ``limiter`` option to its service ID: > - <1-- 2nd argument is the limiter for username+IP --> + From 9d1216e6ced5031867aed987428b78bcfc0a95cf Mon Sep 17 00:00:00 2001 From: Nyholm Date: Wed, 21 Apr 2021 10:16:25 +0200 Subject: [PATCH 0911/1519] Fixed syntax error in 5.2 --- mailer.rst | 2 +- reference/dic_tags.rst | 4 ++-- security.rst | 1 - security/access_control.rst | 2 +- security/experimental_authenticators.rst | 1 + session/database.rst | 8 ++++---- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mailer.rst b/mailer.rst index 721e2144654..a42aecb1d01 100644 --- a/mailer.rst +++ b/mailer.rst @@ -247,7 +247,7 @@ configurable with the ``verify_peer`` option. Although it's not recommended to disable this verification for security reasons, it can be useful while developing the application or when using a self-signed certificate:: - $dsn = 'smtp://user:pass@smtp.example.com?verify_peer=0' + $dsn = 'smtp://user:pass@smtp.example.com?verify_peer=0'; .. versionadded:: 5.1 diff --git a/reference/dic_tags.rst b/reference/dic_tags.rst index 0aca3c91777..5a4716fd3e7 100644 --- a/reference/dic_tags.rst +++ b/reference/dic_tags.rst @@ -316,8 +316,8 @@ is restarted): $container ->register(SomeService::class) - ->addTag('container.preload', ['class' => SomeClass::class) - ->addTag('container.preload', ['class' => OtherClass::class) + ->addTag('container.preload', ['class' => SomeClass::class]) + ->addTag('container.preload', ['class' => OtherClass::class]) // ... ; diff --git a/security.rst b/security.rst index d98506c8ee2..738e35474ea 100644 --- a/security.rst +++ b/security.rst @@ -368,7 +368,6 @@ important section is ``firewalls``: - diff --git a/security/access_control.rst b/security/access_control.rst index 95c57f15a85..2f65dc60281 100644 --- a/security/access_control.rst +++ b/security/access_control.rst @@ -65,7 +65,7 @@ Take the following ``access_control`` entries as an example: https://symfony.com/schema/dic/security/security-1.0.xsd"> - 10.0.0.1, 10.0.0.2 + 10.0.0.1, 10.0.0.2 diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index 269aefe01a0..b7734ef88e0 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -226,6 +226,7 @@ You can configure this using the ``entry_point`` setting: + diff --git a/session/database.rst b/session/database.rst index 71f85e73efc..4aa1bcb4532 100644 --- a/session/database.rst +++ b/session/database.rst @@ -90,7 +90,7 @@ and ``RedisProxy``: arguments: - '@Redis' # you can optionally pass an array of options. The only options are 'prefix' and 'ttl', - # which define the prefix to use for the keys to avoid collision on the Redis server + # which define the prefix to use for the keys to avoid collision on the Redis server # and the expiration time for any given entry (in seconds), defaults are 'sf_s' and null: # - { 'prefix' => 'my_prefix', 'ttl' => 600 } @@ -101,7 +101,7 @@ and ``RedisProxy``: + diff --git a/session/database.rst b/session/database.rst index 71f85e73efc..4aa1bcb4532 100644 --- a/session/database.rst +++ b/session/database.rst @@ -90,7 +90,7 @@ and ``RedisProxy``: arguments: - '@Redis' # you can optionally pass an array of options. The only options are 'prefix' and 'ttl', - # which define the prefix to use for the keys to avoid collision on the Redis server + # which define the prefix to use for the keys to avoid collision on the Redis server # and the expiration time for any given entry (in seconds), defaults are 'sf_s' and null: # - { 'prefix' => 'my_prefix', 'ttl' => 600 } @@ -101,7 +101,7 @@ and ``RedisProxy``: + + + + https://www.symfony.com + https://www.symfony.nl + + + + .. code-block:: php + + // config/routes/annotations.php + use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; + return function (RoutingConfigurator $routes) { + $routes->import('../../src/Controller/', 'annotation') + ->host([ + 'en' => 'https://www.symfony.com', + 'nl' => 'https://www.symfony.nl' + ]) + ; + }; + .. _stateless-routing: Stateless Routes From 2ca4b0a73f5f76c2a96b98c05557d847bee4b425 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 21 Apr 2021 14:41:57 +0200 Subject: [PATCH 0914/1519] Minor tweaks --- routing.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/routing.rst b/routing.rst index 5e2d9475cd9..4a05acaf613 100644 --- a/routing.rst +++ b/routing.rst @@ -2232,8 +2232,8 @@ locale. resource: '../../src/Controller/' type: annotation host: - en: 'https://www.symfony.com' - nl: 'https://www.symfony.nl' + en: 'https://www.example.com' + nl: 'https://www.example.nl' .. code-block:: xml @@ -2244,8 +2244,8 @@ locale. xsi:schemaLocation="http://symfony.com/schema/routing https://symfony.com/schema/routing/routing-1.0.xsd"> - https://www.symfony.com - https://www.symfony.nl + https://www.example.com + https://www.example.nl @@ -2256,8 +2256,8 @@ locale. return function (RoutingConfigurator $routes) { $routes->import('../../src/Controller/', 'annotation') ->host([ - 'en' => 'https://www.symfony.com', - 'nl' => 'https://www.symfony.nl' + 'en' => 'https://www.example.com', + 'nl' => 'https://www.example.nl' ]) ; }; From dc6872c47103671b037e6f65ac61f90b405ede84 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 21 Apr 2021 15:03:53 +0200 Subject: [PATCH 0915/1519] Tweaks --- messenger.rst | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/messenger.rst b/messenger.rst index f5cbb546adc..e66e5219896 100644 --- a/messenger.rst +++ b/messenger.rst @@ -628,17 +628,16 @@ times: Change the ``async`` argument to use the name of your transport (or transports) and ``user`` to the Unix user on your server. -If you use the Redis Transport, note that each worker needs a unique consumer name to -avoid the same message being handled by multiple workers. One way to achieve this is -to set an environment variable in the Supervisor configuration file, which you can -then refer to in `messenger.yaml` (see Redis section above): +If you use the Redis Transport, note that each worker needs a unique consumer +name to avoid the same message being handled by multiple workers. One way to +achieve this is to set an environment variable in the Supervisor configuration +file, which you can then refer to in ``messenger.yaml`` (see Redis section above): .. code-block:: ini environment=MESSENGER_CONSUMER_NAME=%(program_name)s_%(process_num)02d -Next, tell Supervisor to read your -config and start your workers: +Next, tell Supervisor to read your config and start your workers: .. code-block:: terminal @@ -1251,9 +1250,9 @@ claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) There should never be more than one ``messenger:consume`` command running with the same combination of ``stream``, ``group`` and ``consumer``, or messages could end up being - handled more than once. If you run multiple queue workers, ``consumer` can be set to an - environment variable (like ``%env(MESSENGER_CONSUMER_NAME)%`)` set by Supervisor - (example below) or whatever service used to manage the worker processes. + handled more than once. If you run multiple queue workers, ``consumer`` can be set to an + environment variable (like ``%env(MESSENGER_CONSUMER_NAME)%``) set by Supervisor + (example below) or any other service used to manage the worker processes. In a container environment, the ``HOSTNAME`` can be used as the consumer name, since there is only one worker per container/host. If using Kubernetes to orchestrate the containers, consider using a ``StatefulSet`` to have stable names. From 60f5034bfd6cbccd31d49623426fe0b0dbaf44af Mon Sep 17 00:00:00 2001 From: Kamil Kubicki Date: Mon, 15 Jun 2020 17:35:20 +0200 Subject: [PATCH 0916/1519] Update direct_submit.rst Updating the rules for payload data submission - payload fields should equal FormType class describing the Form structure --- form/direct_submit.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/form/direct_submit.rst b/form/direct_submit.rst index 876ad3964b1..4ff676b39b4 100644 --- a/form/direct_submit.rst +++ b/form/direct_submit.rst @@ -59,3 +59,12 @@ control over when exactly your form is submitted and what data is passed to it:: // 'email' and 'username' are added manually to force their validation $form->submit(array_merge(['email' => null, 'username' => null], $request->request->all()), false); + +.. caution:: + + When submitting a form via a "POST" request and manually submitting the form + with ``submit()``, ensure that list of fields in payload equals the list of validated + fields in FormType class - in other case the form validation will fail. + + //'json' represents payload data (used frequently by api client as React/Angular/Vue etc.) + $form->submit(array_merge($json, $request->request->all())); From 4005b8ff66ac106832bf6958b79f6ffe05897717 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 21 Apr 2021 15:27:55 +0200 Subject: [PATCH 0917/1519] Reword --- form/direct_submit.rst | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/form/direct_submit.rst b/form/direct_submit.rst index 4ff676b39b4..92dc09c5de5 100644 --- a/form/direct_submit.rst +++ b/form/direct_submit.rst @@ -34,6 +34,24 @@ control over when exactly your form is submitted and what data is passed to it:: ]); } +The list of fields submitted with the ``submit()`` method must be the same as +the fields defined by the form class. Otherwise, you'll see a form validation error:: + + public function new(Request $request): Response + { + // ... + + if ($request->isMethod('POST')) { + // '$json' represents payload data sent by React/Angular/Vue + // the merge of parameters is needed to submit all form fields + $form->submit(array_merge($json, $request->request->all())); + + // ... + } + + // ... + } + .. tip:: Forms consisting of nested fields expect an array in @@ -59,12 +77,3 @@ control over when exactly your form is submitted and what data is passed to it:: // 'email' and 'username' are added manually to force their validation $form->submit(array_merge(['email' => null, 'username' => null], $request->request->all()), false); - -.. caution:: - - When submitting a form via a "POST" request and manually submitting the form - with ``submit()``, ensure that list of fields in payload equals the list of validated - fields in FormType class - in other case the form validation will fail. - - //'json' represents payload data (used frequently by api client as React/Angular/Vue etc.) - $form->submit(array_merge($json, $request->request->all())); From ddc406012c848976fd386d71188da628a30b21e0 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 21 Apr 2021 18:00:57 +0200 Subject: [PATCH 0918/1519] [Uid] Document the namespace string values --- components/uid.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index b4a14c52698..3402354c279 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -55,12 +55,12 @@ to create each type of UUID:: $uuid = Uuid::v3($namespace, $name); // $uuid is an instance of Symfony\Component\Uid\UuidV3 $uuid = Uuid::v5($namespace, $name); // $uuid is an instance of Symfony\Component\Uid\UuidV5 - // the namespaces defined by RFC 4122 are available as constants - // (see https://tools.ietf.org/html/rfc4122#appendix-C) - $uuid = Uuid::v3(Uuid::NAMESPACE_DNS, $name); - $uuid = Uuid::v3(Uuid::NAMESPACE_URL, $name); - $uuid = Uuid::v3(Uuid::NAMESPACE_OID, $name); - $uuid = Uuid::v3(Uuid::NAMESPACE_X500, $name); + // the namespaces defined by RFC 4122 (see https://tools.ietf.org/html/rfc4122#appendix-C) + // are available as PHP constants and as string values + $uuid = Uuid::v3(Uuid::NAMESPACE_DNS, $name); // same as: Uuid::v3('dns', $name); + $uuid = Uuid::v3(Uuid::NAMESPACE_URL, $name); // same as: Uuid::v3('url', $name); + $uuid = Uuid::v3(Uuid::NAMESPACE_OID, $name); // same as: Uuid::v3('oid', $name); + $uuid = Uuid::v3(Uuid::NAMESPACE_X500, $name); // same as: Uuid::v3('x500', $name); // UUID type 6 is not part of the UUID standard. It's lexicographically sortable // (like ULIDs) and contains a 60-bit timestamp and 63 extra unique bits. @@ -69,7 +69,8 @@ to create each type of UUID:: .. versionadded:: 5.3 - The ``Uuid::NAMESPACE_*`` constants were introduced in Symfony 5.3. + The ``Uuid::NAMESPACE_*`` constants and the namespace string values (``'dns'``, + ``'url'``, etc.) were introduced in Symfony 5.3. If your UUID value is already generated in another format, use any of the following methods to create a ``Uuid`` object from it:: From 14ea9c7bf36387cbc5f958d7238f84237171fe6c Mon Sep 17 00:00:00 2001 From: Nyholm Date: Wed, 21 Apr 2021 21:39:15 +0200 Subject: [PATCH 0919/1519] [ConfigBuilder] Adding PHP ConfigBuilders for DoctrineBundle --- configuration/secrets.rst | 13 ++-- doctrine/custom_dql_functions.rst | 51 ++++++--------- doctrine/dbal.rst | 28 ++++---- doctrine/multiple_entity_managers.rst | 92 ++++++++++++--------------- doctrine/resolve_target_entity.rst | 14 ++-- reference/configuration/doctrine.rst | 47 +++++++------- security/remember_me.rst | 12 ++-- 7 files changed, 119 insertions(+), 138 deletions(-) diff --git a/configuration/secrets.rst b/configuration/secrets.rst index 4f7e921163a..299d36326fc 100644 --- a/configuration/secrets.rst +++ b/configuration/secrets.rst @@ -138,11 +138,14 @@ If you stored a ``DATABASE_PASSWORD`` secret, you can reference it by: .. code-block:: php // config/packages/doctrine.php - $container->loadFromExtension('doctrine', [ - 'dbal' => [ - 'password' => '%env(DATABASE_PASSWORD)%', - ] - ]); + use Symfony\Config\DoctrineConfig; + + return static function (DoctrineConfig $doctrine) { + $doctrine->dbal() + ->connection('default') + ->password('%env(DATABASE_PASSWORD)%') + ; + }; The actual value will be resolved at runtime: container compilation and cache warmup don't need the **decryption key**. diff --git a/doctrine/custom_dql_functions.rst b/doctrine/custom_dql_functions.rst index ee11967da47..8643a3a643b 100644 --- a/doctrine/custom_dql_functions.rst +++ b/doctrine/custom_dql_functions.rst @@ -57,24 +57,19 @@ In Symfony, you can register your custom DQL functions as follows: use App\DQL\NumericFunction; use App\DQL\SecondStringFunction; use App\DQL\StringFunction; + use Symfony\Config\DoctrineConfig; - $container->loadFromExtension('doctrine', [ - 'orm' => [ - // ... - 'dql' => [ - 'string_functions' => [ - 'test_string' => StringFunction::class, - 'second_string' => SecondStringFunction::class, - ], - 'numeric_functions' => [ - 'test_numeric' => NumericFunction::class, - ], - 'datetime_functions' => [ - 'test_datetime' => DatetimeFunction::class, - ], - ], - ], - ]); + return static function (DoctrineConfig $doctrine) { + $defaultDql = $doctrine->orm() + ->entityManager('default') + // ... + ->dql(); + + $defaultDql->stringFunction('test_string', StringFunction::class); + $defaultDql->stringFunction('second_string', SecondStringFunction::class); + $defaultDql->numericFunction('test_numeric', NumericFunction::class); + $defaultDql->datetimeFunction('test_datetime', DatetimeFunction::class); + }; .. note:: @@ -129,21 +124,15 @@ In Symfony, you can register your custom DQL functions as follows: // config/packages/doctrine.php use App\DQL\DatetimeFunction; + use Symfony\Config\DoctrineConfig; - $container->loadFromExtension('doctrine', [ - 'orm' => [ + return static function (DoctrineConfig $doctrine) { + $doctrine->orm() // ... - 'entity_managers' => [ - 'example_manager' => [ - // place your functions here - 'dql' => [ - 'datetime_functions' => [ - 'test_datetime' => DatetimeFunction::class, - ], - ], - ], - ], - ], - ]); + ->entityManager('example_manager') + // place your functions here + ->dql() + ->datetimeFunction('test_datetime', DatetimeFunction::class); + }; .. _`DQL User Defined Functions`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/cookbook/dql-user-defined-functions.html diff --git a/doctrine/dbal.rst b/doctrine/dbal.rst index 80c145d3d6a..e330fd85732 100644 --- a/doctrine/dbal.rst +++ b/doctrine/dbal.rst @@ -105,15 +105,13 @@ mapping types, read Doctrine's `Custom Mapping Types`_ section of their document // config/packages/doctrine.php use App\Type\CustomFirst; use App\Type\CustomSecond; + use Symfony\Config\DoctrineConfig; - $container->loadFromExtension('doctrine', [ - 'dbal' => [ - 'types' => [ - 'custom_first' => CustomFirst::class, - 'custom_second' => CustomSecond::class, - ], - ], - ]); + return static function (DoctrineConfig $doctrine) { + $dbal = $doctrine->dbal(); + $dbal->type('custom_first')->class(CustomFirst::class); + $dbal->type('custom_second')->class(CustomSecond::class); + }; Registering custom Mapping Types in the SchemaTool -------------------------------------------------- @@ -156,13 +154,13 @@ mapping type: .. code-block:: php // config/packages/doctrine.php - $container->loadFromExtension('doctrine', [ - 'dbal' => [ - 'mapping_types' => [ - 'enum' => 'string', - ], - ], - ]); + use Symfony\Config\DoctrineConfig; + + return static function (DoctrineConfig $doctrine) { + $dbalDefault = $doctrine->dbal() + ->connection('default'); + $dbalDefault->mappingType('enum', 'string'); + }; .. _`PDO`: https://www.php.net/pdo .. _`Doctrine`: https://www.doctrine-project.org/ diff --git a/doctrine/multiple_entity_managers.rst b/doctrine/multiple_entity_managers.rst index a78309eb607..ca18e658845 100644 --- a/doctrine/multiple_entity_managers.rst +++ b/doctrine/multiple_entity_managers.rst @@ -128,57 +128,47 @@ The following configuration code shows how you can configure two entity managers .. code-block:: php // config/packages/doctrine.php - $container->loadFromExtension('doctrine', [ - 'dbal' => [ - 'default_connection' => 'default', - 'connections' => [ - // configure these for your database server - 'default' => [ - 'url' => '%env(resolve:DATABASE_URL)%', - 'driver' => 'pdo_mysql', - 'server_version' => '5.7', - 'charset' => 'utf8mb4', - ], - // configure these for your database server - 'customer' => [ - 'url' => '%env(resolve:DATABASE_CUSTOMER_URL)%', - 'driver' => 'pdo_mysql', - 'server_version' => '5.7', - 'charset' => 'utf8mb4', - ], - ], - ], - - 'orm' => [ - 'default_entity_manager' => 'default', - 'entity_managers' => [ - 'default' => [ - 'connection' => 'default', - 'mappings' => [ - 'Main' => [ - 'is_bundle' => false, - 'type' => 'annotation', - 'dir' => '%kernel.project_dir%/src/Entity/Main', - 'prefix' => 'App\Entity\Main', - 'alias' => 'Main', - ] - ], - ], - 'customer' => [ - 'connection' => 'customer', - 'mappings' => [ - 'Customer' => [ - 'is_bundle' => false, - 'type' => 'annotation', - 'dir' => '%kernel.project_dir%/src/Entity/Customer', - 'prefix' => 'App\Entity\Customer', - 'alias' => 'Customer', - ] - ], - ], - ], - ], - ]); + use Symfony\Config\DoctrineConfig; + + return static function (DoctrineConfig $doctrine) { + $doctrine->dbal()->defaultConnection('default'); + + // configure these for your database server + $doctrine->dbal() + ->connection('default') + ->url('%env(resolve:DATABASE_URL)%') + ->driver('pdo_mysql') + ->serverVersion('5.7') + ->charset('utf8mb4'); + + // configure these for your database server + $doctrine->dbal() + ->connection('customer') + ->url('%env(resolve:DATABASE_CUSTOMER_URL)%') + ->driver('pdo_mysql') + ->serverVersion('5.7') + ->charset('utf8mb4'); + + $doctrine->orm()->defaultEntityManager('default'); + $emDefault = $doctrine->orm()->entityManager('default'); + $emDefault->connection('default'); + $emDefault->mapping('Main') + ->isBundle(false) + ->type('annotation') + ->dir('%kernel.project_dir%/src/Entity/Main') + ->prefix('App\Entity\Main') + ->alias('Main'); + + $emCustomer = $doctrine->orm()->entityManager('customer'); + $emCustomer->connection('customer'); + $emCustomer->mapping('Customer') + ->isBundle(false) + ->type('annotation') + ->dir('%kernel.project_dir%/src/Entity/Customer') + ->prefix('App\Entity\Customer') + ->alias('Customer') + ; + }; In this case, you've defined two entity managers and called them ``default`` and ``customer``. The ``default`` entity manager manages entities in the diff --git a/doctrine/resolve_target_entity.rst b/doctrine/resolve_target_entity.rst index 765f5d187ce..f16ca7421e5 100644 --- a/doctrine/resolve_target_entity.rst +++ b/doctrine/resolve_target_entity.rst @@ -139,15 +139,13 @@ about the replacement: // config/packages/doctrine.php use App\Entity\Customer; use App\Model\InvoiceSubjectInterface; + use Symfony\Config\DoctrineConfig; - $container->loadFromExtension('doctrine', [ - 'orm' => [ - // ... - 'resolve_target_entities' => [ - InvoiceSubjectInterface::class => Customer::class, - ], - ], - ]); + return static function (DoctrineConfig $doctrine) { + $orm = $doctrine->orm(); + // ... + $orm->resolveTargetEntity(InvoiceSubjectInterface::class, Customer::class); + }; Final Thoughts -------------- diff --git a/reference/configuration/doctrine.rst b/reference/configuration/doctrine.rst index 226316012d1..b097a15a548 100644 --- a/reference/configuration/doctrine.rst +++ b/reference/configuration/doctrine.rst @@ -345,14 +345,17 @@ directory instead: .. code-block:: php - $container->loadFromExtension('doctrine', [ - 'orm' => [ - 'auto_mapping' => true, - 'mappings' => [ - 'AppBundle' => ['dir' => 'SomeResources/config/doctrine', 'type' => 'xml'], - ], - ], - ]); + use Symfony\Config\DoctrineConfig; + + return static function (DoctrineConfig $doctrine) { + $emDefault = $doctrine->orm()->entityManager('default'); + + $emDefault->autoMapping(true); + $emDefault->mapping('AppBundle') + ->type('xml') + ->dir('SomeResources/config/doctrine') + ; + }; Mapping Entities Outside of a Bundle ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -402,20 +405,20 @@ namespace in the ``src/Entity`` directory and gives them an ``App`` alias .. code-block:: php - $container->loadFromExtension('doctrine', [ - 'orm' => [ - 'auto_mapping' => true, - 'mappings' => [ - 'SomeEntityNamespace' => [ - 'type' => 'annotation', - 'dir' => '%kernel.project_dir%/src/Entity', - 'is_bundle' => false, - 'prefix' => 'App\Entity', - 'alias' => 'App', - ], - ], - ], - ]); + use Symfony\Config\DoctrineConfig; + + return static function (DoctrineConfig $doctrine) { + $emDefault = $doctrine->orm()->entityManager('default'); + + $emDefault->autoMapping(true); + $emDefault->mapping('SomeEntityNamespace') + ->type('annotation') + ->dir('%kernel.project_dir%/src/Entity') + ->isBundle(false) + ->prefix('App\Entity') + ->alias('App') + ; + }; Detecting a Mapping Configuration Format ........................................ diff --git a/security/remember_me.rst b/security/remember_me.rst index 20ac93897c3..4f0af428361 100644 --- a/security/remember_me.rst +++ b/security/remember_me.rst @@ -289,13 +289,13 @@ so ``DoctrineTokenProvider`` can store the tokens: .. code-block:: php # config/packages/doctrine.php - $container->loadFromExtension('doctrine', [ - 'dbal' => [ - 'schema_filter' => '~^(?!rememberme_token)~', - // ... - ], + use Symfony\Config\DoctrineConfig; + + return static function (DoctrineConfig $doctrine) { + $dbalDefault = $doctrine->dbal()->connection('default'); // ... - ]); + $dbalDefault->schemaFilter('~^(?!rememberme_token)~'); + }; Finally, set the ``token_provider`` option of the ``remember_me`` config to the service you created before: From 28d3a5665543629687e7912c653f8c76e3d8644b Mon Sep 17 00:00:00 2001 From: Nyholm Date: Wed, 21 Apr 2021 22:00:34 +0200 Subject: [PATCH 0920/1519] [Twig] [ConfigBuilder] Use ConfigBuilder for TwigBundle --- .../front_controllers_and_kernel.rst | 9 ++++--- configuration/override_dir_structure.rst | 8 +++--- form/bootstrap4.rst | 10 +++---- form/create_custom_field_type.rst | 10 ++++--- form/form_themes.rst | 22 ++++++++++------ mailer.rst | 26 ++++++++++--------- reference/configuration/twig.rst | 24 ++++++++++------- templating/global_variables.rst | 22 +++++++++------- testing.rst | 8 +++--- 9 files changed, 81 insertions(+), 58 deletions(-) diff --git a/configuration/front_controllers_and_kernel.rst b/configuration/front_controllers_and_kernel.rst index fe3c8179ed0..47d8bcfa686 100644 --- a/configuration/front_controllers_and_kernel.rst +++ b/configuration/front_controllers_and_kernel.rst @@ -190,10 +190,13 @@ parameter used, for example, to turn Twig's debug mode on: .. code-block:: php - $container->loadFromExtension('twig', [ - 'debug' => '%kernel.debug%', + // config/packages/twig.php + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { // ... - ]); + $twig->debug('%kernel.debug%'); + }; The Environments ---------------- diff --git a/configuration/override_dir_structure.rst b/configuration/override_dir_structure.rst index 03ed8bcbe41..fef0d7756fb 100644 --- a/configuration/override_dir_structure.rst +++ b/configuration/override_dir_structure.rst @@ -140,9 +140,11 @@ for multiple directories): .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ - 'default_path' => '%kernel.project_dir%/resources/views', - ]); + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { + $twig->defaultPath('%kernel.project_dir%/resources/views'); + }; Override the Translations Directory ----------------------------------- diff --git a/form/bootstrap4.rst b/form/bootstrap4.rst index 6f3b878ed1b..34b83b6a203 100644 --- a/form/bootstrap4.rst +++ b/form/bootstrap4.rst @@ -55,13 +55,13 @@ configuration: .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ - 'form_themes' => [ - 'bootstrap_4_layout.html.twig', - ], + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { + $twig->formThemes(['bootstrap_4_layout.html.twig']); // ... - ]); + }; If you prefer to apply the Bootstrap styles on a form to form basis, include the ``form_theme`` tag in the templates where those forms are used: diff --git a/form/create_custom_field_type.rst b/form/create_custom_field_type.rst index 248818aa6d3..c95a0c80880 100644 --- a/form/create_custom_field_type.rst +++ b/form/create_custom_field_type.rst @@ -405,12 +405,14 @@ rest of files): .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ - 'form_themes' => [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { + $twig->formThemes([ 'form/custom_types.html.twig', '...', - ], - ]); + ]); + }; The last step is to create the actual Twig template that will render the type. The template contents depend on which HTML, CSS and JavaScript frameworks and diff --git a/form/form_themes.rst b/form/form_themes.rst index 927da208176..cdcb1cb2e2c 100644 --- a/form/form_themes.rst +++ b/form/form_themes.rst @@ -88,12 +88,15 @@ want to use another theme for all the forms of your app, configure it in the .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ - 'form_themes' => [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { + $twig->formThemes([ 'bootstrap_4_horizontal_layout.html.twig', - ], + ]); + // ... - ]); + }; You can pass multiple themes to this option because sometimes form themes only redefine a few elements. This way, if some theme doesn't override some element, @@ -514,12 +517,15 @@ you want to apply the theme globally to all forms, define the .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ - 'form_themes' => [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { + $twig->formThemes([ 'form/my_theme.html.twig', - ], + ]); + // ... - ]); + }; If you only want to apply it to some specific forms, use the ``form_theme`` tag: diff --git a/mailer.rst b/mailer.rst index 6d0901504cd..f772dba65af 100644 --- a/mailer.rst +++ b/mailer.rst @@ -704,13 +704,14 @@ image files as usual. First, to simplify things, define a Twig namespace called .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { // ... - 'paths' => [ - // point this wherever your images live - '%kernel.project_dir%/assets/images' => 'images', - ], - ]); + + // point this wherever your images live + $twig->path('%kernel.project_dir%/assets/images', 'images'); + }; Now, use the special ``email.image()`` Twig helper to embed the images inside the email contents: @@ -812,13 +813,14 @@ called ``styles`` that points to the directory where ``email.css`` lives: .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { // ... - 'paths' => [ - // point this wherever your css files live - '%kernel.project_dir%/assets/styles' => 'styles', - ], - ]); + + // point this wherever your css files live + $twig->path('%kernel.project_dir%/assets/styles', 'styles'); + }; .. _mailer-markdown: diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst index 5d5edd1d43c..39a490650c5 100644 --- a/reference/configuration/twig.rst +++ b/reference/configuration/twig.rst @@ -235,13 +235,16 @@ all the forms of the application: .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ - 'form_themes' => [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { + $twig->formThemes([ 'bootstrap_4_layout.html.twig', 'form/my_theme.html.twig', - ], + ]); + // ... - ]); + }; The order in which themes are defined is important because each theme overrides all the previous one. When rendering a form field whose block is not defined in @@ -348,13 +351,14 @@ the directory defined in the :ref:`default_path option loadFromExtension('twig', [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { // ... - 'paths' => [ - 'email/default/templates' => null, - 'backend/templates' => 'admin', - ], - ]); + + $twig->path('email/default/templates', null); + $twig->path('backend/templates', 'admin'); + }; Read more about :ref:`template directories and namespaces `. diff --git a/templating/global_variables.rst b/templating/global_variables.rst index 2e2c841812c..12090f8b859 100644 --- a/templating/global_variables.rst +++ b/templating/global_variables.rst @@ -39,12 +39,13 @@ main Twig configuration file: .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { // ... - 'globals' => [ - 'ga_tracking' => 'UA-xxxxx-x', - ], - ]); + + $twig->global('ga_tracking')->value('UA-xxxxx-x'); + }; Now, the variable ``ga_tracking`` is available in all Twig templates, so you can use it without having to pass it explicitly from the controller or service @@ -98,12 +99,13 @@ the ``@`` character, which is the usual syntax to .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { // ... - 'globals' => [ - 'uuid' => '@App\Generator\UuidGenerator', - ], - ]); + + $twig->global('uuid')->value('@App\Generator\UuidGenerator'); + }; Now you can use the ``uuid`` variable in any Twig template to access to the ``UuidGenerator`` service: diff --git a/testing.rst b/testing.rst index ebf64cc562f..66c36711bd9 100644 --- a/testing.rst +++ b/testing.rst @@ -184,9 +184,11 @@ code to production: .. code-block:: php // config/packages/test/twig.php - $container->loadFromExtension('twig', [ - 'strict_variables' => true, - ]); + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { + $twig->strictVariables(true); + }; You can also use a different environment entirely, or override the default debug mode (``true``) by passing each as options to the ``bootKernel()`` From 0fcc3e80d4559e7cd8ed65d5787375f656c5a11b Mon Sep 17 00:00:00 2001 From: Nyholm Date: Thu, 22 Apr 2021 17:59:49 +0200 Subject: [PATCH 0921/1519] [Monolog] Add ConfigBuilders for Monolog --- email.rst | 8 +- logging.rst | 102 ++++++++------- logging/channels_handlers.rst | 41 +++--- logging/formatter.rst | 24 ++-- logging/handlers.rst | 17 ++- logging/monolog_console.rst | 18 +-- logging/monolog_email.rst | 153 ++++++++++++----------- logging/monolog_exclude_http_codes.rst | 20 +-- logging/monolog_regex_based_excludes.rst | 22 ++-- logging/processors.rst | 20 +-- 10 files changed, 209 insertions(+), 216 deletions(-) diff --git a/email.rst b/email.rst index 60e630abc38..d2f52a21fd6 100644 --- a/email.rst +++ b/email.rst @@ -394,9 +394,11 @@ the report with details of the sent emails. .. code-block:: php // config/packages/dev/web_profiler.php - $container->loadFromExtension('web_profiler', [ - 'intercept_redirects' => 'true', - ]); + use Symfony\Config\WebProfilerConfig; + + return static function (WebProfilerConfig $webProfiler) { + $webProfiler->interceptRedirects(true); + }; .. tip:: diff --git a/logging.rst b/logging.rst index 2651247d5c5..b18c6479bf1 100644 --- a/logging.rst +++ b/logging.rst @@ -138,23 +138,22 @@ to write logs using the :phpfunction:`syslog` function: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - // this "file_log" key could be anything - 'file_log' => [ - 'type' => 'stream', - // log to var/logs/(environment).log - 'path' => '%kernel.logs_dir%/%kernel.environment%.log', - // log *all* messages (debug is lowest level) - 'level' => 'debug', - ], - 'syslog_handler' => [ - 'type' => 'syslog', - // log error-level messages and higher - 'level' => 'error', - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + // this "file_log" key could be anything + $monolog->handler('file_log') + ->type('stream') + // log to var/logs/(environment).log + ->path('%kernel.logs_dir%/%kernel.environment%.log') + // log *all* messages (debug is lowest level) + ->level('debug'); + + $monolog->handler('syslog_handler') + ->type('syslog') + // log error-level messages and higher + ->level('error'); + }; This defines a *stack* of handlers and each handler is called in the order that it's defined. @@ -236,29 +235,29 @@ one of the messages reaches an ``action_level``. Take this example: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'filter_for_errors' => [ - 'type' => 'fingers_crossed', - // if *one* log is error or higher, pass *all* to file_log - 'action_level' => 'error', - 'handler' => 'file_log', - ], - - // now passed *all* logs, but only if one log is error or higher - 'file_log' => [ - 'type' => 'stream', - 'path' => '%kernel.logs_dir%/%kernel.environment%.log', - 'level' => 'debug', - ], - - // still passed *all* logs, and still only logs error or higher - 'syslog_handler' => [ - 'type' => 'syslog', - 'level' => 'error', - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('filter_for_errors') + ->type('fingers_crossed') + // if *one* log is error or higher, pass *all* to file_log + ->actionLevel('error') + ->handler('file_log') + ; + + // now passed *all* logs, but only if one log is error or higher + $monolog->handler('file_log') + ->type('stream') + ->path('%kernel.logs_dir%/%kernel.environment%.log') + ->level('debug') + ; + + // still passed *all* logs, and still only logs error or higher + $monolog->handler('syslog_handler') + ->type('syslog') + ->level('error') + ; + }; Now, if even one log entry has an ``error`` level or higher, then *all* log entries for that request are saved to a file via the ``file_log`` handler. That means that @@ -331,18 +330,17 @@ option of your handler to ``rotating_file``: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'main' => [ - 'type' => 'rotating_file', - 'path' => '%kernel.logs_dir%/%kernel.environment%.log', - 'level' => 'debug', - // max number of log files to keep - // defaults to zero, which means infinite files - 'max_files' => 10, - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('main') + ->type('rotating_file') + ->path('%kernel.logs_dir%/%kernel.environment%.log') + ->level('debug') + // max number of log files to keep + // defaults to zero, which means infinite files + ->maxFiles(10); + }; Using a Logger inside a Service ------------------------------- diff --git a/logging/channels_handlers.rst b/logging/channels_handlers.rst index 8f6e9aed98a..5c06b13d794 100644 --- a/logging/channels_handlers.rst +++ b/logging/channels_handlers.rst @@ -78,23 +78,19 @@ can do it in any (or all) environments: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'security' => [ - 'type' => 'stream', - 'path' => '%kernel.logs_dir%/security.log', - 'channels' => [ - 'security', - ], - ], - 'main' => [ - // ... - 'channels' => [ - '!security', - ], - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('security') + ->type('stream') + ->path('%kernel.logs_dir%/security.log') + ->channels()->elements(['security']); + + $monolog->handler('main') + // ... + + ->channels()->elements(['!security']); + }; .. caution:: @@ -163,12 +159,11 @@ You can also configure additional channels without the need to tag your services .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'channels' => [ - 'foo', - 'bar', - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->channels(['foo', 'bar']); + }; Symfony automatically registers one service per channel (in this example, the channel ``foo`` creates a service called ``monolog.logger.foo``). In order to diff --git a/logging/formatter.rst b/logging/formatter.rst index b41cd7ad06e..737b0b86a5f 100644 --- a/logging/formatter.rst +++ b/logging/formatter.rst @@ -23,7 +23,7 @@ configure your handler to use it: .. code-block:: xml - + - loadFromExtension('monolog', [ - 'handlers' => [ - 'file' => [ - 'type' => 'stream', - 'level' => 'debug', - 'formatter' => 'monolog.formatter.json', - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('file') + ->type('stream') + ->level('debug') + ->formatter('monolog.formatter.json') + ; + }; diff --git a/logging/handlers.rst b/logging/handlers.rst index 9f5b903cfa9..4e37e01f622 100644 --- a/logging/handlers.rst +++ b/logging/handlers.rst @@ -88,14 +88,13 @@ Then reference it in the Monolog configuration: // config/packages/prod/monolog.php use Symfony\Bridge\Monolog\Handler\ElasticsearchLogstashHandler; - - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'es' => [ - 'type' => 'service', - 'id' => ElasticsearchLogstashHandler::class, - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('es') + ->type('service') + ->id(ElasticsearchLogstashHandler::class) + ; + }; .. _`ELK stack`: https://www.elastic.co/what-is/elk-stack diff --git a/logging/monolog_console.rst b/logging/monolog_console.rst index 21c67d705d8..13789a35b25 100644 --- a/logging/monolog_console.rst +++ b/logging/monolog_console.rst @@ -122,15 +122,15 @@ The Monolog console handler is enabled by default: .. code-block:: php // config/packages/dev/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'console' => [ - 'type' => 'console', - 'process_psr_3_messages' => false, - 'channels' => ['!event', '!doctrine', '!console'], - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('console') + ->type('console') + ->processPsr3Messages(false) + ->channels()->elements(['!event', '!doctrine', '!console']) + ; + }; Now, log messages will be shown on the console based on the log levels and verbosity. By default (normal verbosity level), warnings and higher will be shown. But in diff --git a/logging/monolog_email.rst b/logging/monolog_email.rst index 22ed4d08928..77a27cea9cd 100644 --- a/logging/monolog_email.rst +++ b/logging/monolog_email.rst @@ -99,36 +99,36 @@ it is broken down. .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'main' => [ - 'type' => 'fingers_crossed', - // 500 errors are logged at the critical level - 'action_level' => 'critical', - // to also log 400 level errors (but not 404's): - // 'action_level' => 'error', - // 'excluded_404s' => [ - // '^/', - // ], - 'handler' => 'deduplicated', - ], - 'deduplicated' => [ - 'type' => 'deduplication', - 'handler' => 'symfony_mailer', - ], - 'symfony_mailer' => [ - 'type' => 'symfony_mailer', - 'from_email' => 'error@example.com', - 'to_email' => 'error@example.com', - // or a list of recipients - // 'to_email' => ['dev1@example.com', 'dev2@example.com', ...], - 'subject' => 'An Error Occurred! %%message%%', - 'level' => 'debug', - 'formatter' => 'monolog.formatter.html', - 'content_type' => 'text/html', - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('main') + ->type('fingers_crossed') + // 500 errors are logged at the critical level + ->actionLevel('critical') + // to also log 400 level errors (but not 404's): + // ->actionLevel('error') + // ->excluded404s(['^/']) + + ->handler('deduplicated') + ; + + $monolog->handler('deduplicated') + ->type('deduplicated') + ->handler('symfony_mailer'); + + $monolog->handler('symfony_mailer') + ->type('symfony_mailer') + ->fromEmail('error@example.com') + ->toEmail(['error@example.com']) + // or a list of recipients + // ->toEmail(['dev1@example.com', 'dev2@example.com', ...]) + ->subject('An Error Occurred! %%message%%') + ->level('debug') + ->formatter('monolog.formatter.html') + ->contentType('text/html') + ; + }; The ``main`` handler is a ``fingers_crossed`` handler which means that it is only triggered when the action level, in this case ``critical`` is reached. @@ -177,17 +177,18 @@ You can adjust the time period using the ``time`` option: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - // ... - 'deduplicated' => [ - 'type' => 'deduplication', - // the time in seconds during which duplicate entries are discarded (default: 60) - 'time' => 10, - 'handler' => 'symfony_mailer', - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + // ... + + $monolog->handler('deduplicated') + ->type('deduplicated') + // the time in seconds during which duplicate entries are discarded (default: 60) + ->time(10) + ->handler('symfony_mailer') + ; + }; The messages are then passed to the ``symfony_mailer`` handler. This is the handler that actually deals with emailing you the error. The settings for this are @@ -285,39 +286,43 @@ get logged on the server as well as the emails being sent: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'main' => [ - 'type' => 'fingers_crossed', - 'action_level' => 'critical', - 'handler' => 'grouped', - ], - 'grouped' => [ - 'type' => 'group', - 'members' => ['streamed', 'deduplicated'], - ], - 'streamed' => [ - 'type' => 'stream', - 'path' => '%kernel.logs_dir%/%kernel.environment%.log', - 'level' => 'debug', - ], - 'deduplicated' => [ - 'type' => 'deduplication', - 'handler' => 'symfony_mailer', - ], - 'symfony_mailer' => [ - 'type' => 'symfony_mailer', - 'from_email' => 'error@example.com', - 'to_email' => 'error@example.com', - // or a list of recipients - // 'to_email' => ['dev1@example.com', 'dev2@example.com', ...], - 'subject' => 'An Error Occurred! %%message%%', - 'level' => 'debug', - 'formatter' => 'monolog.formatter.html', - 'content_type' => 'text/html', - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('main') + ->type('fingers_crossed') + ->actionLevel('critical') + ->handler('grouped') + ; + + $monolog->handler('group') + ->members(['streamed', 'deduplicated']) + ; + + $monolog->handler('streamed') + ->type('stream') + ->path('%kernel.logs_dir%/%kernel.environment%.log') + ->level('debug') + ; + + $monolog->handler('deduplicated') + ->type('deduplicated') + ->handler('symfony_mailer') + ; + + // still passed *all* logs, and still only logs error or higher + $monolog->handler('symfony_mailer') + ->type('symfony_mailer') + ->fromEmail('error@example.com') + ->toEmail(['error@example.com']) + // or a list of recipients + // ->toEmail(['dev1@example.com', 'dev2@example.com', ...]) + ->subject('An Error Occurred! %%message%%') + ->level('debug') + ->formatter('monolog.formatter.html') + ->contentType('text/html') + ; + }; This uses the ``group`` handler to send the messages to the two group members, the ``deduplicated`` and the ``stream`` handlers. The messages will diff --git a/logging/monolog_exclude_http_codes.rst b/logging/monolog_exclude_http_codes.rst index 9c1bd81bdcc..4382b818437 100644 --- a/logging/monolog_exclude_http_codes.rst +++ b/logging/monolog_exclude_http_codes.rst @@ -49,16 +49,16 @@ logging these HTTP codes based on the MonologBundle configuration: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'main' => [ - // ... - 'type' => 'fingers_crossed', - 'handler' => ..., - 'excluded_http_codes' => [403, 404], - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('main') + // ... + ->type('fingers_crossed') + ->handler(...) + ->excludedHttpCode([403, 404]) + ; + }; .. caution:: diff --git a/logging/monolog_regex_based_excludes.rst b/logging/monolog_regex_based_excludes.rst index be4a6ee8b7e..b5186e13b60 100644 --- a/logging/monolog_regex_based_excludes.rst +++ b/logging/monolog_regex_based_excludes.rst @@ -54,18 +54,16 @@ configuration: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'main' => [ - // ... - 'type' => 'fingers_crossed', - 'handler' => ..., - 'excluded_404s' => [ - '^/phpmyadmin', - ], - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('main') + // ... + ->type('fingers_crossed') + ->handler(...) + ->excluded404s(['^/phpmyadmin']) + ; + }; .. caution:: diff --git a/logging/processors.rst b/logging/processors.rst index c0a3eb33bbf..3c4faacda5f 100644 --- a/logging/processors.rst +++ b/logging/processors.rst @@ -149,16 +149,16 @@ Finally, set the formatter to be used on whatever handler you want: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'main' => [ - 'type' => 'stream', - 'path' => '%kernel.logs_dir%/%kernel.environment%.log', - 'level' => 'debug', - 'formatter' => 'monolog.formatter.session_request', - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('main') + ->type('stream') + ->path('%kernel.logs_dir%/%kernel.environment%.log') + ->level('debug') + ->formatter('monolog.formatter.session_request') + ; + }; If you use several handlers, you can also register a processor at the handler level or at the channel level instead of registering it globally From e6818803044f7331e2bb1f0350eb31da841563a7 Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Sat, 24 Apr 2021 18:01:34 +0200 Subject: [PATCH 0922/1519] Minor rewording --- reference/forms/types/options/label.rst.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/forms/types/options/label.rst.inc b/reference/forms/types/options/label.rst.inc index 9797b6264cf..3d9b6bd1674 100644 --- a/reference/forms/types/options/label.rst.inc +++ b/reference/forms/types/options/label.rst.inc @@ -3,8 +3,8 @@ **type**: ``string`` **default**: The label is "guessed" from the field name -Sets the label that will be used when rendering the field. Setting to false -will suppress the label. The label can also be directly set inside the template: +Sets the label that will be used when rendering the field. Setting to ``false`` +will suppress the label. The label can also be set in the template: .. configuration-block:: From 0df93933009db1380ea525f228e11c8b479ee5c0 Mon Sep 17 00:00:00 2001 From: jean-marie leroux Date: Fri, 23 Apr 2021 18:04:48 +0200 Subject: [PATCH 0923/1519] [Security] Fixes typo in experimental authenticators `$email` was not defined in the example. --- security/experimental_authenticators.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index b7734ef88e0..027b1087d1d 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -582,7 +582,7 @@ would initialize the passport like this:: // ... validate no parameter is empty return new Passport( - new UserBadge($email), + new UserBadge($username), new PasswordCredentials($password), [new CsrfTokenBadge('login', $csrfToken)] ); From c471e642fec742a7ad57e8210a866a0566928c71 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 26 Apr 2021 11:19:05 +0200 Subject: [PATCH 0924/1519] Remove personal e-mailaddress from the code example --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 0c8309aec71..03837f04462 100644 --- a/notifier.rst +++ b/notifier.rst @@ -508,7 +508,7 @@ sent using the Slack transport:: ->content('You got a new invoice for 15 EUR.') ->importance(Notification::IMPORTANCE_HIGH); - $notifier->send($notification, new Recipient('wouter@wouterj.nl')); + $notifier->send($notification, new Recipient('wouter@example.com')); // ... } From ec1920e0712786b00c5d138ebf79fcd1bba726be Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 28 Apr 2021 11:09:11 +0200 Subject: [PATCH 0925/1519] [Runtime] Minor fixes --- components/runtime.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/components/runtime.rst b/components/runtime.rst index 2bdad2e38f5..cf11c81e60f 100644 --- a/components/runtime.rst +++ b/components/runtime.rst @@ -46,7 +46,7 @@ the component. This file runs the following logic: #. It instantiates a :class:`Symfony\\Component\\Runtime\\RuntimeInterface`; #. The callable (returned by ``public/index.php``) is passed to the Runtime, whose job - is to resolve the arguments (in this example: ``array $content``); + is to resolve the arguments (in this example: ``array $context``); #. Then, this callable is called to get the application (``App\Kernel``); #. At last, the Runtime is used to run the application (i.e. calling ``$kernel->handle(Request::createFromGlobals())->send()``). @@ -172,12 +172,12 @@ a number of different applications are supported:: The ``SymfonyRuntime`` can handle these applications: :class:`Symfony\\Component\\HttpKernel\\HttpKernelInterface` - The application will be run with :class:`Symfony\\Component\\Runtime\\Runner\\Symfony\\HttpKernelRunner`` + The application will be run with :class:`Symfony\\Component\\Runtime\\Runner\\Symfony\\HttpKernelRunner` like a "standard" Symfony application. :class:`Symfony\\Component\\HttpFoundation\\Response` The Response will be printed by - :class:`Symfony\\Component\\Runtime\\Runner\\Symfony\\ResponseRunner``:: + :class:`Symfony\\Component\\Runtime\\Runner\\Symfony\\ResponseRunner`:: Date: Thu, 29 Apr 2021 23:20:24 +0300 Subject: [PATCH 0926/1519] Added caution notice about nested bundle configs --- configuration.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/configuration.rst b/configuration.rst index fbd36889577..f2d0e4c0780 100644 --- a/configuration.rst +++ b/configuration.rst @@ -876,7 +876,7 @@ whenever a service/controller defines a ``$projectDir`` argument, use this: // pass this value to any $projectDir argument for any service // that's created in this file (including controller arguments) ->bind('$projectDir', '%kernel.project_dir%'); - + // ... }; @@ -953,6 +953,12 @@ namespace ``Symfony\Config``:: $security->accessControl(['path' => '^/admin', 'roles' => 'ROLE_ADMIN']); }; +.. caution:: + + Note that only "root" classes in the namespace ``Symfony\Config`` are ConfigBuilders. + Nested configs (e.g. ``\Symfony\Config\Framework\CacheConfig``) are the Plain Old PHP + Objects and cannot be autowired when you specify it as an argument type. + Keep Going! ----------- From ce457e0c2aa9625f2f2272e54df3b8576639f433 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 22 Apr 2021 19:47:05 +0200 Subject: [PATCH 0927/1519] [Security] Removed some deprecated features related to User::getUsername() --- controller/argument_value_resolver.rst | 2 +- reference/configuration/security.rst | 4 +-- routing.rst | 6 ++-- security/custom_authentication_provider.rst | 5 ++- security/experimental_authenticators.rst | 2 +- security/guard_authentication.rst | 4 +-- security/json_login_setup.rst | 4 ++- security/login_link.rst | 2 +- security/user_provider.rst | 40 ++++++++++----------- 9 files changed, 37 insertions(+), 32 deletions(-) diff --git a/controller/argument_value_resolver.rst b/controller/argument_value_resolver.rst index c9693bbaf9b..ebc59a02bf5 100644 --- a/controller/argument_value_resolver.rst +++ b/controller/argument_value_resolver.rst @@ -75,7 +75,7 @@ with the ``User`` class:: { public function index(User $user) { - return new Response('Hello '.$user->getUsername().'!'); + return new Response('Hello '.$user->getUserIdentifier().'!'); } } diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index 053ff55e300..630c65879f1 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -89,8 +89,8 @@ If ``true``, when a user is not found a generic exception of type is thrown with the message "Bad credentials". If ``false``, the exception thrown is of type -:class:`Symfony\\Component\\Security\\Core\\Exception\\UsernameNotFoundException` -and it includes the given not found username. +:class:`Symfony\\Component\\Security\\Core\\Exception\\UserNotFoundException` +and it includes the given not found user identifier. session_fixation_strategy ~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/routing.rst b/routing.rst index 191e255aab6..641d4e43b2f 100644 --- a/routing.rst +++ b/routing.rst @@ -2402,7 +2402,7 @@ use the ``generateUrl()`` helper:: // generate a URL with route arguments $userProfilePage = $this->generateUrl('user_profile', [ - 'username' => $user->getUsername(), + 'username' => $user->getUserIdentifier(), ]); // generated URLs are "absolute paths" by default. Pass a third optional @@ -2472,7 +2472,7 @@ the :class:`Symfony\\Component\\Routing\\Generator\\UrlGeneratorInterface` class // generate a URL with route arguments $userProfilePage = $this->router->generate('user_profile', [ - 'username' => $user->getUsername(), + 'username' => $user->getUserIdentifier(), ]); // generated URLs are "absolute paths" by default. Pass a third optional @@ -2595,7 +2595,7 @@ Now you'll get the expected results when generating URLs in your commands:: // generate a URL with route arguments $userProfilePage = $this->router->generate('user_profile', [ - 'username' => $user->getUsername(), + 'username' => $user->getUserIdentifier(), ]); // generated URLs are "absolute paths" by default. Pass a third optional diff --git a/security/custom_authentication_provider.rst b/security/custom_authentication_provider.rst index a638169f4f0..04c94a4a82c 100644 --- a/security/custom_authentication_provider.rst +++ b/security/custom_authentication_provider.rst @@ -218,7 +218,10 @@ the ``PasswordDigest`` header value matches with the user's password:: public function authenticate(TokenInterface $token): WsseUserToken { - $user = $this->userProvider->loadUserByUsername($token->getUsername()); + // The loadUserByIdentifier() and getUserIdentifier() methods were + // introduced in Symfony 5.3. In previous versions they were called + // loadUserByUsername() and getUsername() respectively + $user = $this->userProvider->loadUserByIdentifier($token->getUserIdentifier()); if ($user && $this->validateDigest($token->digest, $token->nonce, $token->created, $user->getPassword())) { $authenticatedToken = new WsseUserToken($user->getRoles()); diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index b7734ef88e0..b35dbd79559 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -456,7 +456,7 @@ using :ref:`the user provider `:: You can optionally pass a user loader as second argument to the ``UserBadge``. This callable receives the ``$userIdentifier`` and must return a ``UserInterface`` object (otherwise a - ``UsernameNotFoundException`` is thrown):: + ``UserNotFoundException`` is thrown):: // src/Security/CustomAuthenticator.php namespace App\Security; diff --git a/security/guard_authentication.rst b/security/guard_authentication.rst index ebd1c2471ce..7108ba0906e 100644 --- a/security/guard_authentication.rst +++ b/security/guard_authentication.rst @@ -172,10 +172,10 @@ This requires you to implement several methods:: return null; } - // The "username" in this case is the apiToken, see the key `property` + // The user identifier in this case is the apiToken, see the key `property` // of `your_db_provider` in `security.yaml`. // If this returns a user, checkCredentials() is called next: - return $userProvider->loadUserByUsername($credentials); + return $userProvider->loadUserByIdentifier($credentials); } public function checkCredentials($credentials, UserInterface $user): bool diff --git a/security/json_login_setup.rst b/security/json_login_setup.rst index 6758a3917ef..41107f9f46a 100644 --- a/security/json_login_setup.rst +++ b/security/json_login_setup.rst @@ -85,7 +85,9 @@ The next step is to configure a route in your app matching this path: $user = $this->getUser(); return $this->json([ - 'username' => $user->getUsername(), + // The getUserIdentifier() method was introduced in Symfony 5.3. + // In previous versions it was called getUsername() + 'username' => $user->getUserIdentifier(), 'roles' => $user->getRoles(), ]); } diff --git a/security/login_link.rst b/security/login_link.rst index 8abe8a05a27..ed8bb195e15 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -401,7 +401,7 @@ The signed URL contains 3 parameters: The UNIX timestamp when the link expires. ``user`` - The value returned from ``$user->getUsername()`` for this user. + The value returned from ``$user->getUserIdentifier()`` for this user. ``hash`` A hash of ``expires``, ``user`` and any configured signature diff --git a/security/user_provider.rst b/security/user_provider.rst index d4c26e9cc5a..e7a3cdec79a 100644 --- a/security/user_provider.rst +++ b/security/user_provider.rst @@ -124,7 +124,7 @@ the ``property`` config key. If you want a bit more control over this - e.g. you want to find a user by ``email`` *or* ``username``, you can do that by making your ``UserRepository`` implement the :class:`Symfony\\Bridge\\Doctrine\\Security\\User\\UserLoaderInterface`. This -interface only requires one method: ``loadUserByUsername($username)``:: +interface only requires one method: ``loadUserByIdentifier($identifier)``:: // src/Repository/UserRepository.php namespace App\Repository; @@ -137,7 +137,9 @@ interface only requires one method: ``loadUserByUsername($username)``:: { // ... - public function loadUserByUsername(string $usernameOrEmail): ?User + // The loadUserByIdentifier() method was introduced in Symfony 5.3. + // In previous versions it was called loadUserByUsername() + public function loadUserByIdentifier(string $usernameOrEmail): ?User { $entityManager = $this->getEntityManager(); @@ -209,7 +211,7 @@ To finish this, remove the ``property`` key from the user provider in This tells Symfony to *not* query automatically for the User. Instead, when needed (e.g. because :doc:`user impersonation `, :doc:`Remember Me `, or some other security feature is -activated), the ``loadUserByUsername()`` method on ``UserRepository`` will be called. +activated), the ``loadUserByIdentifier()`` method on ``UserRepository`` will be called. .. _security-memory-user-provider: @@ -367,7 +369,7 @@ command will generate a nice skeleton to get you started:: namespace App\Security; use Symfony\Component\Security\Core\Exception\UnsupportedUserException; - use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; + use Symfony\Component\Security\Core\Exception\UserNotFoundException; use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; @@ -375,23 +377,21 @@ command will generate a nice skeleton to get you started:: class UserProvider implements UserProviderInterface, PasswordUpgraderInterface { /** - * Symfony calls this method if you use features like switch_user - * or remember_me. - * - * If you're not using these features, you do not need to implement - * this method. + * The loadUserByIdentifier() method was introduced in Symfony 5.3. + * In previous versions it was called loadUserByUsername() * - * @return UserInterface + * Symfony calls this method if you use features like switch_user + * or remember_me. If you're not using these features, you do not + * need to implement this method. * - * @throws UsernameNotFoundException if the user is not found + * @throws UserNotFoundException if the user is not found */ - public function loadUserByUsername(string $username) + public function loadUserByIdentifier(string $identifier): UserInterface { - // Load a User object from your data source or throw UsernameNotFoundException. - // The $username argument may not actually be a username: - // it is whatever value is being returned by the getUsername() - // method in your User class. - throw new \Exception('TODO: fill in loadUserByUsername() inside '.__FILE__); + // Load a User object from your data source or throw UserNotFoundException. + // The $identifier argument is whatever value is being returned by the + // getUserIdentifier() method in your User class. + throw new \Exception('TODO: fill in loadUserByIdentifier() inside '.__FILE__); } /** @@ -414,7 +414,7 @@ command will generate a nice skeleton to get you started:: } // Return a User object after making sure its data is "fresh". - // Or throw a UsernameNotFoundException if the user no longer exists. + // Or throw a UserNotFoundException if the user no longer exists. throw new \Exception('TODO: fill in refreshUser() inside '.__FILE__); } @@ -467,8 +467,8 @@ request, it's deserialized and then passed to your user provider to "refresh" it Then, the two User objects (the original from the session and the refreshed User object) are "compared" to see if they are "equal". By default, the core ``AbstractToken`` class compares the return values of the ``getPassword()``, -``getSalt()`` and ``getUsername()`` methods. If any of these are different, your -user will be logged out. This is a security measure to make sure that malicious +``getSalt()`` and ``getUserIdentifier()`` methods. If any of these are different, +your user will be logged out. This is a security measure to make sure that malicious users can be de-authenticated if core user data changes. However, in some cases, this process can cause unexpected authentication problems. From 2824979e952fcb85a64fea3948b5d8da3133c8c4 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 30 Apr 2021 15:54:09 +0200 Subject: [PATCH 0928/1519] Tweaks --- configuration.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configuration.rst b/configuration.rst index f2d0e4c0780..3a42a45680f 100644 --- a/configuration.rst +++ b/configuration.rst @@ -953,11 +953,11 @@ namespace ``Symfony\Config``:: $security->accessControl(['path' => '^/admin', 'roles' => 'ROLE_ADMIN']); }; -.. caution:: +.. note:: - Note that only "root" classes in the namespace ``Symfony\Config`` are ConfigBuilders. - Nested configs (e.g. ``\Symfony\Config\Framework\CacheConfig``) are the Plain Old PHP - Objects and cannot be autowired when you specify it as an argument type. + Only root classes in the namespace ``Symfony\Config`` are ConfigBuilders. + Nested configs (e.g. ``\Symfony\Config\Framework\CacheConfig``) are regular + PHP objects which aren't autowired when using them as an argument type. Keep Going! ----------- From e57adb90d840d7cde2e419a0c5b27c3d7280e0df Mon Sep 17 00:00:00 2001 From: Nyholm Date: Wed, 21 Apr 2021 11:51:36 +0200 Subject: [PATCH 0929/1519] [ConfigBuilder] Replace all framework config --- bundles/configuration.rst | 21 +- cache.rst | 217 ++++++------ configuration/env_var_processors.rst | 66 ++-- configuration/micro_kernel_trait.rst | 15 +- configuration/override_dir_structure.rst | 12 +- configuration/secrets.rst | 16 +- controller/error_pages.rst | 8 +- deployment/proxies.rst | 22 +- frontend/custom_version_strategy.rst | 11 +- http_cache/esi.rst | 21 +- http_cache/ssi.rst | 12 +- http_client.rst | 144 ++++---- lock.rst | 68 ++-- mailer.rst | 103 +++--- messenger.rst | 419 +++++++++++------------ messenger/custom-transport.rst | 15 +- messenger/multiple_buses.rst | 46 +-- notifier.rst | 107 +++--- rate_limiter.rst | 63 ++-- reference/configuration/framework.rst | 247 ++++++------- security.rst | 64 ++-- security/csrf.rst | 10 +- security/remember_me.rst | 2 +- session/database.rst | 36 +- session/php_bridge.rst | 28 +- session/proxy_examples.rst | 13 +- templating/hinclude.rst | 12 +- testing/profiling.rst | 16 +- translation.rst | 39 ++- translation/locale.rst | 10 +- validation.rst | 24 +- workflow.rst | 233 +++++++------ workflow/dumping-workflows.rst | 131 ++++--- workflow/workflow-and-state-machine.rst | 108 +++--- 34 files changed, 1204 insertions(+), 1155 deletions(-) diff --git a/bundles/configuration.rst b/bundles/configuration.rst index 520e1f04220..198ac07450d 100644 --- a/bundles/configuration.rst +++ b/bundles/configuration.rst @@ -40,9 +40,11 @@ as integration of other related components: .. code-block:: php - $container->loadFromExtension('framework', [ - 'form' => true, - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->form()->enabled(true); + }; Using the Bundle Extension -------------------------- @@ -81,12 +83,13 @@ can add some configuration that looks like this: .. code-block:: php // config/packages/acme_social.php - $container->loadFromExtension('acme_social', [ - 'twitter' => [ - 'client_id' => 123, - 'client_secret' => 'your_secret', - ], - ]); + use Symfony\Config\AcmeSocialConfig; + + return static function (AcmeSocialConfig $acmeSocial) { + $acmeSocial->twitter() + ->clientId(123) + ->clientSecret('your_secret'); + }; The basic idea is that instead of having the user override individual parameters, you let the user configure just a few, specifically created, diff --git a/cache.rst b/cache.rst index 6eb17035e5f..f9a8c42b554 100644 --- a/cache.rst +++ b/cache.rst @@ -85,12 +85,15 @@ adapter (template) they use by using the ``app`` and ``system`` key like: .. code-block:: php // config/packages/cache.php - $container->loadFromExtension('framework', [ - 'cache' => [ - 'app' => 'cache.adapter.filesystem', - 'system' => 'cache.adapter.system', - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->cache() + ->app('cache.adapter.filesystem') + ->system('cache.adapter.system') + ; + }; + The Cache component comes with a series of adapters pre-configured: @@ -165,23 +168,24 @@ will create pools with service IDs that follow the pattern ``cache.[type]``. .. code-block:: php // config/packages/cache.php - $container->loadFromExtension('framework', [ - 'cache' => [ - // Only used with cache.adapter.filesystem - 'directory' => '%kernel.cache_dir%/pools', + use Symfony\Config\FrameworkConfig; + return static function (FrameworkConfig $framework) { + $framework->cache() + // Only used with cache.adapter.filesystem + ->directory('%kernel.cache_dir%/pools') // Service: cache.doctrine - 'default_doctrine_provider' => 'app.doctrine_cache', + ->defaultDoctrineProvider('app.doctrine_cache') // Service: cache.psr6 - 'default_psr6_provider' => 'app.my_psr6_service', + ->defaultPsr6Provider('app.my_psr6_service') // Service: cache.redis - 'default_redis_provider' => 'redis://localhost', + ->defaultRedisProvider('redis://localhost') // Service: cache.memcached - 'default_memcached_provider' => 'memcached://localhost', + ->defaultMemcachedProvider('memcached://localhost') // Service: cache.pdo - 'default_pdo_provider' => 'doctrine.dbal.default_connection', - ], - ]); + ->defaultPdoProvider('doctrine.dbal.default_connection') + ; + }; .. _cache-create-pools: @@ -267,43 +271,36 @@ You can also create more customized pools: .. code-block:: php // config/packages/cache.php - $container->loadFromExtension('framework', [ - 'cache' => [ - 'default_memcached_provider' => 'memcached://localhost', - 'pools' => [ - // creates a "custom_thing.cache" service - // autowireable via "CacheInterface $customThingCache" - // uses the "app" cache configuration - 'custom_thing.cache' => [ - 'adapter' => 'cache.app', - ], - - // creates a "my_cache_pool" service - // autowireable via "CacheInterface $myCachePool" - 'my_cache_pool' => [ - 'adapter' => 'cache.adapter.filesystem', - ], - - // uses the default_memcached_provider from above - 'acme.cache' => [ - 'adapter' => 'cache.adapter.memcached', - ], - - // control adapter's configuration - 'foobar.cache' => [ - 'adapter' => 'cache.adapter.memcached', - 'provider' => 'memcached://user:password@example.com', - ], - - // uses the "foobar.cache" pool as its backend but controls - // the lifetime and (like all pools) has a separate cache namespace - 'short_cache' => [ - 'adapter' => 'foobar.cache', - 'default_lifetime' => 60, - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $cache = $framework->cache(); + $cache->defaultMemcachedProvider('memcached://localhost'); + + // creates a "custom_thing.cache" service + // autowireable via "CacheInterface $customThingCache" + // uses the "app" cache configuration + $cache->pool('custom_thing.cache') + ->adapters(['cache.app']); + + // creates a "my_cache_pool" service + // autowireable via "CacheInterface $myCachePool" + $cache->pool('my_cache_pool') + ->adapters(['cache.adapter.filesystem']); + + // uses the default_memcached_provider from above + $cache->pool('acme.cache') + ->adapters(['cache.adapter.memcached']); + + // control adapter's configuration + $cache->pool('foobar.cache') + ->adapters(['cache.adapter.memcached']) + ->provider('memcached://user:password@example.com'); + + $cache->pool('short_cache') + ->adapters(['foobar.cache']) + ->defaultLifetime(60); + }; Each pool manages a set of independent cache keys: keys from different pools *never* collide, even if they share the same backend. This is achieved by prefixing @@ -442,26 +439,25 @@ and use that when configuring the pool. // config/packages/cache.php use Symfony\Component\Cache\Adapter\RedisAdapter; - - $container->loadFromExtension('framework', [ - 'cache' => [ - 'pools' => [ - 'cache.my_redis' => [ - 'adapter' => 'cache.adapter.redis', - 'provider' => 'app.my_custom_redis_provider', - ], - ], - ], - ]); - - $container->register('app.my_custom_redis_provider', \Redis::class) - ->setFactory([RedisAdapter::class, 'createConnection']) - ->addArgument('redis://localhost') - ->addArgument([ - 'retry_interval' => 2, - 'timeout' => 10 - ]) - ; + use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Config\FrameworkConfig; + + return static function (ContainerBuilder $container, FrameworkConfig $framework) { + $framework->cache() + ->pool('cache.my_redis') + ->adapters(['cache.adapter.redis']) + ->provider('app.my_custom_redis_provider'); + + + $container->register('app.my_custom_redis_provider', \Redis::class) + ->setFactory([RedisAdapter::class, 'createConnection']) + ->addArgument('redis://localhost') + ->addArgument([ + 'retry_interval' => 2, + 'timeout' => 10 + ]) + ; + }; Creating a Cache Chain ---------------------- @@ -521,20 +517,19 @@ Symfony stores the item automatically in all the missing pools. .. code-block:: php // config/packages/cache.php - $container->loadFromExtension('framework', [ - 'cache' => [ - 'pools' => [ - 'my_cache_pool' => [ - 'default_lifetime' => 31536000, // One year - 'adapters' => [ - 'cache.adapter.array', - 'cache.adapter.apcu', - ['name' => 'cache.adapter.redis', 'provider' => 'redis://user:password@example.com'], - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->cache() + ->pool('my_cache_pool') + ->defaultLifetime(31536000) // One year + ->adapters([ + 'cache.adapter.array', + 'cache.adapter.apcu', + ['name' => 'cache.adapter.redis', 'provider' => 'redis://user:password@example.com'], + ]) + ; + }; Using Cache Tags ---------------- @@ -613,16 +608,15 @@ to enable this feature. This could be added by using the following configuration .. code-block:: php // config/packages/cache.php - $container->loadFromExtension('framework', [ - 'cache' => [ - 'pools' => [ - 'my_cache_pool' => [ - 'adapter' => 'cache.adapter.redis', - 'tags' => true, - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->cache() + ->pool('my_cache_pool') + ->tags(true) + ->adapters(['cache.adapter.redis']) + ; + }; Tags are stored in the same pool by default. This is good in most scenarios. But sometimes it might be better to store the tags in a different pool. That could be @@ -663,19 +657,20 @@ achieved by specifying the adapter. .. code-block:: php // config/packages/cache.php - $container->loadFromExtension('framework', [ - 'cache' => [ - 'pools' => [ - 'my_cache_pool' => [ - 'adapter' => 'cache.adapter.redis', - 'tags' => 'tag_pool', - ], - 'tag_pool' => [ - 'adapter' => 'cache.adapter.apcu', - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->cache() + ->pool('my_cache_pool') + ->tags('tag_pool') + ->adapters(['cache.adapter.redis']) + ; + + $framework->cache() + ->pool('tag_pool') + ->adapters(['cache.adapter.apcu']) + ; + }; .. note:: diff --git a/configuration/env_var_processors.rst b/configuration/env_var_processors.rst index 8187364c152..d1be0338448 100644 --- a/configuration/env_var_processors.rst +++ b/configuration/env_var_processors.rst @@ -44,11 +44,15 @@ processor to turn the value of the ``HTTP_PORT`` env var into an integer: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'router' => [ - 'http_port' => '%env(int:HTTP_PORT)%', - ], - ]); + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->router() + ->httpPort(env('HTTP_PORT')->int()) + ; + }; Built-In Environment Variable Processors ---------------------------------------- @@ -90,10 +94,15 @@ Symfony provides the following env var processors: .. code-block:: php // config/packages/framework.php - $container->setParameter('env(SECRET)', 'some_secret'); - $container->loadFromExtension('framework', [ - 'secret' => '%env(string:SECRET)%', - ]); + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Config\FrameworkConfig; + + return static function (ContainerBuilder $container, FrameworkConfig $framework) { + $container->setParameter('env(SECRET)', 'some_secret'); + $framework->secret(env('SECRET')->string()); + }; ``env(bool:FOO)`` Casts ``FOO`` to a bool (``true`` values are ``'true'``, ``'on'``, ``'yes'`` @@ -131,10 +140,15 @@ Symfony provides the following env var processors: .. code-block:: php // config/packages/framework.php - $container->setParameter('env(HTTP_METHOD_OVERRIDE)', 'true'); - $container->loadFromExtension('framework', [ - 'http_method_override' => '%env(bool:HTTP_METHOD_OVERRIDE)%', - ]); + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Config\FrameworkConfig; + + return static function (ContainerBuilder $container, FrameworkConfig $framework) { + $container->setParameter('env(HTTP_METHOD_OVERRIDE)', 'true'); + $framework->httpMethodOverride(env('HTTP_METHOD_OVERRIDE')->bool()); + }; ``env(not:FOO)`` @@ -269,10 +283,15 @@ Symfony provides the following env var processors: .. code-block:: php // config/packages/framework.php - $container->setParameter('env(TRUSTED_HOSTS)', '["10.0.0.1", "10.0.0.2"]'); - $container->loadFromExtension('framework', [ - 'trusted_hosts' => '%env(json:TRUSTED_HOSTS)%', - ]); + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Config\FrameworkConfig; + + return static function (ContainerBuilder $container, FrameworkConfig $framework) { + $container->setParameter('env(TRUSTED_HOSTS)', '["10.0.0.1", "10.0.0.2"]'); + $framework->trustedHosts(env('TRUSTED_HOSTS')->json()); + }; ``env(resolve:FOO)`` If the content of ``FOO`` includes container parameters (with the syntax @@ -353,10 +372,15 @@ Symfony provides the following env var processors: .. code-block:: php // config/packages/framework.php - $container->setParameter('env(TRUSTED_HOSTS)', '10.0.0.1,10.0.0.2'); - $container->loadFromExtension('framework', [ - 'trusted_hosts' => '%env(csv:TRUSTED_HOSTS)%', - ]); + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Config\FrameworkConfig; + + return static function (ContainerBuilder $container, FrameworkConfig $framework) { + $container->setParameter('env(TRUSTED_HOSTS)', '10.0.0.1,10.0.0.2'); + $framework->trustedHosts(env('TRUSTED_HOSTS')->csv()); + }; ``env(file:FOO)`` Returns the contents of a file whose path is the value of the ``FOO`` env var: diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst index 890f60d1ca8..66e9aae2bbe 100644 --- a/configuration/micro_kernel_trait.rst +++ b/configuration/micro_kernel_trait.rst @@ -234,12 +234,15 @@ because the configuration started to get bigger: .. code-block:: php // config/framework.php - $container->loadFromExtension('framework', [ - 'secret' => 'S0ME_SECRET', - 'profiler' => [ - 'only_exceptions' => false, - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework + ->secret('SOME_SECRET') + ->profiler() + ->onlyExceptions(false) + ; + }; This also loads annotation routes from an ``src/Controller/`` directory, which has one file in it:: diff --git a/configuration/override_dir_structure.rst b/configuration/override_dir_structure.rst index fef0d7756fb..6f56f4b54a4 100644 --- a/configuration/override_dir_structure.rst +++ b/configuration/override_dir_structure.rst @@ -186,11 +186,13 @@ configuration option to define your own translations directory (use :ref:`framew .. code-block:: php // config/packages/translation.php - $container->loadFromExtension('framework', [ - 'translator' => [ - 'default_path' => '%kernel.project_dir%/i18n', - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->translator() + ->defaultPath('%kernel.project_dir%/i18n') + ; + }; .. _override-web-dir: .. _override-the-web-directory: diff --git a/configuration/secrets.rst b/configuration/secrets.rst index 299d36326fc..8db723d63de 100644 --- a/configuration/secrets.rst +++ b/configuration/secrets.rst @@ -308,13 +308,15 @@ The secrets system is enabled by default and some of its behavior can be configu .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'secrets' => [ - // 'vault_directory' => '%kernel.project_dir%/config/secrets/%kernel.environment%', - // 'local_dotenv_file' => '%kernel.project_dir%/.env.%kernel.environment%.local', - // 'decryption_env_var' => 'base64:default::SYMFONY_DECRYPTION_SECRET', - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->secrets() + // ->vaultDirectory('%kernel.project_dir%/config/secrets/%kernel.environment%') + // ->localDotenvFile('%kernel.project_dir%/.env.%kernel.environment%.local') + // ->decryptionEnvVar('base64:default::SYMFONY_DECRYPTION_SECRET') + ; + }; .. _`libsodium`: https://pecl.php.net/package/libsodium diff --git a/controller/error_pages.rst b/controller/error_pages.rst index 337723d8605..fabea2dcd22 100644 --- a/controller/error_pages.rst +++ b/controller/error_pages.rst @@ -273,10 +273,12 @@ configuration option to point to it: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'error_controller' => 'App\Controller\ErrorController::show', + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - ]); + $framework->errorController('App\Controller\ErrorController::show'); + }; The :class:`Symfony\\Component\\HttpKernel\\EventListener\\ErrorListener` class used by the FrameworkBundle as a listener of the ``kernel.exception`` event creates diff --git a/deployment/proxies.rst b/deployment/proxies.rst index 49aa04c8361..62d5c182c1e 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -68,16 +68,18 @@ and what headers your reverse proxy uses to send information: .. code-block:: php // config/packages/framework.php - use Symfony\Component\HttpFoundation\Request; - - $container->loadFromExtension('framework', [ - // the IP address (or range) of your proxy - 'trusted_proxies' => '192.0.0.1,10.0.0.0/8', - // trust *all* "X-Forwarded-*" headers (the ! prefix means to not trust those headers) - 'trusted_headers' => ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port'], - // or, if your proxy instead uses the "Forwarded" header - 'trusted_headers' => ['forwarded'], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework + // the IP address (or range) of your proxy + ->trustedProxies('192.0.0.1,10.0.0.0/8') + // trust *all* "X-Forwarded-*" headers (the ! prefix means to not trust those headers) + ->trustedHeaders(['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port']) + // or, if your proxy instead uses the "Forwarded" header + ->trustedHeaders(['forwarded']) + ; + }; .. deprecated:: 5.2 diff --git a/frontend/custom_version_strategy.rst b/frontend/custom_version_strategy.rst index bf5f82fd9f4..336acfbd295 100644 --- a/frontend/custom_version_strategy.rst +++ b/frontend/custom_version_strategy.rst @@ -190,12 +190,13 @@ the :ref:`version_strategy ` option: // config/packages/framework.php use App\Asset\VersionStrategy\GulpBusterVersionStrategy; + use Symfony\Config\FrameworkConfig; - $container->loadFromExtension('framework', [ + return static function (FrameworkConfig $framework) { // ... - 'assets' => [ - 'version_strategy' => GulpBusterVersionStrategy::class, - ], - ]); + $framework->assets() + ->versionStrategy(GulpBusterVersionStrategy::class) + ; + }; .. _`gulp-buster`: https://www.npmjs.com/package/gulp-buster diff --git a/http_cache/esi.rst b/http_cache/esi.rst index 6108df41f49..a166a01762e 100644 --- a/http_cache/esi.rst +++ b/http_cache/esi.rst @@ -88,10 +88,13 @@ First, to use ESI, be sure to enable it in your application configuration: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - // ... - 'esi' => ['enabled' => true], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->esi() + ->enabled(true) + ; + }; Now, suppose you have a page that is relatively static, except for a news ticker at the bottom of the content. With ESI, you can cache the news ticker @@ -225,10 +228,14 @@ that must be enabled in your configuration: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'fragments' => ['path' => '/_fragment'], - ]); + $framework->fragments() + ->path('/_fragment') + ; + }; One great advantage of the ESI renderer is that you can make your application as dynamic as needed and at the same time, hit the application as little as diff --git a/http_cache/ssi.rst b/http_cache/ssi.rst index 94bab702db4..f7cb9671b54 100644 --- a/http_cache/ssi.rst +++ b/http_cache/ssi.rst @@ -76,9 +76,13 @@ First, to use SSI, be sure to enable it in your application configuration: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'ssi' => ['enabled' => true], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->ssi() + ->enabled(true) + ; + }; Suppose you have a page with private content like a Profile page and you want to cache a static GDPR content block. With SSI, you can add some expiration @@ -86,7 +90,7 @@ on this block and keep the page private:: // src/Controller/ProfileController.php namespace App\Controller; - + // ... class ProfileController extends AbstractController { diff --git a/http_client.rst b/http_client.rst index e52f3d4940e..dc4018760fd 100644 --- a/http_client.rst +++ b/http_client.rst @@ -123,13 +123,14 @@ You can configure the global options using the ``default_options`` option: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'http_client' => [ - 'default_options' => [ - 'max_redirects' => 7, - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->httpClient() + ->defaultOptions() + ->maxRedirects(7) + ; + }; .. code-block:: php-standalone @@ -183,12 +184,14 @@ The HTTP client also has one configuration option called .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'http_client' => [ - 'max_host_connections' => 10, + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->httpClient() + ->maxHostConnections(10) // ... - ], - ]); + ; + }; .. code-block:: php-standalone @@ -264,32 +267,26 @@ autoconfigure the HTTP client based on the requested URL: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'http_client' => [ - 'scoped_clients' => [ - // only requests matching scope will use these options - 'github' => [ - 'scope' => 'https://api\.github\.com', - 'headers' => [ - 'Accept' => 'application/vnd.github.v3+json', - 'Authorization' => 'token %env(GITHUB_API_TOKEN)%', - ], - // ... - ], - - // using base_url, relative URLs (e.g. request("GET", "/repos/symfony/symfony-docs")) - // will default to these options - 'github' => [ - 'base_uri' => 'https://api.github.com', - 'headers' => [ - 'Accept' => 'application/vnd.github.v3+json', - 'Authorization' => 'token %env(GITHUB_API_TOKEN)%', - ], - // ... - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + // only requests matching scope will use these options + $framework->httpClient()->scopedClient('github') + ->scope('https://api\.github\.com') + ->header('Accept', 'application/vnd.github.v3+json') + ->header('Authorization', 'token %env(GITHUB_API_TOKEN)%') + // ... + ; + + // using base_url, relative URLs (e.g. request("GET", "/repos/symfony/symfony-docs")) + // will default to these options + $framework->httpClient()->scopedClient('github') + ->baseUri('https://api.github.com') + ->header('Accept', 'application/vnd.github.v3+json') + ->header('Authorization', 'token %env(GITHUB_API_TOKEN)%') + // ... + ; + }; .. code-block:: php-standalone @@ -432,24 +429,21 @@ each request (which overrides any global authentication): .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'http_client' => [ - 'scoped_clients' => [ - 'example_api' => [ - 'base_uri' => 'https://example.com/', + use Symfony\Config\FrameworkConfig; - // HTTP Basic authentication - 'auth_basic' => 'the-username:the-password', + return static function (FrameworkConfig $framework) { + $framework->httpClient()->scopedClient('example_api') + ->baseUri('https://example.com/') + // HTTP Basic authentication + ->authBasic('the-username:the-password') - // HTTP Bearer authentication (also called token authentication) - 'auth_bearer' => 'the-bearer-token', + // HTTP Bearer authentication (also called token authentication) + ->authBearer('the-bearer-token') - // Microsoft NTLM authentication - 'auth_ntlm' => 'the-username:the-password', - ], - ], - ], - ]); + // Microsoft NTLM authentication + ->authNtlm('the-username:the-password') + ; + }; .. code-block:: php-standalone @@ -537,15 +531,14 @@ Use the ``headers`` option to define the default headers added to all requests: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'http_client' => [ - 'default_options' => [ - 'headers' => [ - 'User-Agent' => 'My Fancy App', - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->httpClient() + ->defaultOptions() + ->header('User-Agent', 'My Fancy App') + ; + }; .. code-block:: php-standalone @@ -882,13 +875,14 @@ To force HTTP/2 for ``http`` URLs, you need to enable it explicitly via the .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'http_client' => [ - 'default_options' => [ - 'http_version' => '2.0', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->httpClient() + ->defaultOptions() + ->httpVersion('2.0') + ; + }; .. code-block:: php-standalone @@ -1733,11 +1727,13 @@ Then configure Symfony to use your callback: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'http_client' => [ - 'mock_response_factory' => MockClientCallback::class, - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->httpClient() + ->mockResponseFactory(MockClientCallback::class) + ; + }; .. _`cURL PHP extension`: https://www.php.net/curl .. _`PSR-17`: https://www.php-fig.org/psr/psr-17/ diff --git a/lock.rst b/lock.rst index db987f1d20e..8e64d42249f 100644 --- a/lock.rst +++ b/lock.rst @@ -129,32 +129,33 @@ this behavior by using the ``lock`` key like: .. code-block:: php // config/packages/lock.php - $container->loadFromExtension('framework', [ - 'lock' => null, - 'lock' => 'flock', - 'lock' => 'flock:///path/to/file', - 'lock' => 'semaphore', - 'lock' => 'memcached://m1.docker', - 'lock' => ['memcached://m1.docker', 'memcached://m2.docker'], - 'lock' => 'redis://r1.docker', - 'lock' => ['redis://r1.docker', 'redis://r2.docker'], - 'lock' => 'zookeeper://z1.docker', - 'lock' => 'zookeeper://z1.docker,z2.docker', - 'lock' => 'sqlite:///%kernel.project_dir%/var/lock.db', - 'lock' => 'mysql:host=127.0.0.1;dbname=app', - 'lock' => 'pgsql:host=127.0.0.1;dbname=app', - 'lock' => 'pgsql+advisory:host=127.0.0.1;dbname=lock', - 'lock' => 'sqlsrv:server=127.0.0.1;Database=app', - 'lock' => 'oci:host=127.0.0.1;dbname=app', - 'lock' => 'mongodb://127.0.0.1/app?collection=lock', - 'lock' => '%env(LOCK_DSN)%', - - // named locks - 'lock' => [ - 'invoice' => ['semaphore', 'redis://r2.docker'], - 'report' => 'semaphore', - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->lock() + ->resource('default', ['flock']) + ->resource('default', ['flock:///path/to/file']) + ->resource('default', ['semaphore']) + ->resource('default', ['memcached://m1.docker']) + ->resource('default', ['memcached://m1.docker', 'memcached://m2.docker']) + ->resource('default', ['redis://r1.docker']) + ->resource('default', ['redis://r1.docker', 'redis://r2.docker']) + ->resource('default', ['zookeeper://z1.docker']) + ->resource('default', ['zookeeper://z1.docker,z2.docker']) + ->resource('default', ['sqlite:///%kernel.project_dir%/var/lock.db']) + ->resource('default', ['mysql:host=127.0.0.1;dbname=app']) + ->resource('default', ['pgsql:host=127.0.0.1;dbname=app']) + ->resource('default', ['pgsql+advisory:host=127.0.0.1;dbname=lock']) + ->resource('default', ['sqlsrv:server=127.0.0.1;Database=app']) + ->resource('default', ['oci:host=127.0.0.1;dbname=app']) + ->resource('default', ['mongodb://127.0.0.1/app?collection=lock']) + ->resource('default', ['%env(LOCK_DSN)%']) + + // named locks + ->resource('invoice', ['semaphore', 'redis://r2.docker']) + ->resource('report', ['semaphore']) + ; + }; Locking a Resource ------------------ @@ -269,12 +270,15 @@ provides :ref:`named lock `: .. code-block:: php // config/packages/lock.php - $container->loadFromExtension('framework', [ - 'lock' => [ - 'invoice' => ['semaphore', 'redis://r2.docker'], - 'report' => 'semaphore', - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->lock() + ->resource('invoice', ['semaphore', 'redis://r2.docker']) + ->resource('report', ['semaphore']); + ; + }; + Each name becomes a service where the service id is part of the name of the lock (e.g. ``lock.invoice.factory``). An autowiring alias is also created for diff --git a/mailer.rst b/mailer.rst index f772dba65af..2a7329caacc 100644 --- a/mailer.rst +++ b/mailer.rst @@ -510,20 +510,20 @@ and headers. .. code-block:: php // config/packages/mailer.php - $container->loadFromExtension('framework', [ - // ... - 'mailer' => [ - 'envelope' => [ - 'sender' => 'fabien@example.com', - 'recipients' => ['foo@example.com', 'bar@example.com'], - ], - 'headers' => [ - 'from' => 'Fabien ', - 'bcc' => 'baz@example.com', - 'X-Custom-Header' => 'foobar', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $mailer = $framework->mailer(); + $mailer + ->envelope() + ->sender('fabien@example.com') + ->recipients(['foo@example.com', 'bar@example.com']) + ; + + $mailer->header('from')->value('Fabien '); + $mailer->header('bcc')->value('baz@example.com'); + $mailer->header('X-Custom-Header')->value('foobar'); + }; .. versionadded:: 5.2 @@ -1092,15 +1092,14 @@ This can be configured by replacing the ``dsn`` configuration entry with a .. code-block:: php // config/packages/mailer.php - $container->loadFromExtension('framework', [ - // ... - 'mailer' => [ - 'transports' => [ - 'main' => '%env(MAILER_DSN)%', - 'alternative' => '%env(MAILER_DSN_IMPORTANT)%', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->mailer() + ->transport('main', '%env(MAILER_DSN)%') + ->transport('alternative', '%env(MAILER_DSN_IMPORTANT)%') + ; + }; By default the first transport is used. The other transports can be used by adding a text header ``X-Transport`` to an email:: @@ -1163,16 +1162,17 @@ you have a transport called ``async``, you can route the message there: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'async' => '%env(MESSENGER_TRANSPORT_DSN)%', - ], - 'routing' => [ - 'Symfony\Component\Mailer\Messenger\SendEmailMessage' => 'async', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->messenger() + ->transport('async')->dsn('%env(MESSENGER_TRANSPORT_DSN)%'); + + $framework->messenger() + ->routing('Symfony\Component\Mailer\Messenger\SendEmailMessage') + ->senders(['async']); + }; + Thanks to this, instead of being delivered immediately, messages will be sent to the transport to be handled later (see :ref:`messenger-worker`). @@ -1213,11 +1213,12 @@ disable asynchronous delivery. .. code-block:: php // config/packages/mailer.php - $container->loadFromExtension('framework', [ - 'mailer' => [ - 'message_bus' => 'app.another_bus', - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->mailer() + ->messageBus('app.another_bus'); + }; .. versionadded:: 5.1 @@ -1300,12 +1301,13 @@ the mailer configuration file (e.g. in the ``dev`` or ``test`` environments): .. code-block:: php // config/packages/mailer.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'mailer' => [ - 'dsn' => 'null://null', - ], - ]); + $framework->mailer() + ->dsn('null://null'); + }; .. note:: @@ -1352,14 +1354,15 @@ a specific address, instead of the *real* address: .. code-block:: php // config/packages/mailer.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'mailer' => [ - 'envelope' => [ - 'recipients' => ['youremail@example.com'], - ], - ], - ]); + $framework->mailer() + ->envelope() + ->recipients(['youremail@example.com']) + ; + }; .. _`high availability`: https://en.wikipedia.org/wiki/High_availability .. _`load balancing`: https://en.wikipedia.org/wiki/Load_balancing_(computing) diff --git a/messenger.rst b/messenger.rst index c5725a4153a..000b4b622f6 100644 --- a/messenger.rst +++ b/messenger.rst @@ -179,19 +179,20 @@ that uses this configuration: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'async' => '%env(MESSENGER_TRANSPORT_DSN)%', - - // or expanded to configure more options - 'async' => [ - 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', - 'options' => [], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->messenger() + ->transport('async') + ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ; + + $framework->messenger() + ->transport('async') + ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->options([]) + ; + }; .. _messenger-routing: @@ -240,14 +241,14 @@ you can configure them to be sent to a transport: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'routing' => [ - // async is whatever name you gave your transport above - 'App\Message\SmsNotification' => 'async', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->messenger() + // async is whatever name you gave your transport above + ->routing('App\Message\SmsNotification')->senders(['async']) + ; + }; Thanks to this, the ``App\Message\SmsNotification`` will be sent to the ``async`` transport and its handler(s) will *not* be called immediately. Any messages not @@ -302,16 +303,15 @@ to multiple transports: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'routing' => [ - // route all messages that extend this example base class or interface - 'App\Message\AbstractAsyncMessage' => 'async', - 'App\Message\AsyncMessageInterface' => 'async', - 'My\Message\ToBeSentToTwoSenders' => ['async', 'audit'], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + // route all messages that extend this example base class or interface + $messenger->routing('App\Message\AbstractAsyncMessage')->senders(['async']); + $messenger->routing('App\Message\AsyncMessageInterface')->senders(['async']); + $messenger->routing('My\Message\ToBeSentToTwoSenders')->senders(['async', 'audit']); + }; .. note:: @@ -425,18 +425,16 @@ transport and "sending" messages there to be handled immediately: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - // ... other transports - - 'sync' => 'sync://', - ], - 'routing' => [ - 'App\Message\SmsNotification' => 'sync', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + // ... other transports + + $messenger->transport('sync')->dsn('sync://'); + $messenger->routing('App\Message\SmsNotification')->senders(['sync']); + }; Creating your Own Transport ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -561,28 +559,22 @@ different messages to them. For example: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'async_priority_high' => [ - 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', - 'options' => [ - 'queue_name' => 'high', - ], - ], - 'async_priority_low' => [ - 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', - 'options' => [ - 'queue_name' => 'low', - ], - ], - ], - 'routing' => [ - 'App\Message\SmsNotification' => 'async_priority_low', - 'App\Message\NewUserWelcomeEmail' => 'async_priority_high', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $messenger->transport('async_priority_high') + ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->options(['queue_name' => 'high']); + + $messenger->transport('async_priority_low') + ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->options(['queue_name' => 'low']); + + $messenger->routing('App\Message\SmsNotification')->senders(['async_priority_low']); + $messenger->routing('App\Message\NewUserWelcomeEmail')->senders(['async_priority_high']); + }; You can then run individual workers for each transport or instruct one worker to handle messages in a priority order: @@ -732,29 +724,27 @@ this is configurable for each transport: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'async_priority_high' => [ - 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', - - // default configuration - 'retry_strategy' => [ - 'max_retries' => 3, - // milliseconds delay - 'delay' => 1000, - // causes the delay to be higher before each retry - // e.g. 1 second delay, 2 seconds, 4 seconds - 'multiplier' => 2, - 'max_delay' => 0, - // override all of this with a service that - // implements Symfony\Component\Messenger\Retry\RetryStrategyInterface - // 'service' => null, - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $messenger->transport('async_priority_high') + ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + // default configuration + ->retryStrategy() + ->maxRetries(3) + // milliseconds delay + ->delay(1000) + // causes the delay to be higher before each retry + // e.g. 1 second delay, 2 seconds, 4 seconds + ->multiplier(2) + ->maxDelay(0) + // override all of this with a service that + // implements Symfony\Component\Messenger\Retry\RetryStrategyInterface + ->service(null) + ; + }; .. tip:: @@ -833,20 +823,19 @@ be discarded. To avoid this happening, you can instead configure a ``failure_tra .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - // after retrying, messages will be sent to the "failed" transport - 'failure_transport' => 'failed', - - 'transports' => [ - // ... other transports - - 'failed' => [ - 'dsn' => 'doctrine://default?queue_name=failed', - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + // after retrying, messages will be sent to the "failed" transport + $messenger->failureTransport('failed'); + + // ... other transports + + $messenger->transport('failed') + ->dsn('doctrine://default?queue_name=failed'); + }; In this example, if handling a message fails 3 times (default ``max_retries``), it will then be sent to the ``failed`` transport. While you *can* use @@ -900,8 +889,8 @@ override the failure transport for only specific transports: # config/packages/messenger.yaml framework: messenger: - # after retrying, messages will be sent to the "failed" transport - # by default if no "failed_transport" is configured inside a transport + # after retrying, messages will be sent to the "failed" transport + # by default if no "failed_transport" is configured inside a transport failure_transport: failed_default transports: @@ -915,7 +904,7 @@ override the failure transport for only specific transports: dsn: 'doctrine://default?queue_name=async_priority_low' failed_default: 'doctrine://default?queue_name=failed_default' - failed_high_priority: 'doctrine://default?queue_name=failed_high_priority' + failed_high_priority: 'doctrine://default?queue_name=failed_high_priority' .. code-block:: xml @@ -930,14 +919,14 @@ override the failure transport for only specific transports: https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - - + - + @@ -947,31 +936,30 @@ override the failure transport for only specific transports: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - // after retrying, messages will be sent to the "failed" transport - // by default if no "failure_transport" is configured inside a transport - 'failure_transport' => 'failed_default', - - 'transports' => [ - 'async_priority_high' => [ - 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', - 'failure_transport' => 'failed_high_priority' - ], - // since no failed transport is configured, the one used will be - // the global failure_transport set - 'async_priority_low' => [ - 'dsn' => 'doctrine://default?queue_name=async_priority_low', - ], - 'failed_default' => [ - 'dsn' => 'doctrine://default?queue_name=failed_default', - ], - 'failed_high_priority' => [ - 'dsn' => 'doctrine://default?queue_name=failed_high_priority', - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + // after retrying, messages will be sent to the "failed" transport + // by default if no "failure_transport" is configured inside a transport + $messenger->failureTransport('failed_default'); + + $messenger->transport('async_priority_high') + ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->failureTransport('failed_high_priority'); + + // since no failed transport is configured, the one used will be + // the global failure_transport set + $messenger->transport('async_priority_low') + ->dsn('doctrine://default?queue_name=async_priority_low'); + + $messenger->transport('failed_default') + ->dsn('doctrine://default?queue_name=failed_default'); + + $messenger->transport('failed_high_priority') + ->dsn('doctrine://default?queue_name=failed_high_priority'); + }; If there is no ``failure_transport`` defined globally or on the transport level, the messages will be discarded after the number of retries. @@ -1040,18 +1028,15 @@ options. Options can be passed to the transport via a DSN string or configuratio .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'my_transport' => [ - 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', - 'options' => [ - 'auto_setup' => false, - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $messenger->transport('my_transport') + ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->options(['auto_setup' => false]); + }; Options defined under ``options`` take precedence over ones defined in the DSN. @@ -1454,15 +1439,14 @@ override it in the ``test`` environment to use this transport: .. code-block:: php // config/packages/test/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'async_priority_normal' => [ - 'dsn' => 'in-memory://', - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $messenger->transport('async_priority_normal') + ->dsn('in-memory://'); + }; Then, while testing, messages will *not* be delivered to the real transport. Even better, in a test, you can check that exactly one message was sent @@ -1643,23 +1627,21 @@ this globally (or for each transport) to a service that implements .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'serializer' => [ - 'default_serializer' => 'messenger.transport.symfony_serializer', - 'symfony_serializer' => [ - 'format' => 'json', - 'context' => [], - ], - ], - 'transports' => [ - 'async_priority_normal' => [ - 'dsn' => ..., - 'serializer' => 'messenger.transport.symfony_serializer', - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $messenger->serializer() + ->defaultSerializer('messenger.transport.symfony_serializer') + ->symfonySerializer() + ->format('json') + ->context('foo', 'bar'); + + $messenger->transport('async_priority_normal') + ->dsn(...) + ->serializer('messenger.transport.symfony_serializer'); + }; The ``messenger.transport.symfony_serializer`` is a built-in service that uses the :doc:`Serializer component ` and can be configured in a few ways. @@ -1881,17 +1863,17 @@ Then, make sure to "route" your message to *both* transports: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'async_priority_normal' => '...', - 'image_transport' => '...', - ], - 'routing' => [ - 'App\Message\UploadedImage' => ['image_transport', 'async_priority_normal'], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $messenger->transport('async_priority_normal')->dsn(...); + $messenger->transport('image_transport')->dsn(...); + + $messenger->routing('App\Message\UploadedImage') + ->senders(['image_transport', 'async_priority_normal']); + }; That's it! You can now consume each transport: @@ -2024,22 +2006,16 @@ middleware and *only* include your own: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'buses' => [ - 'messenger.bus.default' => [ - // disable the default middleware - 'default_middleware' => false, - - // and/or add your own - 'middleware' => [ - 'App\Middleware\MyMiddleware', - 'App\Middleware\AnotherMiddleware', - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $bus = $messenger->bus('messenger.bus.default') + ->defaultMiddleware(false); + $bus->middleware()->id('App\Middleware\MyMiddleware'); + $bus->middleware()->id('App\Middleware\AnotherMiddleware'); + }; .. note:: @@ -2118,21 +2094,19 @@ may want to use: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'buses' => [ - 'command_bus' => [ - 'middleware' => [ - 'doctrine_transaction', - 'doctrine_ping_connection', - 'doctrine_close_connection', - // Using another entity manager - ['id' => 'doctrine_transaction', 'arguments' => ['custom']], - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $bus = $messenger->bus('command_bus'); + $bus->middleware()->id('doctrine_transaction'); + $bus->middleware()->id('doctrine_ping_connection'); + $bus->middleware()->id('doctrine_close_connection'); + // Using another entity manager + $bus->middleware()->id('doctrine_transaction') + ->arguments(['custom']); + }; Other Middlewares ~~~~~~~~~~~~~~~~~ @@ -2182,17 +2156,14 @@ when building absolute URLs. .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'buses' => [ - 'command_bus' => [ - 'middleware' => [ - 'router_context', - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $bus = $messenger->bus('command_bus'); + $bus->middleware()->id('router_context'); + }; Messenger Events diff --git a/messenger/custom-transport.rst b/messenger/custom-transport.rst index be41d63a41e..f43f347e642 100644 --- a/messenger/custom-transport.rst +++ b/messenger/custom-transport.rst @@ -203,13 +203,14 @@ named transport using your own DSN: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'yours' => 'my-transport://...', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->messenger() + ->transport('yours') + ->dsn('my-transport://...') + ; + }; In addition of being able to route your messages to the ``yours`` sender, this will give you access to the following services: diff --git a/messenger/multiple_buses.rst b/messenger/multiple_buses.rst index fc61a0c9dd2..5a1ffecf94c 100644 --- a/messenger/multiple_buses.rst +++ b/messenger/multiple_buses.rst @@ -74,33 +74,25 @@ an **event bus**. The event bus could have zero or more subscribers. .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - // The bus that is going to be injected when injecting MessageBusInterface - 'default_bus' => 'command.bus', - 'buses' => [ - 'command.bus' => [ - 'middleware' => [ - 'validation', - 'doctrine_transaction', - ], - ], - 'query.bus' => [ - 'middleware' => [ - 'validation', - ], - ], - 'event.bus' => [ - // the 'allow_no_handlers' middleware allows to have no handler - // configured for this bus without throwing an exception - 'default_middleware' => 'allow_no_handlers', - 'middleware' => [ - 'validation', - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + // The bus that is going to be injected when injecting MessageBusInterface + $framework->messenger()->defaultBus('command.bus'); + + $commandBus = $framework->messenger()->bus('command.bus'); + $commandBus->middleware()->id('validation'); + $commandBus->middleware()->id('doctrine_transaction'); + + $queryBus = $framework->messenger()->bus('query.bus'); + $queryBus->middleware()->id('validation'); + + $eventBus = $framework->messenger()->bus('event.bus'); + // the 'allow_no_handlers' middleware allows to have no handler + // configured for this bus without throwing an exception + $eventBus->defaultMiddleware('allow_no_handlers'); + $eventBus->middleware()->id('validation'); + }; This will create three new services: diff --git a/notifier.rst b/notifier.rst index 5bbd12252a2..c552d757dff 100644 --- a/notifier.rst +++ b/notifier.rst @@ -132,14 +132,14 @@ configure the ``texter_transports``: .. code-block:: php - # config/packages/notifier.php - $container->loadFromExtension('framework', [ - 'notifier' => [ - 'texter_transports' => [ - 'twilio' => '%env(TWILIO_DSN)%', - ], - ], - ]); + // config/packages/notifier.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->notifier() + ->texterTransport('twilio', '%env(TWILIO_DSN)%') + ; + }; .. _notifier-chat-channel: .. _notifier-chatter-dsn: @@ -224,14 +224,14 @@ Chatters are configured using the ``chatter_transports`` setting: .. code-block:: php - # config/packages/notifier.php - $container->loadFromExtension('framework', [ - 'notifier' => [ - 'chatter_transports' => [ - 'slack' => '%env(SLACK_DSN)%', - ], - ], - ]); + // config/packages/notifier.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->notifier() + ->chatterTransport('slack', '%env(SLACK_DSN)%') + ; + }; .. _notifier-email-channel: @@ -288,15 +288,16 @@ notification emails: .. code-block:: php - # config/packages/mailer.php - $container->loadFromExtension('framework', [ - 'mailer' => [ - 'dsn' => '%env(MAILER_DSN)%', - 'envelope' => [ - 'sender' => 'notifications@example.com', - ], - ], - ]); + // config/packages/mailer.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->mailer() + ->dsn('%env(MAILER_DSN)%') + ->envelope() + ->sender('notifications@example.com') + ; + }; Configure to use Failover or Round-Robin Transports ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -351,19 +352,19 @@ transport: .. code-block:: php - # config/packages/notifier.php - $container->loadFromExtension('framework', [ - 'notifier' => [ - 'chatter_transports' => [ - // Send notifications to Slack and use Telegram if - // Slack errored - 'main' => '%env(SLACK_DSN)% || %env(TELEGRAM_DSN)%', + // config/packages/notifier.php + use Symfony\Config\FrameworkConfig; - // Send notifications to the next scheduled transport calculated by round robin - 'roundrobin' => '%env(SLACK_DSN)% && %env(TELEGRAM_DSN)%', - ], - ], - ]); + return static function (FrameworkConfig $framework) { + $framework->notifier() + // Send notifications to Slack and use Telegram if + // Slack errored + ->chatterTransport('main', '%env(SLACK_DSN)% || %env(TELEGRAM_DSN)%') + + // Send notifications to the next scheduled transport calculated by round robin + ->chatterTransport('roundrobin', '%env(SLACK_DSN)% && %env(TELEGRAM_DSN)%') + ; + }; Creating & Sending Notifications -------------------------------- @@ -495,23 +496,21 @@ specify what channels should be used for specific levels (using .. code-block:: php - # config/packages/notifier.php - $container->loadFromExtension('framework', [ - 'notifier' => [ - // ... - 'channel_policy' => [ - // Use SMS, Slack and email for urgent notifications - 'urgent' => ['sms', 'chat/slack', 'email'], - - // Use Slack for highly important notifications - 'high' => ['chat/slack'], - - // Use browser for medium and low notifications - 'medium' => ['browser'], - 'low' => ['browser'], - ], - ], - ]); + // config/packages/notifier.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + // ... + $framework->notifier() + // Use SMS, Slack and email for urgent notifications + ->channelPolicy('urgent', ['sms', 'chat/slack', 'email']) + // Use Slack for highly important notifications + ->channelPolicy('high', ['chat/slack']) + // Use browser for medium and low notifications + ->channelPolicy('medium', ['browser']) + ->channelPolicy('medium', ['browser']) + ; + }; Now, whenever the notification's importance is set to "high", it will be sent using the Slack transport:: diff --git a/rate_limiter.rst b/rate_limiter.rst index 2ab832d7031..96f0cd0e5e0 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -177,21 +177,26 @@ enforce different levels of service (free or paid): .. code-block:: php // config/packages/rate_limiter.php - $container->loadFromExtension('framework', [ - 'rate_limiter' => [ - 'anonymous_api' => [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->rateLimiter() + ->limiter('anonymous_api') // use 'sliding_window' if you prefer that policy - 'policy' => 'fixed_window', - 'limit' => 100, - 'interval' => '60 minutes', - ], - 'authenticated_api' => [ - 'policy' => 'token_bucket', - 'limit' => 5000, - 'rate' => [ 'interval' => '15 minutes', 'amount' => 500 ], - ], - ], - ]); + ->policy('fixed_window') + ->limit(100) + ->interval('60 minutes') + ; + + $framework->rateLimiter() + ->limiter('authenticated_api') + ->policy('token_bucket') + ->limit(5000) + ->rate() + ->interval('15 minutes') + ->amount(500) + ; + }; .. note:: @@ -409,16 +414,17 @@ Use the ``cache_pool`` option to override the cache used by a specific limiter .. code-block:: php // config/packages/rate_limiter.php - $container->loadFromExtension('framework', [ - 'rate_limiter' => [ - 'anonymous_api' => [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->rateLimiter() + ->limiter('anonymous_api') // ... // use the "cache.anonymous_rate_limiter" cache pool - 'cache_pool' => 'cache.anonymous_rate_limiter', - ], - ], - ]); + ->cachePool('cache.anonymous_rate_limiter') + ; + }; .. note:: @@ -483,16 +489,17 @@ you can use a specific :ref:`named lock ` via the .. code-block:: php // config/packages/rate_limiter.php - $container->loadFromExtension('framework', [ - 'rate_limiter' => [ - 'anonymous_api' => [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->rateLimiter() + ->limiter('anonymous_api') // ... // use the "lock.rate_limiter.factory" for this limiter - 'lock_factory' => 'lock.rate_limiter.factory', - ], - ], - ]); + ->lockFactory('lock.rate_limiter.factory') + ; + }; .. _`DoS attacks`: https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html .. _`Apache mod_ratelimit`: https://httpd.apache.org/docs/current/mod/mod_ratelimit.html diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 3b2f97a9156..0ca87286119 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -454,9 +454,11 @@ doubling them to prevent Symfony from interpreting them as container parameters) .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'ide' => 'myide://open?url=file://%%f&line=%%l', - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->ide('myide://open?url=file://%%f&line=%%l'); + }; Since every developer uses a different IDE, the recommended way to enable this feature is to configure it on a system level. This can be done by setting the @@ -596,9 +598,11 @@ the application won't respond and the user will receive a 400 response. .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'trusted_hosts' => ['^example\.com$', '^example\.org$'], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->trustedHosts(['^example\.com$', '^example\.org$']); + }; Hosts can also be configured to respond to any subdomain, via ``^(.+\.)?example\.com$`` for instance. @@ -724,9 +728,11 @@ You can also set ``esi`` to ``true`` to enable it: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'esi' => true, - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->esi()->enabled(true); + }; fragments ~~~~~~~~~ @@ -1359,13 +1365,12 @@ To configure a ``jsonp`` format: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'request' => [ - 'formats' => [ - 'jsonp' => 'application/javascript', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->request() + ->format('jsonp', 'application/javascript'); + }; router ~~~~~~ @@ -1720,11 +1725,12 @@ setting the value to ``null``: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'session' => [ - 'save_path' => null, - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->session() + ->savePath(null); + }; .. _reference-session-metadata-update-threshold: @@ -1774,11 +1780,12 @@ Whether to enable the session support in the framework. .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'session' => [ - 'enabled' => true, - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->session() + ->enabled(true); + }; use_cookies ........... @@ -1830,12 +1837,13 @@ This option allows you to define a base path to be used for assets: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'assets' => [ - 'base_path' => '/images', - ], - ]); + $framework->assets() + ->basePath('/images'); + }; .. _reference-templating-base-urls: .. _reference-assets-base-urls: @@ -1879,12 +1887,13 @@ collection each time it generates an asset's path: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'assets' => [ - 'base_urls' => ['http://cdn.example.com/'], - ], - ]); + $framework->assets() + ->baseUrls(['http://cdn.example.com/']); + }; .. _reference-framework-assets-packages: @@ -1928,16 +1937,14 @@ You can group assets into packages, to specify different base URLs for them: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'assets' => [ - 'packages' => [ - 'avatars' => [ - 'base_urls' => 'http://static_cdn.example.com/avatars', - ], - ], - ], - ]); + $framework->assets() + ->package('avatars') + ->baseUrls(['http://static_cdn.example.com/avatars']); + }; Now you can use the ``avatars`` package in your templates: @@ -2005,12 +2012,13 @@ Now, activate the ``version`` option: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'assets' => [ - 'version' => 'v2', - ], - ]); + $framework->assets() + ->version('v2'); + }; Now, the same asset will be rendered as ``/images/logo.png?v2`` If you use this feature, you **must** manually increment the ``version`` value @@ -2132,25 +2140,25 @@ individually for each asset package: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'assets' => [ - 'version_strategy' => 'app.asset.my_versioning_strategy', - 'packages' => [ - 'foo_package' => [ - // this package removes any versioning (its assets won't be versioned) - 'version' => null, - ], - 'bar_package' => [ - // this package uses its own strategy (the default strategy is ignored) - 'version_strategy' => 'app.asset.another_version_strategy', - ], - 'baz_package' => [ - // this package inherits the default strategy - 'base_path' => '/images', - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + // ... + $framework->assets() + ->versionStrategy('app.asset.my_versioning_strategy'); + + $framework->assets()->package('foo_package') + // this package removes any versioning (its assets won't be versioned) + ->version(null); + + $framework->assets()->package('bar_package') + // this package uses its own strategy (the default strategy is ignored) + ->versionStrategy('app.asset.another_version_strategy'); + + $framework->assets()->package('baz_package') + // this package inherits the default strategy + ->basePath('/images'); + }; .. note:: @@ -2229,24 +2237,24 @@ package: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'assets' => [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + // ... + $framework->assets() // this manifest is applied to every asset (including packages) - 'json_manifest_path' => '%kernel.project_dir%/public/build/manifest.json', - // you can use absolute URLs too and Symfony will download them automatically - // 'json_manifest_path' => 'https://cdn.example.com/manifest.json', - 'packages' => [ - 'foo_package' => [ - // this package uses its own manifest (the default file is ignored) - 'json_manifest_path' => '%kernel.project_dir%/public/build/a_different_manifest.json', - ], - 'bar_package' => [ - // this package uses the global manifest (the default file is used) - 'base_path' => '/images', - ], - ], - ], - ]); + ->jsonManifestPath('%kernel.project_dir%/public/build/manifest.json'); + + // you can use absolute URLs too and Symfony will download them automatically + // 'json_manifest_path' => 'https://cdn.example.com/manifest.json', + $framework->assets()->package('foo_package') + // this package uses its own manifest (the default file is ignored) + ->jsonManifestPath('%kernel.project_dir%/public/build/a_different_manifest.json'); + + $framework->assets()->package('bar_package') + // this package uses the global manifest (the default file is used) + ->basePath('/images'); + }; .. versionadded:: 5.1 @@ -2335,11 +2343,12 @@ performance a bit: .. code-block:: php // config/packages/translation.php - $container->loadFromExtension('framework', [ - 'translator' => [ - 'enabled_locales' => ['en', 'es'], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->translator() + ->enabledLocales(['en', 'es']); + }; If some user makes requests with a locale not included in this option, the application won't display any error because Symfony will display contents using @@ -2621,15 +2630,13 @@ the component will look for additional validation files: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'validation' => [ - 'mapping' => [ - 'paths' => [ - '%kernel.project_dir%/config/validation/', - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->validation() + ->mapping() + ->paths(['%kernel.project_dir%/config/validation/']); + }; annotations ~~~~~~~~~~~ @@ -2927,16 +2934,14 @@ To configure a Redis cache pool with a default lifetime of 1 hour, do the follow .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'cache' => [ - 'pools' => [ - 'cache.mycache' => [ - 'adapter' => 'cache.adapter.redis', - 'default_lifetime' => 3600, - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->cache() + ->pool('cache.mycache') + ->adapters(['cache.adapter.redis']) + ->defaultLifetime(3600); + }; .. _reference-cache-pools-name: @@ -3094,9 +3099,12 @@ A list of lock stores to be created by the framework extension. .. code-block:: php // config/packages/lock.php - $container->loadFromExtension('framework', [ - 'lock' => '%env(LOCK_DSN)%', - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->lock() + ->resource('default', ['%env(LOCK_DSN)%']); + }; .. seealso:: @@ -3281,11 +3289,14 @@ A list of workflows to be created by the framework extension: .. code-block:: php // config/packages/workflow.php - $container->loadFromExtension('framework', [ - 'workflows' => [ - 'my_workflow' => // ... - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->workflows() + ->workflows('my_workflow') + // ... + ; + }; .. seealso:: diff --git a/security.rst b/security.rst index 9368c4464ef..57c306fb26d 100644 --- a/security.rst +++ b/security.rst @@ -680,43 +680,41 @@ and set the ``limiter`` option to its service ID: .. code-block:: php // config/packages/security.php + use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\Security\Http\RateLimiter\DefaultLoginRateLimiter; + use Symfony\Config\FrameworkConfig; + use Symfony\Config\SecurityConfig; + + return static function (ContainerBuilder $container, FrameworkConfig $framework, SecurityConfig $security) { + $framework->rateLimiter() + ->limiter('username_ip_login') + ->policy('token_bucket') + ->limit(5) + ->rate() + ->interval('5 minutes') + ; - $container->loadFromExtension('framework', [ - 'rate_limiter' => [ - // define 2 rate limiters (one for username+IP, the other for IP) - 'username_ip_login' => [ - 'policy' => 'token_bucket', - 'limit' => 5, - 'rate' => [ 'interval' => '5 minutes' ], - ], - 'ip_login' => [ - 'policy' => 'sliding_window', - 'limit' => 50, - 'interval' => '15 minutes', - ], - ], - ]); - - $container->register('app.login_rate_limiter', DefaultLoginRateLimiter::class) - ->setArguments([ - // 1st argument is the limiter for IP - new Reference('limiter.ip_login'), - // 2nd argument is the limiter for username+IP - new Reference('limiter.username_ip_login'), - ]); + $framework->rateLimiter() + ->limiter('ip_login') + ->policy('sliding_window') + ->limit(50) + ->interval('15 minutes') + ; - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - // use a custom rate limiter via its service ID - 'login_throttling' => [ - 'limiter' => 'app.login_rate_limiter', - ], - ], - ], - ]); + $container->register('app.login_rate_limiter', DefaultLoginRateLimiter::class) + ->setArguments([ + // 1st argument is the limiter for IP + new Reference('limiter.ip_login'), + // 2nd argument is the limiter for username+IP + new Reference('limiter.username_ip_login'), + ]); + + $security->firewall('main') + ->loginThrottling() + ->limiter('app.login_rate_limiter') + ; + }; .. _`security-authorization`: .. _denying-access-roles-and-other-authorization: diff --git a/security/csrf.rst b/security/csrf.rst index 51b750b1ceb..8416cd4cafc 100644 --- a/security/csrf.rst +++ b/security/csrf.rst @@ -51,9 +51,13 @@ for more information): .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'csrf_protection' => null, - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->csrfProtection() + ->enabled(true) + ; + }; The tokens used for CSRF protection are meant to be different for every user and they are stored in the session. That's why a session is started automatically as diff --git a/security/remember_me.rst b/security/remember_me.rst index 4f0af428361..2efbd8af94e 100644 --- a/security/remember_me.rst +++ b/security/remember_me.rst @@ -288,7 +288,7 @@ so ``DoctrineTokenProvider`` can store the tokens: .. code-block:: php - # config/packages/doctrine.php + // config/packages/doctrine.php use Symfony\Config\DoctrineConfig; return static function (DoctrineConfig $doctrine) { diff --git a/session/database.rst b/session/database.rst index 58d8e48bab4..5e076329640 100644 --- a/session/database.rst +++ b/session/database.rst @@ -149,14 +149,14 @@ configuration option to tell Symfony to use this service as the session handler: // config/packages/framework.php use Symfony\Component\HttpFoundation\Session\Storage\Handler\RedisSessionHandler; + use Symfony\Config\FrameworkConfig; - // ... - $container->loadFromExtension('framework', [ + return static function (FrameworkConfig $framework) { // ... - 'session' => [ - 'handler_id' => RedisSessionHandler::class, - ], - ]); + $framework->session() + ->handlerId(RedisSessionHandler::class) + ; + }; That's all! Symfony will now use your Redis server to read and write the session data. The main drawback of this solution is that Redis does not perform session @@ -273,14 +273,14 @@ configuration option to tell Symfony to use this service as the session handler: // config/packages/framework.php use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; + use Symfony\Config\FrameworkConfig; - // ... - $container->loadFromExtension('framework', [ + return static function (FrameworkConfig $framework) { // ... - 'session' => [ - 'handler_id' => PdoSessionHandler::class, - ], - ]); + $framework->session() + ->handlerId(PdoSessionHandler::class) + ; + }; Configuring the Session Table and Column Names ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -532,14 +532,14 @@ configuration option to tell Symfony to use this service as the session handler: // config/packages/framework.php use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler; + use Symfony\Config\FrameworkConfig; - // ... - $container->loadFromExtension('framework', [ + return static function (FrameworkConfig $framework) { // ... - 'session' => [ - 'handler_id' => MongoDbSessionHandler::class, - ], - ]); + $framework->session() + ->handlerId(MongoDbSessionHandler::class) + ; + }; .. note:: diff --git a/session/php_bridge.rst b/session/php_bridge.rst index ba7fc53d41a..a0fbfc8e06b 100644 --- a/session/php_bridge.rst +++ b/session/php_bridge.rst @@ -41,12 +41,14 @@ for the ``handler_id``: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'session' => [ - 'storage_factory_id' => 'session.storage.factory.php_bridge', - 'handler_id' => null, - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->session() + ->storageFactoryId('session.storage.factory.php_bridge') + ->handlerId(null) + ; + }; Otherwise, if the problem is that you cannot avoid the application starting the session with ``session_start()``, you can still make use of @@ -83,12 +85,14 @@ the example below: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'session' => [ - 'storage_factory_id' => 'session.storage.factory.php_bridge', - 'handler_id' => 'session.storage.native_file', - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->session() + ->storageFactoryId('session.storage.factory.php_bridge') + ->handlerId('session.storage.native_file') + ; + }; .. note:: diff --git a/session/proxy_examples.rst b/session/proxy_examples.rst index c4c3f9423a3..67d46adb27b 100644 --- a/session/proxy_examples.rst +++ b/session/proxy_examples.rst @@ -46,13 +46,14 @@ Symfony to use your session handler instead of the default one: // config/packages/framework.php use App\Session\CustomSessionHandler; - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'session' => [ - // ... - 'handler_id' => CustomSessionHandler::class, - ], - ]); + $framework->session() + ->handlerId(CustomSessionHandler::class) + ; + }; Keep reading the next sections to learn how to use the session handlers in practice to solve two common use cases: encrypt session information and define read-only diff --git a/templating/hinclude.rst b/templating/hinclude.rst index 8172ae60652..3a117148983 100644 --- a/templating/hinclude.rst +++ b/templating/hinclude.rst @@ -60,12 +60,14 @@ default content rendering some template: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'fragments' => [ - 'hinclude_default_template' => 'hinclude.html.twig', - ], - ]); + $framework->fragments() + ->hincludeDefaultTemplate('hinclude.html.twig') + ; + }; You can define default templates per ``render()`` function (which will override any global default template that is defined): diff --git a/testing/profiling.rst b/testing/profiling.rst index d3fa71f8e76..db7714b9d1f 100644 --- a/testing/profiling.rst +++ b/testing/profiling.rst @@ -47,15 +47,15 @@ tests significantly. That's why Symfony disables it by default: .. code-block:: php // config/packages/test/web_profiler.php + use Symfony\Config\FrameworkConfig; - // ... - $container->loadFromExtension('framework', [ + return static function (FrameworkConfig $framework) { // ... - 'profiler' => [ - 'enabled' => true, - 'collect' => false, - ], - ]); + $framework->profiler() + ->enabled(true) + ->collect(false) + ; + }; Setting ``collect`` to ``true`` enables the profiler for all tests. However, if you need the profiler only in a few tests, you can keep it disabled globally and @@ -71,7 +71,7 @@ provided by the collectors obtained through the ``$client->getProfile()`` call:: // tests/Controller/LuckyControllerTest.php namespace App\Tests\Controller; - + use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class LuckyControllerTest extends WebTestCase diff --git a/translation.rst b/translation.rst index 670142f7b40..382beed92a0 100644 --- a/translation.rst +++ b/translation.rst @@ -92,11 +92,16 @@ are located: .. code-block:: php // config/packages/translation.php - $container->loadFromExtension('framework', [ - 'default_locale' => 'en', - 'translator' => ['default_path' => '%kernel.project_dir%/translations'], + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - ]); + $framework + ->defaultLocale('en') + ->translator() + ->defaultPath('%kernel.project_dir%/translations') + ; + }; The locale used in translations is the one stored on the request. This is typically set via a ``_locale`` attribute on your routes (see :ref:`translation-locale-url`). @@ -571,13 +576,13 @@ if you're generating translations with specialized programs or teams. .. code-block:: php // config/packages/translation.php - $container->loadFromExtension('framework', [ - 'translator' => [ - 'paths' => [ - '%kernel.project_dir%/custom/path/to/translations', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->translator() + ->paths(['%kernel.project_dir%/custom/path/to/translations']) + ; + }; .. note:: @@ -647,10 +652,14 @@ checks translation resources for several locales: .. code-block:: php // config/packages/translation.php - $container->loadFromExtension('framework', [ - 'translator' => ['fallbacks' => ['en']], - // ... - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + // ... + $framework->translator() + ->fallbacks(['en']) + ; + }; .. note:: diff --git a/translation/locale.rst b/translation/locale.rst index 87f973a146a..79a9d45ce39 100644 --- a/translation/locale.rst +++ b/translation/locale.rst @@ -65,7 +65,7 @@ A better policy is to include the locale in the URL using the .. configuration-block:: .. code-block:: php-annotations - + // src/Controller/ContactController.php namespace App\Controller; @@ -177,6 +177,8 @@ the framework: .. code-block:: php // config/packages/translation.php - $container->loadFromExtension('framework', [ - 'default_locale' => 'en', - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->defaultLocale('en'); + }; diff --git a/validation.rst b/validation.rst index 0ad5a3108ec..5f9eab48cc6 100644 --- a/validation.rst +++ b/validation.rst @@ -251,11 +251,13 @@ file: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'validation' => [ - 'enabled' => true, - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->validation() + ->enabled(true) + ; + }; Besides, if you plan to use annotations to configure validation, replace the previous configuration by the following: @@ -287,11 +289,13 @@ previous configuration by the following: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'validation' => [ - 'enable_annotations' => true, - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->validation() + ->enableAnnotations(true) + ; + }; .. tip:: diff --git a/workflow.rst b/workflow.rst index bd36eb49014..6d65ba18305 100644 --- a/workflow.rst +++ b/workflow.rst @@ -120,43 +120,40 @@ like this: // config/packages/workflow.php use App\Entity\BlogPost; - - $container->loadFromExtension('framework', [ - 'workflows' => [ - 'blog_publishing' => [ - 'type' => 'workflow', // or 'state_machine' - 'audit_trail' => [ - 'enabled' => true - ], - 'marking_store' => [ - 'type' => 'method', - 'property' => 'currentPlace', - ], - 'supports' => [BlogPost::class], - 'initial_marking' => 'draft', - 'places' => [ - 'draft', - 'reviewed', - 'rejected', - 'published', - ], - 'transitions' => [ - 'to_review' => [ - 'from' => 'draft', - 'to' => 'reviewed', - ], - 'publish' => [ - 'from' => 'reviewed', - 'to' => 'published', - ], - 'reject' => [ - 'from' => 'reviewed', - 'to' => 'rejected', - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $blogPublishing = $framework->workflows()->workflows('blog_publishing'); + $blogPublishing + ->type('workflow') // or 'state_machine' + ->supports([BlogPost::class]) + ->initialMarking(['draft']); + + $blogPublishing->auditTrail()->enabled(true); + $blogPublishing->markingStore() + ->type('method') + ->property('currentPlace'); + + $blogPublishing->place()->name('draft'); + $blogPublishing->place()->name('reviewed'); + $blogPublishing->place()->name('rejected'); + $blogPublishing->place()->name('published'); + + $blogPublishing->transition() + ->name('to_review') + ->from(['draft']) + ->to(['reviewed']); + + $blogPublishing->transition() + ->name('publish') + ->from(['reviewed']) + ->to(['published']); + + $blogPublishing->transition() + ->name('reject') + ->from(['reviewed']) + ->to(['rejected']); + }; .. tip:: @@ -553,23 +550,25 @@ to :ref:`Guard events `, which are always fired: .. code-block:: php // config/packages/workflow.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'workflows' => [ - 'blog_publishing' => [ - // you can pass one or more event names - 'events_to_dispatch' => [ - 'workflow.leave', - 'workflow.completed', - ], - - // pass an empty array to not dispatch any event - 'events_to_dispatch' => [], - - // ... - ], - ], - ]); + + $blogPublishing = $framework->workflows()->workflows('blog_publishing'); + + // ... + // you can pass one or more event names + $blogPublishing->eventsToDispatch([ + 'workflow.leave', + 'workflow.completed', + ]); + + // pass an empty array to not dispatch any event + $blogPublishing->eventsToDispatch([]); + + // ... + }; You can also disable a specific event from being fired when applying a transition:: @@ -731,36 +730,33 @@ transition. The value of this option is any valid expression created with the .. code-block:: php // config/packages/workflow.php - use App\Entity\BlogPost; - - $container->loadFromExtension('framework', [ - 'workflows' => [ - 'blog_publishing' => [ - // ... previous configuration - - 'transitions' => [ - 'to_review' => [ - // the transition is allowed only if the current user has the ROLE_REVIEWER role. - 'guard' => 'is_granted("ROLE_REVIEWER")', - 'from' => 'draft', - 'to' => 'reviewed', - ], - 'publish' => [ - // or "is_anonymous", "is_remember_me", "is_fully_authenticated", "is_granted" - 'guard' => 'is_authenticated', - 'from' => 'reviewed', - 'to' => 'published', - ], - 'reject' => [ - // or any valid expression language with "subject" referring to the post - 'guard' => 'is_granted("ROLE_ADMIN") and subject.isStatusReviewed()', - 'from' => 'reviewed', - 'to' => 'rejected', - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $blogPublishing = $framework->workflows()->workflows('blog_publishing'); + // ... previous configuration + + $blogPublishing->transition() + ->name('to_review') + // the transition is allowed only if the current user has the ROLE_REVIEWER role. + ->guard('is_granted("ROLE_REVIEWER")') + ->from(['draft']) + ->to(['reviewed']); + + $blogPublishing->transition() + ->name('publish') + // or "is_anonymous", "is_remember_me", "is_fully_authenticated", "is_granted" + ->guard('is_authenticated') + ->from(['reviewed']) + ->to(['published']); + + $blogPublishing->transition() + ->name('reject') + // or any valid expression language with "subject" referring to the post + ->guard('is_granted("ROLE_ADMIN") and subject.isStatusReviewed()') + ->from(['reviewed']) + ->to(['rejected']); + }; You can also use transition blockers to block and return a user-friendly error message when you stop a transition from happening. @@ -945,42 +941,43 @@ be only the title of the workflow or very complex objects: .. code-block:: php // config/packages/workflow.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $blogPublishing = $framework->workflows()->workflows('blog_publishing'); + // ... previous configuration + + $blogPublishing->metadata([ + 'title' => 'Blog Publishing Workflow' + ]); + // ... - 'workflows' => [ - 'blog_publishing' => [ - 'metadata' => [ - 'title' => 'Blog Publishing Workflow', - ], - // ... - 'places' => [ - 'draft' => [ - 'metadata' => [ - 'max_num_of_words' => 500, - ], - ], - // ... - ], - 'transitions' => [ - 'to_review' => [ - 'from' => 'draft', - 'to' => 'review', - 'metadata' => [ - 'priority' => 0.5, - ], - ], - 'publish' => [ - 'from' => 'reviewed', - 'to' => 'published', - 'metadata' => [ - 'hour_limit' => 20, - 'explanation' => 'You can not publish after 8 PM.', - ], - ], - ], - ], - ], - ]); + + $blogPublishing->place() + ->name('draft') + ->metadata([ + 'max_num_of_words' => 500, + ]); + + // ... + + $blogPublishing->transition() + ->name('to_review') + ->from(['draft']) + ->to(['reviewed']) + ->metadata([ + 'priority' => 0.5, + ]); + + $blogPublishing->transition() + ->name('publish') + ->from(['reviewed']) + ->to(['published']) + ->metadata([ + 'hour_limit' => 20, + 'explanation' => 'You can not publish after 8 PM.', + ]); + }; Then you can access this metadata in your controller as follows:: diff --git a/workflow/dumping-workflows.rst b/workflow/dumping-workflows.rst index 5dda2ba6c56..98e5911561f 100644 --- a/workflow/dumping-workflows.rst +++ b/workflow/dumping-workflows.rst @@ -251,75 +251,70 @@ Below is the configuration for the pull request state machine with styling added .. code-block:: php // config/packages/workflow.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'workflows' => [ - 'pull_request' => [ - 'type' => 'state_machine', - 'marking_store' => [ - 'type' => 'method', - 'property' => 'currentPlace', - ], - 'supports' => ['App\Entity\PullRequest'], - 'initial_marking' => 'start', - 'places' => [ - 'start', - 'coding', - 'test', - 'review' => [ - 'metadata' => [ - 'description' => 'Human review', - ], - ], - 'merged', - 'closed' => [ - 'metadata' => [ - 'bg_color' => 'DeepSkyBlue', - ], - ], - ], - 'transitions' => [ - 'submit'=> [ - 'from' => 'start', - 'to' => 'test', - ], - 'update'=> [ - 'from' => ['coding', 'test', 'review'], - 'to' => 'test', - 'metadata' => [ - 'arrow_color' => 'Turquoise', - ], - ], - 'wait_for_review'=> [ - 'from' => 'test', - 'to' => 'review', - 'metadata' => [ - 'color' => 'Orange', - ], - ], - 'request_change'=> [ - 'from' => 'review', - 'to' => 'coding', - ], - 'accept'=> [ - 'from' => 'review', - 'to' => 'merged', - 'metadata' => [ - 'label' => 'Accept PR', - ], - ], - 'reject'=> [ - 'from' => 'review', - 'to' => 'closed', - ], - 'reopen'=> [ - 'from' => 'start', - 'to' => 'review', - ], - ], - ], - ], - ]); + $pullRequest = $framework->workflows()->workflows('pull_request'); + + $pullRequest + ->type('state_machine') + ->supports(['App\Entity\PullRequest']) + ->initialMarking(['start']); + + $pullRequest->markingStore() + ->type('method') + ->property('currentPlace'); + + $pullRequest->place()->name('start'); + $pullRequest->place()->name('coding'); + $pullRequest->place()->name('test'); + $pullRequest->place() + ->name('review') + ->metadata(['description' => 'Human review']); + $pullRequest->place()->name('merged'); + $pullRequest->place() + ->name('closed') + ->metadata(['bg_color' => 'DeepSkyBlue',]); + + $pullRequest->transition() + ->name('submit') + ->from(['start']) + ->to(['test']); + + $pullRequest->transition() + ->name('update') + ->from(['coding', 'test', 'review']) + ->to(['test']) + ->metadata(['arrow_color' => 'Turquoise']); + + $pullRequest->transition() + ->name('wait_for_review') + ->from(['test']) + ->to(['review']) + ->metadata(['color' => 'Orange']); + + $pullRequest->transition() + ->name('request_change') + ->from(['review']) + ->to(['coding']); + + $pullRequest->transition() + ->name('accept') + ->from(['review']) + ->to(['merged']) + ->metadata(['label' => 'Accept PR']); + + $pullRequest->transition() + ->name('reject') + ->from(['review']) + ->to(['closed']); + + $pullRequest->transition() + ->name('accept') + ->from(['closed']) + ->to(['review']); + }; The PlantUML image will look like this: diff --git a/workflow/workflow-and-state-machine.rst b/workflow/workflow-and-state-machine.rst index 730cf66bccc..6ef73aa60cf 100644 --- a/workflow/workflow-and-state-machine.rst +++ b/workflow/workflow-and-state-machine.rst @@ -192,58 +192,62 @@ Below is the configuration for the pull request state machine. .. code-block:: php // config/packages/workflow.php - $container->loadFromExtension('framework', [ - // ... - 'workflows' => [ - 'pull_request' => [ - 'type' => 'state_machine', - 'marking_store' => [ - 'type' => 'method', - 'property' => 'currentPlace', - ], - 'supports' => ['App\Entity\PullRequest'], - 'initial_marking' => 'start', - 'places' => [ - 'start', - 'coding', - 'test', - 'review', - 'merged', - 'closed', - ], - 'transitions' => [ - 'submit'=> [ - 'from' => 'start', - 'to' => 'test', - ], - 'update'=> [ - 'from' => ['coding', 'test', 'review'], - 'to' => 'test', - ], - 'wait_for_review'=> [ - 'from' => 'test', - 'to' => 'review', - ], - 'request_change'=> [ - 'from' => 'review', - 'to' => 'coding', - ], - 'accept'=> [ - 'from' => 'review', - 'to' => 'merged', - ], - 'reject'=> [ - 'from' => 'review', - 'to' => 'closed', - ], - 'reopen'=> [ - 'from' => 'start', - 'to' => 'review', - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $pullRequest = $framework->workflows()->workflows('pull_request'); + + $pullRequest + ->type('state_machine') + ->supports(['App\Entity\PullRequest']) + ->initialMarking(['start']); + + $pullRequest->markingStore() + ->type('method') + ->property('currentPlace'); + + $pullRequest->place()->name('start'); + $pullRequest->place()->name('coding'); + $pullRequest->place()->name('test'); + $pullRequest->place()->name('review'); + $pullRequest->place()->name('merged'); + $pullRequest->place()->name('closed'); + + $pullRequest->transition() + ->name('submit') + ->from(['start']) + ->to(['test']); + + $pullRequest->transition() + ->name('update') + ->from(['coding', 'test', 'review']) + ->to(['test']); + + $pullRequest->transition() + ->name('wait_for_review') + ->from(['test']) + ->to(['review']); + + $pullRequest->transition() + ->name('request_change') + ->from(['review']) + ->to(['coding']); + + $pullRequest->transition() + ->name('accept') + ->from(['review']) + ->to(['merged']); + + $pullRequest->transition() + ->name('reject') + ->from(['review']) + ->to(['closed']); + + $pullRequest->transition() + ->name('accept') + ->from(['closed']) + ->to(['review']); + }; In a Symfony application using the :ref:`default services.yaml configuration `, From 19b8d2318d997af810c6b4c456a29419e551fed0 Mon Sep 17 00:00:00 2001 From: iamvar Date: Sat, 1 May 2021 11:52:17 +0300 Subject: [PATCH 0930/1519] update example for attributes --- components/serializer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/serializer.rst b/components/serializer.rst index ac6ee533c8c..7f71344a61b 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -1608,7 +1608,7 @@ and ``BitBucketCodeRepository`` classes: 'github' => GitHubCodeRepository::class, 'bitbucket' => BitBucketCodeRepository::class, ])] - interface CodeRepository + abstract class CodeRepository { // ... } From 1fb6ce965c054f438ee2f3954f899f7eacef32b3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 3 May 2021 12:14:40 +0200 Subject: [PATCH 0931/1519] Remove unneeded versionadded directives --- testing.rst | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/testing.rst b/testing.rst index d354f7899ab..b523c263c7b 100644 --- a/testing.rst +++ b/testing.rst @@ -812,17 +812,6 @@ However, Symfony provides useful shortcut methods for the most common cases: :local: :depth: 1 -.. versionadded:: 4.3 - - The shortcut methods for assertions using ``WebTestCase`` were introduced - in Symfony 4.3. - -.. versionadded:: 4.4 - - Starting from Symfony 4.4, when using `symfony/panther`_ for end-to-end - testing, you can use all the following assertions except the ones related to - the :doc:`Crawler `. - Response Assertions ................... From 649dd43462a6ba3ed9d50757efa3c576999e2362 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 3 May 2021 12:30:49 +0200 Subject: [PATCH 0932/1519] Minor typo fix --- testing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing.rst b/testing.rst index 51544d0c3e0..442f7b60143 100644 --- a/testing.rst +++ b/testing.rst @@ -876,7 +876,7 @@ Crawler Assertions equal the expected value. ``assertCheckboxChecked(string $fieldName, string $message = '')``/``assertCheckboxNotChecked(string $fieldName, string $message = '')`` Asserts that the checkbox with the given name is (not) checked. -``assertFormValue(string $formSelector, string $fieldName, string $value, string $message = '')`` and ``assertNoFormValue(string $formSelector, string $fieldName, string $message = '')`` +``assertFormValue(string $formSelector, string $fieldName, string $value, string $message = '')``/``assertNoFormValue(string $formSelector, string $fieldName, string $message = '')`` Asserts that value of the field of the first form matching the given selector does (not) equal the expected value. From 1a94e637609b7f48696039babcb679c50195a59f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 3 May 2021 12:31:29 +0200 Subject: [PATCH 0933/1519] Restored a section wrongly removed while upmerging --- testing.rst | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/testing.rst b/testing.rst index b523c263c7b..738245ffaac 100644 --- a/testing.rst +++ b/testing.rst @@ -567,6 +567,65 @@ will no longer be followed:: $client->followRedirects(false); +.. _testing_logging_in_users: + +Logging in Users (Authentication) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.1 + + The ``loginUser()`` method was introduced in Symfony 5.1. + +When you want to add application tests for protected pages, you have to +first "login" as a user. Reproducing the actual steps - such as +submitting a login form - make a test very slow. For this reason, Symfony +provides a ``loginUser()`` method to simulate logging in in your functional +tests. + +Instead of logging in with real users, it's recommended to create a user only for +tests. You can do that with Doctrine :ref:`data fixtures `, +to load the testing users only in the test database. + +After loading users in your database, use your user repository to fetch +this user and use +:method:`$client->loginUser() ` +to simulate a login request:: + + // tests/Controller/ProfileControllerTest.php + namespace App\Tests\Controller; + + use App\Repository\UserRepository; + use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; + + class ProfileControllerTest extends WebTestCase + { + // ... + + public function testVisitingWhileLoggedIn() + { + $client = static::createClient(); + $userRepository = static::$container->get(UserRepository::class); + + // retrieve the test user + $testUser = $userRepository->findOneByEmail('john.doe@example.com'); + + // simulate $testUser being logged in + $client->loginUser($testUser); + + // test e.g. the profile page + $client->request('GET', '/profile'); + + $this->assertResponseIsSuccessful(); + $this->assertSelectorTextContains('h1', 'Hello John!'); + } + } + +You can pass any +:class:`Symfony\\Component\\Security\\Core\\User\\UserInterface` instance to +``loginUser()``. This method creates a special +:class:`Symfony\\Bundle\\FrameworkBundle\\Test\\TestBrowserToken` object and +stores in the session of the test client. + Making AJAX Requests .................... From ad63bc4c46530fd3614438761e0fb5921192e103 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 3 May 2021 12:34:20 +0200 Subject: [PATCH 0934/1519] Readd loginUser() docs --- testing.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/testing.rst b/testing.rst index d22d25256db..1e738fe395d 100644 --- a/testing.rst +++ b/testing.rst @@ -617,7 +617,6 @@ to simulate a login request:: // test e.g. the profile page $client->request('GET', '/profile'); - $this->assertResponseIsSuccessful(); $this->assertSelectorTextContains('h1', 'Hello John!'); } From 0bd963f9876099bb04da2cbec2e22bc260716ca0 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 3 May 2021 12:35:46 +0200 Subject: [PATCH 0935/1519] Fix CI --- testing.rst | 1 - testing/dom_crawler.rst | 4 ---- 2 files changed, 5 deletions(-) diff --git a/testing.rst b/testing.rst index 1e738fe395d..ac92f8afda4 100644 --- a/testing.rst +++ b/testing.rst @@ -1008,6 +1008,5 @@ Learn more .. _`DAMADoctrineTestBundle`: https://github.com/dmaicher/doctrine-test-bundle .. _`DoctrineFixturesBundle documentation`: https://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html .. _`SymfonyMakerBundle`: https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html -.. _`symfony/panther`: https://github.com/symfony/panther .. _`PHPUnit Assertion`: https://phpunit.readthedocs.io/en/stable/assertions.html .. _`section 4.1.18 of RFC 3875`: https://tools.ietf.org/html/rfc3875#section-4.1.18 diff --git a/testing/dom_crawler.rst b/testing/dom_crawler.rst index 9a98ee95aeb..7b47487d09f 100644 --- a/testing/dom_crawler.rst +++ b/testing/dom_crawler.rst @@ -92,7 +92,3 @@ The Crawler can extract information from the nodes:: $data = $crawler->each(function ($node, $i) { return $node->attr('href'); }); - -.. versionadded:: 4.4 - - The option to trim white spaces in ``text()`` was introduced in Symfony 4.4. From d224e0d74e9a9eb96db5498cffd146512f8d50ca Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 3 May 2021 13:07:41 +0200 Subject: [PATCH 0936/1519] Fixed RST issues spotted by DOCtor-RST --- testing.rst | 1 - testing/dom_crawler.rst | 4 ---- 2 files changed, 5 deletions(-) diff --git a/testing.rst b/testing.rst index d22d25256db..68c952556bc 100644 --- a/testing.rst +++ b/testing.rst @@ -1009,6 +1009,5 @@ Learn more .. _`DAMADoctrineTestBundle`: https://github.com/dmaicher/doctrine-test-bundle .. _`DoctrineFixturesBundle documentation`: https://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html .. _`SymfonyMakerBundle`: https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html -.. _`symfony/panther`: https://github.com/symfony/panther .. _`PHPUnit Assertion`: https://phpunit.readthedocs.io/en/stable/assertions.html .. _`section 4.1.18 of RFC 3875`: https://tools.ietf.org/html/rfc3875#section-4.1.18 diff --git a/testing/dom_crawler.rst b/testing/dom_crawler.rst index 9a98ee95aeb..7b47487d09f 100644 --- a/testing/dom_crawler.rst +++ b/testing/dom_crawler.rst @@ -92,7 +92,3 @@ The Crawler can extract information from the nodes:: $data = $crawler->each(function ($node, $i) { return $node->attr('href'); }); - -.. versionadded:: 4.4 - - The option to trim white spaces in ``text()`` was introduced in Symfony 4.4. From 7f580b791d5eec393fdb225b1388cdbd2be54783 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 3 May 2021 12:11:57 +0200 Subject: [PATCH 0937/1519] [FrameworkBundle] Document env vars in framework.ide --- reference/configuration/framework.rst | 50 ++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 0ca87286119..d45f35dc742 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -461,10 +461,52 @@ doubling them to prevent Symfony from interpreting them as container parameters) }; Since every developer uses a different IDE, the recommended way to enable this -feature is to configure it on a system level. This can be done by setting the -``xdebug.file_link_format`` option in your ``php.ini`` configuration file. The -format to use is the same as for the ``framework.ide`` option, but without the -need to escape the percent signs (``%``) by doubling them: +feature is to configure it on a system level. First, you can set its value to +some environment variable that stores the name of the IDE/editor: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/framework.yaml + framework: + # the env var stores the IDE/editor name (e.g. 'phpstorm', 'vscode', etc.) + ide: '%env(resolve:CODE_EDITOR)%' + + .. code-block:: xml + + + + + + + + + + .. code-block:: php + + // config/packages/framework.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + // the env var stores the IDE/editor name (e.g. 'phpstorm', 'vscode', etc.) + $framework->ide('%env(resolve:CODE_EDITOR)%'); + }; + +.. versionadded:: 5.3 + + The option to use env vars in the ``framework.ide`` option was introduced + in Symfony 5.3. + +Another alternative is to set the ``xdebug.file_link_format`` option in your +``php.ini`` configuration file. The format to use is the same as for the +``framework.ide`` option, but without the need to escape the percent signs +(``%``) by doubling them: .. code-block:: ini From ffef3e60567041169c523659151f4b8d317658b2 Mon Sep 17 00:00:00 2001 From: Kiel Goodman Date: Sat, 8 May 2021 14:44:25 +0100 Subject: [PATCH 0938/1519] Options node doesn't do anything The array is passed directly into the Runtime $options so it's already available as $options['project_dir'] --- components/runtime.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/runtime.rst b/components/runtime.rst index cf11c81e60f..e7e14c8f2d2 100644 --- a/components/runtime.rst +++ b/components/runtime.rst @@ -316,9 +316,7 @@ You can also configure ``extra.runtime.options`` in ``composer.json``: }, "extra": { "runtime": { - "options": { - "project_dir": "/var/task" - } + "project_dir": "/var/task" } } } From a6672e96d19447cca282a6edbf3f841a38530073 Mon Sep 17 00:00:00 2001 From: David Ward Date: Thu, 6 May 2021 11:14:07 -0700 Subject: [PATCH 0939/1519] [Uid] Add note about ULIDs not being random in one case --- components/uid.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/uid.rst b/components/uid.rst index 6a73666f511..f0bb06cc07c 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -209,6 +209,13 @@ ULIDs are an alternative to UUIDs when using those is impractical. They provide 128-bit compatibility with UUID, they are lexicographically sortable and they are encoded as 26-character strings (vs 36-character UUIDs). +.. note:: + + If you generate more than one ULID during the same millisecond in the + same process then the random portion is incremented by one bit in order + to provide monotonicity for sorting. The random portion is **not** + random compared to the previous ULID in this case. + Generating ULIDs ~~~~~~~~~~~~~~~~ From c7f60e15fc51df760ad6a419ea75be7534a01832 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 8 May 2021 15:46:58 +0200 Subject: [PATCH 0940/1519] Minor tweak --- components/uid.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index f0bb06cc07c..0e374cb1301 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -213,8 +213,8 @@ are encoded as 26-character strings (vs 36-character UUIDs). If you generate more than one ULID during the same millisecond in the same process then the random portion is incremented by one bit in order - to provide monotonicity for sorting. The random portion is **not** - random compared to the previous ULID in this case. + to provide monotonicity for sorting. The random portion is not random + compared to the previous ULID in this case. Generating ULIDs ~~~~~~~~~~~~~~~~ From 1425b95a6eb4a8f8661dd3d18f1389c25f248b87 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 3 May 2021 17:39:07 +0200 Subject: [PATCH 0941/1519] [Security] Renamed encoders to password_hashers --- _build/redirection_map | 1 + components/security/authentication.rst | 105 ++++++++-------- reference/configuration/security.rst | 116 ++++++++++-------- security.rst | 42 ++++--- .../{named_encoders.rst => named_hashers.rst} | 66 +++++----- security/password_migration.rst | 80 ++++++------ security/user_provider.rst | 22 ++-- 7 files changed, 229 insertions(+), 203 deletions(-) rename security/{named_encoders.rst => named_hashers.rst} (72%) diff --git a/_build/redirection_map b/_build/redirection_map index 68095fcf2b8..1069505a81a 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -514,3 +514,4 @@ /service_container/3.3-di-changes https://symfony.com/doc/3.4/service_container/3.3-di-changes.html /frontend/encore/shared-entry /frontend/encore/split-chunks /testing/functional_tests_assertions /testing#testing-application-assertions +/security/named_encoders /security/named_hashers diff --git a/components/security/authentication.rst b/components/security/authentication.rst index 18b780b6d84..9cca9f18d9f 100644 --- a/components/security/authentication.rst +++ b/components/security/authentication.rst @@ -121,12 +121,12 @@ the given password is valid. This functionality is offered by the :class:`Symfony\\Component\\Security\\Core\\Authentication\\Provider\\DaoAuthenticationProvider`. It fetches the user's data from a :class:`Symfony\\Component\\Security\\Core\\User\\UserProviderInterface`, -uses a :class:`Symfony\\Component\\Security\\Core\\Encoder\\PasswordEncoderInterface` +uses a :class:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface` to create a hash of the password and returns an authenticated token if the password was valid:: + use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface; use Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider; - use Symfony\Component\Security\Core\Encoder\EncoderFactory; use Symfony\Component\Security\Core\User\InMemoryUserProvider; use Symfony\Component\Security\Core\User\UserChecker; @@ -145,14 +145,14 @@ password was valid:: // for some extra checks: is account enabled, locked, expired, etc. $userChecker = new UserChecker(); - // an array of password encoders (see below) - $encoderFactory = new EncoderFactory(...); + // an array of password hashers (see below) + $hasherFactory = new PasswordHasherFactoryInterface(...); $daoProvider = new DaoAuthenticationProvider( $userProvider, $userChecker, 'secured_area', - $encoderFactory + $hasherFactory ); $daoProvider->authenticate($unauthenticatedToken); @@ -165,69 +165,76 @@ password was valid:: It is also possible to let multiple user providers try to find the user's data, using the :class:`Symfony\\Component\\Security\\Core\\User\\ChainUserProvider`. -The Password Encoder Factory -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. _the-password-encoder-factory: + +The Password Hasher Factory +~~~~~~~~~~~~~~~~~~~~~~~~~~~ The :class:`Symfony\\Component\\Security\\Core\\Authentication\\Provider\\DaoAuthenticationProvider` -uses an encoder factory to create a password encoder for a given type of -user. This allows you to use different encoding strategies for different -types of users. The default :class:`Symfony\\Component\\Security\\Core\\Encoder\\EncoderFactory` -receives an array of encoders:: +uses a factory to create a password hasher for a given type of user. This allows +you to use different hashing strategies for different types of users. +The default :class:`Symfony\\Component\\PasswordHasher\\Hasher\\PasswordHasherFactory` +receives an array of hashers:: use Acme\Entity\LegacyUser; - use Symfony\Component\Security\Core\Encoder\EncoderFactory; - use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder; + use Symfony\Component\PasswordHasher\Hasher\MessageDigestPasswordHasher; + use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactory; use Symfony\Component\Security\Core\User\InMemoryUser; - $defaultEncoder = new MessageDigestPasswordEncoder('sha512', true, 5000); - $weakEncoder = new MessageDigestPasswordEncoder('md5', true, 1); + $defaultHasher = new MessageDigestPasswordHasher('sha512', true, 5000); + $weakHasher = new MessageDigestPasswordHasher('md5', true, 1); - $encoders = [ - InMemoryUser::class => $defaultEncoder, - LegacyUser::class => $weakEncoder, + $hashers = [ + InMemoryUser::class => $defaultHasher, + LegacyUser::class => $weakHasher, // ... ]; - $encoderFactory = new EncoderFactory($encoders); + $hasherFactory = new PasswordHasherFactory($hashers); -Each encoder should implement :class:`Symfony\\Component\\Security\\Core\\Encoder\\PasswordEncoderInterface` +Each hasher should implement :class:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface` or be an array with a ``class`` and an ``arguments`` key, which allows the -encoder factory to construct the encoder only when it is needed. +hasher factory to construct the hasher only when it is needed. + +.. _creating-a-custom-password-encoder: -Creating a custom Password Encoder -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Creating a custom Password Hasher +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -There are many built-in password encoders. But if you need to create your +There are many built-in password hasher. But if you need to create your own, it needs to follow these rules: -#. The class must implement :class:`Symfony\\Component\\Security\\Core\\Encoder\\PasswordEncoderInterface` - (you can also extend :class:`Symfony\\Component\\Security\\Core\\Encoder\\BasePasswordEncoder`); +#. The class must implement :class:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface` + (you can also extend :class:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasher`); #. The implementations of - :method:`Symfony\\Component\\Security\\Core\\Encoder\\PasswordEncoderInterface::encodePassword` + :method:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface::hashPassword` and - :method:`Symfony\\Component\\Security\\Core\\Encoder\\PasswordEncoderInterface::isPasswordValid` + :method:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface::isPasswordValid` must first of all make sure the password is not too long, i.e. the password length is no longer than 4096 characters. This is for security reasons (see `CVE-2013-5750`_), and you can use the - :method:`Symfony\\Component\\Security\\Core\\Encoder\\BasePasswordEncoder::isPasswordTooLong` + :method:`Symfony\\Component\\PasswordHasher\\Hasher\\CheckPasswordLengthTrait::isPasswordTooLong` method for this check:: - use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder; + use Symfony\Component\PasswordHasher\Hasher\CheckPasswordLengthTrait; + use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasher; use Symfony\Component\Security\Core\Exception\BadCredentialsException; - class FoobarEncoder extends BasePasswordEncoder + class FoobarHasher extends UserPasswordHasher { - public function encodePassword($raw, $salt) + use CheckPasswordLengthTrait; + + public function hashPassword(UserInterface $user, string $plainPassword): string { - if ($this->isPasswordTooLong($raw)) { + if ($this->isPasswordTooLong($user->getPassword())) { throw new BadCredentialsException('Invalid password.'); } // ... } - public function isPasswordValid($encoded, $raw, $salt) + public function isPasswordValid(UserInterface $user, string $plainPassword) { - if ($this->isPasswordTooLong($raw)) { + if ($this->isPasswordTooLong($user->getPassword())) { return false; } @@ -235,13 +242,15 @@ own, it needs to follow these rules: } } -Using Password Encoders -~~~~~~~~~~~~~~~~~~~~~~~ +.. _using-password-encoders: -When the :method:`Symfony\\Component\\Security\\Core\\Encoder\\EncoderFactory::getEncoder` -method of the password encoder factory is called with the user object as -its first argument, it will return an encoder of type :class:`Symfony\\Component\\Security\\Core\\Encoder\\PasswordEncoderInterface` -which should be used to encode this user's password:: +Using Password Hashers +~~~~~~~~~~~~~~~~~~~~~~ + +When the :method:`Symfony\\Component\\PasswordHasher\\Hasher\\PasswordHasherFactory::getPasswordHasher` +method of the password hasher factory is called with the user object as +its first argument, it will return a hasher of type :class:`Symfony\\Component\\PasswordHasher\\PasswordHasherInterface` +which should be used to hash this user's password:: // a Acme\Entity\LegacyUser instance $user = ...; @@ -249,12 +258,12 @@ which should be used to encode this user's password:: // the password that was submitted, e.g. when registering $plainPassword = ...; - $encoder = $encoderFactory->getEncoder($user); + $hasher = $hasherFactory->getPasswordHasher($user); - // returns $weakEncoder (see above) - $encodedPassword = $encoder->encodePassword($plainPassword, $user->getSalt()); + // returns $weakHasher (see above) + $hashedPassword = $hasher->hashPassword($user, $plainPassword); - $user->setPassword($encodedPassword); + $user->setPassword($hashedPassword); // ... save the user @@ -267,11 +276,7 @@ in) is correct, you can use:: // the submitted password, e.g. from the login form $plainPassword = ...; - $validPassword = $encoder->isPasswordValid( - $user->getPassword(), // the encoded password - $plainPassword, // the submitted password - $user->getSalt() - ); + $validPassword = $hasher->isPasswordValid($user, $plainPassword); Authentication Events --------------------- diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index 630c65879f1..a7b644add9a 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -40,7 +40,7 @@ Some of these options define tens of sub-options and they are explained in separate articles: * `access_control`_ -* `encoders`_ +* `hashers`_ * `firewalls`_ * `providers`_ * `role_hierarchy`_ @@ -120,15 +120,16 @@ and to allow anonymous users to the login form page. This option is explained in detail in :doc:`/security/access_control`. -encoders --------- +.. _encoders: -This option defines the algorithm used to *encode* the password of the users. -Although Symfony calls it *"password encoding"* for historical reasons, this is -in fact, *"password hashing"*. +hashers +------- + +This option defines the algorithm used to *hash* the password of the users +(which in previous Symfony versions was wrongly called *"password encoding"*). If your app defines more than one user class, each of them can define its own -encoding algorithm. Also, each algorithm defines different config options: +hashing algorithm. Also, each algorithm defines different config options: .. configuration-block:: @@ -138,25 +139,25 @@ encoding algorithm. Also, each algorithm defines different config options: security: # ... - encoders: - # auto encoder with default options + password_hashers: + # auto hasher with default options App\Entity\User: 'auto' - # auto encoder with custom options + # auto hasher with custom options App\Entity\User: algorithm: 'auto' cost: 15 - # Sodium encoder with default options + # Sodium hasher with default options App\Entity\User: 'sodium' - # Sodium encoder with custom options + # Sodium hasher with custom options App\Entity\User: algorithm: 'sodium' memory_cost: 16384 # Amount in KiB. (16384 = 16 MiB) time_cost: 2 # Number of iterations - # MessageDigestPasswordEncoder encoder using SHA512 hashing with default options + # MessageDigestPasswordHasher hasher using SHA512 hashing with default options App\Entity\User: 'sha512' .. code-block:: xml @@ -173,37 +174,37 @@ encoding algorithm. Also, each algorithm defines different config options: - - + - - + - - + - + - - - + @@ -217,55 +218,61 @@ encoding algorithm. Also, each algorithm defines different config options: $container->loadFromExtension('security', [ // ... - 'encoders' => [ - // auto encoder with default options + 'password_hashers' => [ + // auto hasher with default options User::class => [ 'algorithm' => 'auto', ], - // auto encoder with custom options + // auto hasher with custom options User::class => [ 'algorithm' => 'auto', 'cost' => 15, ], - // Sodium encoder with default options + // Sodium hasher with default options User::class => [ 'algorithm' => 'sodium', ], - // Sodium encoder with custom options + // Sodium hasher with custom options User::class => [ 'algorithm' => 'sodium', 'memory_cost' => 16384, // Amount in KiB. (16384 = 16 MiB) 'time_cost' => 2, // Number of iterations ], - // MessageDigestPasswordEncoder encoder using SHA512 hashing with default options + // MessageDigestPasswordHasher hasher using SHA512 hashing with default options User::class => [ 'algorithm' => 'sha512', ], ], ]); +.. versionadded:: 5.3 + + The ``password_hashers`` option was introduced in Symfony 5.3. In previous + versions it was called ``encoders``. + .. tip:: - You can also create your own password encoders as services and you can even - select a different password encoder for each user instance. Read - :doc:`this article ` for more details. + You can also create your own password hashers as services and you can even + select a different password hasher for each user instance. Read + :doc:`this article ` for more details. .. tip:: - Encoding passwords is resource intensive and takes time in order to generate + Hashing passwords is resource intensive and takes time in order to generate secure password hashes. In tests however, secure hashes are not important, so - you can change the encoders configuration in ``test`` environment to run tests faster: + you can change the password hasher configuration in ``test`` environment to + run tests faster: .. configuration-block:: .. code-block:: yaml # config/packages/test/security.yaml - encoders: + password_hashers: # Use your user class name here App\Entity\User: algorithm: auto # This should be the same value as in config/packages/security.yaml @@ -289,7 +296,7 @@ encoding algorithm. Also, each algorithm defines different config options: - loadFromExtension('security', [ - 'encoders' => [ + 'password_hashers' => [ // Use your user class name here User::class => [ 'algorithm' => 'auto', // This should be the same value as in config/packages/security.yaml @@ -318,44 +325,46 @@ encoding algorithm. Also, each algorithm defines different config options: .. _reference-security-sodium: .. _using-the-argon2i-password-encoder: +.. _using-the-sodium-password-encoder: -Using the Sodium Password Encoder -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Using the Sodium Password Hasher +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -It uses the `Argon2 key derivation function`_ and it's the encoder recommended +It uses the `Argon2 key derivation function`_ and it's the hasher recommended by Symfony. Argon2 support was introduced in PHP 7.2, but if you use an earlier PHP version, you can install the `libsodium`_ PHP extension. -The encoded passwords are ``96`` characters long, but due to the hashing +The hashed passwords are ``96`` characters long, but due to the hashing requirements saved in the resulting hash this may change in the future, so make sure to allocate enough space for them to be persisted. Also, passwords include the `cryptographic salt`_ inside them (it's generated automatically for each new password) so you don't have to deal with it. .. _reference-security-encoder-auto: +.. _using-the-auto-password-encoder: -Using the "auto" Password Encoder -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Using the "auto" Password Hasher +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -It selects automatically the best possible encoder. Currently, it tries to use +It selects automatically the best possible hasher. Currently, it tries to use Sodium by default and falls back to the `bcrypt password hashing function`_ if not possible. In the future, when PHP adds new hashing techniques, it may use different password hashers. -It produces encoded passwords with ``60`` characters long, so make sure to +It produces hashed passwords with ``60`` characters long, so make sure to allocate enough space for them to be persisted. Also, passwords include the `cryptographic salt`_ inside them (it's generated automatically for each new password) so you don't have to deal with it. Its only configuration option is ``cost``, which is an integer in the range of ``4-31`` (by default, ``13``). Each single increment of the cost **doubles the -time** it takes to encode a password. It's designed this way so the password +time** it takes to hash a password. It's designed this way so the password strength can be adapted to the future improvements in computation power. You can change the cost at any time — even if you already have some passwords -encoded using a different cost. New passwords will be encoded using the new -cost, while the already encoded ones will be validated using a cost that was -used back when they were encoded. +hashed using a different cost. New passwords will be hashed using the new +cost, while the already hashed ones will be validated using a cost that was +used back when they were hashed. .. tip:: @@ -364,13 +373,14 @@ used back when they were encoded. environment configuration. .. _reference-security-pbkdf2: +.. _using-the-pbkdf2-encoder: -Using the PBKDF2 Encoder -~~~~~~~~~~~~~~~~~~~~~~~~ +Using the PBKDF2 Hasher +~~~~~~~~~~~~~~~~~~~~~~~ -Using the `PBKDF2`_ encoder is no longer recommended since PHP added support for +Using the `PBKDF2`_ hasher is no longer recommended since PHP added support for Sodium and BCrypt. Legacy application still using it are encouraged to upgrade -to those newer encoding algorithms. +to those newer hashing algorithms. firewalls --------- diff --git a/security.rst b/security.rst index 57c306fb26d..f5f282f7efa 100644 --- a/security.rst +++ b/security.rst @@ -200,12 +200,13 @@ here: :doc:`User Providers `. .. _security-encoding-user-password: .. _encoding-the-user-s-password: +.. _2c-encoding-passwords: -2c) Encoding Passwords ----------------------- +2c) Hashing Passwords +--------------------- Not all applications have "users" that need passwords. *If* your users have passwords, -you can control how those passwords are encoded in ``security.yaml``. The ``make:user`` +you can control how those passwords are hashed in ``security.yaml``. The ``make:user`` command will pre-configure this for you: .. configuration-block:: @@ -216,10 +217,10 @@ command will pre-configure this for you: security: # ... - encoders: + password_hashers: # use your user class name here App\Entity\User: - # Use native password encoder, which auto-selects the best + # Use native password hasher, which auto-selects the best # possible hashing algorithm (starting from Symfony 5.3 this is "bcrypt") algorithm: auto @@ -238,7 +239,7 @@ command will pre-configure this for you: - @@ -254,7 +255,7 @@ command will pre-configure this for you: $container->loadFromExtension('security', [ // ... - 'encoders' => [ + 'password_hashers' => [ User::class => [ 'algorithm' => 'auto', 'cost' => 12, @@ -264,8 +265,13 @@ command will pre-configure this for you: // ... ]); -Now that Symfony knows *how* you want to encode the passwords, you can use the -``UserPasswordEncoderInterface`` service to do this before saving your users to +.. versionadded:: 5.3 + + The ``password_hashers`` option was introduced in Symfony 5.3. In previous + versions it was called ``encoders``. + +Now that Symfony knows *how* you want to hash the passwords, you can use the +``UserPasswordHasherInterface`` service to do this before saving your users to the database. .. _user-data-fixture: @@ -280,22 +286,22 @@ create dummy database users: The class name of the fixtures to create (e.g. AppFixtures): > UserFixtures -Use this service to encode the passwords: +Use this service to hash the passwords: .. code-block:: diff // src/DataFixtures/UserFixtures.php - + use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; + + use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; // ... class UserFixtures extends Fixture { - + private $passwordEncoder; + + private $passwordHasher; - + public function __construct(UserPasswordEncoderInterface $passwordEncoder) + + public function __construct(UserPasswordHasherInterface $passwordHasher) + { - + $this->passwordEncoder = $passwordEncoder; + + $this->passwordHasher = $passwordHasher; + } public function load(ObjectManager $manager) @@ -303,7 +309,7 @@ Use this service to encode the passwords: $user = new User(); // ... - + $user->setPassword($this->passwordEncoder->encodePassword( + + $user->setPassword($this->passwordHasher->hashPassword( + $user, + 'the_new_password' + )); @@ -312,11 +318,11 @@ Use this service to encode the passwords: } } -You can manually encode a password by running: +You can manually hash a password by running: .. code-block:: terminal - $ php bin/console security:encode-password + $ php bin/console security:hash-password .. _security-yaml-firewalls: .. _security-firewalls: @@ -1503,7 +1509,7 @@ Authentication (Identifying/Logging in the User) security/remember_me security/impersonating_user security/user_checkers - security/named_encoders + security/named_hashers security/multiple_guard_authenticators security/firewall_restriction security/csrf diff --git a/security/named_encoders.rst b/security/named_hashers.rst similarity index 72% rename from security/named_encoders.rst rename to security/named_hashers.rst index 8ff58f0fbef..c377cfa28e9 100644 --- a/security/named_encoders.rst +++ b/security/named_hashers.rst @@ -1,10 +1,10 @@ .. index:: single: Security; Named Encoders -How to Use A Different Password Encoder Algorithm Per User -========================================================== +How to Use A Different Password Hasher Algorithm Per User +========================================================= -Usually, the same password encoder is used for all users by configuring it +Usually, the same password hasher is used for all users by configuring it to apply to all instances of a specific class: .. configuration-block:: @@ -14,7 +14,7 @@ to apply to all instances of a specific class: # config/packages/security.yaml security: # ... - encoders: + password_hashers: App\Entity\User: algorithm: auto cost: 12 @@ -33,7 +33,7 @@ to apply to all instances of a specific class: > - @@ -47,7 +47,7 @@ to apply to all instances of a specific class: $container->loadFromExtension('security', [ // ... - 'encoders' => [ + 'password_hashers' => [ User::class => [ 'algorithm' => 'auto', 'cost' => 12, @@ -55,13 +55,13 @@ to apply to all instances of a specific class: ], ]); -Another option is to use a "named" encoder and then select which encoder +Another option is to use a "named" hasher and then select which hasher you want to use dynamically. In the previous example, you've set the ``auto`` algorithm for ``App\Entity\User``. This may be secure enough for a regular user, but what if you want your admins to have a stronger algorithm, for example ``auto`` with a higher cost. This can -be done with named encoders: +be done with named hashers: .. configuration-block:: @@ -70,7 +70,7 @@ be done with named encoders: # config/packages/security.yaml security: # ... - encoders: + password_hashers: harsh: algorithm: auto cost: 15 @@ -90,7 +90,7 @@ be done with named encoders: - @@ -101,7 +101,7 @@ be done with named encoders: // config/packages/security.php $container->loadFromExtension('security', [ // ... - 'encoders' => [ + 'password_hashers' => [ 'harsh' => [ 'algorithm' => 'auto', 'cost' => '15', @@ -115,33 +115,33 @@ be done with named encoders: then the recommended hashing algorithm to use is :ref:`Sodium `. -This creates an encoder named ``harsh``. In order for a ``User`` instance +This creates a hasher named ``harsh``. In order for a ``User`` instance to use it, the class must implement -:class:`Symfony\\Component\\Security\\Core\\Encoder\\EncoderAwareInterface`. -The interface requires one method - ``getEncoderName()`` - which should return -the name of the encoder to use:: +:class:`Symfony\\Component\\PasswordHasher\\Hasher\\PasswordHasherAwareInterface`. +The interface requires one method - ``getPasswordHasherName()`` - which should return +the name of the hasher to use:: // src/Entity/User.php namespace App\Entity; - use Symfony\Component\Security\Core\Encoder\EncoderAwareInterface; + use Symfony\Component\PasswordHasher\Hasher\PasswordHasherAwareInterface; use Symfony\Component\Security\Core\User\UserInterface; - class User implements UserInterface, EncoderAwareInterface + class User implements UserInterface, PasswordHasherAwareInterface { - public function getEncoderName(): ?string + public function getPasswordHasherName(): ?string { if ($this->isAdmin()) { return 'harsh'; } - return null; // use the default encoder + return null; // use the default hasher } } -If you created your own password encoder implementing the -:class:`Symfony\\Component\\Security\\Core\\Encoder\\PasswordEncoderInterface`, -you must register a service for it in order to use it as a named encoder: +If you created your own password hasher implementing the +:class:`SSymfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface`, +you must register a service for it in order to use it as a named hasher: .. configuration-block:: @@ -150,9 +150,9 @@ you must register a service for it in order to use it as a named encoder: # config/packages/security.yaml security: # ... - encoders: - app_encoder: - id: 'App\Security\Encoder\MyCustomPasswordEncoder' + password_hashers: + app_hasher: + id: 'App\Security\Hasher\MyCustomPasswordHasher' .. code-block:: xml @@ -169,8 +169,8 @@ you must register a service for it in order to use it as a named encoder: - + @@ -178,18 +178,18 @@ you must register a service for it in order to use it as a named encoder: // config/packages/security.php // ... - use App\Security\Encoder\MyCustomPasswordEncoder; + use App\Security\Hasher\MyCustomPasswordHasher; $container->loadFromExtension('security', [ // ... - 'encoders' => [ - 'app_encoder' => [ - 'id' => MyCustomPasswordEncoder::class, + 'password_hashers' => [ + 'app_hasher' => [ + 'id' => MyCustomPasswordHasher::class, ], ], ]); -This creates an encoder named ``app_encoder`` from a service with the ID -``App\Security\Encoder\MyCustomPasswordEncoder``. +This creates a hasher named ``app_hasher`` from a service with the ID +``App\Security\Hasher\MyCustomPasswordHasher``. .. _`libsodium`: https://pecl.php.net/package/libsodium diff --git a/security/password_migration.rst b/security/password_migration.rst index 52e263d478c..f49e01c887a 100644 --- a/security/password_migration.rst +++ b/security/password_migration.rst @@ -9,16 +9,18 @@ hash algorithms. This means that if a better hash algorithm is supported on your system, the user's password should be *rehashed* using the newer algorithm and stored. That's possible with the ``migrate_from`` option: -#. `Configure a new Encoder Using "migrate_from"`_ +#. `Configure a new Hasher Using "migrate_from"`_ #. `Upgrade the Password`_ -#. Optionally, `Trigger Password Migration From a Custom Encoder`_ +#. Optionally, `Trigger Password Migration From a Custom Hasher`_ -Configure a new Encoder Using "migrate_from" ----------------------------------------------- +.. _configure-a-new-encoder-using migrate_from: + +Configure a new Hasher Using "migrate_from" +------------------------------------------- When a better hashing algorithm becomes available, you should keep the existing -encoder(s), rename it, and then define the new one. Set the ``migrate_from`` option -on the new encoder to point to the old, legacy encoder(s): +hasher(s), rename it, and then define the new one. Set the ``migrate_from`` option +on the new hasher to point to the old, legacy hasher(s): .. configuration-block:: @@ -28,19 +30,19 @@ on the new encoder to point to the old, legacy encoder(s): security: # ... - encoders: - # an encoder used in the past for some users + password_hashers: + # a hasher used in the past for some users legacy: algorithm: sha256 encode_as_base64: false iterations: 1 App\Entity\User: - # the new encoder, along with its options + # the new hasher, along with its options algorithm: sodium migrate_from: - - bcrypt # uses the "bcrypt" encoder with the default options - - legacy # uses the "legacy" encoder configured above + - bcrypt # uses the "bcrypt" hasher with the default options + - legacy # uses the "legacy" hasher configured above .. code-block:: xml @@ -57,22 +59,22 @@ on the new encoder to point to the old, legacy encoder(s): - - - + - + bcrypt - + legacy - + @@ -82,7 +84,7 @@ on the new encoder to point to the old, legacy encoder(s): $container->loadFromExtension('security', [ // ... - 'encoders' => [ + 'password_hashers' => [ 'legacy' => [ 'algorithm' => 'sha256', 'encode_as_base64' => false, @@ -90,11 +92,11 @@ on the new encoder to point to the old, legacy encoder(s): ], 'App\Entity\User' => [ - // the new encoder, along with its options + // the new hasher, along with its options 'algorithm' => 'sodium', 'migrate_from' => [ - 'bcrypt', // uses the "bcrypt" encoder with the default options - 'legacy', // uses the "legacy" encoder configured above + 'bcrypt', // uses the "bcrypt" hasher with the default options + 'legacy', // uses the "legacy" hasher configured above ], ], ], @@ -102,14 +104,14 @@ on the new encoder to point to the old, legacy encoder(s): With this setup: -* New users will be encoded with the new algorithm; +* New users will be hashed with the new algorithm; * Whenever a user logs in whose password is still stored using the old algorithm, Symfony will verify the password with the old algorithm and then rehash and update the password using the new algorithm. .. tip:: - The *auto*, *native*, *bcrypt* and *argon* encoders automatically enable + The *auto*, *native*, *bcrypt* and *argon* hashers automatically enable password migration using the following list of ``migrate_from`` algorithms: #. :ref:`PBKDF2 ` (which uses :phpfunction:`hash_pbkdf2`); @@ -117,7 +119,7 @@ With this setup: Both use the ``hash_algorithm`` setting as the algorithm. It is recommended to use ``migrate_from`` instead of ``hash_algorithm``, unless the *auto* - encoder is used. + hasher is used. Upgrade the Password -------------------- @@ -182,10 +184,10 @@ storing the newly created password hash:: { // ... - public function upgradePassword(UserInterface $user, string $newEncodedPassword): void + public function upgradePassword(UserInterface $user, string $newHashedPassword): void { - // set the new encoded password on the User object - $user->setPassword($newEncodedPassword); + // set the new hashed password on the User object + $user->setPassword($newHashedPassword); // execute the queries on the database $this->getEntityManager()->flush(); @@ -211,34 +213,36 @@ the user provider:: { // ... - public function upgradePassword(UserInterface $user, string $newEncodedPassword): void + public function upgradePassword(UserInterface $user, string $newHashedPassword): void { - // set the new encoded password on the User object - $user->setPassword($newEncodedPassword); + // set the new hashed password on the User object + $user->setPassword($newHashedPassword); // ... store the new password } } -Trigger Password Migration From a Custom Encoder ------------------------------------------------- +.. _trigger-password-migration-from-a-custom-encoder: + +Trigger Password Migration From a Custom Hasher +----------------------------------------------- -If you're using a custom password encoder, you can trigger the password +If you're using a custom password hasher, you can trigger the password migration by returning ``true`` in the ``needsRehash()`` method:: - // src/Security/CustomPasswordEncoder.php + // src/Security/CustomPasswordHasher.php namespace App\Security; // ... - use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface; + use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; - class CustomPasswordEncoder implements PasswordEncoderInterface + class CustomPasswordHasher implements UserPasswordHasherInterface { // ... - public function needsRehash(string $encoded): bool + public function needsRehash(string $hashed): bool { - // check whether the current password is hash using an outdated encoder + // check whether the current password is hashed using an outdated hasher $hashIsOutdated = ...; return $hashIsOutdated; diff --git a/security/user_provider.rst b/security/user_provider.rst index e7a3cdec79a..9c3ca7ba3ad 100644 --- a/security/user_provider.rst +++ b/security/user_provider.rst @@ -224,7 +224,7 @@ prototypes and for limited applications that don't store users in databases. This user provider stores all user information in a configuration file, including their passwords. That's why the first step is to configure how these -users will encode their passwords: +users will hash their passwords: .. configuration-block:: @@ -233,7 +233,7 @@ users will encode their passwords: # config/packages/security.yaml security: # ... - encoders: + password_hashers: # this internal class is used by Symfony to represent in-memory users # (the 'InMemoryUser' class was introduced in Symfony 5.3. # In previous versions it was called 'User') @@ -257,7 +257,7 @@ users will encode their passwords: - @@ -274,18 +274,18 @@ users will encode their passwords: $container->loadFromExtension('security', [ // ... - 'encoders' => [ + 'password_hashers' => [ User::class => [ 'algorithm' => 'auto', ], ], ]); -Then, run this command to encode the plain text passwords of your users: +Then, run this command to hash the plain text passwords of your users: .. code-block:: terminal - $ php bin/console security:encode-password + $ php bin/console security:hash-password Now you can configure all the user information in ``config/packages/security.yaml``: @@ -304,7 +304,7 @@ Now you can configure all the user information in ``config/packages/security.yam .. caution:: When using a ``memory`` provider, and not the ``auto`` algorithm, you have - to choose an encoding without salt (i.e. ``bcrypt``). + to choose a hashing algorithm without salt (i.e. ``bcrypt``). .. _security-ldap-user-provider: @@ -427,13 +427,13 @@ command will generate a nice skeleton to get you started:: } /** - * Upgrades the encoded password of a user, typically for using a better hash algorithm. + * Upgrades the hashed password of a user, typically for using a better hash algorithm. */ - public function upgradePassword(UserInterface $user, string $newEncodedPassword): void + public function upgradePassword(UserInterface $user, string $newHashedPassword): void { - // TODO: when encoded passwords are in use, this method should: + // TODO: when hashed passwords are in use, this method should: // 1. persist the new password in the user storage - // 2. update the $user object with $user->setPassword($newEncodedPassword); + // 2. update the $user object with $user->setPassword($newHashedPassword); } } From 7e4edd49164c2aa145ef4829074b57d4eeb2f8e9 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sun, 9 May 2021 14:00:50 +0200 Subject: [PATCH 0942/1519] Fixed some typos related to 5.3 security changes --- security/named_hashers.rst | 2 +- security/user_provider.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/security/named_hashers.rst b/security/named_hashers.rst index c377cfa28e9..200a2174c28 100644 --- a/security/named_hashers.rst +++ b/security/named_hashers.rst @@ -140,7 +140,7 @@ the name of the hasher to use:: } If you created your own password hasher implementing the -:class:`SSymfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface`, +:class:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface`, you must register a service for it in order to use it as a named hasher: .. configuration-block:: diff --git a/security/user_provider.rst b/security/user_provider.rst index 9c3ca7ba3ad..3f5a7a5a7dd 100644 --- a/security/user_provider.rst +++ b/security/user_provider.rst @@ -275,7 +275,7 @@ users will hash their passwords: $container->loadFromExtension('security', [ // ... 'password_hashers' => [ - User::class => [ + InMemoryUser::class => [ 'algorithm' => 'auto', ], ], From 454087da68f63fda7577969a55554f73a1f88f56 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Sun, 9 May 2021 22:42:02 -0400 Subject: [PATCH 0943/1519] Documenting form field priority option --- reference/forms/types/form.rst | 3 +++ reference/forms/types/options/priority.rst.inc | 10 ++++++++++ 2 files changed, 13 insertions(+) create mode 100644 reference/forms/types/options/priority.rst.inc diff --git a/reference/forms/types/form.rst b/reference/forms/types/form.rst index 43a5a398bdf..f77d0f11cd0 100644 --- a/reference/forms/types/form.rst +++ b/reference/forms/types/form.rst @@ -48,6 +48,7 @@ on all types for which ``FormType`` is the parent. | | - `translation_domain`_ | | | - `label_translation_parameters`_ | | | - `attr_translation_parameters`_ | +| | - `priority`_ | +---------------------------+--------------------------------------------------------------------+ | Default invalid message | This value is not valid. | +---------------------------+--------------------------------------------------------------------+ @@ -189,3 +190,5 @@ of the form type tree (i.e. it cannot be used as a form type on its own). .. include:: /reference/forms/types/options/label_translation_parameters.rst.inc .. include:: /reference/forms/types/options/attr_translation_parameters.rst.inc + +.. include:: /reference/forms/types/options/priority.rst.inc diff --git a/reference/forms/types/options/priority.rst.inc b/reference/forms/types/options/priority.rst.inc new file mode 100644 index 00000000000..e836f1f752f --- /dev/null +++ b/reference/forms/types/options/priority.rst.inc @@ -0,0 +1,10 @@ +priority +~~~~~~~~ + +**type**: ``integer`` **default**: ``0`` + + Allows you to set the field rendering priority. This option will affect + the view order only, sorting all fields in order of importance instead of + simply numerical order, i.e. fields with higher priority will be rendered + first, fields with lower priority will be rendered last and fields with + equal priority will keep the original order. From 04316b25f22b64db069551f7a0e0b1fb5596cff5 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Mon, 10 May 2021 00:16:58 -0400 Subject: [PATCH 0944/1519] Documenting prototype options --- components/options_resolver.rst | 49 +++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/components/options_resolver.rst b/components/options_resolver.rst index 747132b516e..7e803995ff4 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -717,6 +717,55 @@ In same way, parent options can access to the nested options as normal arrays:: The fact that an option is defined as nested means that you must pass an array of values to resolve it at runtime. +Prototype Options +~~~~~~~~~~~~~~~~~ + +There are situations where you will have to resolve and validate a set of +options that may repeat many times within another option. Let's imagine a +``connections`` option that will accept an array of database connections +with ``host``, ``database``, ``user`` and ``password`` each. + +To achieve it, you can establish the nested definition of this ``connections`` +option as prototype:: + + $resolver->setDefault('connections', function (OptionsResolver $connResolver) { + $connResolver + ->setPrototype(true) + ->setRequired(['host', 'database']) + ->setDefaults(['user' => 'root', 'password' => null]); + }); + +According to the prototype definition in the example above, it is possible +to have multiple connection arrays like following:: + + $resolver->resolve([ + 'connections' => [ + 'default' => [ + 'host' => '127.0.0.1', + 'database' => 'symfony', + ], + 'test' => [ + 'host' => '127.0.0.1', + 'database' => 'symfony_test', + 'user' => 'test', + 'password' => 'test', + ], + // ... + ], + ]); + +The array keys (``default``, ``test``, etc.) of this prototype option are +validation-free and can be any valid key you want to differentiate the connections. + +.. note:: + + A prototype option can only be defined inside a nested option and + during its resolution it will expect an array of array. + +.. versionadded:: 5.3 + + The ``setPrototype()`` method was introduced in Symfony 5.3. + Deprecating the Option ~~~~~~~~~~~~~~~~~~~~~~ From ac05a6ef72f703c20ce959bb1c5f1377bc8ba51f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 10 May 2021 09:28:02 +0200 Subject: [PATCH 0945/1519] Minor tweaks --- components/options_resolver.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/options_resolver.rst b/components/options_resolver.rst index 7e803995ff4..5b32a612a51 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -720,13 +720,16 @@ In same way, parent options can access to the nested options as normal arrays:: Prototype Options ~~~~~~~~~~~~~~~~~ +.. versionadded:: 5.3 + + Prototype options were introduced in Symfony 5.3. + There are situations where you will have to resolve and validate a set of options that may repeat many times within another option. Let's imagine a ``connections`` option that will accept an array of database connections with ``host``, ``database``, ``user`` and ``password`` each. -To achieve it, you can establish the nested definition of this ``connections`` -option as prototype:: +The best way to implement this is to define the ``connections`` option as prototype:: $resolver->setDefault('connections', function (OptionsResolver $connResolver) { $connResolver @@ -736,7 +739,7 @@ option as prototype:: }); According to the prototype definition in the example above, it is possible -to have multiple connection arrays like following:: +to have multiple connection arrays like the following:: $resolver->resolve([ 'connections' => [ @@ -755,16 +758,13 @@ to have multiple connection arrays like following:: ]); The array keys (``default``, ``test``, etc.) of this prototype option are -validation-free and can be any valid key you want to differentiate the connections. +validation-free and can be any arbitrary value that helps differentiate the +connections. .. note:: A prototype option can only be defined inside a nested option and - during its resolution it will expect an array of array. - -.. versionadded:: 5.3 - - The ``setPrototype()`` method was introduced in Symfony 5.3. + during its resolution it will expect an array of arrays. Deprecating the Option ~~~~~~~~~~~~~~~~~~~~~~ From 8f8b1e8430ed7fa8069714a55afc49392fe55692 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 11 May 2021 12:48:28 +0200 Subject: [PATCH 0946/1519] Minor tweaks --- reference/forms/types/options/priority.rst.inc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/reference/forms/types/options/priority.rst.inc b/reference/forms/types/options/priority.rst.inc index e836f1f752f..8f53a05c9ab 100644 --- a/reference/forms/types/options/priority.rst.inc +++ b/reference/forms/types/options/priority.rst.inc @@ -3,8 +3,14 @@ priority **type**: ``integer`` **default**: ``0`` - Allows you to set the field rendering priority. This option will affect - the view order only, sorting all fields in order of importance instead of - simply numerical order, i.e. fields with higher priority will be rendered - first, fields with lower priority will be rendered last and fields with - equal priority will keep the original order. +.. versionadded:: 5.3 + + The ``priority`` option was introduced in Symfony 5.3. + +Fields are rendered in the same order as they are included in the form. This +option changes the field rendering priority, allowing you to display fields +earlier or later than their original order. + +This option will affect the view order only. The higher this priority, the +earlier the field will be rendered. Priority can also be negative and fields +with the same priority will keep their original order. From 9358d8f7f72fa9b04166c6d4e3d9c7a7a63bd934 Mon Sep 17 00:00:00 2001 From: Maxim Tugaev Date: Tue, 11 May 2021 17:57:47 +0300 Subject: [PATCH 0947/1519] Update experimental_authenticators.rst https://github.com/symfony/symfony/blob/5.x/UPGRADE-5.2.md#security --- security/experimental_authenticators.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index 027b1087d1d..cdcb40b8541 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -120,7 +120,7 @@ unauthenticated access (e.g. the login page): .. code-block:: php // config/packages/security.php - use Symfony\Component\Security\Http\Firewall\AccessListener; + use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter; $container->loadFromExtension('security', [ 'enable_authenticator_manager' => true, @@ -128,7 +128,7 @@ unauthenticated access (e.g. the login page): // ... 'access_control' => [ // allow unauthenticated users to access the login form - ['path' => '^/admin/login', 'roles' => AccessListener::PUBLIC_ACCESS], + ['path' => '^/admin/login', 'roles' => AuthenticatedVoter::PUBLIC_ACCESS], // but require authentication for all other admin routes ['path' => '^/admin', 'roles' => 'ROLE_ADMIN'], From 82c2108bf3bce8863a1578dd18aed7a636ec3a4c Mon Sep 17 00:00:00 2001 From: Stefan Grootscholten Date: Fri, 14 May 2021 19:52:07 +0200 Subject: [PATCH 0948/1519] Adds a description to the exchange arguments The description contains the alternate-exchange as example. --- messenger.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index e66e5219896..aa40f23a3f8 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1023,7 +1023,8 @@ The transport has a number of options: ``queues[name][binding_arguments]`` Arguments to be used while binding the queue. ``queues[name][binding_keys]`` The binding keys (if any) to bind to this queue ``queues[name][flags]`` Queue flags ``AMQP_DURABLE`` -``exchange[arguments]`` +``exchange[arguments]`` Extra arguments for the exchange i.e. + alternate-exchange ``exchange[default_publish_routing_key]`` Routing key to use when publishing, if none is specified on the message ``exchange[flags]`` Exchange flags ``AMQP_DURABLE`` From 87dbab9c039c826db035d8443e95cbae3463a15e Mon Sep 17 00:00:00 2001 From: Artyum Date: Sat, 15 May 2021 13:52:28 +0400 Subject: [PATCH 0949/1519] [Rate Limiter] Added missing opening single quotes Added the missing opening single quotes in the PHP config example --- rate_limiter.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index c95b96161a4..87cd5fe59d1 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -410,7 +410,7 @@ Use the ``cache_pool`` option to override the cache used by a specific limiter // config/packages/rate_limiter.php $container->loadFromExtension('framework', [ - rate_limiter' => [ + 'rate_limiter' => [ 'anonymous_api' => [ // ... @@ -484,7 +484,7 @@ you can use a specific :ref:`named lock ` via the // config/packages/rate_limiter.php $container->loadFromExtension('framework', [ - rate_limiter' => [ + 'rate_limiter' => [ 'anonymous_api' => [ // ... From 57aa49a4a0d7899a2b3aacbd8684852b865af437 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 16 May 2021 14:29:29 +0200 Subject: [PATCH 0950/1519] Fix syntax error --- rate_limiter.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index c95b96161a4..87f61c140ac 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -178,7 +178,7 @@ enforce different levels of service (free or paid): // config/packages/rate_limiter.php $container->loadFromExtension('framework', [ - rate_limiter' => [ + 'rate_limiter' => [ 'anonymous_api' => [ // use 'sliding_window' if you prefer that policy 'policy' => 'fixed_window', @@ -484,7 +484,7 @@ you can use a specific :ref:`named lock ` via the // config/packages/rate_limiter.php $container->loadFromExtension('framework', [ - rate_limiter' => [ + 'rate_limiter' => [ 'anonymous_api' => [ // ... From 943a63f7a1761379fdf67f4839b7eb3437a6539d Mon Sep 17 00:00:00 2001 From: Mathieu Santostefano Date: Wed, 5 May 2021 17:39:59 +0200 Subject: [PATCH 0951/1519] [Translation] Introduce Translation Providers --- reference/configuration/framework.rst | 14 +++ translation.rst | 152 ++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index d45f35dc742..1bc52ee73b4 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -283,6 +283,7 @@ Configuration * `formatter`_ * `logging`_ * :ref:`paths ` + * :ref:`providers ` * `trusted_headers`_ * `trusted_hosts`_ @@ -2455,6 +2456,19 @@ default_path This option allows to define the path where the application translations files are stored. +.. _reference-translator-providers: + +providers +......... + +**type**: ``array`` **default**: ``[]`` + +This option allows you to enable translation providers to push and pull your translations to third party providers. + +.. seealso:: + + For more information about how to configure providers, see :ref:`translation-providers`. + property_access ~~~~~~~~~~~~~~~ diff --git a/translation.rst b/translation.rst index 382beed92a0..406e56603a1 100644 --- a/translation.rst +++ b/translation.rst @@ -591,6 +591,158 @@ if you're generating translations with specialized programs or teams. :class:`Symfony\\Component\\Translation\\Loader\\LoaderInterface` interface. See the :ref:`dic-tags-translation-loader` tag for more information. +.. _translation-providers: + +Translation Providers +--------------------- + +.. versionadded:: 5.3 + + The "Translation Providers" feature was introduced in Symfony 5.3 as an + :doc:`experimental feature `. + +The translation component can push and pull translations to third party providers (e.g. Crowdin or PoEditor). + +Installing and configuring a 3rd Party Provider +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Instead of editing your translation files as code, you can push them to one of the supported third-party providers. +This will make the translations edition easier for you or your translators. + +==================== =========================================================== +Service Install with +==================== =========================================================== +Crowdin ``composer require symfony/crowdin-translation-provider`` +Loco (localise.biz) ``composer require symfony/loco-translation-provider`` +Lokalise ``composer require symfony/lokalise-translation-provider`` +PoEditor ``composer require symfony/po-editor-translation-provider`` +==================== =========================================================== + +Each library includes a :ref:`Symfony Flex recipe ` that will add +a configuration example to your ``.env`` file. For example, suppose you want to +use Loco. First, install it: + +.. code-block:: terminal + + $ composer require symfony/loco-translation-provider + +You'll now have a new line in your ``.env`` file that you can uncomment: + +.. code-block:: env + + # .env + LOCO_DSN=loco://API_KEY@default + +The ``LOCO_DSN`` isn't a *real* address: it's a convenient format that +offloads most of the configuration work to translation. The ``loco`` scheme +activates the Loco provider that you just installed, which knows all about +how to push and pull translations via Loco. The *only* part you need to change is the +``API_KEY`` placeholder. + +This table shows the full list of available DSN formats for each third party provider: + +===================== ================================================================= + Provider DSN +===================== ================================================================= + Crowdin crowdin://PROJECT_ID:API_TOKEN@ORGANIZATION_DOMAIN.default + Loco (localise.biz) loco://API_KEY@default + Lokalise lokalise://PROJECT_ID:API_KEY@default + PoEditor poeditor://PROJECT_ID:API_KEY@default +===================== ================================================================= + +To enable a translation provider, add the correct DSN in your ``.env`` file and +configure the ``providers``: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/translation.yaml + framework: + translator: + providers: + loco: + dsn: '%env(LOCO_DSN)%' + domains: ['messages'] + locales: ['en', 'fr'] + + .. code-block:: xml + + + + + + + + + messages + + en + fr + + + + + + + .. code-block:: php + + # config/packages/translation.php + $container->loadFromExtension('framework', [ + 'translator' => [ + 'providers' => [ + 'loco' => [ + 'dsn' => '%env(LOCO_DSN)%', + 'domains' => ['messages'], + 'locales' => ['en', 'fr'], + ], + ], + ], + ]); + +Push and pull translations +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To push your existing translations to your configured third party provider, you have to use the `translation:push` command: + +.. code-block:: terminal + + # push all local translations to the Loco provider for the locales and domains configured in config/packages/translation.yaml file + # it will update existing translations already on the provider. + $ php bin/console translation:push loco --force + + # push new local translations to the Loco provider for the French locale and the validators domain. + # it will **not** update existing translations already on the provider. + $ php bin/console translation:push loco --locales fr --domain validators + + # push new local translations and delete provider's translations that not exists anymore in local files for the French locale and the validators domain. + # it will **not** update existing translations already on the provider. + $ php bin/console translation:push loco --delete-missing --locales fr --domain validators + + # check out the command help to see its options (format, domains, locales, etc.) + $ php bin/console translation:push --help + +To pull translations from a provider in your local files, you have to use the `translation:pull` command: + +.. code-block:: terminal + + # pull all provider's translations to local files for the locales and domains configured in config/packages/translation.yaml file + # it will overwrite completely your local files. + $ php bin/console translation:pull loco --force + + # pull new translations from the Loco provider to local files for the French locale and the validators domain. + # it will **not** overwrite your local files, only add new translations. + $ php bin/console translation:pull loco --locales fr --domain validators + + # check out the command help to see its options (format, domains, locales, intl-icu, etc.) + $ php bin/console translation:pull --help + Handling the User's Locale -------------------------- From 04ec7c82ed187d9c297670cf34c1b286c7bf8aa1 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 19 May 2021 17:07:39 +0200 Subject: [PATCH 0952/1519] Tweaks --- reference/configuration/framework.rst | 7 ++- translation.rst | 87 +++++++++++++++------------ 2 files changed, 53 insertions(+), 41 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 1bc52ee73b4..cfd85b374a7 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -2463,11 +2463,12 @@ providers **type**: ``array`` **default**: ``[]`` -This option allows you to enable translation providers to push and pull your translations to third party providers. +.. versionadded:: 5.3 -.. seealso:: + The ``providers`` option was introduced in Symfony 5.3. - For more information about how to configure providers, see :ref:`translation-providers`. +This option enables and configures :ref:`translation providers ` +to push and pull your translations to/from third party translation services. property_access ~~~~~~~~~~~~~~~ diff --git a/translation.rst b/translation.rst index 406e56603a1..7ac8f6d05a7 100644 --- a/translation.rst +++ b/translation.rst @@ -598,25 +598,32 @@ Translation Providers .. versionadded:: 5.3 - The "Translation Providers" feature was introduced in Symfony 5.3 as an + Translation providers were introduced in Symfony 5.3 as an :doc:`experimental feature `. -The translation component can push and pull translations to third party providers (e.g. Crowdin or PoEditor). +When using external translators to translate your application, you must send +them the new contents to translate frequently and merge the results back in the +application. -Installing and configuring a 3rd Party Provider -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Instead of doing this manually, Symfony provides integration with several +third-party translation services (e.g. Crowdin or PoEditor). You can upload and +download (called "push" and "pull") translations to/from these services and +merge the results automatically in the application. -Instead of editing your translation files as code, you can push them to one of the supported third-party providers. -This will make the translations edition easier for you or your translators. +Installing and Configuring a Third Party Provider +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -==================== =========================================================== -Service Install with -==================== =========================================================== -Crowdin ``composer require symfony/crowdin-translation-provider`` -Loco (localise.biz) ``composer require symfony/loco-translation-provider`` -Lokalise ``composer require symfony/lokalise-translation-provider`` -PoEditor ``composer require symfony/po-editor-translation-provider`` -==================== =========================================================== +Before pushing/pulling translations to a third-party provider, you must install +the package that provides integration with that provider: + +==================== =========================================================== +Provider Install with +==================== =========================================================== +Crowdin ``composer require symfony/crowdin-translation-provider`` +Loco (localise.biz) ``composer require symfony/loco-translation-provider`` +Lokalise ``composer require symfony/lokalise-translation-provider`` +PoEditor ``composer require symfony/po-editor-translation-provider`` +==================== =========================================================== Each library includes a :ref:`Symfony Flex recipe ` that will add a configuration example to your ``.env`` file. For example, suppose you want to @@ -633,25 +640,25 @@ You'll now have a new line in your ``.env`` file that you can uncomment: # .env LOCO_DSN=loco://API_KEY@default -The ``LOCO_DSN`` isn't a *real* address: it's a convenient format that -offloads most of the configuration work to translation. The ``loco`` scheme -activates the Loco provider that you just installed, which knows all about -how to push and pull translations via Loco. The *only* part you need to change is the +The ``LOCO_DSN`` isn't a *real* address: it's a convenient format that offloads +most of the configuration work to Symfony. The ``loco`` scheme activates the +Loco provider that you just installed, which knows all about how to push and +pull translations via Loco. The *only* part you need to change is the ``API_KEY`` placeholder. -This table shows the full list of available DSN formats for each third party provider: +This table shows the full list of available DSN formats for each provider: -===================== ================================================================= - Provider DSN -===================== ================================================================= - Crowdin crowdin://PROJECT_ID:API_TOKEN@ORGANIZATION_DOMAIN.default - Loco (localise.biz) loco://API_KEY@default - Lokalise lokalise://PROJECT_ID:API_KEY@default - PoEditor poeditor://PROJECT_ID:API_KEY@default -===================== ================================================================= +===================== ========================================================== +Provider DSN +===================== ========================================================== +Crowdin crowdin://PROJECT_ID:API_TOKEN@ORGANIZATION_DOMAIN.default +Loco (localise.biz) loco://API_KEY@default +Lokalise lokalise://PROJECT_ID:API_KEY@default +PoEditor poeditor://PROJECT_ID:API_KEY@default +===================== ========================================================== To enable a translation provider, add the correct DSN in your ``.env`` file and -configure the ``providers``: +configure the ``providers`` option: .. configuration-block:: @@ -706,37 +713,41 @@ configure the ``providers``: ], ]); -Push and pull translations -~~~~~~~~~~~~~~~~~~~~~~~~~~ +Pushing and Pulling Translations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To push your existing translations to your configured third party provider, you have to use the `translation:push` command: +After configuring the credentials to access the translation provider, you can +now use the following commands to push (upload) and pull (download) translations: .. code-block:: terminal - # push all local translations to the Loco provider for the locales and domains configured in config/packages/translation.yaml file + # push all local translations to the Loco provider for the locales and domains + # configured in config/packages/translation.yaml file. # it will update existing translations already on the provider. $ php bin/console translation:push loco --force - # push new local translations to the Loco provider for the French locale and the validators domain. + # push new local translations to the Loco provider for the French locale + # and the validators domain. # it will **not** update existing translations already on the provider. $ php bin/console translation:push loco --locales fr --domain validators - # push new local translations and delete provider's translations that not exists anymore in local files for the French locale and the validators domain. + # push new local translations and delete provider's translations that not + # exists anymore in local files for the French locale and the validators domain. # it will **not** update existing translations already on the provider. $ php bin/console translation:push loco --delete-missing --locales fr --domain validators # check out the command help to see its options (format, domains, locales, etc.) $ php bin/console translation:push --help -To pull translations from a provider in your local files, you have to use the `translation:pull` command: - .. code-block:: terminal - # pull all provider's translations to local files for the locales and domains configured in config/packages/translation.yaml file + # pull all provider's translations to local files for the locales and domains + # configured in config/packages/translation.yaml file. # it will overwrite completely your local files. $ php bin/console translation:pull loco --force - # pull new translations from the Loco provider to local files for the French locale and the validators domain. + # pull new translations from the Loco provider to local files for the French + # locale and the validators domain. # it will **not** overwrite your local files, only add new translations. $ php bin/console translation:pull loco --locales fr --domain validators From 730a4ca82d0cbeba819c8099e2ba206874e36ead Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 16 May 2021 13:01:33 +0200 Subject: [PATCH 0953/1519] Rewrite config form the Security bundle --- configuration/env_var_processors.rst | 18 +- reference/configuration/security.rst | 131 +++++++------ security.rst | 194 ++++++++++---------- security/access_control.rst | 172 ++++++++--------- security/access_denied_handler.rst | 32 ++-- security/auth_providers.rst | 61 +++--- security/custom_authentication_provider.rst | 43 +++-- security/experimental_authenticators.rst | 97 +++++----- security/firewall_restriction.rst | 72 ++++---- security/force_https.rst | 44 ++--- security/form_login.rst | 159 ++++++++-------- security/form_login_setup.rst | 55 +++--- security/guard_authentication.rst | 57 +++--- security/impersonating_user.rst | 59 +++--- security/json_login_setup.rst | 46 +++-- security/ldap.rst | 98 +++++----- security/login_link.rst | 130 +++++++------ security/multiple_guard_authenticators.rst | 83 +++++---- security/named_hashers.rst | 45 +++-- security/password_migration.rst | 37 ++-- security/remember_me.rst | 53 +++--- security/user_checkers.rst | 17 +- security/user_provider.rst | 60 +++--- security/voters.rst | 25 +-- 24 files changed, 871 insertions(+), 917 deletions(-) diff --git a/configuration/env_var_processors.rst b/configuration/env_var_processors.rst index d1be0338448..a12b63a7a3e 100644 --- a/configuration/env_var_processors.rst +++ b/configuration/env_var_processors.rst @@ -234,15 +234,15 @@ Symfony provides the following env var processors: .. code-block:: php // config/packages/security.php - $container->setParameter('env(HEALTH_CHECK_METHOD)', 'Symfony\Component\HttpFoundation\Request::METHOD_HEAD'); - $container->loadFromExtension('security', [ - 'access_control' => [ - [ - 'path' => '^/health-check$', - 'methods' => '%env(const:HEALTH_CHECK_METHOD)%', - ], - ], - ]); + use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Config\SecurityConfig; + + return static function (ContainerBuilder $container, SecurityConfig $security) { + $container->setParameter('env(HEALTH_CHECK_METHOD)', 'Symfony\Component\HttpFoundation\Request::METHOD_HEAD'); + $security->accessControl() + ->path('^/health-check$') + ->methods(['%env(const:HEALTH_CHECK_METHOD)%']); + }; ``env(base64:FOO)`` Decodes the content of ``FOO``, which is a base64 encoded string. diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index 095b4cbdb13..fa9acdaa6a8 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -215,39 +215,34 @@ hashing algorithm. Also, each algorithm defines different config options: // config/packages/security.php use App\Entity\User; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ + return static function (SecurityConfig $security) { // ... - 'password_hashers' => [ - // auto hasher with default options - User::class => [ - 'algorithm' => 'auto', - ], - - // auto hasher with custom options - User::class => [ - 'algorithm' => 'auto', - 'cost' => 15, - ], - - // Sodium hasher with default options - User::class => [ - 'algorithm' => 'sodium', - ], - - // Sodium hasher with custom options - User::class => [ - 'algorithm' => 'sodium', - 'memory_cost' => 16384, // Amount in KiB. (16384 = 16 MiB) - 'time_cost' => 2, // Number of iterations - ], - - // MessageDigestPasswordHasher hasher using SHA512 hashing with default options - User::class => [ - 'algorithm' => 'sha512', - ], - ], - ]); + + // auto hasher with default options + $security->passwordHasher(User::class) + ->algorithm('auto'); + + // auto hasher with custom options + $security->passwordHasher(User::class) + ->algorithm('auto') + ->cost(15); + + // Sodium hasher with default options + $security->passwordHasher(User::class) + ->algorithm('sodium'); + + // Sodium hasher with custom options + $security->passwordHasher(User::class) + ->algorithm('sodium') + ->memoryCost(16384) // Amount in KiB. (16384 = 16 MiB) + ->timeCost(2); // Number of iterations + + // MessageDigestPasswordHasher hasher using SHA512 hashing with default options + $security->passwordHasher(User::class) + ->algorithm('sha512'); + }; .. versionadded:: 5.3 @@ -310,18 +305,19 @@ hashing algorithm. Also, each algorithm defines different config options: // config/packages/test/security.php use App\Entity\User; + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... - $container->loadFromExtension('security', [ - 'password_hashers' => [ - // Use your user class name here - User::class => [ - 'algorithm' => 'auto', // This should be the same value as in config/packages/security.yaml - 'cost' => 4, // Lowest possible value for bcrypt - 'time_cost' => 3, // Lowest possible value for argon - 'memory_cost' => 10, // Lowest possible value for argon - ] - ], - ]); + // Use your user class name here + $security->passwordHasher(User::class) + ->algorithm('auto') // This should be the same value as in config/packages/security.yaml + ->cost(4) // Lowest possible value for bcrypt + ->timeCost(2) // Lowest possible value for argon + ->memoryCost(10) // Lowest possible value for argon + ; + }; .. _reference-security-sodium: .. _using-the-argon2i-password-encoder: @@ -432,20 +428,20 @@ application: .. code-block:: php // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... - // ... - $container->loadFromExtension('security', [ - 'firewalls' => [ - // 'main' is the name of the firewall (can be chosen freely) - 'main' => [ - // 'pattern' is a regular expression matched against the incoming - // request URL. If there's a match, authentication is triggered - 'pattern' => '^/admin', - // the rest of options depend on the authentication mechanism - // ... - ], - ], - ]); + // 'main' is the name of the firewall (can be chosen freely) + $security->firewall('main') + // 'pattern' is a regular expression matched against the incoming + // request URL. If there's a match, authentication is triggered + ->pattern('^/admin') + // the rest of options depend on the authentication mechanism + // ... + ; + }; .. seealso:: @@ -807,18 +803,19 @@ multiple firewalls, the "context" could actually be shared: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'somename' => [ - // ... - 'context' => 'my_context', - ], - 'othername' => [ - // ... - 'context' => 'my_context', - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('somename') + // ... + ->context('my_context') + ; + + $security->firewall('othername') + // ... + ->context('my_context') + ; + }; .. note:: diff --git a/security.rst b/security.rst index f5f282f7efa..466dfa7aacd 100644 --- a/security.rst +++ b/security.rst @@ -75,10 +75,12 @@ install the security feature before using it: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'enable_authenticator_manager' => true, + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->enableAuthenticatorManager(true); // ... - ]); + }; .. _initial-security-yml-setup-authentication: .. _initial-security-yaml-setup-authentication: @@ -178,20 +180,18 @@ Fortunately, the ``make:user`` command already configured one for you in your // config/packages/security.php use App\Entity\User; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ + return static function (SecurityConfig $security) { // ... - 'providers' => [ - // used to reload user from session & other features (e.g. switch_user) - 'app_user_provider' => [ - 'entity' => [ - 'class' => User::class, - 'property' => 'email', - ], - ], - ], - ]); + // used to reload user from session & other features (e.g. switch_user) + $security->provider('app_user_provider') + ->entity() + ->class(User::class) + ->property('email'); + }; + If your ``User`` class is an entity, you don't need to do anything else. But if your class is *not* an entity, then ``make:user`` will also have generated a @@ -251,19 +251,17 @@ command will pre-configure this for you: // config/packages/security.php use App\Entity\User; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ + return static function (SecurityConfig $security) { // ... - 'password_hashers' => [ - User::class => [ - 'algorithm' => 'auto', - 'cost' => 12, - ] - ], + $security->passwordHasher(User::class) + ->algorithm('auto') + ->cost(12); // ... - ]); + }; .. versionadded:: 5.3 @@ -379,18 +377,17 @@ important section is ``firewalls``: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'dev' => [ - 'pattern' => '^/(_(profiler|wdt)|css|images|js)/', - 'security' => false, - ], - 'main' => [ - 'anonymous' => true, - 'lazy' => true, - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('dev') + ->pattern('^/(_(profiler|wdt)|css|images|js)/') + ->security(false); + + $security->firewall('main') + ->lazy(true) + ->anonymous(); + }; A "firewall" is your authentication system: the configuration below it defines *how* your users will be able to authenticate (e.g. login form, API token, etc). @@ -548,29 +545,29 @@ You must enable this using the ``login_throttling`` setting: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'enable_authenticator_manager' => true, + use Symfony\Config\SecurityConfig; - 'firewalls' => [ - // ... + return static function (SecurityConfig $security) { + $security->enableAuthenticatorManager(true); - 'main' => [ - // by default, the feature allows 5 login attempts per minute - 'login_throttling' => null, + // ... + $mainFirewall = $security->firewall('main'); - // configure the maximum login attempts (per minute) - 'login_throttling' => [ - 'max_attempts' => 3, - ], + // by default, the feature allows 5 login attempts per minute + $mainFirewall + ->loginThrottling(); - // configure the maximum login attempts in a custom period of time - 'login_throttling' => [ - 'max_attempts' => 3, - 'interval' => '15 minutes', - ], - ], - ], - ]); + // configure the maximum login attempts (per minute) + $mainFirewall + ->loginThrottling() + ->maxAttempts(3) + ->interval('15 minutes'); + + // configure the maximum login attempts in a custom period of time + $mainFirewall + ->loginThrottling() + ->maxAttempts(3); + }; .. versionadded:: 5.3 @@ -863,27 +860,32 @@ start with ``/admin``, you can: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->enableAuthenticatorManager(true); + + // ... + $security->firewall('main') // ... + ; - 'firewalls' => [ - // ... - 'main' => [ - // ... - ], - ], - 'access_control' => [ - // require ROLE_ADMIN for /admin* - ['path' => '^/admin', 'roles' => 'ROLE_ADMIN'], - - // require ROLE_ADMIN or IS_AUTHENTICATED_FULLY for /admin* - ['path' => '^/admin', 'roles' => ['ROLE_ADMIN', 'IS_AUTHENTICATED_FULLY']], - - // the 'path' value can be any valid regular expression - // (this one will match URLs like /api/post/7298 and /api/comment/528491) - ['path' => '^/api/(post|comment)/\d+$', 'roles' => 'ROLE_USER'], - ], - ]); + // require ROLE_ADMIN for /admin* + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_ADMIN']); + + // require ROLE_ADMIN or IS_AUTHENTICATED_FULLY for /admin* + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_ADMIN', 'IS_AUTHENTICATED_FULLY']); + + // the 'path' value can be any valid regular expression + // (this one will match URLs like /api/post/7298 and /api/comment/528491) + $security->accessControl() + ->path('^/api/(post|comment)/\d+$') + ->roles(['ROLE_USER']); + }; You can define as many URL patterns as you need - each is a regular expression. **BUT**, only **one** will be matched per request: Symfony starts at the top of @@ -927,14 +929,19 @@ the list and stops when it finds the first match: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'access_control' => [ - ['path' => '^/admin/users', 'roles' => 'ROLE_SUPER_ADMIN'], - ['path' => '^/admin', 'roles' => 'ROLE_ADMIN'], - ], - ]); + $security->accessControl() + ->path('^/admin/users') + ->roles(['ROLE_SUPER_ADMIN']); + + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_ADMIN']); + }; Prepending the path with ``^`` means that only URLs *beginning* with the pattern are matched. For example, a path of ``/admin`` (without the ``^``) @@ -1202,16 +1209,16 @@ To enable logging out, activate the ``logout`` config parameter under your fire .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'secured_area' => [ - // ... - 'logout' => ['path' => 'app_logout'], - ], - ], - ]); + $security->firewall('secured_area') + // ... + ->logout() + ->path('app_logout'); + }; Next, you'll need to create a route for this URL (but not a controller): @@ -1419,17 +1426,14 @@ rules by creating a role hierarchy: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'role_hierarchy' => [ - 'ROLE_ADMIN' => 'ROLE_USER', - 'ROLE_SUPER_ADMIN' => [ - 'ROLE_ADMIN', - 'ROLE_ALLOWED_TO_SWITCH', - ], - ], - ]); + $security->roleHierarchy('ROLE_ADMIN', ['ROLE_USER']); + $security->roleHierarchy('ROLE_SUPER_ADMIN', ['ROLE_ADMIN', 'ROLE_ALLOWED_TO_SWITCH']); + }; Users with the ``ROLE_ADMIN`` role will also have the ``ROLE_USER`` role. And users with ``ROLE_SUPER_ADMIN``, will automatically have diff --git a/security/access_control.rst b/security/access_control.rst index 2f65dc60281..ec86b8a6836 100644 --- a/security/access_control.rst +++ b/security/access_control.rst @@ -88,49 +88,46 @@ Take the following ``access_control`` entries as an example: .. code-block:: php // config/packages/security.php - $container->setParameter('env(TRUSTED_IPS)', '10.0.0.1, 10.0.0.2'); - $container->loadFromExtension('security', [ + use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Config\SecurityConfig; + + return static function (ContainerBuilder $container, SecurityConfig $security) { + $container->setParameter('env(TRUSTED_IPS)', '10.0.0.1, 10.0.0.2'); // ... - 'access_control' => [ - [ - 'path' => '^/admin', - 'roles' => 'ROLE_USER_PORT', - 'ip' => '127.0.0.1', - 'port' => '8080', - ], - [ - 'path' => '^/admin', - 'roles' => 'ROLE_USER_IP', - 'ips' => '127.0.0.1', - ], - [ - 'path' => '^/admin', - 'roles' => 'ROLE_USER_HOST', - 'host' => 'symfony\.com$', - ], - [ - 'path' => '^/admin', - 'roles' => 'ROLE_USER_METHOD', - 'methods' => 'POST, PUT', - ], - - // ips can be comma-separated, which is especially useful when using env variables - [ - 'path' => '^/admin', - 'roles' => 'ROLE_USER_IP', - 'ips' => '%env(TRUSTED_IPS)%', - ], - [ - 'path' => '^/admin', - 'roles' => 'ROLE_USER_IP', - 'ips' => [ - '127.0.0.1', - '::1', - '%env(TRUSTED_IPS)%', - ], - ], - ], - ]); + + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_USER_PORT']) + ->ips(['127.0.0.1']) + ->port(8080) + ; + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_USER_IP']) + ->ips(['127.0.0.1']) + ; + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_USER_HOST']) + ->host('symfony\.com$') + ; + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_USER_METHOD']) + ->methods(['POST', 'PUT']) + ; + // ips can be comma-separated, which is especially useful when using env variables + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_USER_IP']) + ->ips(['%env(TRUSTED_IPS)%']) + ; + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_USER_IP']) + ->ips(['127.0.0.1', '::1', '%env(TRUSTED_IPS)%']) + ; + }; .. versionadded:: 5.2 @@ -275,21 +272,23 @@ pattern so that it is only accessible by requests from the local server itself: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'access_control' => [ - [ - 'path' => '^/internal', - 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY', - // the 'ips' option supports IP addresses and subnet masks - 'ips' => ['127.0.0.1', '::1'], - ], - [ - 'path' => '^/internal', - 'roles' => 'ROLE_NO_ACCESS', - ], - ], - ]); + + $security->accessControl() + ->path('^/internal') + ->roles(['IS_AUTHENTICATED_ANONYMOUSLY']) + // the 'ips' option supports IP addresses and subnet masks + ->ips(['127.0.0.1', '::1']) + ; + + $security->accessControl() + ->path('^/internal') + ->roles(['ROLE_NO_ACCESS']) + ; + }; Here is how it works when the path is ``/internal/something`` coming from the external IP address ``10.0.0.1``: @@ -361,18 +360,19 @@ key: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'access_control' => [ - [ - 'path' => '^/_internal/secure', - // the 'role' and 'allow-if' options work like an OR expression, so - // access is granted if the expression is TRUE or the user has ROLE_ADMIN - 'roles' => 'ROLE_ADMIN', - 'allow_if' => '"127.0.0.1" == request.getClientIp() or request.headers.has("X-Secure-Access")', - ], - ], - ]); + + $security->accessControl() + ->path('^/_internal/secure') + // the 'role' and 'allow-if' options work like an OR expression, so + // access is granted if the expression is TRUE or the user has ROLE_ADMIN + ->roles(['ROLE_ADMIN']) + ->allowIf('"127.0.0.1" == request.getClientIp() or request.headers.has("X-Secure-Access")') + ; + }; In this case, when the user tries to access any URL starting with ``/_internal/secure``, they will only be granted access if the IP address is @@ -438,16 +438,17 @@ access those URLs via a specific port. This could be useful for example for .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'access_control' => [ - [ - 'path' => '^/cart/checkout', - 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', - 'port' => '8080', - ], - ], - ]); + + $security->accessControl() + ->path('^/cart/checkout') + ->roles(['IS_AUTHENTICATED_ANONYMOUSLY']) + ->port(8080) + ; + }; Forcing a Channel (http, https) ------------------------------- @@ -491,13 +492,14 @@ the user will be redirected to ``https``: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'access_control' => [ - [ - 'path' => '^/cart/checkout', - 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY', - 'requires_channel' => 'https', - ], - ], - ]); + + $security->accessControl() + ->path('^/cart/checkout') + ->roles(['IS_AUTHENTICATED_ANONYMOUSLY']) + ->requiresChannel('https') + ; + }; diff --git a/security/access_denied_handler.rst b/security/access_denied_handler.rst index cdfb3e6db21..0d4676b3cf7 100644 --- a/security/access_denied_handler.rst +++ b/security/access_denied_handler.rst @@ -90,15 +90,14 @@ Now, configure this service ID as the entry point for the firewall: // config/packages/security.php use App\Security\AuthenticationEntryPoint; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - // ... - 'entry_point' => AuthenticationEntryPoint::class, - ], - ], - ]); + return static function (SecurityConfig $security) { + $security->firewall('main') + // .... + ->entryPoint(AuthenticationEntryPoint::class) + ; + }; Customize the Forbidden Response -------------------------------- @@ -167,15 +166,14 @@ configure it under your firewall: // config/packages/security.php use App\Security\AccessDeniedHandler; - - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - // ... - 'access_denied_handler' => AccessDeniedHandler::class, - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + // .... + ->accessDeniedHandler(AccessDeniedHandler::class) + ; + }; Customizing All Access Denied Responses --------------------------------------- diff --git a/security/auth_providers.rst b/security/auth_providers.rst index 8745585ea83..2f9764a77fa 100644 --- a/security/auth_providers.rst +++ b/security/auth_providers.rst @@ -71,17 +71,16 @@ To support HTTP Basic authentication, add the ``http_basic`` key to your firewal .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - // ... - - 'firewalls' => [ - 'main' => [ - 'http_basic' => [ - 'realm' => 'Secured Area', - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // .... + + $security->firewall('main') + ->httpBasic() + ->realm('Secured Area') + ; + }; That's it! Symfony will now be listening for any HTTP basic authentication data. To load user information, it will use your configured :doc:`user provider `. @@ -140,18 +139,17 @@ Enable the x509 authentication for a particular firewall in the security configu .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - // ... - - 'firewalls' => [ - 'main' => [ - // ... - 'x509' => [ - 'provider' => 'your_user_provider', - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // .... + + $security->firewall('main') + // ... + ->x509() + ->provider('your_user_provider') + ; + }; By default, the firewall provides the ``SSL_CLIENT_S_DN_Email`` variable to the user provider, and sets the ``SSL_CLIENT_S_DN`` as credentials in the @@ -218,15 +216,14 @@ corresponding firewall in your security configuration: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'remote_user' => [ - 'provider' => 'your_user_provider', - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->remoteUser() + ->provider('your_user_provider') + ; + }; The firewall will then provide the ``REMOTE_USER`` environment variable to your user provider. You can change the variable name used by setting the ``user`` diff --git a/security/custom_authentication_provider.rst b/security/custom_authentication_provider.rst index 04c94a4a82c..743fdb9382e 100644 --- a/security/custom_authentication_provider.rst +++ b/security/custom_authentication_provider.rst @@ -511,17 +511,17 @@ You are finished! You can now define parts of your app as under WSSE protection. .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - // ... + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // .... - 'firewalls' => [ - 'wsse_secured' => [ - 'pattern' => '^/api/', - 'stateless' => true, - 'wsse' => true, - ], - ], - ]); + $security->firewall('wsse_secured') + ->pattern('^/api/') + ->stateless(true) + ->wsse() + ; + }; Congratulations! You have written your very own custom security authentication provider! @@ -634,19 +634,18 @@ set to any desirable value per firewall. .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - // ... + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // .... - 'firewalls' => [ - 'wsse_secured' => [ - 'pattern' => '^/api/', - 'stateless' => true, - 'wsse' => [ - 'lifetime' => 30, - ], - ], - ], - ]); + $security->firewall('wsse_secured') + ->pattern('^/api/') + ->stateless(true) + ->wsse() + ->lifetime(30) + ; + }; The rest is up to you! Any relevant configuration items can be defined in the factory and consumed or passed to the other classes in the container. diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst index 92f92ca61c8..10788ecd88e 100644 --- a/security/experimental_authenticators.rst +++ b/security/experimental_authenticators.rst @@ -48,10 +48,12 @@ The authenticator-based system can be enabled using the .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'enable_authenticator_manager' => true, - // ... - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->enableAuthenticatorManager(true); + // .... + }; The new system is backwards compatible with the current authentication system, with some exceptions that will be explained in this article: @@ -121,19 +123,24 @@ unauthenticated access (e.g. the login page): // config/packages/security.php use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ - 'enable_authenticator_manager' => true, + return static function (SecurityConfig $security) { + $security->enableAuthenticatorManager(true); + // .... - // ... - 'access_control' => [ - // allow unauthenticated users to access the login form - ['path' => '^/admin/login', 'roles' => AuthenticatedVoter::PUBLIC_ACCESS], + // allow unauthenticated users to access the login form + $security->accessControl() + ->path('^/admin/login') + ->roles([AuthenticatedVoter::PUBLIC_ACCESS]) + ; - // but require authentication for all other admin routes - ['path' => '^/admin', 'roles' => 'ROLE_ADMIN'], - ], - ]); + // but require authentication for all other admin routes + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_ADMIN']) + ; + }; Granting Anonymous Users Access in a Custom Voter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -233,23 +240,22 @@ You can configure this using the ``entry_point`` setting: .. code-block:: php // config/packages/security.php - use Symfony\Component\Security\Http\Firewall\AccessListener; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ - 'enable_authenticator_manager' => true, + return static function (SecurityConfig $security) { + $security->enableAuthenticatorManager(true); + // .... - // ... - 'firewalls' => [ - 'main' => [ - // allow authentication using a form or HTTP basic - 'form_login' => null, - 'http_basic' => null, - - // configure the form authentication as the entry point for unauthenticated users - 'entry_point' => 'form_login' - ], - ], - ]); + + // allow authentication using a form or HTTP basic + $mainFirewall = $security->firewall('main'); + $mainFirewall->formLogin(); + $mainFirewall->httpBasic(); + + // configure the form authentication as the entry point for unauthenticated users + $mainFirewall + ->entryPoint('form_login'); + }; .. note:: @@ -359,7 +365,7 @@ The authenticator can be enabled using the ``custom_authenticators`` setting: custom_authenticators: - App\Security\ApiKeyAuthenticator - # don't forget to also configure the entry_point if the + # remember to also configure the entry_point if the # authenticator implements AuthenticationEntryPointInterface # entry_point: App\Security\CustomFormLoginAuthenticator @@ -378,7 +384,7 @@ The authenticator can be enabled using the ``custom_authenticators`` setting: - @@ -393,24 +399,21 @@ The authenticator can be enabled using the ``custom_authenticators`` setting: // config/packages/security.php use App\Security\ApiKeyAuthenticator; - use Symfony\Component\Security\Http\Firewall\AccessListener; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ - 'enable_authenticator_manager' => true, + return static function (SecurityConfig $security) { + $security->enableAuthenticatorManager(true); + // .... + + $security->firewall('main') + ->customAuthenticators([ApiKeyAuthenticator::class]) + + // remember to also configure the entry_point if the + // authenticator implements AuthenticatorEntryPointInterface + // ->entryPoint(App\Security\CustomFormLoginAuthenticator::class) + ; + }; - // ... - 'firewalls' => [ - 'main' => [ - 'custom_authenticators' => [ - ApiKeyAuthenticator::class, - ], - - // don't forget to also configure the entry_point if the - // authenticator implements AuthenticatorEntryPointInterface - // 'entry_point' => [App\Security\CustomFormLoginAuthenticator::class], - ], - ], - ]); The ``authenticate()`` method is the most important method of the authenticator. Its job is to extract credentials (e.g. username & diff --git a/security/firewall_restriction.rst b/security/firewall_restriction.rst index c5546a8cba8..3638858efde 100644 --- a/security/firewall_restriction.rst +++ b/security/firewall_restriction.rst @@ -64,16 +64,16 @@ if the request path matches the configured ``pattern``. .. code-block:: php // config/packages/security.php + use Symfony\Config\SecurityConfig; - // ... - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'secured_area' => [ - 'pattern' => '^/admin', - // ... - ], - ], - ]); + return static function (SecurityConfig $security) { + // .... + + $security->firewall('secured_area') + ->pattern('^/admin') + // ... + ; + }; The ``pattern`` is a regular expression. In this example, the firewall will only be activated if the path starts (due to the ``^`` regex character) with ``/admin``. If @@ -123,16 +123,16 @@ only initialize if the host from the request matches against the configuration. .. code-block:: php // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // .... - // ... - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'secured_area' => [ - 'host' => '^admin\.example\.com$', - // ... - ], - ], - ]); + $security->firewall('secured_area') + ->host('^admin\.example\.com$') + // ... + ; + }; The ``host`` (like the ``pattern``) is a regular expression. In this example, the firewall will only be activated if the host is equal exactly (due to @@ -183,16 +183,16 @@ the provided HTTP methods. .. code-block:: php // config/packages/security.php + use Symfony\Config\SecurityConfig; - // ... - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'secured_area' => [ - 'methods' => ['GET', 'POST'], - // ... - ], - ], - ]); + return static function (SecurityConfig $security) { + // .... + + $security->firewall('secured_area') + ->methods(['GET', 'POST']) + // ... + ; + }; In this example, the firewall will only be activated if the HTTP method of the request is either ``GET`` or ``POST``. If the method is not in the array of the @@ -241,13 +241,13 @@ If the above options don't fit your needs you can configure any service implemen .. code-block:: php // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // .... - // ... - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'secured_area' => [ - 'request_matcher' => 'app.firewall.secured_area.request_matcher', - // ... - ], - ], - ]); + $security->firewall('secured_area') + ->requestMatcher('app.firewall.secured_area.request_matcher') + // ... + ; + }; diff --git a/security/force_https.rst b/security/force_https.rst index 1b4a0b36be1..2c2a8fe42c2 100644 --- a/security/force_https.rst +++ b/security/force_https.rst @@ -60,27 +60,29 @@ access control: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - // ... - - 'access_control' => [ - [ - 'path' => '^/secure', - 'roles' => 'ROLE_ADMIN', - 'requires_channel' => 'https', - ], - [ - 'path' => '^/login', - 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', - 'requires_channel' => 'https', - ], - [ - 'path' => '^/', - 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', - 'requires_channel' => 'https', - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // .... + + $security->accessControl() + ->path('^/secure') + ->roles(['ROLE_ADMIN']) + ->requiresChannel('https') + ; + + $security->accessControl() + ->path('^/login') + ->roles(['IS_AUTHENTICATED_ANONYMOUSLY']) + ->requiresChannel('https') + ; + + $security->accessControl() + ->path('^/') + ->roles(['IS_AUTHENTICATED_ANONYMOUSLY']) + ->requiresChannel('https') + ; + }; To make life easier while developing, you can also use an environment variable, like ``requires_channel: '%env(SECURE_SCHEME)%'``. In your ``.env`` file, set diff --git a/security/form_login.rst b/security/form_login.rst index 1ab379e7a83..c8f2cc7c1ff 100644 --- a/security/form_login.rst +++ b/security/form_login.rst @@ -56,18 +56,17 @@ First, enable ``form_login`` under your firewall: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'anonymous' => true, - 'lazy' => true, - 'form_login' => [ - 'login_path' => 'login', - 'check_path' => 'login', - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $mainFirewall = $security->firewall('main'); + $mainFirewall->lazy(true); + $mainFirewall->anonymous(); + $mainFirewall->formLogin() + ->loginPath('login') + ->checkPath('login') + ; + }; .. tip:: @@ -300,19 +299,17 @@ security component: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'secured_area' => [ + $security->firewall('secured_area') + ->formLogin() // ... - 'form_login' => [ - // ... - 'csrf_token_generator' => 'security.csrf.token_manager', - ], - ], - ], - ]); + ->csrfTokenGenerator('security.csrf.token_manager') + ; + }; .. _csrf-login-template: @@ -386,20 +383,18 @@ After this, you have protected your login form against CSRF attacks. .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'secured_area' => [ + $security->firewall('secured_area') + ->formLogin() // ... - 'form_login' => [ - // ... - 'csrf_parameter' => '_csrf_security_token', - 'csrf_token_id' => 'a_private_string', - ], - ], - ], - ]); + ->csrfParameter('_csrf_security_token') + ->csrfTokenId('a_private_string') + ; + }; Redirecting after Success ------------------------- @@ -459,20 +454,18 @@ a relative/absolute URL or a Symfony route name: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'main' => [ + $security->firewall('main') + // ... + ->formLogin() // ... - - 'form_login' => [ - // ... - 'default_target_path' => 'after_login_route_name', - ], - ], - ], - ]); + ->defaultTargetPath('after_login_route_name') + ; + }; Always Redirect to the default Page ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -519,20 +512,18 @@ previously requested URL and always redirect to the default page: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'main' => [ + $security->firewall('main') + // ... + ->formLogin() // ... - - 'form_login' => [ - // ... - 'always_use_default_target_path' => true, - ], - ], - ], - ]); + ->alwaysUseDefaultTargetPath(true) + ; + }; .. _control-the-redirect-url-from-inside-the-form: @@ -609,19 +600,18 @@ parameter is included in the request, you may use the value of the .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'main' => [ + $security->firewall('main') + // ... + ->formLogin() // ... - 'form_login' => [ - // ... - 'use_referer' => true, - ], - ], - ], - ]); + ->useReferer(true) + ; + }; .. note:: @@ -677,19 +667,18 @@ option to define a new target via a relative/absolute URL or a Symfony route nam .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'main' => [ + $security->firewall('main') + // ... + ->formLogin() // ... - 'form_login' => [ - // ... - 'failure_path' => 'login_failure_route_name', - ], - ], - ], - ]); + ->failurePath('login_failure_route_name') + ; + }; This option can also be set via the ``_failure_path`` request parameter: @@ -755,19 +744,19 @@ redirects can be customized using the ``target_path_parameter`` and .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'main' => [ + $security->firewall('main') + // ... + ->formLogin() // ... - 'form_login' => [ - 'target_path_parameter' => 'go_to', - 'failure_path_parameter' => 'back_to', - ], - ], - ], - ]); + ->targetPathParameter('go_to') + ->failurePathParameter('back_to') + ; + }; Using the above configuration, the query string parameters and hidden form fields are now fully customized: diff --git a/security/form_login_setup.rst b/security/form_login_setup.rst index b4bba11862c..7fe912cdac7 100644 --- a/security/form_login_setup.rst +++ b/security/form_login_setup.rst @@ -128,19 +128,19 @@ Edit the ``security.yaml`` file in order to declare the ``/logout`` path: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'main' => [ - // ... - 'logout' => [ - 'path' => 'app_logout', - // where to redirect after logout - 'target' => 'app_any_route' - ], - ], - ], - ]); + + $security->firewall('main') + // ... + ->logout() + ->path('app_logout') + // where to redirect after logout + ->target('app_any_route') + ; + }; **Step 2.** The template has very little to do with security: it generates a traditional HTML form that submits to ``/login``: @@ -347,23 +347,24 @@ a traditional HTML form that submits to ``/login``: // config/packages/security.php use App\Security\LoginFormAuthenticator; + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... - $container->loadFromExtension('security', [ + $mainFirewall = $security->firewall('main'); // ... - 'firewalls' => [ - 'main' => [ - // ..., - 'guard' => [ - 'authenticators' => [ - LoginFormAuthenticator::class, - ] - ], - 'logout' => [ - 'path' => 'app_logout', - ], - ], - ], - ]); + + $mainFirewall + ->guard() + ->authenticators([LoginFormAuthenticator::class]) + ; + + $mainFirewall + ->logout() + ->path('app_logout') + ; + }; Finishing the Login Form ------------------------ diff --git a/security/guard_authentication.rst b/security/guard_authentication.rst index 7108ba0906e..a945cfb89e6 100644 --- a/security/guard_authentication.rst +++ b/security/guard_authentication.rst @@ -98,20 +98,18 @@ Next, configure your "user provider" to use this new ``apiToken`` property: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'providers' => [ - 'your_db_provider' => [ - 'entity' => [ - 'class' => 'App\Entity\User', - 'property' => 'apiToken', - ], - ], - ], + $security->provider('your_db_provider') + ->entity('App\Entity\User') + ->property('apiToken') + ; // ... - ]); + }; Step 2) Create the Authenticator Class -------------------------------------- @@ -292,28 +290,25 @@ Finally, configure your ``firewalls`` key in ``security.yaml`` to use this authe .. code-block:: php // config/packages/security.php - - // ... use App\Security\TokenAuthenticator; - - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'pattern' => '^/', - 'anonymous' => true, - 'lazy' => true, - 'logout' => true, - 'guard' => [ - 'authenticators' => [ - TokenAuthenticator::class, - ], - ], - // if you want, disable storing the user in the session - // 'stateless' => true, - // ... - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $mainFirewall = $security->firewall('main'); + $mainFirewall + ->pattern('^/') + ->lazy(true) + ->anonymous(); + + $mainFirewall->logout(); + $mainFirewall + ->guard() + ->authenticators([TokenAuthenticator::class]) + ; + // if you want, disable storing the user in the session + // $mainFirewall->stateless(true); + // ... + }; You did it! You now have a fully-working API token authentication system. If your homepage required ``ROLE_USER``, then you could test it under different conditions: diff --git a/security/impersonating_user.rst b/security/impersonating_user.rst index 3c5e421c723..f31474f238c 100644 --- a/security/impersonating_user.rst +++ b/security/impersonating_user.rst @@ -55,16 +55,15 @@ listener: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - // ... + use Symfony\Config\SecurityConfig; - 'firewalls' => [ - 'main'=> [ - // ... - 'switch_user' => true, - ], - ], - ]); + return static function (SecurityConfig $security) { + // ... + $security->firewall('main') + // ... + ->switchUser() + ; + }; To switch to another user, add a query string with the ``_switch_user`` parameter and the username (or whatever field our user provider uses to load users) @@ -191,19 +190,17 @@ also adjust the query parameter name via the ``parameter`` setting: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - // ... + use Symfony\Config\SecurityConfig; - 'firewalls' => [ - 'main'=> [ - // ... - 'switch_user' => [ - 'role' => 'ROLE_ADMIN', - 'parameter' => '_want_to_be_this_user', - ], - ], - ], - ]); + return static function (SecurityConfig $security) { + // ... + $security->firewall('main') + // ... + ->switchUser() + ->role('ROLE_ADMIN') + ->parameter('_want_to_be_this_user') + ; + }; Limiting User Switching ----------------------- @@ -250,18 +247,16 @@ be called): .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - // ... + use Symfony\Config\SecurityConfig; - 'firewalls' => [ - 'main'=> [ - // ... - 'switch_user' => [ - 'role' => 'CAN_SWITCH_USER', - ], - ], - ], - ]); + return static function (SecurityConfig $security) { + // ... + $security->firewall('main') + // ... + ->switchUser() + ->role('CAN_SWITCH_USER') + ; + }; Then, create a voter class that responds to this role and includes whatever custom logic you want:: diff --git a/security/json_login_setup.rst b/security/json_login_setup.rst index 41107f9f46a..2806f6c9a97 100644 --- a/security/json_login_setup.rst +++ b/security/json_login_setup.rst @@ -44,17 +44,16 @@ First, enable the JSON login under your firewall: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'anonymous' => true, - 'lazy' => true, - 'json_login' => [ - 'check_path' => '/login', - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $mainFirewall = $security->firewall('main'); + $mainFirewall->anonymous(); + $mainFirewall->lazy(true); + $mainFirewall->jsonLogin() + ->checkPath('/login') + ; + }; .. tip:: @@ -200,16 +199,15 @@ The security configuration should be: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'anonymous' => true, - 'lazy' => true, - 'json_login' => [ - 'check_path' => 'login', - 'username_path' => 'security.credentials.login', - 'password_path' => 'security.credentials.password', - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $mainFirewall = $security->firewall('main'); + $mainFirewall->anonymous(); + $mainFirewall->lazy(true); + $mainFirewall->jsonLogin() + ->checkPath('/login') + ->usernamePath('security.credentials.login') + ->passwordPath('security.credentials.password') + ; + }; diff --git a/security/ldap.rst b/security/ldap.rst index 8e6595a9df9..cabda06a72f 100644 --- a/security/ldap.rst +++ b/security/ldap.rst @@ -179,22 +179,21 @@ use the ``ldap`` user provider. // config/packages/security.php use Symfony\Component\Ldap\Ldap; + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->provider('ldap_users') + ->ldap() + ->service(Ldap::class) + ->baseDn('dc=example,dc=com') + ->searchDn('cn=read-only-admin,dc=example,dc=com') + ->searchPassword('password') + ->defaultRoles(['ROLE_USER']) + ->uidKey('uid') + ->extraFields(['email']) + ; + }; - $container->loadFromExtension('security', [ - 'providers' => [ - 'ldap_users' => [ - 'ldap' => [ - 'service' => Ldap::class, - 'base_dn' => 'dc=example,dc=com', - 'search_dn' => 'cn=read-only-admin,dc=example,dc=com', - 'search_password' => 'password', - 'default_roles' => 'ROLE_USER', - 'uid_key' => 'uid', - 'extra_fields' => ['email'], - ], - ], - ], - ]); .. caution:: @@ -397,18 +396,15 @@ Configuration example for form login // config/packages/security.php use Symfony\Component\Ldap\Ldap; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'form_login_ldap' => [ - 'service' => Ldap::class, - 'dn_string' => 'uid={username},dc=example,dc=com', - // ... - ], - ], - ] - ]); + return static function (SecurityConfig $security) { + $security->firewall('main') + ->formLoginLdap() + ->service(Ldap::class) + ->dnString('uid={username},dc=example,dc=com') + ; + }; Configuration example for HTTP Basic .................................... @@ -454,20 +450,16 @@ Configuration example for HTTP Basic // config/packages/security.php use Symfony\Component\Ldap\Ldap; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ - // ... - - 'firewalls' => [ - 'main' => [ - 'http_basic_ldap' => [ - 'service' => Ldap::class, - 'dn_string' => 'uid={username},dc=example,dc=com', - ], - 'stateless' => true, - ], - ], - ]); + return static function (SecurityConfig $security) { + $security->firewall('main') + ->stateless(true) + ->formLoginLdap() + ->service(Ldap::class) + ->dnString('uid={username},dc=example,dc=com') + ; + }; Configuration example for form login and query_string ..................................................... @@ -518,21 +510,19 @@ Configuration example for form login and query_string // config/packages/security.php use Symfony\Component\Ldap\Ldap; - - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - // ... - 'form_login_ldap' => [ - 'service' => Ldap::class, - 'dn_string' => 'dc=example,dc=com', - 'query_string' => '(&(uid={username})(memberOf=cn=users,ou=Services,dc=example,dc=com))', - 'search_dn' => '...', - 'search_password' => 'the-raw-password', - ], - ], - ] - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->stateless(true) + ->formLoginLdap() + ->service(Ldap::class) + ->dnString('dc=example,dc=com') + ->queryString('(&(uid={username})(memberOf=cn=users,ou=Services,dc=example,dc=com))') + ->searchDn('...') + ->searchPassword('the-raw-password') + ; + }; .. _`LDAP PHP extension`: https://www.php.net/manual/en/intro.ldap.php .. _`RFC4515`: http://www.faqs.org/rfcs/rfc4515.html diff --git a/security/login_link.rst b/security/login_link.rst index ed8bb195e15..1e1641304a3 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -67,15 +67,14 @@ under the firewall. You must configure a ``check_route`` and .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'login_link' => [ - 'check_route' => 'login_check', - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->loginLink() + ->checkRoute('login_check') + ; + }; The ``signature_properties`` are used to create a signed URL. This must contain at least one property of your ``User`` object that uniquely @@ -373,17 +372,16 @@ seconds). You can customize this using the ``lifetime`` option: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'login_link' => [ - 'check_route' => 'login_check', - // lifetime in seconds - 'lifetime' => 300, - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->loginLink() + ->checkRoute('login_check') + // lifetime in seconds + ->lifetime(300) + ; + }; .. _security-login-link-signature: @@ -448,16 +446,15 @@ You can add more properties to the ``hash`` by using the .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'login_link' => [ - 'check_route' => 'login_check', - 'signature_properties' => ['id', 'email'], - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->loginLink() + ->checkRoute('login_check') + ->signatureProperties(['id', 'email']) + ; + }; The properties are fetched from the user object using the :doc:`PropertyAccess component ` (e.g. using @@ -521,20 +518,20 @@ cache. Enable this support by setting the ``max_uses`` option: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'login_link' => [ - 'check_route' => 'login_check', - // only allow the link to be used 3 times - 'max_uses' => 3, - - // optionally, configure the cache pool - //'used_link_cache' => 'cache.redis', - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->loginLink() + ->checkRoute('login_check') + + // only allow the link to be used 3 times + ->maxUses(3) + + // optionally, configure the cache pool + //->usedLinkCache('cache.redis') + ; + }; Make sure there is enough space left in the cache, otherwise invalid links can no longer be stored (and thus become valid again). Expired invalid @@ -594,17 +591,16 @@ the authenticator only handle HTTP POST methods: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'login_link' => [ - 'check_route' => 'login_check', - 'check_post_only' => true, - 'max_uses' => 1, - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->loginLink() + ->checkRoute('login_check') + ->checkPostOnly(true) + ->maxUses(1) + ; + }; Then, use the ``check_route`` controller to render a page that lets the user create this POST request (e.g. by clicking a button):: @@ -726,19 +722,17 @@ Then, configure this service ID as the ``success_handler``: // config/packages/security.php use App\Security\Authentication\AuthenticationSuccessHandler; - - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'login_link' => [ - 'check_route' => 'login_check', - 'lifetime' => 600, - 'max_uses' => 1, - 'success_handler' => AuthenticationSuccessHandler::class, - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->loginLink() + ->checkRoute('login_check') + ->lifetime(600) + ->maxUses(1) + ->successHandler(AuthenticationSuccessHandler::class) + ; + }; .. tip:: diff --git a/security/multiple_guard_authenticators.rst b/security/multiple_guard_authenticators.rst index c52b4cbd1e2..8c4647c49c6 100644 --- a/security/multiple_guard_authenticators.rst +++ b/security/multiple_guard_authenticators.rst @@ -63,23 +63,21 @@ This is how your security configuration can look in action: // config/packages/security.php use App\Security\FacebookConnectAuthenticator; use App\Security\LoginFormAuthenticator; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'default' => [ - 'anonymous' => true, - 'lazy' => true, - 'guard' => [ - 'entry_point' => LoginFormAuthenticator::class, - 'authenticators' => [ - LoginFormAuthenticator::class, - FacebookConnectAuthenticator::class, - ], - ], - ], - ], - ]); + + $defaultFirewall = $security->firewall('default'); + $defaultFirewall->lazy(true); + $defaultFirewall->anonymous(); + $defaultFirewall->guard() + ->entryPoint(LoginFormAuthenticator::class) + ->authenticators([ + LoginFormAuthenticator::class, + FacebookConnectAuthenticator::class, + ]); + }; There is one limitation with this approach - you have to use exactly one entry point. @@ -151,31 +149,32 @@ the solution is to split the configuration into two separate firewalls: // config/packages/security.php use App\Security\ApiTokenAuthenticator; use App\Security\LoginFormAuthenticator; + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('api') + ->pattern('^/api') + ->guard() + ->authenticators([ + ApiTokenAuthenticator::class, + ]); + + $defaultFirewall = $security->firewall('default'); + $defaultFirewall->lazy(true); + $defaultFirewall->anonymous(); + $defaultFirewall->guard() + ->authenticators([ + LoginFormAuthenticator::class, + ]); + + $security->accessControl() + ->path('^/login') + ->roles(['IS_AUTHENTICATED_ANONYMOUSLY']); + $security->accessControl() + ->path('^/api') + ->roles(['ROLE_API_USER']); + $security->accessControl() + ->path('^/') + ->roles(['ROLE_USER']); + }; - $container->loadFromExtension('security', [ - // ... - 'firewalls' => [ - 'api' => [ - 'pattern' => '^/api', - 'guard' => [ - 'authenticators' => [ - ApiTokenAuthenticator::class, - ], - ], - ], - 'default' => [ - 'anonymous' => true, - 'lazy' => true, - 'guard' => [ - 'authenticators' => [ - LoginFormAuthenticator::class, - ], - ], - ], - ], - 'access_control' => [ - ['path' => '^/login', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'], - ['path' => '^/api', 'roles' => 'ROLE_API_USER'], - ['path' => '^/', 'roles' => 'ROLE_USER'], - ], - ]); diff --git a/security/named_hashers.rst b/security/named_hashers.rst index 200a2174c28..06f31852020 100644 --- a/security/named_hashers.rst +++ b/security/named_hashers.rst @@ -44,16 +44,15 @@ to apply to all instances of a specific class: // config/packages/security.php use App\Entity\User; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ + return static function (SecurityConfig $security) { // ... - 'password_hashers' => [ - User::class => [ - 'algorithm' => 'auto', - 'cost' => 12, - ], - ], - ]); + $security->passwordHasher(User::class) + ->algorithm('auto') + ->cost(12) + ; + }; Another option is to use a "named" hasher and then select which hasher you want to use dynamically. @@ -99,15 +98,15 @@ be done with named hashers: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'password_hashers' => [ - 'harsh' => [ - 'algorithm' => 'auto', - 'cost' => '15', - ], - ], - ]); + $security->passwordHasher('harsh') + ->algorithm('auto') + ->cost(15) + ; + }; .. note:: @@ -177,17 +176,15 @@ you must register a service for it in order to use it as a named hasher: .. code-block:: php // config/packages/security.php - // ... use App\Security\Hasher\MyCustomPasswordHasher; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ + return static function (SecurityConfig $security) { // ... - 'password_hashers' => [ - 'app_hasher' => [ - 'id' => MyCustomPasswordHasher::class, - ], - ], - ]); + $security->passwordHasher('app_hasher') + ->id(MyCustomPasswordHasher::class) + ; + }; This creates a hasher named ``app_hasher`` from a service with the ID ``App\Security\Hasher\MyCustomPasswordHasher``. diff --git a/security/password_migration.rst b/security/password_migration.rst index f49e01c887a..6dfcb39cbb2 100644 --- a/security/password_migration.rst +++ b/security/password_migration.rst @@ -81,26 +81,25 @@ on the new hasher to point to the old, legacy hasher(s): .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - // ... + use Symfony\Config\SecurityConfig; - 'password_hashers' => [ - 'legacy' => [ - 'algorithm' => 'sha256', - 'encode_as_base64' => false, - 'iterations' => 1, - ], - - 'App\Entity\User' => [ - // the new hasher, along with its options - 'algorithm' => 'sodium', - 'migrate_from' => [ - 'bcrypt', // uses the "bcrypt" hasher with the default options - 'legacy', // uses the "legacy" hasher configured above - ], - ], - ], - ]); + return static function (SecurityConfig $security) { + // ... + $security->passwordHasher('legacy') + ->algorithm('sha256') + ->encodeAsBase64(true) + ->iterations(1) + ; + + $security->passwordHasher('App\Entity\User') + // the new hasher, along with its options + ->algorithm('sodium') + ->migrateFrom([ + 'bcrypt', // uses the "bcrypt" hasher with the default options + 'legacy', // uses the "legacy" hasher configured above + ]) + ; + }; With this setup: diff --git a/security/remember_me.rst b/security/remember_me.rst index 2efbd8af94e..b14b012202f 100644 --- a/security/remember_me.rst +++ b/security/remember_me.rst @@ -63,24 +63,23 @@ the session lasts using a cookie with the ``remember_me`` firewall option: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - // ... + use Symfony\Config\SecurityConfig; - 'firewalls' => [ - 'main' => [ - // ... - 'remember_me' => [ - 'secret' => '%kernel.secret%', - 'lifetime' => 604800, // 1 week in seconds - 'path' => '/', - // by default, the feature is enabled by checking a - // checkbox in the login form (see below), uncomment - // the following line to always enable it. - //'always_remember_me' => true, - ], - ], - ], - ]); + return static function (SecurityConfig $security) { + // ... + $security->firewall('main') + // ... + ->rememberMe() + ->secret('%kernel.secret%') + ->lifetime(604800) // 1 week in seconds + ->path('/') + + // by default, the feature is enabled by checking a + // checkbox in the login form (see below), uncomment + // the following line to always enable it. + // ->alwaysRememberMe(true) + ; + }; The ``remember_me`` firewall defines the following configuration options: @@ -344,16 +343,14 @@ service you created before: // config/packages/security.php use Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider; - $container->loadFromExtension('security', [ - // ... + use Symfony\Config\SecurityConfig; - 'firewalls' => [ - 'main' => [ + return static function (SecurityConfig $security) { + // ... + $security->firewall('main') + // ... + ->rememberMe() // ... - 'remember_me' => [ - // ... - 'token_provider' => DoctrineTokenProvider::class, - ], - ], - ], - ]); + ->tokenProvider(DoctrineTokenProvider::class) + ; + }; diff --git a/security/user_checkers.rst b/security/user_checkers.rst index 40ed591cef3..a404a668932 100644 --- a/security/user_checkers.rst +++ b/security/user_checkers.rst @@ -110,14 +110,13 @@ is the service id of your user checker: // config/packages/security.php use App\Security\UserChecker; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'main' => [ - 'pattern' => '^/', - 'user_checker' => UserChecker::class, - // ... - ], - ], - ]); + $security->firewall('main') + ->pattern('^/') + ->userChecker(UserChecker::class) + // ... + ; + }; diff --git a/security/user_provider.rst b/security/user_provider.rst index 3f5a7a5a7dd..f064507045d 100644 --- a/security/user_provider.rst +++ b/security/user_provider.rst @@ -90,24 +90,22 @@ to retrieve them: // config/packages/security.php use App\Entity\User; - - $container->loadFromExtension('security', [ - 'providers' => [ - 'users' => [ - 'entity' => [ - // the class of the entity that represents users - 'class' => User::class, - // the property to query by - e.g. username, email, etc - 'property' => 'username', - // optional: if you're using multiple Doctrine entity - // managers, this option defines which one to use - // 'manager_name' => 'customer', - ], - ], - ], + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->provider('users') + ->entity() + // the class of the entity that represents users + ->class(User::class) + // the property to query by - e.g. username, email, etc + ->property('username') + // optional: if you're using multiple Doctrine entity + // managers, this option defines which one to use + ->managerName('customer') + ; // ... - ]); + }; The ``providers`` section creates a "user provider" called ``users`` that knows how to query from your ``App\Entity\User`` entity by the ``username`` property. @@ -195,18 +193,16 @@ To finish this, remove the ``property`` key from the user provider in // config/packages/security.php use App\Entity\User; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ + return static function (SecurityConfig $security) { // ... - 'providers' => [ - 'users' => [ - 'entity' => [ - 'class' => User::class, - ], - ], - ], - ]); + $security->provider('users') + ->entity() + ->class(User::class) + ; + }; This tells Symfony to *not* query automatically for the User. Instead, when needed (e.g. because :doc:`user impersonation `, @@ -271,15 +267,15 @@ users will hash their passwords: // (the 'InMemoryUser' class was introduced in Symfony 5.3. // In previous versions it was called 'User') use Symfony\Component\Security\Core\User\InMemoryUser; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ + return static function (SecurityConfig $security) { // ... - 'password_hashers' => [ - InMemoryUser::class => [ - 'algorithm' => 'auto', - ], - ], - ]); + + $security->passwordHasher(InMemoryUser::class) + ->algorithm('auto') + ; + }; Then, run this command to hash the plain text passwords of your users: diff --git a/security/voters.rst b/security/voters.rst index f702277d008..d860886f175 100644 --- a/security/voters.rst +++ b/security/voters.rst @@ -333,12 +333,14 @@ security configuration: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'access_decision_manager' => [ - 'strategy' => 'unanimous', - 'allow_if_all_abstain' => false, - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->accessDecisionManager() + ->strategy('unanimous') + ->allowIfAllAbstain(false) + ; + }; Custom Access Decision Strategy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -378,10 +380,11 @@ must implement the :class:`Symfony\\Component\\Security\\Core\\Authorization\\Ac // config/packages/security.php use App\Security\MyCustomAccessDecisionManager; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ - 'access_decision_manager' => [ - 'service' => MyCustomAccessDecisionManager::class, + return static function (SecurityConfig $security) { + $security->accessDecisionManager() + ->service(MyCustomAccessDecisionManager::class) // ... - ], - ]); + ; + }; From abfb19d9eb024874a362da644b51b5e14455d07f Mon Sep 17 00:00:00 2001 From: Antonin CLAUZIER Date: Thu, 20 May 2021 15:06:29 +0200 Subject: [PATCH 0954/1519] Closes \#15034 adds information about the lock being nullable --- rate_limiter.rst | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index 96f0cd0e5e0..4f2d20b2b18 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -442,9 +442,9 @@ simultaneous requests (e.g. three servers of a company hitting your API at the same time). Rate limiters use :doc:`locks ` to protect their operations against these race conditions. -By default, Symfony uses the global lock configured by ``framework.lock``), but +By default, Symfony uses the global lock configured by ``framework.lock``, but you can use a specific :ref:`named lock ` via the -``lock_factory`` option: +``lock_factory`` option (or none at all): .. configuration-block:: @@ -459,6 +459,9 @@ you can use a specific :ref:`named lock ` via the # use the "lock.rate_limiter.factory" for this limiter lock_factory: 'lock.rate_limiter.factory' + # or don't use any lock mechanism + lock_factory: null + .. code-block:: xml @@ -481,6 +484,14 @@ you can use a specific :ref:`named lock ` via the lock-factory="lock.rate_limiter.factory" /> + + + @@ -498,9 +509,16 @@ you can use a specific :ref:`named lock ` via the // use the "lock.rate_limiter.factory" for this limiter ->lockFactory('lock.rate_limiter.factory') + + // or don't use any lock mechanism + ->lockFactory(null) ; }; +.. versionadded:: 5.3 + + The login throttling doesn't use any lock since Symfony 5.3 to avoid extra load. + .. _`DoS attacks`: https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html .. _`Apache mod_ratelimit`: https://httpd.apache.org/docs/current/mod/mod_ratelimit.html .. _`NGINX rate limiting`: https://www.nginx.com/blog/rate-limiting-nginx/ From 62997ecf48fa5054fb2d084962b2ce5c13fe8d1e Mon Sep 17 00:00:00 2001 From: Antonin CLAUZIER Date: Fri, 21 May 2021 12:40:04 +0200 Subject: [PATCH 0955/1519] [Notifier] Adds documentation for Slack stuff added in 5.3 --- _images/notifier/slack/message-reply.png | Bin 0 -> 41766 bytes _images/notifier/slack/slack-footer.png | Bin 0 -> 16064 bytes _images/notifier/slack/slack-header.png | Bin 0 -> 10140 bytes notifier/chatters.rst | 114 +++++++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 _images/notifier/slack/message-reply.png create mode 100644 _images/notifier/slack/slack-footer.png create mode 100644 _images/notifier/slack/slack-header.png diff --git a/_images/notifier/slack/message-reply.png b/_images/notifier/slack/message-reply.png new file mode 100644 index 0000000000000000000000000000000000000000..9a60e4573ab2c4c23ae6b0f4d1be84aa1f39b5ba GIT binary patch literal 41766 zcmbrm1yq!8xGy^DUr|z|q;&vM8tFzEq`Osu+h4{&WlVeQg*<94zV>!XU+Qs_F z21@3ki5CizdU}CGZvI*&PCFQQbgF{yXi^k68|bCFqmdnJ6#qQNHZ2^up{_F?NN{l~ zGH|vvT0>7ao`{A(7M3@*H#4&`E9~(g`&RkU4B$i{DW7*#9X+uAX<{Y-{eOu1@mq*Pj350>9ZzKjVC<-Cfok*Xr_##bqtOdLuV zIo%xz^m9Gl;P;&Q{e~fj%YJ*Q1ljcA-Me>ue6!JokHIO#A+C&_CM-_D&uDIG@vxpF z<1i}!m495aOdX$EnngiDkzQ0pj)zx}m%cnvsHLv%DxvaEa*=j}n^Y2a*VL4_nAoOJ z6$U!`RHLDr>|n&F92n&bZ0r`Mp!Y>bTp=>(>^CP4un9=9fMPn9BVYN&?B^t%Y^-{qFHjEp)J zUFZH0XsFIDKCT#Ktg=c{Z1nUe*B60}9M(8PKkbY!uDfxlr7_6YsAw7Q-XE@J(NDi; zVeuE$k-5ubG@hEAY;;jLy}mf|xN0b~v;7oA#O$#ZIb!S)85vpYT5UbsNI^+ye?7r$ zWyR1mQ~ms4 zP&r{?!ytYkAM~xIJ%*yUcl(RWaHqY(w~RU^J7=f6iR_khQ&lq76#6ZX(HdnWWW3g2 zkB?^T{$@^};^O?mnb6r8!{f9oB_%-x#lwqoneVr;wTMZKh)7PJuh$_;F|4QF>%CYr zXJb=>zGvZJVd0>F($g1k=?r)tZ`i1*T?80P7#bKnd`RXeI@;Fq-Op;SR!dd&cr`y( zTl>46t=*$X-$`~X2zrxMx(NJ=a>F7b;`u$y^z_1i{rZ)zU-uJj?Ph;@ATBOWqsk&Q zDhdMw!%%g{YPPo0bi`<{{_zr#4<;cU6_qdyy`?vqW4v!Hv${GXw1b6(MeA}pd{W1Y z_7g-fhR!-t~3w~|uU=tO-v@?q=$jsz& z-WPAt&&%Ha2fr6_<+R)K*qLJy>p{ zpRU9i3QzVduc)xuoRFK*5f|SY-DJ_#9Y{;l*VETe7Vz>snZn>thC7X8l4_B1sKk`5 z_cxrm;p5{a@-MSk^=>Rv%e1w%saVIX+4`arW@P+v-q;^{a^nNRSXr7nSVk!+_3Wr9 zEcj7Tp|mb-<@4mp$1o-;Dz;Y(AM7P9j&`PcM@PGIw5BU96_pghDh*M2NlZZSg6Q

    2gMPN};Q5`Z#G%E)r)01VYbWruG(}7%@(J{7M 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 literal 0 HcmV?d00001 diff --git a/notifier/chatters.rst b/notifier/chatters.rst index f01a8bd7ce6..f77e0ebfd5e 100644 --- a/notifier/chatters.rst +++ b/notifier/chatters.rst @@ -135,6 +135,120 @@ The result will be something like: The `field()` method was introduced in Symfony 5.1. +Adding a header to a Slack Message +------------------------------------------- + +To add a header to your message you can use the +:class:`Symfony\\Component\\Notifier\\Bridge\\Slack\\Block\\SlackHeaderBlock` class:: + + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackDividerBlock; + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackHeaderBlock; + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackSectionBlock; + use Symfony\Component\Notifier\Bridge\Slack\SlackOptions; + use Symfony\Component\Notifier\Message\ChatMessage; + + $chatMessage = new ChatMessage('Symfony Feature'); + + $options = (new SlackOptions()) + ->block((new SlackHeaderBlock('My Header'))) + ->block((new SlackSectionBlock())->text('My message')) + ->block(new SlackDividerBlock()) + ->block( + (new SlackSectionBlock()) + ->field('*Max Rating*') + ->field('5.0') + ->field('*Min Rating*') + ->field('1.0') + ); + + // Add the custom options to the chat message and send the message + $chatMessage->options($options); + + $chatter->send($chatMessage); + +The result will be something like: + +.. image:: /_images/notifier/slack/slack-header.png + :align: center + +.. versionadded:: 5.3 + + The `SlackHeaderBlock` class was introduced in Symfony 5.3. + +Adding a footer to a Slack Message +------------------------------------------- + +To add a footer to your message you can use the +:class:`Symfony\\Component\\Notifier\\Bridge\\Slack\\Block\\SlackContextBlock` class:: + + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackContextBlock; + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackDividerBlock; + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackSectionBlock; + use Symfony\Component\Notifier\Bridge\Slack\SlackOptions; + use Symfony\Component\Notifier\Message\ChatMessage; + + $chatMessage = new ChatMessage('Symfony Feature'); + + $contextBlock = (new SlackContextBlock()) + ->text('My Context') + ->image('https://symfony.com/logos/symfony_white_03.png', 'Symfony Logo') + ; + + $options = (new SlackOptions()) + ->block((new SlackSectionBlock())->text('My message')) + ->block(new SlackDividerBlock()) + ->block( + (new SlackSectionBlock()) + ->field('*Max Rating*') + ->field('5.0') + ->field('*Min Rating*') + ->field('1.0') + ) + ->block($contextBlock) + ; + + $chatter->send($chatMessage); + +The result will be something like: + +.. image:: /_images/notifier/slack/slack-footer.png + :align: center + +.. versionadded:: 5.3 + + The `SlackContextBlock` class was introduced in Symfony 5.3. + +Sending a Slack Message as a reply +------------------------------------------- + +To send your slack message as a reply in a thread you can use the +:method:`SlackOptions::threadTs() ` method:: + + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackSectionBlock; + use Symfony\Component\Notifier\Bridge\Slack\SlackOptions; + use Symfony\Component\Notifier\Message\ChatMessage; + + $chatMessage = new ChatMessage('Symfony Feature'); + + $options = (new SlackOptions()) + ->block((new SlackSectionBlock())->text('My reply')) + ->threadTs('1621592155.003100') + ; + + // Add the custom options to the chat message and send the message + $chatMessage->options($options); + + $chatter->send($chatMessage); + +The result will be something like: + +.. image:: /_images/notifier/slack/message-reply.png + :align: center + +.. versionadded:: 5.3 + + The `threadTs()` method was introduced in Symfony 5.3. + Adding Interactions to a Discord Message ---------------------------------------- From 884629de42c89da7219296dd2651b76736462c76 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 21 May 2021 14:30:18 +0200 Subject: [PATCH 0956/1519] Tweaks --- notifier/chatters.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/notifier/chatters.rst b/notifier/chatters.rst index f77e0ebfd5e..237581556ec 100644 --- a/notifier/chatters.rst +++ b/notifier/chatters.rst @@ -135,10 +135,10 @@ The result will be something like: The `field()` method was introduced in Symfony 5.1. -Adding a header to a Slack Message -------------------------------------------- +Adding a Header to a Slack Message +---------------------------------- -To add a header to your message you can use the +To add a header to your message use the :class:`Symfony\\Component\\Notifier\\Bridge\\Slack\\Block\\SlackHeaderBlock` class:: use Symfony\Component\Notifier\Bridge\Slack\Block\SlackDividerBlock; @@ -173,12 +173,12 @@ The result will be something like: .. versionadded:: 5.3 - The `SlackHeaderBlock` class was introduced in Symfony 5.3. + The ``SlackHeaderBlock`` class was introduced in Symfony 5.3. -Adding a footer to a Slack Message -------------------------------------------- +Adding a Footer to a Slack Message +---------------------------------- -To add a footer to your message you can use the +To add a footer to your message use the :class:`Symfony\\Component\\Notifier\\Bridge\\Slack\\Block\\SlackContextBlock` class:: use Symfony\Component\Notifier\Bridge\Slack\Block\SlackContextBlock; @@ -216,12 +216,12 @@ The result will be something like: .. versionadded:: 5.3 - The `SlackContextBlock` class was introduced in Symfony 5.3. + The ``SlackContextBlock`` class was introduced in Symfony 5.3. -Sending a Slack Message as a reply -------------------------------------------- +Sending a Slack Message as a Reply +---------------------------------- -To send your slack message as a reply in a thread you can use the +To send your slack message as a reply in a thread use the :method:`SlackOptions::threadTs() ` method:: use Symfony\Component\Notifier\Bridge\Slack\Block\SlackSectionBlock; @@ -247,7 +247,7 @@ The result will be something like: .. versionadded:: 5.3 - The `threadTs()` method was introduced in Symfony 5.3. + The ``threadTs()`` method was introduced in Symfony 5.3. Adding Interactions to a Discord Message ---------------------------------------- From bcaf46a21cbfa5ab4d4244c31e61326bb8c647d7 Mon Sep 17 00:00:00 2001 From: Romain Monteil Date: Wed, 17 Mar 2021 00:28:08 +0100 Subject: [PATCH 0957/1519] [Form] Bootstrap 5 documentation --- form/bootstrap5.rst | 265 ++++++++++++++++++++++++++++++++++++++++++++ forms.rst | 1 + 2 files changed, 266 insertions(+) create mode 100644 form/bootstrap5.rst diff --git a/form/bootstrap5.rst b/form/bootstrap5.rst new file mode 100644 index 00000000000..2a219c990a8 --- /dev/null +++ b/form/bootstrap5.rst @@ -0,0 +1,265 @@ +Bootstrap 5 Form Theme +====================== + +.. versionadded:: 5.3 + + The Bootstrap 5 Form Theme was introduce in Symfony 5.3. + +Symfony provides several ways of integrating Bootstrap into your application. The +most straightforward way is to add the required ```` and `` + +Then retrieve it from your JS file: + +.. code:: javascript + + const url = JSON.parse(document.getElementById("mercure-url").textContent); + const eventSource = new EventSource(url); + // ... -Mercure also allows to subscribe to several topics, +Mercure also allows subscribing to several topics, and to use URI Templates or the special value ``*`` (matched by all topics) as patterns: -.. code-block:: javascript +.. code-block:: twig - // URL is a built-in JavaScript class to manipulate URLs - const url = new URL('/.well-known/mercure', window.origin); - url.searchParams.append('topic', 'http://example.com/books/1'); - // Subscribe to updates of several Book resources - url.searchParams.append('topic', 'http://example.com/books/2'); - // All Review resources will match this pattern - url.searchParams.append('topic', 'http://example.com/reviews/{id}'); + .. tip:: @@ -287,7 +352,7 @@ and to subscribe to it: // Append the topic(s) to subscribe as query parameter const hub = new URL(hubUrl, window.origin); - hub.searchParams.append('topic', 'http://example.com/books/{id}'); + hub.searchParams.append('topic', 'https://example.com/books/{id}'); // Subscribe to updates const eventSource = new EventSource(hub); @@ -297,7 +362,7 @@ and to subscribe to it: Authorization ------------- -Mercure also allows to dispatch updates only to authorized clients. +Mercure also allows dispatching updates only to authorized clients. To do so, mark the update as **private** by setting the third parameter of the ``Update`` constructor to ``true``:: @@ -313,7 +378,7 @@ of the ``Update`` constructor to ``true``:: public function publish(HubInterface $hub): Response { $update = new Update( - 'http://example.com/books/1', + 'https://example.com/books/1', json_encode(['status' => 'OutOfStock']), true // private ); @@ -332,78 +397,59 @@ a JWT containing a topic selector matching by the update's topic. To provide this JWT, the subscriber can use a cookie, or a ``Authorization`` HTTP header. -Cookies are automatically sent by the browsers when opening an ``EventSource`` -connection if the ``withCredentials`` attribute is set to ``true``: +Cookies can be set automatically by Symfony by passing the appropriate options to the ``mercure()`` Twig function. +Cookies set by Symfony will be automatically passed by the browsers to the Mercure hub +if the ``withCredentials`` attribute of the ``EventSource`` class is set to ``true``. +Then, the Hub will verify the validity of the provided JWT, and extract the topic selectors +from it. -.. code-block:: javascript +.. code-block:: twig - const eventSource = new EventSource(hub, { + + +The supported options are: + +* ``subscribe``: the list of topic selectors to include in the ``mercure.subscribe`` claim of the JWT +* ``publish``: the list of topic selectors to include in the ``mercure.publish`` claim of the JWT +* ``additionalClaims``: extra claims to include in the JWT (expiration date, token ID...) Using cookies is the most secure and preferred way when the client is a web browser. If the client is not a web browser, then using an authorization header is the way to go. +.. caution:: + + To use the cookie authentication method, the Symfony app and the Hub + must be served from the same domain (can be different sub-domains). + .. tip:: The native implementation of EventSource doesn't allow specifying headers. For example, authorization using Bearer token. In order to achieve that, use `a polyfill`_ - .. code-block:: javascript + .. code-block:: twig - const es = new EventSourcePolyfill(url, { + -In the following example controller, -the generated cookie contains a JWT, itself containing the appropriate topic selector. -This cookie will be automatically sent by the web browser when connecting to the Hub. -Then, the Hub will verify the validity of the provided JWT, and extract the topic selectors -from it. - -Add your JWT secret to the configuration as follow: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/mercure.yaml - mercure: - hubs: - default: - url: https://mercure-hub.example.com/.well-known/mercure - jwt: - secret: '!ChangeMe!' - - .. code-block:: xml - - - - - - - - +Programmatically Setting The Cookie +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. code-block:: php +Sometimes, it can be convenient to set the authorization cookie from +your code instead of using the Twig function. +MercureBundle provides a convenient service, :class:`Symfony\\Component\\Mercure\\Authorization`, to do so. - // config/packages/mercure.php - $container->loadFromExtension('mercure', [ - 'hubs' => [ - 'default' => [ - 'url' => 'https://mercure-hub.example.com/.well-known/mercure', - 'jwt' => [ - 'secret' => '!ChangeMe!', - ], - ], - ], - ]); +In the following example controller, +the added cookie contains a JWT, itself containing the appropriate topic selector. And here is the controller:: @@ -411,36 +457,25 @@ And here is the controller:: namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; - use Symfony\Component\HttpFoundation\Cookie; + use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Mercure\Authorization; use Symfony\Component\Mercure\Discovery; class DiscoverController extends AbstractController { - public function publish(Request $request, Discovery $discovery, Authorization $authorization): Response + public function publish(Request $request, Discovery $discovery, Authorization $authorization): JsonResponse { $discovery->addLink($request); + $authorization->setCookie($request, ['https://example.com/books/1']); - $response = new JsonResponse([ + return $this->json([ '@id' => '/demo/books/1', 'availability' => 'https://schema.org/InStock' ]); - - $response->headers->setCookie( - $authorization->createCookie($request, ["http://example.com/books/1"]) - ); - - return $response; } } -.. caution:: - - To use the cookie authentication method, the Symfony app and the Hub - must be served from the same domain (can be different sub-domains). - Programmatically Generating The JWT Used to Publish --------------------------------------------------- @@ -532,22 +567,16 @@ hypermedia API, and automatic update broadcasting through the Mercure hub:: use ApiPlatform\Core\Annotation\ApiResource; use Doctrine\ORM\Mapping as ORM; - /** - * @ApiResource(mercure=true) - * @ORM\Entity - */ + #[ApiResource(mercure: true)] + #[ORM\Entity] class Book { - /** - * @ORM\Id - * @ORM\Column - */ - public $name; - - /** - * @ORM\Column - */ - public $status; + #[ORM\Id] + #[ORM\Column] + public string $name = ''; + + #[ORM\Column] + public string $status = ''; } As showcased `in this recording`_, the API Platform Client Generator also @@ -629,34 +658,12 @@ Debugging Enable the panel in your configuration, as follows: -.. configuration-block:: - - .. code-block:: yaml +MercureBundle is shipped with a debug panel. Install the Debug pack to +enable it:: - # config/packages/mercure.yaml - mercure: - enable_profiler: '%kernel.debug%' - - .. code-block:: xml - - - - - - - - - - .. code-block:: php - - // config/packages/mercure.php - $container->loadFromExtension('mercure', [ - 'enable_profiler' => '%kernel.debug%', - ]); +.. code-block:: terminal + $ composer require --dev symfony/debug-pack .. image:: /_images/mercure/panel.png @@ -693,7 +700,7 @@ it will be handled automatically:: public function publish(MessageBusInterface $bus): Response { $update = new Update( - 'http://example.com/books/1', + 'https://example.com/books/1', json_encode(['status' => 'OutOfStock']) ); @@ -704,6 +711,12 @@ it will be handled automatically:: } } +Going further +------------- + +* The Mercure protocol is also supported by :doc:`the Notifier component `. Use it to send push notifications to web browsers. +* `Symfony UX Turbo`_ is a library using Mercure to provide the same experience as with Single Page Applications but without having to write a single line of JavaScript! + .. _`the Mercure protocol`: https://mercure.rocks/spec .. _`Server-Sent Events (SSE)`: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events @@ -720,3 +733,4 @@ it will be handled automatically:: .. _`the dedicated API Platform documentation`: https://api-platform.com/docs/core/mercure/ .. _`the online debugger`: https://uri-template-tester.mercure.rocks .. _`a feature to test applications using Mercure`: https://github.com/symfony/panther#creating-isolated-browsers-to-test-apps-using-mercure-or-websocket +.. _`Symfony UX Turbo`: https://github.com/symfony/ux-turbo diff --git a/setup/symfony_server.rst b/setup/symfony_server.rst index aa23a26a61e..4ac94fd857f 100644 --- a/setup/symfony_server.rst +++ b/setup/symfony_server.rst @@ -275,6 +275,8 @@ server provides a ``run`` command to wrap them as follows: # stop the web server (and all the associated commands) when you are finished $ symfony server:stop +.. _symfony-server-docker: + Docker Integration ------------------ From 4479c32a4eb60e4012b11db1ee34f80cc4fc3c14 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 14 Oct 2021 16:41:32 +0200 Subject: [PATCH 1196/1519] Tweaks --- mercure.rst | 65 ++++++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/mercure.rst b/mercure.rst index 72ce65145e5..e9d9f163692 100644 --- a/mercure.rst +++ b/mercure.rst @@ -57,16 +57,17 @@ can be downloaded as a static binary from `Mercure.rocks`_. A Docker image, a Helm chart for Kubernetes and a managed, High Availability Hub are also provided. -If you use `Symfony Docker`_ or the `API Platform distribution`_, -a Mercure Hub is automatically installed and your Symfony application -is automatically configured to use it. -You can jump directly to the next section. +If you use `Symfony Docker`_ or the `API Platform distribution`_, a Mercure Hub +is automatically installed and your Symfony application is automatically +configured to use it. You can jump directly to the next section. If you use the :doc:`Symfony Local Web Server `, -a Mercure hub will be automatically available as a Docker service thanks to its :ref:`Docker integration . +a Mercure hub will be automatically available as a Docker service thanks to its +:ref:`Docker integration . -Be sure that recent versions of Docker and Docker Compose are properly installed on your computer -and to start the Symfony Local Web Server with the ``--no-tls`` option: +Be sure that recent versions of Docker and Docker Compose are properly installed +on your computer and to start the Symfony Local Web Server with the ``--no-tls`` +option: .. code-block:: terminal @@ -81,9 +82,9 @@ Run this command to install the Mercure support before using it: $ composer require mercure -:ref:`Symfony Flex ` has automatically installed and configured MercureBundle. -It also created (if needed) and configured a Docker Compose definition that provides a Mercure service. -Run ``docker-compose up`` to start it. +:ref:`Symfony Flex ` has automatically installed and configured +MercureBundle. It also created (if needed) and configured a Docker Compose +definition that provides a Mercure service. Run ``docker-compose up`` to start it. Configuration ------------- @@ -94,8 +95,9 @@ The preferred way to configure the MercureBundle is using When MercureBundle has been installed, the ``.env`` file of your project has been updated by the Flex recipe to include the available env vars. -If you use the Symfony Local Web Server, Symfony Docker or the API Platform distribution, -the Symfony app is automatically configured and you can skip straight to the next section. +If you use the Symfony Local Web Server, Symfony Docker or the API Platform +distribution, the Symfony app is automatically configured and you can skip +straight to the next section. Otherwise, set the URL of your hub as the value of the ``MERCURE_URL`` and ``MERCURE_PUBLIC_URL`` env vars. @@ -251,10 +253,12 @@ Subscribing to updates in JavaScript from a Twig template is straightforward: } The ``mercure()`` Twig function will generate the URL of the Mercure hub according to the configuration. The URL will include the ``topic`` query @@ -260,13 +260,15 @@ parameters corresponding to the topics passed as first argument. If you want to access to this URL from an external JavaScript file, generate the URL in a dedicated HTML element: -.. code:: twig +.. code-block:: twig - + Then retrieve it from your JS file: -.. code:: javascript +.. code-block:: javascript const url = JSON.parse(document.getElementById("mercure-url").textContent); const eventSource = new EventSource(url); From 44ffc2f64cdc535782aef9cdd5415f6dd3cbff34 Mon Sep 17 00:00:00 2001 From: BahmanMD Date: Tue, 26 Oct 2021 13:25:49 +0330 Subject: [PATCH 1221/1519] Add Attributes code --- page_creation.rst | 56 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/page_creation.rst b/page_creation.rst index 642d1dd2de8..7e17c017e9b 100644 --- a/page_creation.rst +++ b/page_creation.rst @@ -94,6 +94,10 @@ to creating a page? Annotation Routes ----------------- +.. caution:: + + If you use PHP8 or later, you do not need to install annotations package and instead of annotations, you can use structured metadata with PHP's native syntax (Attributes) + Instead of defining your route in YAML, Symfony also allows you to use *annotation* routes. To do this, install the annotations package: @@ -103,23 +107,41 @@ routes. To do this, install the annotations package: You can now add your route directly *above* the controller: -.. code-block:: diff - - // src/Controller/LuckyController.php - - // ... - + use Symfony\Component\Routing\Annotation\Route; - - class LuckyController - { - + /** - + * @Route("/lucky/number") - + */ - public function number() - { - // this looks exactly the same - } - } +.. configuration-block:: + + .. code-block:: Annotations + + // src/Controller/LuckyController.php + + // ... + + use Symfony\Component\Routing\Annotation\Route; + + class LuckyController + { + + /** + + * @Route("/lucky/number") + + */ + public function number() + { + // this looks exactly the same + } + } + + .. code-block:: Attributes + + // src/Controller/LuckyController.php + + // ... + + use Symfony\Component\Routing\Annotation\Route; + + class LuckyController + { + + #[Route('/lucky/number') + public function number() + { + // this looks exactly the same + } + } That's it! The page - http://localhost:8000/lucky/number will work exactly like before! Annotations are the recommended way to configure routes. From 9320163d95828fd591a4b5129424f6eb34c36339 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 26 Oct 2021 13:38:30 +0200 Subject: [PATCH 1222/1519] Fix some line numbers in a code example --- migration.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migration.rst b/migration.rst index 0c298af44a9..71c55ba240d 100644 --- a/migration.rst +++ b/migration.rst @@ -289,7 +289,7 @@ could look something like this:: There are 2 major deviations from the original file: -Line 15 +Line 18 First of all, ``$kernel`` is made globally available. This allows you to use Symfony features inside your existing application and gives access to services configured in our Symfony application. This helps you prepare your @@ -297,7 +297,7 @@ Line 15 it over. For instance, by replacing outdated or redundant libraries with Symfony components. -Line 38 - 47 +Line 41 - 50 Instead of sending the Symfony response directly, a ``LegacyBridge`` is called to decide whether the legacy application should be booted and used to create the response instead. From 90936ab2786537b4dd6693eb4eba539a3fec15f8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 26 Oct 2021 15:50:29 +0200 Subject: [PATCH 1223/1519] Minor reword --- page_creation.rst | 75 +++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/page_creation.rst b/page_creation.rst index 7e17c017e9b..cc00e592880 100644 --- a/page_creation.rst +++ b/page_creation.rst @@ -94,12 +94,9 @@ to creating a page? Annotation Routes ----------------- -.. caution:: - - If you use PHP8 or later, you do not need to install annotations package and instead of annotations, you can use structured metadata with PHP's native syntax (Attributes) - Instead of defining your route in YAML, Symfony also allows you to use *annotation* -routes. To do this, install the annotations package: +or *attribute* routes. Attributes are built-in in PHP starting from PHP 8. In earlier +PHP versions you can use annotations. To do this, install the annotations package: .. code-block:: terminal @@ -109,42 +106,42 @@ You can now add your route directly *above* the controller: .. configuration-block:: - .. code-block:: Annotations - - // src/Controller/LuckyController.php - - // ... - + use Symfony\Component\Routing\Annotation\Route; - - class LuckyController - { - + /** - + * @Route("/lucky/number") - + */ - public function number() - { - // this looks exactly the same - } - } - - .. code-block:: Attributes - - // src/Controller/LuckyController.php - - // ... - + use Symfony\Component\Routing\Annotation\Route; - - class LuckyController - { - + #[Route('/lucky/number') - public function number() - { - // this looks exactly the same - } - } + .. code-block:: php-annotations + + // src/Controller/LuckyController.php + + // ... + + use Symfony\Component\Routing\Annotation\Route; + + class LuckyController + { + + /** + + * @Route("/lucky/number") + + */ + public function number() + { + // this looks exactly the same + } + } + + .. code-block:: php-attributes + + // src/Controller/LuckyController.php + + // ... + + use Symfony\Component\Routing\Annotation\Route; + + class LuckyController + { + + #[Route('/lucky/number') + public function number() + { + // this looks exactly the same + } + } That's it! The page - http://localhost:8000/lucky/number will work exactly -like before! Annotations are the recommended way to configure routes. +like before! Annotations/attributes are the recommended way to configure routes. .. _flex-quick-intro: From b430be892853ad6d2699fa09ce6d63532649503c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 26 Oct 2021 16:26:12 +0200 Subject: [PATCH 1224/1519] Minor tweaks --- configuration.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/configuration.rst b/configuration.rst index 81437a3f861..f08668905dd 100644 --- a/configuration.rst +++ b/configuration.rst @@ -718,8 +718,8 @@ you can encrypt the value using the :doc:`secrets management system Date: Tue, 26 Oct 2021 16:27:23 +0200 Subject: [PATCH 1225/1519] Remove the versionadded directive --- configuration.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/configuration.rst b/configuration.rst index a21f39b7f46..e08760d88b9 100644 --- a/configuration.rst +++ b/configuration.rst @@ -747,10 +747,6 @@ Use the ``debug:dotenv`` command to understand how Symfony parses the different ALICE BOB BOB bob ---------- ------- ---------- ------ -.. versionadded:: 5.4 - - The ``debug:dotenv`` command was introduced in Symfony 5.4. - Additionally, and regardless of how you set environment variables, you can see all environment variables, with their values, referenced in Symfony's container configuration: From e1126491c9443dcc8a4b52bc34dbaba0d4b759d7 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Wed, 27 Oct 2021 10:42:08 -0400 Subject: [PATCH 1226/1519] [DependencyInjection] ServiceSubscriberTrait 5.4 update --- .../service_subscribers_locators.rst | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/service_container/service_subscribers_locators.rst b/service_container/service_subscribers_locators.rst index db75b181446..2459139ed70 100644 --- a/service_container/service_subscribers_locators.rst +++ b/service_container/service_subscribers_locators.rst @@ -627,8 +627,9 @@ Service Subscriber Trait The :class:`Symfony\\Contracts\\Service\\ServiceSubscriberTrait` provides an implementation for :class:`Symfony\\Contracts\\Service\\ServiceSubscriberInterface` -that looks through all methods in your class that have no arguments and a return -type. It provides a ``ServiceLocator`` for the services of those return types. +that looks through all methods in your class that are marked with the +:class:`Symfony\\Contracts\\Service\\Attribute\\SubscribedService` attribute. It +provides a ``ServiceLocator`` for the services of each method's return type. The service id is ``__METHOD__``. This allows you to add dependencies to your services based on type-hinted helper methods:: @@ -637,6 +638,7 @@ services based on type-hinted helper methods:: use Psr\Log\LoggerInterface; use Symfony\Component\Routing\RouterInterface; + use Symfony\Contracts\Service\Attribute\SubscribedService; use Symfony\Contracts\Service\ServiceSubscriberInterface; use Symfony\Contracts\Service\ServiceSubscriberTrait; @@ -650,11 +652,13 @@ services based on type-hinted helper methods:: // $this->logger() ... } + #[SubscribedService] private function router(): RouterInterface { return $this->container->get(__METHOD__); } + #[SubscribedService] private function logger(): LoggerInterface { return $this->container->get(__METHOD__); @@ -668,9 +672,11 @@ and compose your services with them:: namespace App\Service; use Psr\Log\LoggerInterface; + use Symfony\Contracts\Service\Attribute\SubscribedService; trait LoggerAware { + #[SubscribedService] private function logger(): LoggerInterface { return $this->container->get(__CLASS__.'::'.__FUNCTION__); @@ -681,9 +687,11 @@ and compose your services with them:: namespace App\Service; use Symfony\Component\Routing\RouterInterface; + use Symfony\Contracts\Service\Attribute\SubscribedService; trait RouterAware { + #[SubscribedService] private function router(): RouterInterface { return $this->container->get(__CLASS__.'::'.__FUNCTION__); @@ -713,4 +721,12 @@ and compose your services with them:: as this will include the trait name, not the class name. Instead, use ``__CLASS__.'::'.__FUNCTION__`` as the service id. +.. deprecated:: 5.4 + + Defining your *subscribed service* methods with the + :class:`Symfony\\Contracts\\Service\\Attribute\\SubscribedService` attribute + was added in Symfony 5.4. Previously, any methods with no arguments and a + return type were *subscribed*. This still works in 5.4 but is deprecated (only + when using PHP 8) and will be removed in 6.0. + .. _`Command pattern`: https://en.wikipedia.org/wiki/Command_pattern From bbee2bf824296bed62969f1c8b0cc3161005026a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 27 Oct 2021 17:35:44 +0200 Subject: [PATCH 1227/1519] Remove the deprecated directive --- service_container/service_subscribers_locators.rst | 8 -------- 1 file changed, 8 deletions(-) diff --git a/service_container/service_subscribers_locators.rst b/service_container/service_subscribers_locators.rst index 427ba5725b6..6bc379ee9cc 100644 --- a/service_container/service_subscribers_locators.rst +++ b/service_container/service_subscribers_locators.rst @@ -720,12 +720,4 @@ and compose your services with them:: as this will include the trait name, not the class name. Instead, use ``__CLASS__.'::'.__FUNCTION__`` as the service id. -.. deprecated:: 5.4 - - Defining your *subscribed service* methods with the - :class:`Symfony\\Contracts\\Service\\Attribute\\SubscribedService` attribute - was added in Symfony 5.4. Previously, any methods with no arguments and a - return type were *subscribed*. This still works in 5.4 but is deprecated (only - when using PHP 8) and will be removed in 6.0. - .. _`Command pattern`: https://en.wikipedia.org/wiki/Command_pattern From a0d0c46a176b55c4546f1e1d23b11ac39a6edb58 Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Wed, 27 Oct 2021 22:39:02 +0200 Subject: [PATCH 1228/1519] CSP => Content Security Policy --- frontend/encore/vuejs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/encore/vuejs.rst b/frontend/encore/vuejs.rst index 4473849be22..896c1e6de19 100644 --- a/frontend/encore/vuejs.rst +++ b/frontend/encore/vuejs.rst @@ -45,7 +45,7 @@ runtime. This means that you *can* do either of these: }); If you do *not* need this functionality (e.g. you use single file components), -then you can tell Encore to create a *smaller* and CSP-compliant build: +then you can tell Encore to create a *smaller* build following Content Security Policy: .. code-block:: javascript From a2fed1ad73b61d5a2df96154a64745793ddc4ca6 Mon Sep 17 00:00:00 2001 From: Quentin Dequippe Date: Thu, 28 Oct 2021 08:47:46 +0200 Subject: [PATCH 1229/1519] Unexpected arrow for hash key Replace arrow by colon --- translation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translation.rst b/translation.rst index 3026da62ff8..2d9a66f1c35 100644 --- a/translation.rst +++ b/translation.rst @@ -304,7 +304,7 @@ using PHP's :phpclass:`MessageFormatter` class. Read more about this in .. code-block:: twig - {{ message|trans({'%name%': '...', '%count%' => 1}, 'app') }} + {{ message|trans({'%name%': '...', '%count%': 1}, 'app') }} The ``message`` variable must include all the different versions of this message based on the value of the ``count`` parameter. For example: From 7f44b336c28ab8ac66cfd4a3912779d4b0f1f0aa Mon Sep 17 00:00:00 2001 From: Mathieu Santostefano Date: Thu, 28 Oct 2021 10:08:24 +0200 Subject: [PATCH 1230/1519] Rename translation:update to translation:extract --- reference/dic_tags.rst | 2 +- translation.rst | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/reference/dic_tags.rst b/reference/dic_tags.rst index 23b694910d9..fd84a0ac70b 100644 --- a/reference/dic_tags.rst +++ b/reference/dic_tags.rst @@ -1021,7 +1021,7 @@ translation.extractor **Purpose**: To register a custom service that extracts messages from a file -When executing the ``translation:update`` command, it uses extractors to +When executing the ``translation:extract`` command, it uses extractors to extract translation messages from a file. By default, the Symfony Framework has a :class:`Symfony\\Bridge\\Twig\\Translation\\TwigExtractor` and a :class:`Symfony\\Component\\Translation\\Extractor\\PhpExtractor`, which diff --git a/translation.rst b/translation.rst index 83e95f8dda4..a3d49778c5e 100644 --- a/translation.rst +++ b/translation.rst @@ -466,21 +466,26 @@ Extracting Translation Contents and Updating Catalogs Automatically The most time-consuming tasks when translating an application is to extract all the template contents to be translated and to keep all the translation files in -sync. Symfony includes a command called ``translation:update`` that helps you +sync. Symfony includes a command called ``translation:extract`` that helps you with these tasks: .. code-block:: terminal # shows all the messages that should be translated for the French language - $ php bin/console translation:update --dump-messages fr + $ php bin/console translation:extract --dump-messages fr # updates the French translation files with the missing strings for that locale - $ php bin/console translation:update --force fr + $ php bin/console translation:extract --force fr # check out the command help to see its options (prefix, output format, domain, sorting, etc.) - $ php bin/console translation:update --help + $ php bin/console translation:extract --help -The ``translation:update`` command looks for missing translations in: +.. deprecated:: 5.4 + + Support for ``translation:update`` was deprecated in Symfony 5.4 + and it will be removed in Symfony 6.0. + +The ``translation:extract`` command looks for missing translations in: * Templates stored in the ``templates/`` directory (or any other directory defined in the :ref:`twig.default_path ` and From 4c34e056918e790ccc39804afe892524013df76c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=AF=E8=80=83=E5=90=89=E6=81=A9?= Date: Thu, 28 Oct 2021 17:12:04 +0800 Subject: [PATCH 1231/1519] make following jquery example works in this section: https://symfony.com/doc/5.4/frontend/encore/simple-example.html#requiring-javascript-modules It's using jquery as example, so we should tell user that they have to enable autoProvidejQuery option to use jquery in following tutorial. --- frontend/encore/simple-example.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/encore/simple-example.rst b/frontend/encore/simple-example.rst index 3cd89e092bf..cbec25be78c 100644 --- a/frontend/encore/simple-example.rst +++ b/frontend/encore/simple-example.rst @@ -43,7 +43,8 @@ of your project. It already holds the basic config you need: .addEntry('app', './assets/app.js') - // ... + // Don't forget to uncomment If you want use following JQuery example code + .autoProvidejQuery() ; // ... From 7fd01364d897b72635ec2c7e2eb2dd2e1acf2c46 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 28 Oct 2021 11:44:42 +0200 Subject: [PATCH 1232/1519] Minor tweak --- translation.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/translation.rst b/translation.rst index a3d49778c5e..e716f057dc2 100644 --- a/translation.rst +++ b/translation.rst @@ -482,7 +482,8 @@ with these tasks: .. deprecated:: 5.4 - Support for ``translation:update`` was deprecated in Symfony 5.4 + In previous Symfony versions, the ``translation:extract`` command was called + ``translation:update``, but that name was deprecated in Symfony 5.4 and it will be removed in Symfony 6.0. The ``translation:extract`` command looks for missing translations in: From 34a35c060cfcd1b2cccb42e8393e41955142b0a2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 28 Oct 2021 11:47:17 +0200 Subject: [PATCH 1233/1519] Remove deprecated directive --- translation.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/translation.rst b/translation.rst index eb0ea87e5dc..fc78df9808e 100644 --- a/translation.rst +++ b/translation.rst @@ -476,12 +476,6 @@ with these tasks: # check out the command help to see its options (prefix, output format, domain, sorting, etc.) $ php bin/console translation:extract --help -.. deprecated:: 5.4 - - In previous Symfony versions, the ``translation:extract`` command was called - ``translation:update``, but that name was deprecated in Symfony 5.4 - and it will be removed in Symfony 6.0. - The ``translation:extract`` command looks for missing translations in: * Templates stored in the ``templates/`` directory (or any other directory From c955fd705f9d1734dd97b85a47a95c4aab244949 Mon Sep 17 00:00:00 2001 From: Tom Nguyen <7121553+tunggnu@users.noreply.github.com> Date: Thu, 28 Oct 2021 22:11:13 +0700 Subject: [PATCH 1234/1519] Add the missing square bracket for a route --- page_creation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/page_creation.rst b/page_creation.rst index cc00e592880..76b892c8455 100644 --- a/page_creation.rst +++ b/page_creation.rst @@ -133,7 +133,7 @@ You can now add your route directly *above* the controller: class LuckyController { - + #[Route('/lucky/number') + + #[Route('/lucky/number')] public function number() { // this looks exactly the same From 04ce795303a21d1681e450135d6f469ce8c6d4e3 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Fri, 29 Oct 2021 16:17:14 +0200 Subject: [PATCH 1235/1519] Document custom access decision managers --- components/security/authorization.rst | 90 +++++++++++++++++---------- security/voters.rst | 53 +++++++++++++++- 2 files changed, 109 insertions(+), 34 deletions(-) diff --git a/components/security/authorization.rst b/components/security/authorization.rst index ffc4edc278a..3effc3d0794 100644 --- a/components/security/authorization.rst +++ b/components/security/authorization.rst @@ -37,26 +37,8 @@ Access Decision Manager Since deciding whether or not a user is authorized to perform a certain action can be a complicated process, the standard :class:`Symfony\\Component\\Security\\Core\\Authorization\\AccessDecisionManager` itself depends on multiple voters, and makes a final verdict based on all -the votes (either positive, negative or neutral) it has received. It -recognizes several strategies: - -``affirmative`` (default) - grant access as soon as there is one voter granting access; - -``consensus`` - grant access if there are more voters granting access than there are denying; - -``unanimous`` - only grant access if none of the voters has denied access. If all voters - abstained from voting, the decision is based on the ``allow_if_all_abstain`` - config option (which defaults to ``false``). - -``priority`` - grants or denies access by the first voter that does not abstain; - - .. versionadded:: 5.1 - - The ``priority`` version strategy was introduced in Symfony 5.1. +the votes (either positive, negative or neutral) it has received and the +given strategy. Usage of the available options in detail:: @@ -65,27 +47,69 @@ Usage of the available options in detail:: // instances of Symfony\Component\Security\Core\Authorization\Voter\VoterInterface $voters = [...]; - // one of "affirmative", "consensus", "unanimous", "priority" + // instance of Symfony\Component\Security\Core\Authorization\Strategy\AccessDecisionStrategyInterface $strategy = ...; - // whether or not to grant access when all voters abstain - $allowIfAllAbstainDecisions = ...; - - // whether or not to grant access when there is no majority (applies only to the "consensus" strategy) - $allowIfEqualGrantedDeniedDecisions = ...; - - $accessDecisionManager = new AccessDecisionManager( - $voters, - $strategy, - $allowIfAllAbstainDecisions, - $allowIfEqualGrantedDeniedDecisions - ); + $accessDecisionManager = new AccessDecisionManager($voters, $strategy); .. seealso:: You can change the default strategy in the :ref:`configuration `. +Strategies +---------- + +.. versionadded:: 5.4 + + The strategy classes were introduced in Symfony 5.4. In earlier versions, the strategy was passed as a string. + +The following strategies are bundled with the component: + +``AffirmativeStrategy`` (default) + grant access as soon as there is one voter granting access; + +``ConsensusStrategy`` + grant access if there are more voters granting access than there are denying; + if there is a draw between votes, the decision is made based on the + ``$allowIfEqualGrantedDeniedDecisions`` constructor parameter which defaults to ``true``. + +``UnanimousStrategy`` + only grant access if none of the voters has denied access. + +``PriorityStrategy`` + grants or denies access by the first voter that does not abstain; + + .. versionadded:: 5.1 + + The "priority" version strategy was introduced in Symfony 5.1. + +If all voters abstained from voting, the decision is based on the ``$allowIfAllAbstainDecisions`` +constructor parameter which is supported by all of the built-in strategies and defaults to ``false``. + +If none of the built-in strategies seem to fit, a custom strategy may be provided. The strategy will +receive a stream of votes and may return as soon as it has seen enough votes to come to a conclusion. + +:: + + /** + * Always picks the third voter. + */ + class ThirdVoterStrategy implements AccessDecisionStrategyInterface + { + public function decide(\Traversable $results): bool + { + $votes = 0; + foreach ($results as $result) { + if (++$votes === 3) { + return $result === VoterInterface::ACCESS_GRANTED; + } + } + + return false; + } + } + Voters ------ diff --git a/security/voters.rst b/security/voters.rst index d860886f175..6b8d674adab 100644 --- a/security/voters.rst +++ b/security/voters.rst @@ -345,7 +345,58 @@ security configuration: Custom Access Decision Strategy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If none of the built-in strategies fits your use case, define the ``service`` +.. versionadded:: 5.4 + + The ``strategy_service`` option was introduced in Symfony 5.4. + +If none of the built-in strategies fits your use case, define the ``strategy_service`` +option to use a custom service (your service must implement the +:class:`Symfony\\Component\\Security\\Core\Authorization\\Strategy\\AccessDecisionStrategyInterface`): + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + access_decision_manager: + strategy_service: App\Security\MyCustomAccessDecisionStrategy + # ... + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use App\Security\MyCustomAccessDecisionStrategy; + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->accessDecisionManager() + ->strategyService(MyCustomAccessDecisionStrategy::class) + // ... + ; + }; + +Custom Access Decision Manager +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you need to provide an entirely custom access decision manager, define the ``service`` option to use a custom service as the Access Decision Manager (your service must implement the :class:`Symfony\\Component\\Security\\Core\\Authorization\\AccessDecisionManagerInterface`): From 1381c83b1b6e6a723a8052281caddbf3dae18935 Mon Sep 17 00:00:00 2001 From: Maxime Pinot Date: Fri, 29 Oct 2021 16:46:11 +0200 Subject: [PATCH 1236/1519] [HTTP Foundation] Improve sentence to avoid repetition --- components/http_foundation.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 3df8d5c9c94..a66baa7609d 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -252,8 +252,10 @@ Accessing the Session ~~~~~~~~~~~~~~~~~~~~~ If you have a session attached to the request, you can access it via the -:method:`Symfony\\Component\\HttpFoundation\\Request::getSession` method or the -:method:`Symfony\\Component\\HttpFoundation\\RequestStack::getSession` method; +:method:`Symfony\\Component\\HttpFoundation\\Request::getSession` method +from the :class:`Symfony\\Component\\HttpFoundation\\Request` class or the +:method:`Symfony\\Component\\HttpFoundation\\RequestStack::getSession` method +from the :class:`Symfony\\Component\\HttpFoundation\\RequestStack` class; the :method:`Symfony\\Component\\HttpFoundation\\Request::hasPreviousSession` method tells you if the request contains a session which was started in one of From cb8ba0067c22c628c8a2607b7ad9fcc4c2019d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Fri, 29 Oct 2021 18:29:18 +0200 Subject: [PATCH 1237/1519] Add documentation about CacheableVoterInterface --- security/voters.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/security/voters.rst b/security/voters.rst index d860886f175..aec93cff3a6 100644 --- a/security/voters.rst +++ b/security/voters.rst @@ -62,6 +62,18 @@ which makes creating a voter even easier:: .. _how-to-use-the-voter-in-a-controller: +.. tip:: + + Checking each voter several times can be time consumming for applications + that perform a lot of permission checks. However, when a voter implements + the :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\CacheableVoterInterface`, + the access decision manager, will remember the attribute and type of subject + supported by the voter, and will, next, only call the involved voters. + + .. versionadded:: 5.4 + + The ``CacheableVoterInterface`` interface was introduced in Symfony 5.4. + Setup: Checking for Access in a Controller ------------------------------------------ From 8df9ed2132612540f701166ca956ca50b28ce2c6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 29 Oct 2021 20:12:45 +0200 Subject: [PATCH 1238/1519] Minor tweak --- components/http_foundation.rst | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index a66baa7609d..6154119e715 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -252,12 +252,9 @@ Accessing the Session ~~~~~~~~~~~~~~~~~~~~~ If you have a session attached to the request, you can access it via the -:method:`Symfony\\Component\\HttpFoundation\\Request::getSession` method -from the :class:`Symfony\\Component\\HttpFoundation\\Request` class or the -:method:`Symfony\\Component\\HttpFoundation\\RequestStack::getSession` method -from the :class:`Symfony\\Component\\HttpFoundation\\RequestStack` class; -the -:method:`Symfony\\Component\\HttpFoundation\\Request::hasPreviousSession` +``getSession()`` method of the :class:`Symfony\\Component\\HttpFoundation\\Request` +or :class:`Symfony\\Component\\HttpFoundation\\RequestStack` class; +the :method:`Symfony\\Component\\HttpFoundation\\Request::hasPreviousSession` method tells you if the request contains a session which was started in one of the previous requests. From 8700a11c079dfb65a842bfc92be792e5aa06b737 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 30 Oct 2021 12:44:46 +0200 Subject: [PATCH 1239/1519] Remove options in new constraints too --- reference/constraints/CssColor.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/reference/constraints/CssColor.rst b/reference/constraints/CssColor.rst index 8f62ed3e531..dc216c7422c 100644 --- a/reference/constraints/CssColor.rst +++ b/reference/constraints/CssColor.rst @@ -10,10 +10,6 @@ casted to a string before being validated. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `formats`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\CssColor` Validator :class:`Symfony\\Component\\Validator\\Constraints\\CssColorValidator` ========== =================================================================== From bf1e1c73e32a90b62bb2a81e2be33d494d554bf5 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 30 Oct 2021 13:03:26 +0200 Subject: [PATCH 1240/1519] Minor tweaks --- security/voters.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/security/voters.rst b/security/voters.rst index d8457e066cd..87b5249e996 100644 --- a/security/voters.rst +++ b/security/voters.rst @@ -65,10 +65,10 @@ which makes creating a voter even easier:: .. tip:: Checking each voter several times can be time consumming for applications - that perform a lot of permission checks. However, when a voter implements - the :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\CacheableVoterInterface`, - the access decision manager, will remember the attribute and type of subject - supported by the voter, and will, next, only call the involved voters. + that perform a lot of permission checks. To improve performance in those cases, + you can make your voters implement the :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\CacheableVoterInterface`. + This allows the access decision manager to remember the attribute and type + of subject supported by the voter, to only call the needed voters each time. .. versionadded:: 5.4 From a92b139b65ab235b19fb01d2c7e6526444e07ef9 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 30 Oct 2021 13:03:56 +0200 Subject: [PATCH 1241/1519] Remove the versionadded directive --- security/voters.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/security/voters.rst b/security/voters.rst index 26e2c332234..71ccb8b2f7c 100644 --- a/security/voters.rst +++ b/security/voters.rst @@ -70,10 +70,6 @@ which makes creating a voter even easier:: This allows the access decision manager to remember the attribute and type of subject supported by the voter, to only call the needed voters each time. - .. versionadded:: 5.4 - - The ``CacheableVoterInterface`` interface was introduced in Symfony 5.4. - Setup: Checking for Access in a Controller ------------------------------------------ From 5d7687f208bc339aae3b943a6c2bd92babc0ee78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20B=C5=82oszyk?= Date: Sat, 30 Oct 2021 12:48:10 +0200 Subject: [PATCH 1242/1519] Parameter as connection value in doctrine tags --- doctrine/events.rst | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/doctrine/events.rst b/doctrine/events.rst index 3a964dc5ea3..282b91e47ad 100644 --- a/doctrine/events.rst +++ b/doctrine/events.rst @@ -171,7 +171,8 @@ with the ``doctrine.event_listener`` tag: priority: 500 # you can also restrict listeners to a specific Doctrine connection - connection: 'default' + # '%doctrine_default_connection%' = 'default' + connection: '%doctrine_default_connection%' .. code-block:: xml @@ -187,12 +188,13 @@ with the ``doctrine.event_listener`` tag: * 'priority': used when multiple subscribers or listeners are associated to the same event * (default priority = 0; higher numbers = listener is run earlier) * 'connection': restricts the listener to a specific Doctrine connection + * '%doctrine_default_connection%' = 'default' --> + connection="%doctrine_default_connection%"/> @@ -218,7 +220,8 @@ with the ``doctrine.event_listener`` tag: 'priority' => 500, # you can also restrict listeners to a specific Doctrine connection - 'connection' => 'default', + # '%doctrine_default_connection%' = 'default' + 'connection' => '%doctrine_default_connection%', ]) ; }; @@ -439,7 +442,8 @@ Doctrine connection to use) you must do that in the manual service configuration priority: 500 # you can also restrict listeners to a specific Doctrine connection - connection: 'default' + # '%doctrine_default_connection%' = 'default' + connection: '%doctrine_default_connection%' .. code-block:: xml @@ -454,9 +458,10 @@ Doctrine connection to use) you must do that in the manual service configuration * 'priority': used when multiple subscribers or listeners are associated to the same event * (default priority = 0; higher numbers = listener is run earlier) * 'connection': restricts the listener to a specific Doctrine connection + * '%doctrine_default_connection%' = 'default' --> - + @@ -478,7 +483,8 @@ Doctrine connection to use) you must do that in the manual service configuration 'priority' => 500, // you can also restrict listeners to a specific Doctrine connection - 'connection' => 'default', + # '%doctrine_default_connection%' = 'default' + 'connection' => '%doctrine_default_connection%', ]) ; }; @@ -487,6 +493,10 @@ Doctrine connection to use) you must do that in the manual service configuration Subscriber priority was introduced in Symfony 5.3. +.. versionadded:: 5.4 + + Parameter as connection value was introduced in Symfony 5.4. + .. tip:: Symfony loads (and instantiates) Doctrine subscribers whenever the From 233beab84c781ea1a167832e03b3e7ccb888f881 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 30 Oct 2021 15:56:47 +0200 Subject: [PATCH 1243/1519] Minor tweak --- console/style.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/console/style.rst b/console/style.rst index 5dc5f24fca8..33f1ff59cc5 100644 --- a/console/style.rst +++ b/console/style.rst @@ -167,7 +167,8 @@ Content Methods :method:`Symfony\\Component\\Console\\Style\\SymfonyStyle::createTable` Creates an instance of :class:`Symfony\\Component\\Console\\Helper\\Table` - styled according to the Symfony Style Guide. + styled according to the Symfony Style Guide, which allows you to use + features such as appending rows dynamically. .. versionadded:: 5.4 From 0ae2afaa9862ca5f60bc0e8e35ebb91fad02afa1 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 30 Oct 2021 15:58:47 +0200 Subject: [PATCH 1244/1519] Remove the versionadded directives --- console/style.rst | 8 -------- 1 file changed, 8 deletions(-) diff --git a/console/style.rst b/console/style.rst index 34f32ac8ecc..b175a4f4cc7 100644 --- a/console/style.rst +++ b/console/style.rst @@ -170,10 +170,6 @@ Content Methods styled according to the Symfony Style Guide, which allows you to use features such as appending rows dynamically. -.. versionadded:: 5.4 - - The ``createTable()`` method was introduced in Symfony 5.4. - :method:`Symfony\\Component\\Console\\Style\\SymfonyStyle::newLine` It displays a blank line in the command output. Although it may seem useful, most of the times you won't need it at all. The reason is that every helper @@ -262,10 +258,6 @@ Progress Bar Methods // ... do some work } -.. versionadded:: 5.4 - - The ``progressIterate`` method was introduced in Symfony 5.4. - :method:`Symfony\\Component\\Console\\Style\\SymfonyStyle::createProgressBar` Creates an instance of :class:`Symfony\\Component\\Console\\Helper\\ProgressBar` styled according to the Symfony Style Guide. From c5420cf9826f7190fe0d639cb1ef4f5cf4de3345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFck=20Piera?= Date: Sun, 31 Oct 2021 22:35:50 +0100 Subject: [PATCH 1245/1519] Fix Response HTTP constant --- security.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security.rst b/security.rst index 8d55515b692..86d4e9a6fa0 100644 --- a/security.rst +++ b/security.rst @@ -1073,7 +1073,7 @@ token (or whatever you need to return) and return the JSON response: + if (null === $user) { + return $this->json([ + 'message' => 'missing credentials', - + ], Response::HTTP_UNAUTHENTICATED); + + ], Response::HTTP_UNAUTHORIZED); + } + + $token = ...; // somehow create an API token for $user From ea6a3e2d546fcbc31063f81b64a9b60ef8925c6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Barto=C5=A1?= Date: Sun, 31 Oct 2021 22:42:06 +0100 Subject: [PATCH 1246/1519] Fix example url --- http_client.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http_client.rst b/http_client.rst index 8efbd4b3a41..295fe360f6d 100644 --- a/http_client.rst +++ b/http_client.rst @@ -1646,7 +1646,7 @@ the response, replace the current request by another one or change the chunk passthru itself. Checking the test cases implemented in -:class:`Symfony\\Component\\HttpClient\\Response\\Tests\\AsyncDecoratorTraitTest` +:class:`Symfony\\Component\\HttpClient\\Tests\\AsyncDecoratorTraitTest` might be a good start to get various working examples for a better understanding. Here are the use cases that it simulates: From ce9e9956b438f29e468524a86f83f30cc9de28bc Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 2 Nov 2021 12:07:34 +0100 Subject: [PATCH 1247/1519] Remove the repeated options in Color form type --- reference/forms/types/color.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/reference/forms/types/color.rst b/reference/forms/types/color.rst index e31747d4457..b9119039115 100644 --- a/reference/forms/types/color.rst +++ b/reference/forms/types/color.rst @@ -17,10 +17,6 @@ element. +---------------------------+---------------------------------------------------------------------+ | Rendered as | ``input`` ``color`` field (a text box) | +---------------------------+---------------------------------------------------------------------+ -| Options | - `html5`_ | -+---------------------------+---------------------------------------------------------------------+ -| Overridden options | - `invalid_message`_ | -+---------------------------+---------------------------------------------------------------------+ | Default invalid message | Please select a valid color. | +---------------------------+---------------------------------------------------------------------+ | Legacy invalid message | The value {{ value }} is not valid. | From 544bcf987a34ee7a3a7c9e76af8ad1900e6ddf58 Mon Sep 17 00:00:00 2001 From: Julien Falque Date: Tue, 2 Nov 2021 17:59:25 +0100 Subject: [PATCH 1248/1519] [Finder] Add note about .gitignore rules precedence --- components/finder.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/finder.rst b/components/finder.rst index eac3e20d8da..c0cecfa0032 100644 --- a/components/finder.rst +++ b/components/finder.rst @@ -148,6 +148,14 @@ can reuse those rules to exclude files and directories from the results with the // excludes files/directories matching the .gitignore patterns $finder->ignoreVCSIgnored(true); +Rules from higher levels will be overridden by those in lower levels. + +.. note:: + + Only ``.gitignore`` files from search directories and their descendants are + read. Files from parent directories are ignored. To be consistent with Git + behavior, you should explicitly search from the Git repository root. + .. versionadded:: 5.4 ``.gitignore`` files recursive support was introduced in Symfony 5.4. From 249c86dbf22df38bbbf9b9c9c3a1d47edfec8563 Mon Sep 17 00:00:00 2001 From: Bruno Baguette <1922257+Levure@users.noreply.github.com> Date: Tue, 2 Nov 2021 21:52:33 +0100 Subject: [PATCH 1249/1519] =?UTF-8?q?Typo=20fix=20:=20distrupting=20?= =?UTF-8?q?=E2=9E=A4=20disrupting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- security.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security.rst b/security.rst index 86d4e9a6fa0..6720fb9a6e1 100644 --- a/security.rst +++ b/security.rst @@ -1476,7 +1476,7 @@ By default, login attempts are limited on ``max_attempts`` (default: 5) failed requests for ``IP address + username`` and ``5 * max_attempts`` failed requests for ``IP address``. The second limit protects against an attacker using multiple usernames from bypassing the first limit, without -distrupting normal users on big networks (such as offices). +disrupting normal users on big networks (such as offices). .. tip:: From 786989297118424ad47bc271c6e783859415be2d Mon Sep 17 00:00:00 2001 From: Bruno Baguette <1922257+Levure@users.noreply.github.com> Date: Tue, 2 Nov 2021 22:02:00 +0100 Subject: [PATCH 1250/1519] =?UTF-8?q?Typo=20fixes=20:=20Remove=20extra=20"?= =?UTF-8?q?s"=20+=20througth=20=E2=9E=A4=20through?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- session.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/session.rst b/session.rst index 70e62b62263..de422ca6792 100644 --- a/session.rst +++ b/session.rst @@ -131,7 +131,7 @@ Check out the Symfony config reference to learn more about the other available Basic Usage ----------- -The sessions is available througth the Request and the RequestStack. +The session is available through the Request and the RequestStack. Symfony provides a request_stack service that is injected in your services and controllers if you type-hint an argument with :class:`Symfony\\Component\\HttpFoundation\\RequestStack`:: From 1b548185685bdd8a5298e7dfa7344795a9a87717 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 5 Nov 2021 16:05:07 +0100 Subject: [PATCH 1251/1519] Fix a minor typo --- components/console/helpers/cursor.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/console/helpers/cursor.rst b/components/console/helpers/cursor.rst index da450925fc3..2485498fcab 100644 --- a/components/console/helpers/cursor.rst +++ b/components/console/helpers/cursor.rst @@ -53,7 +53,7 @@ Using the cursor Moving the cursor ................. -There are fews methods to control moving the command cursor:: +There are few methods to control moving the command cursor:: // moves the cursor 1 line up from its current position $cursor->moveUp(); From 05437d3657016f9af32b8c39c7552aa8fec47f02 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 5 Nov 2021 17:13:50 +0100 Subject: [PATCH 1252/1519] Reword --- doctrine/events.rst | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/doctrine/events.rst b/doctrine/events.rst index 282b91e47ad..4e5581c14de 100644 --- a/doctrine/events.rst +++ b/doctrine/events.rst @@ -171,8 +171,7 @@ with the ``doctrine.event_listener`` tag: priority: 500 # you can also restrict listeners to a specific Doctrine connection - # '%doctrine_default_connection%' = 'default' - connection: '%doctrine_default_connection%' + connection: 'default' .. code-block:: xml @@ -188,13 +187,12 @@ with the ``doctrine.event_listener`` tag: * 'priority': used when multiple subscribers or listeners are associated to the same event * (default priority = 0; higher numbers = listener is run earlier) * 'connection': restricts the listener to a specific Doctrine connection - * '%doctrine_default_connection%' = 'default' --> + connection="default"/> @@ -220,8 +218,7 @@ with the ``doctrine.event_listener`` tag: 'priority' => 500, # you can also restrict listeners to a specific Doctrine connection - # '%doctrine_default_connection%' = 'default' - 'connection' => '%doctrine_default_connection%', + 'connection' => 'default', ]) ; }; @@ -232,6 +229,16 @@ with the ``doctrine.event_listener`` tag: Doctrine event is actually fired; whereas Doctrine subscribers are always loaded (and instantiated) by Symfony, making them less performant. +.. tip:: + + The value of the ``connection`` option can also be a + :ref:`configuration parameter `. + + .. versionadded:: 5.4 + + The feature to allow using configuration parameters in ``connection`` + was introduced in Symfony 5.4. + Doctrine Entity Listeners ------------------------- @@ -442,8 +449,7 @@ Doctrine connection to use) you must do that in the manual service configuration priority: 500 # you can also restrict listeners to a specific Doctrine connection - # '%doctrine_default_connection%' = 'default' - connection: '%doctrine_default_connection%' + connection: 'default' .. code-block:: xml @@ -458,10 +464,9 @@ Doctrine connection to use) you must do that in the manual service configuration * 'priority': used when multiple subscribers or listeners are associated to the same event * (default priority = 0; higher numbers = listener is run earlier) * 'connection': restricts the listener to a specific Doctrine connection - * '%doctrine_default_connection%' = 'default' --> - + @@ -483,8 +488,7 @@ Doctrine connection to use) you must do that in the manual service configuration 'priority' => 500, // you can also restrict listeners to a specific Doctrine connection - # '%doctrine_default_connection%' = 'default' - 'connection' => '%doctrine_default_connection%', + 'connection' => 'default', ]) ; }; @@ -493,10 +497,6 @@ Doctrine connection to use) you must do that in the manual service configuration Subscriber priority was introduced in Symfony 5.3. -.. versionadded:: 5.4 - - Parameter as connection value was introduced in Symfony 5.4. - .. tip:: Symfony loads (and instantiates) Doctrine subscribers whenever the From dea59657423d709f51a2c2212ffcd9eca0f9fe75 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 5 Nov 2021 17:14:17 +0100 Subject: [PATCH 1253/1519] Remove the versionadded directive --- doctrine/events.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/doctrine/events.rst b/doctrine/events.rst index 5c7401c53f6..dc3df4b6e20 100644 --- a/doctrine/events.rst +++ b/doctrine/events.rst @@ -234,11 +234,6 @@ with the ``doctrine.event_listener`` tag: The value of the ``connection`` option can also be a :ref:`configuration parameter `. - .. versionadded:: 5.4 - - The feature to allow using configuration parameters in ``connection`` - was introduced in Symfony 5.4. - Doctrine Entity Listeners ------------------------- From f32ee434c78f0210b1630aecf31b2c89a80f0074 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 6 Nov 2021 16:30:26 +0100 Subject: [PATCH 1254/1519] Minor tweaks --- reference/constraints/Cidr.rst | 20 ++++++++++---------- reference/constraints/map.rst.inc | 1 + 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/reference/constraints/Cidr.rst b/reference/constraints/Cidr.rst index 8f415162437..658a9910b7c 100644 --- a/reference/constraints/Cidr.rst +++ b/reference/constraints/Cidr.rst @@ -1,18 +1,17 @@ Cidr -== +==== -Validates that a value is a valid CIDR notation. By default, this will validate -the CIDR's IP and netmask both for version 4 and version 6, with the option of allowing -only one type of IP version to be valid. It also supports a minimum and maximum range -constraint in which the value of the netmask is valid. +.. versionadded:: 5.4 + + The ``Cidr`` constraint was introduced in Symfony 5.4. + +Validates that a value is a valid `CIDR`_ (Classless Inter-Domain Routing) notation. +By default, this will validate the CIDR's IP and netmask both for version 4 and 6, +with the option of allowing only one type of IP version to be valid. It also supports +a minimum and maximum range constraint in which the value of the netmask is valid. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `netmaskRangeViolationMessage`_ - - `payload`_ - - `version`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Cidr` Validator :class:`Symfony\\Component\\Validator\\Constraints\\CidrValidator` ========== =================================================================== @@ -153,3 +152,4 @@ of a variety of different values: ``all`` Validates all CIDR formats +.. _`CIDR`: https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index d6b974cefb3..9f8eb4b8c3f 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -22,6 +22,7 @@ String Constraints * :doc:`Regex ` * :doc:`Hostname ` * :doc:`Ip ` +* :doc:`Cidr ` * :doc:`Json ` * :doc:`Uuid ` * :doc:`Ulid ` From 1fb1f9919b36cc1b78ff9ebea6378e313b905147 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 6 Nov 2021 16:42:26 +0100 Subject: [PATCH 1255/1519] Remove the versionadded directive --- reference/constraints/Cidr.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/reference/constraints/Cidr.rst b/reference/constraints/Cidr.rst index 658a9910b7c..3bc3dcf3dec 100644 --- a/reference/constraints/Cidr.rst +++ b/reference/constraints/Cidr.rst @@ -1,10 +1,6 @@ Cidr ==== -.. versionadded:: 5.4 - - The ``Cidr`` constraint was introduced in Symfony 5.4. - Validates that a value is a valid `CIDR`_ (Classless Inter-Domain Routing) notation. By default, this will validate the CIDR's IP and netmask both for version 4 and 6, with the option of allowing only one type of IP version to be valid. It also supports From d92e0f8c566ee62840caf12b0a6eb5cbe61b5941 Mon Sep 17 00:00:00 2001 From: BahmanMD Date: Sun, 7 Nov 2021 10:01:01 +0330 Subject: [PATCH 1256/1519] Update setup.rst for V5.4 Creating the correct command and fixing the installation problem of version 5.4 --- setup.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.rst b/setup.rst index d766fbfc5dd..122294b2e49 100644 --- a/setup.rst +++ b/setup.rst @@ -54,10 +54,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_name --version=next --full + $ symfony new my_project_name --version="5.4.x@dev" --full # run this if you are building a microservice, console application or API - $ symfony new my_project_name --version=next + $ symfony new my_project_name --version="5.4.x@dev" The only difference between these two commands is the number of packages installed by default. The ``--full`` option installs all the packages that you From 3fc3c5f39a586e04caf46fbb31fb691783a55db1 Mon Sep 17 00:00:00 2001 From: Zairig Imad Date: Sun, 7 Nov 2021 15:55:23 +0100 Subject: [PATCH 1257/1519] Add Push Channel with Integration Expo & OneSignal --- notifier.rst | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/notifier.rst b/notifier.rst index 8a56a0dc6ed..9a8d306ddca 100644 --- a/notifier.rst +++ b/notifier.rst @@ -21,8 +21,8 @@ Get the Notifier installed using: $ composer require symfony/notifier -Channels: Chatters, Texters, Email and Browser ----------------------------------------------- +Channels: Chatters, Texters, Email, Browser and Push +---------------------------------------------------- The notifier component can send notifications to different channels. Each channel can integrate with different providers (e.g. Slack or Twilio SMS) @@ -36,6 +36,7 @@ The notifier component supports the following channels: services like Slack and Telegram; * :ref:`Email channel ` integrates the :doc:`Symfony Mailer `; * Browser channel uses :ref:`flash messages `. +* Push Channel sends notifications to phones via push notifications. .. tip:: @@ -317,6 +318,75 @@ notification emails: ; }; +Push Channel +~~~~~~~~~~~~ + +The push channel is used to send notifications to users by using +:class:`Symfony\\Component\\Notifier\\Texter` classes. Symfony provides +integration with these push services: + +============== ==================================== ================================================================================= +Service Package DSN +============== ==================================== ================================================================================= +Firebase ``symfony/firebase-notifier`` ``firebase://USERNAME:PASSWORD@default`` +Expo ``symfony/expo-notifier`` ``expo://Token@default`` +OneSignal ``symfony/one-signal-notifier`` ``onesignal://APP_ID:API_KEY@default?defaultRecipientId=DEFAULT_RECIPIENT_ID''`` +============== ==================================== ================================================================================= + +.. versionadded:: 5.4 + + The Expo and OneSignal integrations were introduced in Symfony 5.4. + +To enable a texter, add the correct DSN in your ``.env`` file and +configure the ``texter_transports``: + +.. code-block:: bash + + # .env + EXPO_DSN=expo://TOKEN@default + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/notifier.yaml + framework: + notifier: + texter_transports: + expo: '%env(EXPO_DSN)%' + + .. code-block:: xml + + + + + + + + + %env(EXPO_DSN)% + + + + + + .. code-block:: php + + // config/packages/notifier.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->notifier() + ->texterTransport('expo', '%env(EXPO_DSN)%') + ; + }; + Configure to use Failover or Round-Robin Transports ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 3976f357240458a9ebc59de44c0ccfd0cfa7dfa1 Mon Sep 17 00:00:00 2001 From: BahmanMD Date: Sun, 7 Nov 2021 10:04:56 +0330 Subject: [PATCH 1258/1519] Update setup.rst for V6.0 Creating the correct command and fixing the installation problem of version 6.0 --- setup.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.rst b/setup.rst index 5d1ac071551..f6e35a764f5 100644 --- a/setup.rst +++ b/setup.rst @@ -54,10 +54,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_name --version="5.4.x@dev" --full + $ symfony new my_project_name --version="6.0.x@dev" --full # run this if you are building a microservice, console application or API - $ symfony new my_project_name --version="5.4.x@dev" + $ symfony new my_project_name --version="6.0.x@dev" The only difference between these two commands is the number of packages installed by default. The ``--full`` option installs all the packages that you From 63eb9889bea62e624aa6391dd64100bb60afa820 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 8 Nov 2021 13:27:58 +0100 Subject: [PATCH 1259/1519] Re-add a refernece to keep previous links --- notifier.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/notifier.rst b/notifier.rst index 9a8d306ddca..c0aa0ac125f 100644 --- a/notifier.rst +++ b/notifier.rst @@ -21,6 +21,8 @@ Get the Notifier installed using: $ composer require symfony/notifier +.. _channels-chatters-texters-email-and-browser: + Channels: Chatters, Texters, Email, Browser and Push ---------------------------------------------------- From d8a01786e2992fb7fd231f8fb19e40eb040c6e37 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 8 Nov 2021 13:28:40 +0100 Subject: [PATCH 1260/1519] Remove a versionadded directive --- notifier.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/notifier.rst b/notifier.rst index 7af92f7f797..1b301c6fc35 100644 --- a/notifier.rst +++ b/notifier.rst @@ -294,10 +294,6 @@ Expo ``symfony/expo-notifier`` ``expo://Token@default`` OneSignal ``symfony/one-signal-notifier`` ``onesignal://APP_ID:API_KEY@default?defaultRecipientId=DEFAULT_RECIPIENT_ID''`` ============== ==================================== ================================================================================= -.. versionadded:: 5.4 - - The Expo and OneSignal integrations were introduced in Symfony 5.4. - To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: From f9f61db5637caa1b9eb145171b6dc96403c64f30 Mon Sep 17 00:00:00 2001 From: Zairig Imad Date: Mon, 8 Nov 2021 15:44:14 +0100 Subject: [PATCH 1261/1519] Update testing.rst --- testing.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/testing.rst b/testing.rst index 2f058ad8a5a..ca8cde0825f 100644 --- a/testing.rst +++ b/testing.rst @@ -899,10 +899,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 = '')`` + Asserts the response is unprocessable (HTTP status is 422) .. versionadded:: 5.3 The ``assertResponseFormatSame()`` method was introduced in Symfony 5.3. + +.. versionadded:: 5.4 + + The ``assertResponseIsUnprocessable()`` method was introduced in Symfony 5.4. Request Assertions .................. From 263bdd7f821a1208c70f1b64a48c0957516595f0 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 8 Nov 2021 16:19:02 +0100 Subject: [PATCH 1262/1519] [Notifier] Minor tweak --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index c0aa0ac125f..e3e96f847c3 100644 --- a/notifier.rst +++ b/notifier.rst @@ -38,7 +38,7 @@ The notifier component supports the following channels: services like Slack and Telegram; * :ref:`Email channel ` integrates the :doc:`Symfony Mailer `; * Browser channel uses :ref:`flash messages `. -* Push Channel sends notifications to phones via push notifications. +* Push Channel sends notifications to phones and browsers via push notifications. .. tip:: From 78e6f65a7910ece4d9490f55212ba5004df2eb3e Mon Sep 17 00:00:00 2001 From: Zairig Imad Date: Mon, 8 Nov 2021 15:24:00 +0100 Subject: [PATCH 1263/1519] Update filesystem.rst --- components/filesystem.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/filesystem.rst b/components/filesystem.rst index 447c95f7ff5..2a1843ead2a 100644 --- a/components/filesystem.rst +++ b/components/filesystem.rst @@ -311,10 +311,16 @@ The ``file.txt`` file contains ``Hello World`` now. contents at the end of some file:: $filesystem->appendToFile('logs.txt', 'Email sent to user@example.com'); + // with the third argument set to true you can lock the file when writing to it. + $filesystem->appendToFile('logs.txt', 'Email sent to user@example.com', true); If either the file or its containing directory doesn't exist, this method creates them before appending the contents. +.. versionadded:: 5.4 + + The third argument ``$lock`` was introduced in Symfony 5.4. + Error Handling -------------- From 7dd29957a7413194f318cbcf92ecf55ea033d40c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 8 Nov 2021 16:44:41 +0100 Subject: [PATCH 1264/1519] Minor tweaks --- components/filesystem.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/filesystem.rst b/components/filesystem.rst index 2a1843ead2a..821a5f801fd 100644 --- a/components/filesystem.rst +++ b/components/filesystem.rst @@ -311,7 +311,7 @@ The ``file.txt`` file contains ``Hello World`` now. contents at the end of some file:: $filesystem->appendToFile('logs.txt', 'Email sent to user@example.com'); - // with the third argument set to true you can lock the file when writing to it. + // the third argument tells whether the file should be locked when writing to it $filesystem->appendToFile('logs.txt', 'Email sent to user@example.com', true); If either the file or its containing directory doesn't exist, this method @@ -319,7 +319,7 @@ creates them before appending the contents. .. versionadded:: 5.4 - The third argument ``$lock`` was introduced in Symfony 5.4. + The third argument of ``appendToFile()`` was introduced in Symfony 5.4. Error Handling -------------- From ab5b1c236d84a94f80902c1633d856a9712d22a9 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 8 Nov 2021 16:47:00 +0100 Subject: [PATCH 1265/1519] Remove a versionadded directive --- components/filesystem.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/components/filesystem.rst b/components/filesystem.rst index aed1976b3b8..d26ff7e83d9 100644 --- a/components/filesystem.rst +++ b/components/filesystem.rst @@ -313,10 +313,6 @@ contents at the end of some file:: If either the file or its containing directory doesn't exist, this method creates them before appending the contents. -.. versionadded:: 5.4 - - The third argument of ``appendToFile()`` was introduced in Symfony 5.4. - Error Handling -------------- From 4b6e7d26280a12d893438b68710f21d6b73137b0 Mon Sep 17 00:00:00 2001 From: Samuel NELA Date: Mon, 8 Nov 2021 20:10:50 +0100 Subject: [PATCH 1266/1519] Fix method for the user password hasher service --- security/passwords.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/passwords.rst b/security/passwords.rst index 25c24354568..521be799277 100644 --- a/security/passwords.rst +++ b/security/passwords.rst @@ -230,7 +230,7 @@ After configuring the correct algorithm, you can use the $plaintextPassword = ...; // hash the password (based on the security.yaml config for the $user class) - $hashedPassword = $passwordHasher->hash( + $hashedPassword = $passwordHasher->hashPassword( $user, $plaintextPassword ); @@ -260,7 +260,7 @@ After configuring the correct algorithm, you can use the $plaintextPassword = ...; // hash the password (based on the password hasher factory config for the $user class) - $hashedPassword = $passwordHasher->hash( + $hashedPassword = $passwordHasher->hashPassword( $user, $plaintextPassword ); From 3e4c7d78d0287346257fa2884afec189ce43d215 Mon Sep 17 00:00:00 2001 From: gndk <25748293+gndk@users.noreply.github.com> Date: Mon, 8 Nov 2021 20:12:45 +0100 Subject: [PATCH 1267/1519] Update type declaration for Doctrine DBAL Connection In doctrine/dbal 3.0.0 Doctrine\DBAL\Driver\Connection has become an internal interface and the wrapper-level Doctrine\DBAL\Connection should be used. --- doctrine/dbal.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doctrine/dbal.rst b/doctrine/dbal.rst index e330fd85732..8459b597faa 100644 --- a/doctrine/dbal.rst +++ b/doctrine/dbal.rst @@ -47,7 +47,7 @@ object:: // src/Controller/UserController.php namespace App\Controller; - use Doctrine\DBAL\Driver\Connection; + use Doctrine\DBAL\Connection; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; From 9963782f865f57677971d90f9fc78a19f5122935 Mon Sep 17 00:00:00 2001 From: chapterjason Date: Fri, 12 Nov 2021 16:14:05 +0100 Subject: [PATCH 1268/1519] Fix confusing character in class name --- form/bootstrap5.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/form/bootstrap5.rst b/form/bootstrap5.rst index 779820b9861..2e82bda0cab 100644 --- a/form/bootstrap5.rst +++ b/form/bootstrap5.rst @@ -114,7 +114,7 @@ Form type or ``ChoiceType`` configuration) to the label class. $builder ->add('myCheckbox', CheckboxType::class, [ 'label_attr' => [ - 'class' => '`checkbox-inline', + 'class' => 'checkbox-inline', ], ]) ->add('myRadio', RadioType::class, [ From 6f70302e93008c907dce6bc8c5a0ca1f0eee5382 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 12 Nov 2021 16:23:04 +0100 Subject: [PATCH 1269/1519] [Validator] Cidr constraint tweaks --- reference/constraints/Cidr.rst | 45 +++++++++++++++------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/reference/constraints/Cidr.rst b/reference/constraints/Cidr.rst index 658a9910b7c..bb51a4826be 100644 --- a/reference/constraints/Cidr.rst +++ b/reference/constraints/Cidr.rst @@ -23,12 +23,12 @@ Basic Usage .. code-block:: php-annotations - // src/Entity/Author.php + // src/Entity/NetworkSettings.php namespace App\Entity; use Symfony\Component\Validator\Constraints as Assert; - class Author + class NetworkSettings { /** * @Assert\Cidr @@ -38,12 +38,12 @@ Basic Usage .. code-block:: php-attributes - // src/Entity/Author.php + // src/Entity/NetworkSettings.php namespace App\Entity; use Symfony\Component\Validator\Constraints as Assert; - class Author + class NetworkSettings { #[Assert\Cidr] protected $cidrNotation; @@ -52,7 +52,7 @@ Basic Usage .. code-block:: yaml # config/validator/validation.yaml - App\Entity\Author: + App\Entity\NetworkSettings: properties: cidrNotation: - Cidr: ~ @@ -65,7 +65,7 @@ Basic Usage xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> - + @@ -74,13 +74,13 @@ Basic Usage .. code-block:: php - // src/Entity/Author.php + // src/Entity/NetworkSettings.php namespace App\Entity; use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Mapping\ClassMetadata; - class Author + class NetworkSettings { public static function loadValidatorMetadata(ClassMetadata $metadata) { @@ -103,34 +103,34 @@ Options This message is shown if the string is not a valid CIDR notation. ``netmaskMin`` -~~~~~~~~~~~ +~~~~~~~~~~~~~~ **type**: ``integer`` **default**: ``0`` It's a constraint for the lowest value a valid netmask may have. ``netmaskMax`` -~~~~~~~~~~~ +~~~~~~~~~~~~~~ -**type**: ``string`` **default**: ``32 for IPv4 or 128 for IPv6`` +**type**: ``string`` **default**: ``32`` for IPv4 or ``128`` for IPv6 It's a constraint for the biggest value a valid netmask may have. ``netmaskRangeViolationMessage`` -~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``The value of the netmask should be between {{ min }} and {{ max }}.`` -This message is shown if the value of the CIDR's netmask is bigger then the value of the `max_` or lower than -the value of the `min_`. +This message is shown if the value of the CIDR's netmask is bigger than the +``netmaskMax`` value or lower than the ``netmaskMin`` value. You can use the following parameters in this message: =============== ============================================================== Parameter Description =============== ============================================================== -``{{ min }}`` The minimum value a CIDR netmask may have -``{{ max }}`` The maximum value a CIDR netmask may have +``{{ min }}`` The minimum value a CIDR netmask may have +``{{ max }}`` The maximum value a CIDR netmask may have =============== ============================================================== .. include:: /reference/constraints/_payload-option.rst.inc @@ -141,15 +141,10 @@ Parameter Description **type**: ``string`` **default**: ``all`` This determines exactly *how* the CIDR notation is validated and can take one -of a variety of different values: - -**All ranges** +of these values: -``4`` - Validates for CIDR notations that have an IPv4. -``6`` - Validates for CIDR notations that have an IPv6. -``all`` - Validates all CIDR formats +* ``4``: validates for CIDR notations that have an IPv4; +* ``6``: validates for CIDR notations that have an IPv6; +* ``all``: validates all CIDR formats. .. _`CIDR`: https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing From 89f956493bc609a6da24ba03b3f15fd9f9669c6b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 12 Nov 2021 16:10:19 +0100 Subject: [PATCH 1270/1519] [Testing] Add comments to the work-in-progress section --- .doctor-rst.yaml | 1 + testing.rst | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.doctor-rst.yaml b/.doctor-rst.yaml index b1cd5645be8..86741f56f86 100644 --- a/.doctor-rst.yaml +++ b/.doctor-rst.yaml @@ -106,3 +106,4 @@ whitelist: - 'End to End Tests (E2E)' - '.. code-block:: php' - '.. _`a feature to test applications using Mercure`: https://github.com/symfony/panther#creating-isolated-browsers-to-test-apps-using-mercure-or-websocket' + - '.. End to End Tests (E2E)' diff --git a/testing.rst b/testing.rst index 1fe8e409a69..363abb9b98b 100644 --- a/testing.rst +++ b/testing.rst @@ -992,12 +992,11 @@ Mailer Assertions `` into ``jane@example.com``. .. TODO - End to End Tests (E2E) - ---------------------- - - * panther - * testing javascript - * UX or form collections as example? +.. End to End Tests (E2E) +.. ---------------------- +.. * panther +.. * testing javascript +.. * UX or form collections as example? Learn more ---------- From 33c5b6be42f29675f5cbc5f0ccfc8b5df3cd89de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maikel=20Ortega=20Hern=C3=A1ndez?= Date: Mon, 15 Nov 2021 12:53:39 -0500 Subject: [PATCH 1271/1519] Update workflow docs for $context in GuardEvent Make the doc reflect the current behavior for $context on GuardEvent to avoid confusing use of the events $context --- workflow.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow.rst b/workflow.rst index 1d70f38b0d6..2d3fdb9352c 100644 --- a/workflow.rst +++ b/workflow.rst @@ -388,7 +388,7 @@ order: .. versionadded:: 5.2 - In Symfony 5.2, the context is accessible in all events:: + In Symfony 5.2, the context is customizable for all events except for workflow.guard events, which will not receive the custom $context:: // $context must be an array $context = ['context_key' => 'context_value']; From 57edf91e2d42a4280f243f0050449a5dfa0bde01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Isaert?= Date: Tue, 16 Nov 2021 12:30:09 +0100 Subject: [PATCH 1272/1519] [Security] Add example with PHP attributes for login link --- security/login_link.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/security/login_link.rst b/security/login_link.rst index e5680ea5de3..86406f9b316 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -108,6 +108,23 @@ intercept requests to this route: throw new \LogicException('This code should never be reached'); } } + + .. code-block:: php-attributes + + // src/Controller/SecurityController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class SecurityController extends AbstractController + { + #[Route('/login_check', name: 'login_check')] + public function check() + { + throw new \LogicException('This code should never be reached'); + } + } .. code-block:: yaml From 29a024acb0bf43e920e28aa080ff141123105fbb Mon Sep 17 00:00:00 2001 From: Harry van der Valk Date: Tue, 16 Nov 2021 17:06:38 +0100 Subject: [PATCH 1273/1519] Change $requestStack to $this->requestStack Within the __invoke() method a call was made to $requestStack. This update will use the private $requestStack property as defined in the SessionRequestProcessor class. --- logging/processors.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logging/processors.rst b/logging/processors.rst index 3c4faacda5f..fbc7d14c151 100644 --- a/logging/processors.rst +++ b/logging/processors.rst @@ -35,7 +35,7 @@ using a processor:: public function __invoke(array $record) { try { - $session = $requestStack->getSession(); + $session = $this->requestStack->getSession(); } catch (SessionNotFoundException $e) { return; } From 9931fd6bbd56a8a7a5ed4b32557b2efb3d9855fc Mon Sep 17 00:00:00 2001 From: BahmanMD Date: Wed, 17 Nov 2021 00:19:49 +0330 Subject: [PATCH 1274/1519] Update doctrine.rst --- doctrine.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doctrine.rst b/doctrine.rst index 97d4fa79c86..02260346d57 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -233,9 +233,11 @@ already installed: If everything worked, you should see something like this: +.. code-block:: text + SUCCESS! - Next: Review the new migration "migrations/Version20180207231217.php" + Next: Review the new migration "migrations/Version20211116204726.php" Then: Run the migration with php bin/console doctrine:migrations:migrate If you open this file, it contains the SQL needed to update your database! To run From c4fe71f03557c8c847557f569337bfc3dd6db729 Mon Sep 17 00:00:00 2001 From: Schultheisz Norbert Date: Thu, 21 Oct 2021 10:51:52 +0200 Subject: [PATCH 1275/1519] [Messenger] Redis Sentinel support --- messenger.rst | 78 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/messenger.rst b/messenger.rst index cbbd7e6b31f..0e3b8f51b0d 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1441,38 +1441,47 @@ A number of options can be configured via the DSN or via the ``options`` key under the transport in ``messenger.yaml``: -=================== ===================================== ================================= -Option Description Default -=================== ===================================== ================================= -stream The Redis stream name messages -group The Redis consumer group name symfony -consumer Consumer name used in Redis consumer -auto_setup Create the Redis group automatically? true -auth The Redis password -delete_after_ack If ``true``, messages are deleted false - automatically after processing them -delete_after_reject If ``true``, messages are deleted true - automatically if they are rejected -lazy Connect only when a connection is false - really needed -serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` - in Redis (the - ``Redis::OPT_SERIALIZER`` option) -stream_max_entries The maximum number of entries which ``0`` (which means "no trimming") - the stream will be trimmed to. Set - it to a large enough number to - avoid losing pending messages -tls Enable TLS support for the connection false -redeliver_timeout Timeout before retrying a pending ``3600`` - message which is owned by an - abandoned consumer (if a worker died - for some reason, this will occur, - eventually you should retry the - message) - in seconds. -claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) - messages should be checked for to - claim - in milliseconds -=================== ===================================== ================================= +======================= ===================================== ================================= + Option Description Default +======================= ===================================== ================================= +stream The Redis stream name messages +group The Redis consumer group name symfony +consumer Consumer name used in Redis consumer +auto_setup Create the Redis group automatically? true +auth The Redis password +delete_after_ack If ``true``, messages are deleted false + automatically after processing them +delete_after_reject If ``true``, messages are deleted true + automatically if they are rejected +lazy Connect only when a connection is false + really needed +serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` + in Redis (the + ``Redis::OPT_SERIALIZER`` option) +stream_max_entries The maximum number of entries which ``0`` (which means "no trimming") + the stream will be trimmed to. Set + it to a large enough number to + avoid losing pending messages +tls Enable TLS support for the connection false +redeliver_timeout Timeout before retrying a pending ``3600`` + message which is owned by an + abandoned consumer (if a worker died + for some reason, this will occur, + eventually you should retry the + message) - in seconds. +claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) + messages should be checked for to + claim - in milliseconds +sentinel_persistent_id String, if null connection is null + non-persistent. +sentinel_retry_interval Int, value in milliseconds ``0`` +sentinel_read_timeout Float, value in seconds ``0`` + default indicates unlimited +sentinel_timeout Float, value in seconds ``0`` + default indicates unlimited +sentinel_master String, if null or empty Sentinel null + support is disabled +======================= ===================================== ================================= .. caution:: @@ -1500,6 +1509,11 @@ claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) .. versionadded:: 5.2 The ``delete_after_reject`` and ``lazy`` options were introduced in Symfony 5.2. + +.. versionadded:: 5.4 + + The ``sentinel_persistent_id``, ``sentinel_retry_interval``, ``sentinel_read_timeout``, + ``sentinel_timeout``, and ``sentinel_master`` options were introduced in Symfony 5.4. .. deprecated:: 5.4 From 09f0759039a21977b2d94a682c05b2826371aeaa Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 17 Nov 2021 17:00:03 +0100 Subject: [PATCH 1276/1519] Minor tweaks --- messenger.rst | 84 +++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/messenger.rst b/messenger.rst index 0e3b8f51b0d..59ac3a5fb4e 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1441,47 +1441,47 @@ A number of options can be configured via the DSN or via the ``options`` key under the transport in ``messenger.yaml``: -======================= ===================================== ================================= - Option Description Default -======================= ===================================== ================================= -stream The Redis stream name messages -group The Redis consumer group name symfony -consumer Consumer name used in Redis consumer -auto_setup Create the Redis group automatically? true -auth The Redis password -delete_after_ack If ``true``, messages are deleted false - automatically after processing them -delete_after_reject If ``true``, messages are deleted true - automatically if they are rejected -lazy Connect only when a connection is false - really needed -serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` - in Redis (the - ``Redis::OPT_SERIALIZER`` option) -stream_max_entries The maximum number of entries which ``0`` (which means "no trimming") - the stream will be trimmed to. Set - it to a large enough number to - avoid losing pending messages -tls Enable TLS support for the connection false -redeliver_timeout Timeout before retrying a pending ``3600`` - message which is owned by an - abandoned consumer (if a worker died - for some reason, this will occur, - eventually you should retry the - message) - in seconds. -claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) - messages should be checked for to - claim - in milliseconds -sentinel_persistent_id String, if null connection is null - non-persistent. -sentinel_retry_interval Int, value in milliseconds ``0`` -sentinel_read_timeout Float, value in seconds ``0`` - default indicates unlimited -sentinel_timeout Float, value in seconds ``0`` - default indicates unlimited -sentinel_master String, if null or empty Sentinel null - support is disabled -======================= ===================================== ================================= +======================= ===================================== ================================= +Option Description Default +======================= ===================================== ================================= +stream The Redis stream name messages +group The Redis consumer group name symfony +consumer Consumer name used in Redis consumer +auto_setup Create the Redis group automatically? true +auth The Redis password +delete_after_ack If ``true``, messages are deleted false + automatically after processing them +delete_after_reject If ``true``, messages are deleted true + automatically if they are rejected +lazy Connect only when a connection is false + really needed +serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` + in Redis (the + ``Redis::OPT_SERIALIZER`` option) +stream_max_entries The maximum number of entries which ``0`` (which means "no trimming") + the stream will be trimmed to. Set + it to a large enough number to + avoid losing pending messages +tls Enable TLS support for the connection false +redeliver_timeout Timeout before retrying a pending ``3600`` + message which is owned by an + abandoned consumer (if a worker died + for some reason, this will occur, + eventually you should retry the + message) - in seconds. +claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) + messages should be checked for to + claim - in milliseconds +sentinel_persistent_id String, if null connection is null + non-persistent. +sentinel_retry_interval Int, value in milliseconds ``0`` +sentinel_read_timeout Float, value in seconds ``0`` + default indicates unlimited +sentinel_timeout Float, value in seconds ``0`` + default indicates unlimited +sentinel_master String, if null or empty Sentinel null + support is disabled +======================= ===================================== ================================= .. caution:: @@ -1509,7 +1509,7 @@ sentinel_master String, if null or empty Sentinel null .. versionadded:: 5.2 The ``delete_after_reject`` and ``lazy`` options were introduced in Symfony 5.2. - + .. versionadded:: 5.4 The ``sentinel_persistent_id``, ``sentinel_retry_interval``, ``sentinel_read_timeout``, From 165244e7b0c182745033a894be6f849ef1bbab2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Sun, 29 Aug 2021 12:08:00 +0200 Subject: [PATCH 1277/1519] [Filesystem] Add documentation for the Path class --- components/filesystem.rst | 210 +++++++++++++++++++++++++++++++++++++- 1 file changed, 206 insertions(+), 4 deletions(-) diff --git a/components/filesystem.rst b/components/filesystem.rst index a5023a270e1..c274c78f921 100644 --- a/components/filesystem.rst +++ b/components/filesystem.rst @@ -4,7 +4,8 @@ The Filesystem Component ======================== - The Filesystem component provides basic utilities for the filesystem. + The Filesystem component provides basic utilities for the filesystem and + paths manipulation. Installation ------------ @@ -18,20 +19,30 @@ Installation Usage ----- -The :class:`Symfony\\Component\\Filesystem\\Filesystem` class is the unique -endpoint for filesystem operations:: +The component contains two classes: + +- The :class:`Symfony\\Component\\Filesystem\\Filesystem` which provides utilities + for filesystem write operations. +- The :class:`Symfony\\Component\\Filesystem\\Path` which provides utilities + for paths manipulation.:: use Symfony\Component\Filesystem\Exception\IOExceptionInterface; use Symfony\Component\Filesystem\Filesystem; + use Symfony\Component\Filesystem\Path; $filesystem = new Filesystem(); try { - $filesystem->mkdir(sys_get_temp_dir().'/'.random_int(0, 1000)); + $filesystem->mkdir( + Path::normalize(sys_get_temp_dir().'/'.random_int(0, 1000)), + ); } catch (IOExceptionInterface $exception) { echo "An error occurred while creating your directory at ".$exception->getPath(); } +Filesystem +---------- + ``mkdir`` ~~~~~~~~~ @@ -224,6 +235,11 @@ Its behavior is the following:: * if ``$path`` does not exist, it returns null. * if ``$path`` exists, it returns its absolute fully resolved final version. +.. note:: + + If you wish to canonicalize the path without checking its existence, you can + use :method:`Symfony\\Component\\Filesystem\\Path::canonicalize` method instead. + ``makePathRelative`` ~~~~~~~~~~~~~~~~~~~~ @@ -309,6 +325,192 @@ creates them before appending the contents. The third argument of ``appendToFile()`` was introduced in Symfony 5.4. +Path +---- + +.. versionadded:: 5.4 + + The :class:`Symfony\\Component\\Filesystem\\Path` class was introduced in Symfony 5.4. + +Dealing with file paths usually involves some difficulties: + +- System Heterogeneity: file paths look different on different platforms. UNIX + file paths start with a slash ("/"), while Windows file paths start with a + system drive ("C:"). UNIX uses forward slashes, while Windows uses backslashes + by default (""). +- Absolute/relative paths: web applications frequently need to deal with absolute + and relative paths. Converting one to the other properly is tricky and + repetitive. + +:class:`Symfony\\Component\\Filesystem\\Path` provides utility methods to tackle +those issues. + +Canonicalization +~~~~~~~~~~~~~~~~ + +Returns the shortest path name equivalent to the given path. It applies the +following rules iteratively until no further processing can be done: + +- "." segments are removed; +- ".." segments are resolved; +- backslashes ("\") are converted into forward slashes ("/"); +- root paths ("/" and "C:/") always terminate with a slash; +- non-root paths never terminate with a slash; +- schemes (such as "phar://") are kept; +- replace "~" with the user's home directory. + +You can canonicalize a path with :method:`Symfony\\Component\\Filesystem\\Path::canonicalize`:: + + echo Path::canonicalize('/var/www/vhost/webmozart/../config.ini'); + // => /var/www/vhost/config.ini + +You can pass absolute paths and relative paths to the +:method:`Symfony\\Component\\Filesystem\\Path::canonicalize` method. When a +relative path is passed, ".." segments at the beginning of the path are kept:: + + echo Path::canonicalize('../uploads/../config/config.yaml'); + // => ../config/config.yaml + +Malformed paths are returned unchanged:: + + echo Path::canonicalize('C:Programs/PHP/php.ini'); + // => C:Programs/PHP/php.ini + +Converting Absolute/Relative Paths +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Absolute/relative paths can be converted with the methods +:method:`Symfony\\Component\\Filesystem\\Path::makeAbsolute` +and :method:`Symfony\\Component\\Filesystem\\Path::makeRelative`. + +:method:`Symfony\\Component\\Filesystem\\Path::makeAbsolute` method expects a +relative path and a base path to base that relative path upon:: + + echo Path::makeAbsolute('config/config.yaml', '/var/www/project'); + // => /var/www/project/config/config.yaml + +If an absolute path is passed in the first argument, the absolute path is +returned unchanged:: + + echo Path::makeAbsolute('/usr/share/lib/config.ini', '/var/www/project'); + // => /usr/share/lib/config.ini + +The method resolves ".." segments, if there are any:: + + echo Path::makeAbsolute('../config/config.yaml', '/var/www/project/uploads'); + // => /var/www/project/config/config.yaml + +This method is very useful if you want to be able to accept relative paths (for +example, relative to the root directory of your project) and absolute paths at +the same time. + +:method:`Symfony\\Component\\Filesystem\\Path::makeRelative` is the inverse +operation to :method:`Symfony\\Component\\Filesystem\\Path::makeAbsolute`:: + + echo Path::makeRelative('/var/www/project/config/config.yaml', '/var/www/project'); + // => config/config.yaml + +If the path is not within the base path, the method will prepend ".." segments +as necessary:: + + echo Path::makeRelative('/var/www/project/config/config.yaml', '/var/www/project/uploads'); + // => ../config/config.yaml + +Use :method:`Symfony\\Component\\Filesystem\\Path::makeAbsolute` and +:method:`Symfony\\Component\\Filesystem\\Path::makeRelative` to check whether a +path is absolute or relative:: + + Path::isAbsolute('C:\Programs\PHP\php.ini') + // => true + +All four methods internally canonicalize the passed path. + +Finding Longest Common Base Paths +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When you store absolute file paths on the file system, this leads to a lot of +duplicated information:: + + return [ + '/var/www/vhosts/project/httpdocs/config/config.yaml', + '/var/www/vhosts/project/httpdocs/config/routing.yaml', + '/var/www/vhosts/project/httpdocs/config/services.yaml', + '/var/www/vhosts/project/httpdocs/images/banana.gif', + '/var/www/vhosts/project/httpdocs/uploads/images/nicer-banana.gif', + ]; + +Especially when storing many paths, the amount of duplicated information is +noticeable. You can use :method:`Symfony\\Component\\Filesystem\\Path::getLongestCommonBasePath` +to check a list of paths for a common base path:: + + $paths = [ + '/var/www/vhosts/project/httpdocs/config/config.yaml', + '/var/www/vhosts/project/httpdocs/config/routing.yaml', + '/var/www/vhosts/project/httpdocs/config/services.yaml', + '/var/www/vhosts/project/httpdocs/images/banana.gif', + '/var/www/vhosts/project/httpdocs/uploads/images/nicer-banana.gif', + ]; + + Path::getLongestCommonBasePath($paths); + // => /var/www/vhosts/project/httpdocs + +Use this path together with :method:`Symfony\\Component\\Filesystem\\Path::makeRelative` +to shorten the stored paths:: + + $bp = '/var/www/vhosts/project/httpdocs'; + + return [ + $bp.'/config/config.yaml', + $bp.'/config/routing.yaml', + $bp.'/config/services.yaml', + $bp.'/images/banana.gif', + $bp.'/uploads/images/nicer-banana.gif', + ]; + +:method:`Symfony\\Component\\Filesystem\\Path::getLongestCommonBasePath` always +returns canonical paths. + +Use :method:`Symfony\\Component\\Filesystem\\Path::isBasePath` to test whether a +path is a base path of another path:: + + Path::isBasePath("/var/www", "/var/www/project"); + // => true + + Path::isBasePath("/var/www", "/var/www/project/.."); + // => true + + Path::isBasePath("/var/www", "/var/www/project/../.."); + // => false + +Finding Directories/Root Directories +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +PHP offers the function :phpfunction:`dirname` to obtain the directory path of a +file path. This method has a few quirks:: + +- `dirname()` does not accept backslashes on UNIX +- `dirname("C:/Programs")` returns "C:", not "C:/" +- `dirname("C:/")` returns ".", not "C:/" +- `dirname("C:")` returns ".", not "C:/" +- `dirname("Programs")` returns ".", not "" +- `dirname()` does not canonicalize the result + +:method:`Symfony\\Component\\Filesystem\\Path::getDirectory` fixes these +shortcomings:: + + echo Path::getDirectory("C:\Programs"); + // => C:/ + +Additionally, you can use :method:`Symfony\\Component\\Filesystem\\Path::getRoot` +to obtain the root of a path:: + + echo Path::getRoot("/etc/apache2/sites-available"); + // => / + + echo Path::getRoot("C:\Programs\Apache\Config"); + // => C:/ +>>>>>>> a992f6342 ([Filesystem] Add documentation for the Path class) + Error Handling -------------- From 304de64e7dccfc9d6e093d5e2f47822631f928b9 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 18 Nov 2021 12:36:41 +0100 Subject: [PATCH 1278/1519] Minor tweaks --- components/filesystem.rst | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/components/filesystem.rst b/components/filesystem.rst index c274c78f921..e60e0b389af 100644 --- a/components/filesystem.rst +++ b/components/filesystem.rst @@ -4,8 +4,8 @@ The Filesystem Component ======================== - The Filesystem component provides basic utilities for the filesystem and - paths manipulation. + The Filesystem component provides platform-independent utilities for + filesystem operations and for file/directory paths manipulation. Installation ------------ @@ -19,12 +19,8 @@ Installation Usage ----- -The component contains two classes: - -- The :class:`Symfony\\Component\\Filesystem\\Filesystem` which provides utilities - for filesystem write operations. -- The :class:`Symfony\\Component\\Filesystem\\Path` which provides utilities - for paths manipulation.:: +The component contains two main classes called :class:`Symfony\\Component\\Filesystem\\Filesystem` +and :class:`Symfony\\Component\\Filesystem\\Path`:: use Symfony\Component\Filesystem\Exception\IOExceptionInterface; use Symfony\Component\Filesystem\Filesystem; @@ -40,8 +36,8 @@ The component contains two classes: echo "An error occurred while creating your directory at ".$exception->getPath(); } -Filesystem ----------- +Filesystem Utilities +-------------------- ``mkdir`` ~~~~~~~~~ @@ -325,8 +321,8 @@ creates them before appending the contents. The third argument of ``appendToFile()`` was introduced in Symfony 5.4. -Path ----- +Path Manipulation Utilities +--------------------------- .. versionadded:: 5.4 @@ -334,13 +330,12 @@ Path Dealing with file paths usually involves some difficulties: -- System Heterogeneity: file paths look different on different platforms. UNIX +- Platform differences: file paths look different on different platforms. UNIX file paths start with a slash ("/"), while Windows file paths start with a system drive ("C:"). UNIX uses forward slashes, while Windows uses backslashes - by default (""). + by default. - Absolute/relative paths: web applications frequently need to deal with absolute - and relative paths. Converting one to the other properly is tricky and - repetitive. + and relative paths. Converting one to the other properly is tricky and repetitive. :class:`Symfony\\Component\\Filesystem\\Path` provides utility methods to tackle those issues. @@ -509,7 +504,6 @@ to obtain the root of a path:: echo Path::getRoot("C:\Programs\Apache\Config"); // => C:/ ->>>>>>> a992f6342 ([Filesystem] Add documentation for the Path class) Error Handling -------------- From 3f9ff65206a47eed4e2aaecd043067ef5b31d56a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 18 Nov 2021 13:39:30 +0100 Subject: [PATCH 1279/1519] Remove conditional includes on other files --- reference/forms/types/ulid.rst | 6 ++---- reference/forms/types/uuid.rst | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/reference/forms/types/ulid.rst b/reference/forms/types/ulid.rst index 7dba8164b19..90d2f33589b 100644 --- a/reference/forms/types/ulid.rst +++ b/reference/forms/types/ulid.rst @@ -43,13 +43,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``''`` (the empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc diff --git a/reference/forms/types/uuid.rst b/reference/forms/types/uuid.rst index 0fe52f16330..c5d0827558e 100644 --- a/reference/forms/types/uuid.rst +++ b/reference/forms/types/uuid.rst @@ -43,13 +43,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``''`` (the empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc From 5d033cf57ba5b72e21aae706868eb298a34ffcad Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 18 Nov 2021 15:24:30 +0100 Subject: [PATCH 1280/1519] [Frontend] Remove all Assetic references --- _build/redirection_map | 2 ++ _build/spelling_word_list.txt | 1 - frontend.rst | 1 - frontend/assetic/index.rst | 8 -------- 4 files changed, 2 insertions(+), 10 deletions(-) delete mode 100644 frontend/assetic/index.rst diff --git a/_build/redirection_map b/_build/redirection_map index 87a36a5a2b9..b4338e01043 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -534,3 +534,5 @@ /security/multiple_guard_authenticators /security/entry_point /security/guard_authentication /security/custom_authenticator /email /mailer +/frontend/assetic /frontend +/frontend/assetic/index /frontend diff --git a/_build/spelling_word_list.txt b/_build/spelling_word_list.txt index 3b1d630fa11..ba76529bd7a 100644 --- a/_build/spelling_word_list.txt +++ b/_build/spelling_word_list.txt @@ -3,7 +3,6 @@ Akamai analytics Ansi Ansible -Assetic async authenticator authenticators diff --git a/frontend.rst b/frontend.rst index b95f0aa216e..d4eff6cc357 100644 --- a/frontend.rst +++ b/frontend.rst @@ -92,7 +92,6 @@ Other Front-End Articles :hidden: :glob: - frontend/assetic/index frontend/encore/installation frontend/encore/simple-example frontend/encore/* diff --git a/frontend/assetic/index.rst b/frontend/assetic/index.rst deleted file mode 100644 index 63955c9f8dd..00000000000 --- a/frontend/assetic/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -Assetic -======= - -.. caution:: - - Using Assetic to manage web assets in Symfony applications is no longer - recommended. Instead, use :doc:`Webpack Encore `, which bridges - Symfony applications with modern JavaScript-based tools to manage web assets. From 2075bb9fac81ad3014f5d79e9673f49cbdd9d92a Mon Sep 17 00:00:00 2001 From: Antoine Makdessi Date: Wed, 17 Nov 2021 14:13:31 +0100 Subject: [PATCH 1281/1519] Update page_creation.rst --- page_creation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/page_creation.rst b/page_creation.rst index 76b892c8455..b921671c6ae 100644 --- a/page_creation.rst +++ b/page_creation.rst @@ -118,7 +118,7 @@ You can now add your route directly *above* the controller: + /** + * @Route("/lucky/number") + */ - public function number() + public function number(): Response { // this looks exactly the same } @@ -134,7 +134,7 @@ You can now add your route directly *above* the controller: class LuckyController { + #[Route('/lucky/number')] - public function number() + public function number(): Response { // this looks exactly the same } From 2b08260b78f68e3dc89a7fbc57b4fed9bdffff89 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 18 Nov 2021 17:41:13 +0100 Subject: [PATCH 1282/1519] Tweak --- workflow.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workflow.rst b/workflow.rst index 2d3fdb9352c..8845953a2e1 100644 --- a/workflow.rst +++ b/workflow.rst @@ -388,7 +388,8 @@ order: .. versionadded:: 5.2 - In Symfony 5.2, the context is customizable for all events except for workflow.guard events, which will not receive the custom $context:: + In Symfony 5.2, the context is customizable for all events except for + ``workflow.guard`` events, which will not receive the custom ``$context``:: // $context must be an array $context = ['context_key' => 'context_value']; From 27622db2ba2b1f2130cf6a7ad26a24e98fbc5166 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 18 Nov 2021 12:04:46 -0500 Subject: [PATCH 1283/1519] Adding a page about Symfony & Docker --- .doctor-rst.yaml | 1 + setup.rst | 8 ++++++ setup/docker.rst | 56 ++++++++++++++++++++++++++++++++++++++++ setup/symfony_server.rst | 2 +- 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 setup/docker.rst diff --git a/.doctor-rst.yaml b/.doctor-rst.yaml index 86741f56f86..70b646e146a 100644 --- a/.doctor-rst.yaml +++ b/.doctor-rst.yaml @@ -71,6 +71,7 @@ whitelist: - '/``.yml``/' - '/(.*)\.orm\.yml/' # currently DoctrineBundle only supports .yml - '/rst-class/' + - /docker-compose\.yml/ lines: - 'in config files, so the old ``app/config/config_dev.yml`` goes to' - '#. The most important config file is ``app/config/services.yml``, which now is' diff --git a/setup.rst b/setup.rst index 323821be54f..3cfbae048b0 100644 --- a/setup.rst +++ b/setup.rst @@ -122,6 +122,8 @@ In production, you should install a webserver like Nginx or Apache and method can also be used if you're not using the Symfony local web server for development. +.. _symfony-binary-web-server: + However for local development, the most convenient way of running Symfony is by using the :doc:`local web server ` provided by the ``symfony`` binary. This local server provides among other things support for @@ -145,6 +147,11 @@ the server by pressing ``Ctrl+C`` from your terminal. The web server works with any PHP application, not only Symfony projects, so it's a very useful generic development tool. +Symfony Docker Integration +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you'd like to use Docker with Symfony, see :doc:`setup/docker` + .. _symfony-flex: Installing Packages @@ -303,6 +310,7 @@ Learn More :maxdepth: 1 :glob: + setup/docker setup/homestead setup/web_server_configuration setup/* diff --git a/setup/docker.rst b/setup/docker.rst new file mode 100644 index 00000000000..5ac1e47b97b --- /dev/null +++ b/setup/docker.rst @@ -0,0 +1,56 @@ +.. index:: Docker + +Using Docker with Symfony +========================= + +Can you use Docker with Symfony? Of course! And several tools exist to help, +depending on your needs. + +Complete Docker Environment +--------------------------- + +If you'd like a complete Docker environment (i.e. where PHP, web server, database, +etc. are all in Docker), check out `https://github.com/dunglas/symfony-docker`_. + +Alternatively, you can install PHP on your local machine and use the +:ref:`symfony binary Docker integration `. In both cases, +you can take advantage of automatic Docker configuration from :ref:`Symfony Flex `. + +Flex Recipes & Docker Configuration +----------------------------------- + +The :ref:`Flex recipe ` for some packages also include Docker configuration. +For example, when you run ``composer require doctrine`` (to get ``symfony/orm-pack``), +your ``docker-compose.yml`` file will automatically be updated to include a +``database`` service. + +The first time you install a recipe containing Docker config, Flex will ask you +if you want to include it. Or, you can set your preference in ``composer.json``, +by seting the ``symfony.extra.docker`` config to ``true`` or ``false``. + +Some recipes also include additions to your ``Dockerfile``. To get those changes, +you need to already have a ``Dockerfile`` at the root of your app *with* the +following code somewhere inside: + +.. code-block:: text + + ###> recipes ### + ###< recipes ### + +The recipe will find this section and add the changes inside. If you're using +`https://github.com/dunglas/symfony-docker`_, you'll already have this. + +After installing the package, rebuild your containers by running: + +.. code-block:: terminal + + $ docker-compose up --build + +Symfony Binary Web Server and Docker Support +-------------------------------------------- + +If you're using the :ref:`symfony binary web server` (e.g. ``symfony server:start``), +then it can automatically detect your Docker services and expose them as environment +variables. See :ref:`symfony-server-docker`. + +.. _`https://github.com/dunglas/symfony-docker`: https://github.com/dunglas/symfony-docker diff --git a/setup/symfony_server.rst b/setup/symfony_server.rst index 8172060484e..d1570fe6f01 100644 --- a/setup/symfony_server.rst +++ b/setup/symfony_server.rst @@ -281,7 +281,7 @@ Docker Integration ------------------ The local Symfony server provides full `Docker`_ integration for projects that -use it. +use it. To learn more about Docker & Symfony, see :doc:`docker`. When the web server detects that Docker Compose is running for the project, it automatically exposes some environment variables. From 54ea02185091cc71061efa27fcd4765ed05fc76b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 19 Nov 2021 15:10:47 +0100 Subject: [PATCH 1284/1519] Typo --- setup/docker.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/docker.rst b/setup/docker.rst index 5ac1e47b97b..bd8eb145af8 100644 --- a/setup/docker.rst +++ b/setup/docker.rst @@ -26,7 +26,7 @@ your ``docker-compose.yml`` file will automatically be updated to include a The first time you install a recipe containing Docker config, Flex will ask you if you want to include it. Or, you can set your preference in ``composer.json``, -by seting the ``symfony.extra.docker`` config to ``true`` or ``false``. +by setting the ``symfony.extra.docker`` config to ``true`` or ``false``. Some recipes also include additions to your ``Dockerfile``. To get those changes, you need to already have a ``Dockerfile`` at the root of your app *with* the From da7c88512a7686bc8a742da2fab0369178fcaf16 Mon Sep 17 00:00:00 2001 From: VosKoen <40901069+VosKoen@users.noreply.github.com> Date: Fri, 19 Nov 2021 20:06:52 +0100 Subject: [PATCH 1285/1519] Update associations.rst syntax error in orphanRemoval=true In the Attributes code example #[ORM\OneToMany(mappedBy: 'user', targetEntity: Recipe::class, orphanRemoval=true)], doesn't work because of wrong syntax. should be #[ORM\OneToMany(mappedBy: 'user', targetEntity: Recipe::class, orphanRemoval: true)] --- doctrine/associations.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doctrine/associations.rst b/doctrine/associations.rst index 94c74dc0a6f..46c843699de 100644 --- a/doctrine/associations.rst +++ b/doctrine/associations.rst @@ -676,7 +676,7 @@ that behavior, use the `orphanRemoval`_ option inside ``Category``: // ... - #[ORM\OneToMany(targetEntity: Product::class, mappedBy: "category", orphanRemoval=true)] + #[ORM\OneToMany(targetEntity: Product::class, mappedBy: "category", orphanRemoval: true)] private $products; From 40cf2223f956390d7e58a0e0fb8250c3bf2110c9 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 20 Nov 2021 11:09:20 +0100 Subject: [PATCH 1286/1519] remove outdated doc URL that redirects to the same page --- security.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/security.rst b/security.rst index 6720fb9a6e1..912ad871b1d 100644 --- a/security.rst +++ b/security.rst @@ -27,7 +27,6 @@ creates a ``security.yaml`` configuration file for you: # config/packages/security.yaml security: - # https://symfony.com/doc/current/security/experimental_authenticators.html enable_authenticator_manager: true # https://symfony.com/doc/current/security.html#c-hashing-passwords password_hashers: From 16ffcdae52493d4f23c1841e56a32aad81531f7b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 18 Nov 2021 16:29:39 +0100 Subject: [PATCH 1287/1519] [Form] Add the docs for EnumType --- reference/forms/types.rst | 1 + reference/forms/types/enum.rst | 119 ++++++++++++++++++++++++++++++ reference/forms/types/map.rst.inc | 1 + 3 files changed, 121 insertions(+) create mode 100644 reference/forms/types/enum.rst diff --git a/reference/forms/types.rst b/reference/forms/types.rst index 61ff1b5bf86..eaa0344f141 100644 --- a/reference/forms/types.rst +++ b/reference/forms/types.rst @@ -23,6 +23,7 @@ Form Types Reference types/color types/choice + types/enum types/entity types/country types/language diff --git a/reference/forms/types/enum.rst b/reference/forms/types/enum.rst new file mode 100644 index 00000000000..e9842516acc --- /dev/null +++ b/reference/forms/types/enum.rst @@ -0,0 +1,119 @@ +.. index:: + single: Forms; Fields; EnumType + +EnumType Field +============== + +.. versionadded:: 5.4 + + The ``EnumType`` form field was introduced in Symfony 5.4. + +A multi-purpose field used to allow the user to "choose" one or more options +defined in a `PHP enumeration`_. It extends the :doc:`ChoiceType ` +field and defines the same options. + ++---------------------------+----------------------------------------------------------------------+ +| Rendered as | can be various tags (see below) | ++---------------------------+----------------------------------------------------------------------+ +| Default invalid message | The selected choice is invalid. | ++---------------------------+----------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+----------------------------------------------------------------------+ +| Parent type | :doc:`ChoiceType ` | ++---------------------------+----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\EnumType` | ++---------------------------+----------------------------------------------------------------------+ + +.. include:: /reference/forms/types/options/_debug_form.rst.inc + +Example Usage +------------- + +Before using this field, you'll need to have some PHP enumeration (or "enum" for +short) defined somewhere in your application. This enum has to be of type +"backed enum", where each keyword defines a scalar value such a string:: + + // src/Config/TextAlign.php + namespace App\Config; + + enum TextAlign + { + case Left = 'Left/Start aligned'; + case Center = 'Center/Middle aligned'; + case Right = 'Right/End aligned'; + } + +Instead of using the values of the enumeration in a ``choices`` option, the +``EnumType`` only requires to define the ``class`` option pointing to the enum:: + + use App\Config\TextAlign; + use Symfony\Component\Form\Extension\Core\Type\EnumType; + // ... + + $builder->add('alignment', EnumType::class, ['class' => TextAlign::class]); + +This will display a ```` and ````. + +Field Options +------------- + +class +~~~~~ + +**type**: ``string`` **default**: (it has no default) + +The fully-qualified class name (FQCN) of the PHP enum used to get the values +displayed by this form field. + +Inherited Options +----------------- + +These options inherit from the :doc:`ChoiceType `: + +.. include:: /reference/forms/types/options/error_bubbling.rst.inc + +.. include:: /reference/forms/types/options/error_mapping.rst.inc + +.. include:: /reference/forms/types/options/expanded.rst.inc + +.. include:: /reference/forms/types/options/multiple.rst.inc + +.. include:: /reference/forms/types/options/placeholder.rst.inc + +.. include:: /reference/forms/types/options/preferred_choices.rst.inc + +.. include:: /reference/forms/types/options/choice_type_trim.rst.inc + +These options inherit from the :doc:`FormType `: + +.. include:: /reference/forms/types/options/attr.rst.inc + +.. include:: /reference/forms/types/options/data.rst.inc + +.. include:: /reference/forms/types/options/disabled.rst.inc + +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc + +.. include:: /reference/forms/types/options/empty_data_description.rst.inc + +.. include:: /reference/forms/types/options/help.rst.inc + +.. include:: /reference/forms/types/options/help_attr.rst.inc + +.. include:: /reference/forms/types/options/help_html.rst.inc + +.. include:: /reference/forms/types/options/label.rst.inc + +.. include:: /reference/forms/types/options/label_attr.rst.inc + +.. include:: /reference/forms/types/options/label_format.rst.inc + +.. include:: /reference/forms/types/options/mapped.rst.inc + +.. include:: /reference/forms/types/options/required.rst.inc + +.. include:: /reference/forms/types/options/row_attr.rst.inc + +.. _`PHP enumeration`: https://wiki.php.net/rfc/enumerations diff --git a/reference/forms/types/map.rst.inc b/reference/forms/types/map.rst.inc index 8171c836a4d..4d1ed612c67 100644 --- a/reference/forms/types/map.rst.inc +++ b/reference/forms/types/map.rst.inc @@ -19,6 +19,7 @@ Choice Fields ~~~~~~~~~~~~~ * :doc:`ChoiceType ` +* :doc:`EnumType ` * :doc:`EntityType ` * :doc:`CountryType ` * :doc:`LanguageType ` From fe3a9ba932ff50b0919af0c633b1990e99a33fc3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 20 Nov 2021 12:44:49 +0100 Subject: [PATCH 1288/1519] Remove the versionadded directive --- reference/forms/types/enum.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/reference/forms/types/enum.rst b/reference/forms/types/enum.rst index e9842516acc..cea0aa09e3e 100644 --- a/reference/forms/types/enum.rst +++ b/reference/forms/types/enum.rst @@ -4,10 +4,6 @@ EnumType Field ============== -.. versionadded:: 5.4 - - The ``EnumType`` form field was introduced in Symfony 5.4. - A multi-purpose field used to allow the user to "choose" one or more options defined in a `PHP enumeration`_. It extends the :doc:`ChoiceType ` field and defines the same options. From c3695e417b38e587b8f7e2d9ecd86d9da00977d4 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 20 Nov 2021 12:45:08 +0100 Subject: [PATCH 1289/1519] Readd the versionadded directive --- reference/forms/types/enum.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/reference/forms/types/enum.rst b/reference/forms/types/enum.rst index cea0aa09e3e..e9842516acc 100644 --- a/reference/forms/types/enum.rst +++ b/reference/forms/types/enum.rst @@ -4,6 +4,10 @@ EnumType Field ============== +.. versionadded:: 5.4 + + The ``EnumType`` form field was introduced in Symfony 5.4. + A multi-purpose field used to allow the user to "choose" one or more options defined in a `PHP enumeration`_. It extends the :doc:`ChoiceType ` field and defines the same options. From 8071ddc5c9608c3b1c7731b2d82f1b9d33f83cc8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 20 Nov 2021 12:45:36 +0100 Subject: [PATCH 1290/1519] Remove the versionadded directive --- reference/forms/types/enum.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/reference/forms/types/enum.rst b/reference/forms/types/enum.rst index e9842516acc..cea0aa09e3e 100644 --- a/reference/forms/types/enum.rst +++ b/reference/forms/types/enum.rst @@ -4,10 +4,6 @@ EnumType Field ============== -.. versionadded:: 5.4 - - The ``EnumType`` form field was introduced in Symfony 5.4. - A multi-purpose field used to allow the user to "choose" one or more options defined in a `PHP enumeration`_. It extends the :doc:`ChoiceType ` field and defines the same options. From 32278d443fe62c8f1a044e6c8fbf29b2830c265c Mon Sep 17 00:00:00 2001 From: Sebastian Paczkowski <74934099+sebpacz@users.noreply.github.com> Date: Mon, 22 Nov 2021 19:14:56 +0100 Subject: [PATCH 1291/1519] [Serializer] Fix grammar issue --- components/serializer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/serializer.rst b/components/serializer.rst index 53a1475ee17..6fd84b02077 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -872,7 +872,7 @@ The Serializer component provides several built-in normalizers: This normalizer works with classes that implement :class:`Symfony\\Component\\Form\\FormInterface`. - It will get errors from the form and normalize them into an normalized array. + It will get errors from the form and normalize them into a normalized array. :class:`Symfony\\Component\\Serializer\\Normalizer\\ConstraintViolationListNormalizer` This normalizer converts objects that implement From 66a248ae15b714cab3f100895873f9f07c7d7500 Mon Sep 17 00:00:00 2001 From: Al-Saleh KEITA <28827545+askeita@users.noreply.github.com> Date: Wed, 24 Nov 2021 09:03:23 +0100 Subject: [PATCH 1292/1519] Corrected typo in notifier.rst Replaced "send" by "sent". --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 1ef5b5521f7..0280a04f8ad 100644 --- a/notifier.rst +++ b/notifier.rst @@ -615,7 +615,7 @@ The :class:`Symfony\\Component\\Notifier\\Notification\\SmsNotificationInterface` and :class:`Symfony\\Component\\Notifier\\Notification\\EmailNotificationInterface` -also exists to modify messages send to those channels. +also exists to modify messages sent to those channels. Disabling Delivery ------------------ From 14e521e016908940267d885586a284839af9b205 Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Wed, 24 Nov 2021 15:38:12 +0100 Subject: [PATCH 1293/1519] [Form] Minor --- reference/forms/types/enum.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reference/forms/types/enum.rst b/reference/forms/types/enum.rst index e9842516acc..c91111e4284 100644 --- a/reference/forms/types/enum.rst +++ b/reference/forms/types/enum.rst @@ -31,7 +31,7 @@ Example Usage Before using this field, you'll need to have some PHP enumeration (or "enum" for short) defined somewhere in your application. This enum has to be of type -"backed enum", where each keyword defines a scalar value such a string:: +"backed enum", where each keyword defines a scalar value such as a string:: // src/Config/TextAlign.php namespace App\Config; @@ -53,8 +53,8 @@ Instead of using the values of the enumeration in a ``choices`` option, the $builder->add('alignment', EnumType::class, ['class' => TextAlign::class]); This will display a ```` and ````. +the ``TextAlign`` enum. Use the `expanded`_ and `multiple`_ options to display +these values as ```` or ````. Field Options ------------- From 4f475d6e1e120ae423695be0281bea2b0d9492fc Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 25 Nov 2021 09:00:37 +0100 Subject: [PATCH 1294/1519] Minor reword --- components/finder.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/components/finder.rst b/components/finder.rst index 4ccd6c7fe0d..ecae414084a 100644 --- a/components/finder.rst +++ b/components/finder.rst @@ -148,13 +148,14 @@ can reuse those rules to exclude files and directories from the results with the // excludes files/directories matching the .gitignore patterns $finder->ignoreVCSIgnored(true); -Rules from higher levels will be overridden by those in lower levels. +The rules of a directory always override the rules of its parent directories. .. note:: - Only ``.gitignore`` files from search directories and their descendants are - read. Files from parent directories are ignored. To be consistent with Git - behavior, you should explicitly search from the Git repository root. + Git looks for ``.gitignore`` files starting from the repository root directory. + Symfony's Finder behavior is different and it looks for ``.gitignore`` files + starting from the directory used to search files/directories. To be consistent + with Git behavior, you should explicitly search from the Git repository root. .. versionadded:: 5.4 From 2133ec4fc0df3e158b3b5d4974b4b82d68b10a9c Mon Sep 17 00:00:00 2001 From: helmi <43951764+helmis123@users.noreply.github.com> Date: Thu, 25 Nov 2021 15:29:07 +0100 Subject: [PATCH 1295/1519] Update http_cache.rst Update CacheKernel implementation in public/index.php Removal of "$request" which was moved to SymfonyRuntime --- http_cache.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/http_cache.rst b/http_cache.rst index 35620d1cd76..59ca7e19526 100644 --- a/http_cache.rst +++ b/http_cache.rst @@ -98,15 +98,14 @@ caching kernel: + use App\CacheKernel; use App\Kernel; - // ... - $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); + // ... + $kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); + // Wrap the default Kernel with the CacheKernel one in 'prod' environment + if ('prod' === $kernel->getEnvironment()) { - + $kernel = new CacheKernel($kernel); + + return new CacheKernel($kernel); + } + return $kernel; - $request = Request::createFromGlobals(); - // ... The caching kernel will immediately act as a reverse proxy: caching responses from your application and returning them to the client. From 8a5ac3137501f9c4ae7b7e930c6ae89b5a1505ce Mon Sep 17 00:00:00 2001 From: Yoann Chocteau Date: Thu, 25 Nov 2021 19:43:46 +0100 Subject: [PATCH 1296/1519] =?UTF-8?q?The=20method=20renderForm=20generate?= =?UTF-8?q?=20a=20422=20Unprocessable=20Entity=20if=20the=20form=20is=20in?= =?UTF-8?q?valid.=20So=20we=20can=E2=80=99t=20pass=20in=20the=20success=20?= =?UTF-8?q?method.=20I=20suggest=20to=20replace=20it=20with=20the=20comple?= =?UTF-8?q?te=20method.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- form/dynamic_form_modification.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/form/dynamic_form_modification.rst b/form/dynamic_form_modification.rst index 30d53efb780..01694ad9653 100644 --- a/form/dynamic_form_modification.rst +++ b/form/dynamic_form_modification.rst @@ -568,11 +568,11 @@ field according to the current selection in the ``sport`` field: url : $form.attr('action'), type: $form.attr('method'), data : data, - success: function(html) { + complete: function(html) { // Replace current position field ... $('#meetup_position').replaceWith( // ... with the returned one from the AJAX response. - $(html).find('#meetup_position') + $(html.responseText).find('#meetup_position') ); // Position field now displays the appropriate positions. } From b5c0d3e2af8029cdfb7d91abb7fb3bbcf4c11563 Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Fri, 26 Nov 2021 20:03:12 +0100 Subject: [PATCH 1297/1519] Typo --- form/bootstrap5.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/form/bootstrap5.rst b/form/bootstrap5.rst index 2e82bda0cab..1ff693a753f 100644 --- a/form/bootstrap5.rst +++ b/form/bootstrap5.rst @@ -90,7 +90,7 @@ If you prefer to apply the Bootstrap styles on a form to form basis, include the Error Messages -------------- -Unlike the :doc:`Bootstrap 4 theme `, errors are rendered +Unlike in the :doc:`Bootstrap 4 theme `, errors are rendered **after** the ``input`` element. However, this still makes a strong connection between the error and its ````, as required by the `WCAG 2.0 standard`_. From 1aa5b6e2372bf1f1e216ce1f9c58ea2272c04527 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 29 Nov 2021 16:36:16 +0100 Subject: [PATCH 1298/1519] [Notifier] Vonage bridge and deprecation of nexmo bridge --- notifier.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/notifier.rst b/notifier.rst index 555a624c814..febb0d331e4 100644 --- a/notifier.rst +++ b/notifier.rst @@ -86,6 +86,7 @@ SpotHit ``symfony/spothit-notifier`` ``spothit://TOKEN@default? Telnyx ``symfony/telnyx-notifier`` ``telnyx://API_KEY@default?from=FROM&messaging_profile_id=MESSAGING_PROFILE_ID`` TurboSms ``symfony/turbo-sms-notifier`` ``turbosms://AUTH_TOKEN@default?from=FROM`` Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` +Vonage ``symfony/vonage-notifier`` ``vonage://KEY:SECRET@default?from=FROM`` Yunpian ``symfony/yunpian-notifier`` ``yunpian://APIKEY@default`` ============== ==================================== =========================================================================== @@ -102,10 +103,14 @@ Yunpian ``symfony/yunpian-notifier`` ``yunpian://APIKEY@default The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell, SpotHit, FakeSms (email), LightSms, SmsBiuras and MessageBird integrations were introduced in Symfony 5.3. +.. deprecated:: 5.4 + + The Nexmo integration was deprecated in Symfony 5.4, use the Vonage integration instead. + .. versionadded:: 5.4 - The MessageMedia, Smsc, Yunpian, AmazonSns, Telnyx, TurboSms, Mailjet, FakeSms (logger) - and Sms77 integrations were introduced in Symfony 5.4. + The MessageMedia, Smsc, Yunpian, AmazonSns, Telnyx, TurboSms, Mailjet, FakeSms (logger), + Sms77 and Vonage integrations were introduced in Symfony 5.4. To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: From 80ba85c806f1181ee158b35ba0e9a4bacad2dc72 Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Mon, 29 Nov 2021 22:45:13 +0100 Subject: [PATCH 1299/1519] Updating link to PHP enum --- reference/forms/types/enum.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/forms/types/enum.rst b/reference/forms/types/enum.rst index c91111e4284..51fefe016f0 100644 --- a/reference/forms/types/enum.rst +++ b/reference/forms/types/enum.rst @@ -116,4 +116,4 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/row_attr.rst.inc -.. _`PHP enumeration`: https://wiki.php.net/rfc/enumerations +.. _`PHP enumeration`: https://www.php.net/manual/language.enumerations.php From ad1438b20bf12e954d0fe5ce937443974ca5e254 Mon Sep 17 00:00:00 2001 From: BahmanMD Date: Mon, 29 Nov 2021 21:18:04 +0330 Subject: [PATCH 1300/1519] Update setup.rst - Symfony 5.4 --- setup.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/setup.rst b/setup.rst index 92206e09ab7..0fdc698699a 100644 --- a/setup.rst +++ b/setup.rst @@ -54,10 +54,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_name --version="5.4.x@dev" --full + $ symfony new my_project_name --version="5.4.x" --full # run this if you are building a microservice, console application or API - $ symfony new my_project_name --version="5.4.x@dev" + $ symfony new my_project_name --version="5.4.x" The only difference between these two commands is the number of packages installed by default. The ``--full`` option installs all the packages that you @@ -69,10 +69,10 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/website-skeleton:"5.4.x@dev" my_project_name + $ composer create-project symfony/website-skeleton:"5.4.x" my_project_name # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton:"5.4.x@dev" my_project_name + $ composer create-project symfony/skeleton:"5.4.x" my_project_name No matter which command you run to create the Symfony application. All of them will create a new ``my_project_name/`` directory, download some dependencies @@ -271,14 +271,14 @@ stable version. If you want to use an LTS version, add the ``--version`` option: $ symfony new my_project_name --version=next # you can also select an exact specific Symfony version - $ symfony new my_project_name --version=4.4 + $ symfony new my_project_name --version=5.4 The ``lts`` and ``next`` shortcuts are only available when using Symfony to create new projects. If you use Composer, you need to tell the exact version: .. code-block:: terminal - $ composer create-project symfony/website-skeleton:"^4.4" my_project_name + $ composer create-project symfony/website-skeleton:"^5.4" my_project_name The Symfony Demo application ---------------------------- From 01d3ba49bad380489ca2b9a9b5ae5683ae74caab Mon Sep 17 00:00:00 2001 From: BahmanMD Date: Mon, 29 Nov 2021 21:19:22 +0330 Subject: [PATCH 1301/1519] Update setup.rst - Symfony 6.0 --- setup.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/setup.rst b/setup.rst index 890d0f891c1..5df1a17b22c 100644 --- a/setup.rst +++ b/setup.rst @@ -54,10 +54,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_name --version="6.0.x@dev" --full + $ symfony new my_project_name --full # run this if you are building a microservice, console application or API - $ symfony new my_project_name --version="6.0.x@dev" + $ symfony new my_project_name The only difference between these two commands is the number of packages installed by default. The ``--full`` option installs all the packages that you @@ -69,10 +69,10 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/website-skeleton:"6.0.x@dev" my_project_name + $ composer create-project symfony/website-skeleton my_project_name # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton:"6.0.x@dev" my_project_name + $ composer create-project symfony/skeleton my_project_name No matter which command you run to create the Symfony application. All of them will create a new ``my_project_name/`` directory, download some dependencies @@ -271,14 +271,14 @@ stable version. If you want to use an LTS version, add the ``--version`` option: $ symfony new my_project_name --version=next # you can also select an exact specific Symfony version - $ symfony new my_project_name --version=4.4 + $ symfony new my_project_name --version=5.4 The ``lts`` and ``next`` shortcuts are only available when using Symfony to create new projects. If you use Composer, you need to tell the exact version: .. code-block:: terminal - $ composer create-project symfony/website-skeleton:"^4.4" my_project_name + $ composer create-project symfony/website-skeleton:"^5.4" my_project_name The Symfony Demo application ---------------------------- From c2e8f1764e43b763630cc264880f7de456d37866 Mon Sep 17 00:00:00 2001 From: Bruno Baguette Date: Wed, 1 Dec 2021 21:38:31 +0100 Subject: [PATCH 1302/1519] =?UTF-8?q?Typo=20fix=20:=20"Thees"=20=E2=9E=A4?= =?UTF-8?q?=20"These"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- workflow.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow.rst b/workflow.rst index 40e1d5e7986..2f03abb49df 100644 --- a/workflow.rst +++ b/workflow.rst @@ -587,7 +587,7 @@ events specified in the workflow configuration. In the above example the ``workflow.leave`` event will not be fired, even if it has been specified as an event to be dispatched for all transitions in the workflow configuration. -Thees are all the available constants: +These are all the available constants: * ``Workflow::DISABLE_LEAVE_EVENT`` * ``Workflow::DISABLE_TRANSITION_EVENT`` From ccc04feedfaa3d6a9a0a88df809af5ae45d98ebe Mon Sep 17 00:00:00 2001 From: Pierre Galvez Date: Wed, 1 Dec 2021 22:05:07 +0100 Subject: [PATCH 1303/1519] Fix exemple config The reset_on_message config is in messenger and not in async. --- messenger.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index 59ac3a5fb4e..3bae8e29f8b 100644 --- a/messenger.rst +++ b/messenger.rst @@ -719,10 +719,11 @@ reset the service container between two messages: # config/packages/messenger.yaml framework: messenger: + reset_on_message: true transports: async: dsn: '%env(MESSENGER_TRANSPORT_DSN)%' - reset_on_message: true + .. code-block:: xml From 92d26eb9f6852940fc8e52190295098c0807f4f0 Mon Sep 17 00:00:00 2001 From: BahmanMD Date: Thu, 2 Dec 2021 10:17:19 +0330 Subject: [PATCH 1304/1519] Update setup.rst (Symfony 6.0) --- setup.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.rst b/setup.rst index 5df1a17b22c..5e184d7437f 100644 --- a/setup.rst +++ b/setup.rst @@ -278,7 +278,7 @@ create new projects. If you use Composer, you need to tell the exact version: .. code-block:: terminal - $ composer create-project symfony/website-skeleton:"^5.4" my_project_name + $ composer create-project symfony/skeleton:"^5.4" my_project_name The Symfony Demo application ---------------------------- From d19515c6a2a506e8d01fdc138f5e6ef1c77352a8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 2 Dec 2021 11:59:32 +0100 Subject: [PATCH 1305/1519] Minor tweaks --- templates.rst | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/templates.rst b/templates.rst index 7993826e30e..e25bcb790f1 100644 --- a/templates.rst +++ b/templates.rst @@ -513,7 +513,7 @@ provided by Symfony: # the path of the template to render template: 'static/privacy.html.twig' - # the status code to include in the response headers + # the response status code (default: 200) statusCode: 200 # special options defined by Symfony to set the page cache @@ -542,6 +542,9 @@ provided by Symfony: static/privacy.html.twig + + 200 + 86400 86400 @@ -570,6 +573,9 @@ provided by Symfony: // the path of the template to render 'template' => 'static/privacy.html.twig', + // the response status code (default: 200) + 'statusCode' => 200, + // special options defined by Symfony to set the page cache 'maxAge' => 86400, 'sharedAge' => 86400, @@ -590,6 +596,10 @@ provided by Symfony: The ``context`` option was introduced in Symfony 5.1. +.. versionadded:: 5.4 + + The ``statusCode`` option was introduced in Symfony 5.4. + Checking if a Template Exists ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 6e4b85bd50bed0ed7ae594b053ab91eeb19140de Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 2 Dec 2021 12:24:42 +0100 Subject: [PATCH 1306/1519] Tweak --- messenger.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index 3bae8e29f8b..87fa30ea818 100644 --- a/messenger.rst +++ b/messenger.rst @@ -723,7 +723,6 @@ reset the service container between two messages: transports: async: dsn: '%env(MESSENGER_TRANSPORT_DSN)%' - .. code-block:: xml From 4417f13b90078472f875ce6af6cbb5c5da2c6c90 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 2 Dec 2021 12:49:23 +0100 Subject: [PATCH 1307/1519] [DomCrawler] Fix typo --- components/dom_crawler.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/dom_crawler.rst b/components/dom_crawler.rst index 170127b839f..e39a04224e5 100644 --- a/components/dom_crawler.rst +++ b/components/dom_crawler.rst @@ -230,8 +230,8 @@ Access the value of the first node of the current selection:: // pass FALSE as the second argument to return the original text unchanged $crawler->filterXPath('//body/p')->text('Default text content', false); - // innerText() is similar to text() but returns only the text that is - // the direct descendent of the current node, excluding any child nodes + // innerText() is similar to text() but only returns the text that is + // the direct descendant of the current node, excluding any child nodes $text = $crawler->filterXPath('//body/p')->innerText(); // if content is

    Foo Bar

    // innerText() returns 'Foo' and text() returns 'Foo Bar' From 789d6b658ea60c3230e46900a69f62a7051c148a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Isaert?= Date: Thu, 2 Dec 2021 16:18:08 +0100 Subject: [PATCH 1308/1519] [Setup] Fix references of previous version --- setup/upgrade_major.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup/upgrade_major.rst b/setup/upgrade_major.rst index b52b0ad61de..f2cffe9679c 100644 --- a/setup/upgrade_major.rst +++ b/setup/upgrade_major.rst @@ -33,9 +33,9 @@ it will be removed/changed in the future and that you should stop using it. When the major version is released (e.g. 6.0.0), all deprecated features and functionality are removed. So, as long as you've updated your code to stop using these deprecated features in the last version before the major (e.g. -``4.4.*``), you should be able to upgrade without a problem. That means that +``5.4.*``), you should be able to upgrade without a problem. That means that you should first :doc:`upgrade to the last minor version ` -(e.g. 4.4) so that you can see *all* the deprecations. +(e.g. 5.4) so that you can see *all* the deprecations. To help you find deprecations, notices are triggered whenever you end up using a deprecated feature. When visiting your application in the @@ -104,7 +104,7 @@ done! .. sidebar:: Using the Weak Deprecations Mode Sometimes, you can't fix all deprecations (e.g. something was deprecated - in 4.4 and you still need to support 4.3). In these cases, you can still + in 5.4 and you still need to support 5.3). In these cases, you can still use the bridge to fix as many deprecations as possible and then allow more of them to make your tests pass again. You can do this by using the ``SYMFONY_DEPRECATIONS_HELPER`` env variable: @@ -167,7 +167,7 @@ this one. For instance, update it to ``6.0.*`` to upgrade to Symfony 6.0: "extra": { "symfony": { "allow-contrib": false, - - "require": "4.4.*" + - "require": "5.4.*" + "require": "6.0.*" } } From 167f5619e54e81b90d124f458205f9bc1d22846b Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Thu, 2 Dec 2021 17:25:54 +0100 Subject: [PATCH 1309/1519] PHP 8.1 is the last release --- setup.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.rst b/setup.rst index 5df1a17b22c..adbec8c27a4 100644 --- a/setup.rst +++ b/setup.rst @@ -23,7 +23,7 @@ Before creating your first Symfony application you must: * Note that all newer, released versions of PHP will be supported during the lifetime of each Symfony release (including new major versions). - For example, PHP 8.0 is supported. + For example, PHP 8.1 is supported. * `Install Composer`_, which is used to install PHP packages. Optionally, you can also `install Symfony CLI`_. This creates a binary called From ced58a09bc9e6deb2f207f296ffa01dd73bccf92 Mon Sep 17 00:00:00 2001 From: BahmanMD Date: Thu, 2 Dec 2021 10:13:01 +0330 Subject: [PATCH 1310/1519] Update setup.rst (Symfony 5.3) --- setup.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/setup.rst b/setup.rst index 5381f7bcee8..c795feab42e 100644 --- a/setup.rst +++ b/setup.rst @@ -54,10 +54,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_name --full + $ symfony new my_project_name --version=5.3 --full # run this if you are building a microservice, console application or API - $ symfony new my_project_name + $ symfony new my_project_name --version=5.3 The only difference between these two commands is the number of packages installed by default. The ``--full`` option installs all the packages that you @@ -69,10 +69,10 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/website-skeleton my_project_name + $ composer create-project symfony/website-skeleton:"^5.3" my_project_name # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton my_project_name + $ composer create-project symfony/skeleton:"^5.3" my_project_name No matter which command you run to create the Symfony application. All of them will create a new ``my_project_name/`` directory, download some dependencies @@ -271,14 +271,14 @@ stable version. If you want to use an LTS version, add the ``--version`` option: $ symfony new my_project_name --version=next # you can also select an exact specific Symfony version - $ symfony new my_project_name --version=4.4 + $ symfony new my_project_name --version=5.4 The ``lts`` and ``next`` shortcuts are only available when using Symfony to create new projects. If you use Composer, you need to tell the exact version: .. code-block:: terminal - $ composer create-project symfony/skeleton:"^4.4" my_project_name + $ composer create-project symfony/skeleton:"^5.4" my_project_name The Symfony Demo application ---------------------------- From c10e3d807bc675b99203ca8fdb9549bf60745d99 Mon Sep 17 00:00:00 2001 From: BahmanMD Date: Thu, 2 Dec 2021 10:15:28 +0330 Subject: [PATCH 1311/1519] Update setup.rst (Symfony 5.4) --- setup.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.rst b/setup.rst index c795feab42e..bd8e018da8f 100644 --- a/setup.rst +++ b/setup.rst @@ -54,10 +54,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_name --version=5.3 --full + $ symfony new my_project_name --version=5.4 --full # run this if you are building a microservice, console application or API - $ symfony new my_project_name --version=5.3 + $ symfony new my_project_name --version=5.4 The only difference between these two commands is the number of packages installed by default. The ``--full`` option installs all the packages that you @@ -69,10 +69,10 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/website-skeleton:"^5.3" my_project_name + $ composer create-project symfony/website-skeleton:"^5.4" my_project_name # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton:"^5.3" my_project_name + $ composer create-project symfony/skeleton:"^5.4" my_project_name No matter which command you run to create the Symfony application. All of them will create a new ``my_project_name/`` directory, download some dependencies From 5720f50c52cb8164ba923a240e9c48b6b6e79e81 Mon Sep 17 00:00:00 2001 From: Sander De la Marche Date: Mon, 29 Nov 2021 21:03:00 +0100 Subject: [PATCH 1312/1519] Add UrlHelper section to HttpFoundation docs --- components/http_foundation.rst | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 6154119e715..ec3450a7ed0 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -783,6 +783,38 @@ The following example shows how to detect if the user agent prefers "safe" conte $response->setContentSafe(); return $response; + +UrlHelper +------- + +Generating absolute (and relative) URLs for a given path is a common need +in lots of applications. In Twig templates this is trivial thanks to the +absolute_url() and relative_path() functions. The same functionality can +be found in the :class:`Symfony\\Component\\HttpFoundation\\UrlHelper` class, +which can be injected as a service anywhere in your application. This class +provides two public methods called getAbsoluteUrl() and getRelativePath():: + + // src/Normalizer/UserApiNormalizer.php + + namespace App\Normalizer; + + use Symfony\Component\HttpFoundation\UrlHelper; + + class UserApiNormalizer + { + private UrlHelper $urlHelper; + + public function __construct(UrlHelper $urlHelper) + { + $this->urlHelper = $urlHelper; + } + + public function normalize($user) + { + return [ + 'avatar' => $this->urlHelper->getAbsoluteUrl($user->avatar()->path()), + ]; + } } Learn More From eee8c62280308ed2dadfea88fd0c9d1aa92eabe3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 3 Dec 2021 17:44:13 +0100 Subject: [PATCH 1313/1519] Minor reword --- components/http_foundation.rst | 23 ++++++++++++++--------- reference/twig_reference.rst | 4 ++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index ec3450a7ed0..344b88d6e99 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -784,18 +784,23 @@ The following example shows how to detect if the user agent prefers "safe" conte return $response; -UrlHelper -------- +Generating Relative and Absolute URLs +------------------------------------- -Generating absolute (and relative) URLs for a given path is a common need -in lots of applications. In Twig templates this is trivial thanks to the -absolute_url() and relative_path() functions. The same functionality can -be found in the :class:`Symfony\\Component\\HttpFoundation\\UrlHelper` class, -which can be injected as a service anywhere in your application. This class -provides two public methods called getAbsoluteUrl() and getRelativePath():: +.. versionadded:: 5.4 - // src/Normalizer/UserApiNormalizer.php + The feature to generate relative and absolute URLs was introduced in Symfony 5.4. + +Generating absolute and relative URLs for a given path is a common need +in some applications. In Twig templates you can use the +:ref:`absolute_url() ` and +:ref:`relative_path() ` functions to do that. +The :class:`Symfony\\Component\\HttpFoundation\\UrlHelper` class provides the +same functionality for PHP code via the ``getAbsoluteUrl()`` and ``getRelativePath()`` +methods. You can inject this as a service anywhere in your application:: + + // src/Normalizer/UserApiNormalizer.php namespace App\Normalizer; use Symfony\Component\HttpFoundation\UrlHelper; diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index e4991845096..d2246edef52 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -225,6 +225,8 @@ Returns the absolute URL (with scheme and host) for the given route. If Read more about :doc:`Symfony routing ` and about :ref:`creating links in Twig templates `. +.. _reference-twig-function-absolute-url: + absolute_url ~~~~~~~~~~~~ @@ -239,6 +241,8 @@ Returns the absolute URL (with scheme and host) from the passed relative path. C :ref:`asset() function ` to generate absolute URLs for web assets. Read more about :ref:`Linking to CSS, JavaScript and Image Assets `. +.. _reference-twig-function-relative-path: + relative_path ~~~~~~~~~~~~~ From 89f89f72972b275251cd42014577bfccfd1795c5 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 3 Dec 2021 17:45:00 +0100 Subject: [PATCH 1314/1519] Remove a versionadded directive --- components/http_foundation.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/components/http_foundation.rst b/components/http_foundation.rst index ab410bf19b8..3e2abc7288f 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -761,10 +761,6 @@ The following example shows how to detect if the user agent prefers "safe" conte Generating Relative and Absolute URLs ------------------------------------- -.. versionadded:: 5.4 - - The feature to generate relative and absolute URLs was introduced in Symfony 5.4. - Generating absolute and relative URLs for a given path is a common need in some applications. In Twig templates you can use the :ref:`absolute_url() ` and From d957600d184e852abc70ae4cdf7a3ec22887ce26 Mon Sep 17 00:00:00 2001 From: Guillaume HARARI Date: Fri, 3 Dec 2021 22:51:45 +0100 Subject: [PATCH 1315/1519] Update doctrine.rst Since 5.4, documentation inject ManagerRegistry but kept Doctrine\ORM\EntityManagerInterface in uses. --- doctrine.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doctrine.rst b/doctrine.rst index b2ac440d72a..4e1bc649d39 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -361,7 +361,7 @@ and save it:: // ... use App\Entity\Product; - use Doctrine\ORM\EntityManagerInterface; + use Doctrine\Persistence\ManagerRegistry; use Symfony\Component\HttpFoundation\Response; class ProductController extends AbstractController From 142731afab74430fda36d058616d31c53aa71425 Mon Sep 17 00:00:00 2001 From: jerzy-dudzic <30810342+jerzy-dudzic@users.noreply.github.com> Date: Sun, 5 Dec 2021 12:51:55 +0100 Subject: [PATCH 1316/1519] Removed not needed jQuery mention Removed mention of required jQuery library for example of "allow_add" in Form Collections. Since 5.3 example is pure javascript --- form/form_collections.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/form/form_collections.rst b/form/form_collections.rst index c58bf996235..078b74323e0 100644 --- a/form/form_collections.rst +++ b/form/form_collections.rst @@ -281,9 +281,7 @@ On the rendered page, the result will look something like this: and you need to adjust the following JavaScript accordingly. Now add some JavaScript to read this attribute and dynamically add new tag forms -when the user clicks the "Add a tag" link. This example uses `jQuery`_ and -assumes you have it included somewhere on your page (e.g. using Symfony's -:doc:`Webpack Encore `). +when the user clicks the "Add a tag" link. Add a `` + + See note below about the "defer" attribute --> {% endblock %} - + + + .. _encore-entrypointsjson-simple-description: @@ -130,27 +135,32 @@ filename(s) to render. This file is *especially* useful because you can :doc:`enable versioning ` or :doc:`point assets to a CDN ` without making *any* changes to your template: the paths in ``entrypoints.json`` will always be the final, correct paths. +And if you use :doc:`splitEntryChunks() ` (where Webpack splits the output into even +more files), all the necessary ``script`` and ``link`` tags will render automatically. If you're *not* using Symfony, you can ignore the ``entrypoints.json`` file and point to the final, built file directly. ``entrypoints.json`` is only required for some optional features. -.. versionadded:: 0.21.0 +.. versionadded:: 1.9.0 - The ``encore_entry_link_tags()`` comes from WebpackEncoreBundle and relies - on a feature in Encore that was first introduced in version 0.21.0. Previously, - the ``asset()`` function was used to point directly to the file. + The ``defer`` attribute on the ``script`` tags delays the execution of the + JavaScript until the page loads (similar to putting the ``script`` at the + bottom of the page). The ability to always add this attribute was introduced + in WebpackEncoreBundle 1.9.0 and is automatically enabled in that bundle's + recipe in the ``config/packages/webpack_encore.yaml`` file. See + `WebpackEncoreBundle Configuration`_ for more details. Requiring JavaScript Modules ---------------------------- -Webpack is a module bundler, which means that you can ``require`` other JavaScript +Webpack is a module bundler, which means that you can ``import`` other JavaScript files. First, create a file that exports a function: .. code-block:: javascript // assets/greet.js - module.exports = function(name) { + export default function(name) { return `Yo yo ${name} - welcome to Encore!`; }; @@ -158,21 +168,25 @@ We'll use jQuery to print this message on the page. Install it via: .. code-block:: terminal + # if you use the Yarn package manager $ yarn add jquery --dev -Great! Use ``require()`` to import ``jquery`` and ``greet.js``: + # if you use the npm package manager + $ npm install jquery --save-dev + +Great! Use ``import`` to import ``jquery`` and ``greet.js``: .. code-block:: diff - // assets/app.js - // ... + // assets/app.js + // ... + // loads the jquery package from node_modules - + var $ = require('jquery'); + + import jquery from 'jquery'; + // import the function from greet.js (the .js extension is optional) + // ./ (or ../) means to look for a local file - + var greet = require('./greet'); + + import greet from './greet'; + $(document).ready(function() { + $('body').prepend('

    '+greet('jill')+'

    '); @@ -182,37 +196,6 @@ That's it! If you previously ran ``encore dev --watch``, your final, built files have already been updated: jQuery and ``greet.js`` have been automatically added to the output file (``app.js``). Refresh to see the message! -The import and export Statements --------------------------------- - -Instead of using ``require()`` and ``module.exports`` like shown above, JavaScript -provides an alternate syntax based on the `ECMAScript 6 modules`_ that includes -the ability to use dynamic imports. - -To export values using the alternate syntax, use ``export``: - -.. code-block:: diff - - // assets/greet.js - - module.exports = function(name) { - + export default function(name) { - return `Yo yo ${name} - welcome to Encore!`; - }; - -To import values, use ``import``: - -.. code-block:: diff - - // assets/app.js - - require('../css/app.css'); - + import '../css/app.css'; - - - var $ = require('jquery'); - + import $ from 'jquery'; - - - var greet = require('./greet'); - + import greet from './greet'; - .. _multiple-javascript-entries: Page-Specific JavaScript or CSS (Multiple Entries) @@ -237,20 +220,24 @@ Next, use ``addEntry()`` to tell Webpack to read these two new files when it bui .. code-block:: diff - // webpack.config.js - Encore - // ... - .addEntry('app', './assets/app.js') + // webpack.config.js + Encore + // ... + .addEntry('app', './assets/app.js') + .addEntry('checkout', './assets/checkout.js') + .addEntry('account', './assets/account.js') - // ... + // ... And because you just changed the ``webpack.config.js`` file, make sure to stop and restart Encore: .. code-block:: terminal - $ yarn run encore dev --watch + # if you use the Yarn package manager + $ yarn encore dev --watch + + # if you use the npm package manager + $ npm run watch Webpack will now output a new ``checkout.js`` file and a new ``account.js`` file in your build directory. And, if any of those files require/import CSS, Webpack @@ -261,8 +248,8 @@ you need them: .. code-block:: diff - {# templates/.../checkout.html.twig #} - {% extends 'base.html.twig' %} + {# templates/.../checkout.html.twig #} + {% extends 'base.html.twig' %} + {% block stylesheets %} + {{ parent() }} @@ -291,37 +278,42 @@ file to ``app.scss`` and update the ``import`` statement: .. code-block:: diff - // assets/app.js - - import '../css/app.css'; - + import '../css/app.scss'; + // assets/app.js + - import './styles/app.css'; + + import './styles/app.scss'; Then, tell Encore to enable the Sass pre-processor: .. code-block:: diff - // webpack.config.js - Encore - // ... + // webpack.config.js + Encore + // ... + .enableSassLoader() - ; + ; Because you just changed your ``webpack.config.js`` file, you'll need to restart Encore. When you do, you'll see an error! .. code-block:: terminal - > Error: Install sass-loader & node-sass to use enableSassLoader() - > yarn add sass-loader@^8.0.0 node-sass --dev + > Error: Install sass-loader & sass to use enableSassLoader() + > yarn add sass-loader@^12.0.0 sass --dev Encore supports many features. But, instead of forcing all of them on you, when you need a feature, Encore will tell you what you need to install. Run: .. code-block:: terminal - $ yarn add sass-loader@^8.0.0 node-sass --dev + # if you use the Yarn package manager + $ yarn add sass-loader@^12.0.0 sass --dev $ yarn encore dev --watch + # if you use the npm package manager + $ npm install sass-loader@^12.0.0 sass --save-dev + $ npm run watch + Your app now supports Sass. Encore also supports LESS and Stylus. See :doc:`/frontend/encore/css-preprocessors`. @@ -354,4 +346,4 @@ Encore supports many more features! For a full list of what you can do, see `Encore's index.js file`_. Or, go back to :ref:`list of Encore articles `. .. _`Encore's index.js file`: https://github.com/symfony/webpack-encore/blob/master/index.js -.. _`ECMAScript 6 modules`: https://hacks.mozilla.org/2015/08/es6-in-depth-modules/ +.. _`WebpackEncoreBundle Configuration`: https://github.com/symfony/webpack-encore-bundle#configuration diff --git a/frontend/encore/split-chunks.rst b/frontend/encore/split-chunks.rst index 0205537b7d0..7739b0a49c6 100644 --- a/frontend/encore/split-chunks.rst +++ b/frontend/encore/split-chunks.rst @@ -10,22 +10,24 @@ To enable this, call ``splitEntryChunks()``: .. code-block:: diff - Encore - // ... + // webpack.config.js + Encore + // ... - // multiple entry files, which probably import the same code - .addEntry('app', './assets/app.js') - .addEntry('homepage', './assets/homepage.js') - .addEntry('blog', './assets/blog.js') - .addEntry('store', './assets/store.js') + // multiple entry files, which probably import the same code + .addEntry('app', './assets/app.js') + .addEntry('homepage', './assets/homepage.js') + .addEntry('blog', './assets/blog.js') + .addEntry('store', './assets/store.js') + .splitEntryChunks() Now, each output file (e.g. ``homepage.js``) *may* be split into multiple file -(e.g. ``homepage.js``, ``vendor~homepage.js``). This means that you *may* need to -include *multiple* ``script`` tags (or ``link`` tags for CSS) in your template. -Encore creates an :ref:`entrypoints.json ` +(e.g. ``homepage.js`` & ``vendors-node_modules_jquery_dist_jquery_js.js`` - the +filename of the second will be less obvious when you build for production). This +means that you *may* need to include *multiple* ``script`` tags (or ``link`` tags +for CSS) in your template. Encore creates an :ref:`entrypoints.json ` file that lists exactly which CSS and JavaScript files are needed for each entry. If you're using the ``encore_entry_link_tags()`` and ``encore_entry_script_tags()`` @@ -37,9 +39,9 @@ tags as needed: {# May now render multiple script tags: - - - + + + #} {{ encore_entry_script_tags('homepage') }} @@ -52,10 +54,11 @@ this plugin with the ``configureSplitChunks()`` function: .. code-block:: diff - Encore - // ... + // webpack.config.js + Encore + // ... - .splitEntryChunks() + .splitEntryChunks() + .configureSplitChunks(function(splitChunks) { + // change the configuration + splitChunks.minSize = 0; diff --git a/frontend/encore/typescript.rst b/frontend/encore/typescript.rst index b1af45d9c04..103f1f0b293 100644 --- a/frontend/encore/typescript.rst +++ b/frontend/encore/typescript.rst @@ -5,20 +5,24 @@ Want to use `TypeScript`_? No problem! First, enable it: .. code-block:: diff - // webpack.config.js - // ... + // webpack.config.js - Encore - // ... + // ... + Encore + // ... + .addEntry('main', './assets/main.ts') + .enableTypeScriptLoader() - // optionally enable forked type script for faster builds - // https://www.npmjs.com/package/fork-ts-checker-webpack-plugin - // requires that you have a tsconfig.json file that is setup correctly. + // optionally enable forked type script for faster builds + // https://www.npmjs.com/package/fork-ts-checker-webpack-plugin + // requires that you have a tsconfig.json file that is setup correctly. + //.enableForkedTypeScriptTypesChecking() - ; + ; + +Then create an empty ``tsconfig.json`` file with the contents ``{}`` in the project +root folder (or in the folder where your TypeScript files are located; e.g. ``assets/``). +In ``tsconfig.json`` you can define more options, as shown in `tsconfig.json reference`_. Then restart Encore. When you do, it will give you a command you can run to install any missing dependencies. After running that command and restarting @@ -30,9 +34,10 @@ method. .. code-block:: diff - Encore - // ... - .addEntry('main', './assets/main.ts') + // webpack.config.js + Encore + // ... + .addEntry('main', './assets/main.ts') - .enableTypeScriptLoader() + .enableTypeScriptLoader(function(tsConfig) { @@ -42,8 +47,8 @@ method. + // tsConfig.silent = false + }) - // ... - ; + // ... + ; See the `Encore's index.js file`_ for detailed documentation and check out the `tsconfig.json reference`_ and the `Webpack guide about Typescript`_. diff --git a/frontend/encore/url-loader.rst b/frontend/encore/url-loader.rst index 976cd6974d8..5e89234f295 100644 --- a/frontend/encore/url-loader.rst +++ b/frontend/encore/url-loader.rst @@ -1,18 +1,11 @@ -Inlining files in CSS with Webpack URL Loader -============================================= +Inlining Images & Fonts in CSS +============================== A simple technique to improve the performance of web applications is to reduce the number of HTTP requests inlining small files as base64 encoded URLs in the generated CSS files. -Webpack Encore provides this feature via Webpack's `URL Loader`_ plugin, but -it's disabled by default. First, add the URL loader to your project: - -.. code-block:: terminal - - $ yarn add url-loader --dev - -Then enable it in your ``webpack.config.js``: +You can enable this in ``webpack.config.js`` for images, fonts or both: .. code-block:: javascript @@ -21,31 +14,19 @@ Then enable it in your ``webpack.config.js``: Encore // ... - .configureUrlLoader({ - fonts: { limit: 4096 }, - images: { limit: 4096 } + .configureImageRule({ + // tell Webpack it should consider inlining + type: 'asset', + //maxSize: 4 * 1024, // 4 kb - the default is 8kb }) - ; - -The ``limit`` option defines the maximum size in bytes of the inlined files. In -the previous example, font and image files having a size below or equal to 4 KB -will be inlined and the rest of files will be processed as usual. - -You can also use all the other options supported by the `URL Loader`_. If you -want to disable this loader for either images or fonts, remove the corresponding -key from the object that is passed to the ``configureUrlLoader()`` method: - -.. code-block:: javascript - - // webpack.config.js - // ... - Encore - // ... - .configureUrlLoader({ - // 'fonts' is not defined, so only images will be inlined - images: { limit: 4096 } + .configureFontRule({ + type: 'asset', + //maxSize: 4 * 1024 }) ; -.. _`URL Loader`: https://github.com/webpack-contrib/url-loader +This leverages Webpack `Asset Modules`_. You can read more about this and the +configuration there. + +.. _`Asset Modules`: https://webpack.js.org/guides/asset-modules/ diff --git a/frontend/encore/versioning.rst b/frontend/encore/versioning.rst index 1f3d0cdd39e..6fe8a8275cd 100644 --- a/frontend/encore/versioning.rst +++ b/frontend/encore/versioning.rst @@ -7,17 +7,17 @@ Tired of deploying and having browser's cache the old version of your assets? By calling ``enableVersioning()``, each filename will now include a hash that changes whenever the *contents* of that file change (e.g. ``app.123abc.js`` instead of ``app.js``). This allows you to use aggressive caching strategies -(e.g. a far future ``Expires``) because, whenever a file change, its hash will change, +(e.g. a far future ``Expires``) because, whenever a file changes, its hash will change, ignoring any existing cache: .. code-block:: diff - // webpack.config.js - // ... + // webpack.config.js - Encore - .setOutputPath('public/build/') - // ... + // ... + Encore + .setOutputPath('public/build/') + // ... + .enableVersioning() To link to these assets, Encore creates two files ``entrypoints.json`` and @@ -28,11 +28,12 @@ To link to these assets, Encore creates two files ``entrypoints.json`` and Loading Assets from ``entrypoints.json`` & ``manifest.json`` ------------------------------------------------------------ -Whenever you run Encore, two configuration files are generated: ``entrypoints.json`` +Whenever you run Encore, two configuration files are generated in your +output folder (default location: ``public/build/``): ``entrypoints.json`` and ``manifest.json``. Each file is similar, and contains a map to the final, versioned -filename. +filenames. -The first file - ``entrypoints.json`` - is used by the ``encore_entry_script_tags()`` +The first file – ``entrypoints.json`` – is used by the ``encore_entry_script_tags()`` and ``encore_entry_link_tags()`` Twig helpers. If you're using these, then your CSS and JavaScript files will render with the new, versioned filename. If you're not using Symfony, your app will need to read this file in a similar way. diff --git a/frontend/encore/virtual-machine.rst b/frontend/encore/virtual-machine.rst index 068d5c8451f..23010b9f169 100644 --- a/frontend/encore/virtual-machine.rst +++ b/frontend/encore/virtual-machine.rst @@ -49,14 +49,14 @@ If your Symfony application is running on a custom domain (e.g. .. code-block:: diff - { - ... - "scripts": { + { + ... + "scripts": { - "dev-server": "encore dev-server", + "dev-server": "encore dev-server --public http://app.vm:8080", - ... - } - } + ... + } + } After restarting Encore and reloading your web page, you will probably see different issues in the web console: @@ -78,14 +78,14 @@ connections: .. code-block:: diff - { - ... - "scripts": { + { + ... + "scripts": { - "dev-server": "encore dev-server --public http://app.vm:8080", + "dev-server": "encore dev-server --public http://app.vm:8080 --host 0.0.0.0", - ... - } - } + ... + } + } .. caution:: @@ -96,26 +96,27 @@ Fix "Invalid Host header" Issue ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Webpack will respond ``Invalid Host header`` when trying to access files from -the dev-server. To fix this, add the argument ``--disable-host-check``: +the dev-server. To fix this, set the ``firewall`` option: -.. code-block:: diff +.. code-block:: javascript + + // webpack.config.js + // ... + + Encore + // ... - { - ... - "scripts": { - - "dev-server": "encore dev-server --public http://app.vm:8080 --host 0.0.0.0", - + "dev-server": "encore dev-server --public http://app.vm:8080 --host 0.0.0.0 --disable-host-check", - ... - } - } + .configureDevServerOptions(options => { + options.firewall = false; + }) .. caution:: - Beware that `it's not recommended to disable host checking`_ in general, but + Beware that `it's not recommended to disable the firewall`_ in general, but here it's required to solve the issue when using Encore in a virtual machine. .. _`VirtualBox`: https://www.virtualbox.org/ .. _`VMWare`: https://www.vmware.com .. _`NFS`: https://en.wikipedia.org/wiki/Network_File_System .. _`polling`: https://webpack.js.org/configuration/watch/#watchoptionspoll -.. _`it's not recommended to disable host checking`: https://webpack.js.org/configuration/dev-server/#devserverdisablehostcheck +.. _`it's not recommended to disable the firewall`: https://webpack.js.org/configuration/dev-server/#devserverdisablehostcheck diff --git a/frontend/encore/vuejs.rst b/frontend/encore/vuejs.rst index 3d10eedcd41..896c1e6de19 100644 --- a/frontend/encore/vuejs.rst +++ b/frontend/encore/vuejs.rst @@ -10,15 +10,15 @@ Want to use `Vue.js`_? No problem! First enable it in ``webpack.config.js``: .. code-block:: diff - // webpack.config.js - // ... + // webpack.config.js + // ... - Encore - // ... - .addEntry('main', './assets/main.js') + Encore + // ... + .addEntry('main', './assets/main.js') + .enableVueLoader() - ; + ; Then restart Encore. When you do, it will give you a command you can run to install any missing dependencies. After running that command and restarting @@ -45,7 +45,7 @@ runtime. This means that you *can* do either of these: }); If you do *not* need this functionality (e.g. you use single file components), -then you can tell Encore to create a *smaller* and CSP-compliant build: +then you can tell Encore to create a *smaller* build following Content Security Policy: .. code-block:: javascript @@ -65,11 +65,15 @@ Hot Module Replacement (HMR) The ``vue-loader`` supports hot module replacement: just update your code and watch your Vue.js app update *without* a browser refresh! To activate it, use the -``dev-server`` with the ``--hot`` option: +``dev-server``: .. code-block:: terminal - $ yarn encore dev-server --hot + # if you use the Yarn package manager + $ yarn encore dev-server + + # if you use the npm package manager + $ npm run dev-server That's it! Change one of your ``.vue`` files and watch your browser update. But note: this does *not* currently work for *style* changes in a ``.vue`` file. Seeing @@ -85,18 +89,18 @@ You can enable `JSX with Vue.js`_ by configuring the second parameter of the .. code-block:: diff - // webpack.config.js - // ... + // webpack.config.js + // ... - Encore - // ... - .addEntry('main', './assets/main.js') + Encore + // ... + .addEntry('main', './assets/main.js') - .enableVueLoader() + .enableVueLoader(() => {}, { + useJsx: true + }) - ; + ; Next, run or restart Encore. When you do, you will see an error message helping you install any missing dependencies. After running that command and restarting diff --git a/http_cache.rst b/http_cache.rst index 3e444c2d2b6..35620d1cd76 100644 --- a/http_cache.rst +++ b/http_cache.rst @@ -93,20 +93,20 @@ caching kernel: .. code-block:: diff - // public/index.php + // public/index.php + use App\CacheKernel; - use App\Kernel; + use App\Kernel; - // ... - $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); + // ... + $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); + // Wrap the default Kernel with the CacheKernel one in 'prod' environment + if ('prod' === $kernel->getEnvironment()) { + $kernel = new CacheKernel($kernel); + } - $request = Request::createFromGlobals(); - // ... + $request = Request::createFromGlobals(); + // ... The caching kernel will immediately act as a reverse proxy: caching responses from your application and returning them to the client. @@ -155,7 +155,7 @@ header to the response. You can also use the ``trace_level`` config option and set it to either ``none``, ``short`` or ``full`` to add this information. -``short`` will add the information for the master request only. +``short`` will add the information for the main request only. It's written in a concise way that makes it easy to record the information in your server log files. For example, in Apache you can use ``%{X-Symfony-Cache}o`` in ``LogFormat`` format statements. @@ -310,7 +310,7 @@ Safe Methods: Only caching GET or HEAD requests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HTTP caching only works for "safe" HTTP methods (like GET and HEAD). This means -two things: +three things: * Don't try to cache PUT or DELETE requests. It won't work and with good reason. These methods are meant to be used when mutating the state of your application diff --git a/http_cache/esi.rst b/http_cache/esi.rst index 621f604ea95..7229608665e 100644 --- a/http_cache/esi.rst +++ b/http_cache/esi.rst @@ -88,10 +88,13 @@ First, to use ESI, be sure to enable it in your application configuration: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - // ... - 'esi' => ['enabled' => true], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->esi() + ->enabled(true) + ; + }; Now, suppose you have a page that is relatively static, except for a news ticker at the bottom of the content. With ESI, you can cache the news ticker @@ -99,7 +102,7 @@ independently of the rest of the page:: // src/Controller/DefaultController.php namespace App\Controller; - + // ... class DefaultController extends AbstractController { @@ -156,12 +159,12 @@ used ``render()``. .. note:: - Symfony detects if a gateway cache supports ESI via another Akamai - specification that is supported out of the box by the Symfony reverse - proxy. + Symfony considers that a gateway cache supports ESI if its request include + the ``Surrogate-Capability`` HTTP header and the value of that header + contains the ``ESI/1.0`` string anywhere. The embedded action can now specify its own caching rules entirely independently -of the master page:: +of the main page:: // src/Controller/NewsController.php namespace App\Controller; @@ -171,9 +174,8 @@ of the master page:: { public function latest($maxPerPage) { - // ... - $response->setPublic(); - $response->setMaxAge(60); + // sets to public and adds some expiration + $response->setSharedMaxAge(60); return $response; } @@ -225,10 +227,14 @@ that must be enabled in your configuration: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'fragments' => ['path' => '/_fragment'], - ]); + $framework->fragments() + ->path('/_fragment') + ; + }; One great advantage of the ESI renderer is that you can make your application as dynamic as needed and at the same time, hit the application as little as diff --git a/http_cache/expiration.rst b/http_cache/expiration.rst index d30893b58fe..ae436e631ee 100644 --- a/http_cache/expiration.rst +++ b/http_cache/expiration.rst @@ -34,7 +34,7 @@ additional directives): .. code-block:: text - Cache-Control: public, maxage=600 + Cache-Control: public, max-age=600 .. note:: diff --git a/http_cache/ssi.rst b/http_cache/ssi.rst index 94bab702db4..82654222f17 100644 --- a/http_cache/ssi.rst +++ b/http_cache/ssi.rst @@ -76,9 +76,13 @@ First, to use SSI, be sure to enable it in your application configuration: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'ssi' => ['enabled' => true], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->ssi() + ->enabled(true) + ; + }; Suppose you have a page with private content like a Profile page and you want to cache a static GDPR content block. With SSI, you can add some expiration @@ -86,7 +90,7 @@ on this block and keep the page private:: // src/Controller/ProfileController.php namespace App\Controller; - + // ... class ProfileController extends AbstractController { @@ -126,7 +130,7 @@ The ``render_ssi`` twig helper will generate something like: -``render_ssi`` ensures that SSI directive are generated only if the request +``render_ssi`` ensures that SSI directive is generated only if the request has the header requirement like ``Surrogate-Capability: device="SSI/1.0"`` (normally given by the web server). Otherwise it will embed directly the sub-response. diff --git a/http_cache/validation.rst b/http_cache/validation.rst index 3a1dabf902e..599d0883b52 100644 --- a/http_cache/validation.rst +++ b/http_cache/validation.rst @@ -106,7 +106,7 @@ doing so much work. .. tip:: - Symfony also supports weak ``ETag``s by passing ``true`` as the second + Symfony also supports weak ``ETag`` s by passing ``true`` as the second argument to the :method:`Symfony\\Component\\HttpFoundation\\Response::setEtag` method. diff --git a/http_client.rst b/http_client.rst index 2fb102a0fcc..43109959e35 100644 --- a/http_client.rst +++ b/http_client.rst @@ -116,20 +116,21 @@ You can configure the global options using the ``default_options`` option: - + .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'http_client' => [ - 'default_options' => [ - 'max_redirects' => 7, - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->httpClient() + ->defaultOptions() + ->maxRedirects(7) + ; + }; .. code-block:: php-standalone @@ -137,6 +138,18 @@ You can configure the global options using the ``default_options`` option: 'max_redirects' => 7, ]); +You can also use the :method:`Symfony\\Contracts\\HttpClient\\HttpClientInterface::withOptions` +method to retrieve a new instance of the client with new default options:: + + $this->client = $client->withOptions([ + 'base_uri' => 'https://...', + 'headers' => ['header-name' => 'header-value'] + ]); + +.. versionadded:: 5.3 + + The ``withOptions()`` method was introduced in Symfony 5.3. + Some options are described in this guide: * `Authentication`_ @@ -176,19 +189,21 @@ The HTTP client also has one configuration option called - + .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'http_client' => [ - 'max_host_connections' => 10, + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->httpClient() + ->maxHostConnections(10) // ... - ], - ]); + ; + }; .. code-block:: php-standalone @@ -212,7 +227,7 @@ autoconfigure the HTTP client based on the requested URL: http_client: scoped_clients: # only requests matching scope will use these options - github: + github.client: scope: 'https://api\.github\.com' headers: Accept: 'application/vnd.github.v3+json' @@ -221,7 +236,7 @@ autoconfigure the HTTP client based on the requested URL: # using base_uri, relative URLs (e.g. request("GET", "/repos/symfony/symfony-docs")) # will default to these options - github: + github.client: base_uri: 'https://api.github.com' headers: Accept: 'application/vnd.github.v3+json' @@ -242,7 +257,7 @@ autoconfigure the HTTP client based on the requested URL: - application/vnd.github.v3+json @@ -251,7 +266,7 @@ autoconfigure the HTTP client based on the requested URL: - application/vnd.github.v3+json @@ -264,32 +279,26 @@ autoconfigure the HTTP client based on the requested URL: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'http_client' => [ - 'scoped_clients' => [ - // only requests matching scope will use these options - 'github' => [ - 'scope' => 'https://api\.github\.com', - 'headers' => [ - 'Accept' => 'application/vnd.github.v3+json', - 'Authorization' => 'token %env(GITHUB_API_TOKEN)%', - ], - // ... - ], - - // using base_url, relative URLs (e.g. request("GET", "/repos/symfony/symfony-docs")) - // will default to these options - 'github' => [ - 'base_uri' => 'https://api.github.com', - 'headers' => [ - 'Accept' => 'application/vnd.github.v3+json', - 'Authorization' => 'token %env(GITHUB_API_TOKEN)%', - ], - // ... - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + // only requests matching scope will use these options + $framework->httpClient()->scopedClient('github.client') + ->scope('https://api\.github\.com') + ->header('Accept', 'application/vnd.github.v3+json') + ->header('Authorization', 'token %env(GITHUB_API_TOKEN)%') + // ... + ; + + // using base_url, relative URLs (e.g. request("GET", "/repos/symfony/symfony-docs")) + // will default to these options + $framework->httpClient()->scopedClient('github.client') + ->baseUri('https://api.github.com') + ->header('Accept', 'application/vnd.github.v3+json') + ->header('Authorization', 'token %env(GITHUB_API_TOKEN)%') + // ... + ; + }; .. code-block:: php-standalone @@ -326,10 +335,16 @@ Each client has a unique service named after its configuration. Each scoped client also defines a corresponding named autowiring alias. If you use for example -``Symfony\Contracts\HttpClient\HttpClientInterface $myApiClient`` -as the type and name of an argument, autowiring will inject the ``my_api.client`` +``Symfony\Contracts\HttpClient\HttpClientInterface $githubClient`` +as the type and name of an argument, autowiring will inject the ``github.client`` service into your autowired classes. +.. note:: + + Read the :ref:`base_uri option docs ` to + learn the rules applied when merging relative URIs into the base URI of the + scoped client. + Making Requests --------------- @@ -419,31 +434,28 @@ each request (which overrides any global authentication): auth-bearer="the-bearer-token" auth-ntlm="the-username:the-password" /> - + .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'http_client' => [ - 'scoped_clients' => [ - 'example_api' => [ - 'base_uri' => 'https://example.com/', + use Symfony\Config\FrameworkConfig; - // HTTP Basic authentication - 'auth_basic' => 'the-username:the-password', + return static function (FrameworkConfig $framework) { + $framework->httpClient()->scopedClient('example_api') + ->baseUri('https://example.com/') + // HTTP Basic authentication + ->authBasic('the-username:the-password') - // HTTP Bearer authentication (also called token authentication) - 'auth_bearer' => 'the-bearer-token', + // HTTP Bearer authentication (also called token authentication) + ->authBearer('the-bearer-token') - // Microsoft NTLM authentication - 'auth_ntlm' => 'the-username:the-password', - ], - ], - ], - ]); + // Microsoft NTLM authentication + ->authNtlm('the-username:the-password') + ; + }; .. code-block:: php-standalone @@ -495,8 +507,7 @@ associative array via the ``query`` option, that will be merged with the URL:: Headers ~~~~~~~ -Use the ``headers`` option to define both the default headers added to all -requests and the specific headers for each request: +Use the ``headers`` option to define the default headers added to all requests: .. configuration-block:: @@ -505,8 +516,9 @@ requests and the specific headers for each request: # config/packages/framework.yaml framework: http_client: - headers: - 'User-Agent': 'My Fancy App' + default_options: + headers: + 'User-Agent': 'My Fancy App' .. code-block:: xml @@ -521,21 +533,24 @@ requests and the specific headers for each request: - My Fancy App - + + My Fancy App + + .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'http_client' => [ - 'headers' => [ - 'User-Agent' => 'My Fancy App', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->httpClient() + ->defaultOptions() + ->header('User-Agent', 'My Fancy App') + ; + }; .. code-block:: php-standalone @@ -546,7 +561,7 @@ requests and the specific headers for each request: ], ]); -.. code-block:: php +You can also set new headers or override the default ones for specific requests:: // this header is only included in this request and overrides the value // of the same header if defined globally by the HTTP client @@ -757,6 +772,48 @@ called when new data is uploaded or downloaded and at least once per second:: Any exceptions thrown from the callback will be wrapped in an instance of ``TransportExceptionInterface`` and will abort the request. +HTTPS Certificates +~~~~~~~~~~~~~~~~~~ + +HttpClient uses the system's certificate store to validate SSL certificates +(while browsers use their own stores). When using self-signed certificates +during development, it's recommended to create your own certificate authority +(CA) and add it to your system's store. + +Alternatively, you can also disable ``verify_host`` and ``verify_peer`` (see +:ref:`http_client config reference `), but this is not +recommended in production. + +SSRF (Server-side request forgery) Handling +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.1 + + The SSRF protection was introduced in Symfony 5.1. + +`SSRF`_ allows an attacker to induce the backend application to make HTTP +requests to an arbitrary domain. These attacks can also target the internal +hosts and IPs of the attacked server. + +If you use an ``HttpClient`` together with user-provided URIs, it is probably a +good idea to decorate it with a ``NoPrivateNetworkHttpClient``. This will +ensure local networks are made inaccessible to the HTTP client:: + + use Symfony\Component\HttpClient\HttpClient; + use Symfony\Component\HttpClient\NoPrivateNetworkHttpClient; + + $client = new NoPrivateNetworkHttpClient(HttpClient::create()); + // nothing changes when requesting public networks + $client->request('GET', 'https://example.com/'); + + // however, all requests to private networks are now blocked by default + $client->request('GET', 'http://localhost/'); + + // the second optional argument defines the networks to block + // in this example, requests from 104.26.14.0 to 104.26.15.255 will result in an exception + // but all the other requests, including other internal networks, will be allowed + $client = new NoPrivateNetworkHttpClient(HttpClient::create(), ['104.26.14.0/23']); + Performance ----------- @@ -813,9 +870,9 @@ Add an ``extra.curl`` option in your configuration to pass those extra options:: // ... 'extra' => [ 'curl' => [ - CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V6 - ] - ] + CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V6, + ], + ], ]); .. note:: @@ -848,7 +905,8 @@ To force HTTP/2 for ``http`` URLs, you need to enable it explicitly via the # config/packages/framework.yaml framework: http_client: - http_version: '2.0' + default_options: + http_version: '2.0' .. code-block:: xml @@ -862,18 +920,23 @@ To force HTTP/2 for ``http`` URLs, you need to enable it explicitly via the http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + + + .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'http_client' => [ - 'http_version' => '2.0', - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->httpClient() + ->defaultOptions() + ->httpVersion('2.0') + ; + }; .. code-block:: php-standalone @@ -916,6 +979,8 @@ following methods:: // you can get individual info too $startTime = $response->getInfo('start_time'); + // e.g. this returns the final response URL (resolving redirections if needed) + $url = $response->getInfo('url'); // returns detailed logs about the requests and responses of the HTTP transaction $httpLogs = $response->getInfo('debug'); @@ -964,7 +1029,7 @@ To abort a request (e.g. because it didn't complete in due time, or you want to fetch only the first bytes of the response, etc.), you can either use the ``cancel()`` method of ``ResponseInterface``:: - $response->cancel() + $response->cancel(); Or throw an exception from a progress callback:: @@ -985,21 +1050,32 @@ In case the response was canceled using ``$response->cancel()``, Handling Exceptions ~~~~~~~~~~~~~~~~~~~ +There are three types of exceptions, all of which implement the +:class:`Symfony\\Contracts\\HttpClient\\Exception\\ExceptionInterface`: + +* Exceptions implementing the :class:`Symfony\\Contracts\\HttpClient\\Exception\\HttpExceptionInterface` + are thrown when your code does not handle the status codes in the 300-599 range. + +* Exceptions implementing the :class:`Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface` + are thrown when a lower level issue occurs. + +* Exceptions implementing the :class:`Symfony\\Contracts\\HttpClient\\Exception\\DecodingExceptionInterface` + are thrown when a content-type cannot be decoded to the expected representation. + When the HTTP status code of the response is in the 300-599 range (i.e. 3xx, -4xx or 5xx) your code is expected to handle it. If you don't do that, the -``getHeaders()``, ``getContent()`` and ``toArray()`` methods throw an appropriate exception, all of -which implement the :class:`Symfony\\Contracts\\HttpClient\\Exception\\HttpExceptionInterface`:: +4xx or 5xx), the ``getHeaders()``, ``getContent()`` and ``toArray()`` methods +throw an appropriate exception, all of which implement the +:class:`Symfony\\Contracts\\HttpClient\\Exception\\HttpExceptionInterface`. - // the response of this request will be a 403 HTTP error - $response = $client->request('GET', 'https://httpbin.org/status/403'); +To opt-out from this exception and deal with 300-599 status codes on your own, +pass ``false`` as the optional argument to every call of those methods, +e.g. ``$response->getHeaders(false);``. - // this code results in a Symfony\Component\HttpClient\Exception\ClientException - // because it doesn't check the status code of the response - $content = $response->getContent(); +If you do not call any of these 3 methods at all, the exception will still be thrown +when the ``$response`` object is destructed. - // pass FALSE as the optional argument to not throw an exception and return - // instead the original response content (even if it's an error message) - $content = $response->getContent(false); +Calling ``$response->getStatusCode()`` is enough to disable this behavior +(but then don't miss checking the status code yourself). While responses are lazy, their destructor will always wait for headers to come back. This means that the following request *will* complete; and if e.g. a 404 @@ -1026,19 +1102,9 @@ responses in an array:: This behavior provided at destruction-time is part of the fail-safe design of the component. No errors will be unnoticed: if you don't write the code to handle errors, exceptions will notify you when needed. On the other hand, if you write -the error-handling code, you will opt-out from these fallback mechanisms as the -destructor won't have anything remaining to do. - -There are three types of exceptions: - -* Exceptions implementing the :class:`Symfony\\Contracts\\HttpClient\\Exception\\HttpExceptionInterface` - are thrown when your code does not handle the status codes in the 300-599 range. - -* Exceptions implementing the :class:`Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface` - are thrown when a lower level issue occurs. - -* Exceptions implementing the :class:`Symfony\\Contracts\\HttpClient\\Exception\\DecodingExceptionInterface` - are thrown when a content-type cannot be decoded to the expected representation. +the error-handling code (by calling ``$response->getStatusCode()``), you will +opt-out from these fallback mechanisms as the destructor won't have anything +remaining to do. Concurrent Requests ------------------- @@ -1064,6 +1130,13 @@ first and be read later on. This will allow the client to monitor all pending requests while your code waits for a specific one, as done in each iteration of the above "foreach" loop. +.. note:: + + The maximum number of concurrent requests that you can perform depends on + the resources of your machine (e.g. your operating system may limit the + number of simultaneous reads of the file that stores the certificates + file). Make your requests in batches to avoid these issues. + Multiplexing Responses ~~~~~~~~~~~~~~~~~~~~~~ @@ -1238,6 +1311,7 @@ server-sent events. Use the :class:`Symfony\\Component\\HttpClient\\EventSourceH to wrap your HTTP client, open a connection to a server that responds with a ``text/event-stream`` content type and consume the stream as follows:: + use Symfony\Component\HttpClient\Chunk\ServerSentEvent; use Symfony\Component\HttpClient\EventSourceHttpClient; // the second optional argument is the reconnection time in seconds (default = 10) @@ -1480,12 +1554,131 @@ This allows using them where native PHP streams are needed:: // later on if you need to, you can access the response from the stream $response = stream_get_meta_data($streamResource)['wrapper_data']->getResponse(); -Testing HTTP Clients and Responses ----------------------------------- +Extensibility +------------- + +If you want to extend the behavior of a base HTTP client, you can use +:doc:`service decoration `:: + + class MyExtendedHttpClient implements HttpClientInterface + { + private $decoratedClient; + + public function __construct(HttpClientInterface $decoratedClient = null) + { + $this->decoratedClient = $decoratedClient ?? HttpClient::create(); + } + + public function request(string $method, string $url, array $options = []): ResponseInterface + { + // process and/or change the $method, $url and/or $options as needed + $response = $this->decoratedClient->request($method, $url, $options); + + // if you call here any method on $response, the HTTP request + // won't be async; see below for a better way + + return $response; + } + + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + return $this->decoratedClient->stream($responses, $timeout); + } + } + +A decorator like this one is useful in cases where processing the requests' +arguments is enough. By decorating the ``on_progress`` option, you can +even implement basic monitoring of the response. However, since calling +responses' methods forces synchronous operations, doing so inside ``request()`` +will break async. + +The solution is to also decorate the response object itself. +:class:`Symfony\\Component\\HttpClient\\TraceableHttpClient` and +:class:`Symfony\\Component\\HttpClient\\Response\\TraceableResponse` are good +examples as a starting point. + +.. versionadded:: 5.2 + + ``AsyncDecoratorTrait`` was introduced in Symfony 5.2. + +In order to help writing more advanced response processors, the component provides +an :class:`Symfony\\Component\\HttpClient\\AsyncDecoratorTrait`. This trait allows +processing the stream of chunks as they come back from the network:: + + class MyExtendedHttpClient implements HttpClientInterface + { + use AsyncDecoratorTrait; + + public function request(string $method, string $url, array $options = []): ResponseInterface + { + // process and/or change the $method, $url and/or $options as needed + + $passthru = function (ChunkInterface $chunk, AsyncContext $context) { + // do what you want with chunks, e.g. split them + // in smaller chunks, group them, skip some, etc. + + yield $chunk; + }; + + return new AsyncResponse($this->client, $method, $url, $options, $passthru); + } + } + +Because the trait already implements a constructor and the ``stream()`` method, +you don't need to add them. The ``request()`` method should still be defined; +it shall return an +:class:`Symfony\\Component\\HttpClient\\Response\\AsyncResponse`. + +The custom processing of chunks should happen in ``$passthru``: this generator +is where you need to write your logic. It will be called for each chunk yielded +by the underlying client. A ``$passthru`` that does nothing would just ``yield +$chunk;``. You could also yield a modified chunk, split the chunk into many +ones by yielding several times, or even skip a chunk altogether by issuing a +``return;`` instead of yielding. + +In order to control the stream, the chunk passthru receives an +:class:`Symfony\\Component\\HttpClient\\Response\\AsyncContext` as second +argument. This context object has methods to read the current state of the +response. It also allows altering the response stream with methods to create +new chunks of content, pause the stream, cancel the stream, change the info of +the response, replace the current request by another one or change the chunk +passthru itself. + +Checking the test cases implemented in +:class:`Symfony\\Component\\HttpClient\\Tests\\AsyncDecoratorTraitTest` +might be a good start to get various working examples for a better understanding. +Here are the use cases that it simulates: + +* retry a failed request; +* send a preflight request, e.g. for authentication needs; +* issue subrequests and include their content in the main response's body. + +The logic in :class:`Symfony\\Component\\HttpClient\\Response\\AsyncResponse` +has many safety checks that will throw a ``LogicException`` if the chunk +passthru doesn't behave correctly; e.g. if a chunk is yielded after an ``isLast()`` +one, or if a content chunk is yielded before an ``isFirst()`` one, etc. + +Testing +------- This component includes the ``MockHttpClient`` and ``MockResponse`` classes to -use them in tests that need an HTTP client which doesn't make actual HTTP -requests. +use in tests that shouldn't make actual HTTP requests. Such tests can be +useful, as they will run faster and produce consistent results, since they're +not dependent on an external service. By not making actual HTTP requests there +is no need to worry about the service being online or the request changing +state, for example deleting a resource. + +``MockHttpClient`` implements the ``HttpClientInterface``, just like any actual +HTTP client in this component. When you type-hint with ``HttpClientInterface`` +your code will accept the real client outside tests, while replacing it with +``MockHttpClient`` in the test. + +When the ``request`` method is used on ``MockHttpClient``, it will respond with +the supplied ``MockResponse``. There are a few ways to use it, as described +below. + +HTTP Client and Responses +~~~~~~~~~~~~~~~~~~~~~~~~~ The first way of using ``MockHttpClient`` is to pass a list of responses to its constructor. These will be yielded in order when requests are made:: @@ -1516,6 +1709,19 @@ responses dynamically when it's called:: $client = new MockHttpClient($callback); $response = $client->request('...'); // calls $callback to get the response +If you need to test responses with HTTP status codes different than 200, +define the ``http_code`` option:: + + use Symfony\Component\HttpClient\MockHttpClient; + use Symfony\Component\HttpClient\Response\MockResponse; + + $client = new MockHttpClient([ + new MockResponse('...', ['http_code' => 500]), + new MockResponse('...', ['http_code' => 404]), + ]); + + $response = $client->request('...'); + The responses provided to the mock client don't have to be instances of ``MockResponse``. Any class implementing ``ResponseInterface`` will work (e.g. ``$this->createMock(ResponseInterface::class)``). @@ -1601,11 +1807,126 @@ Then configure Symfony to use your callback: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'http_client' => [ - 'mock_response_factory' => MockClientCallback::class, - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->httpClient() + ->mockResponseFactory(MockClientCallback::class) + ; + }; + +Testing Request Data +~~~~~~~~~~~~~~~~~~~~ + +The ``MockResponse`` class comes with some helper methods to test the request: + +* ``getRequestMethod()`` - returns the HTTP method; +* ``getRequestUrl()`` - returns the URL the request would be sent to; +* ``getRequestOptions()`` - returns an array containing other information about + the request such as headers, query parameters, body content etc. + +Usage example:: + + $mockResponse = new MockResponse('', ['http_code' => 204]); + $httpClient = new MockHttpClient($mockResponse, 'https://example.com'); + + $response = $httpClient->request('DELETE', 'api/article/1337', [ + 'headers' => [ + 'Accept: */*', + 'Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l', + ], + ]); + + $mockResponse->getRequestMethod(); + // returns "DELETE" + + $mockResponse->getRequestUrl(); + // returns "https://example.com/api/article/1337" + + $mockResponse->getRequestOptions()['headers']; + // returns ["Accept: */*", "Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l"] + +Full Example +~~~~~~~~~~~~ + +The following standalone example demonstrates a way to use the HTTP client and +test it in a real application:: + + // ExternalArticleService.php + use Symfony\Contracts\HttpClient\HttpClientInterface; + + final class ExternalArticleService + { + private HttpClientInterface $httpClient; + + public function __construct(HttpClientInterface $httpClient) + { + $this->httpClient = $httpClient; + } + + public function createArticle(array $requestData): array + { + $requestJson = json_encode($requestData, JSON_THROW_ON_ERROR); + + $response = $this->httpClient->request('POST', 'api/article', [ + 'headers' => [ + 'Content-Type: application/json', + 'Accept: application/json', + ], + 'body' => $requestJson, + ]); + + if (201 !== $response->getStatusCode()) { + throw new Exception('Response status code is different than expected.'); + } + + // ... other checks + + $responseJson = $response->getContent(); + $responseData = json_decode($responseJson, true, 512, JSON_THROW_ON_ERROR); + + return $responseData; + } + } + + // ExternalArticleServiceTest.php + use PHPUnit\Framework\TestCase; + use Symfony\Component\HttpClient\MockHttpClient; + use Symfony\Component\HttpClient\Response\MockResponse; + + final class ExternalArticleServiceTest extends TestCase + { + public function testSubmitData(): void + { + // Arrange + $requestData = ['title' => 'Testing with Symfony HTTP Client']; + $expectedRequestData = json_encode($requestData, JSON_THROW_ON_ERROR); + + $expectedResponseData = ['id' => 12345]; + $mockResponseJson = json_encode($expectedResponseData, JSON_THROW_ON_ERROR); + $mockResponse = new MockResponse($mockResponseJson, [ + 'http_code' => 201, + 'response_headers' => ['Content-Type: application/json'], + ]); + + $httpClient = new MockHttpClient($mockResponse, 'https://example.com'); + $service = new ExternalArticleService($httpClient); + + // Act + $responseData = $service->createArticle($requestData); + + // Assert + self::assertSame('POST', $mockResponse->getRequestMethod()); + self::assertSame('https://example.com/api/article', $mockResponse->getRequestUrl()); + self::assertContains( + 'Content-Type: application/json', + $mockResponse->getRequestOptions()['headers'] + ); + self::assertSame($expectedRequestData, $mockResponse->getRequestOptions()['body']); + + self::assertSame($responseData, $expectedResponseData); + } + } .. _`cURL PHP extension`: https://www.php.net/curl .. _`PSR-17`: https://www.php-fig.org/psr/psr-17/ @@ -1616,5 +1937,6 @@ Then configure Symfony to use your callback: .. _`amphp/http-client`: https://packagist.org/packages/amphp/http-client .. _`cURL options`: https://www.php.net/manual/en/function.curl-setopt.php .. _`Server-sent events`: https://html.spec.whatwg.org/multipage/server-sent-events.html -.. _`EventSource`: https://www.w3.org/TR/eventsource/#eventsource -.. _`idempotent method`: https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods_and_web_applications +.. _`EventSource`: https://www.w3.org/TR/eventsource/#eventsource +.. _`idempotent method`: https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods +.. _`SSRF`: https://portswigger.net/web-security/ssrf diff --git a/introduction/from_flat_php_to_symfony.rst b/introduction/from_flat_php_to_symfony.rst index 40a421f85dd..3d7ea851bb7 100644 --- a/introduction/from_flat_php_to_symfony.rst +++ b/introduction/from_flat_php_to_symfony.rst @@ -528,7 +528,7 @@ The Sample Application in Symfony The blog has come a *long* way, but it still contains a lot of code for such a basic application. Along the way, you've made a basic routing system and -a method using ``ob_start()`` and ``ob_get_clean()`` to render templates. +a function using ``ob_start()`` and ``ob_get_clean()`` to render templates. If, for some reason, you needed to continue building this "framework" from scratch, you could at least use Symfony's standalone :doc:`Routing ` component and :doc:`Twig `, which already solve these problems. @@ -540,24 +540,21 @@ them for you. Here's the same sample application, now built in Symfony:: namespace App\Controller; use App\Entity\Post; + use Doctrine\Persistence\ManagerRegistry; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; class BlogController extends AbstractController { - public function list() + public function list(ManagerRegistry $doctrine) { - $posts = $this->getDoctrine() - ->getRepository(Post::class) - ->findAll(); + $posts = $doctrine->getRepository(Post::class)->findAll(); return $this->render('blog/list.html.twig', ['posts' => $posts]); } - public function show($id) + public function show(ManagerRegistry $doctrine, $id) { - $post = $this->getDoctrine() - ->getRepository(Post::class) - ->find($id); + $post = $doctrine->getRepository(Post::class)->find($id); if (!$post) { // cause the 404 page not found to be displayed @@ -580,7 +577,7 @@ and uses Twig: .. code-block:: html+twig - + {# templates/blog/list.html.twig #} {% extends 'base.html.twig' %} {% block title %}List of Posts{% endblock %} @@ -609,10 +606,10 @@ The ``layout.php`` file is nearly identical: {% block title %}Welcome!{% endblock %} {% block stylesheets %}{% endblock %} + {% block javascripts %}{% endblock %} {% block body %}{% endblock %} - {% block javascripts %}{% endblock %} diff --git a/lock.rst b/lock.rst index 92fa69cc526..207d4f93d4f 100644 --- a/lock.rst +++ b/lock.rst @@ -129,32 +129,33 @@ this behavior by using the ``lock`` key like: .. code-block:: php // config/packages/lock.php - $container->loadFromExtension('framework', [ - 'lock' => null, - 'lock' => 'flock', - 'lock' => 'flock:///path/to/file', - 'lock' => 'semaphore', - 'lock' => 'memcached://m1.docker', - 'lock' => ['memcached://m1.docker', 'memcached://m2.docker'], - 'lock' => 'redis://r1.docker', - 'lock' => ['redis://r1.docker', 'redis://r2.docker'], - 'lock' => 'zookeeper://z1.docker', - 'lock' => 'zookeeper://z1.docker,z2.docker', - 'lock' => 'sqlite:///%kernel.project_dir%/var/lock.db', - 'lock' => 'mysql:host=127.0.0.1;dbname=app', - 'lock' => 'pgsql:host=127.0.0.1;dbname=app', - 'lock' => 'pgsql+advisory:host=127.0.0.1;dbname=lock', - 'lock' => 'sqlsrv:server=127.0.0.1;Database=app', - 'lock' => 'oci:host=127.0.0.1;dbname=app', - 'lock' => 'mongodb://127.0.0.1/app?collection=lock', - 'lock' => '%env(LOCK_DSN)%', - - // named locks - 'lock' => [ - 'invoice' => ['semaphore', 'redis://r2.docker'], - 'report' => 'semaphore', - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->lock() + ->resource('default', ['flock']) + ->resource('default', ['flock:///path/to/file']) + ->resource('default', ['semaphore']) + ->resource('default', ['memcached://m1.docker']) + ->resource('default', ['memcached://m1.docker', 'memcached://m2.docker']) + ->resource('default', ['redis://r1.docker']) + ->resource('default', ['redis://r1.docker', 'redis://r2.docker']) + ->resource('default', ['zookeeper://z1.docker']) + ->resource('default', ['zookeeper://z1.docker,z2.docker']) + ->resource('default', ['sqlite:///%kernel.project_dir%/var/lock.db']) + ->resource('default', ['mysql:host=127.0.0.1;dbname=app']) + ->resource('default', ['pgsql:host=127.0.0.1;dbname=app']) + ->resource('default', ['pgsql+advisory:host=127.0.0.1;dbname=lock']) + ->resource('default', ['sqlsrv:server=127.0.0.1;Database=app']) + ->resource('default', ['oci:host=127.0.0.1;dbname=app']) + ->resource('default', ['mongodb://127.0.0.1/app?collection=lock']) + ->resource('default', ['%env(LOCK_DSN)%']) + + // named locks + ->resource('invoice', ['semaphore', 'redis://r2.docker']) + ->resource('report', ['semaphore']) + ; + }; Locking a Resource ------------------ @@ -198,8 +199,8 @@ Locking a Dynamic Resource -------------------------- Sometimes the application is able to cut the resource into small pieces in order -to lock a small subset of process and let other through. In our previous example -with see how to lock the ``$pdf->getOrCreatePdf('terms-of-use')`` for everybody, +to lock a small subset of process and let other through. The previous example +showed how to lock the ``$pdf->getOrCreatePdf('terms-of-use')`` for everybody, now let's see how to lock ``$pdf->getOrCreatePdf($version)`` only for processes asking for the same ``$version``:: @@ -228,11 +229,13 @@ processes asking for the same ``$version``:: } } +.. _lock-named-locks: + Named Lock ---------- If the application needs different kind of Stores alongside each other, Symfony -provides :ref:`named lock `:: +provides :ref:`named lock `: .. configuration-block:: @@ -267,12 +270,15 @@ provides :ref:`named lock `:: .. code-block:: php // config/packages/lock.php - $container->loadFromExtension('framework', [ - 'lock' => [ - 'invoice' => ['semaphore', 'redis://r2.docker'], - 'report' => 'semaphore', - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->lock() + ->resource('invoice', ['semaphore', 'redis://r2.docker']) + ->resource('report', ['semaphore']); + ; + }; + Each name becomes a service where the service id is part of the name of the lock (e.g. ``lock.invoice.factory``). An autowiring alias is also created for @@ -292,4 +298,4 @@ you can do it by :doc:`decorating the store `. Logging a Message ----------------- -To log a message, inject the default logger in your controller:: +To log a message, inject the default logger in your controller or service:: use Psr\Log\LoggerInterface; @@ -64,13 +64,15 @@ The following sections assume that Monolog is installed. Where Logs are Stored --------------------- -By default, log entries are written to the ``var/log/dev.log`` file when you're in -the ``dev`` environment. In the ``prod`` environment, logs are written to ``var/log/prod.log``, -but *only* during a request where an error or high-priority log entry was made -(i.e. ``error()`` , ``critical()``, ``alert()`` or ``emergency()``). +By default, log entries are written to the ``var/log/dev.log`` file when you're +in the ``dev`` environment. -To control this, you'll configure different *handlers* that handle log entries, sometimes -modify them, and ultimately store them. +In the ``prod`` environment, logs are written to `STDERR PHP stream`_, which +works best in modern containerized applications deployed to servers without +disk write permissions. + +If you prefer to store production logs in a file, set the ``path`` of your +log handler(s) to the path of the file to use (e.g. ``var/log/prod.log``). Handlers: Writing Logs to different Locations --------------------------------------------- @@ -138,27 +140,35 @@ to write logs using the :phpfunction:`syslog` function: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - // this "file_log" key could be anything - 'file_log' => [ - 'type' => 'stream', - // log to var/logs/(environment).log - 'path' => '%kernel.logs_dir%/%kernel.environment%.log', - // log *all* messages (debug is lowest level) - 'level' => 'debug', - ], - 'syslog_handler' => [ - 'type' => 'syslog', - // log error-level messages and higher - 'level' => 'error', - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + // this "file_log" key could be anything + $monolog->handler('file_log') + ->type('stream') + // log to var/logs/(environment).log + ->path('%kernel.logs_dir%/%kernel.environment%.log') + // log *all* messages (debug is lowest level) + ->level('debug'); + + $monolog->handler('syslog_handler') + ->type('syslog') + // log error-level messages and higher + ->level('error'); + }; This defines a *stack* of handlers and each handler is called in the order that it's defined. +.. note:: + + If you want to override the ``monolog`` configuration via another config + file, you will need to redefine the entire ``handlers`` stack. The configuration + from the two files cannot be merged because the order matters and a merge does + not allow to control the order. + +.. _logging-handler-fingers_crossed: + Handlers that Modify Log Entries ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -229,29 +239,29 @@ one of the messages reaches an ``action_level``. Take this example: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'filter_for_errors' => [ - 'type' => 'fingers_crossed', - // if *one* log is error or higher, pass *all* to file_log - 'action_level' => 'error', - 'handler' => 'file_log', - ], - - // now passed *all* logs, but only if one log is error or higher - 'file_log' => [ - 'type' => 'stream', - 'path' => '%kernel.logs_dir%/%kernel.environment%.log', - 'level' => 'debug', - ], - - // still passed *all* logs, and still only logs error or higher - 'syslog_handler' => [ - 'type' => 'syslog', - 'level' => 'error', - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('filter_for_errors') + ->type('fingers_crossed') + // if *one* log is error or higher, pass *all* to file_log + ->actionLevel('error') + ->handler('file_log') + ; + + // now passed *all* logs, but only if one log is error or higher + $monolog->handler('file_log') + ->type('stream') + ->path('%kernel.logs_dir%/%kernel.environment%.log') + ->level('debug') + ; + + // still passed *all* logs, and still only logs error or higher + $monolog->handler('syslog_handler') + ->type('syslog') + ->level('error') + ; + }; Now, if even one log entry has an ``error`` level or higher, then *all* log entries for that request are saved to a file via the ``file_log`` handler. That means that @@ -263,13 +273,6 @@ debugging much easier! The handler named "file_log" will not be included in the stack itself as it is used as a nested handler of the ``fingers_crossed`` handler. -.. note:: - - If you want to override the ``monolog`` configuration via another config - file, you will need to redefine the entire ``handlers`` stack. The configuration - from the two files cannot be merged because the order matters and a merge does - not allow to control the order. - All Built-in Handlers --------------------- @@ -331,18 +334,17 @@ option of your handler to ``rotating_file``: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'main' => [ - 'type' => 'rotating_file', - 'path' => '%kernel.logs_dir%/%kernel.environment%.log', - 'level' => 'debug', - // max number of log files to keep - // defaults to zero, which means infinite files - 'max_files' => 10, - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('main') + ->type('rotating_file') + ->path('%kernel.logs_dir%/%kernel.environment%.log') + ->level('debug') + // max number of log files to keep + // defaults to zero, which means infinite files + ->maxFiles(10); + }; Using a Logger inside a Service ------------------------------- @@ -379,15 +381,11 @@ Learn more logging/monolog_exclude_http_codes logging/monolog_console -.. toctree:: - :hidden: - - logging/monolog_regex_based_excludes - .. _`the twelve-factor app methodology`: https://12factor.net/logs -.. _PSR-3: https://www.php-fig.org/psr/psr-3/ +.. _`PSR-3`: https://www.php-fig.org/psr/psr-3/ .. _`stderr`: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr) -.. _Monolog: https://github.com/Seldaek/monolog -.. _LoggerInterface: https://github.com/php-fig/log/blob/master/Psr/Log/LoggerInterface.php +.. _`Monolog`: https://github.com/Seldaek/monolog +.. _`LoggerInterface`: https://github.com/php-fig/log/blob/master/src/LoggerInterface.php .. _`logrotate`: https://github.com/logrotate/logrotate .. _`Monolog Configuration`: https://github.com/symfony/monolog-bundle/blob/master/DependencyInjection/Configuration.php#L25 +.. _`STDERR PHP stream`: https://www.php.net/manual/en/features.commandline.io-streams.php diff --git a/logging/channels_handlers.rst b/logging/channels_handlers.rst index 8f6e9aed98a..ae0567fd551 100644 --- a/logging/channels_handlers.rst +++ b/logging/channels_handlers.rst @@ -78,23 +78,19 @@ can do it in any (or all) environments: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'security' => [ - 'type' => 'stream', - 'path' => '%kernel.logs_dir%/security.log', - 'channels' => [ - 'security', - ], - ], - 'main' => [ - // ... - 'channels' => [ - '!security', - ], - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('security') + ->type('stream') + ->path('%kernel.logs_dir%/security.log') + ->channels()->elements(['security']); + + $monolog->handler('main') + // ... + + ->channels()->elements(['!security']); + }; .. caution:: @@ -163,12 +159,11 @@ You can also configure additional channels without the need to tag your services .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'channels' => [ - 'foo', - 'bar', - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->channels(['foo', 'bar']); + }; Symfony automatically registers one service per channel (in this example, the channel ``foo`` creates a service called ``monolog.logger.foo``). In order to @@ -182,18 +177,18 @@ How to Autowire Logger Channels Starting from `MonologBundle`_ 3.5 you can autowire different Monolog channels by type-hinting your service arguments with the following syntax: -``Psr\Log\LoggerInterface $Logger``. The ```` must have been -:ref:`predefined in your Monolog configuration `. +``Psr\Log\LoggerInterface $ + Logger``. The ```` +must have been :ref:`predefined in your Monolog configuration `. -For example to inject the service related to the ``app`` logger channel, +For example to inject the service related to the ``foo_bar`` logger channel, change your constructor like this: .. code-block:: diff - public function __construct(LoggerInterface $logger) - + public function __construct(LoggerInterface $appLogger) + + public function __construct(LoggerInterface $fooBarLogger) { - $this->logger = $appLogger; + $this->logger = $fooBarLogger; } .. _`MonologBundle`: https://github.com/symfony/monolog-bundle diff --git a/logging/formatter.rst b/logging/formatter.rst index b41cd7ad06e..737b0b86a5f 100644 --- a/logging/formatter.rst +++ b/logging/formatter.rst @@ -23,7 +23,7 @@ configure your handler to use it: .. code-block:: xml - + - loadFromExtension('monolog', [ - 'handlers' => [ - 'file' => [ - 'type' => 'stream', - 'level' => 'debug', - 'formatter' => 'monolog.formatter.json', - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('file') + ->type('stream') + ->level('debug') + ->formatter('monolog.formatter.json') + ; + }; diff --git a/logging/handlers.rst b/logging/handlers.rst index 9f5b903cfa9..4e37e01f622 100644 --- a/logging/handlers.rst +++ b/logging/handlers.rst @@ -88,14 +88,13 @@ Then reference it in the Monolog configuration: // config/packages/prod/monolog.php use Symfony\Bridge\Monolog\Handler\ElasticsearchLogstashHandler; - - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'es' => [ - 'type' => 'service', - 'id' => ElasticsearchLogstashHandler::class, - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('es') + ->type('service') + ->id(ElasticsearchLogstashHandler::class) + ; + }; .. _`ELK stack`: https://www.elastic.co/what-is/elk-stack diff --git a/logging/monolog_console.rst b/logging/monolog_console.rst index 5c0263c5349..b0f2a1b252f 100644 --- a/logging/monolog_console.rst +++ b/logging/monolog_console.rst @@ -42,7 +42,6 @@ The example above could then be rewritten as:: use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; - // ... class YourCommand extends Command { @@ -56,7 +55,6 @@ The example above could then be rewritten as:: protected function execute(InputInterface $input, OutputInterface $output) { $this->logger->debug('Some info'); - // ... $this->logger->notice('Some more info'); } } @@ -67,6 +65,16 @@ the console. If they are displayed, they are timestamped and colored appropriate Additionally, error logs are written to the error output (``php://stderr``). There is no need to conditionally handle the verbosity settings anymore. +=============== ======================================= ============ +LoggerInterface Verbosity Command line +=============== ======================================= ============ +->error() OutputInterface::VERBOSITY_QUIET stderr +->warning() OutputInterface::VERBOSITY_NORMAL stdout +->notice() OutputInterface::VERBOSITY_VERBOSE -v +->info() OutputInterface::VERBOSITY_VERY_VERBOSE -vv +->debug() OutputInterface::VERBOSITY_DEBUG -vvv +=============== ======================================= ============ + The Monolog console handler is enabled by default: .. configuration-block:: @@ -112,15 +120,15 @@ The Monolog console handler is enabled by default: .. code-block:: php // config/packages/dev/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'console' => [ - 'type' => 'console', - 'process_psr_3_messages' => false, - 'channels' => ['!event', '!doctrine', '!console'], - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('console') + ->type('console') + ->processPsr3Messages(false) + ->channels()->elements(['!event', '!doctrine', '!console']) + ; + }; Now, log messages will be shown on the console based on the log levels and verbosity. By default (normal verbosity level), warnings and higher will be shown. But in diff --git a/logging/monolog_email.rst b/logging/monolog_email.rst index 22ed4d08928..0a3c85cc5bd 100644 --- a/logging/monolog_email.rst +++ b/logging/monolog_email.rst @@ -28,8 +28,7 @@ it is broken down. action_level: critical # to also log 400 level errors (but not 404's): # action_level: error - # excluded_404s: - # - ^/ + # excluded_http_codes: [404] handler: deduplicated deduplicated: type: deduplication @@ -62,7 +61,7 @@ it is broken down. to also log 400 level errors (but not 404's): action-level="error" And add this child inside this monolog:handler - ^/ + --> loadFromExtension('monolog', [ - 'handlers' => [ - 'main' => [ - 'type' => 'fingers_crossed', - // 500 errors are logged at the critical level - 'action_level' => 'critical', - // to also log 400 level errors (but not 404's): - // 'action_level' => 'error', - // 'excluded_404s' => [ - // '^/', - // ], - 'handler' => 'deduplicated', - ], - 'deduplicated' => [ - 'type' => 'deduplication', - 'handler' => 'symfony_mailer', - ], - 'symfony_mailer' => [ - 'type' => 'symfony_mailer', - 'from_email' => 'error@example.com', - 'to_email' => 'error@example.com', - // or a list of recipients - // 'to_email' => ['dev1@example.com', 'dev2@example.com', ...], - 'subject' => 'An Error Occurred! %%message%%', - 'level' => 'debug', - 'formatter' => 'monolog.formatter.html', - 'content_type' => 'text/html', - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $mainHandler = $monolog->handler('main') + ->type('fingers_crossed') + // 500 errors are logged at the critical level + ->actionLevel('critical') + // to also log 400 level errors: + // ->actionLevel('error') + ->handler('deduplicated') + ; + + // add this to exclude 404 errors + // $mainHandler->excludedHttpCode()->code(404); + + $monolog->handler('deduplicated') + ->type('deduplication') + ->handler('symfony_mailer'); + + $monolog->handler('symfony_mailer') + ->type('symfony_mailer') + ->fromEmail('error@example.com') + ->toEmail(['error@example.com']) + // or a list of recipients + // ->toEmail(['dev1@example.com', 'dev2@example.com', ...]) + ->subject('An Error Occurred! %%message%%') + ->level('debug') + ->formatter('monolog.formatter.html') + ->contentType('text/html') + ; + }; The ``main`` handler is a ``fingers_crossed`` handler which means that it is only triggered when the action level, in this case ``critical`` is reached. @@ -177,17 +177,18 @@ You can adjust the time period using the ``time`` option: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - // ... - 'deduplicated' => [ - 'type' => 'deduplication', - // the time in seconds during which duplicate entries are discarded (default: 60) - 'time' => 10, - 'handler' => 'symfony_mailer', - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + // ... + + $monolog->handler('deduplicated') + ->type('deduplicated') + // the time in seconds during which duplicate entries are discarded (default: 60) + ->time(10) + ->handler('symfony_mailer') + ; + }; The messages are then passed to the ``symfony_mailer`` handler. This is the handler that actually deals with emailing you the error. The settings for this are @@ -285,39 +286,43 @@ get logged on the server as well as the emails being sent: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'main' => [ - 'type' => 'fingers_crossed', - 'action_level' => 'critical', - 'handler' => 'grouped', - ], - 'grouped' => [ - 'type' => 'group', - 'members' => ['streamed', 'deduplicated'], - ], - 'streamed' => [ - 'type' => 'stream', - 'path' => '%kernel.logs_dir%/%kernel.environment%.log', - 'level' => 'debug', - ], - 'deduplicated' => [ - 'type' => 'deduplication', - 'handler' => 'symfony_mailer', - ], - 'symfony_mailer' => [ - 'type' => 'symfony_mailer', - 'from_email' => 'error@example.com', - 'to_email' => 'error@example.com', - // or a list of recipients - // 'to_email' => ['dev1@example.com', 'dev2@example.com', ...], - 'subject' => 'An Error Occurred! %%message%%', - 'level' => 'debug', - 'formatter' => 'monolog.formatter.html', - 'content_type' => 'text/html', - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('main') + ->type('fingers_crossed') + ->actionLevel('critical') + ->handler('grouped') + ; + + $monolog->handler('group') + ->members(['streamed', 'deduplicated']) + ; + + $monolog->handler('streamed') + ->type('stream') + ->path('%kernel.logs_dir%/%kernel.environment%.log') + ->level('debug') + ; + + $monolog->handler('deduplicated') + ->type('deduplicated') + ->handler('symfony_mailer') + ; + + // still passed *all* logs, and still only logs error or higher + $monolog->handler('symfony_mailer') + ->type('symfony_mailer') + ->fromEmail('error@example.com') + ->toEmail(['error@example.com']) + // or a list of recipients + // ->toEmail(['dev1@example.com', 'dev2@example.com', ...]) + ->subject('An Error Occurred! %%message%%') + ->level('debug') + ->formatter('monolog.formatter.html') + ->contentType('text/html') + ; + }; This uses the ``group`` handler to send the messages to the two group members, the ``deduplicated`` and the ``stream`` handlers. The messages will diff --git a/logging/monolog_exclude_http_codes.rst b/logging/monolog_exclude_http_codes.rst index 9c1bd81bdcc..a064370d0c5 100644 --- a/logging/monolog_exclude_http_codes.rst +++ b/logging/monolog_exclude_http_codes.rst @@ -49,16 +49,18 @@ logging these HTTP codes based on the MonologBundle configuration: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'main' => [ - // ... - 'type' => 'fingers_crossed', - 'handler' => ..., - 'excluded_http_codes' => [403, 404], - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $mainHandler = $monolog->handler('main') + // ... + ->type('fingers_crossed') + ->handler(...) + ; + + $mainHandler->excludedHttpCode()->code(403); + $mainHandler->excludedHttpCode()->code(404); + }; .. caution:: diff --git a/logging/monolog_regex_based_excludes.rst b/logging/monolog_regex_based_excludes.rst deleted file mode 100644 index be4a6ee8b7e..00000000000 --- a/logging/monolog_regex_based_excludes.rst +++ /dev/null @@ -1,78 +0,0 @@ -.. index:: - single: Logging - single: Logging; Exclude 404 Errors - single: Monolog; Exclude 404 Errors - -How to Configure Monolog to Exclude 404 Errors from the Log -=========================================================== - -.. tip:: - - Read :doc:`/logging/monolog_exclude_http_codes` to learn about a similar - but more generic feature that allows to exclude logs for any HTTP status - code and not only 404 errors. - -Sometimes your logs become flooded with unwanted 404 HTTP errors, for example, -when an attacker scans your app for some well-known application paths (e.g. -`/phpmyadmin`). When using a ``fingers_crossed`` handler, you can exclude -logging these 404 errors based on a regular expression in the MonologBundle -configuration: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/prod/monolog.yaml - monolog: - handlers: - main: - # ... - type: fingers_crossed - handler: ... - excluded_404s: - - ^/phpmyadmin - - .. code-block:: xml - - - - - - - - ^/phpmyadmin - - - - - .. code-block:: php - - // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'main' => [ - // ... - 'type' => 'fingers_crossed', - 'handler' => ..., - 'excluded_404s' => [ - '^/phpmyadmin', - ], - ], - ], - ]); - - -.. caution:: - - Combining ``excluded_404s`` with a ``passthru_level`` lower than - ``error`` (i.e. ``debug``, ``info``, ``notice`` or ``warning``) will not - actually exclude log messages for the URL(s) listed in ``excluded_404s`` - because they are logged with level of ``error`` or higher and - ``passthru_level`` takes precedence over the URLs being listed in - ``excluded_404s``. diff --git a/logging/processors.rst b/logging/processors.rst index 605c571b244..fbc7d14c151 100644 --- a/logging/processors.rst +++ b/logging/processors.rst @@ -19,30 +19,33 @@ using a processor:: // src/Logger/SessionRequestProcessor.php namespace App\Logger; - use Symfony\Component\HttpFoundation\Session\SessionInterface; + use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException; + use Symfony\Component\HttpFoundation\RequestStack; class SessionRequestProcessor { - private $session; - private $sessionId; + private $requestStack; - public function __construct(SessionInterface $session) + public function __construct(RequestStack $requestStack) { - $this->session = $session; + $this->requestStack = $requestStack; } // this method is called for each log record; optimize it to not hurt performance public function __invoke(array $record) { - if (!$this->session->isStarted()) { + try { + $session = $this->requestStack->getSession(); + } catch (SessionNotFoundException $e) { + return; + } + if (!$session->isStarted()) { return $record; } - if (!$this->sessionId) { - $this->sessionId = substr($this->session->getId(), 0, 8) ?: '????????'; - } + $sessionId = substr($session->getId(), 0, 8) ?: '????????'; - $record['extra']['token'] = $this->sessionId.'-'.substr(uniqid('', true), -8); + $record['extra']['token'] = $sessionId.'-'.substr(uniqid('', true), -8); return $record; } @@ -103,7 +106,7 @@ information: $container ->register(SessionRequestProcessor::class) - ->addTag('monolog.processor', ['method' => 'processRecord']); + ->addTag('monolog.processor'); Finally, set the formatter to be used on whatever handler you want: @@ -146,16 +149,16 @@ Finally, set the formatter to be used on whatever handler you want: .. code-block:: php // config/packages/prod/monolog.php - $container->loadFromExtension('monolog', [ - 'handlers' => [ - 'main' => [ - 'type' => 'stream', - 'path' => '%kernel.logs_dir%/%kernel.environment%.log', - 'level' => 'debug', - 'formatter' => 'monolog.formatter.session_request', - ], - ], - ]); + use Symfony\Config\MonologConfig; + + return static function (MonologConfig $monolog) { + $monolog->handler('main') + ->type('stream') + ->path('%kernel.logs_dir%/%kernel.environment%.log') + ->level('debug') + ->formatter('monolog.formatter.session_request') + ; + }; If you use several handlers, you can also register a processor at the handler level or at the channel level instead of registering it globally diff --git a/mailer.rst b/mailer.rst index 352e3613fea..421e14ee054 100644 --- a/mailer.rst +++ b/mailer.rst @@ -27,15 +27,78 @@ over SMTP by configuring the DSN in your ``.env`` file (the ``user``, # .env MAILER_DSN=smtp://user:pass@smtp.example.com:port +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/mailer.yaml + framework: + mailer: + dsn: '%env(MAILER_DSN)%' + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // config/packages/mailer.php + use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; + + return static function (ContainerConfigurator $containerConfigurator): void { + $containerConfigurator->extension('framework', [ + 'mailer' => [ + 'dsn' => '%env(MAILER_DSN)%', + ], + ]); + }; + +.. caution:: + + If the username, password or host contain any character considered special in a + URI (such as ``+``, ``@``, ``$``, ``#``, ``/``, ``:``, ``*``, ``!``), you must + encode them. See `RFC 3986`_ for the full list of reserved characters or use the + :phpfunction:`urlencode` function to encode them. + .. caution:: If you are migrating from Swiftmailer (and the Swiftmailer bundle), be warned that the DSN format is different. +Using Built-in Transports +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.2 + + The native protocol was introduced in Symfony 5.2. + +============ ======================================== ============================================================== +DSN protocol Example Description +============ ======================================== ============================================================== +smtp ``smtp://user:pass@smtp.example.com:25`` Mailer uses an SMTP server to send emails +sendmail ``sendmail://default`` Mailer uses the local sendmail binary to send emails +native ``native://default`` Mailer uses the sendmail binary and options configured + in the ``sendmail_path`` setting of ``php.ini``. On Windows + hosts, Mailer fallbacks to ``smtp`` and ``smtp_port`` + ``php.ini`` settings when ``sendmail_path`` is not configured. +============ ======================================== ============================================================== + Using a 3rd Party Transport ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Instead of using your own SMTP server, you can send emails via a 3rd party +Instead of using your own SMTP server or sendmail binary, you can send emails via a 3rd party provider. Mailer supports several - install whichever you want: ================== ============================================== @@ -49,12 +112,17 @@ Mailjet ``composer require symfony/mailjet-mailer`` Postmark ``composer require symfony/postmark-mailer`` SendGrid ``composer require symfony/sendgrid-mailer`` Sendinblue ``composer require symfony/sendinblue-mailer`` +OhMySMTP ``composer require symfony/oh-my-smtp-mailer`` ================== ============================================== .. versionadded:: 5.2 The Sendinblue integration was introduced in Symfony 5.2. +.. versionadded:: 5.4 + + The OhMySMTP integration was introduced in Symfony 5.4. + Each library includes a :ref:`Symfony Flex recipe ` that will add a configuration example to your ``.env`` file. For example, suppose you want to use SendGrid. First, install it: @@ -93,16 +161,17 @@ This table shows the full list of available DSN formats for each third party provider: ==================== ==================================================== =========================================== ======================================== - Provider SMTP HTTP API +Provider SMTP HTTP API ==================== ==================================================== =========================================== ======================================== - Amazon SES ses+smtp://ACCESS_KEY:SECRET_KEY@default ses+https://ACCESS_KEY:SECRET_KEY@default ses+api://ACCESS_KEY:SECRET_KEY@default - Google Gmail gmail+smtp://USERNAME:PASSWORD@default n/a n/a - Mailchimp Mandrill mandrill+smtp://USERNAME:PASSWORD@default mandrill+https://KEY@default mandrill+api://KEY@default - Mailgun mailgun+smtp://USERNAME:PASSWORD@default mailgun+https://KEY:DOMAIN@default mailgun+api://KEY:DOMAIN@default - Mailjet mailjet+smtp://ACCESS_KEY:SECRET_KEY@default n/a mailjet+api://ACCESS_KEY:SECRET_KEY@default - Postmark postmark+smtp://ID:ID@default n/a postmark+api://KEY@default - Sendgrid sendgrid+smtp://apikey:KEY@default n/a sendgrid+api://KEY@default - Sendinblue sendinblue+smtp://apikey:USERNAME:PASSWORD@default n/a sendinblue+api://KEY@default +Amazon SES ses+smtp://USERNAME:PASSWORD@default ses+https://ACCESS_KEY:SECRET_KEY@default ses+api://ACCESS_KEY:SECRET_KEY@default +Google Gmail gmail+smtp://USERNAME:PASSWORD@default n/a n/a +Mailchimp Mandrill mandrill+smtp://USERNAME:PASSWORD@default mandrill+https://KEY@default mandrill+api://KEY@default +Mailgun mailgun+smtp://USERNAME:PASSWORD@default mailgun+https://KEY:DOMAIN@default mailgun+api://KEY:DOMAIN@default +Mailjet mailjet+smtp://ACCESS_KEY:SECRET_KEY@default n/a mailjet+api://ACCESS_KEY:SECRET_KEY@default +Postmark postmark+smtp://ID@default n/a postmark+api://KEY@default +Sendgrid sendgrid+smtp://KEY@default n/a sendgrid+api://KEY@default +Sendinblue sendinblue+smtp://USERNAME:PASSWORD@default n/a sendinblue+api://KEY@default +OhMySMTP ohmysmtp+smtp://API_TOKEN@default n/a ohmysmtp+api://API_TOKEN@default ==================== ==================================================== =========================================== ======================================== .. caution:: @@ -111,6 +180,17 @@ party provider: For example, the DSN ``ses+smtp://ABC1234:abc+12/345@default`` should be configured as ``ses+smtp://ABC1234:abc%2B12%2F345@default`` +.. caution:: + + If you want to use ``ses+smtp`` transport together with :doc:`Messenger ` + to :ref:`send messages in background `, + you need to add the ``ping_threshold`` parameter to your ``MAILER_DSN`` with + a value lower than ``10``: ``ses+smtp://USERNAME:PASSWORD@default?ping_threshold=9`` + + .. versionadded:: 5.4 + + The ``ping_threshold`` option for ``ses-smtp`` was introduced in Symfony 5.4. + .. note:: When using SMTP, the default timeout for sending a message before throwing an @@ -129,8 +209,8 @@ party provider: .. code-block:: env # .env - MAILER_DSN=mailgun+https://KEY:DOMAIN@example.com - MAILER_DSN=mailgun+https://KEY:DOMAIN@example.com:99 + MAILER_DSN=mailgun+https://KEY:DOMAIN@requestbin.com + MAILER_DSN=mailgun+https://KEY:DOMAIN@requestbin.com:99 Note that the protocol is *always* HTTPs and cannot be changed. @@ -147,9 +227,9 @@ A failover transport is configured with two or more transports and the MAILER_DSN="failover(postmark+api://ID@default sendgrid+smtp://KEY@default)" -The mailer will start using the first transport. If the sending fails, the -mailer won't retry it with the other transports, but it will switch to the next -transport automatically for the following deliveries. +The failover-transport starts using the first transport and if it fails, it +will retry the same delivery with the next transports until one of them succeeds +(or until all of them fail). Load Balancing ~~~~~~~~~~~~~~ @@ -164,9 +244,12 @@ A round-robin transport is configured with two or more transports and the MAILER_DSN="roundrobin(postmark+api://ID@default sendgrid+smtp://KEY@default)" -The mailer will start using a randomly selected transport and if it fails, it -will retry the same delivery with the next transports until one of them succeeds -(or until all of them fail). +The round-robin transport starts with a *randomly* selected transport and +then switches to the next available transport for each subsequent email. + +As with the failover transport, round-robin retries deliveries until +a transport succeeds (or all fail). In contrast to the failover transport, +it *spreads* the load across all its transports. .. versionadded:: 5.1 @@ -181,12 +264,63 @@ configurable with the ``verify_peer`` option. Although it's not recommended to disable this verification for security reasons, it can be useful while developing the application or when using a self-signed certificate:: - $dsn = 'smtp://user:pass@smtp.example.com?verify_peer=0' + $dsn = 'smtp://user:pass@smtp.example.com?verify_peer=0'; .. versionadded:: 5.1 The ``verify_peer`` option was introduced in Symfony 5.1. +Other Options +~~~~~~~~~~~~~ + +``command`` + Command to be executed by ``sendmail`` transport:: + + $dsn = 'sendmail://default?command=/usr/sbin/sendmail%20-oi%20-t' + + .. versionadded:: 5.2 + + This option was introduced in Symfony 5.2. + + +``local_domain`` + The domain name to use in ``HELO`` command:: + + $dsn = 'smtps://smtp.example.com?local_domain=example.org' + + .. versionadded:: 5.2 + + This option was introduced in Symfony 5.2. + +``restart_threshold`` + The maximum number of messages to send before re-starting the transport. It + can be used together with ``restart_threshold_sleep``:: + + $dsn = 'smtps://smtp.example.com?restart_threshold=10&restart_threshold_sleep=1' + + .. versionadded:: 5.2 + + This option was introduced in Symfony 5.2. + +``restart_threshold_sleep`` + The number of seconds to sleep between stopping and re-starting the transport. + It's common to combine it with ``restart_threshold``:: + + $dsn = 'smtps://smtp.example.com?restart_threshold=10&restart_threshold_sleep=1' + + .. versionadded:: 5.2 + + This option was introduced in Symfony 5.2. + +``ping_threshold`` + The minimum number of seconds between two messages required to ping the server:: + + $dsn = 'smtps://smtp.example.com?ping_threshold=200' + + .. versionadded:: 5.2 + + This option was introduced in Symfony 5.2. + Creating & Sending Messages --------------------------- @@ -198,6 +332,7 @@ and create an :class:`Symfony\\Component\\Mime\\Email` object:: namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Mime\Email; @@ -206,7 +341,7 @@ and create an :class:`Symfony\\Component\\Mime\\Email` object:: /** * @Route("/email") */ - public function sendEmail(MailerInterface $mailer) + public function sendEmail(MailerInterface $mailer): Response { $email = (new Email()) ->from('hello@example.com') @@ -257,8 +392,7 @@ both strings or address objects:: .. tip:: Instead of calling ``->from()`` *every* time you create a new email, you can - create an :doc:`event subscriber ` and listen to the - :class:`Symfony\\Component\\Mailer\\Event\\MessageEvent` event to set the + :ref:`configure emails globally ` to set the same ``From`` email to all messages. .. note:: @@ -271,12 +405,13 @@ both strings or address objects:: Support for UTF-8 characters in email addresses was introduced in Symfony 5.2. -Multiple addresses are defined with the ``addXXX()`` methods:: +Use ``addTo()``, ``addCc()``, or ``addBcc()`` methods to add more addresses:: $email = (new Email()) ->to('foo@example.com') ->addTo('bar@example.com') - ->addTo('baz@example.com') + ->cc('cc@example.com') + ->addCc('cc2@example.com') // ... ; @@ -304,11 +439,17 @@ header, etc.) but most of the times you'll set text headers:: ->getHeaders() // this header tells auto-repliers ("email holiday mode") to not // reply to this message because it's an automated email - ->addTextHeader('X-Auto-Response-Suppress', 'OOF, DR, RN, NRN, AutoReply'); + ->addTextHeader('X-Auto-Response-Suppress', 'OOF, DR, RN, NRN, AutoReply') // ... ; +.. tip:: + + Instead of calling ``->addTextHeader()`` *every* time you create a new email, you can + :ref:`configure emails globally ` to set the same + headers to all sent emails. + Message Contents ~~~~~~~~~~~~~~~~ @@ -384,6 +525,78 @@ images inside the HTML contents:: ->html(' ... ...') ; +.. _mailer-configure-email-globally: + +Configuring Emails Globally +--------------------------- + +Instead of calling ``->from()`` on each Email you create, you can configure this +value globally so that it is set on all sent emails. The same is true with ``->to()`` +and headers. + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/dev/mailer.yaml + framework: + mailer: + envelope: + sender: 'fabien@example.com' + recipients: ['foo@example.com', 'bar@example.com'] + headers: + from: 'Fabien ' + bcc: 'baz@example.com' + X-Custom-Header: 'foobar' + + .. code-block:: xml + + + + + + + + + + fabien@example.com + foo@example.com + bar@example.com + + Fabien <fabien@example.com> + baz@example.com + foobar + + + + + .. code-block:: php + + // config/packages/mailer.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $mailer = $framework->mailer(); + $mailer + ->envelope() + ->sender('fabien@example.com') + ->recipients(['foo@example.com', 'bar@example.com']) + ; + + $mailer->header('from')->value('Fabien '); + $mailer->header('bcc')->value('baz@example.com'); + $mailer->header('X-Custom-Header')->value('foobar'); + }; + +.. versionadded:: 5.2 + + The ``headers`` option was introduced in Symfony 5.2. + Handling Sending Failures ------------------------- @@ -559,13 +772,14 @@ image files as usual. First, to simplify things, define a Twig namespace called .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { // ... - 'paths' => [ - // point this wherever your images live - '%kernel.project_dir%/assets/images' => 'images', - ], - ]); + + // point this wherever your images live + $twig->path('%kernel.project_dir%/assets/images', 'images'); + }; Now, use the special ``email.image()`` Twig helper to embed the images inside the email contents: @@ -623,14 +837,14 @@ arguments to the filter: .. code-block:: html+twig - {% apply inline_css(source('@css/email.css')) %} + {% apply inline_css(source('@styles/email.css')) %}

    Welcome {{ username }}!

    {# ... #} {% endapply %} You can pass unlimited number of arguments to ``inline_css()`` to load multiple CSS files. For this example to work, you also need to define a new Twig namespace -called ``css`` that points to the directory where ``email.css`` lives: +called ``styles`` that points to the directory where ``email.css`` lives: .. _mailer-css-namespace: @@ -667,13 +881,14 @@ called ``css`` that points to the directory where ``email.css`` lives: .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { // ... - 'paths' => [ - // point this wherever your css files live - '%kernel.project_dir%/assets/styles' => 'styles', - ], - ]); + + // point this wherever your css files live + $twig->path('%kernel.project_dir%/assets/styles', 'styles'); + }; .. _mailer-markdown: @@ -753,11 +968,11 @@ You can combine all filters to create complex email messages: .. code-block:: twig - {% apply inky_to_html|inline_css(source('@css/foundation-emails.css')) %} + {% apply inky_to_html|inline_css(source('@styles/foundation-emails.css')) %} {# ... #} {% endapply %} -This makes use of the :ref:`css Twig namespace ` we created +This makes use of the :ref:`styles Twig namespace ` we created earlier. You could, for example, `download the foundation-emails.css file`_ directly from GitHub and save it in ``assets/styles``. @@ -902,6 +1117,8 @@ and it will select the appropriate certificate depending on the ``To`` option:: $firstEncryptedEmail = $encrypter->encrypt($firstEmail); $secondEncryptedEmail = $encrypter->encrypt($secondEmail); +.. _multiple-email-transports: + Multiple Email Transports ------------------------- @@ -943,26 +1160,28 @@ This can be configured by replacing the ``dsn`` configuration entry with a .. code-block:: php // config/packages/mailer.php - $container->loadFromExtension('framework', [ - // ... - 'mailer' => [ - 'transports' => [ - 'main' => '%env(MAILER_DSN)%', - 'alternative' => '%env(MAILER_DSN_IMPORTANT)%', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->mailer() + ->transport('main', '%env(MAILER_DSN)%') + ->transport('alternative', '%env(MAILER_DSN_IMPORTANT)%') + ; + }; -By default the first transport is used. The other transports can be used by -adding a text header ``X-Transport`` to an email:: +By default the first transport is used. The other transports can be selected by +adding an ``X-Transport`` header (which Mailer will remove automatically from +the final email):: - // Send using first "main" transport ... + // Send using first transport ("main"): $mailer->send($email); - // ... or use the "alternative" one + // ... or use the transport "alternative": $email->getHeaders()->addTextHeader('X-Transport', 'alternative'); $mailer->send($email); +.. _mailer-sending-messages-async: + Sending Messages Async ---------------------- @@ -987,7 +1206,7 @@ you have a transport called ``async``, you can route the message there: async: "%env(MESSENGER_TRANSPORT_DSN)%" routing: - 'Symfony\Component\Mailer\Messenger\SendEmailMessage': async + 'Symfony\Component\Mailer\Messenger\SendEmailMessage': async .. code-block:: xml @@ -1003,6 +1222,7 @@ you have a transport called ``async``, you can route the message there: + %env(MESSENGER_TRANSPORT_DSN)% @@ -1013,17 +1233,68 @@ you have a transport called ``async``, you can route the message there: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'routing' => [ - 'Symfony\Component\Mailer\Messenger\SendEmailMessage' => 'async', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->messenger() + ->transport('async')->dsn('%env(MESSENGER_TRANSPORT_DSN)%'); + + $framework->messenger() + ->routing('Symfony\Component\Mailer\Messenger\SendEmailMessage') + ->senders(['async']); + }; + Thanks to this, instead of being delivered immediately, messages will be sent to the transport to be handled later (see :ref:`messenger-worker`). +You can configure which bus is used to dispatch the message using the ``message_bus`` option. +You can also set this to ``false`` to call the Mailer transport directly and +disable asynchronous delivery. + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/mailer.yaml + framework: + mailer: + message_bus: app.another_bus + + .. code-block:: xml + + + + + + + + + + + + .. code-block:: php + + // config/packages/mailer.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->mailer() + ->messageBus('app.another_bus'); + }; + +.. versionadded:: 5.1 + + The ``message_bus`` option was introduced in Symfony 5.1. + Adding Tags and Metadata to Emails ---------------------------------- @@ -1056,9 +1327,19 @@ If your transport does not support tags and metadata, they will be added as cust The following transports currently support tags and metadata: -* Postmark -* Mailgun * MailChimp +* Mailgun +* Postmark +* Sendgrid +* Sendinblue + +.. versionadded:: 5.4 + + The tag and metadata support for Sendgrid was introduced in Symfony 5.4. + +The following transports only support tags: + +* OhMySMTP Development & Debugging ----------------------- @@ -1100,12 +1381,13 @@ the mailer configuration file (e.g. in the ``dev`` or ``test`` environments): .. code-block:: php // config/packages/mailer.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'mailer' => [ - 'dsn' => 'null://null', - ], - ]); + $framework->mailer() + ->dsn('null://null'); + }; .. note:: @@ -1152,14 +1434,15 @@ a specific address, instead of the *real* address: .. code-block:: php // config/packages/mailer.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'mailer' => [ - 'envelope' => [ - 'recipients' => ['youremail@example.com'], - ], - ], - ]); + $framework->mailer() + ->envelope() + ->recipients(['youremail@example.com']) + ; + }; .. _`high availability`: https://en.wikipedia.org/wiki/High_availability .. _`load balancing`: https://en.wikipedia.org/wiki/Load_balancing_(computing) @@ -1172,3 +1455,4 @@ a specific address, instead of the *real* address: .. _`OpenSSL PHP extension`: https://www.php.net/manual/en/book.openssl.php .. _`PEM encoded`: https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail .. _`default_socket_timeout`: https://www.php.net/manual/en/filesystem.configuration.php#ini.default-socket-timeout +.. _`RFC 3986`: https://www.ietf.org/rfc/rfc3986.txt diff --git a/mercure.rst b/mercure.rst index 8c0f52f8039..9a0c1e9dfea 100644 --- a/mercure.rst +++ b/mercure.rst @@ -22,8 +22,9 @@ server to clients. It is a modern and efficient alternative to timer-based polling and to WebSocket. Because it is built on top `Server-Sent Events (SSE)`_, Mercure is supported -out of the box in most modern browsers (Edge and IE require `a polyfill`_) and -has `high-level implementations`_ in many programming languages. +out of the box in most modern browsers (old versions of Edge and IE require +`a polyfill`_) and has `high-level implementations`_ in many programming +languages. Mercure comes with an authorization mechanism, automatic re-connection in case of network issues @@ -34,10 +35,6 @@ thanks to a specific HTTP header). All these features are supported in the Symfony integration. -Unlike WebSocket, which is only compatible with HTTP 1.x, -Mercure leverages the multiplexing capabilities provided by HTTP/2 -and HTTP/3 (but also supports older versions of HTTP). - `In this recording`_ you can see how a Symfony web API leverages Mercure and API Platform to update in live a React app and a mobile app (React Native) generated using the API Platform client generator. @@ -45,16 +42,6 @@ generated using the API Platform client generator. Installation ------------ -Installing the Symfony Component -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In applications using :ref:`Symfony Flex `, run this command to -install the Mercure support before using it: - -.. code-block:: terminal - - $ composer require mercure - Running a Mercure Hub ~~~~~~~~~~~~~~~~~~~~~ @@ -65,26 +52,39 @@ clients. .. image:: /_images/mercure/schema.png -An official and open source (AGPL) implementation of a Hub can be downloaded -as a static binary from `Mercure.rocks`_. +An official and open source (AGPL) Hub based on the Caddy web server +can be downloaded as a static binary from `Mercure.rocks`_. +A Docker image, a Helm chart for Kubernetes +and a managed, High Availability Hub are also provided. + +If you use `Symfony Docker`_ or the `API Platform distribution`_, a Mercure Hub +is automatically installed and your Symfony application is automatically +configured to use it. You can jump directly to the next section. + +If you use the :doc:`Symfony Local Web Server `, +a Mercure hub will be automatically available as a Docker service thanks to its +:ref:`Docker integration . -Run the following command to start it: +Be sure that recent versions of Docker and Docker Compose are properly installed +on your computer and to start the Symfony Local Web Server with the ``--no-tls`` +option: .. code-block:: terminal - $ ./mercure --jwt-key='!ChangeMe!' --addr='localhost:3000' --allow-anonymous --cors-allowed-origins='*' + $ symfony server:start --no-tls -d -.. note:: +Installing the Symfony Bundle +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Alternatively to the binary, a Docker image, a Helm chart for Kubernetes - and a managed, High Availability Hub are also provided by Mercure.rocks. +Run this command to install the Mercure support before using it: -.. tip:: +.. code-block:: terminal - The `API Platform distribution`_ comes with a Docker Compose configuration - as well as a Helm chart for Kubernetes that are 100% compatible with Symfony, - and contain a Mercure hub. - You can copy them in your project, even if you don't use API Platform. + $ composer require mercure + +:ref:`Symfony Flex ` has automatically installed and configured +MercureBundle. It also created (if needed) and configured a Docker Compose +definition that provides a Mercure service. Run ``docker-compose up`` to start it. Configuration ------------- @@ -92,18 +92,30 @@ Configuration The preferred way to configure the MercureBundle is using :doc:`environment variables `. -Set the URL of your hub as the value of the ``MERCURE_PUBLISH_URL`` env var. -The ``.env`` file of your project has been updated by the Flex recipe to -provide example values. -Set it to the URL of the Mercure Hub (``http://localhost:3000/.well-known/mercure`` by default). +When MercureBundle has been installed, the ``.env`` file of your project +has been updated by the Flex recipe to include the available env vars. + +If you use the Symfony Local Web Server, Symfony Docker or the API Platform +distribution, the Symfony app is automatically configured and you can skip +straight to the next section. + +Otherwise, set the URL of your hub as the value of the ``MERCURE_URL`` +and ``MERCURE_PUBLIC_URL`` env vars. +Sometimes a different URL must be called by the Symfony app (usually to publish), +and the JavaScript client (usually to subscribe). It's especially common when +the Symfony app must use a local URL and the client-side JavaScript code a public one. +In this case, ``MERCURE_URL`` must contain the local URL that will be used by the +Symfony app (e.g. ``https://mercure/.well-known/mercure``), and ``MERCURE_PUBLIC_URL`` +the publicly available URL (e.g. ``https://example.com/.well-known/mercure``). -In addition, the Symfony application must bear a `JSON Web Token`_ (JWT) -to the Mercure Hub to be authorized to publish updates. +The clients must also bear a `JSON Web Token`_ (JWT) +to the Mercure Hub to be authorized to publish updates and, sometimes, to subscribe. -This JWT should be stored in the ``MERCURE_JWT_TOKEN`` environment variable. +This JWT should be stored in the ``MERCURE_JWT_SECRET`` environment variable. The JWT must be signed with the same secret key as the one used by -the Hub to verify the JWT (``!ChangeMe!`` in our example). +the Hub to verify the JWT (``!ChangeMe!`` in you use the Local Web Server or +Symfony Docker). Its payload must contain at least the following structure to be allowed to publish: @@ -127,11 +139,54 @@ public updates (see the authorization_ section for further information). .. caution:: - Don't put the secret key in ``MERCURE_JWT_TOKEN``, it will not work! + Don't put the secret key in ``MERCURE_JWT_SECRET``, it will not work! This environment variable must contain a JWT, signed with the secret key. Also, be sure to keep both the secret key and the JWTs... secrets! +If you don't want to use the provided environment variables, +use the following configuration: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/mercure.yaml + mercure: + hubs: + default: + url: https://mercure-hub.example.com/.well-known/mercure + jwt: + secret: '!ChangeMe!' + + .. code-block:: xml + + + + + + + + + + .. code-block:: php + + // config/packages/mercure.php + $container->loadFromExtension('mercure', [ + 'hubs' => [ + 'default' => [ + 'url' => 'https://mercure-hub.example.com/.well-known/mercure', + 'jwt' => [ + 'secret' => '!ChangeMe!', + ], + ], + ], + ]); + + Basic Usage ----------- @@ -149,21 +204,21 @@ service, including controllers:: // src/Controller/PublishController.php namespace App\Controller; + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\Mercure\PublisherInterface; + use Symfony\Component\Mercure\HubInterface; use Symfony\Component\Mercure\Update; - class PublishController + class PublishController extends AbstractController { - public function __invoke(PublisherInterface $publisher): Response + public function publish(HubInterface $hub): Response { $update = new Update( - 'http://example.com/books/1', + 'https://example.com/books/1', json_encode(['status' => 'OutOfStock']) ); - // The Publisher service is an invokable object - $publisher($update); + $hub->publish($update); return new Response('published!'); } @@ -175,8 +230,8 @@ the **topic** being updated. This topic should be an `IRI`_ of the resource being dispatched. Usually, this parameter contains the original URL of the resource -transmitted to the client, but it can be any valid `IRI`_, it doesn't -have to be a URL that exists (similarly to XML namespaces). +transmitted to the client, but it can be any string or `IRI`_, +and it doesn't have to be a URL that exists (similarly to XML namespaces). The second parameter of the constructor is the content of the update. It can be anything, stored in any format. @@ -186,34 +241,57 @@ Atom, HTML or XML is recommended. Subscribing ~~~~~~~~~~~ -Subscribing to updates in JavaScript is straightforward: +Subscribing to updates in JavaScript from a Twig template is straightforward: -.. code-block:: javascript +.. code-block:: twig - const eventSource = new EventSource('http://localhost:3000/.well-known/mercure?topic=' + encodeURIComponent('http://example.com/books/1')); + + +The ``mercure()`` Twig function will generate the URL of the Mercure hub +according to the configuration. The URL will include the ``topic`` query +parameters corresponding to the topics passed as first argument. + +If you want to access to this URL from an external JavaScript file, generate the +URL in a dedicated HTML element: -Mercure also allows to subscribe to several topics, +.. code-block:: twig + + + +Then retrieve it from your JS file: + +.. code-block:: javascript + + const url = JSON.parse(document.getElementById("mercure-url").textContent); + const eventSource = new EventSource(url); + // ... + +Mercure also allows subscribing to several topics, and to use URI Templates or the special value ``*`` (matched by all topics) as patterns: -.. code-block:: javascript +.. code-block:: twig - // URL is a built-in JavaScript class to manipulate URLs - const url = new URL('http://localhost:3000/.well-known/mercure'); - url.searchParams.append('topic', 'http://example.com/books/1'); - // Subscribe to updates of several Book resources - url.searchParams.append('topic', 'http://example.com/books/2'); - // All Review resources will match this pattern - url.searchParams.append('topic', 'http://example.com/reviews/{id}'); + .. tip:: @@ -233,43 +311,6 @@ as patterns: Test if a URI Template match a URL using `the online debugger`_ -Async dispatching ------------------ - -Instead of calling the ``Publisher`` service directly, you can also let Symfony -dispatching the updates asynchronously thanks to the provided integration with -the Messenger component. - -First, be sure :doc:`to install the Messenger component ` -and to configure properly a transport (if you don't, the handler will -be called synchronously). - -Then, dispatch the Mercure ``Update`` to the Messenger's Message Bus, -it will be handled automatically:: - - // src/Controller/PublishController.php - namespace App\Controller; - - use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\Mercure\Update; - use Symfony\Component\Messenger\MessageBusInterface; - - class PublishController - { - public function __invoke(MessageBusInterface $bus): Response - { - $update = new Update( - 'http://example.com/books/1', - json_encode(['status' => 'OutOfStock']) - ); - - // Sync, or async (RabbitMQ, Kafka...) - $bus->dispatch($update); - - return new Response('published!'); - } - } - Discovery --------- @@ -288,17 +329,14 @@ by using the ``AbstractController::addLink`` helper method:: use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\WebLink\Link; + use Symfony\Component\Mercure\Discovery; class DiscoverController extends AbstractController { - public function __invoke(Request $request): JsonResponse + public function __invoke(Request $request, Discovery $discovery): JsonResponse { - // This parameter is automatically created by the MercureBundle - $hubUrl = $this->getParameter('mercure.default_hub'); - // Link: ; rel="mercure" - $this->addLink($request, new Link('mercure', $hubUrl)); + $discovery->addLink($request); return $this->json([ '@id' => '/books/1', @@ -319,8 +357,8 @@ and to subscribe to it: const hubUrl = response.headers.get('Link').match(/<([^>]+)>;\s+rel=(?:mercure|"[^"]*mercure[^"]*")/)[1]; // Append the topic(s) to subscribe as query parameter - const hub = new URL(hubUrl); - hub.searchParams.append('topic', 'http://example.com/books/{id}'); + const hub = new URL(hubUrl, window.origin); + hub.searchParams.append('topic', 'https://example.com/books/{id}'); // Subscribe to updates const eventSource = new EventSource(hub); @@ -330,30 +368,30 @@ and to subscribe to it: Authorization ------------- -Mercure also allows to dispatch updates only to authorized clients. +Mercure also allows dispatching updates only to authorized clients. To do so, mark the update as **private** by setting the third parameter of the ``Update`` constructor to ``true``:: // src/Controller/Publish.php namespace App\Controller; + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\Mercure\PublisherInterface; use Symfony\Component\Mercure\Update; - class PublishController + class PublishController extends AbstractController { - public function __invoke(PublisherInterface $publisher): Response + public function publish(HubInterface $hub): Response { $update = new Update( - 'http://example.com/books/1', + 'https://example.com/books/1', json_encode(['status' => 'OutOfStock']), true // private ); // Publisher's JWT must contain this topic, a URI template it matches or * in mercure.publish or you'll get a 401 // Subscriber's JWT must contain this topic, a URI template it matches or * in mercure.subscribe to receive the update - $publisher($update); + $hub->publish($update); return new Response('private update published!'); } @@ -365,102 +403,100 @@ a JWT containing a topic selector matching by the update's topic. To provide this JWT, the subscriber can use a cookie, or a ``Authorization`` HTTP header. -Cookies are automatically sent by the browsers when opening an ``EventSource`` -connection if the ``withCredentials`` attribute is set to ``true``: +Cookies can be set automatically by Symfony by passing the appropriate options +to the ``mercure()`` Twig function. Cookies set by Symfony will be automatically +passed by the browsers to the Mercure hub if the ``withCredentials`` attribute +of the ``EventSource`` class is set to ``true``. Then, the Hub will verify the +validity of the provided JWT, and extract the topic selectors from it. -.. code-block:: javascript +.. code-block:: twig - const eventSource = new EventSource(hub, { + + +The supported options are: + +* ``subscribe``: the list of topic selectors to include in the ``mercure.subscribe`` claim of the JWT +* ``publish``: the list of topic selectors to include in the ``mercure.publish`` claim of the JWT +* ``additionalClaims``: extra claims to include in the JWT (expiration date, token ID...) Using cookies is the most secure and preferred way when the client is a web browser. If the client is not a web browser, then using an authorization header is the way to go. +.. caution:: + + To use the cookie authentication method, the Symfony app and the Hub + must be served from the same domain (can be different sub-domains). + .. tip:: The native implementation of EventSource doesn't allow specifying headers. For example, authorization using Bearer token. In order to achieve that, use `a polyfill`_ - .. code-block:: javascript + .. code-block:: twig - const es = new EventSourcePolyfill(url, { + -In the following example controller, -the generated cookie contains a JWT, itself containing the appropriate topic selector. -This cookie will be automatically sent by the web browser when connecting to the Hub. -Then, the Hub will verify the validity of the provided JWT, and extract the topic selectors -from it. - -To generate the JWT, we'll use the ``lcobucci/jwt`` library. Install it: +Programmatically Setting The Cookie +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code-block:: terminal +Sometimes, it can be convenient to set the authorization cookie from your code +instead of using the Twig function. MercureBundle provides a convenient service, +:class:`Symfony\\Component\\Mercure\\Authorization`, to do so. - $ composer require lcobucci/jwt +In the following example controller, the added cookie contains a JWT, itself +containing the appropriate topic selector. And here is the controller:: // src/Controller/DiscoverController.php namespace App\Controller; - use Lcobucci\JWT\Builder; - use Lcobucci\JWT\Signer\Hmac\Sha256; - use Lcobucci\JWT\Signer\Key; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; - use Symfony\Component\HttpFoundation\Cookie; + use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\WebLink\Link; + use Symfony\Component\Mercure\Authorization; + use Symfony\Component\Mercure\Discovery; class DiscoverController extends AbstractController { - public function __invoke(Request $request): Response + public function publish(Request $request, Discovery $discovery, Authorization $authorization): JsonResponse { - $hubUrl = $this->getParameter('mercure.default_hub'); - $this->addLink($request, new Link('mercure', $hubUrl)); - - $token = (new Builder()) - // set other appropriate JWT claims, such as an expiration date - ->withClaim('mercure', ['subscribe' => ["http://example.com/books/1"]]) // can also be a URI template, or * - ->getToken(new Sha256(), new Key($this->getParameter('mercure_secret_key'))); // don't forget to set this parameter! Test value: !ChangeMe! - - $response = $this->json(['@id' => '/demo/books/1', 'availability' => 'https://schema.org/InStock']); - $cookie = Cookie::create('mercureAuthorization') - ->withValue($token) - ->withPath('/.well-known/mercure') - ->withSecure(true) - ->withHttpOnly(true) - ->withSameSite('strict') - ; - $response->headers->setCookie($cookie); - - return $response; + $discovery->addLink($request); + $authorization->setCookie($request, ['https://example.com/books/1']); + + return $this->json([ + '@id' => '/demo/books/1', + 'availability' => 'https://schema.org/InStock' + ]); } } -.. caution:: - - To use the cookie authentication method, the Symfony app and the Hub - must be served from the same domain (can be different sub-domains). - Programmatically Generating The JWT Used to Publish --------------------------------------------------- Instead of directly storing a JWT in the configuration, -you can create a service that will return the token used by -the ``Publisher`` object:: +you can create a token provider that will return the token used by +the ``HubInterface`` object:: - // src/Mercure/MyJwtProvider.php + // src/Mercure/MyTokenProvider.php namespace App\Mercure; - final class MyJwtProvider + use Symfony\Component\Mercure\Jwt\TokenProviderInterface; + + final class MyTokenProvider implements TokenProviderInterface { - public function __invoke(): string + public function getJwt(): string { return 'the-JWT'; } @@ -477,7 +513,8 @@ Then, reference this service in the bundle configuration: hubs: default: url: https://mercure-hub.example.com/.well-known/mercure - jwt_provider: App\Mercure\MyJwtProvider + jwt: + provider: App\Mercure\MyTokenProvider .. code-block:: xml @@ -487,8 +524,9 @@ Then, reference this service in the bundle configuration: + > + +
    .. code-block:: php @@ -500,7 +538,9 @@ Then, reference this service in the bundle configuration: 'hubs' => [ 'default' => [ 'url' => 'https://mercure-hub.example.com/.well-known/mercure', - 'jwt_provider' => MyJwtProvider::class, + 'jwt' => [ + 'provider' => MyJwtProvider::class, + ], ], ], ]); @@ -533,22 +573,16 @@ hypermedia API, and automatic update broadcasting through the Mercure hub:: use ApiPlatform\Core\Annotation\ApiResource; use Doctrine\ORM\Mapping as ORM; - /** - * @ApiResource(mercure=true) - * @ORM\Entity - */ + #[ApiResource(mercure: true)] + #[ORM\Entity] class Book { - /** - * @ORM\Id - * @ORM\Column - */ - public $name; - - /** - * @ORM\Column - */ - public $status; + #[ORM\Id] + #[ORM\Column] + public string $name = ''; + + #[ORM\Column] + public string $status = ''; } As showcased `in this recording`_, the API Platform Client Generator also @@ -561,30 +595,65 @@ its Mercure support. Testing -------- -During functional testing there is no need to send updates to Mercure. They will -be handled by a stub publisher:: +During unit testing there is not need to send updates to Mercure. + +You can instead make use of the `MockHub`:: + + // tests/FunctionalTest.php + namespace App\Tests\Unit\Controller; + + use App\Controller\MessageController; + use Symfony\Component\Mercure\HubInterface; + use Symfony\Component\Mercure\JWT\StaticTokenProvider; + use Symfony\Component\Mercure\MockHub; + use Symfony\Component\Mercure\Update; + + class MessageControllerTest extends TestCase + { + public function testPublishing() + { + $hub = new MockHub('https://internal/.well-known/mercure', new StaticTokenProvider('foo'), function(Update $update): string { + // $this->assertTrue($update->isPrivate()); + + return 'id'; + }); - // tests/Functional/Fixtures/PublisherStub.php + $controller = new MessageController($hub); + + // ... + } + } + +During functional testing you can instead decorate the Hub:: + + // tests/Functional/Fixtures/HubStub.php namespace App\Tests\Functional\Fixtures; - use Symfony\Component\Mercure\PublisherInterface; + use Symfony\Component\Mercure\HubInterface; use Symfony\Component\Mercure\Update; - class PublisherStub implements PublisherInterface + class HubStub implements HubInterface { - public function __invoke(Update $update): string + public function publish(Update $update): string { - return ''; + return 'id'; } + + // implement rest of HubInterface methods here } -PublisherStub decorates the default publisher service so no updates are actually -sent. Here is the PublisherStub implementation:: +HubStub decorates the default hub service so no updates are actually +sent. Here is the HubStub implementation: + +.. code-block:: yaml # config/services_test.yaml - App\Tests\Functional\Fixtures\PublisherStub: - decorates: mercure.hub.default.publisher + App\Tests\Functional\Fixtures\HubStub: + decorates: mercure.hub.default + +.. tip:: + Symfony Panther has `a feature to test applications using Mercure`_. Debugging --------- @@ -595,36 +664,66 @@ Debugging Enable the panel in your configuration, as follows: -.. configuration-block:: +MercureBundle is shipped with a debug panel. Install the Debug pack to +enable it:: - .. code-block:: yaml +.. code-block:: terminal - # config/packages/mercure.yaml - mercure: - enable_profiler: '%kernel.debug%' + $ composer require --dev symfony/debug-pack - .. code-block:: xml +.. image:: /_images/mercure/panel.png - - - +Async dispatching +----------------- - +.. tip:: - + Async dispatching is discouraged. Most Mercure hubs already + handle publications asynchronously and using Messenger is + usually not necessary. - .. code-block:: php +Instead of calling the ``Publisher`` service directly, you can also let Symfony +dispatching the updates asynchronously thanks to the provided integration with +the Messenger component. - // config/packages/mercure.php - $container->loadFromExtension('mercure', [ - 'enable_profiler' => '%kernel.debug%', - ]); +First, be sure :doc:`to install the Messenger component ` +and to configure properly a transport (if you don't, the handler will +be called synchronously). +Then, dispatch the Mercure ``Update`` to the Messenger's Message Bus, +it will be handled automatically:: -.. image:: /_images/mercure/panel.png + // src/Controller/PublishController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\Mercure\Update; + use Symfony\Component\Messenger\MessageBusInterface; + + class PublishController extends AbstractController + { + public function publish(MessageBusInterface $bus): Response + { + $update = new Update( + 'https://example.com/books/1', + json_encode(['status' => 'OutOfStock']) + ); + + // Sync, or async (Doctrine, RabbitMQ, Kafka...) + $bus->dispatch($update); + + return new Response('published!'); + } + } + +Going further +------------- + +* The Mercure protocol is also supported by :doc:`the Notifier component `. + Use it to send push notifications to web browsers. +* `Symfony UX Turbo`_ is a library using Mercure to provide the same experience + as with Single Page Applications but without having to write a single line of JavaScript! .. _`the Mercure protocol`: https://mercure.rocks/spec .. _`Server-Sent Events (SSE)`: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events @@ -632,6 +731,7 @@ Enable the panel in your configuration, as follows: .. _`high-level implementations`: https://mercure.rocks/docs/ecosystem/awesome .. _`In this recording`: https://www.youtube.com/watch?v=UI1l0JOjLeI .. _`Mercure.rocks`: https://mercure.rocks +.. _`Symfony Docker`: https://github.com/dunglas/symfony-docker/ .. _`API Platform distribution`: https://api-platform.com/docs/distribution/ .. _`JSON Web Token`: https://tools.ietf.org/html/rfc7519 .. _`example JWT`: https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOlsiKiJdfX0.iHLdpAEjX4BqCsHJEegxRmO-Y6sMxXwNATrQyRNt3GY @@ -639,3 +739,5 @@ Enable the panel in your configuration, as follows: .. _`practical UI`: https://twitter.com/ChromeDevTools/status/562324683194785792 .. _`the dedicated API Platform documentation`: https://api-platform.com/docs/core/mercure/ .. _`the online debugger`: https://uri-template-tester.mercure.rocks +.. _`a feature to test applications using Mercure`: https://github.com/symfony/panther#creating-isolated-browsers-to-test-apps-using-mercure-or-websocket +.. _`Symfony UX Turbo`: https://github.com/symfony/ux-turbo diff --git a/messenger.rst b/messenger.rst index 6c2f2e35794..87fa30ea818 100644 --- a/messenger.rst +++ b/messenger.rst @@ -99,9 +99,6 @@ You're ready! To dispatch the message (and call the handler), inject the // will cause the SmsNotificationHandler to be called $bus->dispatch(new SmsNotification('Look! I created a message!')); - // or use the shortcut - $this->dispatchMessage(new SmsNotification('Look! I created a message!')); - // ... } } @@ -179,19 +176,20 @@ that uses this configuration: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'async' => '%env(MESSENGER_TRANSPORT_DSN)%', - - // or expanded to configure more options - 'async' => [ - 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', - 'options' => [] - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->messenger() + ->transport('async') + ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ; + + $framework->messenger() + ->transport('async') + ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->options([]) + ; + }; .. _messenger-routing: @@ -213,7 +211,7 @@ you can configure them to be sent to a transport: routing: # async is whatever name you gave your transport above - 'App\Message\SmsNotification': async + 'App\Message\SmsNotification': async .. code-block:: xml @@ -240,14 +238,14 @@ you can configure them to be sent to a transport: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'routing' => [ - // async is whatever name you gave your transport above - 'App\Message\SmsNotification' => 'async', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->messenger() + // async is whatever name you gave your transport above + ->routing('App\Message\SmsNotification')->senders(['async']) + ; + }; Thanks to this, the ``App\Message\SmsNotification`` will be sent to the ``async`` transport and its handler(s) will *not* be called immediately. Any messages not @@ -302,16 +300,22 @@ to multiple transports: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'routing' => [ - // route all messages that extend this example base class or interface - 'App\Message\AbstractAsyncMessage' => 'async', - 'App\Message\AsyncMessageInterface' => 'async', - 'My\Message\ToBeSentToTwoSenders' => ['async', 'audit'], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + // route all messages that extend this example base class or interface + $messenger->routing('App\Message\AbstractAsyncMessage')->senders(['async']); + $messenger->routing('App\Message\AsyncMessageInterface')->senders(['async']); + $messenger->routing('My\Message\ToBeSentToTwoSenders')->senders(['async', 'audit']); + }; + +.. note:: + + If you configure routing for both a child and parent class, both rules + are used. E.g. if you have an ``SmsNotification`` object that extends + from ``Notification``, both the routing for ``Notification`` and + ``SmsNotification`` will be used. Doctrine Entities in Messages ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -418,18 +422,16 @@ transport and "sending" messages there to be handled immediately: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - // ... other transports - - 'sync' => 'sync://', - ], - 'routing' => [ - 'App\Message\SmsNotification' => 'sync', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + // ... other transports + + $messenger->transport('sync')->dsn('sync://'); + $messenger->routing('App\Message\SmsNotification')->senders(['sync']); + }; Creating your Own Transport ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -456,6 +458,16 @@ The first argument is the receiver's name (or service id if you routed to a custom service). By default, the command will run forever: looking for new messages on your transport and handling them. This command is called your "worker". +.. tip:: + + To properly stop a worker, throw an instance of + :class:`Symfony\\Component\\Messenger\\Exception\\StopWorkerException`. + + .. versionadded:: 5.4 + + The :class:`Symfony\\Component\\Messenger\\Exception\\StopWorkerException` + class was introduced in Symfony 5.4. + Deploying to Production ~~~~~~~~~~~~~~~~~~~~~~~ @@ -480,6 +492,14 @@ On production, there are a few important things to think about: new worker processes. The command uses the :ref:`app ` cache internally - so make sure this is configured to use an adapter you like. +**Use the Same Cache Between Deploys** + If your deploy strategy involves the creation of new target directories, you + should set a value for the :ref:`cache.prefix.seed ` + configuration option in order to use the same cache namespace between deployments. + Otherwise, the ``cache.app`` pool will use the value of the ``kernel.project_dir`` + parameter as base for the namespace, which will lead to different namespaces + each time a new deployment is made. + Prioritized Transports ~~~~~~~~~~~~~~~~~~~~~~ @@ -554,28 +574,22 @@ different messages to them. For example: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'async_priority_high' => [ - 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', - 'options' => [ - 'queue_name' => 'high', - ], - ], - 'async_priority_low' => [ - 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', - 'options' => [ - 'queue_name' => 'low', - ], - ], - ], - 'routing' => [ - 'App\Message\SmsNotification' => 'async_priority_low', - 'App\Message\NewUserWelcomeEmail' => 'async_priority_high', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $messenger->transport('async_priority_high') + ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->options(['queue_name' => 'high']); + + $messenger->transport('async_priority_low') + ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->options(['queue_name' => 'low']); + + $messenger->routing('App\Message\SmsNotification')->senders(['async_priority_low']); + $messenger->routing('App\Message\NewUserWelcomeEmail')->senders(['async_priority_high']); + }; You can then run individual workers for each transport or instruct one worker to handle messages in a priority order: @@ -587,6 +601,29 @@ to handle messages in a priority order: The worker will always first look for messages waiting on ``async_priority_high``. If there are none, *then* it will consume messages from ``async_priority_low``. +.. _messenger-limit-queues: + +Limit Consuming to Specific Queues +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some transports (notably AMQP) have the concept of exchanges and queues. A Symfony +transport is always bound to an exchange. By default, the worker consumes from all +queues attached to the exchange of the specified transport. However, there are use +cases to want a worker to only consume from specific queues. + +You can limit the worker to only process messages from specific queues: + +.. code-block:: terminal + + $ php bin/console messenger:consume my_transport --queues=fasttrack + +To allow using the ``queues`` option, the receiver must implement the +:class:`Symfony\\Component\\Messenger\\Transport\\Receiver\\QueueReceiverInterface`. + +.. versionadded:: 5.3 + + Limiting the worker to specific queues was introduced in Symfony 5.3. + .. _messenger-supervisor: Supervisor Configuration @@ -619,8 +656,18 @@ times: process_name=%(program_name)s_%(process_num)02d Change the ``async`` argument to use the name of your transport (or transports) -and ``user`` to the Unix user on your server. Next, tell Supervisor to read your -config and start your workers: +and ``user`` to the Unix user on your server. + +If you use the Redis Transport, note that each worker needs a unique consumer +name to avoid the same message being handled by multiple workers. One way to +achieve this is to set an environment variable in the Supervisor configuration +file, which you can then refer to in ``messenger.yaml`` (see Redis section above): + +.. code-block:: ini + + environment=MESSENGER_CONSUMER_NAME=%(program_name)s_%(process_num)02d + +Next, tell Supervisor to read your config and start your workers: .. code-block:: terminal @@ -632,6 +679,89 @@ config and start your workers: See the `Supervisor docs`_ for more details. +Graceful Shutdown +~~~~~~~~~~~~~~~~~ + +If you install the `PCNTL`_ PHP extension in your project, workers will handle +the ``SIGTERM`` POSIX signal to finish processing their current message before +exiting. + +In some cases the ``SIGTERM`` signal is sent by Supervisor itself (e.g. stopping +a Docker container having Supervisor as its entrypoint). In these cases you +need to add a ``stopwaitsecs`` key to the program configuration (with a value +of the desired grace period in seconds) in order to perform a graceful shutdown: + +.. code-block:: ini + + [program:x] + stopwaitsecs=20 + +Stateless Worker +~~~~~~~~~~~~~~~~ + +PHP is designed to be stateless, there are no shared resources across different +requests. In HTTP context PHP cleans everything after sending the response, so +you can decide to not take care of services that may leak memory. + +On the other hand, workers usually run in long-running CLI processes, which don't +finish after processing a message. That's why you need to be careful about services +state to not leak information and/or memory from one message to another message. + +However, certain Symfony services, such as the Monolog +:ref:`fingers crossed handler `, leak by design. +In those cases, use the ``reset_on_message`` transport option to automatically +reset the service container between two messages: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/messenger.yaml + framework: + messenger: + reset_on_message: true + transports: + async: + dsn: '%env(MESSENGER_TRANSPORT_DSN)%' + + .. code-block:: xml + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/messenger.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $messenger->transport('async') + ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->resetOnMessage(true) + ; + }; + +.. versionadded:: 5.4 + + The ``reset_on_message`` option was introduced in Symfony 5.4. + .. _messenger-retries-failures: Retries & Failures @@ -692,29 +822,36 @@ this is configurable for each transport: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'async_priority_high' => [ - 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', - - // default configuration - 'retry_strategy' => [ - 'max_retries' => 3, - // milliseconds delay - 'delay' => 1000, - // causes the delay to be higher before each retry - // e.g. 1 second delay, 2 seconds, 4 seconds - 'multiplier' => 2, - 'max_delay' => 0, - // override all of this with a service that - // implements Symfony\Component\Messenger\Retry\RetryStrategyInterface - // 'service' => null, - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $messenger->transport('async_priority_high') + ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + // default configuration + ->retryStrategy() + ->maxRetries(3) + // milliseconds delay + ->delay(1000) + // causes the delay to be higher before each retry + // e.g. 1 second delay, 2 seconds, 4 seconds + ->multiplier(2) + ->maxDelay(0) + // override all of this with a service that + // implements Symfony\Component\Messenger\Retry\RetryStrategyInterface + ->service(null) + ; + }; + +.. tip:: + + Symfony triggers a :class:`Symfony\\Component\\Messenger\\Event\\WorkerMessageRetriedEvent` + when a message is retried so you can run your own logic. + + .. versionadded:: 5.2 + + The ``WorkerMessageRetriedEvent`` class was introduced in Symfony 5.2. Avoiding Retrying ~~~~~~~~~~~~~~~~~ @@ -734,7 +871,7 @@ Forcing Retrying Sometimes handling a message must fail in a way that you *know* is temporary and must be retried. If you throw :class:`Symfony\\Component\\Messenger\\Exception\\RecoverableMessageHandlingException`, -the message will always be retried. +the message will always be retried infinitely and ``max_retries`` setting will be ignored. .. _messenger-failure-transport: @@ -784,20 +921,19 @@ be discarded. To avoid this happening, you can instead configure a ``failure_tra .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - // after retrying, messages will be sent to the "failed" transport - 'failure_transport' => 'failed', - - 'transports' => [ - // ... other transports - - 'failed' => [ - 'dsn' => 'doctrine://default?queue_name=failed', - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + // after retrying, messages will be sent to the "failed" transport + $messenger->failureTransport('failed'); + + // ... other transports + + $messenger->transport('failed') + ->dsn('doctrine://default?queue_name=failed'); + }; In this example, if handling a message fails 3 times (default ``max_retries``), it will then be sent to the ``failed`` transport. While you *can* use @@ -833,6 +969,113 @@ If the message fails again, it will be re-sent back to the failure transport due to the normal :ref:`retry rules `. Once the max retry has been hit, the message will be discarded permanently. +Multiple Failed Transports +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.3 + + The possibility to use multiple failed transports was introduced in Symfony 5.3. + +Sometimes it is not enough to have a single, global ``failed transport`` configured +because some messages are more important than others. In those cases, you can +override the failure transport for only specific transports: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/messenger.yaml + framework: + messenger: + # after retrying, messages will be sent to the "failed" transport + # by default if no "failed_transport" is configured inside a transport + failure_transport: failed_default + + transports: + async_priority_high: + dsn: '%env(MESSENGER_TRANSPORT_DSN)%' + failure_transport: failed_high_priority + + # since no failed transport is configured, the one used will be + # the global "failure_transport" set + async_priority_low: + dsn: 'doctrine://default?queue_name=async_priority_low' + + failed_default: 'doctrine://default?queue_name=failed_default' + failed_high_priority: 'doctrine://default?queue_name=failed_high_priority' + + .. code-block:: xml + + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/messenger.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + // after retrying, messages will be sent to the "failed" transport + // by default if no "failure_transport" is configured inside a transport + $messenger->failureTransport('failed_default'); + + $messenger->transport('async_priority_high') + ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->failureTransport('failed_high_priority'); + + // since no failed transport is configured, the one used will be + // the global failure_transport set + $messenger->transport('async_priority_low') + ->dsn('doctrine://default?queue_name=async_priority_low'); + + $messenger->transport('failed_default') + ->dsn('doctrine://default?queue_name=failed_default'); + + $messenger->transport('failed_high_priority') + ->dsn('doctrine://default?queue_name=failed_high_priority'); + }; + +If there is no ``failure_transport`` defined globally or on the transport level, +the messages will be discarded after the number of retries. + +The failed commands have an optional option ``--transport`` to specify +the ``failure_transport`` configured at the transport level. + +.. code-block:: terminal + + # see all messages in "failure_transport" transport + $ php bin/console messenger:failed:show --transport=failure_transport + + # retry specific messages from "failure_transport" + $ php bin/console messenger:failed:retry 20 30 --transport=failure_transport --force + + # remove a message without retrying it from "failure_transport" + $ php bin/console messenger:failed:remove 20 --transport=failure_transport + .. _messenger-transports-config: Transport Configuration @@ -883,18 +1126,15 @@ options. Options can be passed to the transport via a DSN string or configuratio .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'my_transport' => [ - 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', - 'options' => [ - 'auto_setup' => false, - ] - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $messenger->transport('my_transport') + ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->options(['auto_setup' => false]); + }; Options defined under ``options`` take precedence over ones defined in the DSN. @@ -941,6 +1181,11 @@ it in the ``port`` parameter of the DSN (e.g. ``amqps://localhost?cacert=/etc/ss binding keys that are needed. That can be disabled, but some functionality may not work correctly (like delayed queues). +.. note:: + + With Symfony 5.3 or newer, you can limit the consumer of an AMQP transport to only + process messages from some queues of an exchange. See :ref:`messenger-limit-queues`. + The transport has a number of other options, including ways to configure the exchange, queues binding keys and more. See the documentation on :class:`Symfony\\Component\\Messenger\\Bridge\\Amqp\\Transport\\Connection`. @@ -956,8 +1201,8 @@ The transport has a number of options: ``cert`` Path to the client certificate in PEM format. ``channel_max`` Specifies highest channel number that the server permits. 0 means standard extension limit -``confirm_timeout`` Timeout in seconds for confirmation, if none - specified transport will not wait for message +``confirm_timeout`` Timeout in seconds for confirmation; if none + specified, transport will not wait for message confirmation. Note: 0 or greater seconds. May be fractional. ``connect_timeout`` Connection timeout. Note: 0 or greater seconds. @@ -997,7 +1242,8 @@ The transport has a number of options: ``queues[name][binding_arguments]`` Arguments to be used while binding the queue. ``queues[name][binding_keys]`` The binding keys (if any) to bind to this queue ``queues[name][flags]`` Queue flags ``AMQP_DURABLE`` -``exchange[arguments]`` +``exchange[arguments]`` Extra arguments for the exchange (e.g. + ``alternate-exchange``) ``exchange[default_publish_routing_key]`` Routing key to use when publishing, if none is specified on the message ``exchange[flags]`` Exchange flags ``AMQP_DURABLE`` @@ -1005,6 +1251,15 @@ The transport has a number of options: ``exchange[type]`` Type of exchange ``fanout`` ============================================ ================================================= =================================== +.. versionadded:: 5.2 + + The ``confirm_timeout`` option was introduced in Symfony 5.2. + +.. deprecated:: 5.3 + + The ``prefetch_count`` option was deprecated in Symfony 5.3 because it has + no effect on the AMQP Messenger transport. + You can also configure AMQP-specific settings on your message by adding :class:`Symfony\\Component\\Messenger\\Bridge\\Amqp\\Transport\\AmqpStamp` to your Envelope:: @@ -1014,7 +1269,7 @@ your Envelope:: $attributes = []; $bus->dispatch(new SmsNotification(), [ - new AmqpStamp('custom-routing-key', AMQP_NOPARAM, $attributes) + new AmqpStamp('custom-routing-key', AMQP_NOPARAM, $attributes), ]); .. caution:: @@ -1061,10 +1316,16 @@ a table named ``messenger_messages``. Or, to create the table yourself, set the ``auto_setup`` option to ``false`` and :ref:`generate a migration `. +.. caution:: + + The datetime property of the messages stored in the database uses the + timezone of the current system. This may cause issues if multiple machines + with different timezone configuration use the same storage. + The transport has a number of options: ================== ===================================== ====================== - Option Description Default +Option Description Default ================== ===================================== ====================== table_name Name of the table messenger_messages queue_name Name of the queue (a column in the default @@ -1080,6 +1341,29 @@ auto_setup Whether the table should be created automatically during send / get. true ================== ===================================== ====================== +.. versionadded:: 5.1 + + The ability to leverage PostgreSQL's LISTEN/NOTIFY was introduced + in Symfony 5.1. + +When using PostgreSQL, you have access to the following options to leverage +the `LISTEN/NOTIFY`_ feature. This allow for a more performant approach +than the default polling behavior of the Doctrine transport because +PostgreSQL will directly notify the workers when a new message is inserted +in the table. + +======================= ========================================== ====================== +Option Description Default +======================= ========================================== ====================== +use_notify Whether to use LISTEN/NOTIFY. true +check_delayed_interval The interval to check for delayed 1000 + messages, in milliseconds. + Set to 0 to disable checks. +get_notify_timeout The length of time to wait for a 0 + response when calling + ``PDO::pgsqlGetNotify``, in milliseconds. +======================= ========================================== ====================== + Beanstalkd Transport ~~~~~~~~~~~~~~~~~~~~ @@ -1087,7 +1371,7 @@ Beanstalkd Transport The Beanstalkd transport was introduced in Symfony 5.2. -The Beanstalkd transports sends messages directly to a Beanstalkd work queue. Install +The Beanstalkd transport sends messages directly to a Beanstalkd work queue. Install it by running: .. code-block:: terminal @@ -1143,7 +1427,9 @@ The Redis transport DSN may looks like this: # .env MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages # Full DSN Example - MESSENGER_TRANSPORT_DSN=redis://password@localhost:6379/messages/symfony/consumer?auto_setup=true&serializer=1&stream_max_entries=0&dbindex=0 + MESSENGER_TRANSPORT_DSN=redis://password@localhost:6379/messages/symfony/consumer?auto_setup=true&serializer=1&stream_max_entries=0&dbindex=0&delete_after_ack=true + # Redis Cluster Example + MESSENGER_TRANSPORT_DSN=redis://host-01:6379,redis://host-02:6379,redis://host-03:6379,redis://host-04:6379 # Unix Socket Example MESSENGER_TRANSPORT_DSN=redis:///var/run/redis.sock @@ -1151,51 +1437,62 @@ The Redis transport DSN may looks like this: The Unix socket DSN was introduced in Symfony 5.1. -To use the Redis transport, you will need the Redis PHP extension (>=4.3) and -a running Redis server (^5.0). - A number of options can be configured via the DSN or via the ``options`` key under the transport in ``messenger.yaml``: -=================== ===================================== ================================= - Option Description Default -=================== ===================================== ================================= -stream The Redis stream name messages -group The Redis consumer group name symfony -consumer Consumer name used in Redis consumer -auto_setup Create the Redis group automatically? true -auth The Redis password -delete_after_ack If ``true``, messages are deleted false - automatically after processing them -delete_after_reject If ``true``, messages are deleted true - automatically if they are rejected -lazy Connect only when a connection is false - really needed -serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` - in Redis (the - ``Redis::OPT_SERIALIZER`` option) -stream_max_entries The maximum number of entries which ``0`` (which means "no trimming") - the stream will be trimmed to. Set - it to a large enough number to - avoid losing pending messages -tls Enable TLS support for the connection false -redeliver_timeout Timeout before retrying a pending ``3600`` - message which is owned by an - abandoned consumer (if a worker died - for some reason, this will occur, - eventually you should retry the - message) - in seconds. -claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) - messages should be checked for to - claim - in milliseconds -=================== ===================================== ================================= + +======================= ===================================== ================================= +Option Description Default +======================= ===================================== ================================= +stream The Redis stream name messages +group The Redis consumer group name symfony +consumer Consumer name used in Redis consumer +auto_setup Create the Redis group automatically? true +auth The Redis password +delete_after_ack If ``true``, messages are deleted false + automatically after processing them +delete_after_reject If ``true``, messages are deleted true + automatically if they are rejected +lazy Connect only when a connection is false + really needed +serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` + in Redis (the + ``Redis::OPT_SERIALIZER`` option) +stream_max_entries The maximum number of entries which ``0`` (which means "no trimming") + the stream will be trimmed to. Set + it to a large enough number to + avoid losing pending messages +tls Enable TLS support for the connection false +redeliver_timeout Timeout before retrying a pending ``3600`` + message which is owned by an + abandoned consumer (if a worker died + for some reason, this will occur, + eventually you should retry the + message) - in seconds. +claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) + messages should be checked for to + claim - in milliseconds +sentinel_persistent_id String, if null connection is null + non-persistent. +sentinel_retry_interval Int, value in milliseconds ``0`` +sentinel_read_timeout Float, value in seconds ``0`` + default indicates unlimited +sentinel_timeout Float, value in seconds ``0`` + default indicates unlimited +sentinel_master String, if null or empty Sentinel null + support is disabled +======================= ===================================== ================================= .. caution:: There should never be more than one ``messenger:consume`` command running with the same - config (stream, group and consumer name) to avoid having a message handled more than once. - Using the ``HOSTNAME`` as the consumer might often be a good idea. In case you are using - Kubernetes to orchestrate your containers, consider using a ``StatefulSet``. + combination of ``stream``, ``group`` and ``consumer``, or messages could end up being + handled more than once. If you run multiple queue workers, ``consumer`` can be set to an + environment variable (like ``%env(MESSENGER_CONSUMER_NAME)%``) set by Supervisor + (example below) or any other service used to manage the worker processes. + In a container environment, the ``HOSTNAME`` can be used as the consumer name, since + there is only one worker per container/host. If using Kubernetes to orchestrate the + containers, consider using a ``StatefulSet`` to have stable names. .. tip:: @@ -1213,6 +1510,17 @@ claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) The ``delete_after_reject`` and ``lazy`` options were introduced in Symfony 5.2. +.. versionadded:: 5.4 + + The ``sentinel_persistent_id``, ``sentinel_retry_interval``, ``sentinel_read_timeout``, + ``sentinel_timeout``, and ``sentinel_master`` options were introduced in Symfony 5.4. + +.. deprecated:: 5.4 + + Not setting a explicit value for the ``delete_after_ack`` option is + deprecated since Symfony 5.4. In Symfony 6.0, the default value of this + option changes from ``false`` to ``true``. + In Memory Transport ~~~~~~~~~~~~~~~~~~~ @@ -1253,15 +1561,14 @@ override it in the ``test`` environment to use this transport: .. code-block:: php // config/packages/test/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'async_priority_normal' => [ - 'dsn' => 'in-memory://', - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $messenger->transport('async_priority_normal') + ->dsn('in-memory://'); + }; Then, while testing, messages will *not* be delivered to the real transport. Even better, in a test, you can check that exactly one message was sent @@ -1283,11 +1590,21 @@ during a request:: $this->assertSame(200, $client->getResponse()->getStatusCode()); /* @var InMemoryTransport $transport */ - $transport = self::$container->get('messenger.transport.async_priority_normal'); + $transport = $this->getContainer()->get('messenger.transport.async_priority_normal'); $this->assertCount(1, $transport->getSent()); } } +The transport has a number of options: + +``serialize`` (boolean, default: ``false``) + Whether to serialize messages or not. This is useful to test an additional + layer, especially when you use your own message serializer. + +.. versionadded:: 5.3 + + The ``serialize`` option was introduced in Symfony 5.3. + .. note:: All ``in-memory`` transports will be reset automatically after each test **in** @@ -1300,7 +1617,7 @@ Amazon SQS .. versionadded:: 5.1 - The Amazon SQS transport as introduced in Symfony 5.1. + The Amazon SQS transport was introduced in Symfony 5.1. The Amazon SQS transport is perfect for application hosted on AWS. Install it by running: @@ -1314,7 +1631,7 @@ The SQS transport DSN may looks like this: .. code-block:: env # .env - MESSENGER_TRANSPORT_DSN=sqs://AKIAIOSFODNN7EXAMPLE:j17M97ffSVoKI0briFoo9a@sqs.eu-west-3.amazonaws.com/messages + MESSENGER_TRANSPORT_DSN=https://sqs.eu-west-3.amazonaws.com/123456789012/messages?access_key=AKIAIOSFODNN7EXAMPLE&secret_key=j17M97ffSVoKI0briFoo9a MESSENGER_TRANSPORT_DSN=sqs://localhost:9494/messages?sslmode=disable .. note:: @@ -1322,27 +1639,43 @@ The SQS transport DSN may looks like this: The transport will automatically create queues that are needed. This can be disabled setting the ``auto_setup`` option to ``false``. +.. tip:: + + Before sending or receiving a message, Symfony needs to convert the queue + name into an AWS queue URL by calling the ``GetQueueUrl`` API in AWS. This + extra API call can be avoided by providing a DSN which is the queue URL. + + .. versionadded:: 5.2 + + The feature to provide the queue URL in the DSN was introduced in Symfony 5.2. + The transport has a number of options: ====================== ====================================== =================================== Option Description Default ====================== ====================================== =================================== -``access_key`` AWS access key +``access_key`` AWS access key must be urlencoded ``account`` Identifier of the AWS account The owner of the credentials -``auto_setup`` Whether the table should be created ``true`` +``auto_setup`` Whether the queue should be created ``true`` automatically during send / get. ``buffer_size`` Number of messages to prefetch 9 +``debug`` If ``true`` it logs all HTTP requests ``false`` + and responses (it impacts performance) ``endpoint`` Absolute URL to the SQS service https://sqs.eu-west-1.amazonaws.com ``poll_timeout`` Wait for new message duration in 0.1 seconds ``queue_name`` Name of the queue messages ``region`` Name of the AWS region eu-west-1 -``secret_key`` AWS secret key +``secret_key`` AWS secret key must be urlencoded ``visibility_timeout`` Amount of seconds the message will Queue's configuration not be visible (`Visibility Timeout`_) ``wait_time`` `Long polling`_ duration in seconds 20 ====================== ====================================== =================================== +.. versionadded:: 5.3 + + The ``debug`` option was introduced in Symfony 5.3. + .. note:: The ``wait_time`` parameter defines the maximum duration Amazon SQS should @@ -1416,23 +1749,21 @@ this globally (or for each transport) to a service that implements .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'serializer' => [ - 'default_serializer' => 'messenger.transport.symfony_serializer', - 'symfony_serializer' => [ - 'format' => 'json', - 'context' => [], - ], - ], - 'transports' => [ - 'async_priority_normal' => [ - 'dsn' => // ... - 'serializer' => 'messenger.transport.symfony_serializer', - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $messenger->serializer() + ->defaultSerializer('messenger.transport.symfony_serializer') + ->symfonySerializer() + ->format('json') + ->context('foo', 'bar'); + + $messenger->transport('async_priority_normal') + ->dsn(...) + ->serializer('messenger.transport.symfony_serializer'); + }; The ``messenger.transport.symfony_serializer`` is a built-in service that uses the :doc:`Serializer component ` and can be configured in a few ways. @@ -1654,17 +1985,17 @@ Then, make sure to "route" your message to *both* transports: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'async_priority_normal' => '...', - 'image_transport' => '...', - ], - 'routing' => [ - 'App\Message\UploadedImage' => ['image_transport', 'async_priority_normal'] - ] - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $messenger->transport('async_priority_normal')->dsn(...); + $messenger->transport('image_transport')->dsn(...); + + $messenger->routing('App\Message\UploadedImage') + ->senders(['image_transport', 'async_priority_normal']); + }; That's it! You can now consume each transport: @@ -1699,12 +2030,12 @@ to your message:: { $bus->dispatch(new SmsNotification('...'), [ // wait 5 seconds before processing - new DelayStamp(5000) + new DelayStamp(5000), ]); // or explicitly create an Envelope $bus->dispatch(new Envelope(new SmsNotification('...'), [ - new DelayStamp(5000) + new DelayStamp(5000), ])); // ... @@ -1797,22 +2128,16 @@ middleware and *only* include your own: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'buses' => [ - 'messenger.bus.default' => [ - // disable the default middleware - 'default_middleware' => false, - - // and/or add your own - 'middleware' => [ - 'App\Middleware\MyMiddleware', - 'App\Middleware\AnotherMiddleware', - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $bus = $messenger->bus('messenger.bus.default') + ->defaultMiddleware(false); + $bus->middleware()->id('App\Middleware\MyMiddleware'); + $bus->middleware()->id('App\Middleware\AnotherMiddleware'); + }; .. note:: @@ -1891,21 +2216,77 @@ may want to use: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'buses' => [ - 'command_bus' => [ - 'middleware' => [ - 'doctrine_transaction', - 'doctrine_ping_connection', - 'doctrine_close_connection', - // Using another entity manager - ['id' => 'doctrine_transaction', 'arguments' => ['custom']], - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $bus = $messenger->bus('command_bus'); + $bus->middleware()->id('doctrine_transaction'); + $bus->middleware()->id('doctrine_ping_connection'); + $bus->middleware()->id('doctrine_close_connection'); + // Using another entity manager + $bus->middleware()->id('doctrine_transaction') + ->arguments(['custom']); + }; + +Other Middlewares +~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.3 + + The ``router_context`` middleware was introduced in Symfony 5.3. + +Add the ``router_context`` middleware if you need to generate absolute URLs in +the consumer (e.g. render a template with links). This middleware stores the +original request context (i.e. the host, the HTTP port, etc.) which is needed +when building absolute URLs. + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/messenger.yaml + framework: + messenger: + buses: + command_bus: + middleware: + - router_context + + .. code-block:: xml + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/messenger.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $messenger = $framework->messenger(); + + $bus = $messenger->bus('command_bus'); + $bus->middleware()->id('router_context'); + }; + Messenger Events ~~~~~~~~~~~~~~~~ @@ -1941,7 +2322,9 @@ Learn more .. _`Enqueue's transport`: https://github.com/sroze/messenger-enqueue-transport .. _`streams`: https://redis.io/topics/streams-intro .. _`Supervisor docs`: http://supervisord.org/ +.. _`PCNTL`: https://www.php.net/manual/book.pcntl.php .. _`SymfonyCasts' message serializer tutorial`: https://symfonycasts.com/screencast/messenger/transport-serializer .. _`Long polling`: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html .. _`Visibility Timeout`: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html .. _`FIFO queue`: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html +.. _`LISTEN/NOTIFY`: https://www.postgresql.org/docs/current/sql-notify.html diff --git a/messenger/custom-transport.rst b/messenger/custom-transport.rst index be41d63a41e..ae15b15bbeb 100644 --- a/messenger/custom-transport.rst +++ b/messenger/custom-transport.rst @@ -65,7 +65,7 @@ Here is a simplified example of a database transport:: WHERE (delivered_at IS NULL OR delivered_at < :redeliver_timeout) AND handled = FALSE' ) - ->setParameter('redeliver_timeout', new DateTimeImmutable('-5minutes')) + ->setParameter('redeliver_timeout', new DateTimeImmutable('-5 minutes')) ->getOneOrNullResult(); if (null === $row) { @@ -203,13 +203,14 @@ named transport using your own DSN: .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'yours' => 'my-transport://...', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->messenger() + ->transport('yours') + ->dsn('my-transport://...') + ; + }; In addition of being able to route your messages to the ``yours`` sender, this will give you access to the following services: diff --git a/messenger/dispatch_after_current_bus.rst b/messenger/dispatch_after_current_bus.rst index e382f49eed3..7daaaebc676 100644 --- a/messenger/dispatch_after_current_bus.rst +++ b/messenger/dispatch_after_current_bus.rst @@ -40,7 +40,7 @@ DispatchAfterCurrentBusMiddleware Middleware -------------------------------------------- For many applications, the desired behavior is to *only* handle messages that -are dispatched by a handler once that handler has fully finished. This can be by +are dispatched by a handler once that handler has fully finished. This can be done by using the ``DispatchAfterCurrentBusMiddleware`` and adding a ``DispatchAfterCurrentBusStamp`` stamp to :ref:`the message Envelope `:: diff --git a/messenger/handler_results.rst b/messenger/handler_results.rst index dc4c1fd0821..8d630d011f4 100644 --- a/messenger/handler_results.rst +++ b/messenger/handler_results.rst @@ -11,7 +11,7 @@ You can use this to get the value returned by the handler(s):: use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\Stamp\HandledStamp; - $envelope = $messageBus->dispatch(SomeMessage()); + $envelope = $messageBus->dispatch(new SomeMessage()); // get the value that was returned by the last message handler $handledStamp = $envelope->last(HandledStamp::class); @@ -62,7 +62,7 @@ handler is registered. The ``HandleTrait`` can be used in any class that has a } // Creating such a method is optional, but allows type-hinting the result - private function query(ListItemsQuery $query): ListItemsResult + private function query(ListItemsQuery $query): ListItemsQueryResult { return $this->handle($query); } diff --git a/messenger/multiple_buses.rst b/messenger/multiple_buses.rst index 5136553dac2..5a1ffecf94c 100644 --- a/messenger/multiple_buses.rst +++ b/messenger/multiple_buses.rst @@ -34,6 +34,8 @@ an **event bus**. The event bus could have zero or more subscribers. middleware: - validation event.bus: + # the 'allow_no_handlers' middleware allows to have no handler + # configured for this bus without throwing an exception default_middleware: allow_no_handlers middleware: - validation @@ -56,13 +58,15 @@ an **event bus**. The event bus could have zero or more subscribers. - + - + + - + @@ -70,31 +74,25 @@ an **event bus**. The event bus could have zero or more subscribers. .. code-block:: php // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - // The bus that is going to be injected when injecting MessageBusInterface - 'default_bus' => 'command.bus', - 'buses' => [ - 'command.bus' => [ - 'middleware' => [ - 'validation', - 'doctrine_transaction', - ], - ], - 'query.bus' => [ - 'middleware' => [ - 'validation', - ], - ], - 'event.bus' => [ - 'default_middleware' => 'allow_no_handlers', - 'middleware' => [ - 'validation', - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + // The bus that is going to be injected when injecting MessageBusInterface + $framework->messenger()->defaultBus('command.bus'); + + $commandBus = $framework->messenger()->bus('command.bus'); + $commandBus->middleware()->id('validation'); + $commandBus->middleware()->id('doctrine_transaction'); + + $queryBus = $framework->messenger()->bus('query.bus'); + $queryBus->middleware()->id('validation'); + + $eventBus = $framework->messenger()->bus('event.bus'); + // the 'allow_no_handlers' middleware allows to have no handler + // configured for this bus without throwing an exception + $eventBus->defaultMiddleware('allow_no_handlers'); + $eventBus->middleware()->id('validation'); + }; This will create three new services: @@ -150,30 +148,30 @@ you can restrict each handler to a specific bus using the ``messenger.message_ha This way, the ``App\MessageHandler\SomeCommandHandler`` handler will only be known by the ``command.bus`` bus. -You can also automatically add this tag to a number of classes by following -a naming convention and registering all of the handler services by name with -the correct tag: +You can also automatically add this tag to a number of classes by using +the :ref:`_instanceof service configuration `. Using this, +you can determine the message bus based on an implemented interface: .. configuration-block:: .. code-block:: yaml # config/services.yaml + services: + # ... + + _instanceof: + # all services implementing the CommandHandlerInterface + # will be registered on the command.bus bus + App\MessageHandler\CommandHandlerInterface: + tags: + - { name: messenger.message_handler, bus: command.bus } - # put this after the "App\" line that registers all your services - command_handlers: - namespace: App\MessageHandler\ - resource: '%kernel.project_dir%/src/MessageHandler/*CommandHandler.php' - autoconfigure: false - tags: - - { name: messenger.message_handler, bus: command.bus } - - query_handlers: - namespace: App\MessageHandler\ - resource: '%kernel.project_dir%/src/MessageHandler/*QueryHandler.php' - autoconfigure: false - tags: - - { name: messenger.message_handler, bus: query.bus } + # while those implementing QueryHandlerInterface will be + # registered on the query.bus bus + App\MessageHandler\QueryHandlerInterface: + tags: + - { name: messenger.message_handler, bus: query.bus } .. code-block:: xml @@ -185,32 +183,45 @@ the correct tag: https://symfony.com/schema/dic/services/services-1.0.xsd"> - - + + + + - - - + + + + - + .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; - // Command handlers - $container->services() - ->load('App\MessageHandler\\', '%kernel.project_dir%/src/MessageHandler/*CommandHandler.php') - ->autoconfigure(false) - ->tag('messenger.message_handler', ['bus' => 'command.bus']); + use App\MessageHandler\CommandHandlerInterface; + use App\MessageHandler\QueryHandlerInterface; - // Query handlers - $container->services() - ->load('App\MessageHandler\\', '%kernel.project_dir%/src/MessageHandler/*QueryHandler.php') - ->autoconfigure(false) - ->tag('messenger.message_handler', ['bus' => 'query.bus']); + return function(ContainerConfigurator $configurator) { + $services = $configurator->services(); + + // ... + + // all services implementing the CommandHandlerInterface + // will be registered on the command.bus bus + $services->instanceof(CommandHandlerInterface::class) + ->tag('messenger.message_handler', ['bus' => 'command.bus']); + + // while those implementing QueryHandlerInterface will be + // registered on the query.bus bus + $services->instanceof(QueryHandlerInterface::class) + ->tag('messenger.message_handler', ['bus' => 'query.bus']); + }; Debugging the Buses ------------------- @@ -249,4 +260,9 @@ You can also restrict the list to a specific bus by providing its name as argume handled by App\MessageHandler\MultipleBusesMessageHandler --------------------------------------------------------------------------------------- +.. tip:: + + Since Symfony 5.1, the command will also show the PHPDoc description of + the message and handler classes. + .. _article about CQRS: https://martinfowler.com/bliki/CQRS.html diff --git a/migration.rst b/migration.rst index fa8c2bfc24b..71c55ba240d 100644 --- a/migration.rst +++ b/migration.rst @@ -7,7 +7,7 @@ Migrating an Existing Application to Symfony When you have an existing application that was not built with Symfony, you might want to move over parts of that application without rewriting the existing logic completely. For those cases there is a pattern called -`Strangler Application`_. The basic idea of this pattern is to create a +`Strangler Fig Application`_. The basic idea of this pattern is to create a new application that gradually takes over functionality from an existing application. This migration approach can be implemented with Symfony in various ways and has some benefits over a rewrite such as being able @@ -82,7 +82,7 @@ Setting up Composer Another point you will have to look out for is conflicts between dependencies in both applications. This is especially important if your existing application already uses Symfony components or libraries commonly -used in Symfony applications such as Doctrine ORM, Swiftmailer or Twig. +used in Symfony applications such as Doctrine ORM or Twig. A good way for ensuring compatibility is to use the same ``composer.json`` for both project's dependencies. @@ -238,6 +238,7 @@ could look something like this:: // public/index.php use App\Kernel; use App\LegacyBridge; + use Symfony\Component\Dotenv\Dotenv; use Symfony\Component\ErrorHandler\Debug; use Symfony\Component\HttpFoundation\Request; @@ -262,7 +263,7 @@ could look something like this:: if ($trustedProxies = $_SERVER['TRUSTED_PROXIES'] ?? $_ENV['TRUSTED_PROXIES'] ?? false) { Request::setTrustedProxies( explode(',', $trustedProxies), - Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST + Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO ); } @@ -288,7 +289,7 @@ could look something like this:: There are 2 major deviations from the original file: -Line 15 +Line 18 First of all, ``$kernel`` is made globally available. This allows you to use Symfony features inside your existing application and gives access to services configured in our Symfony application. This helps you prepare your @@ -296,7 +297,7 @@ Line 15 it over. For instance, by replacing outdated or redundant libraries with Symfony components. -Line 38 - 47 +Line 41 - 50 Instead of sending the Symfony response directly, a ``LegacyBridge`` is called to decide whether the legacy application should be booted and used to create the response instead. @@ -315,11 +316,11 @@ somewhat like this:: class LegacyBridge { - public static function prepareLegacyScript(Request $request, Response $response, string $publicDirectory): string + public static function prepareLegacyScript(Request $request, Response $response, string $publicDirectory): ?string { // If Symfony successfully handled the route, you do not have to do anything. if (false === $response->isNotFound()) { - return; + return null; } // Figure out how to map to the needed script file @@ -463,7 +464,7 @@ chance to use Symfony's event lifecycle. For instance, this allows you to transition the authentication and authorization of the legacy application over to the Symfony application using the Security component and its firewalls. -.. _`Strangler Application`: https://martinfowler.com/bliki/StranglerFigApplication.html +.. _`Strangler Fig Application`: https://martinfowler.com/bliki/StranglerFigApplication.html .. _`autoload`: https://getcomposer.org/doc/04-schema.md#autoload .. _`Modernizing with Symfony`: https://youtu.be/YzyiZNY9htQ .. _`Symfony Panther`: https://github.com/symfony/panther diff --git a/notifier.rst b/notifier.rst index b626a79ac39..febb0d331e4 100644 --- a/notifier.rst +++ b/notifier.rst @@ -6,8 +6,7 @@ Creating and Sending Notifications .. versionadded:: 5.0 - The Notifier component was introduced in Symfony 5.0 as an - :doc:`experimental feature `. + The Notifier component was introduced in Symfony 5.0. Installation ------------ @@ -22,8 +21,10 @@ Get the Notifier installed using: $ composer require symfony/notifier -Channels: Chatters, Texters, Email and Browser ----------------------------------------------- +.. _channels-chatters-texters-email-and-browser: + +Channels: Chatters, Texters, Email, Browser and Push +---------------------------------------------------- The notifier component can send notifications to different channels. Each channel can integrate with different providers (e.g. Slack or Twilio SMS) @@ -37,6 +38,7 @@ The notifier component supports the following channels: services like Slack and Telegram; * :ref:`Email channel ` integrates the :doc:`Symfony Mailer `; * Browser channel uses :ref:`flash messages `. +* Push Channel sends notifications to phones and browsers via push notifications. .. tip:: @@ -54,20 +56,39 @@ to send SMS messages to mobile phones. This feature requires subscribing to a third-party service that sends SMS messages. Symfony provides integration with a couple popular SMS services: -========== ================================ ==================================================== -Service Package DSN -========== ================================ ==================================================== -Esendex ``symfony/esendex-notifier`` ``esendex://USER_NAME:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM`` -FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` -Infobip ``symfony/infobip-notifier`` ``infobip://TOKEN@default?from=FROM`` -Mobyt ``symfony/mobyt-notifier`` ``mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM`` -Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` -OvhCloud ``symfony/ovhcloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` -Sendinblue ``symfony/sendinblue-notifier`` ``sendinblue://API_KEY@default?sender=PHONE`` -Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` -Smsapi ``symfony/smsapi-notifier`` ``smsapi://TOKEN@default?from=FROM`` -Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` -========== ================================ ==================================================== +============== ==================================== =========================================================================== +Service Package DSN +============== ==================================== =========================================================================== +AllMySms ``symfony/allmysms-notifier`` ``allmysms://LOGIN:APIKEY@default?from=FROM`` +AmazonSns ``symfony/amazon-sns-notifier`` ``sns://ACCESS_KEY:SECRET_KEY@default?region=REGION`` +Clickatell ``symfony/clickatell-notifier`` ``clickatell://ACCESS_TOKEN@default?from=FROM`` +Esendex ``symfony/esendex-notifier`` ``esendex://USER_NAME:PASSWORD@default?accountreference=ACCOUNT_REFERENCE&from=FROM`` +FakeSms ``symfony/fake-sms-notifier`` ``fakesms+email://MAILER_SERVICE_ID?to=TO&from=FROM`` or ``fakesms+logger://default`` +FreeMobile ``symfony/free-mobile-notifier`` ``freemobile://LOGIN:PASSWORD@default?phone=PHONE`` +GatewayApi ``symfony/gatewayapi-notifier`` ``gatewayapi://TOKEN@default?from=FROM`` +Infobip ``symfony/infobip-notifier`` ``infobip://AUTH_TOKEN@HOST?from=FROM`` +Iqsms ``symfony/iqsms-notifier`` ``iqsms://LOGIN:PASSWORD@default?from=FROM`` +LightSms ``symfony/light-sms-notifier`` ``lightsms://LOGIN:TOKEN@default?from=PHONE`` +Mailjet ``symfony/mailjet-notifier`` ``mailjet://TOKEN@default?from=FROM`` +MessageBird ``symfony/message-bird-notifier`` ``messagebird://TOKEN@default?from=FROM`` +MessageMedia ``symfony/message-media-notifier`` ``messagemedia://API_KEY:API_SECRET@default?from=FROM`` +Mobyt ``symfony/mobyt-notifier`` ``mobyt://USER_KEY:ACCESS_TOKEN@default?from=FROM`` +Nexmo ``symfony/nexmo-notifier`` ``nexmo://KEY:SECRET@default?from=FROM`` +Octopush ``symfony/octopush-notifier`` ``octopush://USERLOGIN:APIKEY@default?from=FROM&type=TYPE`` +OvhCloud ``symfony/ovh-cloud-notifier`` ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` +Sendinblue ``symfony/sendinblue-notifier`` ``sendinblue://API_KEY@default?sender=PHONE`` +Sms77 ``symfony/sms77-notifier`` ``sms77://API_KEY@default?from=FROM`` +Sinch ``symfony/sinch-notifier`` ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` +Smsapi ``symfony/smsapi-notifier`` ``smsapi://TOKEN@default?from=FROM`` +SmsBiuras ``symfony/sms-biuras-notifier`` ``smsbiuras://UID:API_KEY@default?from=FROM&test_mode=0`` +Smsc ``symfony/smsc-notifier`` ``smsc://LOGIN:PASSWORD@default?from=FROM`` +SpotHit ``symfony/spothit-notifier`` ``spothit://TOKEN@default?from=FROM`` +Telnyx ``symfony/telnyx-notifier`` ``telnyx://API_KEY@default?from=FROM&messaging_profile_id=MESSAGING_PROFILE_ID`` +TurboSms ``symfony/turbo-sms-notifier`` ``turbosms://AUTH_TOKEN@default?from=FROM`` +Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from=FROM`` +Vonage ``symfony/vonage-notifier`` ``vonage://KEY:SECRET@default?from=FROM`` +Yunpian ``symfony/yunpian-notifier`` ``yunpian://APIKEY@default`` +============== ==================================== =========================================================================== .. versionadded:: 5.1 @@ -77,6 +98,20 @@ Twilio ``symfony/twilio-notifier`` ``twilio://SID:TOKEN@default?from= The Smsapi, Infobip, Mobyt, Esendex and Sendinblue integrations were introduced in Symfony 5.2. +.. versionadded:: 5.3 + + The Iqsms, GatewayApi, Octopush, AllMySms, Clickatell, SpotHit, FakeSms (email), LightSms, SmsBiuras + and MessageBird integrations were introduced in Symfony 5.3. + +.. deprecated:: 5.4 + + The Nexmo integration was deprecated in Symfony 5.4, use the Vonage integration instead. + +.. versionadded:: 5.4 + + The MessageMedia, Smsc, Yunpian, AmazonSns, Telnyx, TurboSms, Mailjet, FakeSms (logger), + Sms77 and Vonage integrations were introduced in Symfony 5.4. + To enable a texter, add the correct DSN in your ``.env`` file and configure the ``texter_transports``: @@ -118,14 +153,14 @@ configure the ``texter_transports``: .. code-block:: php - # config/packages/notifier.php - $container->loadFromExtension('framework', [ - 'notifier' => [ - 'texter_transports' => [ - 'twilio' => '%env(TWILIO_DSN)%', - ], - ], - ]); + // config/packages/notifier.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->notifier() + ->texterTransport('twilio', '%env(TWILIO_DSN)%') + ; + }; .. _notifier-chat-channel: .. _notifier-chatter-dsn: @@ -137,35 +172,50 @@ The chat channel is used to send chat messages to users by using :class:`Symfony\\Component\\Notifier\\Chatter` classes. Symfony provides integration with these chat services: -========== ================================ =========================================================================== -Service Package DSN -========== ================================ =========================================================================== -Discord ``symfony/discord-notifier`` ``discord://TOKEN@default?webhook_id=ID`` -GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?threadKey=THREAD_KEY`` -LinkedIn ``symfony/linked-in-notifier`` ``linkedin://TOKEN:USER_ID@default`` -Mattermost ``symfony/mattermost-notifier`` ``mattermost://TOKEN@ENDPOINT?channel=CHANNEL`` -RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` -Slack ``symfony/slack-notifier`` ``slack://default/ID`` -Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` -Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:APIKEY@ENDPOINT?channel=CHANNEL`` -========== ================================ =========================================================================== +============== ==================================== ============================================================================= +Service Package DSN +============== ==================================== ============================================================================= +AmazonSns ``symfony/amazon-sns-notifier`` ``sns://ACCESS_KEY:SECRET_KEY@default?region=REGION`` +Discord ``symfony/discord-notifier`` ``discord://TOKEN@default?webhook_id=ID`` +FakeChat ``symfony/fake-chat-notifier`` ``fakechat+email://default?to=TO&from=FROM`` or ``fakechat+logger://default`` +Firebase ``symfony/firebase-notifier`` ``firebase://USERNAME:PASSWORD@default`` +Gitter ``symfony/gitter-notifier`` ``gitter://TOKEN@default?room_id=ROOM_ID`` +GoogleChat ``symfony/google-chat-notifier`` ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?thread_key=THREAD_KEY`` +LinkedIn ``symfony/linked-in-notifier`` ``linkedin://TOKEN:USER_ID@default`` +Mattermost ``symfony/mattermost-notifier`` ``mattermost://ACCESS_TOKEN@HOST/PATH?channel=CHANNEL`` +Mercure ``symfony/mercure-notifier`` ``mercure://HUB_ID?topic=TOPIC`` +MicrosoftTeams ``symfony/microsoft-teams-notifier`` ``microsoftteams://default/PATH`` +RocketChat ``symfony/rocket-chat-notifier`` ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL`` +Slack ``symfony/slack-notifier`` ``slack://TOKEN@default?channel=CHANNEL`` +Telegram ``symfony/telegram-notifier`` ``telegram://TOKEN@default?channel=CHAT_ID`` +Zulip ``symfony/zulip-notifier`` ``zulip://EMAIL:TOKEN@HOST?channel=CHANNEL`` +============== ==================================== ============================================================================= .. versionadded:: 5.1 - The Mattermost and RocketChat integrations were introduced in Symfony + The Firebase, Mattermost and RocketChat integrations were introduced in Symfony 5.1. The Slack DSN changed in Symfony 5.1 to use Slack Incoming Webhooks instead of legacy tokens. .. versionadded:: 5.2 The GoogleChat, LinkedIn, Zulip and Discord integrations were introduced in Symfony 5.2. + The Slack DSN changed in Symfony 5.2 to use Slack Web API again same as in 5.0. + +.. versionadded:: 5.3 + + The Gitter, Mercure, FakeChat (email) and Microsoft Teams integrations were introduced in Symfony 5.3. + +.. versionadded:: 5.4 + + The AmazonSns and FakeChat (logger) integrations were introduced in Symfony 5.4. Chatters are configured using the ``chatter_transports`` setting: .. code-block:: bash # .env - SLACK_DSN=slack://default/ID + SLACK_DSN=slack://TOKEN@default?channel=CHANNEL .. configuration-block:: @@ -200,14 +250,14 @@ Chatters are configured using the ``chatter_transports`` setting: .. code-block:: php - # config/packages/notifier.php - $container->loadFromExtension('framework', [ - 'notifier' => [ - 'chatter_transports' => [ - 'slack' => '%env(SLACK_DSN)%', - ], - ], - ]); + // config/packages/notifier.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->notifier() + ->chatterTransport('slack', '%env(SLACK_DSN)%') + ; + }; .. _notifier-email-channel: @@ -264,15 +314,85 @@ notification emails: .. code-block:: php - # config/packages/mailer.php - $container->loadFromExtension('framework', [ - 'mailer' => [ - 'dsn' => '%env(MAILER_DSN)%', - 'envelope' => [ - 'sender' => 'notifications@example.com', - ], - ], - ]); + // config/packages/mailer.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->mailer() + ->dsn('%env(MAILER_DSN)%') + ->envelope() + ->sender('notifications@example.com') + ; + }; + +Push Channel +~~~~~~~~~~~~ + +The push channel is used to send notifications to users by using +:class:`Symfony\\Component\\Notifier\\Texter` classes. Symfony provides +integration with these push services: + +============== ==================================== ================================================================================= +Service Package DSN +============== ==================================== ================================================================================= +Firebase ``symfony/firebase-notifier`` ``firebase://USERNAME:PASSWORD@default`` +Expo ``symfony/expo-notifier`` ``expo://Token@default`` +OneSignal ``symfony/one-signal-notifier`` ``onesignal://APP_ID:API_KEY@default?defaultRecipientId=DEFAULT_RECIPIENT_ID''`` +============== ==================================== ================================================================================= + +.. versionadded:: 5.4 + + The Expo and OneSignal integrations were introduced in Symfony 5.4. + +To enable a texter, add the correct DSN in your ``.env`` file and +configure the ``texter_transports``: + +.. code-block:: bash + + # .env + EXPO_DSN=expo://TOKEN@default + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/notifier.yaml + framework: + notifier: + texter_transports: + expo: '%env(EXPO_DSN)%' + + .. code-block:: xml + + + + + + + + + %env(EXPO_DSN)% + + + + + + .. code-block:: php + + // config/packages/notifier.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->notifier() + ->texterTransport('expo', '%env(EXPO_DSN)%') + ; + }; Configure to use Failover or Round-Robin Transports ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -327,19 +447,19 @@ transport: .. code-block:: php - # config/packages/notifier.php - $container->loadFromExtension('framework', [ - 'notifier' => [ - 'chatter_transports' => [ - // Send notifications to Slack and use Telegram if - // Slack errored - 'main' => '%env(SLACK_DSN)% || %env(TELEGRAM_DSN)%', + // config/packages/notifier.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->notifier() + // Send notifications to Slack and use Telegram if + // Slack errored + ->chatterTransport('main', '%env(SLACK_DSN)% || %env(TELEGRAM_DSN)%') - // Send notifications to the next scheduled transport calculated by round robin - 'roundrobin' => '%env(SLACK_DSN)% && %env(TELEGRAM_DSN)%', - ], - ], - ]); + // Send notifications to the next scheduled transport calculated by round robin + ->chatterTransport('roundrobin', '%env(SLACK_DSN)% && %env(TELEGRAM_DSN)%') + ; + }; Creating & Sending Notifications -------------------------------- @@ -378,7 +498,7 @@ To send a notification, autowire the ); // Send the notification to the recipient - $sentMessage = $notifier->send($notification, $recipient); + $notifier->send($notification, $recipient); // ... } @@ -389,14 +509,6 @@ channels. The channels specify which channel (or transport) should be used to send the notification. For instance, ``['email', 'sms']`` will send both an email and sms notification to the user. -The ``send()`` method used to send the notification returns a variable of type -:class:`Symfony\\Component\\Notifier\\Message\\SentMessage` which provides -information such as the message ID and the original message contents. - -.. versionadded:: 5.2 - - The ``SentMessage`` class was introduced in Symfony 5.2. - The default notification also has a ``content()`` and ``emoji()`` method to set the notification content and icon. @@ -479,23 +591,21 @@ specify what channels should be used for specific levels (using .. code-block:: php - # config/packages/notifier.php - $container->loadFromExtension('framework', [ - 'notifier' => [ - // ... - 'channel_policy' => [ - // Use SMS, Slack and email for urgent notifications - 'urgent' => ['sms', 'chat/slack', 'email'], + // config/packages/notifier.php + use Symfony\Config\FrameworkConfig; - // Use Slack for highly important notifications - 'high' => ['chat/slack'], - - // Use browser for medium and low notifications - 'medium' => ['browser'], - 'low' => ['browser'], - ], - ], - ]); + return static function (FrameworkConfig $framework) { + // ... + $framework->notifier() + // Use SMS, Slack and email for urgent notifications + ->channelPolicy('urgent', ['sms', 'chat/slack', 'email']) + // Use Slack for highly important notifications + ->channelPolicy('high', ['chat/slack']) + // Use browser for medium and low notifications + ->channelPolicy('medium', ['browser']) + ->channelPolicy('medium', ['browser']) + ; + }; Now, whenever the notification's importance is set to "high", it will be sent using the Slack transport:: @@ -514,7 +624,7 @@ sent using the Slack transport:: ->content('You got a new invoice for 15 EUR.') ->importance(Notification::IMPORTANCE_HIGH); - $notifier->send($notification, new Recipient('wouter@wouterj.nl')); + $notifier->send($notification, new Recipient('wouter@example.com')); // ... } @@ -600,7 +710,7 @@ The :class:`Symfony\\Component\\Notifier\\Notification\\SmsNotificationInterface` and :class:`Symfony\\Component\\Notifier\\Notification\\EmailNotificationInterface` -also exists to modify messages send to those channels. +also exists to modify messages sent to those channels. Disabling Delivery ------------------ diff --git a/notifier/chatters.rst b/notifier/chatters.rst index 9d03f83987c..bc1a4da1914 100644 --- a/notifier/chatters.rst +++ b/notifier/chatters.rst @@ -6,8 +6,7 @@ How to send Chat Messages .. versionadded:: 5.0 - The Notifier component was introduced in Symfony 5.0 as an - :doc:`experimental feature `. + The Notifier component was introduced in Symfony 5.0. The :class:`Symfony\\Component\\Notifier\\ChatterInterface` class allows you to send messages to chat services like Slack or Telegram:: @@ -55,12 +54,12 @@ Adding Interactions to a Slack Message -------------------------------------- With a Slack message, you can use the -:class:`Symfony\\Component\\Notifier\\Bridge\\Slack\\SlackOptions` to add -some interactive options called `Block elements`_:: +:class:`Symfony\\Component\\Notifier\\Bridge\\Slack\\SlackOptions` class +to add some interactive options called `Block elements`_:: use Symfony\Component\Notifier\Bridge\Slack\Block\SlackActionsBlock; use Symfony\Component\Notifier\Bridge\Slack\Block\SlackDividerBlock; - use Symfony\Component\Notifier\Bridge\Slack\Block\SlackImageBlock; + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackImageBlockElement; use Symfony\Component\Notifier\Bridge\Slack\Block\SlackSectionBlock; use Symfony\Component\Notifier\Bridge\Slack\SlackOptions; use Symfony\Component\Notifier\Message\ChatMessage; @@ -98,20 +97,170 @@ some interactive options called `Block elements`_:: $chatter->send($chatMessage); -.. _`Block elements`: https://api.slack.com/reference/block-kit/block-elements +Adding Fields and Values to a Slack Message +------------------------------------------- + +To add fields and values to your message you can use the +:method:`SlackSectionBlock::field() ` method:: + + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackDividerBlock; + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackSectionBlock; + use Symfony\Component\Notifier\Bridge\Slack\SlackOptions; + use Symfony\Component\Notifier\Message\ChatMessage; + + $chatMessage = new ChatMessage('Symfony Feature'); + + $options = (new SlackOptions()) + ->block((new SlackSectionBlock())->text('My message')) + ->block(new SlackDividerBlock()) + ->block( + (new SlackSectionBlock()) + ->field('*Max Rating*') + ->field('5.0') + ->field('*Min Rating*') + ->field('1.0') + ); + + // Add the custom options to the chat message and send the message + $chatMessage->options($options); + + $chatter->send($chatMessage); + +The result will be something like: + +.. image:: /_images/notifier/slack/field-method.png + :align: center + +.. versionadded:: 5.1 + + The `field()` method was introduced in Symfony 5.1. + +Adding a Header to a Slack Message +---------------------------------- + +To add a header to your message use the +:class:`Symfony\\Component\\Notifier\\Bridge\\Slack\\Block\\SlackHeaderBlock` class:: + + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackDividerBlock; + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackHeaderBlock; + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackSectionBlock; + use Symfony\Component\Notifier\Bridge\Slack\SlackOptions; + use Symfony\Component\Notifier\Message\ChatMessage; + + $chatMessage = new ChatMessage('Symfony Feature'); + + $options = (new SlackOptions()) + ->block((new SlackHeaderBlock('My Header'))) + ->block((new SlackSectionBlock())->text('My message')) + ->block(new SlackDividerBlock()) + ->block( + (new SlackSectionBlock()) + ->field('*Max Rating*') + ->field('5.0') + ->field('*Min Rating*') + ->field('1.0') + ); + + // Add the custom options to the chat message and send the message + $chatMessage->options($options); + + $chatter->send($chatMessage); + +The result will be something like: + +.. image:: /_images/notifier/slack/slack-header.png + :align: center + +.. versionadded:: 5.3 + + The ``SlackHeaderBlock`` class was introduced in Symfony 5.3. + +Adding a Footer to a Slack Message +---------------------------------- + +To add a footer to your message use the +:class:`Symfony\\Component\\Notifier\\Bridge\\Slack\\Block\\SlackContextBlock` class:: + + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackContextBlock; + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackDividerBlock; + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackSectionBlock; + use Symfony\Component\Notifier\Bridge\Slack\SlackOptions; + use Symfony\Component\Notifier\Message\ChatMessage; + + $chatMessage = new ChatMessage('Symfony Feature'); + + $contextBlock = (new SlackContextBlock()) + ->text('My Context') + ->image('https://symfony.com/logos/symfony_white_03.png', 'Symfony Logo') + ; + + $options = (new SlackOptions()) + ->block((new SlackSectionBlock())->text('My message')) + ->block(new SlackDividerBlock()) + ->block( + (new SlackSectionBlock()) + ->field('*Max Rating*') + ->field('5.0') + ->field('*Min Rating*') + ->field('1.0') + ) + ->block($contextBlock) + ; + + $chatter->send($chatMessage); + +The result will be something like: + +.. image:: /_images/notifier/slack/slack-footer.png + :align: center + +.. versionadded:: 5.3 + + The ``SlackContextBlock`` class was introduced in Symfony 5.3. + +Sending a Slack Message as a Reply +---------------------------------- + +To send your slack message as a reply in a thread use the +:method:`SlackOptions::threadTs() ` method:: + + use Symfony\Component\Notifier\Bridge\Slack\Block\SlackSectionBlock; + use Symfony\Component\Notifier\Bridge\Slack\SlackOptions; + use Symfony\Component\Notifier\Message\ChatMessage; + + $chatMessage = new ChatMessage('Symfony Feature'); + + $options = (new SlackOptions()) + ->block((new SlackSectionBlock())->text('My reply')) + ->threadTs('1621592155.003100') + ; + + // Add the custom options to the chat message and send the message + $chatMessage->options($options); + + $chatter->send($chatMessage); + +The result will be something like: + +.. image:: /_images/notifier/slack/message-reply.png + :align: center + +.. versionadded:: 5.3 + + The ``threadTs()`` method was introduced in Symfony 5.3. Adding Interactions to a Discord Message ---------------------------------------- With a Discord message, you can use the -:class:`Symfony\\Component\\Notifier\\Bridge\\Discord\\DiscordOptions` to add -some interactive options called `Embed elements`_:: +:class:`Symfony\\Component\\Notifier\\Bridge\\Discord\\DiscordOptions` class +to add some interactive options called `Embed elements`_:: - use Symfony\Component\Notifier\Bridge\Discord\Block\DiscordEmbed; - use Symfony\Component\Notifier\Bridge\Discord\Block\DiscordFieldEmbedObject; - use Symfony\Component\Notifier\Bridge\Discord\Block\DiscordFooterEmbedObject; - use Symfony\Component\Notifier\Bridge\Discord\Block\DiscordMediaEmbedObject; use Symfony\Component\Notifier\Bridge\Discord\DiscordOptions; + use Symfony\Component\Notifier\Bridge\Discord\Embeds\DiscordEmbed; + use Symfony\Component\Notifier\Bridge\Discord\Embeds\DiscordFieldEmbedObject; + use Symfony\Component\Notifier\Bridge\Discord\Embeds\DiscordFooterEmbedObject; + use Symfony\Component\Notifier\Bridge\Discord\Embeds\DiscordMediaEmbedObject; use Symfony\Component\Notifier\Message\ChatMessage; $chatMessage = new ChatMessage(''); @@ -151,4 +300,131 @@ some interactive options called `Embed elements`_:: $chatter->send($chatMessage); +Adding Interactions to a Telegram Message +----------------------------------------- + +With a Telegram message, you can use the +:class:`Symfony\\Component\\Notifier\\Bridge\\Telegram\\TelegramOptions` class +to add `message options`_:: + + use Symfony\Component\Notifier\Bridge\Telegram\Reply\Markup\Button\InlineKeyboardButton; + use Symfony\Component\Notifier\Bridge\Telegram\Reply\Markup\InlineKeyboardMarkup; + use Symfony\Component\Notifier\Bridge\Telegram\TelegramOptions; + use Symfony\Component\Notifier\Message\ChatMessage; + + $chatMessage = new ChatMessage(''); + + // Create Telegram options + $telegramOptions = (new TelegramOptions()) + ->chatId('@symfonynotifierdev') + ->parseMode('MarkdownV2') + ->disableWebPagePreview(true) + ->disableNotification(true) + ->replyMarkup((new InlineKeyboardMarkup()) + ->inlineKeyboard([ + (new InlineKeyboardButton('Visit symfony.com')) + ->url('https://symfony.com/'), + ]) + ); + + // Add the custom options to the chat message and send the message + $chatMessage->options($telegramOptions); + + $chatter->send($chatMessage); + +Adding text to a Microsoft Teams Message +---------------------------------------- + +With a Microsoft Teams, you can use the ChatMessage class:: + + use Symfony\Component\Notifier\Bridge\MicrosoftTeams\MicrosoftTeamsTransport; + use Symfony\Component\Notifier\Message\ChatMessage; + + $chatMessage = (new ChatMessage('Contribute To Symfony'))->transport('microsoftteams'); + $chatter->send($chatMessage); + +The result will be something like: + +.. image:: /_images/notifier/microsoft_teams/message.png + :align: center + +Adding Interactions to a Microsoft Teams Message +------------------------------------------------ + +With a Microsoft Teams Message, you can use the +:class:`Symfony\\Component\\Notifier\\Bridge\\MicrosoftTeams\\MicrosoftTeamsOptions` class +to add `MessageCard options`_:: + + use Symfony\Component\Notifier\Bridge\MicrosoftTeams\Action\ActionCard; + use Symfony\Component\Notifier\Bridge\MicrosoftTeams\Action\HttpPostAction; + use Symfony\Component\Notifier\Bridge\MicrosoftTeams\Action\Input\DateInput; + use Symfony\Component\Notifier\Bridge\MicrosoftTeams\Action\Input\TextInput; + use Symfony\Component\Notifier\Bridge\MicrosoftTeams\MicrosoftTeamsOptions; + use Symfony\Component\Notifier\Bridge\MicrosoftTeams\MicrosoftTeamsTransport; + use Symfony\Component\Notifier\Bridge\MicrosoftTeams\Section\Field\Fact; + use Symfony\Component\Notifier\Bridge\MicrosoftTeams\Section\Section; + use Symfony\Component\Notifier\Message\ChatMessage; + + $chatMessage = new ChatMessage(''); + + // Action elements + $input = new TextInput(); + $input->id('input_title'); + $input->isMultiline(true)->maxLength(5)->title('In a few words, why would you like to participate?'); + + $inputDate = new DateInput(); + $inputDate->title('Proposed date')->id('input_date'); + + // Create Microsoft Teams MessageCard + $microsoftTeamsOptions = (new MicrosoftTeamsOptions()) + ->title('Symfony Online Meeting') + ->text('Symfony Online Meeting are the events where the best developers meet to share experiences...') + ->summary('Summary') + ->themeColor('#F4D35E') + ->section((new Section()) + ->title('Talk about Symfony 5.3 - would you like to join? Please give a shout!') + ->fact((new Fact()) + ->name('Presenter') + ->value('Fabien Potencier') + ) + ->fact((new Fact()) + ->name('Speaker') + ->value('Patricia Smith') + ) + ->fact((new Fact()) + ->name('Duration') + ->value('90 min') + ) + ->fact((new Fact()) + ->name('Date') + ->value('TBA') + ) + ) + ->action((new ActionCard()) + ->name('ActionCard') + ->input($input) + ->input($inputDate) + ->action((new HttpPostAction()) + ->name('Add comment') + ->target('http://target') + ) + ) + ; + + // Add the custom options to the chat message and send the message + $chatMessage->options($microsoftTeamsOptions); + $chatter->send($chatMessage); + +The result will be something like: + +.. image:: /_images/notifier/microsoft_teams/message-card.png + :align: center + +.. versionadded:: 5.4 + + Options for Microsoft Teams were introduced in Symfony 5.4. + +.. _`Block elements`: https://api.slack.com/reference/block-kit/block-elements .. _`Embed elements`: https://discord.com/developers/docs/resources/webhook +.. _`message options`: https://core.telegram.org/bots/api +.. _`MessageCard options`: https://docs.microsoft.com/en-us/outlook/actionable-messages/message-card-reference diff --git a/notifier/texters.rst b/notifier/texters.rst index eb663b13726..4cf9b6f2de2 100644 --- a/notifier/texters.rst +++ b/notifier/texters.rst @@ -6,8 +6,7 @@ How to send SMS Messages .. versionadded:: 5.0 - The Notifier component was introduced in Symfony 5.0 as an - :doc:`experimental feature `. + The Notifier component was introduced in Symfony 5.0. The :class:`Symfony\\Component\\Notifier\\TexterInterface` class allows you to send SMS messages:: diff --git a/page_creation.rst b/page_creation.rst index 0d7ff3e910b..012fc208c15 100644 --- a/page_creation.rst +++ b/page_creation.rst @@ -81,13 +81,13 @@ If you see a lucky number being printed back to you, congratulations! But before you run off to play the lottery, check out how this works. Remember the two steps to creating a page? -#. *Create a route*: In ``config/routes.yaml``, the route defines the URL to your - page (``path``) and what ``controller`` to call. You'll learn more about :doc:`routing ` - in its own section, including how to make *variable* URLs; - -#. *Create a controller*: This is a function where *you* build the page and ultimately +#. *Create a controller and a method*: This is a function where *you* build the page and ultimately return a ``Response`` object. You'll learn more about :doc:`controllers ` - in their own section, including how to return JSON responses. + in their own section, including how to return JSON responses; + +#. *Create a route*: In ``config/routes.yaml``, the route defines the URL to your + page (``path``) and what ``controller`` to call. You'll learn more about :doc:`routing ` + in its own section, including how to make *variable* URLs. .. _annotation-routes: @@ -95,7 +95,8 @@ Annotation Routes ----------------- Instead of defining your route in YAML, Symfony also allows you to use *annotation* -routes. To do this, install the annotations package: +or *attribute* routes. Attributes are built-in in PHP starting from PHP 8. In earlier +PHP versions you can use annotations. To do this, install the annotations package: .. code-block:: terminal @@ -103,26 +104,44 @@ routes. To do this, install the annotations package: You can now add your route directly *above* the controller: -.. code-block:: diff +.. configuration-block:: - // src/Controller/LuckyController.php + .. code-block:: php-annotations - // ... - + use Symfony\Component\Routing\Annotation\Route; + // src/Controller/LuckyController.php - class LuckyController - { - + /** - + * @Route("/lucky/number") - + */ - public function number() + // ... + + use Symfony\Component\Routing\Annotation\Route; + + class LuckyController { - // this looks exactly the same + + /** + + * @Route("/lucky/number") + + */ + public function number(): Response + { + // this looks exactly the same + } + } + + .. code-block:: php-attributes + + // src/Controller/LuckyController.php + + // ... + + use Symfony\Component\Routing\Annotation\Route; + + class LuckyController + { + + #[Route('/lucky/number')] + public function number(): Response + { + // this looks exactly the same + } } - } That's it! The page - http://localhost:8000/lucky/number will work exactly -like before! Annotations are the recommended way to configure routes. +like before! Annotations/attributes are the recommended way to configure routes. .. _flex-quick-intro: @@ -163,15 +182,15 @@ To get a list of *all* of the routes in your system, use the ``debug:router`` co $ php bin/console debug:router -You should see your ``app_lucky_number`` route at the very top: +You should see your ``app_lucky_number`` route in the list: ================== ======== ======== ====== =============== - Name Method Scheme Host Path +Name Method Scheme Host Path ================== ======== ======== ====== =============== - app_lucky_number ANY ANY ANY /lucky/number +app_lucky_number ANY ANY ANY /lucky/number ================== ======== ======== ====== =============== -You will also see debugging routes below ``app_lucky_number`` -- more on +You will also see debugging routes besides ``app_lucky_number`` -- more on the debugging routes in the next section. You'll learn about many more commands as you continue! @@ -209,18 +228,18 @@ Make sure that ``LuckyController`` extends Symfony's base .. code-block:: diff - // src/Controller/LuckyController.php + // src/Controller/LuckyController.php - // ... + // ... + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; - class LuckyController + class LuckyController extends AbstractController - { - // ... - } + { + // ... + } -Now, use the handy ``render()`` function to render a template. Pass it a ``number`` +Now, use the handy ``render()`` method to render a template. Pass it a ``number`` variable so you can use it in Twig:: // src/Controller/LuckyController.php diff --git a/performance.rst b/performance.rst index 48fc4c5d942..e9d1b5558d6 100644 --- a/performance.rst +++ b/performance.rst @@ -43,7 +43,7 @@ features, such as the APCu Cache adapter. Restrict the Number of Locales Enabled in the Application ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Use the :ref:`framework.translator.enabled_locales ` +Use the :ref:`framework.enabled_locales ` option to only generate the translation files actually used in your application. .. _performance-service-container-single-file: @@ -84,7 +84,7 @@ container into a single file, which could improve performance when using // config/services.php // ... - $container->setParameter('container.dumper.inline_factories', true); + $container->parameters()->set('container.dumper.inline_factories', true); .. _performance-use-opcache: @@ -106,18 +106,22 @@ make them available to all requests until the server is restarted, improving performance significantly. During container compilation (e.g. when running the ``cache:clear`` command), -Symfony generates a file called ``preload.php`` in the ``config/`` directory -with the list of classes to preload. - -The only requirement is that you need to set both ``container.dumper.inline_factories`` -and ``container.dumper.inline_class_loader`` parameters to ``true``. Then, you -can configure PHP to use this preload file: +Symfony generates a file with the list of classes to preload in the +``var/cache/`` directory. Rather than use this file directly, use the +``config/preload.php`` file that is created when +:doc:`using Symfony Flex in your project `: .. code-block:: ini ; php.ini opcache.preload=/path/to/project/config/preload.php + ; required for opcache.preload: + opcache.preload_user=www-data + +If this file is missing, run this command to reinstall the Symfony Flex recipe: +``composer recipes:install symfony/framework-bundle --force -v``. + Use the :ref:`container.preload ` and :ref:`container.no_preload ` service tags to define which classes should or should not be preloaded by PHP. @@ -193,14 +197,14 @@ such as Symfony projects, should use at least these values: Optimize Composer Autoloader ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The class loader used while developing the application is optimized to find -new and changed classes. In production servers, PHP files should never change, +The class loader used while developing the application is optimized to find new +and changed classes. In production servers, PHP files should never change, unless a new application version is deployed. That's why you can optimize -Composer's autoloader to scan the entire application once and build a "class map", -which is a big array of the locations of all the classes and it's stored -in ``vendor/composer/autoload_classmap.php``. +Composer's autoloader to scan the entire application once and build an +optimized "class map", which is a big array of the locations of all the classes +and it's stored in ``vendor/composer/autoload_classmap.php``. -Execute this command to generate the class map (and make it part of your +Execute this command to generate the new class map (and make it part of your deployment process too): .. code-block:: terminal @@ -281,7 +285,7 @@ You can also profile your template code with the :ref:`stopwatch Twig tag getKernel()->isDebug()) { + if (!$event->getKernel()->isDebug()) { return; } diff --git a/profiler/data_collector.rst b/profiler/data_collector.rst index 276d1e88324..ef377c47974 100644 --- a/profiler/data_collector.rst +++ b/profiler/data_collector.rst @@ -31,7 +31,6 @@ request:: use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\HttpKernel\DataCollector\DataCollector; class RequestCollector extends AbstractDataCollector { @@ -96,7 +95,7 @@ template that includes some specific blocks. First, add the ``getTemplate()`` method in your data collector class to return the path of the Twig template to use. Then, add some *getters* to give the -template access to the collected information:::: +template access to the collected information:: // src/DataCollector/RequestCollector.php namespace App\DataCollector; diff --git a/quick_tour/flex_recipes.rst b/quick_tour/flex_recipes.rst index 435b4f07351..1b929667b92 100644 --- a/quick_tour/flex_recipes.rst +++ b/quick_tour/flex_recipes.rst @@ -75,28 +75,28 @@ Thanks to Flex, after one command, you can start using Twig immediately: .. code-block:: diff - render('default/index.html.twig', [ + 'name' => $name, + ]); - } - } + } + } By extending ``AbstractController``, you now have access to a number of shortcut methods and tools, like ``render()``. Create the new template: diff --git a/quick_tour/the_architecture.rst b/quick_tour/the_architecture.rst index 69883859d53..b7e9764c717 100644 --- a/quick_tour/the_architecture.rst +++ b/quick_tour/the_architecture.rst @@ -72,9 +72,6 @@ What other possible classes or interfaces could you use? Find out by running: Request stack that controls the lifecycle of requests. Symfony\Component\HttpFoundation\RequestStack (request_stack) - Interface for the session. - Symfony\Component\HttpFoundation\Session\SessionInterface (session) - RouterInterface is the interface that all Router classes must implement. Symfony\Component\Routing\RouterInterface (router.default) @@ -138,12 +135,12 @@ difference is that it's done in the constructor: .. code-block:: diff - logger = $logger; + } - public function getRandomGreeting() - { - // ... + public function getRandomGreeting() + { + // ... - + $this->logger->info('Using the greeting: '.$greeting); + + $this->logger->info('Using the greeting: '.$greeting); - return $greeting; - } - } + return $greeting; + } + } Yes! This works too: no configuration, no time wasted. Keep coding! @@ -279,7 +276,7 @@ from ``dev`` to ``prod``: .. code-block:: diff - # .env + # .env - APP_ENV=dev + APP_ENV=prod @@ -321,10 +318,10 @@ Thanks to a new recipe installed by Flex, look at the ``.env`` file again: .. code-block:: diff - ###> symfony/framework-bundle ### - APP_ENV=dev - APP_SECRET=cc86c7ca937636d5ddf1b754beb22a10 - ###< symfony/framework-bundle ### + ###> symfony/framework-bundle ### + APP_ENV=dev + APP_SECRET=cc86c7ca937636d5ddf1b754beb22a10 + ###< symfony/framework-bundle ### + ###> doctrine/doctrine-bundle ### + # ... diff --git a/quick_tour/the_big_picture.rst b/quick_tour/the_big_picture.rst index 4fae7ef5991..b6ad8eaafdd 100644 --- a/quick_tour/the_big_picture.rst +++ b/quick_tour/the_big_picture.rst @@ -105,32 +105,32 @@ But the routing system is *much* more powerful. So let's make the route more int .. code-block:: diff - # config/routes.yaml - index: + # config/routes.yaml + index: - path: / + path: /hello/{name} - controller: 'App\Controller\DefaultController::index' + controller: 'App\Controller\DefaultController::index' The URL to this page has changed: it is *now* ``/hello/*``: the ``{name}`` acts like a wildcard that matches anything. And it gets better! Update the controller too: .. code-block:: diff - `. + The RateLimiter component was introduced in Symfony 5.2. A "rate limiter" controls how frequently some event (e.g. an HTTP request or a login attempt) is allowed to happen. Rate limiting is commonly used as a @@ -16,6 +15,16 @@ Symfony uses these rate limiters in built-in features like "login throttling", which limits how many failed login attempts a user can make in a given period of time, but you can use them for your own features too. +.. caution:: + + By definition, the Symfony rate limiters require Symfony to be booted + in a PHP process. This makes them not useful to protect against `DoS attacks`_. + Such protections must consume the least resources possible. Consider + using `Apache mod_ratelimit`_, `NGINX rate limiting`_ or proxies (like + AWS or Cloudflare) to prevent your server from being overwhelmed. + +.. _rate-limiter-policies: + Rate Limiting Policies ---------------------- @@ -26,22 +35,44 @@ Fixed Window Rate Limiter ~~~~~~~~~~~~~~~~~~~~~~~~~ This is the simplest technique and it's based on setting a limit for a given -interval of time. For example: 5,000 requests per hour or 3 login attempts -every 15 minutes. +interval of time (e.g. 5,000 requests per hour or 3 login attempts every 15 +minutes). + +In the diagram below, the limit is set to "5 tokens per hour". Each window +starts at the first hit (i.e. 10:15, 11:30 and 12:30). As soon as there are +5 hits (the blue squares) in a window, all others will be rejected (red +squares). + +.. raw:: html + + Its main drawback is that resource usage is not evenly distributed in time and -it can overload the server at the window edges. In the previous example, a user -could make the 4,999 requests in the last minute of some hour and another 5,000 -requests during the first minute of the next hour, making 9,999 requests in -total in two minutes and possibly overloading the server. These periods of -excessive usage are called "bursts". +it can overload the server at the window edges. In the previous example, +there are 6 accepted requests between 11:00 and 12:00. + +This is more significant with bigger limits. For instance, with 5,000 requests +per hour, a user could make the 4,999 requests in the last minute of some +hour and another 5,000 requests during the first minute of the next hour, +making 9,999 requests in total in two minutes and possibly overloading the +server. These periods of excessive usage are called "bursts". Sliding Window Rate Limiter ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The sliding window algorithm is an alternative to the fixed window algorithm -designed to reduce bursts. To do that, the rate limit is calculated based on -the current window and the previous window. +designed to reduce bursts. This is the same example as above, but then +using a 1 hour window that slides over the timeline: + +.. raw:: html + + + +As you can see, this removes the edges of the window and would prevent the +6th request at 11:45. + +To achieve this, the rate limit is approximated based on the current window and +the previous window. For example: the limit is 5,000 requests per hour; a user made 4,000 requests the previous hour and 500 requests this hour. 15 minutes in to the current hour @@ -64,6 +95,18 @@ continuously updating budget of resource usage. It roughly works like this: * If the bucket still contains tokens, the event is allowed; otherwise, it's denied; * If the bucket is at full capacity, new tokens are discarded. +The below diagram shows a token bucket of size 4 that is filled with a rate +of 1 token per 15 minutes: + +.. raw:: html + + + +This algorithm handles more complex back-off algorithm to manage bursts. +For instance, it can allow a user to try a password 5 times and then only +allow 1 every 15 minutes (unless the user waits 75 minutes and they will be +allowed 5 tries again). + Installation ------------ @@ -80,20 +123,79 @@ Configuration The following example creates two different rate limiters for an API service, to enforce different levels of service (free or paid): -.. code-block:: yaml - - # config/packages/rate_limiter.yaml - framework: - rate_limiter: - anonymous_api: - # use 'sliding_window' if you prefer that policy - policy: 'fixed_window' - limit: 100 - interval: '60 minutes' - authenticated_api: - policy: 'token_bucket' - limit: 5000 - rate: { interval: '15 minutes', amount: 500 } +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/rate_limiter.yaml + framework: + rate_limiter: + anonymous_api: + # use 'sliding_window' if you prefer that policy + policy: 'fixed_window' + limit: 100 + interval: '60 minutes' + authenticated_api: + policy: 'token_bucket' + limit: 5000 + rate: { interval: '15 minutes', amount: 500 } + + .. code-block:: xml + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/rate_limiter.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->rateLimiter() + ->limiter('anonymous_api') + // use 'sliding_window' if you prefer that policy + ->policy('fixed_window') + ->limit(100) + ->interval('60 minutes') + ; + + $framework->rateLimiter() + ->limiter('authenticated_api') + ->policy('token_bucket') + ->limit(5000) + ->rate() + ->interval('15 minutes') + ->amount(500) + ; + }; .. note:: @@ -123,14 +225,15 @@ the number of requests to the API:: namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; use Symfony\Component\RateLimiter\RateLimiterFactory; class ApiController extends AbstractController { // if you're using service autowiring, the variable name must be: - // "rate limiter name" (in camelCase) + "limiter" suffix - public function index(RateLimiterFactory $anonymousApiLimiter) + // "rate limiter name" (in camelCase) + "Limiter" suffix + public function index(Request $request, RateLimiterFactory $anonymousApiLimiter) { // create a limiter based on a unique identifier of the client // (e.g. the client's IP address, a username/email, an API key, etc.) @@ -228,12 +331,13 @@ the :class:`Symfony\\Component\\RateLimiter\\Reservation` object returned by the namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\RateLimiter\RateLimiterFactory; class ApiController extends AbstractController { - public function index(RateLimiterFactory $anonymousApiLimiter) + public function index(Request $request, RateLimiterFactory $anonymousApiLimiter) { $limiter = $anonymousApiLimiter->create($request->getClientIp()); $limit = $limiter->consume(); @@ -249,34 +353,174 @@ the :class:`Symfony\\Component\\RateLimiter\\Reservation` object returned by the // ... - $reponse = new Response('...'); + $response = new Response('...'); $response->headers->add($headers); return $response; } } -Rate Limiter Storage and Locking --------------------------------- +Storing Rate Limiter State +-------------------------- + +All rate limiter policies require to store their state(e.g. how many hits were +already made in the current time window). By default, all limiters use the +``cache.rate_limiter`` cache pool created with the :doc:`Cache component `. + +Use the ``cache_pool`` option to override the cache used by a specific limiter +(or even :ref:`create a new cache pool ` for it): + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/rate_limiter.yaml + framework: + rate_limiter: + anonymous_api: + # ... + + # use the "cache.anonymous_rate_limiter" cache pool + cache_pool: 'cache.anonymous_rate_limiter' -Rate limiters use the default cache and locking mechanisms defined in your -Symfony application. If you prefer to change that, use the ``lock`` and -``storage`` options: + .. code-block:: xml -.. code-block:: yaml + + + - # config/packages/rate_limiter.yaml - framework: - rate_limiter: - anonymous_api_limiter: - # ... - # the value is the name of any cache pool defined in your application - cache_pool: 'app.redis_cache' - # or define a service implementing StorageInterface to use a different - # mechanism to store the limiter information - storage: 'App\RateLimiter\CustomRedisStorage' - # the value is the name of any lock defined in your application - lock: 'app.rate_limiter_lock' + + + + + + + + + + + .. code-block:: php + + // config/packages/rate_limiter.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->rateLimiter() + ->limiter('anonymous_api') + // ... + + // use the "cache.anonymous_rate_limiter" cache pool + ->cachePool('cache.anonymous_rate_limiter') + ; + }; + +.. note:: + Instead of using the Cache component, you can also implement a custom + storage. Create a PHP class that implements the + :class:`Symfony\\Component\\RateLimiter\\Storage\\StorageInterface` and + use the ``storage_service`` setting of each limiter to the service ID + of this class. + +Using Locks to Prevent Race Conditions +-------------------------------------- + +`Race conditions`_ can happen when the same rate limiter is used by multiple +simultaneous requests (e.g. three servers of a company hitting your API at the +same time). Rate limiters use :doc:`locks ` to protect their operations +against these race conditions. + +By default, Symfony uses the global lock configured by ``framework.lock``, but +you can use a specific :ref:`named lock ` via the +``lock_factory`` option (or none at all): + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/rate_limiter.yaml + framework: + rate_limiter: + anonymous_api: + # ... + + # use the "lock.rate_limiter.factory" for this limiter + lock_factory: 'lock.rate_limiter.factory' + + # or don't use any lock mechanism + lock_factory: null + + .. code-block:: xml + + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/rate_limiter.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->rateLimiter() + ->limiter('anonymous_api') + // ... + + // use the "lock.rate_limiter.factory" for this limiter + ->lockFactory('lock.rate_limiter.factory') + + // or don't use any lock mechanism + ->lockFactory(null) + ; + }; + +.. versionadded:: 5.3 + + The login throttling doesn't use any lock since Symfony 5.3 to avoid extra load. + +.. _`DoS attacks`: https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html +.. _`Apache mod_ratelimit`: https://httpd.apache.org/docs/current/mod/mod_ratelimit.html +.. _`NGINX rate limiting`: https://www.nginx.com/blog/rate-limiting-nginx/ .. _`token bucket algorithm`: https://en.wikipedia.org/wiki/Token_bucket .. _`PHP date relative formats`: https://www.php.net/datetime.formats.relative +.. _`Race conditions`: https://en.wikipedia.org/wiki/Race_condition diff --git a/reference/configuration/debug.rst b/reference/configuration/debug.rst index 86aed3b7ba6..e77ee6e7bd6 100644 --- a/reference/configuration/debug.rst +++ b/reference/configuration/debug.rst @@ -25,13 +25,6 @@ key in your application configuration. Configuration ------------- -.. rst-class:: list-config-options - -* `dump_destination`_ -* `max_items`_ -* `min_depth`_ -* `max_string_length`_ - max_items ~~~~~~~~~ @@ -67,9 +60,10 @@ dump_destination Configures the output destination of the dumps. -By default, the dumps are shown in the toolbar. Since this is not always -possible (e.g. when working on a JSON API), you can have an alternate output -destination for dumps. Typically, you would set this to ``php://stderr``: +By default, dumps are shown in the WebDebugToolbar when returning HTML. +Since this is not always possible (e.g. when working on a JSON API), +you can have an alternate output destination for dumps. +Typically, you would set this to ``php://stderr``: .. configuration-block:: diff --git a/reference/configuration/doctrine.rst b/reference/configuration/doctrine.rst index 281d9193203..d7ce406ab76 100644 --- a/reference/configuration/doctrine.rst +++ b/reference/configuration/doctrine.rst @@ -65,7 +65,7 @@ The following block shows all possible configuration keys: charset: UTF8 logging: '%kernel.debug%' platform_service: App\DBAL\MyDatabasePlatformService - server_version: '5.6' + server_version: '5.7' mapping_types: enum: string types: @@ -99,7 +99,7 @@ The following block shows all possible configuration keys: charset="UTF8" logging="%kernel.debug%" platform-service="App\DBAL\MyDatabasePlatformService" - server-version="5.6"> + server-version="5.7"> bar string @@ -121,8 +121,8 @@ The following block shows all possible configuration keys: Always wrap the server version number with quotes to parse it as a string instead of a float number. Otherwise, the floating-point representation - issues can make your version be considered a different number (e.g. ``5.6`` - will be rounded as ``5.5999999999999996447286321199499070644378662109375``). + issues can make your version be considered a different number (e.g. ``5.7`` + will be rounded as ``5.6999999999999996447286321199499070644378662109375``). If you don't define this option and you haven't created your database yet, you may get ``PDOException`` errors because Doctrine will try to @@ -155,13 +155,22 @@ which is the first one defined or the one configured via the ``default_connection`` parameter. Each connection is also accessible via the ``doctrine.dbal.[name]_connection`` -service where ``[name]`` is the name of the connection. In a controller -extending ``AbstractController``, you can access it directly using the -``getConnection()`` method and the name of the connection:: +service where ``[name]`` is the name of the connection. In a :doc:`controller ` +you can access it using the ``getConnection()`` method and the name of the connection:: - $connection = $this->getDoctrine()->getConnection('customer'); + // src/Controller/SomeController.php + use Doctrine\Persistence\ManagerRegistry; - $result = $connection->fetchAll('SELECT name FROM customer'); + class SomeController + { + public function someMethod(ManagerRegistry $doctrine) + { + $connection = $doctrine->getConnection('customer'); + $result = $connection->fetchAll('SELECT name FROM customer'); + + // ... + } + } Doctrine ORM Configuration -------------------------- @@ -265,9 +274,12 @@ you can control. The following configuration options exist for a mapping: ``type`` ........ -One of ``annotation`` (the default value), ``xml``, ``yml``, ``php`` or +One of ``annotation`` (for PHP annotations; it's the default value), +``attribute`` (for PHP attributes), ``xml``, ``yml``, ``php`` or ``staticphp``. This specifies which type of metadata type your mapping uses. +See `Doctrine Metadata Drivers`_ for more information about this option. + ``dir`` ....... @@ -329,7 +341,7 @@ directory instead: .. code-block:: xml - + loadFromExtension('doctrine', [ - 'orm' => [ - 'auto_mapping' => true, - 'mappings' => [ - 'AppBundle' => ['dir' => 'SomeResources/config/doctrine', 'type' => 'xml'], - ], - ], - ]); + use Symfony\Config\DoctrineConfig; + + return static function (DoctrineConfig $doctrine) { + $emDefault = $doctrine->orm()->entityManager('default'); + + $emDefault->autoMapping(true); + $emDefault->mapping('AppBundle') + ->type('xml') + ->dir('SomeResources/config/doctrine') + ; + }; Mapping Entities Outside of a Bundle ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -380,7 +395,7 @@ namespace in the ``src/Entity`` directory and gives them an ``App`` alias .. code-block:: xml - + loadFromExtension('doctrine', [ - 'orm' => [ - 'auto_mapping' => true, - 'mappings' => [ - 'SomeEntityNamespace' => [ - 'type' => 'annotation', - 'dir' => '%kernel.project_dir%/src/Entity', - 'is_bundle' => false, - 'prefix' => 'App\Entity', - 'alias' => 'App', - ], - ], - ], - ]); + use Symfony\Config\DoctrineConfig; + + return static function (DoctrineConfig $doctrine) { + $emDefault = $doctrine->orm()->entityManager('default'); + + $emDefault->autoMapping(true); + $emDefault->mapping('SomeEntityNamespace') + ->type('annotation') + ->dir('%kernel.project_dir%/src/Entity') + ->isBundle(false) + ->prefix('App\Entity') + ->alias('App') + ; + }; Detecting a Mapping Configuration Format ........................................ @@ -450,3 +465,4 @@ is ``true``, the DoctrineBundle will prefix the ``dir`` configuration with the path of the bundle. .. _DBAL documentation: https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/configuration.html +.. _`Doctrine Metadata Drivers`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/metadata-drivers.html diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index b8b0a7887d6..4ff34ecee12 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -27,272 +27,6 @@ configured under the ``framework`` key in your application configuration. Configuration ------------- -.. rst-class:: list-config-options list-config-options--complex - -* `annotations`_ - - * :ref:`cache ` - * `debug`_ - * `file_cache_dir`_ - -* `assets`_ - - * `base_path`_ - * `base_urls`_ - * `json_manifest_path`_ - * `packages`_ - * `version_format`_ - * `version_strategy`_ - * `version`_ - -* :ref:`cache ` - - * :ref:`app ` - * `default_doctrine_provider`_ - * `default_memcached_provider`_ - * `default_pdo_provider`_ - * `default_psr6_provider`_ - * `default_redis_provider`_ - * `directory`_ - * `pools`_ - - * :ref:`name ` - - * `adapter`_ - * `clearer`_ - * `default_lifetime`_ - * `provider`_ - * `public`_ - * `tags`_ - - * `prefix_seed`_ - * `system`_ - -* `csrf_protection`_ - - * :ref:`enabled ` - -* `default_locale`_ -* `disallow_search_engine_index`_ -* `error_controller`_ -* `esi`_ - - * :ref:`enabled ` - -* :ref:`form ` - - * :ref:`enabled ` - -* `fragments`_ - - * :ref:`enabled ` - * `hinclude_default_template`_ - * :ref:`path ` - -* `http_client`_ - - * :ref:`default_options ` - - * `bindto`_ - * `buffer`_ - * `cafile`_ - * `capath`_ - * `ciphers`_ - * `headers`_ - * `http_version`_ - * `local_cert`_ - * `local_pk`_ - * `max_redirects`_ - * `no_proxy`_ - * `passphrase`_ - * `peer_fingerprint`_ - * `proxy`_ - * `resolve`_ - * `timeout`_ - * `max_duration`_ - * `verify_host`_ - * `verify_peer`_ - - * `max_host_connections`_ - * :ref:`scoped_clients ` - - * `scope`_ - * `auth_basic`_ - * `auth_bearer`_ - * `auth_ntlm`_ - * `base_uri`_ - * `bindto`_ - * `buffer`_ - * `cafile`_ - * `capath`_ - * `ciphers`_ - * `headers`_ - * `http_version`_ - * `local_cert`_ - * `local_pk`_ - * `max_redirects`_ - * `no_proxy`_ - * `passphrase`_ - * `peer_fingerprint`_ - * `proxy`_ - * `query`_ - * `resolve`_ - - * :ref:`retry_failed ` - - * `retry_strategy`_ - * :ref:`enabled ` - * `delay`_ - * `http_codes`_ - * `max_delay`_ - * `max_retries`_ - * `multiplier`_ - * `jitter`_ - - * `timeout`_ - * `max_duration`_ - * `verify_host`_ - * `verify_peer`_ - - * :ref:`retry_failed ` - - * `retry_strategy`_ - * :ref:`enabled ` - * `delay`_ - * `http_codes`_ - * `max_delay`_ - * `max_retries`_ - * `multiplier`_ - * `jitter`_ - -* `http_method_override`_ -* `ide`_ -* :ref:`lock ` - - * :ref:`enabled ` - * :ref:`resources ` - - * :ref:`name ` - -* `php_errors`_ - - * `log`_ - * `throw`_ - -* `profiler`_ - - * `collect`_ - * `dsn`_ - * :ref:`enabled ` - * `only_exceptions`_ - * `only_master_requests`_ - -* `property_access`_ - - * `magic_call`_ - * `magic_get`_ - * `magic_set`_ - * `throw_exception_on_invalid_index`_ - * `throw_exception_on_invalid_property_path`_ - -* `property_info`_ - - * :ref:`enabled ` - -* `request`_: - - * `formats`_ - -* `router`_ - - * `http_port`_ - * `https_port`_ - * `resource`_ - * `strict_requirements`_ - * :ref:`type ` - * `utf8`_ - -* `secret`_ -* `serializer`_ - - * :ref:`circular_reference_handler ` - * :ref:`enable_annotations ` - * :ref:`enabled ` - * :ref:`mapping ` - - * :ref:`paths ` - - * :ref:`name_converter ` - -* `session`_ - - * `cache_limiter`_ - * `cookie_domain`_ - * `cookie_httponly`_ - * `cookie_lifetime`_ - * `cookie_path`_ - * `cookie_samesite`_ - * `cookie_secure`_ - * :ref:`enabled ` - * `gc_divisor`_ - * `gc_maxlifetime`_ - * `gc_probability`_ - * `handler_id`_ - * `metadata_update_threshold`_ - * `name`_ - * `save_path`_ - * `sid_length`_ - * `sid_bits_per_character`_ - * `storage_id`_ - * `use_cookies`_ - -* `test`_ -* `translator`_ - - * `cache_dir`_ - * :ref:`default_path ` - * :ref:`enabled ` - * :ref:`enabled_locales ` - * `fallbacks`_ - * `formatter`_ - * `logging`_ - * :ref:`paths ` - -* `trusted_hosts`_ -* `trusted_proxies`_ -* `validation`_ - - * :ref:`cache ` - * `email_validation_mode`_ - * :ref:`enable_annotations ` - * :ref:`enabled ` - * :ref:`mapping ` - - * :ref:`paths ` - - * :ref:`not_compromised_password ` - - * :ref:`enabled ` - * `endpoint`_ - - * `static_method`_ - * `translation_domain`_ - -* `workflows`_ - - * :ref:`enabled ` - * :ref:`name ` - - * `audit_trail`_ - * `initial_marking`_ - * `marking_store`_ - * `metadata`_ - * `places`_ - * `supports`_ - * `support_strategy`_ - * `transitions`_ - * :ref:`type ` - secret ~~~~~~ @@ -306,6 +40,8 @@ recommended length is around 32 characters. In practice, Symfony uses this value for encrypting the cookies used in the :doc:`remember me functionality ` and for creating signed URIs when using :ref:`ESI (Edge Side Includes) `. +That's why you should treat this value as if it were a sensitive credential and +**never make it public**. This option becomes the service container parameter named ``kernel.secret``, which you can use whenever the application needs an immutable random string @@ -353,12 +89,32 @@ named ``kernel.http_method_override``. $request = Request::createFromGlobals(); // ... +.. _reference-framework-trusted-headers: + +trusted_headers +~~~~~~~~~~~~~~~ + +.. versionadded:: 5.2 + + The ``trusted_headers`` option was introduced in Symfony 5.2. + +The ``trusted_headers`` option is needed to configure which client information +should be trusted (e.g. their host) when running Symfony behind a load balancer +or a reverse proxy. See :doc:`/deployment/proxies`. + .. _reference-framework-trusted-proxies: trusted_proxies ~~~~~~~~~~~~~~~ -The ``trusted_proxies`` option was removed in Symfony 3.3. See :doc:`/deployment/proxies`. +.. versionadded:: 5.2 + + The ``trusted_proxies`` option was reintroduced in Symfony 5.2 (it had been + removed in Symfony 3.3). + +The ``trusted_proxies`` option is needed to get precise information about the +client (e.g. their IP address) when running Symfony behind a load balancer or a +reverse proxy. See :doc:`/deployment/proxies`. ide ~~~ @@ -406,15 +162,67 @@ doubling them to prevent Symfony from interpreting them as container parameters) .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'ide' => 'myide://open?url=file://%%f&line=%%l', - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->ide('myide://open?url=file://%%f&line=%%l'); + }; Since every developer uses a different IDE, the recommended way to enable this -feature is to configure it on a system level. This can be done by setting the -``xdebug.file_link_format`` option in your ``php.ini`` configuration file. The -format to use is the same as for the ``framework.ide`` option, but without the -need to escape the percent signs (``%``) by doubling them. +feature is to configure it on a system level. First, you can set its value to +some environment variable that stores the name of the IDE/editor: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/framework.yaml + framework: + # the env var stores the IDE/editor name (e.g. 'phpstorm', 'vscode', etc.) + ide: '%env(resolve:CODE_EDITOR)%' + + .. code-block:: xml + + + + + + + + + + .. code-block:: php + + // config/packages/framework.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + // the env var stores the IDE/editor name (e.g. 'phpstorm', 'vscode', etc.) + $framework->ide('%env(resolve:CODE_EDITOR)%'); + }; + +.. versionadded:: 5.3 + + The option to use env vars in the ``framework.ide`` option was introduced + in Symfony 5.3. + +Another alternative is to set the ``xdebug.file_link_format`` option in your +``php.ini`` configuration file. The format to use is the same as for the +``framework.ide`` option, but without the need to escape the percent signs +(``%``) by doubling them: + +.. code-block:: ini + + // example for PhpStorm + xdebug.file_link_format="phpstorm://open?file=%f&line=%l" + + // example for Sublime + xdebug.file_link_format="subl://open?url=file://%f&line=%l" .. note:: @@ -431,7 +239,9 @@ need to escape the percent signs (``%``) by doubling them. When running your app in a container or in a virtual machine, you can tell Symfony to map files from the guest to the host by changing their prefix. This map should be specified at the end of the URL template, using ``&`` and - ``>`` as guest-to-host separators:: + ``>`` as guest-to-host separators: + + .. code-block:: text // /path/to/guest/.../file will be opened // as /path/to/host/.../file on the host @@ -474,6 +284,88 @@ method. You can read more information about the default locale in :ref:`translation-default-locale`. +.. _reference-translator-enabled-locales: +.. _reference-enabled-locales: + +enabled_locales +............... + +**type**: ``array`` **default**: ``[]`` (empty array = enable all locales) + +.. versionadded:: 5.1 + + The ``enabled_locales`` option was introduced in Symfony 5.1. + +Symfony applications generate by default the translation files for validation +and security messages in all locales. If your application only uses some +locales, use this option to restrict the files generated by Symfony and improve +performance a bit: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/translation.yaml + framework: + enabled_locales: ['en', 'es'] + + .. code-block:: xml + + + + + + + en + es + + + + .. code-block:: php + + // config/packages/translation.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->enabledLocales(['en', 'es']); + }; + +If some user makes requests with a locale not included in this option, the +application won't display any error because Symfony will display contents using +the fallback locale. + +set_content_language_from_locale +................................ + +**type**: ``boolean`` **default**: ``false`` + +.. versionadded:: 5.4 + + The ``set_content_language_from_locale`` option was introduced in Symfony 5.4. + +If this option is set to ``true``, the response will have a ``Content-Language`` +HTTP header set with the ``Request`` locale. + +set_locale_from_accept_language +............................... + +**type**: ``boolean`` **default**: ``false`` + +.. versionadded:: 5.4 + + The ``set_locale_from_accept_language`` option was introduced in Symfony 5.4. + +If this option is set to ``true``, the ``Request`` locale will automatically be +set to the value of the ``Accept-Language`` HTTP header. + +When the ``_locale`` request attribute is passed, the ``Accept-Language`` header +is ignored. + disallow_search_engine_index ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -504,7 +396,7 @@ instance), the host might have been manipulated by an attacker. The Symfony :method:`Request::getHost() ` method might be vulnerable to some of these attacks because it depends on the configuration of your web server. One simple solution to avoid these -attacks is to whitelist the hosts that your Symfony application can respond +attacks is to configure a list of hosts that your Symfony application can respond to. That's the purpose of this ``trusted_hosts`` option. If the incoming request's hostname doesn't match one of the regular expressions in this list, the application won't respond and the user will receive a 400 response. @@ -538,9 +430,11 @@ the application won't respond and the user will receive a 400 response. .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'trusted_hosts' => ['^example\.com$', '^example\.org$'], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->trustedHosts(['^example\.com$', '^example\.org$']); + }; Hosts can also be configured to respond to any subdomain, via ``^(.+\.)?example\.com$`` for instance. @@ -666,9 +560,11 @@ You can also set ``esi`` to ``true`` to enable it: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'esi' => true, - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->esi()->enabled(true); + }; fragments ~~~~~~~~~ @@ -726,16 +622,62 @@ as a service named ``http_client`` or using the autowiring alias This service can be configured using ``framework.http_client.default_options``: -.. code-block:: yaml +.. configuration-block:: - # config/packages/framework.yaml - framework: - # ... - http_client: - max_host_connections: 10 - default_options: - headers: { 'X-Powered-By': 'ACME App' } - max_redirects: 7 + .. code-block:: yaml + + # config/packages/framework.yaml + framework: + # ... + http_client: + max_host_connections: 10 + default_options: + headers: { 'X-Powered-By': 'ACME App' } + max_redirects: 7 + + .. code-block:: xml + + + + + + + + + ACME App + + + + + + .. code-block:: php + + // config/packages/framework.php + $container->loadFromExtension('framework', [ + 'http_client' => [ + 'max_host_connections' => 10, + 'default_options' => [ + 'headers' => [ + 'X-Powered-By' => 'ACME App', + ], + 'max_redirects' => 7, + ], + ], + ]); + + .. code-block:: php-standalone + + $client = HttpClient::create([ + 'headers' => [ + 'X-Powered-By' => 'ACME App', + ], + 'max_redirects' => 7, + ], 10); .. _reference-http-client-scoped-clients: @@ -744,16 +686,57 @@ service name defined as a key under ``scoped_clients``. Scoped clients inherit the default options defined for the ``http_client`` service. You can override these options and can define a few others: -.. code-block:: yaml +.. configuration-block:: - # config/packages/framework.yaml - framework: - # ... - http_client: - scoped_clients: - my_api.client: - auth_bearer: secret_bearer_token - # ... + .. code-block:: yaml + + # config/packages/framework.yaml + framework: + # ... + http_client: + scoped_clients: + my_api.client: + auth_bearer: secret_bearer_token + # ... + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/framework.php + $container->loadFromExtension('framework', [ + 'http_client' => [ + 'scoped_clients' => [ + 'my_api.client' => [ + 'auth_bearer' => 'secret_bearer_token', + // ... + ], + ], + ], + ]); + + .. code-block:: php-standalone + + $client = HttpClient::createForBaseUri('https://...', [ + 'auth_bearer' => 'secret_bearer_token', + // ... + ]); Options defined for scoped clients apply only to URLs that match either their `base_uri`_ or the `scope`_ option when it is defined. Non-matching URLs always @@ -777,17 +760,18 @@ will automatically retry failed HTTP requests. # ... http_client: # ... - retry_failed: - # retry_strategy: app.custom_strategy - http_codes: - 0: ['GET', 'HEAD'] # retry network errors if request method is GET or HEAD - 429: true # retry all responses with 429 status code - 500: ['GET', 'HEAD'] - max_retries: 2 - delay: 1000 - multiplier: 3 - max_delay: 5000 - jitter: 0.3 + default_options: + retry_failed: + # retry_strategy: app.custom_strategy + http_codes: + 0: ['GET', 'HEAD'] # retry network errors if request method is GET or HEAD + 429: true # retry all responses with 429 status code + 500: ['GET', 'HEAD'] + max_retries: 2 + delay: 1000 + multiplier: 3 + max_delay: 5000 + jitter: 0.3 scoped_clients: my_api.client: @@ -826,6 +810,8 @@ in the `Microsoft NTLM authentication protocol`_. The value of this option must follow the format ``username:password``. This authentication mechanism requires using the cURL-based transport. +.. _reference-http-client-base-uri: + base_uri ........ @@ -860,7 +846,7 @@ outgoing network interface. buffer ...... -**type**: ``bool`` | ``Closure`` +**type**: ``boolean`` | ``Closure`` Buffering the response means that you can access its content multiple times without performing the request again. Buffering is enabled by default when the @@ -915,6 +901,8 @@ enabled Whether to enable the support for retry failed HTTP request or not. This setting is automatically set to true when one of the child settings is configured. +.. _http-headers: + headers ....... @@ -1132,7 +1120,7 @@ config option. verify_host ........... -**type**: ``boolean`` +**type**: ``boolean`` **default**: ``true`` If ``true``, the certificate sent by other servers is verified to ensure that their common name matches the host included in the URL. This is usually @@ -1141,7 +1129,7 @@ combined with ``verify_peer`` to also verify the certificate authenticity. verify_peer ........... -**type**: ``boolean`` +**type**: ``boolean`` **default**: ``true`` If ``true``, the certificate sent by other servers when negotiating a TLS or SSL connection is verified for authenticity. Authenticating the certificate is not @@ -1188,14 +1176,23 @@ only_exceptions When this is set to ``true``, the profiler will only be enabled when an exception is thrown during the handling of the request. -only_master_requests -.................... +.. _only_master_requests: + +only_main_requests +.................. **type**: ``boolean`` **default**: ``false`` -When this is set to ``true``, the profiler will only be enabled on the master +.. versionadded:: 5.3 + + The ``only_main_requests`` option was introduced in Symfony 5.3. In previous + versions it was called ``only_master_requests``. + +When this is set to ``true``, the profiler will only be enabled on the main requests (and not on the subrequests). +.. _profiler-dsn: + dsn ... @@ -1203,6 +1200,35 @@ dsn The DSN where to store the profiling information. +rate_limiter +~~~~~~~~~~~~ + +.. _reference-rate-limiter-name: + +name +.... + +**type**: ``prototype`` + +Name of the rate limiter you want to create. + +lock_factory +"""""""""""" + +**type**: ``string`` **default:** ``lock.factory`` + +The service that is used to create a lock. The service has to be an instance of +the :class:`Symfony\\Component\\Lock\\LockFactory` class. + +policy +"""""" + +**type**: ``string`` **required** + +The name of the rate limiting algorithm to use. Example names are ``fixed_window``, +``sliding_window`` and ``no_limit``. See :ref:`Rate Limiter Policies `) +for more information. + request ~~~~~~~ @@ -1258,13 +1284,12 @@ To configure a ``jsonp`` format: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'request' => [ - 'formats' => [ - 'jsonp' => 'application/javascript', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->request() + ->format('jsonp', 'application/javascript'); + }; router ~~~~~~ @@ -1288,6 +1313,18 @@ The type of the resource to hint the loaders about the format. This isn't needed when you use the default routers with the expected file extensions (``.xml``, ``.yaml``, ``.php``). +default_uri +........... + +**type**: ``string`` + +.. versionadded:: 5.1 + + The ``default_uri`` option was introduced in Symfony 5.1. + +The default URI used to generate URLs in a non-HTTP context (see +:ref:`Generating URLs in Commands `). + http_port ......... @@ -1316,7 +1353,7 @@ The value can be one of: ``true`` Throw an exception when the requirements are not met; ``false`` - Disable exceptions when the requirements are not met and return ``null`` + Disable exceptions when the requirements are not met and return ``''`` instead; ``null`` Disable checking the requirements (thus, match the route even when the @@ -1350,25 +1387,37 @@ errors. session ~~~~~~~ -storage_id -.......... +.. _storage_id: + +storage_factory_id +.................. + +**type**: ``string`` **default**: ``'session.storage.factory.native'`` + +The service ID used for creating the ``SessionStorageInterface`` that stores +the session. This service is available in the Symfony application via the +``session.storage.factory`` service alias. The class has to implement +:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorageFactoryInterface`. +To see a list of all available storages, run: + +.. code-block:: terminal + + $ php bin/console debug:container session.storage.factory. -**type**: ``string`` **default**: ``'session.storage.native'`` +.. versionadded:: 5.3 -The service id used for session storage. The ``session.storage`` service -alias will be set to this service id. This class has to implement -:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorageInterface`. + The ``storage_factory_id`` option was introduced in Symfony 5.3. .. _config-framework-session-handler-id: handler_id .......... -**type**: ``string`` **default**: ``null`` +**type**: ``string`` **default**: ``'session.handler.native_file'`` -The service id used for session storage. The default ``null`` value means to use -the native PHP session mechanism. Set it to ``'session.handler.native_file'`` to -let Symfony manage the sessions itself using files to store the session metadata. +The service id used for session storage. The default value ``'session.handler.native_file'`` +will let Symfony manage the sessions itself using files to store the session metadata. +Set it to ``null`` to use the native PHP session mechanism. You can also :doc:`store sessions in a database `. .. _name: @@ -1472,7 +1521,7 @@ The possible values for this option are: * ``null``, use it to disable this protection. Same behavior as in older Symfony versions. -* ``'none'`` (or the ``Cookie::SAMESITE_NONE`` constant), use it to allow +* ``'none'`` (or the ``Symfony\Component\HttpFoundation\Cookie::SAMESITE_NONE`` constant), use it to allow sending of cookies when the HTTP request originated from a different domain (previously this was the default behavior of null, but in newer browsers ``'lax'`` would be applied when the header has not been set) @@ -1491,10 +1540,10 @@ The possible values for this option are: cookie_secure ............. -**type**: ``boolean`` or ``null`` **default**: ``null`` +**type**: ``boolean`` or ``'auto'`` **default**: ``'auto'`` This determines whether cookies should only be sent over secure connections. In -addition to ``true`` and ``false``, there's a special ``null`` value that +addition to ``true`` and ``false``, there's a special ``'auto'`` value that means ``true`` for HTTPS requests and ``false`` for HTTP requests. cookie_httponly @@ -1595,11 +1644,12 @@ setting the value to ``null``: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'session' => [ - 'save_path' => null, - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->session() + ->savePath(null); + }; .. _reference-session-metadata-update-threshold: @@ -1649,11 +1699,12 @@ Whether to enable the session support in the framework. .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'session' => [ - 'enabled' => true, - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->session() + ->enabled(true); + }; use_cookies ........... @@ -1705,12 +1756,13 @@ This option allows you to define a base path to be used for assets: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'assets' => [ - 'base_path' => '/images', - ], - ]); + $framework->assets() + ->basePath('/images'); + }; .. _reference-templating-base-urls: .. _reference-assets-base-urls: @@ -1754,12 +1806,13 @@ collection each time it generates an asset's path: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'assets' => [ - 'base_urls' => ['http://cdn.example.com/'], - ], - ]); + $framework->assets() + ->baseUrls(['http://cdn.example.com/']); + }; .. _reference-framework-assets-packages: @@ -1803,16 +1856,14 @@ You can group assets into packages, to specify different base URLs for them: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'assets' => [ - 'packages' => [ - 'avatars' => [ - 'base_urls' => 'http://static_cdn.example.com/avatars', - ], - ], - ], - ]); + $framework->assets() + ->package('avatars') + ->baseUrls(['http://static_cdn.example.com/avatars']); + }; Now you can use the ``avatars`` package in your templates: @@ -1880,12 +1931,13 @@ Now, activate the ``version`` option: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'assets' => [ - 'version' => 'v2', - ], - ]); + $framework->assets() + ->version('v2'); + }; Now, the same asset will be rendered as ``/images/logo.png?v2`` If you use this feature, you **must** manually increment the ``version`` value @@ -2007,25 +2059,25 @@ individually for each asset package: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'assets' => [ - 'version_strategy' => 'app.asset.my_versioning_strategy', - 'packages' => [ - 'foo_package' => [ - // this package removes any versioning (its assets won't be versioned) - 'version' => null, - ], - 'bar_package' => [ - // this package uses its own strategy (the default strategy is ignored) - 'version_strategy' => 'app.asset.another_version_strategy', - ], - 'baz_package' => [ - // this package inherits the default strategy - 'base_path' => '/images', - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + // ... + $framework->assets() + ->versionStrategy('app.asset.my_versioning_strategy'); + + $framework->assets()->package('foo_package') + // this package removes any versioning (its assets won't be versioned) + ->version(null); + + $framework->assets()->package('bar_package') + // this package uses its own strategy (the default strategy is ignored) + ->versionStrategy('app.asset.another_version_strategy'); + + $framework->assets()->package('baz_package') + // this package inherits the default strategy + ->basePath('/images'); + }; .. note:: @@ -2104,24 +2156,24 @@ package: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'assets' => [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + // ... + $framework->assets() // this manifest is applied to every asset (including packages) - 'json_manifest_path' => '%kernel.project_dir%/public/build/manifest.json', - // you can use absolute URLs too and Symfony will download them automatically - // 'json_manifest_path' => 'https://cdn.example.com/manifest.json', - 'packages' => [ - 'foo_package' => [ - // this package uses its own manifest (the default file is ignored) - 'json_manifest_path' => '%kernel.project_dir%/public/build/a_different_manifest.json', - ], - 'bar_package' => [ - // this package uses the global manifest (the default file is used) - 'base_path' => '/images', - ], - ], - ], - ]); + ->jsonManifestPath('%kernel.project_dir%/public/build/manifest.json'); + + // you can use absolute URLs too and Symfony will download them automatically + // 'json_manifest_path' => 'https://cdn.example.com/manifest.json', + $framework->assets()->package('foo_package') + // this package uses its own manifest (the default file is ignored) + ->jsonManifestPath('%kernel.project_dir%/public/build/a_different_manifest.json'); + + $framework->assets()->package('bar_package') + // this package uses the global manifest (the default file is used) + ->basePath('/images'); + }; .. versionadded:: 5.1 @@ -2174,51 +2226,10 @@ enabled_locales The ``enabled_locales`` option was introduced in Symfony 5.1. -Symfony applications generate by default the translation files for validation -and security messages in all locales. If your application only uses some -locales, use this option to restrict the files generated by Symfony and improve -performance a bit: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/translation.yaml - framework: - translator: - enabled_locales: ['en', 'es'] - - .. code-block:: xml +.. deprecated:: 5.4 - - - - - - - en - es - - - - - .. code-block:: php - - // config/packages/translation.php - $container->loadFromExtension('framework', [ - 'translator' => [ - 'enabled_locales' => ['en', 'es'], - ], - ]); - -If some user makes requests with a locale not included in this option, the -application won't display any error because Symfony will display contents using -the fallback locale. + Using ``framework.translator.enabled_locales`` has been deprecated in favor of + :ref:`framework.enabled_locales ` since Symfony 5.4. .. _fallback: @@ -2242,9 +2253,9 @@ logging **default**: ``true`` when the debug mode is enabled, ``false`` otherwise. When ``true``, a log entry is made whenever the translator cannot find a translation -for a given key. The logs are made to the ``translation`` channel and at the -``debug`` for level for keys where there is a translation in the fallback -locale and the ``warning`` level if there is no translation to use at all. +for a given key. The logs are made to the ``translation`` channel at the +``debug`` level for keys where there is a translation in the fallback +locale, and the ``warning`` level if there is no translation to use at all. .. _reference-framework-translator-formatter: @@ -2266,7 +2277,7 @@ paths This option allows to define an array of paths where the component will look for translation files. The later a path is added, the more priority it has (translations from later paths overwrite earlier ones). Translations from the -`default_path ` have more priority than +:ref:`default_path ` have more priority than translations from all these paths. .. _reference-translator-default_path: @@ -2279,6 +2290,20 @@ default_path This option allows to define the path where the application translations files are stored. +.. _reference-translator-providers: + +providers +......... + +**type**: ``array`` **default**: ``[]`` + +.. versionadded:: 5.3 + + The ``providers`` option was introduced in Symfony 5.3. + +This option enables and configures :ref:`translation providers ` +to push and pull your translations to/from third party translation services. + property_access ~~~~~~~~~~~~~~~ @@ -2343,6 +2368,8 @@ enabled **type**: ``boolean`` **default**: ``true`` or ``false`` depending on your installation +.. _reference-validation: + validation ~~~~~~~~~~ @@ -2430,22 +2457,15 @@ metadata of the class. You can define an array of strings with the names of several methods. In that case, all of them will be called in that order to load the metadata. +.. _reference-validation-email_validation_mode: + email_validation_mode ..................... **type**: ``string`` **default**: ``loose`` -It controls the way email addresses are validated by the -:doc:`/reference/constraints/Email` validator. The possible values are: - -* ``loose``, it uses a simple regular expression to validate the address (it - checks that at least one ``@`` character is present, etc.). This validation is - too simple and it's recommended to use the ``html5`` validation instead; -* ``html5``, it validates email addresses using the same regular expression - defined in the HTML5 standard, making the backend validation consistent with - the one provided by browsers; -* ``strict``, it uses the `egulias/email-validator`_ library (which you must - install separately) to validate the addresses according to the `RFC 5322`_. +Sets the default value for the +:ref:`"mode" option of the Email validator `. .. _reference-validation-mapping: @@ -2496,15 +2516,13 @@ the component will look for additional validation files: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'validation' => [ - 'mapping' => [ - 'paths' => [ - '%kernel.project_dir%/config/validation/', - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->validation() + ->mapping() + ->paths(['%kernel.project_dir%/config/validation/']); + }; annotations ~~~~~~~~~~~ @@ -2514,10 +2532,12 @@ annotations cache ..... -**type**: ``string`` **default**: ``'file'`` +**type**: ``string`` **default**: ``'php_array'`` This option can be one of the following values: +php_array + Use a PHP array to cache annotations in memory file Use the filesystem to cache annotations none @@ -2525,6 +2545,10 @@ none a service id A service id referencing a `Doctrine Cache`_ implementation +.. deprecated:: 5.3 + + Using a service ID as the value of ``cache`` is deprecated since Symfony 5.3. + file_cache_dir .............. @@ -2544,6 +2568,31 @@ annotation changes). For performance reasons, it is recommended to disable debug mode in production, which will happen automatically if you use the default value. + +secrets +~~~~~~~ + +decryption_env_var +.................. + +**type**: ``string`` **default**: ``base64:default::SYMFONY_DECRYPTION_SECRET`` + +The environment variable that contains the decryption key. + +local_dotenv_file +................. + +**type**: ``string`` **default**: ``%kernel.project_dir%/.env.%kernel.environment%.local`` + +Path to an dotenv file that holds secrets. This is primarily used for testing. + +vault_directory +............... + +**type**: ``string`` **default**: ``%kernel.project_dir%/config/secrets/%kernel.environment%`` + +The directory where the vault of secrets is stored. + .. _configuration-framework-serializer: serializer @@ -2631,6 +2680,69 @@ Use the application logger instead of the PHP logger for logging PHP errors. When an integer value is used, it also sets the log level. Those integer values must be the same used in the `error_reporting PHP option`_. +This option also accepts a map of PHP errors to log levels: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/framework.yaml + framework: + php_errors: + log: + '!php/const \E_DEPRECATED': !php/const Psr\Log\LogLevel::ERROR + '!php/const \E_USER_DEPRECATED': !php/const Psr\Log\LogLevel::ERROR + '!php/const \E_NOTICE': !php/const Psr\Log\LogLevel::ERROR + '!php/const \E_USER_NOTICE': !php/const Psr\Log\LogLevel::ERROR + '!php/const \E_STRICT': !php/const Psr\Log\LogLevel::ERROR + '!php/const \E_WARNING': !php/const Psr\Log\LogLevel::ERROR + '!php/const \E_USER_WARNING': !php/const Psr\Log\LogLevel::ERROR + '!php/const \E_COMPILE_WARNING': !php/const Psr\Log\LogLevel::ERROR + '!php/const \E_CORE_WARNING': !php/const Psr\Log\LogLevel::ERROR + '!php/const \E_USER_ERROR': !php/const Psr\Log\LogLevel::CRITICAL + '!php/const \E_RECOVERABLE_ERROR': !php/const Psr\Log\LogLevel::CRITICAL + '!php/const \E_COMPILE_ERROR': !php/const Psr\Log\LogLevel::CRITICAL + '!php/const \E_PARSE': !php/const Psr\Log\LogLevel::CRITICAL + '!php/const \E_ERROR': !php/const Psr\Log\LogLevel::CRITICAL + '!php/const \E_CORE_ERROR': !php/const Psr\Log\LogLevel::CRITICAL + + .. code-block:: xml + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/framework.php + use Psr\Log\LogLevel; + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->phpErrors()->log(\E_DEPRECATED, LogLevel::ERROR); + $framework->phpErrors()->log(\E_USER_DEPRECATED, LogLevel::ERROR); + // ... + }; + +.. versionadded:: 5.3 + + The option to map PHP errors to log levels was introduced in Symfony 5.3. + throw ..... @@ -2767,7 +2879,7 @@ To configure a Redis cache pool with a default lifetime of 1 hour, do the follow @@ -2777,16 +2889,14 @@ To configure a Redis cache pool with a default lifetime of 1 hour, do the follow .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'cache' => [ - 'pools' => [ - 'cache.mycache' => [ - 'adapter' => 'cache.adapter.redis', - 'default_lifetime' => 3600, - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->cache() + ->pool('cache.mycache') + ->adapters(['cache.adapter.redis']) + ->defaultLifetime(3600); + }; .. _reference-cache-pools-name: @@ -2868,9 +2978,9 @@ The cache clearer used to clear your PSR-6 cache. prefix_seed ........... -**type**: ``string`` **default**: ``null`` +**type**: ``string`` **default**: ``_%kernel.project_dir%.%kernel.container_class%`` -If defined, this value is used as part of the "namespace" generated for the +This value is used as part of the "namespace" generated for the cache item keys. A common practice is to use the unique name of the application (e.g. ``symfony.com``) because that prevents naming collisions when deploying multiple applications into the same path (on different servers) that share the @@ -2944,9 +3054,12 @@ A list of lock stores to be created by the framework extension. .. code-block:: php // config/packages/lock.php - $container->loadFromExtension('framework', [ - 'lock' => '%env(LOCK_DSN)%', - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->lock() + ->resource('default', ['%env(LOCK_DSN)%']); + }; .. seealso:: @@ -2961,17 +3074,135 @@ name Name of the lock you want to create. -.. tip:: +mailer +~~~~~~ + +.. _mailer-dsn: + +dsn +... + +**type**: ``string`` **default**: ``null`` + +The DSN used by the mailer. When several DSN may be used, use +``transports`` option (see below) instead. + +transports +.......... + +**type**: ``array`` + +A :ref:`list of DSN ` that can be used by the +mailer. A transport name is the key and the dsn is the value. + +message_bus +........... + +.. versionadded:: 5.1 + + The ``message_bus`` option was introduced in Symfony 5.1. + +**type**: ``string`` **default**: ``null`` or default bus if Messenger component is installed + +Service identifier of the message bus to use when using the +:doc:`Messenger component ` (e.g. ``messenger.default_bus``). + +envelope +........ + +sender +"""""" - If you want to use the `RetryTillSaveStore` for :ref:`non-blocking locks `, - you can do it by :doc:`decorating the store ` service: +**type**: ``string`` + +The "envelope sender" which is used as the value of ``MAIL FROM`` during the +`SMTP session`_. This value overrides any other sender set in the code. + +recipients +"""""""""" + +**type**: ``array`` + +The "envelope recipient" which is used as the value of ``RCPT TO`` during the +the `SMTP session`_. This value overrides any other recipient set in the code. + +.. configuration-block:: .. code-block:: yaml - lock.invoice.retry_till_save.store: - class: Symfony\Component\Lock\Store\RetryTillSaveStore - decorates: lock.invoice.store - arguments: ['@.inner', 100, 50] + # config/packages/mailer.yaml + framework: + mailer: + dsn: 'smtp://localhost:25' + envelope: + recipients: ['admin@symfony.com', 'lead@symfony.com'] + + .. code-block:: xml + + + + + + + + admin@symfony.com + lead@symfony.com + + + + + + .. code-block:: php + + // config/packages/mailer.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + return static function (ContainerConfigurator $containerConfigurator): void { + $containerConfigurator->extension('framework', [ + 'mailer' => [ + 'dsn' => 'smtp://localhost:25', + 'envelope' => [ + 'recipients' => [ + 'admin@symfony.com', + 'lead@symfony.com', + ], + ], + ], + ]); + }; + +.. _mailer-headers: + +headers +....... + +.. versionadded:: 5.2 + + The ``headers`` mailer option was introduced in Symfony 5.2. + +**type**: ``array`` + +Headers to add to emails. The key (``name`` attribute in xml format) is the +header name and value the header value. + +.. seealso:: + + For more information, see :ref:`Configuring Emails Globally ` + +web_link +~~~~~~~~ + +enabled +....... + +**type**: ``boolean`` **default**: ``true`` or ``false`` depending on your installation + +Adds a `Link HTTP header`_ to the response. workflows ~~~~~~~~~ @@ -3013,11 +3244,14 @@ A list of workflows to be created by the framework extension: .. code-block:: php // config/packages/workflow.php - $container->loadFromExtension('framework', [ - 'workflows' => [ - 'my_workflow' => // ... - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->workflows() + ->workflows('my_workflow') + // ... + ; + }; .. seealso:: @@ -3045,7 +3279,7 @@ Name of the workflow you want to create. audit_trail """"""""""" -**type**: ``bool`` +**type**: ``boolean`` If set to ``true``, the :class:`Symfony\\Component\\Workflow\\EventListener\\AuditTrailListener` will be enabled. @@ -3127,8 +3361,6 @@ to know their differences. .. _`HTTP Host header attacks`: https://www.skeletonscribe.net/2013/05/practical-http-host-header-attacks.html .. _`Security Advisory Blog post`: https://symfony.com/blog/security-releases-symfony-2-0-24-2-1-12-2-2-5-and-2-3-3-released#cve-2013-4752-request-gethost-poisoning .. _`Doctrine Cache`: https://www.doctrine-project.org/projects/doctrine-cache/en/current/index.html -.. _`egulias/email-validator`: https://github.com/egulias/EmailValidator -.. _`RFC 5322`: https://tools.ietf.org/html/rfc5322 .. _`PhpStormProtocol`: https://github.com/aik099/PhpStormProtocol .. _`phpstorm-url-handler`: https://github.com/sanduhrs/phpstorm-url-handler .. _`blue/green deployment`: https://martinfowler.com/bliki/BlueGreenDeployment.html @@ -3146,3 +3378,5 @@ to know their differences. .. _`session.cache-limiter`: https://www.php.net/manual/en/session.configuration.php#ini.session.cache-limiter .. _`Microsoft NTLM authentication protocol`: https://docs.microsoft.com/en-us/windows/win32/secauthn/microsoft-ntlm .. _`utf-8 modifier`: https://www.php.net/reference.pcre.pattern.modifiers +.. _`Link HTTP header`: https://tools.ietf.org/html/rfc5988 +.. _`SMTP session`: https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#SMTP_transport_example diff --git a/reference/configuration/kernel.rst b/reference/configuration/kernel.rst index 27707807ed4..006ad7b3208 100644 --- a/reference/configuration/kernel.rst +++ b/reference/configuration/kernel.rst @@ -5,18 +5,12 @@ Configuring in the Kernel ========================= Some configuration can be done on the kernel class itself (located by default at -``src/Kernel.php``). You can do this by overriding specific methods in +``src/Kernel.php``). You can do this by overriding specific methods of the parent :class:`Symfony\\Component\\HttpKernel\\Kernel` class. Configuration ------------- -* `Charset`_ -* `Project Directory`_ -* `Cache Directory`_ -* `Log Directory`_ -* `Container Build Time`_ - In previous Symfony versions there was another configuration option to define the "kernel name", which is only important when :doc:`using applications with multiple kernels `. @@ -103,6 +97,8 @@ the :method:`Symfony\\Component\\HttpKernel\\Kernel::getCacheDir` method. To change this setting, override the ``getCacheDir()`` method to return the correct cache directory. +.. _configuration-kernel-build-directory: + Build Directory ~~~~~~~~~~~~~~~ @@ -123,7 +119,6 @@ the :method:`Symfony\\Component\\HttpKernel\\Kernel::getBuildDir` method. To change this setting, override the ``getBuildDir()`` method to return the correct build directory. - Log Directory ~~~~~~~~~~~~~ diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index f4310635c5e..50cc2ddf2cc 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -29,7 +29,6 @@ Configuration * `access_denied_url`_ * `always_authenticate_before_granting`_ -* `anonymous`_ * `erase_credentials`_ * `hide_user_not_found`_ * `session_fixation_strategy`_ @@ -40,7 +39,7 @@ Some of these options define tens of sub-options and they are explained in separate articles: * `access_control`_ -* `encoders`_ +* :ref:`hashers ` * `firewalls`_ * `providers`_ * `role_hierarchy`_ @@ -58,19 +57,15 @@ always_authenticate_before_granting **type**: ``boolean`` **default**: ``false`` +.. deprecated:: 5.4 + + The ``always_authenticate_before_granting`` option was deprecated in + Symfony 5.4 and it will be removed in Symfony 6.0. + If ``true``, the user is asked to authenticate before each call to the ``isGranted()`` method in services and controllers or ``is_granted()`` from templates. -anonymous -~~~~~~~~~ - -**type**: ``string`` **default**: ``~`` - -When set to ``lazy``, Symfony loads the user (and starts the session) only if -the application actually accesses the ``User`` object (e.g. via a ``is_granted()`` -call in a template or ``isGranted()`` in a controller or service). - erase_credentials ~~~~~~~~~~~~~~~~~ @@ -89,8 +84,8 @@ If ``true``, when a user is not found a generic exception of type is thrown with the message "Bad credentials". If ``false``, the exception thrown is of type -:class:`Symfony\\Component\\Security\\Core\\Exception\\UsernameNotFoundException` -and it includes the given not found username. +:class:`Symfony\\Component\\Security\\Core\\Exception\\UserNotFoundException` +and it includes the given not found user identifier. session_fixation_strategy ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -116,200 +111,10 @@ access_control Defines the security protection of the URLs of your application. It's used for example to trigger the user authentication when trying to access to the backend -and to allow anonymous users to the login form page. +and to allow unauthenticated users to the login form page. This option is explained in detail in :doc:`/security/access_control`. -encoders --------- - -This option defines the algorithm used to *encode* the password of the users. -Although Symfony calls it *"password encoding"* for historical reasons, this is -in fact, *"password hashing"*. - -If your app defines more than one user class, each of them can define its own -encoding algorithm. Also, each algorithm defines different config options: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - encoders: - # auto encoder with default options - App\Entity\User: 'auto' - - # auto encoder with custom options - App\Entity\User: - algorithm: 'auto' - cost: 15 - - # Sodium encoder with default options - App\Entity\User: 'sodium' - - # Sodium encoder with custom options - App\Entity\User: - algorithm: 'sodium' - memory_cost: 16384 # Amount in KiB. (16384 = 16 MiB) - time_cost: 2 # Number of iterations - - # MessageDigestPasswordEncoder encoder using SHA512 hashing with default options - App\Entity\User: 'sha512' - - .. code-block:: xml - - - - - - - - - - - - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - use App\Entity\User; - - $container->loadFromExtension('security', [ - // ... - 'encoders' => [ - // auto encoder with default options - User::class => [ - 'algorithm' => 'auto', - ], - - // auto encoder with custom options - User::class => [ - 'algorithm' => 'auto', - 'cost' => 15, - ], - - // Sodium encoder with default options - User::class => [ - 'algorithm' => 'sodium', - ], - - // Sodium encoder with custom options - User::class => [ - 'algorithm' => 'sodium', - 'memory_cost' => 16384, // Amount in KiB. (16384 = 16 MiB) - 'time_cost' => 2, // Number of iterations - ], - - // MessageDigestPasswordEncoder encoder using SHA512 hashing with default options - User::class => [ - 'algorithm' => 'sha512', - ], - ], - ]); - -.. tip:: - - You can also create your own password encoders as services and you can even - select a different password encoder for each user instance. Read - :doc:`this article ` for more details. - -.. _reference-security-sodium: -.. _using-the-argon2i-password-encoder: - -Using the Sodium Password Encoder -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -It uses the `Argon2 key derivation function`_ and it's the encoder recommended -by Symfony. Argon2 support was introduced in PHP 7.2, but if you use an earlier -PHP version, you can install the `libsodium`_ PHP extension. - -The encoded passwords are ``96`` characters long, but due to the hashing -requirements saved in the resulting hash this may change in the future, so make -sure to allocate enough space for them to be persisted. Also, passwords include -the `cryptographic salt`_ inside them (it's generated automatically for each new -password) so you don't have to deal with it. - -.. _reference-security-encoder-auto: - -Using the "auto" Password Encoder -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -It selects automatically the best possible encoder. Currently, it tries to use -Sodium by default and falls back to the `bcrypt password hashing function`_ if -not possible. In the future, when PHP adds new hashing techniques, it may use -different password hashers. - -It produces encoded passwords with ``60`` characters long, so make sure to -allocate enough space for them to be persisted. Also, passwords include the -`cryptographic salt`_ inside them (it's generated automatically for each new -password) so you don't have to deal with it. - -Its only configuration option is ``cost``, which is an integer in the range of -``4-31`` (by default, ``13``). Each single increment of the cost **doubles the -time** it takes to encode a password. It's designed this way so the password -strength can be adapted to the future improvements in computation power. - -You can change the cost at any time — even if you already have some passwords -encoded using a different cost. New passwords will be encoded using the new -cost, while the already encoded ones will be validated using a cost that was -used back when they were encoded. - -.. tip:: - - A simple technique to make tests much faster when using BCrypt is to set - the cost to ``4``, which is the minimum value allowed, in the ``test`` - environment configuration. - -.. _reference-security-pbkdf2: - -Using the PBKDF2 Encoder -~~~~~~~~~~~~~~~~~~~~~~~~ - -Using the `PBKDF2`_ encoder is no longer recommended since PHP added support for -Sodium and BCrypt. Legacy application still using it are encouraged to upgrade -to those newer encoding algorithms. - firewalls --------- @@ -336,7 +141,7 @@ application: .. code-block:: xml - + loadFromExtension('security', [ - 'firewalls' => [ - // 'main' is the name of the firewall (can be chosen freely) - 'main' => [ - // 'pattern' is a regular expression matched against the incoming - // request URL. If there's a match, authentication is triggered - 'pattern' => '^/admin', - // the rest of options depend on the authentication mechanism - // ... - ], - ], - ]); + // 'main' is the name of the firewall (can be chosen freely) + $security->firewall('main') + // 'pattern' is a regular expression matched against the incoming + // request URL. If there's a match, authentication is triggered + ->pattern('^/admin') + // the rest of options depend on the authentication mechanism + // ... + ; + }; .. seealso:: @@ -410,6 +215,26 @@ depend on the authentication mechanism, which can be any of these: http_digest: # ... +You can view actual information about the firewalls in your application with +the ``debug:firewall`` command: + +.. code-block:: terminal + + # displays a list of firewalls currently configured for your application + $ php bin/console debug:firewall + + # displays the details of a specific firewall + $ php bin/console debug:firewall main + + # displays the details of a specific firewall, including detailed information + # about the event listeners for the firewall + $ php bin/console debug:firewall main --events + +.. versionadded:: 5.3 + + The ``debug:firewall`` command was introduced in Symfony 5.3. + + .. _reference-security-firewall-form-login: ``form_login`` Authentication @@ -552,6 +377,15 @@ the current firewall and not the other ones. The path which triggers logout. If you change it from the default value ``/logout``, you need to set up a route with a matching path. +target +~~~~~~ + +**type**: ``string`` **default**: ``/`` + +The relative path (if the value starts with ``/``), or absolute URL (if it +starts with ``http://`` or ``https://``) or the route name (otherwise) to +redirect after logout. + success_handler ~~~~~~~~~~~~~~~ @@ -567,6 +401,8 @@ success_handler The service ID used for handling a successful logout. The service must implement :class:`Symfony\\Component\\Security\\Http\\Logout\\LogoutSuccessHandlerInterface`. +If it is set, the logout ``target`` option will be ignored. + .. _reference-security-logout-csrf: csrf_parameter @@ -591,6 +427,102 @@ csrf_token_id An arbitrary string used to identify the token (and check its validity afterwards). +.. _reference-security-firewall-json-login: + +JSON Login Authentication +~~~~~~~~~~~~~~~~~~~~~~~~~ + +check_path +.......... + +**type**: ``string`` **default**: ``/login_check`` + +This is the URL or route name the system must post to authenticate using +the JSON authenticator. The path must be covered by the firewall to which +the user will authenticate. + +username_path +............. + +**type**: ``string`` **default**: ``username`` + +Use this and ``password_path`` to modify the expected request body +structure of the JSON authenticator. For instance, if the JSON document has +the following structure: + +.. code-block:: json + + { + "security": { + "credentials": { + "login": "dunglas", + "password": "MyPassword" + } + } + } + +The security configuration should be: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + + firewalls: + main: + lazy: true + json_login: + check_path: login + username_path: security.credentials.login + password_path: security.credentials.password + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $mainFirewall = $security->firewall('main'); + $mainFirewall->lazy(true); + $mainFirewall->jsonLogin() + ->checkPath('/login') + ->usernamePath('security.credentials.login') + ->passwordPath('security.credentials.password') + ; + }; + +password_path +............. + +**type**: ``string`` **default**: ``password`` + +Use this option to modify the expected request body structure. See +`username_path`_ for more details. + .. _reference-security-ldap: LDAP Authentication @@ -647,12 +579,157 @@ fetch your users from an LDAP server, you will need to use the :doc:`LDAP User Provider ` and any of these authentication providers: ``form_login_ldap`` or ``http_basic_ldap`` or ``json_login_ldap``. +.. _reference-security-firewall-x509: + +X.509 Authentication +~~~~~~~~~~~~~~~~~~~~ + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + + firewalls: + main: + # ... + x509: + provider: your_user_provider + user: SSL_CLIENT_S_DN_Email + credentials: SSL_CLIENT_S_DN + + .. code-block:: xml + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $mainFirewall = $security->firewall('main'); + $mainFirewall->x509() + ->provider('your_user_provider') + ->user('SSL_CLIENT_S_DN_Email') + ->credentials('SSL_CLIENT_S_DN') + ; + }; + +user +.... + +**type**: ``string`` **default**: ``SSL_CLIENT_S_DN_Email`` + +The name of the ``$_SERVER`` parameter containing the user identifier used +to load the user in Symfony. The default value is exposed by Apache. + +credentials +........... + +**type**: ``string`` **default**: ``SSL_CLIENT_S_DN`` + +If the ``user`` parameter is not available, the name of the ``$_SERVER`` +parameter containing the full "distinguished name" of the certificate +(exposed by e.g. Nginx). + +Symfony identifies the value following ``emailAddress=`` in this parameter. + +.. _reference-security-firewall-remote-user: + +Remote User Authentication +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + firewalls: + main: + # ... + remote_user: + provider: your_user_provider + user: REMOTE_USER + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $mainFirewall = $security->firewall('main'); + $mainFirewall->remoteUser() + ->provider('your_user_provider') + ->user('REMOTE_USER') + ; + }; + +provider +........ + +**type**: ``string`` + +The service ID of the user provider that should be used by this +authenticator. + +user +.... + +**type**: ``string`` **default**: ``REMOTE_USER`` + +The name of the ``$_SERVER`` parameter holding the user identifier. + .. _reference-security-firewall-context: Firewall Context ~~~~~~~~~~~~~~~~ -Most applications will only need one :ref:`firewall `. +Most applications will only need one :ref:`firewall `. But if your application *does* use multiple firewalls, you'll notice that if you're authenticated in one firewall, you're not automatically authenticated in another. In other words, the systems don't share a common "context": @@ -682,7 +759,7 @@ multiple firewalls, the "context" could actually be shared: .. code-block:: xml - + loadFromExtension('security', [ - 'firewalls' => [ - 'somename' => [ - // ... - 'context' => 'my_context', - ], - 'othername' => [ - // ... - 'context' => 'my_context', - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('somename') + // ... + ->context('my_context') + ; + + $security->firewall('othername') + // ... + ->context('my_context') + ; + }; .. note:: @@ -737,13 +815,9 @@ providers --------- This options defines how the application users are loaded (from a database, -an LDAP server, a configuration file, etc.) Read the following articles to learn -more about each of those providers: - -* :ref:`Load users from a database ` -* :ref:`Load users from an LDAP server ` -* :ref:`Load users from a configuration file ` -* :ref:`Create your own user provider ` +an LDAP server, a configuration file, etc.) Read +:doc:`/security/user_providers` to learn more about each of those +providers. role_hierarchy -------------- @@ -752,9 +826,4 @@ Instead of associating many roles to users, this option allows you to define role inheritance rules by creating a role hierarchy, as explained in :ref:`security-role-hierarchy`. -.. _`PBKDF2`: https://en.wikipedia.org/wiki/PBKDF2 -.. _`libsodium`: https://pecl.php.net/package/libsodium .. _`Session Fixation`: https://owasp.org/www-community/attacks/Session_fixation -.. _`Argon2 key derivation function`: https://en.wikipedia.org/wiki/Argon2 -.. _`bcrypt password hashing function`: https://en.wikipedia.org/wiki/Bcrypt -.. _`cryptographic salt`: https://en.wikipedia.org/wiki/Salt_(cryptography) diff --git a/reference/configuration/swiftmailer.rst b/reference/configuration/swiftmailer.rst index 674cee6ae53..2e46e99b000 100644 --- a/reference/configuration/swiftmailer.rst +++ b/reference/configuration/swiftmailer.rst @@ -4,391 +4,10 @@ Mailer Configuration Reference (SwiftmailerBundle) ================================================== -The SwiftmailerBundle integrates the Swiftmailer library in Symfony applications -to :doc:`send emails `. All these options are configured under the -``swiftmailer`` key in your application configuration. - -.. code-block:: terminal - - # displays the default config values defined by Symfony - $ php bin/console config:dump-reference swiftmailer - - # displays the actual config values used by your application - $ php bin/console debug:config swiftmailer - -.. note:: - - When using XML, you must use the ``http://symfony.com/schema/dic/swiftmailer`` - namespace and the related XSD schema is available at: - ``https://symfony.com/schema/dic/swiftmailer/swiftmailer-1.0.xsd`` - -Configuration -------------- - -.. rst-class:: list-config-options list-config-options--complex - -* `antiflood`_ - - * `sleep`_ - * `threshold`_ - -* `auth_mode`_ -* `command`_ -* `delivery_addresses`_ -* `delivery_whitelist`_ -* `disable_delivery`_ -* `encryption`_ -* `host`_ -* `local_domain`_ -* `logging`_ -* `password`_ -* `port`_ -* `sender_address`_ -* `source_ip`_ -* `spool`_ - - * `path`_ - * `type`_ - -* `timeout`_ -* `transport`_ -* `url`_ -* `username`_ - -url -~~~ - -**type**: ``string`` - -The entire SwiftMailer configuration using a DSN-like URL format. - -Example: ``smtp://user:pass@host:port/?timeout=60&encryption=ssl&auth_mode=login&...`` - -transport -~~~~~~~~~ - -**type**: ``string`` **default**: ``smtp`` - -The exact transport method to use to deliver emails. Valid values are: - -* smtp -* gmail (see :ref:`email-using-gmail`) -* mail (deprecated in SwiftMailer since version 5.4.5) -* sendmail -* null (same as setting `disable_delivery`_ to ``true``) - -username -~~~~~~~~ - -**type**: ``string`` - -The username when using ``smtp`` as the transport. - -password -~~~~~~~~ - -**type**: ``string`` - -The password when using ``smtp`` as the transport. - -command -~~~~~~~~ - -**type**: ``string`` **default**: ``/usr/sbin/sendmail -bs`` - -Command to be executed by ``sendmail`` transport. - -host -~~~~ - -**type**: ``string`` **default**: ``localhost`` - -The host to connect to when using ``smtp`` as the transport. - -port -~~~~ - -**type**: ``string`` **default**: 25 or 465 (depending on `encryption`_) - -The port when using ``smtp`` as the transport. This defaults to 465 if encryption -is ``ssl`` and 25 otherwise. - -timeout -~~~~~~~ - -**type**: ``integer`` - -The timeout in seconds when using ``smtp`` as the transport. - -source_ip -~~~~~~~~~ - -**type**: ``string`` - -The source IP address when using ``smtp`` as the transport. - -local_domain -~~~~~~~~~~~~ - -**type**: ``string`` - -.. versionadded:: 2.4.0 - - The ``local_domain`` option was introduced in SwiftMailerBundle 2.4.0. - -The domain name to use in ``HELO`` command. - -encryption -~~~~~~~~~~ - -**type**: ``string`` - -The encryption mode to use when using ``smtp`` as the transport. Valid values -are ``tls``, ``ssl``, or ``null`` (indicating no encryption). - -auth_mode -~~~~~~~~~ - -**type**: ``string`` - -The authentication mode to use when using ``smtp`` as the transport. Valid -values are ``plain``, ``login``, ``cram-md5``, or ``null``. - -spool -~~~~~ - -For details on email spooling, see :doc:`/mailer`. - -type -.... - -**type**: ``string`` **default**: ``file`` - -The method used to store spooled messages. Valid values are ``memory`` and -``file``. A custom spool should be possible by creating a service called -``swiftmailer.spool.myspool`` and setting this value to ``myspool``. - -path -.... - -**type**: ``string`` **default**: ``%kernel.cache_dir%/swiftmailer/spool`` - -When using the ``file`` spool, this is the path where the spooled messages -will be stored. - -sender_address -~~~~~~~~~~~~~~ - -**type**: ``string`` - -If set, all messages will be delivered with this address as the "return -path" address, which is where bounced messages should go. This is handled -internally by Swift Mailer's ``Swift_Plugins_ImpersonatePlugin`` class. - -antiflood -~~~~~~~~~ - -threshold -......... - -**type**: ``integer`` **default**: ``99`` - -Used with ``Swift_Plugins_AntiFloodPlugin``. This is the number of emails -to send before restarting the transport. - -sleep -..... - -**type**: ``integer`` **default**: ``0`` - -Used with ``Swift_Plugins_AntiFloodPlugin``. This is the number of seconds -to sleep for during a transport restart. - -.. _delivery-address: - -delivery_addresses -~~~~~~~~~~~~~~~~~~ - -**type**: ``array`` - -.. note:: - - In previous versions, this option was called ``delivery_address``. - -If set, all email messages will be sent to these addresses instead of being sent -to their actual recipients. This is often useful when developing. For example, -by setting this in the ``config/packages/dev/swiftmailer.yaml`` file, you can -guarantee that all emails sent during development go to one or more some -specific accounts. - -This uses ``Swift_Plugins_RedirectingPlugin``. Original recipients are available -on the ``X-Swift-To``, ``X-Swift-Cc`` and ``X-Swift-Bcc`` headers. - -delivery_whitelist -~~~~~~~~~~~~~~~~~~ - -**type**: ``array`` - -Used in combination with ``delivery_address`` or ``delivery_addresses``. If set, emails matching any -of these patterns will be delivered like normal, as well as being sent to -``delivery_address`` or ``delivery_addresses``. For details, see the -:ref:`How to Work with Emails during Development ` -article. - -disable_delivery -~~~~~~~~~~~~~~~~ - -**type**: ``boolean`` **default**: ``false`` - -If true, the ``transport`` will automatically be set to ``null`` and no -emails will actually be delivered. - -logging -~~~~~~~ - -**type**: ``boolean`` **default**: ``%kernel.debug%`` - -If true, Symfony's data collector will be activated for Swift Mailer and -the information will be available in the profiler. - -.. tip:: - - The following options can be set via environment variables: ``url``, - ``transport``, ``username``, ``password``, ``host``, ``port``, ``timeout``, - ``source_ip``, ``local_domain``, ``encryption``, ``auth_mode``. For details, - see: :ref:`config-env-vars`. - -Using Multiple Mailers ----------------------- - -You can configure multiple mailers by grouping them under the ``mailers`` -key (the default mailer is identified by the ``default_mailer`` option): - -.. configuration-block:: - - .. code-block:: yaml - - swiftmailer: - default_mailer: second_mailer - mailers: - first_mailer: - # ... - second_mailer: - # ... - - .. code-block:: xml - - - - - - - - - - - .. code-block:: php - - $container->loadFromExtension('swiftmailer', [ - 'default_mailer' => 'second_mailer', - 'mailers' => [ - 'first_mailer' => [ - // ... - ], - 'second_mailer' => [ - // ... - ], - ], - ]); - -Each mailer is registered automatically as a service with these IDs:: - - // ... - - // returns the first mailer - $container->get('swiftmailer.mailer.first_mailer'); - - // also returns the second mailer since it is the default mailer - $container->get('swiftmailer.mailer'); - - // returns the second mailer - $container->get('swiftmailer.mailer.second_mailer'); - .. caution:: - When configuring multiple mailers, options must be placed under the - appropriate mailer key of the configuration instead of directly under the - ``swiftmailer`` key. - -When using :ref:`autowiring ` only the default mailer is -injected when type-hinting some argument with the ``\Swift_Mailer`` class. If -you need to inject a different mailer in some service, use any of these -alternatives based on the :ref:`service binding ` feature: - -.. configuration-block:: - - .. code-block:: yaml - - # config/services.yaml - services: - _defaults: - bind: - # this injects the second mailer when type-hinting constructor arguments with \Swift_Mailer - \Swift_Mailer: '@swiftmailer.mailer.second_mailer' - # this injects the second mailer when a service constructor argument is called $specialMailer - $specialMailer: '@swiftmailer.mailer.second_mailer' - - App\Some\Service: - # this injects the second mailer only for this argument of this service - $differentMailer: '@swiftmailer.mailer.second_mailer' - - # ... - - .. code-block:: xml - - - - - - - - - @swiftmailer.mailer.second_mailer - - @swiftmailer.mailer.second_mailer - - - - - @swiftmailer.mailer.second_mailer - - - - - - - .. code-block:: php - - // config/services.php - use App\Some\Service; - use Psr\Log\LoggerInterface; - + The Swift Mailer project is not supported since November 2021 and its + integration with Symfony was removed in Symfony 6.0. - $container->register(Service::class) - ->setPublic(true) - ->setBindings([ - // this injects the second mailer when this service type-hints constructor arguments with \Swift_Mailer - \Swift_Mailer::class => '@swiftmailer.mailer.second_mailer', - // this injects the second mailer when this service has a constructor argument called $specialMailer - '$specialMailer' => '@swiftmailer.mailer.second_mailer', - ]) - ; + Use the :doc:`Symfony Mailer ` component, which was introduced in + Symfony 4.3 as a modern replacement of Swift Mailer. diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst index e00d7f63958..b4893beabae 100644 --- a/reference/configuration/twig.rst +++ b/reference/configuration/twig.rst @@ -25,35 +25,6 @@ under the ``twig`` key in your application configuration. Configuration ------------- -.. rst-class:: list-config-options list-config-options--complex - -* `auto_reload`_ -* `autoescape`_ -* `autoescape_service`_ -* `autoescape_service_method`_ -* `base_template_class`_ -* `cache`_ -* `charset`_ -* `date`_ - - * `format`_ - * `interval_format`_ - * `timezone`_ - -* `debug`_ -* `default_path`_ -* `form_themes`_ -* `globals`_ -* `number_format`_ - - * `decimals`_ - * `decimal_point`_ - * `thousands_separator`_ - -* `optimizations`_ -* `paths`_ -* `strict_variables`_ - auto_reload ~~~~~~~~~~~ @@ -235,13 +206,16 @@ all the forms of the application: .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ - 'form_themes' => [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { + $twig->formThemes([ 'bootstrap_4_layout.html.twig', 'form/my_theme.html.twig', - ], + ]); + // ... - ]); + }; The order in which themes are defined is important because each theme overrides all the previous one. When rendering a form field whose block is not defined in @@ -294,7 +268,7 @@ no specific character is passed as argument to the ``number_format`` filter. optimizations ~~~~~~~~~~~~~ -**type**: ``int`` **default**: ``-1`` +**type**: ``integer`` **default**: ``-1`` Twig includes an extension called ``optimizer`` which is enabled by default in Symfony applications. This extension analyzes the templates to optimize them @@ -348,20 +322,23 @@ the directory defined in the :ref:`default_path option loadFromExtension('twig', [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { // ... - 'paths' => [ - 'email/default/templates' => null, - 'backend/templates' => 'admin', - ], - ]); + + $twig->path('email/default/templates', null); + $twig->path('backend/templates', 'admin'); + }; Read more about :ref:`template directories and namespaces `. +.. _config-twig-strict-variables: + strict_variables ~~~~~~~~~~~~~~~~ -**type**: ``boolean`` **default**: ``false`` +**type**: ``boolean`` **default**: ``%kernel.debug%`` If set to ``true``, Symfony shows an exception whenever a Twig variable, attribute or method doesn't exist. If set to ``false`` these errors are ignored diff --git a/reference/configuration/web_profiler.rst b/reference/configuration/web_profiler.rst index 83f92e215a5..9d3ddb088f5 100644 --- a/reference/configuration/web_profiler.rst +++ b/reference/configuration/web_profiler.rst @@ -30,12 +30,6 @@ under the ``web_profiler`` key in your application configuration. Configuration ------------- -.. rst-class:: list-config-options - -* `excluded_ajax_paths`_ -* `intercept_redirects`_ -* `toolbar`_ - excluded_ajax_paths ~~~~~~~~~~~~~~~~~~~ diff --git a/reference/constraints.rst b/reference/constraints.rst index 56acb087114..34ed5d08dab 100644 --- a/reference/constraints.rst +++ b/reference/constraints.rst @@ -76,6 +76,7 @@ Validation Constraints Reference constraints/NotCompromisedPassword constraints/Valid constraints/Traverse + constraints/CssColor The Validator is designed to validate objects against *constraints*. In real life, a constraint could be: "The cake must not be burned". In diff --git a/reference/constraints/All.rst b/reference/constraints/All.rst index 1577a07ec4d..bdb0ebda7d1 100644 --- a/reference/constraints/All.rst +++ b/reference/constraints/All.rst @@ -6,9 +6,6 @@ you to apply a collection of constraints to each element of the array. ========== =================================================================== Applies to :ref:`property or method ` -Options - `constraints`_ - - `groups`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\All` Validator :class:`Symfony\\Component\\Validator\\Constraints\\AllValidator` ========== =================================================================== diff --git a/reference/constraints/AtLeastOneOf.rst b/reference/constraints/AtLeastOneOf.rst index 6a48c44a4fd..9a173008c0f 100644 --- a/reference/constraints/AtLeastOneOf.rst +++ b/reference/constraints/AtLeastOneOf.rst @@ -10,12 +10,6 @@ constraints. The validation stops as soon as one constraint is satisfied. ========== =================================================================== Applies to :ref:`property or method ` -Options - `constraints`_ - - `includeInternalMessages`_ - - `message`_ - - `messageCollection`_ - - `groups`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\AtLeastOneOf` Validator :class:`Symfony\\Component\\Validator\\Constraints\\AtLeastOneOfValidator` ========== =================================================================== @@ -141,7 +135,7 @@ The following constraints ensure that: new Assert\Count(['min' => 3]), new Assert\All([ 'constraints' => [ - new Assert\GreaterThanOrEqual(['value' => 5]), + new Assert\GreaterThanOrEqual(5), ], ]), ], @@ -163,7 +157,7 @@ has to be satisfied in order for the validation to succeed. includeInternalMessages ~~~~~~~~~~~~~~~~~~~~~~~ -**type**: ``bool`` **default**: ``true`` +**type**: ``boolean`` **default**: ``true`` If set to ``true``, the message that is shown if the validation fails, will include the list of messages for the internal constraints. See option diff --git a/reference/constraints/Bic.rst b/reference/constraints/Bic.rst index 029a322e294..0f041e4a26f 100644 --- a/reference/constraints/Bic.rst +++ b/reference/constraints/Bic.rst @@ -8,12 +8,6 @@ check that the BIC's country code is the same as a given IBAN's one. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `iban`_ - - `ibanMessage`_ - - `ibanPropertyPath`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Bic` Validator :class:`Symfony\\Component\\Validator\\Constraints\\BicValidator` ========== =================================================================== @@ -41,6 +35,19 @@ will contain a Business Identifier Code (BIC). protected $businessIdentifierCode; } + .. code-block:: php-attributes + + // src/Entity/Transaction.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Transaction + { + #[Assert\Bic] + protected $businessIdentifierCode; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -87,22 +94,22 @@ Available Options .. include:: /reference/constraints/_groups-option.rst.inc -iban -~~~~ +``iban`` +~~~~~~~~ **type**: ``string`` **default**: ``null`` An IBAN value to validate that its country code is the same as the BIC's one. -ibanMessage -~~~~~~~~~~~ +``ibanMessage`` +~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}.`` The default message supplied when the value does not pass the combined BIC/IBAN check. -ibanPropertyPath -~~~~~~~~~~~~~~~~ +``ibanPropertyPath`` +~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``null`` @@ -112,8 +119,8 @@ For example, if you want to compare the ``$bic`` property of some object with regard to the ``$iban`` property of the same object, use ``ibanPropertyPath="iban"`` in the comparison constraint of ``$bic``. -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This is not a valid Business Identifier Code (BIC).`` diff --git a/reference/constraints/Blank.rst b/reference/constraints/Blank.rst index 8a5ba13671a..4bd7a6f869f 100644 --- a/reference/constraints/Blank.rst +++ b/reference/constraints/Blank.rst @@ -15,9 +15,6 @@ But be careful as ``NotBlank`` is *not* strictly the opposite of ``Blank``. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Blank` Validator :class:`Symfony\\Component\\Validator\\Constraints\\BlankValidator` ========== =================================================================== @@ -45,6 +42,19 @@ of an ``Author`` class were blank, you could do the following: protected $firstName; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Blank] + protected $firstName; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Callback.rst b/reference/constraints/Callback.rst index 6985f3953e1..177b3e074a8 100644 --- a/reference/constraints/Callback.rst +++ b/reference/constraints/Callback.rst @@ -19,9 +19,6 @@ can do anything, including creating and assigning validation errors. ========== =================================================================== Applies to :ref:`class ` or :ref:`property/method ` -Options - :ref:`callback ` - - `groups`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Callback` Validator :class:`Symfony\\Component\\Validator\\Constraints\\CallbackValidator` ========== =================================================================== @@ -50,6 +47,23 @@ Configuration } } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Context\ExecutionContextInterface; + + class Author + { + #[Assert\Callback] + public function validate(ExecutionContextInterface $context, $payload) + { + // ... + } + } + .. code-block:: yaml # config/validator/validation.yaml @@ -178,6 +192,19 @@ You can then use the following configuration to invoke this validator: { } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Acme\Validator; + use Symfony\Component\Validator\Constraints as Assert; + + #[Assert\Callback([Validator::class, 'validate'])] + class Author + { + } + .. code-block:: yaml # config/validator/validation.yaml @@ -251,6 +278,12 @@ constructor of the Callback constraint:: } } +.. warning:: + + Using a ``Closure`` together with annotation configuration will disable the + annotation cache for that class/property/method because ``Closure`` cannot + be cached. For best performance, it's recommended to use a static callback method. + Options ------- diff --git a/reference/constraints/CardScheme.rst b/reference/constraints/CardScheme.rst index 64d6157e2c8..f8487b75e93 100644 --- a/reference/constraints/CardScheme.rst +++ b/reference/constraints/CardScheme.rst @@ -7,10 +7,6 @@ a payment through a payment gateway. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ - - `schemes`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\CardScheme` Validator :class:`Symfony\\Component\\Validator\\Constraints\\CardSchemeValidator` ========== =================================================================== @@ -41,6 +37,22 @@ on an object that will contain a credit card number. protected $cardNumber; } + .. code-block:: php-attributes + + // src/Entity/Transaction.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Transaction + { + #[Assert\CardScheme( + schemes: [Assert\CardScheme::VISA], + message: 'Your credit card number is invalid.', + )] + protected $cardNumber; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -85,7 +97,7 @@ on an object that will contain a credit card number. { $metadata->addPropertyConstraint('cardNumber', new Assert\CardScheme([ 'schemes' => [ - 'VISA', + Assert\CardScheme::VISA, ], 'message' => 'Your credit card number is invalid.', ])); @@ -99,8 +111,8 @@ Available Options .. include:: /reference/constraints/_groups-option.rst.inc -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``Unsupported card type or invalid card number.`` @@ -121,8 +133,8 @@ Parameter Description .. include:: /reference/constraints/_payload-option.rst.inc -schemes -~~~~~~~ +``schemes`` +~~~~~~~~~~~ **type**: ``mixed`` [:ref:`default option `] diff --git a/reference/constraints/Choice.rst b/reference/constraints/Choice.rst index fd8481d6152..ebf0efaaff7 100644 --- a/reference/constraints/Choice.rst +++ b/reference/constraints/Choice.rst @@ -7,17 +7,6 @@ an array of items is one of those valid choices. ========== =================================================================== Applies to :ref:`property or method ` -Options - `callback`_ - - `choices`_ - - `groups`_ - - `max`_ - - `maxMessage`_ - - `message`_ - - `min`_ - - `minMessage`_ - - `multiple`_ - - `multipleMessage`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Choice` Validator :class:`Symfony\\Component\\Validator\\Constraints\\ChoiceValidator` ========== =================================================================== @@ -58,6 +47,24 @@ If your valid choice list is simple, you can pass them in directly via the protected $genre; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + const GENRES = ['fiction', 'non-fiction']; + + #[Assert\Choice(['New York', 'Berlin', 'Tokyo'])] + protected $city; + + #[Assert\Choice(choices: Author::GENRES, message: 'Choose a valid genre.')] + protected $genre; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -160,6 +167,19 @@ constraint. protected $genre; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Choice(callback: 'getGenres')] + protected $genre; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -225,6 +245,20 @@ you can pass the class name and the method as an array. protected $genre; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use App\Entity\Genre + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Choice(callback: [Genre::class, 'getGenres'])] + protected $genre; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -275,8 +309,8 @@ you can pass the class name and the method as an array. Available Options ----------------- -callback -~~~~~~~~ +``callback`` +~~~~~~~~~~~~ **type**: ``string|array|Closure`` @@ -284,8 +318,8 @@ This is a callback method that can be used instead of the `choices`_ option to return the choices array. See `Supplying the Choices with a Callback Function`_ for details on its usage. -choices -~~~~~~~ +``choices`` +~~~~~~~~~~~ **type**: ``array`` [:ref:`default option `] @@ -295,8 +329,8 @@ will be matched against this array. .. include:: /reference/constraints/_groups-option.rst.inc -max -~~~ +``max`` +~~~~~~~ **type**: ``integer`` @@ -305,8 +339,8 @@ to force no more than XX number of values to be selected. For example, if ``max`` is 3, but the input array contains 4 valid items, the validation will fail. -maxMessage -~~~~~~~~~~ +``maxMessage`` +~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``You must select at most {{ limit }} choices.`` @@ -322,8 +356,8 @@ Parameter Description ``{{ value }}`` The current (invalid) value ================= ============================================================ -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``The value you selected is not a valid choice.`` @@ -340,8 +374,8 @@ Parameter Description ``{{ value }}`` The current (invalid) value ================= ============================================================ -min -~~~ +``min`` +~~~~~~~ **type**: ``integer`` @@ -350,8 +384,8 @@ to force at least XX number of values to be selected. For example, if ``min`` is 3, but the input array only contains 2 valid items, the validation will fail. -minMessage -~~~~~~~~~~ +``minMessage`` +~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``You must select at least {{ limit }} choices.`` @@ -367,8 +401,8 @@ Parameter Description ``{{ value }}`` The current (invalid) value ================= ============================================================ -multiple -~~~~~~~~ +``multiple`` +~~~~~~~~~~~~ **type**: ``boolean`` **default**: ``false`` @@ -377,8 +411,8 @@ of a single, scalar value. The constraint will check that each value of the input array can be found in the array of valid choices. If even one of the input values cannot be found, the validation will fail. -multipleMessage -~~~~~~~~~~~~~~~ +``multipleMessage`` +~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``One or more of the given values is invalid.`` diff --git a/reference/constraints/Cidr.rst b/reference/constraints/Cidr.rst new file mode 100644 index 00000000000..bb51a4826be --- /dev/null +++ b/reference/constraints/Cidr.rst @@ -0,0 +1,150 @@ +Cidr +==== + +.. versionadded:: 5.4 + + The ``Cidr`` constraint was introduced in Symfony 5.4. + +Validates that a value is a valid `CIDR`_ (Classless Inter-Domain Routing) notation. +By default, this will validate the CIDR's IP and netmask both for version 4 and 6, +with the option of allowing only one type of IP version to be valid. It also supports +a minimum and maximum range constraint in which the value of the netmask is valid. + +========== =================================================================== +Applies to :ref:`property or method ` +Class :class:`Symfony\\Component\\Validator\\Constraints\\Cidr` +Validator :class:`Symfony\\Component\\Validator\\Constraints\\CidrValidator` +========== =================================================================== + +Basic Usage +----------- + +.. configuration-block:: + + .. code-block:: php-annotations + + // src/Entity/NetworkSettings.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class NetworkSettings + { + /** + * @Assert\Cidr + */ + protected $cidrNotation; + } + + .. code-block:: php-attributes + + // src/Entity/NetworkSettings.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class NetworkSettings + { + #[Assert\Cidr] + protected $cidrNotation; + } + + .. code-block:: yaml + + # config/validator/validation.yaml + App\Entity\NetworkSettings: + properties: + cidrNotation: + - Cidr: ~ + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/NetworkSettings.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; + + class NetworkSettings + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('cidrNotation', new Assert\Cidr()); + } + } + +.. include:: /reference/constraints/_empty-values-are-valid.rst.inc + +Options +------- + +.. include:: /reference/constraints/_groups-option.rst.inc + +``message`` +~~~~~~~~~~~ + +**type**: ``string`` **default**: ``This value is not a valid CIDR notation.`` + +This message is shown if the string is not a valid CIDR notation. + +``netmaskMin`` +~~~~~~~~~~~~~~ + +**type**: ``integer`` **default**: ``0`` + +It's a constraint for the lowest value a valid netmask may have. + +``netmaskMax`` +~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``32`` for IPv4 or ``128`` for IPv6 + +It's a constraint for the biggest value a valid netmask may have. + +``netmaskRangeViolationMessage`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``The value of the netmask should be between {{ min }} and {{ max }}.`` + +This message is shown if the value of the CIDR's netmask is bigger than the +``netmaskMax`` value or lower than the ``netmaskMin`` value. + +You can use the following parameters in this message: + +=============== ============================================================== +Parameter Description +=============== ============================================================== +``{{ min }}`` The minimum value a CIDR netmask may have +``{{ max }}`` The maximum value a CIDR netmask may have +=============== ============================================================== + +.. include:: /reference/constraints/_payload-option.rst.inc + +``version`` +~~~~~~~~~~~ + +**type**: ``string`` **default**: ``all`` + +This determines exactly *how* the CIDR notation is validated and can take one +of these values: + +* ``4``: validates for CIDR notations that have an IPv4; +* ``6``: validates for CIDR notations that have an IPv6; +* ``all``: validates all CIDR formats. + +.. _`CIDR`: https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing diff --git a/reference/constraints/Collection.rst b/reference/constraints/Collection.rst index 2f3dfd52035..b6b75ce09b5 100644 --- a/reference/constraints/Collection.rst +++ b/reference/constraints/Collection.rst @@ -18,13 +18,6 @@ and that extra keys are not present. ========== =================================================================== Applies to :ref:`property or method ` -Options - `allowExtraFields`_ - - `allowMissingFields`_ - - `extraFieldsMessage`_ - - `fields`_ - - `groups`_ - - `missingFieldsMessage`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Collection` Validator :class:`Symfony\\Component\\Validator\\Constraints\\CollectionValidator` ========== =================================================================== @@ -289,6 +282,40 @@ However, if the ``personal_email`` field does not exist in the array, the ``NotBlank`` constraint will still be applied (since it is wrapped in ``Required``) and you will receive a constraint violation. +When you define groups in nested constraints they are automatically added to +the ``Collection`` constraint itself so it can be traversed for all nested +groups. Take the following example:: + + use Symfony\Component\Validator\Constraints as Assert; + + $constraint = new Assert\Collection([ + 'fields' => [ + 'name' => new Assert\NotBlank(['groups' => 'basic']), + 'email' => new Assert\NotBlank(['groups' => 'contact']), + ], + ]); + +This will result in the following configuration:: + + $constraint = new Assert\Collection([ + 'fields' => [ + 'name' => new Assert\Required([ + 'constraints' => new Assert\NotBlank(['groups' => 'basic']), + 'groups' => ['basic', 'strict'], + ]), + 'email' => new Assert\Required([ + "constraints" => new Assert\NotBlank(['groups' => 'contact']), + 'groups' => ['basic', 'strict'], + ]), + ], + 'groups' => ['basic', 'strict'], + ]); + +The default ``allowMissingFields`` option requires the fields in all groups. +So when validating in ``contact`` group, ``$name`` can be empty but the key is +still required. If this is not the intended behavior, use the ``Optional`` +constraint explicitly instead of ``Required``. + Options ------- diff --git a/reference/constraints/Compound.rst b/reference/constraints/Compound.rst index 6e0ab5db139..a3a2e335379 100644 --- a/reference/constraints/Compound.rst +++ b/reference/constraints/Compound.rst @@ -11,8 +11,6 @@ rules to use consistently across your application, by extending the constraint. ========== =================================================================== Applies to :ref:`class ` or :ref:`property or method ` -Options - `groups`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Compound` Validator :class:`Symfony\\Component\\Validator\\Constraints\\CompoundValidator` ========== =================================================================== @@ -21,29 +19,65 @@ Basic Usage ----------- Suppose that you have different places where a user password must be validated, -you can create your own named set or requirements to be reused consistently everywhere:: +you can create your own named set or requirements to be reused consistently everywhere: - // src/Validator/Constraints/PasswordRequirements.php - namespace App\Validator\Constraints; +.. configuration-block:: + + .. code-block:: php-annotations - use Symfony\Component\Validator\Constraints\Compound; - use Symfony\Component\Validator\Constraints as Assert; + // src/Validator/Constraints/PasswordRequirements.php + namespace App\Validator\Constraints; - /** - * @Annotation - */ - class PasswordRequirements extends Compound - { - protected function getConstraints(array $options): array + use Symfony\Component\Validator\Constraints\Compound; + use Symfony\Component\Validator\Constraints as Assert; + + /** + * @Annotation + */ + class PasswordRequirements extends Compound { - return [ - new Assert\NotBlank(), - new Assert\Type('string'), - new Assert\Length(['min' => 12]), - new Assert\NotCompromisedPassword(), - ]; + protected function getConstraints(array $options): array + { + return [ + new Assert\NotBlank(), + new Assert\Type('string'), + new Assert\Length(['min' => 12]), + new Assert\NotCompromisedPassword(), + ]; + } } - } + + .. code-block:: php-attributes + + // src/Validator/Constraints/PasswordRequirements.php + namespace App\Validator\Constraints; + + use Symfony\Component\Validator\Constraints\Compound; + use Symfony\Component\Validator\Constraints as Assert; + + #[\Attribute] + class PasswordRequirements extends Compound + { + protected function getConstraints(array $options): array + { + return [ + new Assert\NotBlank(), + new Assert\Type('string'), + new Assert\Length(['min' => 12]), + new Assert\NotCompromisedPassword(), + ]; + } + } + +Add ``@Annotation`` or ``#[\Attribute]`` to the constraint class if you want to +use it as an annotation/attribute in other classes. If the constraint has +configuration options, define them as public properties on the constraint class. + +.. versionadded:: 5.2 + + The ability to use PHP attributes to configure constraints was introduced in + Symfony 5.2. Prior to this, Doctrine Annotations were the only way to + annotate constraints. You can now use it anywhere you need it: @@ -51,25 +85,38 @@ You can now use it anywhere you need it: .. code-block:: php-annotations - // src/User/RegisterUser.php - namespace App\User; + // src/Entity/User.php + namespace App\Entity\User; - use App\Validator\Constraints as AcmeAssert; + use App\Validator\Constraints as Assert; - class RegisterUser + class User { /** - * @AcmeAssert\PasswordRequirements() + * @Assert\PasswordRequirements() */ - public $password; + public $plainPassword; + } + + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity\User; + + use App\Validator\Constraints as Assert; + + class User + { + #[Assert\PasswordRequirements] + public $plainPassword; } .. code-block:: yaml # config/validator/validation.yaml - App\User\RegisterUser: + App\Entity\User: properties: - password: + plainPassword: - App\Validator\Constraints\PasswordRequirements: ~ .. code-block:: xml @@ -80,8 +127,8 @@ You can now use it anywhere you need it: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> - - + + @@ -89,17 +136,17 @@ You can now use it anywhere you need it: .. code-block:: php - // src/User/RegisterUser.php - namespace App\User; + // src/Entity/User.php + namespace App\Entity\User; - use App\Validator\Constraints as AcmeAssert; + use App\Validator\Constraints as Assert; use Symfony\Component\Validator\Mapping\ClassMetadata; - class RegisterUser + class User { public static function loadValidatorMetadata(ClassMetadata $metadata) { - $metadata->addPropertyConstraint('password', new AcmeAssert\PasswordRequirements()); + $metadata->addPropertyConstraint('plainPassword', new Assert\PasswordRequirements()); } } diff --git a/reference/constraints/Count.rst b/reference/constraints/Count.rst index 4ce4691c6c9..d4e7e796acc 100644 --- a/reference/constraints/Count.rst +++ b/reference/constraints/Count.rst @@ -6,15 +6,6 @@ Countable) element count is *between* some minimum and maximum value. ========== =================================================================== Applies to :ref:`property or method ` -Options - `divisibleBy`_ - - `divisibleByMessage`_ - - `exactMessage`_ - - `groups`_ - - `max`_ - - `maxMessage`_ - - `min`_ - - `minMessage`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Count` Validator :class:`Symfony\\Component\\Validator\\Constraints\\CountValidator` ========== =================================================================== @@ -47,6 +38,24 @@ you might add the following: protected $emails = []; } + .. code-block:: php-attributes + + // src/Entity/Participant.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Participant + { + #[Assert\Count( + min: 1, + max: 5, + minMessage: 'You must specify at least one email', + maxMessage: 'You cannot specify more than {{ limit }} emails', + )] + protected $emails = []; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -103,8 +112,8 @@ you might add the following: Options ------- -divisibleBy -~~~~~~~~~~~ +``divisibleBy`` +~~~~~~~~~~~~~~~ **type**: ``integer`` **default**: null @@ -121,8 +130,8 @@ a certain number. are divisible by a certain number, use the :doc:`DivisibleBy ` constraint. -divisibleByMessage -~~~~~~~~~~~~~~~~~~ +``divisibleByMessage`` +~~~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``The number of elements in this collection should be a multiple of {{ compared_value }}.`` @@ -141,8 +150,8 @@ Parameter Description ``{{ compared_value }}`` The number configured in the ``divisibleBy`` option ======================== =================================================== -exactMessage -~~~~~~~~~~~~ +``exactMessage`` +~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This collection should contain exactly {{ limit }} elements.`` @@ -160,8 +169,8 @@ Parameter Description .. include:: /reference/constraints/_groups-option.rst.inc -max -~~~ +``max`` +~~~~~~~ **type**: ``integer`` @@ -170,8 +179,8 @@ collection elements count is **greater** than this max value. This option is required when the ``min`` option is not defined. -maxMessage -~~~~~~~~~~ +``maxMessage`` +~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This collection should contain {{ limit }} elements or less.`` @@ -187,8 +196,8 @@ Parameter Description ``{{ limit }}`` The upper limit =============== ============================================================== -min -~~~ +``min`` +~~~~~~~ **type**: ``integer`` @@ -197,8 +206,8 @@ collection elements count is **less** than this min value. This option is required when the ``max`` option is not defined. -minMessage -~~~~~~~~~~ +``minMessage`` +~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This collection should contain {{ limit }} elements or more.`` diff --git a/reference/constraints/Country.rst b/reference/constraints/Country.rst index 744de6dd0fb..60ed57b98d2 100644 --- a/reference/constraints/Country.rst +++ b/reference/constraints/Country.rst @@ -5,10 +5,6 @@ Validates that a value is a valid `ISO 3166-1 alpha-2`_ country code. ========== =================================================================== Applies to :ref:`property or method ` -Options - `alpha3`_ - - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Country` Validator :class:`Symfony\\Component\\Validator\\Constraints\\CountryValidator` ========== =================================================================== @@ -33,6 +29,19 @@ Basic Usage protected $country; } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class User + { + #[Assert\Country] + protected $country; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/CssColor.rst b/reference/constraints/CssColor.rst new file mode 100644 index 00000000000..dc216c7422c --- /dev/null +++ b/reference/constraints/CssColor.rst @@ -0,0 +1,310 @@ +CssColor +======== + +.. versionadded:: 5.4 + + The ``CssColor`` constraint was introduced in Symfony 5.4. + +Validates that a value is a valid CSS color. The underlying value is +casted to a string before being validated. + +========== =================================================================== +Applies to :ref:`property or method ` +Class :class:`Symfony\\Component\\Validator\\Constraints\\CssColor` +Validator :class:`Symfony\\Component\\Validator\\Constraints\\CssColorValidator` +========== =================================================================== + +Basic Usage +----------- + +In the following example, the ``$defaultColor`` value must be a CSS color +defined in any of the valid CSS formats (e.g. ``red``, ``#369``, +``hsla(0, 0%, 20%, 0.4)``); the ``$accentColor`` must be a CSS color defined in +hexadecimal format; and ``$currentColor`` must be a CSS color defined as any of +the named CSS colors: + +.. configuration-block:: + + .. code-block:: php-annotations + + // src/Entity/Bulb.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Bulb + { + /** + * @Assert\CssColor + */ + protected $defaultColor; + + /** + * @Assert\CssColor( + * formats = Assert\CssColor::HEX_LONG, + * message = "The accent color must be a 6-character hexadecimal color." + * ) + */ + protected $accentColor; + + /** + * @Assert\CssColor( + * formats = { + * Assert\CssColor::BASIC_NAMED_COLORS, + * Assert\CssColor::EXTENDED_NAMED_COLORS + * }, + * message = "The color '{{ value }}' is not a valid CSS color name." + * ) + */ + protected $currentColor; + } + + .. code-block:: php-attributes + + // src/Entity/Bulb.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Bulb + { + #[Assert\CssColor] + protected $defaultColor; + + #[Assert\CssColor( + formats: Assert\CssColor::HEX_LONG, + message: 'The accent color must be a 6-character hexadecimal color.', + )] + protected $accentColor; + + #[Assert\CssColor( + formats: [Assert\CssColor::BASIC_NAMED_COLORS, Assert\CssColor::EXTENDED_NAMED_COLORS], + message: 'The color '{{ value }}' is not a valid CSS color name.', + )] + protected $currentColor; + } + + .. code-block:: yaml + + # config/validator/validation.yaml + App\Entity\Bulb: + properties: + defaultColor: + - CssColor: ~ + accentColor: + - CssColor: + formats: !php/const Symfony\Component\Validator\Constraints\CssColor::HEX_LONG + message: The accent color must be a 6-character hexadecimal color. + currentColor: + - CssColor: + formats: + - !php/const Symfony\Component\Validator\Constraints\CssColor::BASIC_NAMED_COLORS + - !php/const Symfony\Component\Validator\Constraints\CssColor::EXTENDED_NAMED_COLORS + message: The color "{{ value }}" is not a valid CSS color name. + + .. code-block:: xml + + + + + + + + + + + + + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/Bulb.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; + + class Bulb + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('defaultColor', new Assert\CssColor()); + + $metadata->addPropertyConstraint('accentColor', new Assert\CssColor([ + 'formats' => Assert\CssColor::HEX_LONG, + 'message' => 'The accent color must be a 6-character hexadecimal color.', + ])); + + $metadata->addPropertyConstraint('currentColor', new Assert\CssColor([ + 'formats' => [Assert\CssColor::BASIC_NAMED_COLORS, Assert\CssColor::EXTENDED_NAMED_COLORS], + 'message' => 'The color "{{ value }}" is not a valid CSS color name.', + ])); + } + } + +.. include:: /reference/constraints/_empty-values-are-valid.rst.inc + +Options +------- + +.. include:: /reference/constraints/_groups-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This value is not a valid CSS color.`` + +This message is shown if the underlying data is not a valid CSS color. + +You can use the following parameters in this message: + +=============== ============================================================== +Parameter Description +=============== ============================================================== +``{{ value }}`` The current (invalid) value +=============== ============================================================== + +formats +~~~~~~~ + +**type**: ``string`` | ``array`` + +By default, this constraint considers valid any of the many ways of defining +CSS colors. Use the ``formats`` option to restrict which CSS formats are allowed. +These are the available formats (which are also defined as PHP constants; e.g. +``Assert\CssColor::HEX_LONG``): + +* ``hex_long`` +* ``hex_long_with_alpha`` +* ``hex_short`` +* ``hex_short_with_alpha`` +* ``basic_named_colors`` +* ``extended_named_colors`` +* ``system_colors`` +* ``keywords`` +* ``rgb`` +* ``rgba`` +* ``hsl`` +* ``hsla`` + +hex_long +........ + +A regular expression. Allows all values which represent a CSS color of 6 +characters (in addition of the leading ``#``) and contained in ranges: ``0`` to +``9`` and ``A`` to ``F`` (case insensitive). + +Examples: ``#2F2F2F``, ``#2f2f2f`` + +hex_long_with_alpha +................... + +A regular expression. Allows all values which represent a CSS color with alpha +part of 8 characters (in addition of the leading ``#``) and contained in +ranges: ``0`` to ``9`` and ``A`` to ``F`` (case insensitive). + +Examples: ``#2F2F2F80``, ``#2f2f2f80`` + +hex_short +......... + +A regular expression. Allows all values which represent a CSS color of strictly +3 characters (in addition of the leading ``#``) and contained in ranges: ``0`` +to ``9`` and ``A`` to ``F`` (case insensitive). + +Examples: ``#CCC``, ``#ccc`` + +hex_short_with_alpha +.................... + +A regular expression. Allows all values which represent a CSS color with alpha +part of strictly 4 characters (in addition of the leading ``#``) and contained +in ranges: ``0`` to ``9`` and ``A`` to ``F`` (case insensitive). + +Examples: ``#CCC8``, ``#ccc8`` + +basic_named_colors +.................. + +Any of the valid color names defined in the `W3C list of basic named colors`_ +(case insensitive). + +Examples: ``black``, ``red``, ``green`` + +extended_named_colors +..................... + +Any of the valid color names defined in the `W3C list of extended named colors`_ +(case insensitive). + +Examples: ``aqua``, ``brown``, ``chocolate`` + +system_colors +............. + +Any of the valid color names defined in the `CSS WG list of system colors`_ +(case insensitive). + +Examples: ``LinkText``, ``VisitedText``, ``ActiveText``, ``ButtonFace``, ``ButtonText`` + +keywords +........ + +Any of the valid keywords defined in the `CSS WG list of keywords`_ (case insensitive). + +Examples: ``transparent``, ``currentColor`` + +rgb +... + +A regular expression. Allows all values which represent a CSS color following +the RGB notation, with or without space between values. + +Examples: ``rgb(255, 255, 255)``, ``rgb(255,255,255)`` + +rgba +.... + +A regular expression. Allows all values which represent a CSS color with alpha +part following the RGB notation, with or without space between values. + +Examples: ``rgba(255, 255, 255, 0.3)``, ``rgba(255,255,255,0.3)`` + +hsl +... + +A regular expression. Allows all values which represent a CSS color following +the HSL notation, with or without space between values. + +Examples: ``hsl(0, 0%, 20%)``, ``hsl(0,0%,20%)`` + +hsla +.... + +A regular expression. Allows all values which represent a CSS color with alpha +part following the HSLA notation, with or without space between values. + +Examples: ``hsla(0, 0%, 20%, 0.4)``, ``hsla(0,0%,20%,0.4)`` + +.. include:: /reference/constraints/_payload-option.rst.inc + +.. _`W3C list of basic named colors`: https://www.w3.org/wiki/CSS/Properties/color/keywords#Basic_Colors +.. _`W3C list of extended named colors`: https://www.w3.org/wiki/CSS/Properties/color/keywords#Extended_colors +.. _`CSS WG list of system colors`: https://drafts.csswg.org/css-color/#css-system-colors +.. _`CSS WG list of keywords`: https://drafts.csswg.org/css-color/#transparent-color diff --git a/reference/constraints/Currency.rst b/reference/constraints/Currency.rst index 651af1b1a92..d1cd5c4d17d 100644 --- a/reference/constraints/Currency.rst +++ b/reference/constraints/Currency.rst @@ -5,9 +5,6 @@ Validates that a value is a valid `3-letter ISO 4217`_ currency name. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Currency` Validator :class:`Symfony\\Component\\Validator\\Constraints\\CurrencyValidator` ========== =================================================================== @@ -35,6 +32,19 @@ a valid currency, you could do the following: protected $currency; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\Currency] + protected $currency; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Date.rst b/reference/constraints/Date.rst index 4b1e99c3ed1..999c06f939c 100644 --- a/reference/constraints/Date.rst +++ b/reference/constraints/Date.rst @@ -6,9 +6,6 @@ be cast into a string) that follows a valid ``YYYY-MM-DD`` format. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Date` Validator :class:`Symfony\\Component\\Validator\\Constraints\\DateValidator` ========== =================================================================== @@ -34,6 +31,19 @@ Basic Usage protected $birthday; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Date] + protected $birthday; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/DateTime.rst b/reference/constraints/DateTime.rst index 582f93aeac8..4802e06392b 100644 --- a/reference/constraints/DateTime.rst +++ b/reference/constraints/DateTime.rst @@ -6,10 +6,6 @@ that can be cast into a string) that follows a specific format. ========== =================================================================== Applies to :ref:`property or method ` -Options - `format`_ - - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\DateTime` Validator :class:`Symfony\\Component\\Validator\\Constraints\\DateTimeValidator` ========== =================================================================== @@ -35,6 +31,22 @@ Basic Usage protected $createdAt; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + /** + * @var string A "Y-m-d H:i:s" formatted value + */ + #[Assert\DateTime] + protected $createdAt; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -84,8 +96,8 @@ Basic Usage Options ------- -format -~~~~~~ +``format`` +~~~~~~~~~~ **type**: ``string`` **default**: ``Y-m-d H:i:s`` diff --git a/reference/constraints/DivisibleBy.rst b/reference/constraints/DivisibleBy.rst index 4503959aa57..2c1fdb4fe87 100644 --- a/reference/constraints/DivisibleBy.rst +++ b/reference/constraints/DivisibleBy.rst @@ -11,11 +11,6 @@ Validates that a value is divisible by another value, defined in the options. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ - - `propertyPath`_ - - `value`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\DivisibleBy` Validator :class:`Symfony\\Component\\Validator\\Constraints\\DivisibleByValidator` ========== =================================================================== @@ -39,7 +34,6 @@ The following constraints ensure that: class Item { - /** * @Assert\DivisibleBy(0.25) */ @@ -53,6 +47,24 @@ The following constraints ensure that: protected $quantity; } + .. code-block:: php-attributes + + // src/Entity/Item.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Item + { + #[Assert\DivisibleBy(0.25)] + protected $weight; + + #[Assert\DivisibleBy( + value: 5, + )] + protected $quantity; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -111,8 +123,8 @@ Options .. include:: /reference/constraints/_groups-option.rst.inc -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This value should be a multiple of {{ compared_value }}.`` diff --git a/reference/constraints/Email.rst b/reference/constraints/Email.rst index 468051004a0..ddf462ef6b4 100644 --- a/reference/constraints/Email.rst +++ b/reference/constraints/Email.rst @@ -6,11 +6,6 @@ cast to a string before being validated. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `mode`_ - - `normalizer`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Email` Validator :class:`Symfony\\Component\\Validator\\Constraints\\EmailValidator` ========== =================================================================== @@ -37,6 +32,21 @@ Basic Usage protected $email; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Email( + message: 'The email {{ value }} is not a valid email.', + )] + protected $email; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -88,8 +98,8 @@ Options .. include:: /reference/constraints/_groups-option.rst.inc -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This value is not a valid email address.`` @@ -108,34 +118,26 @@ Parameter Description The ``{{ label }}`` parameter was introduced in Symfony 5.2. -mode -~~~~ - -**type**: ``string`` **default**: ``loose`` - -This option is optional and defines the pattern the email address is validated against. -Valid values are: - -* ``loose`` -* ``strict`` -* ``html5`` - -loose -..... +.. _reference-constraint-email-mode: -A simple regular expression. Allows all values with an "@" symbol in, and a "." -in the second host part of the email address. +``mode`` +~~~~~~~~ -strict -...... +**type**: ``string`` **default**: (see below) -Uses the `egulias/email-validator`_ library to perform an RFC compliant -validation. You will need to install that library to use this mode. +This option defines the pattern used to validate the email address. Valid values are: -html5 -..... +* ``loose`` uses a simple regular expression (just checks that at least one ``@`` + character is present, etc.). This validation is too simple and it's recommended + to use one of the other modes instead; +* ``html5`` uses the same regular expression as the `HTML5 email input element`_, + making the backend validation consistent with the one provided by browsers; +* ``strict`` uses the `egulias/email-validator`_ library (which you must + install separately) for validation according to `RFC 5322`_. -This matches the pattern used for the `HTML5 email input element`_. +The default value used by this option is set in the +:ref:`framework.validation.email_validation_mode ` +configuration option. .. include:: /reference/constraints/_normalizer-option.rst.inc @@ -143,3 +145,4 @@ This matches the pattern used for the `HTML5 email input element`_. .. _egulias/email-validator: https://packagist.org/packages/egulias/email-validator .. _HTML5 email input element: https://www.w3.org/TR/html5/sec-forms.html#valid-e-mail-address +.. _RFC 5322: https://tools.ietf.org/html/rfc5322 diff --git a/reference/constraints/EqualTo.rst b/reference/constraints/EqualTo.rst index 153d13a3098..06578c27c19 100644 --- a/reference/constraints/EqualTo.rst +++ b/reference/constraints/EqualTo.rst @@ -13,11 +13,6 @@ To force that a value is *not* equal, see :doc:`/reference/constraints/NotEqualT ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ - - `propertyPath`_ - - `value`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\EqualTo` Validator :class:`Symfony\\Component\\Validator\\Constraints\\EqualToValidator` ========== =================================================================== @@ -52,6 +47,24 @@ and that the ``age`` is ``20``, you could do the following: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\EqualTo('Mary')] + protected $firstName; + + #[Assert\EqualTo( + value: 20, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Expression.rst b/reference/constraints/Expression.rst index 2ed816f3a03..65a38efb415 100644 --- a/reference/constraints/Expression.rst +++ b/reference/constraints/Expression.rst @@ -9,11 +9,6 @@ gives you similar flexibility. ========== =================================================================== Applies to :ref:`class ` or :ref:`property/method ` -Options - :ref:`expression ` - - `groups`_ - - `message`_ - - `payload`_ - - `values`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Expression` Validator :class:`Symfony\\Component\\Validator\\Constraints\\ExpressionValidator` ========== =================================================================== @@ -78,6 +73,22 @@ One way to accomplish this is with the Expression constraint: // ... } + .. code-block:: php-attributes + + // src/Model/BlogPost.php + namespace App\Model; + + use Symfony\Component\Validator\Constraints as Assert; + + #[Assert\Expression( + "this.getCategory() in ['php', 'symfony'] or !this.isTechnicalPost()", + message: 'If this is a tech post, the category should be either php or symfony!', + )] + class BlogPost + { + // ... + } + .. code-block:: yaml # config/validator/validation.yaml @@ -163,6 +174,26 @@ more about the expression language syntax, see // ... } + .. code-block:: php-attributes + + // src/Model/BlogPost.php + namespace App\Model; + + use Symfony\Component\Validator\Constraints as Assert; + + class BlogPost + { + // ... + + #[Assert\Expression( + "this.getCategory() in ['php', 'symfony'] or value == false", + message: 'If this is a tech post, the category should be either php or symfony!', + )] + private $isTechnicalPost; + + // ... + } + .. code-block:: yaml # config/validator/validation.yaml @@ -269,8 +300,8 @@ Parameter Description .. include:: /reference/constraints/_payload-option.rst.inc -values -~~~~~~ +``values`` +~~~~~~~~~~ **type**: ``array`` **default**: ``[]`` @@ -299,6 +330,24 @@ type (numeric, boolean, strings, null, etc.) // ... } + .. code-block:: php-attributes + + // src/Model/Analysis.php + namespace App\Model; + + use Symfony\Component\Validator\Constraints as Assert; + + class Analysis + { + #[Assert\Expression( + 'value + error_margin < threshold', + values: ['error_margin' => 0.25, 'threshold' => 1.5], + )] + private $metric; + + // ... + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/ExpressionLanguageSyntax.rst b/reference/constraints/ExpressionLanguageSyntax.rst index 2ca0355dfaf..6dfb7cbc420 100644 --- a/reference/constraints/ExpressionLanguageSyntax.rst +++ b/reference/constraints/ExpressionLanguageSyntax.rst @@ -10,10 +10,6 @@ expression. ========== =================================================================== Applies to :ref:`property or method ` -Options - `allowedVariables`_ - - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageSyntax` Validator :class:`Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageSyntaxValidator` ========== =================================================================== @@ -40,18 +36,36 @@ The following constraints ensure that: class Order { /** - * @Assert\ExpressionLanguageSyntax() + * @Assert\ExpressionLanguageSyntax */ protected $promotion; /** * @Assert\ExpressionLanguageSyntax( - * allowedVariables = ['user', 'shipping_centers'] + * allowedVariables={"user", "shipping_centers"} * ) */ protected $shippingOptions; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\ExpressionLanguageSyntax] + protected $promotion; + + #[Assert\ExpressionLanguageSyntax( + allowedVariables: ['user', 'shipping_centers'], + )] + protected $shippingOptions; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -77,7 +91,10 @@ The following constraints ensure that: - + diff --git a/reference/constraints/File.rst b/reference/constraints/File.rst index f1a27ac8f20..1eaed6075d0 100644 --- a/reference/constraints/File.rst +++ b/reference/constraints/File.rst @@ -11,31 +11,13 @@ Validates that a value is a valid "file", which can be one of the following: This constraint is commonly used in forms with the :doc:`FileType ` form field. -.. tip:: +.. seealso:: If the file you're validating is an image, try the :doc:`Image ` constraint. ========== =================================================================== Applies to :ref:`property or method ` -Options - `binaryFormat`_ - - `disallowEmptyMessage`_ - - `groups`_ - - `maxSize`_ - - `maxSizeMessage`_ - - `mimeTypes`_ - - `mimeTypesMessage`_ - - `notFoundMessage`_ - - `notReadableMessage`_ - - `payload`_ - - `uploadCantWriteErrorMessage`_ - - `uploadErrorMessage`_ - - `uploadExtensionErrorMessage`_ - - `uploadFormSizeErrorMessage`_ - - `uploadIniSizeErrorMessage`_ - - `uploadNoFileErrorMessage`_ - - `uploadNoTmpDirErrorMessage`_ - - `uploadPartialErrorMessage`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\File` Validator :class:`Symfony\\Component\\Validator\\Constraints\\FileValidator` ========== =================================================================== @@ -93,6 +75,23 @@ below a certain file size and a valid PDF, add the following: protected $bioFile; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\File( + maxSize: '1024k', + mimeTypes: ['application/pdf', 'application/x-pdf'], + mimeTypesMessage: 'Please upload a valid PDF', + )] + protected $bioFile; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -158,8 +157,8 @@ have been specified. Options ------- -binaryFormat -~~~~~~~~~~~~ +``binaryFormat`` +~~~~~~~~~~~~~~~~ **type**: ``boolean`` **default**: ``null`` @@ -171,8 +170,8 @@ the value defined in the ``maxSize`` option. For more information about the difference between binary and SI prefixes, see `Wikipedia: Binary prefix`_. -disallowEmptyMessage -~~~~~~~~~~~~~~~~~~~~ +``disallowEmptyMessage`` +~~~~~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``An empty file is not allowed.`` @@ -190,8 +189,8 @@ Parameter Description .. include:: /reference/constraints/_groups-option.rst.inc -maxSize -~~~~~~~ +``maxSize`` +~~~~~~~~~~~ **type**: ``mixed`` @@ -212,8 +211,8 @@ Suffix Unit Name Value Example For more information about the difference between binary and SI prefixes, see `Wikipedia: Binary prefix`_. -maxSizeMessage -~~~~~~~~~~~~~~ +``maxSizeMessage`` +~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}.`` @@ -231,8 +230,8 @@ Parameter Description ``{{ suffix }}`` Suffix for the used file size unit (see above) ================ ============================================================= -mimeTypes -~~~~~~~~~ +``mimeTypes`` +~~~~~~~~~~~~~ **type**: ``array`` or ``string`` @@ -252,8 +251,8 @@ You can find a list of existing mime types on the `IANA website`_. (i.e. the form type is not defined explicitly in the ``->add()`` method of the form builder) and when the field doesn't define its own ``accept`` value. -mimeTypesMessage -~~~~~~~~~~~~~~~~ +``mimeTypesMessage`` +~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}.`` @@ -271,8 +270,8 @@ Parameter Description ``{{ types }}`` The list of allowed MIME types =============== ============================================================== -notFoundMessage -~~~~~~~~~~~~~~~ +``notFoundMessage`` +~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``The file could not be found.`` @@ -288,8 +287,8 @@ Parameter Description ``{{ file }}`` Absolute file path =============== ============================================================== -notReadableMessage -~~~~~~~~~~~~~~~~~~ +``notReadableMessage`` +~~~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``The file is not readable.`` @@ -306,8 +305,8 @@ Parameter Description .. include:: /reference/constraints/_payload-option.rst.inc -uploadCantWriteErrorMessage -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``uploadCantWriteErrorMessage`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``Cannot write temporary file to disk.`` @@ -316,8 +315,8 @@ temporary folder. This message has no parameters. -uploadErrorMessage -~~~~~~~~~~~~~~~~~~ +``uploadErrorMessage`` +~~~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``The file could not be uploaded.`` @@ -326,8 +325,8 @@ for some unknown reason. This message has no parameters. -uploadExtensionErrorMessage -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``uploadExtensionErrorMessage`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``A PHP extension caused the upload to fail.`` @@ -336,8 +335,8 @@ fail. This message has no parameters. -uploadFormSizeErrorMessage -~~~~~~~~~~~~~~~~~~~~~~~~~~ +``uploadFormSizeErrorMessage`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``The file is too large.`` @@ -346,8 +345,8 @@ by the HTML file input field. This message has no parameters. -uploadIniSizeErrorMessage -~~~~~~~~~~~~~~~~~~~~~~~~~ +``uploadIniSizeErrorMessage`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}.`` @@ -363,8 +362,8 @@ Parameter Description ``{{ suffix }}`` Suffix for the used file size unit (see above) ================ ============================================================= -uploadNoFileErrorMessage -~~~~~~~~~~~~~~~~~~~~~~~~ +``uploadNoFileErrorMessage`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``No file was uploaded.`` @@ -372,8 +371,8 @@ The message that is displayed if no file was uploaded. This message has no parameters. -uploadNoTmpDirErrorMessage -~~~~~~~~~~~~~~~~~~~~~~~~~~ +``uploadNoTmpDirErrorMessage`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``No temporary folder was configured in php.ini.`` @@ -382,8 +381,8 @@ missing. This message has no parameters. -uploadPartialErrorMessage -~~~~~~~~~~~~~~~~~~~~~~~~~ +``uploadPartialErrorMessage`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``The file was only partially uploaded.`` diff --git a/reference/constraints/GreaterThan.rst b/reference/constraints/GreaterThan.rst index d27017fdbe5..22331edd957 100644 --- a/reference/constraints/GreaterThan.rst +++ b/reference/constraints/GreaterThan.rst @@ -8,11 +8,6 @@ than another value, see :doc:`/reference/constraints/LessThan`. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ - - `propertyPath`_ - - `value`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\GreaterThan` Validator :class:`Symfony\\Component\\Validator\\Constraints\\GreaterThanValidator` ========== =================================================================== @@ -49,6 +44,24 @@ The following constraints ensure that: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\GreaterThan(5)] + protected $siblings; + + #[Assert\GreaterThan( + value: 18, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -126,6 +139,19 @@ that a date must at least be the next day: protected $deliveryDate; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\GreaterThan('today')] + protected $deliveryDate; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -185,6 +211,19 @@ dates. If you want to fix the timezone, append it to the date string: protected $deliveryDate; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\GreaterThan('today UTC')] + protected $deliveryDate; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -245,6 +284,19 @@ current time: protected $deliveryDate; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\GreaterThan('+5 hours')] + protected $deliveryDate; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/GreaterThanOrEqual.rst b/reference/constraints/GreaterThanOrEqual.rst index 8a054e6bbb9..79578c5a5f7 100644 --- a/reference/constraints/GreaterThanOrEqual.rst +++ b/reference/constraints/GreaterThanOrEqual.rst @@ -7,11 +7,6 @@ the options. To force that a value is greater than another value, see ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ - - `propertyPath`_ - - `value`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\GreaterThanOrEqual` Validator :class:`Symfony\\Component\\Validator\\Constraints\\GreaterThanOrEqualValidator` ========== =================================================================== @@ -48,6 +43,24 @@ The following constraints ensure that: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\GreaterThanOrEqual(5)] + protected $siblings; + + #[Assert\GreaterThanOrEqual( + value: 18, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -125,6 +138,19 @@ that a date must at least be the current day: protected $deliveryDate; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\GreaterThanOrEqual('today')] + protected $deliveryDate; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -184,6 +210,19 @@ dates. If you want to fix the timezone, append it to the date string: protected $deliveryDate; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\GreaterThanOrEqual('today UTC')] + protected $deliveryDate; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -244,6 +283,19 @@ current time: protected $deliveryDate; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\GreaterThanOrEqual('+5 hours')] + protected $deliveryDate; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Hostname.rst b/reference/constraints/Hostname.rst index 9e67fb3c8fc..56182fafc9a 100644 --- a/reference/constraints/Hostname.rst +++ b/reference/constraints/Hostname.rst @@ -11,10 +11,6 @@ function). ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ - - `requireTld`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Hostname` Validator :class:`Symfony\\Component\\Validator\\Constraints\\HostnameValidator` ========== =================================================================== @@ -42,6 +38,19 @@ will contain a host name. protected $name; } + .. code-block:: php-attributes + + // src/Entity/ServerSettings.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class ServerSettings + { + #[Assert\Hostname(message: 'The server name must be a valid hostname.')] + protected $name; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -122,7 +131,7 @@ Parameter Description ``requireTld`` ~~~~~~~~~~~~~~ -**type**: ``bool`` **default**: ``true`` +**type**: ``boolean`` **default**: ``true`` By default, hostnames are considered valid only when they are fully qualified and include their TLDs (top-level domain names). For instance, ``example.com`` diff --git a/reference/constraints/Iban.rst b/reference/constraints/Iban.rst index 709270f7b12..7c8ee5ab060 100644 --- a/reference/constraints/Iban.rst +++ b/reference/constraints/Iban.rst @@ -8,9 +8,6 @@ borders with a reduced risk of propagating transcription errors. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Iban` Validator :class:`Symfony\\Component\\Validator\\Constraints\\IbanValidator` ========== =================================================================== @@ -40,6 +37,21 @@ will contain an International Bank Account Number. protected $bankAccountNumber; } + .. code-block:: php-attributes + + // src/Entity/Transaction.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Transaction + { + #[Assert\Iban( + message: 'This is not a valid International Bank Account Number (IBAN).', + )] + protected $bankAccountNumber; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/IdenticalTo.rst b/reference/constraints/IdenticalTo.rst index 10f1fb52342..f5b2644e3a9 100644 --- a/reference/constraints/IdenticalTo.rst +++ b/reference/constraints/IdenticalTo.rst @@ -13,11 +13,6 @@ To force that a value is *not* identical, see ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ - - `propertyPath`_ - - `value`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\IdenticalTo` Validator :class:`Symfony\\Component\\Validator\\Constraints\\IdenticalToValidator` ========== =================================================================== @@ -54,6 +49,24 @@ The following constraints ensure that: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\IdenticalTo('Mary')] + protected $firstName; + + #[Assert\IdenticalTo( + value: 20, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Image.rst b/reference/constraints/Image.rst index e8b492bf4ae..408341427db 100644 --- a/reference/constraints/Image.rst +++ b/reference/constraints/Image.rst @@ -13,35 +13,6 @@ of the documentation on this constraint. ========== =================================================================== Applies to :ref:`property or method ` -Options - `allowLandscape`_ - - `allowLandscapeMessage`_ - - `allowPortrait`_ - - `allowPortraitMessage`_ - - `allowSquare`_ - - `allowSquareMessage`_ - - `corruptedMessage`_ - - `detectCorrupted`_ - - `groups`_ - - `maxHeight`_ - - `maxHeightMessage`_ - - `maxPixels`_ - - `maxPixelsMessage`_ - - `maxRatio`_ - - `maxRatioMessage`_ - - `maxWidth`_ - - `maxWidthMessage`_ - - `mimeTypes`_ - - `mimeTypesMessage`_ - - `minHeight`_ - - `minHeightMessage`_ - - `minPixels`_ - - `minPixelsMessage`_ - - `minRatio`_ - - `minRatioMessage`_ - - `minWidth`_ - - `minWidthMessage`_ - - `sizeNotDetectedMessage`_ - - See :doc:`File ` for inherited options Class :class:`Symfony\\Component\\Validator\\Constraints\\Image` Validator :class:`Symfony\\Component\\Validator\\Constraints\\ImageValidator` ========== =================================================================== @@ -100,6 +71,24 @@ that it is between a certain size, add the following: protected $headshot; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Image( + minWidth: 200, + maxWidth: 400, + minHeight: 200, + maxHeight: 400, + )] + protected $headshot; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -180,6 +169,22 @@ following code: protected $headshot; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Image( + allowLandscape: false, + allowPortrait: false, + )] + protected $headshot; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -230,15 +235,15 @@ This constraint shares all of its options with the :doc:`File ` -Options - `groups`_ - - `message`_ - - `normalizer`_ - - `payload`_ - - `version`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Ip` Validator :class:`Symfony\\Component\\Validator\\Constraints\\IpValidator` ========== =================================================================== @@ -36,6 +31,19 @@ Basic Usage protected $ipAddress; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Ip] + protected $ipAddress; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -82,8 +90,8 @@ Options .. include:: /reference/constraints/_groups-option.rst.inc -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This is not a valid IP address.`` @@ -106,8 +114,8 @@ Parameter Description .. include:: /reference/constraints/_payload-option.rst.inc -version -~~~~~~~ +``version`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``4`` diff --git a/reference/constraints/IsFalse.rst b/reference/constraints/IsFalse.rst index 17881aa9a75..860004691eb 100644 --- a/reference/constraints/IsFalse.rst +++ b/reference/constraints/IsFalse.rst @@ -3,15 +3,12 @@ IsFalse Validates that a value is ``false``. Specifically, this checks to see if the value is exactly ``false``, exactly the integer ``0``, or exactly the -string "``0``". +string ``'0'``. Also see :doc:`IsTrue `. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\IsFalse` Validator :class:`Symfony\\Component\\Validator\\Constraints\\IsFalseValidator` ========== =================================================================== @@ -58,6 +55,24 @@ method returns **false**: } } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\IsFalse( + message: "You've entered an invalid state." + )] + public function isStateInvalid() + { + // ... + } + } + .. code-block:: yaml # config/validator/validation.yaml @@ -97,16 +112,18 @@ method returns **false**: public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addGetterConstraint('stateInvalid', new Assert\IsFalse([ - 'message' => 'You've entered an invalid state.', + 'message' => "You've entered an invalid state.", ])); } - } - public function isStateInvalid() - { - // ... + public function isStateInvalid() + { + // ... + } } +.. include:: /reference/constraints/_null-values-are-valid.rst.inc + Options ------- diff --git a/reference/constraints/IsNull.rst b/reference/constraints/IsNull.rst index 252c23d934b..9bf4273c111 100644 --- a/reference/constraints/IsNull.rst +++ b/reference/constraints/IsNull.rst @@ -9,9 +9,6 @@ Also see :doc:`NotNull `. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\IsNull` Validator :class:`Symfony\\Component\\Validator\\Constraints\\IsNullValidator` ========== =================================================================== @@ -39,6 +36,19 @@ of an ``Author`` class exactly equal to ``null``, you could do the following: protected $firstName; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\IsNull] + protected $firstName; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/IsTrue.rst b/reference/constraints/IsTrue.rst index 2698ad233e9..91076f4e1e4 100644 --- a/reference/constraints/IsTrue.rst +++ b/reference/constraints/IsTrue.rst @@ -2,15 +2,12 @@ IsTrue ====== Validates that a value is ``true``. Specifically, this checks if the value is -exactly ``true``, exactly the integer ``1``, or exactly the string ``"1"``. +exactly ``true``, exactly the integer ``1``, or exactly the string ``'1'``. Also see :doc:`IsFalse `. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\IsTrue` Validator :class:`Symfony\\Component\\Validator\\Constraints\\IsTrueValidator` ========== =================================================================== @@ -60,6 +57,24 @@ Then you can validate this method with ``IsTrue`` as follows: } } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + protected $token; + + #[Assert\IsTrue(message: 'The token is invalid.')] + public function isTokenValid() + { + return $this->token == $this->generateToken(); + } + } + .. code-block:: yaml # config/validator/validation.yaml @@ -111,6 +126,8 @@ Then you can validate this method with ``IsTrue`` as follows: If the ``isTokenValid()`` returns false, the validation will fail. +.. include:: /reference/constraints/_null-values-are-valid.rst.inc + Options ------- diff --git a/reference/constraints/Isbn.rst b/reference/constraints/Isbn.rst index e30d4e96040..d9ce6d46bbc 100644 --- a/reference/constraints/Isbn.rst +++ b/reference/constraints/Isbn.rst @@ -6,13 +6,6 @@ is either a valid ISBN-10 or a valid ISBN-13. ========== =================================================================== Applies to :ref:`property or method ` -Options - `bothIsbnMessage`_ - - `groups`_ - - `isbn10Message`_ - - `isbn13Message`_ - - `message`_ - - `payload`_ - - `type`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Isbn` Validator :class:`Symfony\\Component\\Validator\\Constraints\\IsbnValidator` ========== =================================================================== @@ -37,12 +30,28 @@ on an object that will contain an ISBN. /** * @Assert\Isbn( * type = "isbn10", - * message = "This value is not valid." + * message = "This value is not valid." * ) */ protected $isbn; } + .. code-block:: php-attributes + + // src/Entity/Book.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Book + { + #[Assert\Isbn( + type: Assert\Isbn::ISBN_10, + message: 'This value is not valid.', + )] + protected $isbn; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -51,7 +60,7 @@ on an object that will contain an ISBN. isbn: - Isbn: type: isbn10 - message: This value is not valid. + message: This value is not valid. .. code-block:: xml @@ -65,7 +74,7 @@ on an object that will contain an ISBN. - + @@ -84,7 +93,7 @@ on an object that will contain an ISBN. public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('isbn', new Assert\Isbn([ - 'type' => 'isbn10', + 'type' => Assert\Isbn::ISBN_10, 'message' => 'This value is not valid.', ])); } @@ -95,8 +104,8 @@ on an object that will contain an ISBN. Available Options ----------------- -bothIsbnMessage -~~~~~~~~~~~~~~~ +``bothIsbnMessage`` +~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This value is neither a valid ISBN-10 nor a valid ISBN-13.`` @@ -118,8 +127,8 @@ Parameter Description .. include:: /reference/constraints/_groups-option.rst.inc -isbn10Message -~~~~~~~~~~~~~ +``isbn10Message`` +~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This value is not a valid ISBN-10.`` @@ -139,8 +148,8 @@ Parameter Description The ``{{ label }}`` parameter was introduced in Symfony 5.2. -isbn13Message -~~~~~~~~~~~~~ +``isbn13Message`` +~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This value is not a valid ISBN-13.`` @@ -160,8 +169,8 @@ Parameter Description The ``{{ label }}`` parameter was introduced in Symfony 5.2. -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``null`` @@ -183,8 +192,8 @@ Parameter Description .. include:: /reference/constraints/_payload-option.rst.inc -type -~~~~ +``type`` +~~~~~~~~ **type**: ``string`` **default**: ``null`` diff --git a/reference/constraints/Isin.rst b/reference/constraints/Isin.rst index c646f33a53a..d547798f6d6 100644 --- a/reference/constraints/Isin.rst +++ b/reference/constraints/Isin.rst @@ -6,9 +6,6 @@ Validates that a value is a valid ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Isin` Validator :class:`Symfony\\Component\\Validator\\Constraints\\IsinValidator` ========== =================================================================== @@ -33,6 +30,19 @@ Basic Usage protected $isin; } + .. code-block:: php-attributes + + // src/Entity/UnitAccount.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class UnitAccount + { + #[Assert\Isin] + protected $isin; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Issn.rst b/reference/constraints/Issn.rst index 6cc5734aaa2..5d2013988c8 100644 --- a/reference/constraints/Issn.rst +++ b/reference/constraints/Issn.rst @@ -6,11 +6,6 @@ Validates that a value is a valid ========== =================================================================== Applies to :ref:`property or method ` -Options - `caseSensitive`_ - - `groups`_ - - `message`_ - - `payload`_ - - `requireHyphen`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Issn` Validator :class:`Symfony\\Component\\Validator\\Constraints\\IssnValidator` ========== =================================================================== @@ -35,6 +30,19 @@ Basic Usage protected $issn; } + .. code-block:: php-attributes + + // src/Entity/Journal.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Journal + { + #[Assert\Issn] + protected $issn; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -79,8 +87,8 @@ Basic Usage Options ------- -caseSensitive -~~~~~~~~~~~~~ +``caseSensitive`` +~~~~~~~~~~~~~~~~~ **type**: ``boolean`` default: ``false`` @@ -89,8 +97,8 @@ When switching this to ``true``, the validator requires an upper case 'X'. .. include:: /reference/constraints/_groups-option.rst.inc -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` default: ``This value is not a valid ISSN.`` @@ -111,8 +119,8 @@ Parameter Description .. include:: /reference/constraints/_payload-option.rst.inc -requireHyphen -~~~~~~~~~~~~~ +``requireHyphen`` +~~~~~~~~~~~~~~~~~ **type**: ``boolean`` default: ``false`` diff --git a/reference/constraints/Json.rst b/reference/constraints/Json.rst index 6e8318077da..c76c7cf3edc 100644 --- a/reference/constraints/Json.rst +++ b/reference/constraints/Json.rst @@ -5,8 +5,6 @@ Validates that a value has valid `JSON`_ syntax. ========== =================================================================== Applies to :ref:`property or method ` -Options - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Json` Validator :class:`Symfony\\Component\\Validator\\Constraints\\JsonValidator` ========== =================================================================== @@ -35,6 +33,21 @@ The ``Json`` constraint can be applied to a property or a "getter" method: private $chapters; } + .. code-block:: php-attributes + + // src/Entity/Book.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Book + { + #[Assert\Json( + message: "You've entered an invalid Json." + )] + private $chapters; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -82,8 +95,8 @@ The ``Json`` constraint can be applied to a property or a "getter" method: Options ------- -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This value should be valid JSON.`` diff --git a/reference/constraints/Language.rst b/reference/constraints/Language.rst index dac3e2819db..5fe5c93426c 100644 --- a/reference/constraints/Language.rst +++ b/reference/constraints/Language.rst @@ -6,10 +6,6 @@ Validates that a value is a valid language *Unicode language identifier* ========== =================================================================== Applies to :ref:`property or method ` -Options - `alpha3`_ - - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Language` Validator :class:`Symfony\\Component\\Validator\\Constraints\\LanguageValidator` ========== =================================================================== @@ -34,6 +30,19 @@ Basic Usage protected $preferredLanguage; } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class User + { + #[Assert\Language] + protected $preferredLanguage; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -88,7 +97,7 @@ alpha3 **type**: ``boolean`` **default**: ``false`` If this option is ``true``, the constraint checks that the value is a -`ISO 639-2`_ three-letter code (e.g. French = ``fra``) instead of the default +`ISO 639-2 (2T)`_ three-letter code (e.g. French = ``fra``) instead of the default `ISO 639-1`_ two-letter code (e.g. French = ``fr``). .. include:: /reference/constraints/_groups-option.rst.inc @@ -116,4 +125,4 @@ Parameter Description .. include:: /reference/constraints/_payload-option.rst.inc .. _`ISO 639-1`: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes -.. _`ISO 639-2`: https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes +.. _`ISO 639-2 (2T)`: https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes diff --git a/reference/constraints/Length.rst b/reference/constraints/Length.rst index 365aedfb585..7baed971032 100644 --- a/reference/constraints/Length.rst +++ b/reference/constraints/Length.rst @@ -5,17 +5,6 @@ Validates that a given string length is *between* some minimum and maximum value ========== =================================================================== Applies to :ref:`property or method ` -Options - `allowEmptyString`_ - - `charset`_ - - `charsetMessage`_ - - `exactMessage`_ - - `groups`_ - - `max`_ - - `maxMessage`_ - - `min`_ - - `minMessage`_ - - `normalizer`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Length` Validator :class:`Symfony\\Component\\Validator\\Constraints\\LengthValidator` ========== =================================================================== @@ -23,8 +12,8 @@ Validator :class:`Symfony\\Component\\Validator\\Constraints\\LengthValidator` Basic Usage ----------- -To verify that the ``firstName`` field length of a class is between "2" -and "50", you might add the following: +To verify that the ``firstName`` field length of a class is between ``2`` +and ``50``, you might add the following: .. configuration-block:: @@ -48,6 +37,25 @@ and "50", you might add the following: protected $firstName; } + .. code-block:: php-attributes + + // src/Entity/Participant.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Participant + { + #[Assert\Length( + min: 2, + max: 50, + minMessage: 'Your first name must be at least {{ limit }} characters long', + maxMessage: 'Your first name cannot be longer than {{ limit }} characters', + )] + protected $firstName; + } + + .. code-block:: yaml # config/validator/validation.yaml @@ -110,8 +118,8 @@ and "50", you might add the following: Options ------- -allowEmptyString -~~~~~~~~~~~~~~~~ +``allowEmptyString`` +~~~~~~~~~~~~~~~~~~~~ **type**: ``boolean`` **default**: ``false`` @@ -130,8 +138,8 @@ empty strings not valid. This option does not have any effect when no minimum length is given. -charset -~~~~~~~ +``charset`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``UTF-8`` @@ -139,8 +147,8 @@ The charset to be used when computing value's length with the :phpfunction:`mb_check_encoding` and :phpfunction:`mb_strlen` PHP functions. -charsetMessage -~~~~~~~~~~~~~~ +``charsetMessage`` +~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This value does not match the expected {{ charset }} charset.`` @@ -174,8 +182,8 @@ Parameter Description .. include:: /reference/constraints/_groups-option.rst.inc -max -~~~ +``max`` +~~~~~~~ **type**: ``integer`` @@ -184,8 +192,8 @@ the given value's length is **greater** than this max value. This option is required when the ``min`` option is not defined. -maxMessage -~~~~~~~~~~ +``maxMessage`` +~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This value is too long. It should have {{ limit }} characters or less.`` @@ -201,8 +209,8 @@ Parameter Description ``{{ value }}`` The current (invalid) value ================= ============================================================ -min -~~~ +``min`` +~~~~~~~ **type**: ``integer`` @@ -215,8 +223,8 @@ It is important to notice that NULL values and empty strings are considered valid no matter if the constraint required a minimum length. Validators are triggered only if the value is not blank. -minMessage -~~~~~~~~~~ +``minMessage`` +~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This value is too short. It should have {{ limit }} characters or more.`` diff --git a/reference/constraints/LessThan.rst b/reference/constraints/LessThan.rst index abd0aab721c..22ebce5c094 100644 --- a/reference/constraints/LessThan.rst +++ b/reference/constraints/LessThan.rst @@ -8,11 +8,6 @@ than another value, see :doc:`/reference/constraints/GreaterThan`. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ - - `propertyPath`_ - - `value`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\LessThan` Validator :class:`Symfony\\Component\\Validator\\Constraints\\LessThanValidator` ========== =================================================================== @@ -49,6 +44,24 @@ The following constraints ensure that: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThan(5)] + protected $siblings; + + #[Assert\LessThan( + value: 80, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -126,6 +139,19 @@ that a date must be in the past like this: protected $dateOfBirth; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThan('today')] + protected $dateOfBirth; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -185,6 +211,19 @@ dates. If you want to fix the timezone, append it to the date string: protected $dateOfBirth; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThan('today UTC')] + protected $dateOfBirth; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -244,6 +283,19 @@ can check that a person must be at least 18 years old like this: protected $dateOfBirth; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThan('-18 years')] + protected $dateOfBirth; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/LessThanOrEqual.rst b/reference/constraints/LessThanOrEqual.rst index 42ec3e939e5..05e2dedbfe5 100644 --- a/reference/constraints/LessThanOrEqual.rst +++ b/reference/constraints/LessThanOrEqual.rst @@ -7,11 +7,6 @@ options. To force that a value is less than another value, see ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ - - `propertyPath`_ - - `value`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\LessThanOrEqual` Validator :class:`Symfony\\Component\\Validator\\Constraints\\LessThanOrEqualValidator` ========== =================================================================== @@ -48,6 +43,24 @@ The following constraints ensure that: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThanOrEqual(5)] + protected $siblings; + + #[Assert\LessThanOrEqual( + value: 80, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -125,6 +138,19 @@ that a date must be today or in the past like this: protected $dateOfBirth; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThanOrEqual('today')] + protected $dateOfBirth; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -184,6 +210,19 @@ dates. If you want to fix the timezone, append it to the date string: protected $dateOfBirth; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThanOrEqual('today UTC')] + protected $dateOfBirth; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -243,6 +282,19 @@ can check that a person must be at least 18 years old like this: protected $dateOfBirth; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\LessThanOrEqual('-18 years')] + protected $dateOfBirth; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Locale.rst b/reference/constraints/Locale.rst index f5f381629e3..c61b12187b7 100644 --- a/reference/constraints/Locale.rst +++ b/reference/constraints/Locale.rst @@ -14,9 +14,6 @@ issues with wrong uppercase/lowercase values and to remove unneeded elements ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Locale` Validator :class:`Symfony\\Component\\Validator\\Constraints\\LocaleValidator` ========== =================================================================== @@ -43,6 +40,21 @@ Basic Usage protected $locale; } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class User + { + #[Assert\Locale( + canonicalize: true, + )] + protected $locale; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Luhn.rst b/reference/constraints/Luhn.rst index 2bee41d5f2c..30a8092c1bc 100644 --- a/reference/constraints/Luhn.rst +++ b/reference/constraints/Luhn.rst @@ -7,9 +7,6 @@ card: before communicating with a payment gateway. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Luhn` Validator :class:`Symfony\\Component\\Validator\\Constraints\\LuhnValidator` ========== =================================================================== @@ -37,6 +34,19 @@ will contain a credit card number. protected $cardNumber; } + .. code-block:: php-attributes + + // src/Entity/Transaction.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Transaction + { + #[Assert\Luhn(message: 'Please check your credit card number.')] + protected $cardNumber; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Negative.rst b/reference/constraints/Negative.rst index 7468b4bfc4a..c77d0586cbf 100644 --- a/reference/constraints/Negative.rst +++ b/reference/constraints/Negative.rst @@ -7,9 +7,6 @@ want to allow zero as value. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Negative` Validator :class:`Symfony\\Component\\Validator\\Constraints\\LesserThanValidator` ========== =================================================================== @@ -37,6 +34,19 @@ The following constraint ensures that the ``withdraw`` of a bank account protected $withdraw; } + .. code-block:: php-attributes + + // src/Entity/TransferItem.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class TransferItem + { + #[Assert\Negative] + protected $withdraw; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -81,8 +91,8 @@ Available Options .. include:: /reference/constraints/_groups-option.rst.inc -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This value should be negative.`` diff --git a/reference/constraints/NegativeOrZero.rst b/reference/constraints/NegativeOrZero.rst index f010acda0b1..0aead7184e3 100644 --- a/reference/constraints/NegativeOrZero.rst +++ b/reference/constraints/NegativeOrZero.rst @@ -6,9 +6,6 @@ want to allow zero as value, use :doc:`/reference/constraints/Negative` instead. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\NegativeOrZero` Validator :class:`Symfony\\Component\\Validator\\Constraints\\LesserThanOrEqualValidator` ========== =================================================================== @@ -36,6 +33,19 @@ is a negative number or equal to zero: protected $level; } + .. code-block:: php-attributes + + // src/Entity/TransferItem.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class UnderGroundGarage + { + #[Assert\NegativeOrZero] + protected $level; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -80,8 +90,8 @@ Available Options .. include:: /reference/constraints/_groups-option.rst.inc -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This value should be either negative or zero.`` diff --git a/reference/constraints/NotBlank.rst b/reference/constraints/NotBlank.rst index f5711e001c3..64a2b59733f 100644 --- a/reference/constraints/NotBlank.rst +++ b/reference/constraints/NotBlank.rst @@ -8,11 +8,6 @@ that a value is not equal to ``null``, see the ========== =================================================================== Applies to :ref:`property or method ` -Options - `allowNull`_ - - `groups`_ - - `message`_ - - `normalizer`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\NotBlank` Validator :class:`Symfony\\Component\\Validator\\Constraints\\NotBlankValidator` ========== =================================================================== @@ -40,6 +35,19 @@ class were not blank, you could do the following: protected $firstName; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\NotBlank] + protected $firstName; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -82,10 +90,10 @@ class were not blank, you could do the following: Options ------- -allowNull -~~~~~~~~~ +``allowNull`` +~~~~~~~~~~~~~ -**type**: ``bool`` **default**: ``false`` +**type**: ``boolean`` **default**: ``false`` If set to ``true``, ``null`` values are considered valid and won't trigger a constraint violation. diff --git a/reference/constraints/NotCompromisedPassword.rst b/reference/constraints/NotCompromisedPassword.rst index bcd1c61b560..74729853128 100644 --- a/reference/constraints/NotCompromisedPassword.rst +++ b/reference/constraints/NotCompromisedPassword.rst @@ -6,11 +6,6 @@ not included in any of the public data breaches tracked by `haveibeenpwned.com`_ ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ - - `skipOnError`_ - - `threshold`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\NotCompromisedPassword` Validator :class:`Symfony\\Component\\Validator\\Constraints\\NotCompromisedPasswordValidator` ========== =================================================================== @@ -38,6 +33,19 @@ The following constraint ensures that the ``rawPassword`` property of the protected $rawPassword; } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class User + { + #[Assert\NotCompromisedPassword] + protected $rawPassword; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -102,8 +110,8 @@ Available Options .. include:: /reference/constraints/_groups-option.rst.inc -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This password has been leaked in a data breach, it must not be used. Please use another password.`` @@ -111,8 +119,8 @@ The default message supplied when the password has been compromised. .. include:: /reference/constraints/_payload-option.rst.inc -skipOnError -~~~~~~~~~~~ +``skipOnError`` +~~~~~~~~~~~~~~~ **type**: ``boolean`` **default**: ``false`` @@ -120,8 +128,8 @@ When the HTTP request made to the ``haveibeenpwned.com`` API fails for any reason, an exception is thrown (no validation error is displayed). Set this option to ``true`` to not throw the exception and consider the password valid. -threshold -~~~~~~~~~ +``threshold`` +~~~~~~~~~~~~~ **type**: ``integer`` **default**: ``1`` diff --git a/reference/constraints/NotEqualTo.rst b/reference/constraints/NotEqualTo.rst index e1436657ae8..993402f0964 100644 --- a/reference/constraints/NotEqualTo.rst +++ b/reference/constraints/NotEqualTo.rst @@ -13,11 +13,6 @@ options. To force that a value is equal, see ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ - - `propertyPath`_ - - `value`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\NotEqualTo` Validator :class:`Symfony\\Component\\Validator\\Constraints\\NotEqualToValidator` ========== =================================================================== @@ -53,6 +48,24 @@ the following: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\NotEqualTo('Mary')] + protected $firstName; + + #[Assert\NotEqualTo( + value: 15, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/NotIdenticalTo.rst b/reference/constraints/NotIdenticalTo.rst index 66ccb871670..381aa5de2b5 100644 --- a/reference/constraints/NotIdenticalTo.rst +++ b/reference/constraints/NotIdenticalTo.rst @@ -13,11 +13,6 @@ the options. To force that a value is identical, see ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ - - `propertyPath`_ - - `value`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\NotIdenticalTo` Validator :class:`Symfony\\Component\\Validator\\Constraints\\NotIdenticalToValidator` ========== =================================================================== @@ -54,6 +49,24 @@ The following constraints ensure that: protected $age; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\NotIdenticalTo('Mary')] + protected $firstName; + + #[Assert\NotIdenticalTo( + value: 15, + )] + protected $age; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/NotNull.rst b/reference/constraints/NotNull.rst index 56d088c4cba..3c34f8e221e 100644 --- a/reference/constraints/NotNull.rst +++ b/reference/constraints/NotNull.rst @@ -7,9 +7,6 @@ constraint. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\NotNull` Validator :class:`Symfony\\Component\\Validator\\Constraints\\NotNullValidator` ========== =================================================================== @@ -37,6 +34,19 @@ class were not strictly equal to ``null``, you would: protected $firstName; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\NotNull] + protected $firstName; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Positive.rst b/reference/constraints/Positive.rst index af76f205e53..b918c21695a 100644 --- a/reference/constraints/Positive.rst +++ b/reference/constraints/Positive.rst @@ -7,9 +7,6 @@ want to allow zero as value. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Positive` Validator :class:`Symfony\\Component\\Validator\\Constraints\\GreaterThanValidator` ========== =================================================================== @@ -37,6 +34,19 @@ positive number (greater than zero): protected $income; } + .. code-block:: php-attributes + + // src/Entity/Employee.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Employee + { + #[Assert\Positive] + protected $income; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -82,8 +92,8 @@ Available Options .. include:: /reference/constraints/_groups-option.rst.inc -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This value should be positive.`` diff --git a/reference/constraints/PositiveOrZero.rst b/reference/constraints/PositiveOrZero.rst index ea762e78f90..2d39d0d6d19 100644 --- a/reference/constraints/PositiveOrZero.rst +++ b/reference/constraints/PositiveOrZero.rst @@ -6,9 +6,6 @@ want to allow zero as value, use :doc:`/reference/constraints/Positive` instead. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\PositiveOrZero` Validator :class:`Symfony\\Component\\Validator\\Constraints\\GreaterThanOrEqualValidator` ========== =================================================================== @@ -36,6 +33,19 @@ is positive or zero: protected $siblings; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\PositiveOrZero] + protected $siblings; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -80,8 +90,8 @@ Available Options .. include:: /reference/constraints/_groups-option.rst.inc -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This value should be either positive or zero.`` diff --git a/reference/constraints/Range.rst b/reference/constraints/Range.rst index d5b473362dd..1812eeba82b 100644 --- a/reference/constraints/Range.rst +++ b/reference/constraints/Range.rst @@ -5,17 +5,6 @@ Validates that a given number or ``DateTime`` object is *between* some minimum a ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `invalidDateTimeMessage`_ - - `invalidMessage`_ - - `max`_ - - `maxMessage`_ - - `maxPropertyPath`_ - - `min`_ - - `minMessage`_ - - `minPropertyPath`_ - - `notInRangeMessage`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Range` Validator :class:`Symfony\\Component\\Validator\\Constraints\\RangeValidator` ========== =================================================================== @@ -23,7 +12,7 @@ Validator :class:`Symfony\\Component\\Validator\\Constraints\\RangeValidator` Basic Usage ----------- -To verify that the "height" field of a class is between "120" and "180", +To verify that the ``height`` field of a class is between ``120`` and ``180``, you might add the following: .. configuration-block:: @@ -47,6 +36,23 @@ you might add the following: protected $height; } + .. code-block:: php-attributes + + // src/Entity/Participant.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Participant + { + #[Assert\Range( + min: 120, + max: 180, + notInRangeMessage: 'You must be between {{ min }}cm and {{ max }}cm tall to enter', + )] + protected $height; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -125,6 +131,22 @@ date must lie within the current year like this: protected $startDate; } + .. code-block:: php-attributes + + // src/Entity/Event.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Event + { + #[Assert\Range( + min: 'first day of January', + max: 'first day of January next year', + )] + protected $startDate; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -195,6 +217,22 @@ dates. If you want to fix the timezone, append it to the date string: protected $startDate; } + .. code-block:: php-attributes + + // src/Entity/Event.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Event + { + #[Assert\Range( + min: 'first day of January UTC', + max: 'first day of January next year UTC', + )] + protected $startDate; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -265,6 +303,22 @@ can check that a delivery date starts within the next five hours like this: protected $deliveryDate; } + .. code-block:: php-attributes + + // src/Entity/Order.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Order + { + #[Assert\Range( + min: 'now', + max: '+5 hours', + )] + protected $deliveryDate; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -317,8 +371,8 @@ Options .. include:: /reference/constraints/_groups-option.rst.inc -invalidDateTimeMessage -~~~~~~~~~~~~~~~~~~~~~~ +``invalidDateTimeMessage`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This value should be a valid number.`` @@ -337,8 +391,8 @@ Parameter Description ``{{ value }}`` The current (invalid) value =============== ============================================================== -invalidMessage -~~~~~~~~~~~~~~ +``invalidMessage`` +~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This value should be a valid number.`` @@ -358,16 +412,16 @@ Parameter Description The ``{{ label }}`` parameter was introduced in Symfony 5.2. -max -~~~ +``max`` +~~~~~~~ **type**: ``number`` or ``string`` (date format) This required option is the "max" value. Validation will fail if the given value is **greater** than this max value. -maxMessage -~~~~~~~~~~ +``maxMessage`` +~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This value should be {{ limit }} or less.`` @@ -384,8 +438,8 @@ Parameter Description ``{{ value }}`` The current (invalid) value =============== ============================================================== -maxPropertyPath -~~~~~~~~~~~~~~~ +``maxPropertyPath`` +~~~~~~~~~~~~~~~~~~~ **type**: ``string`` @@ -402,16 +456,16 @@ with regard to the ``$deadline`` property of the same object, use include it in the error messages displayed to end users, it's useful when using APIs for doing any mapping logic on client-side. -min -~~~ +``min`` +~~~~~~~ **type**: ``number`` or ``string`` (date format) This required option is the "min" value. Validation will fail if the given value is **less** than this min value. -minMessage -~~~~~~~~~~ +``minMessage`` +~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This value should be {{ limit }} or more.`` @@ -428,8 +482,8 @@ Parameter Description ``{{ value }}`` The current (invalid) value =============== ============================================================== -minPropertyPath -~~~~~~~~~~~~~~~ +``minPropertyPath`` +~~~~~~~~~~~~~~~~~~~ **type**: ``string`` @@ -446,8 +500,8 @@ with regard to the ``$startDate`` property of the same object, use include it in the error messages displayed to end users, it's useful when using APIs for doing any mapping logic on client-side. -notInRangeMessage -~~~~~~~~~~~~~~~~~ +``notInRangeMessage`` +~~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``This value should be between {{ min }} and {{ max }}.`` diff --git a/reference/constraints/Regex.rst b/reference/constraints/Regex.rst index 642a1fc180d..d4ecf423fd0 100644 --- a/reference/constraints/Regex.rst +++ b/reference/constraints/Regex.rst @@ -5,13 +5,6 @@ Validates that a value matches a regular expression. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `htmlPattern`_ - - `match`_ - - `message`_ - - `pattern`_ - - `normalizer`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Regex` Validator :class:`Symfony\\Component\\Validator\\Constraints\\RegexValidator` ========== =================================================================== @@ -41,6 +34,19 @@ more word characters at the beginning of your string: protected $description; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Regex('/^\w+/')] + protected $description; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -110,6 +116,23 @@ it a custom message: protected $firstName; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Regex( + pattern: '/\d/', + match: false, + message: 'Your name cannot contain a number', + )] + protected $firstName; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -167,20 +190,20 @@ Options .. include:: /reference/constraints/_groups-option.rst.inc -htmlPattern -~~~~~~~~~~~ +``htmlPattern`` +~~~~~~~~~~~~~~~ **type**: ``string|boolean`` **default**: null This option specifies the pattern to use in the HTML5 ``pattern`` attribute. You usually don't need to specify this option because by default, the constraint will convert the pattern given in the `pattern`_ option into an HTML5 compatible -pattern. This means that the delimiters are removed (e.g. ``/[a-z]+/`` becomes -``[a-z]+``). +pattern. Notably, the delimiters are removed and the anchors are implicit (e.g. +``/^[a-z]+$/`` becomes ``[a-z]+``, and ``/[a-z]+/`` becomes ``.*[a-z]+.*``). However, there are some other incompatibilities between both patterns which cannot be fixed by the constraint. For instance, the HTML5 ``pattern`` attribute -does not support flags. If you have a pattern like ``/[a-z]+/i``, you +does not support flags. If you have a pattern like ``/^[a-z]+$/i``, you need to specify the HTML5 compatible pattern in the ``htmlPattern`` option: .. configuration-block:: @@ -197,12 +220,28 @@ need to specify the HTML5 compatible pattern in the ``htmlPattern`` option: /** * @Assert\Regex( * pattern = "/^[a-z]+$/i", - * htmlPattern = "^[a-zA-Z]+$" + * htmlPattern = "[a-zA-Z]+" * ) */ protected $name; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Regex( + pattern: '/^[a-z]+$/i', + htmlPattern: '^[a-zA-Z]+$' + )] + protected $name; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -211,7 +250,7 @@ need to specify the HTML5 compatible pattern in the ``htmlPattern`` option: name: - Regex: pattern: '/^[a-z]+$/i' - htmlPattern: '^[a-zA-Z]+$' + htmlPattern: '[a-zA-Z]+' .. code-block:: xml @@ -225,7 +264,7 @@ need to specify the HTML5 compatible pattern in the ``htmlPattern`` option: - + @@ -245,15 +284,15 @@ need to specify the HTML5 compatible pattern in the ``htmlPattern`` option: { $metadata->addPropertyConstraint('name', new Assert\Regex([ 'pattern' => '/^[a-z]+$/i', - 'htmlPattern' => '^[a-zA-Z]+$', + 'htmlPattern' => '[a-zA-Z]+', ])); } } Setting ``htmlPattern`` to false will disable client side validation. -match -~~~~~ +``match`` +~~~~~~~~~ **type**: ``boolean`` default: ``true`` @@ -262,8 +301,8 @@ the given `pattern`_ regular expression. However, when this option is set to ``false``, the opposite will occur: validation will pass only if the given string does **not** match the `pattern`_ regular expression. -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This value is not valid.`` @@ -282,8 +321,8 @@ Parameter Description The ``{{ label }}`` parameter was introduced in Symfony 5.2. -pattern -~~~~~~~ +``pattern`` +~~~~~~~~~~~ **type**: ``string`` [:ref:`default option `] diff --git a/reference/constraints/Sequentially.rst b/reference/constraints/Sequentially.rst index 39424a6c523..5bc2e044db5 100644 --- a/reference/constraints/Sequentially.rst +++ b/reference/constraints/Sequentially.rst @@ -13,9 +13,6 @@ using :doc:`GroupSequence ` which allows more con ========== =================================================================== Applies to :ref:`property or method ` -Options - `constraints`_ - - `groups`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Sequentially` Validator :class:`Symfony\\Component\\Validator\\Constraints\\SequentiallyValidator` ========== =================================================================== @@ -35,7 +32,7 @@ In such situations, you may encounter three issues: * the ``Length`` or ``Regex`` constraints may fail hard with a :class:`Symfony\\Component\\Validator\\Exception\\UnexpectedValueException` exception if the actual value is not a string, as enforced by ``Type``. -* you may end with multiple error messages for the same property +* you may end with multiple error messages for the same property. * you may perform a useless and heavy external call to geolocalize the address, while the format isn't valid. @@ -120,7 +117,7 @@ You can validate each of these constraints sequentially to solve these issues: { $metadata->addPropertyConstraint('address', new Assert\Sequentially([ new Assert\NotNull(), - new Assert\Type("string"), + new Assert\Type('string'), new Assert\Length(['min' => 10]), new Assert\Regex(self::ADDRESS_REGEX), new AcmeAssert\Geolocalizable(), diff --git a/reference/constraints/Time.rst b/reference/constraints/Time.rst index e94613e1f6f..b3f13894120 100644 --- a/reference/constraints/Time.rst +++ b/reference/constraints/Time.rst @@ -6,9 +6,6 @@ be cast into a string) that follows a valid ``HH:MM:SS`` format. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Time` Validator :class:`Symfony\\Component\\Validator\\Constraints\\TimeValidator` ========== =================================================================== @@ -37,6 +34,22 @@ of the day when the event starts: protected $startsAt; } + .. code-block:: php-attributes + + // src/Entity/Event.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Event + { + /** + * @var string A "H:i:s" formatted value + */ + #[Assert\Time] + protected $startsAt; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index 98ca73c156a..d155f09dcfd 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -5,12 +5,6 @@ Validates that a value is a valid timezone identifier (e.g. ``Europe/Paris``). ========== ====================================================================== Applies to :ref:`property or method ` -Options - `countryCode`_ - - `groups`_ - - `intlCompatible`_ - - `message`_ - - `payload`_ - - `zone`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Timezone` Validator :class:`Symfony\\Component\\Validator\\Constraints\\TimezoneValidator` ========== ====================================================================== @@ -38,6 +32,19 @@ string which contains any of the `PHP timezone identifiers`_ (e.g. ``America/New protected $timezone; } + .. code-block:: php-attributes + + // src/Entity/UserSettings.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class UserSettings + { + #[Assert\Timezone] + protected $timezone; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -82,8 +89,8 @@ string which contains any of the `PHP timezone identifiers`_ (e.g. ``America/New Options ------- -countryCode -~~~~~~~~~~~ +``countryCode`` +~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``null`` @@ -96,8 +103,8 @@ The value of this option must be a valid `ISO 3166-1 alpha-2`_ country code .. include:: /reference/constraints/_groups-option.rst.inc -intlCompatible -~~~~~~~~~~~~~~ +``intlCompatible`` +~~~~~~~~~~~~~~~~~~ **type**: ``boolean`` **default**: ``false`` @@ -110,8 +117,8 @@ timezones provided by PHP's Intl extension (because they use different ICU versions). If this option is set to ``true``, this constraint only considers valid the values compatible with the PHP ``\IntlTimeZone::createTimeZone()`` method. -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This value is not a valid timezone.`` @@ -132,8 +139,8 @@ Parameter Description .. include:: /reference/constraints/_payload-option.rst.inc -zone -~~~~ +``zone`` +~~~~~~~~ **type**: ``string`` **default**: ``\DateTimeZone::ALL`` diff --git a/reference/constraints/Traverse.rst b/reference/constraints/Traverse.rst index fd329bd38a3..dfb92943050 100644 --- a/reference/constraints/Traverse.rst +++ b/reference/constraints/Traverse.rst @@ -8,8 +8,6 @@ constraint. ========== =================================================================== Applies to :ref:`class ` -Options - `payload`_ - - :ref:`traverse ` Class :class:`Symfony\\Component\\Validator\\Constraints\\Traverse` ========== =================================================================== @@ -89,6 +87,70 @@ that all have constraints on their properties. } } + .. code-block:: php-attributes + + // src/Entity/BookCollection.php + namespace App\Entity; + + use App\Entity\Book; + use Doctrine\Common\Collections\ArrayCollection; + use Doctrine\Common\Collections\Collection; + use Doctrine\ORM\Mapping as ORM; + use Symfony\Component\Validator\Constraints as Assert; + + #[ORM\Entity] + #[Assert\Traverse] + class BookCollection implements \IteratorAggregate + { + /** + * @var string + */ + #[ORM\Column] + #[Assert\NotBlank] + protected $name = ''; + + /** + * @var Collection|Book[] + */ + #[ORM\ManyToMany(targetEntity: Book::class)] + protected $books; + + // some other properties + + public function __construct() + { + $this->books = new ArrayCollection(); + } + + // ... setter for name, adder and remover for books + + // the name can be validated by calling the getter + public function getName(): string + { + return $this->name; + } + + /** + * @return \Generator|Book[] The books for a given author + */ + public function getBooksForAuthor(Author $author): iterable + { + foreach ($this->books as $book) { + if ($book->isAuthoredBy($author)) { + yield $book; + } + } + } + + // neither the method above nor any other specific getter + // could be used to validated all nested books; + // this object needs to be traversed to call the iterator + public function getIterator() + { + return $this->books->getIterator(); + } + } + .. code-block:: yaml # config/validator/validation.yaml @@ -146,7 +208,7 @@ The ``groups`` option is not available for this constraint. ``traverse`` ~~~~~~~~~~~~ -**type**: ``bool`` **default**: ``true`` +**type**: ``boolean`` **default**: ``true`` Instances of ``\Traversable`` are traversed by default, use this option to disable validating: @@ -168,6 +230,21 @@ disable validating: // ... } + .. code-block:: php-attributes + + // src/Entity/BookCollection.php + + // ... same as above + + /** + * ... + */ + #[Assert\Traverse(false)] + class BookCollection implements \IteratorAggregate + { + // ... + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Type.rst b/reference/constraints/Type.rst index 1962dffa284..be6149f53aa 100644 --- a/reference/constraints/Type.rst +++ b/reference/constraints/Type.rst @@ -7,10 +7,6 @@ option to validate this. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ - - :ref:`type ` Class :class:`Symfony\\Component\\Validator\\Constraints\\Type` Validator :class:`Symfony\\Component\\Validator\\Constraints\\TypeValidator` ========== =================================================================== @@ -18,7 +14,7 @@ Validator :class:`Symfony\\Component\\Validator\\Constraints\\TypeValidator` Basic Usage ----------- -This will check if ``id`` is an instance of ``Ramsey\Uuid\UuidInterface``, +This will check if ``emailAddress`` is an instance of ``Symfony\Component\Mime\Address``, ``firstName`` is of type ``string`` (using :phpfunction:`is_string` PHP function), ``age`` is an ``integer`` (using :phpfunction:`is_int` PHP function) and ``accessCode`` contains either only letters or only digits (using @@ -36,9 +32,9 @@ This will check if ``id`` is an instance of ``Ramsey\Uuid\UuidInterface``, class Author { /** - * @Assert\Type("Ramsey\Uuid\UuidInterface") + * @Assert\Type("Symfony\Component\Mime\Address") */ - protected $id; + protected $emailAddress; /** * @Assert\Type("string") @@ -59,13 +55,39 @@ This will check if ``id`` is an instance of ``Ramsey\Uuid\UuidInterface``, protected $accessCode; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Mime\Address; + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Type(Address::class)] + protected $emailAddress; + + #[Assert\Type('string')] + protected $firstName; + + #[Assert\Type( + type: 'integer', + message: 'The value {{ value }} is not a valid {{ type }}.', + )] + protected $age; + + #[Assert\Type(type: ['alpha', 'digit'])] + protected $accessCode; + } + .. code-block:: yaml # config/validator/validation.yaml App\Entity\Author: properties: - id: - - Type: Ramsey\Uuid\UuidInterface + emailAddress: + - Type: Symfony\Component\Mime\Address firstName: - Type: string @@ -88,9 +110,9 @@ This will check if ``id`` is an instance of ``Ramsey\Uuid\UuidInterface``, xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> - + - + @@ -120,7 +142,7 @@ This will check if ``id`` is an instance of ``Ramsey\Uuid\UuidInterface``, // src/Entity/Author.php namespace App\Entity; - use Ramsey\Uuid\UuidInterface; + use Symfony\Component\Mime\Address; use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Mapping\ClassMetadata; @@ -128,7 +150,7 @@ This will check if ``id`` is an instance of ``Ramsey\Uuid\UuidInterface``, { public static function loadValidatorMetadata(ClassMetadata $metadata) { - $metadata->addPropertyConstraint('id', new Assert\Type(UuidInterface::class)); + $metadata->addPropertyConstraint('emailAddress', new Assert\Type(Address::class)); $metadata->addPropertyConstraint('firstName', new Assert\Type('string')); @@ -143,13 +165,15 @@ This will check if ``id`` is an instance of ``Ramsey\Uuid\UuidInterface``, } } +.. include:: /reference/constraints/_null-values-are-valid.rst.inc + Options ------- .. include:: /reference/constraints/_groups-option.rst.inc -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This value should be of type {{ type }}.`` @@ -173,8 +197,8 @@ Parameter Description .. _reference-constraint-type-type: -type -~~~~ +``type`` +~~~~~~~~ **type**: ``string`` or ``array`` [:ref:`default option `] diff --git a/reference/constraints/Ulid.rst b/reference/constraints/Ulid.rst index 7bcae08e961..102e6486e41 100644 --- a/reference/constraints/Ulid.rst +++ b/reference/constraints/Ulid.rst @@ -9,10 +9,6 @@ Validates that a value is a valid `Universally Unique Lexicographically Sortable ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `normalizer`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Ulid` Validator :class:`Symfony\\Component\\Validator\\Constraints\\UlidValidator` ========== =================================================================== @@ -37,6 +33,19 @@ Basic Usage protected $identifier; } + .. code-block:: php-attributes + + // src/Entity/File.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class File + { + #[Assert\Ulid] + protected $identifier; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Unique.rst b/reference/constraints/Unique.rst index 97cb6ff8602..f54885cbc2f 100644 --- a/reference/constraints/Unique.rst +++ b/reference/constraints/Unique.rst @@ -2,8 +2,9 @@ Unique ====== Validates that all the elements of the given collection are unique (none of them -is present more than once). Elements are compared strictly, so ``'7'`` and ``7`` -are considered different elements (a string and an integer, respectively). +is present more than once). By default elements are compared strictly, +so ``'7'`` and ``7`` are considered different elements (a string and an integer, respectively). +If you want to apply any other comparison logic, use the `normalizer`_ option. .. seealso:: @@ -19,9 +20,6 @@ are considered different elements (a string and an integer, respectively). ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Unique` Validator :class:`Symfony\\Component\\Validator\\Constraints\\UniqueValidator` ========== =================================================================== @@ -50,6 +48,19 @@ strings: protected $contactEmails; } + .. code-block:: php-attributes + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + #[Assert\Unique] + protected $contactEmails; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -94,8 +105,8 @@ Options .. include:: /reference/constraints/_groups-option.rst.inc -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This collection should contain only unique elements.`` @@ -107,7 +118,25 @@ You can use the following parameters in this message: ============================= ================================================ Parameter Description ============================= ================================================ -``{{ value }}`` The repeated value +``{{ value }}`` The current (invalid) value ============================= ================================================ +``normalizer`` +~~~~~~~~~~~~~~ + +**type**: a `PHP callable`_ **default**: ``null`` + +.. versionadded:: 5.3 + + The ``normalizer`` option was introduced in Symfony 5.3. + +This option defined the PHP callable applied to each element of the given +collection before checking if the collection is valid. + +For example, you can pass the ``'trim'`` string to apply the :phpfunction:`trim` +PHP function to each element of the collection in order to ignore leading and +trailing whitespace during validation. + .. include:: /reference/constraints/_payload-option.rst.inc + +.. _`PHP callable`: https://www.php.net/callable diff --git a/reference/constraints/UniqueEntity.rst b/reference/constraints/UniqueEntity.rst index 2bf2533f57e..fc6fccb18f6 100644 --- a/reference/constraints/UniqueEntity.rst +++ b/reference/constraints/UniqueEntity.rst @@ -10,17 +10,13 @@ using an email address that already exists in the system. If you want to validate that all the elements of the collection are unique use the :doc:`Unique constraint `. +.. note:: + + In order to use this constraint, you should have installed the + symfony/doctrine-bridge with Composer. + ========== =================================================================== Applies to :ref:`class ` -Options - `em`_ - - `entityClass`_ - - `errorPath`_ - - `fields`_ - - `groups`_ - - `ignoreNull`_ - - `message`_ - - `payload`_ - - `repositoryMethod`_ Class :class:`Symfony\\Bridge\\Doctrine\\Validator\\Constraints\\UniqueEntity` Validator :class:`Symfony\\Bridge\\Doctrine\\Validator\\Constraints\\UniqueEntityValidator` ========== =================================================================== @@ -59,6 +55,27 @@ between all of the rows in your user table: protected $email; } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Doctrine\ORM\Mapping as ORM; + + // DON'T forget the following use statement!!! + use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; + + use Symfony\Component\Validator\Constraints as Assert; + + #[ORM\Entity] + #[UniqueEntity('email')] + class User + { + #[ORM\Column(name: 'email', type: 'string', length: 255, unique: true)] + #[Assert\Email] + protected $email; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -135,8 +152,8 @@ the uniqueness. If it's left blank, the correct entity manager will be determined for this class. For that reason, this option should probably not need to be used. -entityClass -~~~~~~~~~~~ +``entityClass`` +~~~~~~~~~~~~~~~ **type**: ``string`` @@ -146,8 +163,8 @@ inheritance mapping, you need to execute the query in a different repository. Use this option to define the fully-qualified class name (FQCN) of the Doctrine entity associated with the repository you want to use. -errorPath -~~~~~~~~~ +``errorPath`` +~~~~~~~~~~~~~ **type**: ``string`` **default**: The name of the first field in `fields`_ @@ -188,6 +205,30 @@ Consider this example: public $port; } + .. code-block:: php-attributes + + // src/Entity/Service.php + namespace App\Entity; + + use App\Entity\Host; + use Doctrine\ORM\Mapping as ORM; + use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; + + #[ORM\Entity] + #[UniqueEntity( + fields: ['host', 'port'], + errorPath: 'port', + message: 'This port is already in use on that host.', + )] + class Service + { + #[ORM\ManyToOne(targetEntity: Host::class)] + public $host; + + #[ORM\Column(type: 'integer')] + public $port; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -244,8 +285,8 @@ Consider this example: Now, the message would be bound to the ``port`` field with this configuration. -fields -~~~~~~ +``fields`` +~~~~~~~~~~ **type**: ``array`` | ``string`` [:ref:`default option `] @@ -261,8 +302,8 @@ each with a single field. .. include:: /reference/constraints/_groups-option.rst.inc -ignoreNull -~~~~~~~~~~ +``ignoreNull`` +~~~~~~~~~~~~~~ **type**: ``boolean`` **default**: ``true`` @@ -271,8 +312,8 @@ entities to have a ``null`` value for a field without failing validation. If set to ``false``, only one ``null`` value is allowed - if a second entity also has a ``null`` value, validation would fail. -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This value is already used.`` @@ -300,8 +341,8 @@ Parameter Description .. include:: /reference/constraints/_payload-option.rst.inc -repositoryMethod -~~~~~~~~~~~~~~~~ +``repositoryMethod`` +~~~~~~~~~~~~~~~~~~~~ **type**: ``string`` **default**: ``findBy`` diff --git a/reference/constraints/Url.rst b/reference/constraints/Url.rst index 5f4ac23245f..13fb590236b 100644 --- a/reference/constraints/Url.rst +++ b/reference/constraints/Url.rst @@ -5,12 +5,6 @@ Validates that a value is a valid URL string. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `normalizer`_ - - `payload`_ - - `protocols`_ - - `relativeProtocol`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Url` Validator :class:`Symfony\\Component\\Validator\\Constraints\\UrlValidator` ========== =================================================================== @@ -35,6 +29,19 @@ Basic Usage protected $bioUrl; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Url] + protected $bioUrl; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -85,8 +92,8 @@ Options .. include:: /reference/constraints/_groups-option.rst.inc -message -~~~~~~~ +``message`` +~~~~~~~~~~~ **type**: ``string`` **default**: ``This value is not a valid URL.`` @@ -124,6 +131,21 @@ Parameter Description protected $bioUrl; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Url( + message: 'The url {{ value }} is not a valid url', + )] + protected $bioUrl; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -172,8 +194,8 @@ Parameter Description .. include:: /reference/constraints/_payload-option.rst.inc -protocols -~~~~~~~~~ +``protocols`` +~~~~~~~~~~~~~ **type**: ``array`` **default**: ``['http', 'https']`` @@ -200,6 +222,21 @@ the ``ftp://`` type URLs to be valid, redefine the ``protocols`` array, listing protected $bioUrl; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Url( + protocols: ['http', 'https', 'ftp'], + )] + protected $bioUrl; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -247,8 +284,8 @@ the ``ftp://`` type URLs to be valid, redefine the ``protocols`` array, listing } } -relativeProtocol -~~~~~~~~~~~~~~~~ +``relativeProtocol`` +~~~~~~~~~~~~~~~~~~~~ **type**: ``boolean`` **default**: ``false`` @@ -275,6 +312,21 @@ also relative URLs that contain no protocol (e.g. ``//example.com``). protected $bioUrl; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Url( + relativeProtocol: true, + )] + protected $bioUrl; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/UserPassword.rst b/reference/constraints/UserPassword.rst index 9655380bf95..c1632c3f7c7 100644 --- a/reference/constraints/UserPassword.rst +++ b/reference/constraints/UserPassword.rst @@ -12,16 +12,13 @@ password, but needs to enter their old password for security. .. note:: - In order to use this constraints, you should have installed the + In order to use this constraint, you should have installed the symfony/security-core component with Composer. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `payload`_ -Class :class:`Symfony\\Component\\Validator\\Constraints\\UserPassword` -Validator :class:`Symfony\\Component\\Validator\\Constraints\\UserPasswordValidator` +Class :class:`Symfony\\Component\\Security\\Core\\Validator\\Constraints\\UserPassword` +Validator :class:`Symfony\\Component\\Security\\Core\\Validator\\Constraints\\UserPasswordValidator` ========== =================================================================== Basic Usage @@ -51,6 +48,21 @@ the user's current password: protected $oldPassword; } + .. code-block:: php-attributes + + // src/Form/Model/ChangePassword.php + namespace App\Form\Model; + + use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert; + + class ChangePassword + { + #[SecurityAssert\UserPassword( + message: 'Wrong value for your current password', + )] + protected $oldPassword; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Uuid.rst b/reference/constraints/Uuid.rst index 427a373f788..865be23e277 100644 --- a/reference/constraints/Uuid.rst +++ b/reference/constraints/Uuid.rst @@ -4,16 +4,10 @@ UUID Validates that a value is a valid `Universally unique identifier (UUID)`_ per `RFC 4122`_. By default, this will validate the format according to the RFC's guidelines, but this can be relaxed to accept non-standard UUIDs that other systems (like PostgreSQL) accept. -UUID versions can also be restricted using a whitelist. +UUID versions can also be restricted using a list of allowed versions. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `message`_ - - `normalizer`_ - - `payload`_ - - `strict`_ - - `versions`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Uuid` Validator :class:`Symfony\\Component\\Validator\\Constraints\\UuidValidator` ========== =================================================================== @@ -38,6 +32,19 @@ Basic Usage protected $identifier; } + .. code-block:: php-attributes + + // src/Entity/File.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class File + { + #[Assert\Uuid] + protected $identifier; + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/reference/constraints/Valid.rst b/reference/constraints/Valid.rst index 1cb992128ac..ba4e789091c 100644 --- a/reference/constraints/Valid.rst +++ b/reference/constraints/Valid.rst @@ -7,9 +7,6 @@ an object and all sub-objects associated with it. ========== =================================================================== Applies to :ref:`property or method ` -Options - `groups`_ - - `payload`_ - - `traverse`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Valid` ========== =================================================================== @@ -87,6 +84,40 @@ stores an ``Address`` instance in the ``$address`` property:: protected $address; } + .. code-block:: php-attributes + + // src/Entity/Address.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Address + { + #[Assert\NotBlank] + protected $street; + + #[Assert\NotBlank] + #[Assert\Length(max: 5)] + protected $zipCode; + } + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\NotBlank] + #[Assert\Length(min: 4)] + protected $firstName; + + #[Assert\NotBlank] + protected $lastName; + + protected $address; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -196,6 +227,19 @@ an invalid address. To prevent that, add the ``Valid`` constraint to the protected $address; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Valid] + protected $address; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -243,6 +287,11 @@ the validation of the ``Address`` fields failed. App\Entity\Author.address.zipCode: This value is too long. It should have 5 characters or less. +.. tip:: + + If you also want to validate that the ``address`` property is an instance of + the ``App\Entity\Address`` class, add the :doc:`Type constraint `. + Options ------- @@ -250,8 +299,8 @@ Options .. include:: /reference/constraints/_payload-option.rst.inc -traverse -~~~~~~~~ +``traverse`` +~~~~~~~~~~~~ **type**: ``boolean`` **default**: ``true`` diff --git a/reference/constraints/_normalizer-option.rst.inc b/reference/constraints/_normalizer-option.rst.inc index 784f915ff95..dcbba1c2da8 100644 --- a/reference/constraints/_normalizer-option.rst.inc +++ b/reference/constraints/_normalizer-option.rst.inc @@ -1,5 +1,5 @@ -normalizer -~~~~~~~~~~ +``normalizer`` +~~~~~~~~~~~~~~ **type**: a `PHP callable`_ **default**: ``null`` diff --git a/reference/constraints/_null-values-are-valid.rst.inc b/reference/constraints/_null-values-are-valid.rst.inc new file mode 100644 index 00000000000..49b6a54faad --- /dev/null +++ b/reference/constraints/_null-values-are-valid.rst.inc @@ -0,0 +1,6 @@ +.. note:: + + As with most of the other constraints, ``null`` is + considered a valid value. This is to allow the use of optional values. + If the value is mandatory, a common solution is to combine this constraint + with :doc:`NotNull `. diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index 020e84cde65..9f8eb4b8c3f 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -22,11 +22,13 @@ String Constraints * :doc:`Regex ` * :doc:`Hostname ` * :doc:`Ip ` +* :doc:`Cidr ` * :doc:`Json ` * :doc:`Uuid ` * :doc:`Ulid ` * :doc:`UserPassword ` * :doc:`NotCompromisedPassword ` +* :doc:`CssColor ` Comparison Constraints ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/reference/dic_tags.rst b/reference/dic_tags.rst index 0aca3c91777..fd84a0ac70b 100644 --- a/reference/dic_tags.rst +++ b/reference/dic_tags.rst @@ -5,50 +5,63 @@ Built-in Symfony Service Tags :doc:`DependencyInjection component ` to flag services that require special processing, like console commands or Twig extensions. -These are the most common tags provided by Symfony components, but in your -application there could be more tags available provided by third-party bundles: - -======================================== ======================================================================== -Tag Name Usage -======================================== ======================================================================== -`auto_alias`_ Define aliases based on the value of container parameters -`console.command`_ Add a command -`container.hot_path`_ Add to list of always needed services -`container.no_preload`_ Remove a class from the list of classes preloaded by PHP -`container.preload`_ Add some class to the list of classes preloaded by PHP -`controller.argument_value_resolver`_ Register a value resolver for controller arguments such as ``Request`` -`data_collector`_ Create a class that collects custom data for the profiler -`doctrine.event_listener`_ Add a Doctrine event listener -`doctrine.event_subscriber`_ Add a Doctrine event subscriber -`form.type`_ Create a custom form field type -`form.type_extension`_ Create a custom "form extension" -`form.type_guesser`_ Add your own logic for "form type guessing" -`kernel.cache_clearer`_ Register your service to be called during the cache clearing process -`kernel.cache_warmer`_ Register your service to be called during the cache warming process -`kernel.event_listener`_ Listen to different events/hooks in Symfony -`kernel.event_subscriber`_ To subscribe to a set of different events/hooks in Symfony -`kernel.fragment_renderer`_ Add new HTTP content rendering strategies -`kernel.reset`_ Allows to clean up services between requests -`mime.mime_type_guesser`_ Add your own logic for guessing MIME types -`monolog.logger`_ Logging with a custom logging channel -`monolog.processor`_ Add a custom processor for logging -`routing.loader`_ Register a custom service that loads routes -`routing.expression_language_provider`_ Register a provider for expression language functions in routing -`security.expression_language_provider`_ Register a provider for expression language functions in security -`security.voter`_ Add a custom voter to Symfony's authorization logic -`security.remember_me_aware`_ To allow remember me authentication -`serializer.encoder`_ Register a new encoder in the ``serializer`` service -`serializer.normalizer`_ Register a new normalizer in the ``serializer`` service -`swiftmailer.default.plugin`_ Register a custom SwiftMailer Plugin -`translation.loader`_ Register a custom service that loads translations -`translation.extractor`_ Register a custom service that extracts translation messages from a file -`translation.dumper`_ Register a custom service that dumps translation messages -`twig.extension`_ Register a custom Twig Extension -`twig.loader`_ Register a custom service that loads Twig templates -`twig.runtime`_ Register a lazy-loaded Twig Extension -`validator.constraint_validator`_ Create your own custom validation constraint -`validator.initializer`_ Register a service that initializes objects before validation -======================================== ======================================================================== +This article shows the most common tags provided by Symfony components, but in +your application there could be more tags available provided by third-party bundles. + +assets.package +-------------- + +**Purpose**: Add an asset package to the application + +.. versionadded:: 5.3 + + The ``assets.package`` tag was introduced in Symfony 5.3. + +This is an alternative way to declare an :ref:`asset package `. +The name of the package is set in this order: + +* first, the ``package`` attribute of the tag; +* then, the value returned by the static method ``getDefaultPackageName()`` if defined; +* finally, the service name. + +.. configuration-block:: + + .. code-block:: yaml + + services: + App\Assets\AvatarPackage: + tags: + - { name: assets.package, package: avatars } + + .. code-block:: xml + + + + + + + + + + + + .. code-block:: php + + use App\Assets\AvatarPackage; + + $container + ->register(AvatarPackage::class) + ->addTag('assets.package', ['package' => 'avatars']) + ; + +Now you can use the ``avatars`` package in your templates: + +.. code-block:: html+twig + + auto_alias ---------- @@ -316,8 +329,8 @@ is restarted): $container ->register(SomeService::class) - ->addTag('container.preload', ['class' => SomeClass::class) - ->addTag('container.preload', ['class' => OtherClass::class) + ->addTag('container.preload', ['class' => SomeClass::class]) + ->addTag('container.preload', ['class' => OtherClass::class]) // ... ; @@ -940,28 +953,6 @@ The priorities of the default normalizers can be found in the :method:`Symfony\\Bundle\\FrameworkBundle\\DependencyInjection\\FrameworkExtension::registerSerializerConfiguration` method. -swiftmailer.default.plugin --------------------------- - -**Purpose**: Register a custom SwiftMailer Plugin - -If you're using a custom SwiftMailer plugin (or want to create one), you -can register it with SwiftMailer by creating a service for your plugin and -tagging it with ``swiftmailer.default.plugin`` (it has no options). - -.. note:: - - ``default`` in this tag is the name of the mailer. If you have multiple - mailers configured or have changed the default mailer name for some - reason, you should change it to the name of your mailer in order to - use this tag. - -A SwiftMailer plugin must implement the ``Swift_Events_EventListener`` interface. -For more information on plugins, see `SwiftMailer's Plugin Documentation`_. - -Several SwiftMailer plugins are core to Symfony and can be activated via -different configuration. For details, see :doc:`/reference/configuration/swiftmailer`. - .. _dic-tags-translation-loader: translation.loader @@ -1030,7 +1021,7 @@ translation.extractor **Purpose**: To register a custom service that extracts messages from a file -When executing the ``translation:update`` command, it uses extractors to +When executing the ``translation:extract`` command, it uses extractors to extract translation messages from a file. By default, the Symfony Framework has a :class:`Symfony\\Bridge\\Twig\\Translation\\TwigExtractor` and a :class:`Symfony\\Component\\Translation\\Extractor\\PhpExtractor`, which @@ -1343,6 +1334,5 @@ For an example, see the ``DoctrineInitializer`` class inside the Doctrine Bridge. .. _`Twig's documentation`: https://twig.symfony.com/doc/2.x/advanced.html#creating-an-extension -.. _`SwiftMailer's Plugin Documentation`: https://swiftmailer.symfony.com/docs/plugins.html .. _`Twig Loader`: https://twig.symfony.com/doc/2.x/api.html#loaders .. _`PHP class preloading`: https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.preload diff --git a/reference/events.rst b/reference/events.rst index 900d40eb12c..75694ab1097 100644 --- a/reference/events.rst +++ b/reference/events.rst @@ -1,10 +1,11 @@ Built-in Symfony Events ======================= -During the handling of an HTTP request, the Symfony framework (or any +The Symfony framework is an HTTP Request-Response one. +During the handling of an HTTP request, the framework (or any application using the :doc:`HttpKernel component `) dispatches some :doc:`events ` which you can use to modify -how the request is handled. +how the request is handled and how the response is returned. Kernel Events ------------- @@ -14,7 +15,7 @@ Each event dispatched by the HttpKernel component is a subclass of following information: :method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::getRequestType` - Returns the *type* of the request (``HttpKernelInterface::MASTER_REQUEST`` + Returns the *type* of the request (``HttpKernelInterface::MAIN_REQUEST`` or ``HttpKernelInterface::SUB_REQUEST``). :method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::getKernel` @@ -23,8 +24,8 @@ following information: :method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::getRequest` Returns the current ``Request`` being handled. -:method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::isMasterRequest` - Checks if this is a master request. +:method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::isMainRequest` + Checks if this is a main request. .. _kernel-core-request: diff --git a/reference/forms/types.rst b/reference/forms/types.rst index 49d769c8967..eaa0344f141 100644 --- a/reference/forms/types.rst +++ b/reference/forms/types.rst @@ -23,6 +23,7 @@ Form Types Reference types/color types/choice + types/enum types/entity types/country types/language @@ -41,6 +42,9 @@ Form Types Reference types/file types/radio + types/uuid + types/ulid + types/collection types/repeated diff --git a/reference/forms/types/birthday.rst b/reference/forms/types/birthday.rst index 6299dbf1e09..f130aa9fc6a 100644 --- a/reference/forms/types/birthday.rst +++ b/reference/forms/types/birthday.rst @@ -14,51 +14,28 @@ This type is essentially the same as the :doc:`DateType `) | -+----------------------+-------------------------------------------------------------------------------+ -| Rendered as | can be three select boxes or 1 or 3 text boxes, based on the `widget`_ option | -+----------------------+-------------------------------------------------------------------------------+ -| Overridden options | - `years`_ | -+----------------------+-------------------------------------------------------------------------------+ -| Inherited options | from the :doc:`DateType `: | -| | | -| | - `choice_translation_domain`_ | -| | - `days`_ | -| | - `placeholder`_ | -| | - `format`_ | -| | - `input`_ | -| | - `input_format`_ | -| | - `model_timezone`_ | -| | - `months`_ | -| | - `view_timezone`_ | -| | - `widget`_ | -| | | -| | from the :doc:`FormType `: | -| | | -| | - `attr`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `inherit_data`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `mapped`_ | -| | - `row_attr`_ | -+----------------------+-------------------------------------------------------------------------------+ -| Parent type | :doc:`DateType ` | -+----------------------+-------------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\BirthdayType` | -+----------------------+-------------------------------------------------------------------------------+ ++---------------------------+-------------------------------------------------------------------------------+ +| Underlying Data Type | can be ``DateTime``, ``string``, ``timestamp``, or ``array`` | +| | (see the :ref:`input option `) | ++---------------------------+-------------------------------------------------------------------------------+ +| Rendered as | can be three select boxes or 1 or 3 text boxes, based on the `widget`_ option | ++---------------------------+-------------------------------------------------------------------------------+ +| Default invalid message | Please enter a valid birthdate. | ++---------------------------+-------------------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+-------------------------------------------------------------------------------+ +| Parent type | :doc:`DateType ` | ++---------------------------+-------------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\BirthdayType` | ++---------------------------+-------------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc Overridden Options ------------------ +.. include:: /reference/forms/types/options/invalid_message.rst.inc + ``years`` ~~~~~~~~~ @@ -95,7 +72,7 @@ values for the year, month and day fields:: $builder->add('birthdate', BirthdayType::class, [ 'placeholder' => [ 'year' => 'Year', 'month' => 'Month', 'day' => 'Day', - ] + ], ]); .. include:: /reference/forms/types/options/date_format.rst.inc @@ -128,8 +105,6 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/inherit_data.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/mapped.rst.inc diff --git a/reference/forms/types/button.rst b/reference/forms/types/button.rst index 655d515215b..5c490a79dca 100644 --- a/reference/forms/types/button.rst +++ b/reference/forms/types/button.rst @@ -9,15 +9,6 @@ A simple, non-responsive button. +----------------------+----------------------------------------------------------------------+ | Rendered as | ``button`` tag | +----------------------+----------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `attr_translation_parameters`_ | -| | - `disabled`_ | -| | - `label`_ | -| | - `label_html`_ | -| | - `label_translation_parameters`_ | -| | - `row_attr`_ | -| | - `translation_domain`_ | -+----------------------+----------------------------------------------------------------------+ | Parent type | none | +----------------------+----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\ButtonType` | diff --git a/reference/forms/types/checkbox.rst b/reference/forms/types/checkbox.rst index aef03ef1e44..a27637bff4b 100644 --- a/reference/forms/types/checkbox.rst +++ b/reference/forms/types/checkbox.rst @@ -11,34 +11,17 @@ you can specify an array of values that, if submitted, will be evaluated to "false" as well (this differs from what HTTP defines, but can be handy if you want to handle submitted values like "0" or "false"). -+-------------+------------------------------------------------------------------------+ -| Rendered as | ``input`` ``checkbox`` field | -+-------------+------------------------------------------------------------------------+ -| Options | - `false_values`_ | -| | - `value`_ | -+-------------+------------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | - `empty_data`_ | -+-------------+------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CheckboxType` | -+-------------+------------------------------------------------------------------------+ ++---------------------------+------------------------------------------------------------------------+ +| Rendered as | ``input`` ``checkbox`` field | ++---------------------------+------------------------------------------------------------------------+ +| Default invalid message | The checkbox has an invalid value. | ++---------------------------+------------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+------------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CheckboxType` | ++---------------------------+------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -74,6 +57,8 @@ Overridden Options .. include:: /reference/forms/types/options/checkbox_empty_data.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/choice.rst b/reference/forms/types/choice.rst index 04efd2fe02c..2581f7b7af7 100644 --- a/reference/forms/types/choice.rst +++ b/reference/forms/types/choice.rst @@ -9,52 +9,17 @@ It can be rendered as a ``select`` tag, radio buttons, or checkboxes. To use this field, you must specify *either* ``choices`` or ``choice_loader`` option. -+-------------+------------------------------------------------------------------------------+ -| Rendered as | can be various tags (see below) | -+-------------+------------------------------------------------------------------------------+ -| Options | - `choices`_ | -| | - `choice_attr`_ | -| | - `choice_filter`_ | -| | - `choice_label`_ | -| | - `choice_loader`_ | -| | - `choice_name`_ | -| | - `choice_translation_domain`_ | -| | - `choice_value`_ | -| | - `expanded`_ | -| | - `group_by`_ | -| | - `multiple`_ | -| | - `placeholder`_ | -| | - `preferred_choices`_ | -+-------------+------------------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `trim`_ | -+-------------+------------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `by_reference`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `inherit_data`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `translation_domain`_ | -| | - `label_translation_parameters`_ | -| | - `attr_translation_parameters`_ | -| | - `help_translation_parameters`_ | -+-------------+------------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+------------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\ChoiceType` | -+-------------+------------------------------------------------------------------------------+ ++---------------------------+----------------------------------------------------------------------+ +| Rendered as | can be various tags (see below) | ++---------------------------+----------------------------------------------------------------------+ +| Default invalid message | The selected choice is invalid. | ++---------------------------+----------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+----------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\ChoiceType` | ++---------------------------+----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -227,6 +192,8 @@ correct types will be assigned to the model. .. include:: /reference/forms/types/options/choice_translation_domain_enabled.rst.inc +.. include:: /reference/forms/types/options/choice_translation_parameters.rst.inc + .. include:: /reference/forms/types/options/choice_value.rst.inc .. include:: /reference/forms/types/options/expanded.rst.inc @@ -250,8 +217,7 @@ compound This option specifies if a form is compound. The value is by default overridden by the value of the ``expanded`` option. -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The actual default value of this option depends on other field options: @@ -259,8 +225,7 @@ The actual default value of this option depends on other field options: (empty string); * Otherwise ``[]`` (empty array). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc error_bubbling ~~~~~~~~~~~~~~ @@ -272,6 +237,8 @@ the parent field (the form in most cases). .. include:: /reference/forms/types/options/choice_type_trim.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/collection.rst b/reference/forms/types/collection.rst index f3f0c8f4562..c5572f93c6b 100644 --- a/reference/forms/types/collection.rst +++ b/reference/forms/types/collection.rst @@ -11,37 +11,17 @@ forms, which is useful when creating forms that expose one-to-many relationships (e.g. a product from where you can manage many related product photos). -+-------------+-----------------------------------------------------------------------------+ -| Rendered as | depends on the `entry_type`_ option | -+-------------+-----------------------------------------------------------------------------+ -| Options | - `allow_add`_ | -| | - `allow_delete`_ | -| | - `delete_empty`_ | -| | - `entry_options`_ | -| | - `entry_type`_ | -| | - `prototype`_ | -| | - `prototype_data`_ | -| | - `prototype_name`_ | -+-------------+-----------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `by_reference`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+-----------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+-----------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CollectionType` | -+-------------+-----------------------------------------------------------------------------+ ++---------------------------+--------------------------------------------------------------------------+ +| Rendered as | depends on the `entry_type`_ option | ++---------------------------+--------------------------------------------------------------------------+ +| Default invalid message | The collection is invalid. | ++---------------------------+--------------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+--------------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+--------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CollectionType` | ++---------------------------+--------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -396,6 +376,11 @@ If you have several collections in your form, or worse, nested collections you may want to change the placeholder so that unrelated placeholders are not replaced with the same value. +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -408,13 +393,11 @@ Not all options are listed here - only the most applicable to this type: .. include:: /reference/forms/types/options/by_reference.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``[]`` (empty array). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc error_bubbling ~~~~~~~~~~~~~~ diff --git a/reference/forms/types/color.rst b/reference/forms/types/color.rst index a290b31e673..213c88323cc 100644 --- a/reference/forms/types/color.rst +++ b/reference/forms/types/color.rst @@ -14,32 +14,17 @@ The value of the underlying ```` field is always a That's why it's not possible to select semi-transparent colors with this element. -+-------------+---------------------------------------------------------------------+ -| Rendered as | ``input`` ``color`` field (a text box) | -+-------------+---------------------------------------------------------------------+ -| Options | - `html5`_ | -+-------------+---------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `trim`_ | -+-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | -+-------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\ColorType` | -+-------------+---------------------------------------------------------------------+ ++---------------------------+---------------------------------------------------------------------+ +| Rendered as | ``input`` ``color`` field (a text box) | ++---------------------------+---------------------------------------------------------------------+ +| Default invalid message | Please select a valid color. | ++---------------------------+---------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+---------------------------------------------------------------------+ +| Parent type | :doc:`TextType ` | ++---------------------------+---------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\ColorType` | ++---------------------------+---------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -49,7 +34,7 @@ Field Options html5 ~~~~~ -**type**: ``bool`` **default**: ``false`` +**type**: ``boolean`` **default**: ``false`` .. versionadded:: 5.1 @@ -59,6 +44,11 @@ When this option is set to ``true``, the form type checks that its value matches the `HTML5 color format`_ (``/^#[0-9a-f]{6}$/i``). If it doesn't match it, you'll see the following error message: *"This value is not a valid HTML5 color"*. +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -70,13 +60,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``''`` (the empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc diff --git a/reference/forms/types/country.rst b/reference/forms/types/country.rst index f4082e498e8..4362cefd0d0 100644 --- a/reference/forms/types/country.rst +++ b/reference/forms/types/country.rst @@ -18,45 +18,17 @@ Unlike the ``ChoiceType``, you don't need to specify a ``choices`` option as the field type automatically uses all of the countries of the world. You *can* specify the option manually, but then you should just use the ``ChoiceType`` directly. -+-------------+-----------------------------------------------------------------------+ -| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | -+-------------+-----------------------------------------------------------------------+ -| Options | - `alpha3`_ | -| | - `choice_translation_locale`_ | -+-------------+-----------------------------------------------------------------------+ -| Overridden | - `choices`_ | -| options | - `choice_translation_domain`_ | -+-------------+-----------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType ` | -| options | | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `expanded`_ | -| | - `multiple`_ | -| | - `placeholder`_ | -| | - `preferred_choices`_ | -| | - `trim`_ | -| | | -| | from the :doc:`FormType ` | -| | | -| | - `attr`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+-----------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | -+-------------+-----------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CountryType` | -+-------------+-----------------------------------------------------------------------+ ++---------------------------+-----------------------------------------------------------------------+ +| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | ++---------------------------+-----------------------------------------------------------------------+ +| Default invalid message | Please select a valid country. | ++---------------------------+-----------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------+ +| Parent type | :doc:`ChoiceType ` | ++---------------------------+-----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CountryType` | ++---------------------------+-----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -92,6 +64,8 @@ The locale is used to translate the countries names. .. include:: /reference/forms/types/options/choice_translation_domain_disabled.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -119,8 +93,7 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The actual default value of this option depends on other field options: @@ -128,8 +101,7 @@ The actual default value of this option depends on other field options: (empty string); * Otherwise ``[]`` (empty array). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/help.rst.inc diff --git a/reference/forms/types/currency.rst b/reference/forms/types/currency.rst index 77da0481942..7ffa36a4f73 100644 --- a/reference/forms/types/currency.rst +++ b/reference/forms/types/currency.rst @@ -11,43 +11,17 @@ Unlike the ``ChoiceType``, you don't need to specify a ``choices`` option as the field type automatically uses a large list of currencies. You *can* specify the option manually, but then you should just use the ``ChoiceType`` directly. -+-------------+------------------------------------------------------------------------+ -| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | -+-------------+------------------------------------------------------------------------+ -| Options | - `choice_translation_locale`_ | -+-------------+------------------------------------------------------------------------+ -| Overridden | - `choices`_ | -| options | - `choice_translation_domain`_ | -+-------------+------------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType ` | -| options | | -| | - `error_bubbling`_ | -| | - `expanded`_ | -| | - `multiple`_ | -| | - `placeholder`_ | -| | - `preferred_choices`_ | -| | - `trim`_ | -| | | -| | from the :doc:`FormType ` type | -| | | -| | - `attr`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | -+-------------+------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CurrencyType` | -+-------------+------------------------------------------------------------------------+ ++---------------------------+------------------------------------------------------------------------+ +| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | ++---------------------------+------------------------------------------------------------------------+ +| Default invalid message | Please select a valid currency. | ++---------------------------+------------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+------------------------------------------------------------------------+ +| Parent type | :doc:`ChoiceType ` | ++---------------------------+------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CurrencyType` | ++---------------------------+------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -73,6 +47,8 @@ The choices option defaults to all currencies. .. include:: /reference/forms/types/options/choice_translation_domain_disabled.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -98,8 +74,7 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The actual default value of this option depends on other field options: @@ -107,8 +82,7 @@ The actual default value of this option depends on other field options: (empty string); * Otherwise ``[]`` (empty array). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/help.rst.inc diff --git a/reference/forms/types/date.rst b/reference/forms/types/date.rst index 582b5bef6ff..22a64567a08 100644 --- a/reference/forms/types/date.rst +++ b/reference/forms/types/date.rst @@ -10,46 +10,19 @@ different HTML elements. This field can be rendered in a variety of different ways via the `widget`_ option and can understand a number of different input formats via the `input`_ option. -+----------------------+-----------------------------------------------------------------------------+ -| Underlying Data Type | can be ``DateTime``, string, timestamp, or array (see the ``input`` option) | -+----------------------+-----------------------------------------------------------------------------+ -| Rendered as | single text box or three select fields | -+----------------------+-----------------------------------------------------------------------------+ -| Options | - `days`_ | -| | - `placeholder`_ | -| | - `format`_ | -| | - `html5`_ | -| | - `input`_ | -| | - `input_format`_ | -| | - `model_timezone`_ | -| | - `months`_ | -| | - `view_timezone`_ | -| | - `widget`_ | -| | - `years`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Overridden options | - `by_reference`_ | -| | - `choice_translation_domain`_ | -| | - `compound`_ | -| | - `data_class`_ | -| | - `error_bubbling`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `inherit_data`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `mapped`_ | -| | - `row_attr`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+----------------------+-----------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateType` | -+----------------------+-----------------------------------------------------------------------------+ ++---------------------------+-----------------------------------------------------------------------------+ +| Underlying Data Type | can be ``DateTime``, string, timestamp, or array (see the ``input`` option) | ++---------------------------+-----------------------------------------------------------------------------+ +| Rendered as | single text box or three select fields | ++---------------------------+-----------------------------------------------------------------------------+ +| Default invalid message | Please enter a valid date. | ++---------------------------+-----------------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+-----------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateType` | ++---------------------------+-----------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -164,7 +137,7 @@ values for the year, month and day fields:: $builder->add('dueDate', DateType::class, [ 'placeholder' => [ 'year' => 'Year', 'month' => 'Month', 'day' => 'Day', - ] + ], ]); .. _reference-forms-type-date-format: @@ -210,6 +183,8 @@ The ``DateTime`` classes are treated as immutable objects. **default**: ``false`` +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -231,8 +206,6 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/inherit_data.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/mapped.rst.inc diff --git a/reference/forms/types/dateinterval.rst b/reference/forms/types/dateinterval.rst index 84986f93c87..d625c058836 100644 --- a/reference/forms/types/dateinterval.rst +++ b/reference/forms/types/dateinterval.rst @@ -12,47 +12,19 @@ The field can be rendered in a variety of different ways (see `widget`_) and can give you a ``DateInterval`` object, an `ISO 8601`_ duration string (e.g. ``P1DT12H``) or an array (see `input`_). -+----------------------+----------------------------------------------------------------------------------+ -| Underlying Data Type | can be ``DateInterval``, string or array (see the ``input`` option) | -+----------------------+----------------------------------------------------------------------------------+ -| Rendered as | single text box, multiple text boxes or select fields - see the `widget`_ option | -+----------------------+----------------------------------------------------------------------------------+ -| Options | - `days`_ | -| | - `hours`_ | -| | - `minutes`_ | -| | - `months`_ | -| | - `seconds`_ | -| | - `weeks`_ | -| | - `input`_ | -| | - `labels`_ | -| | - `placeholder`_ | -| | - `widget`_ | -| | - `with_days`_ | -| | - `with_hours`_ | -| | - `with_invert`_ | -| | - `with_minutes`_ | -| | - `with_months`_ | -| | - `with_seconds`_ | -| | - `with_weeks`_ | -| | - `with_years`_ | -| | - `years`_ | -+----------------------+----------------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `inherit_data`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `mapped`_ | -| | - `row_attr`_ | -+----------------------+----------------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+----------------------+----------------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateIntervalType` | -+----------------------+----------------------------------------------------------------------------------+ ++---------------------------+----------------------------------------------------------------------------------+ +| Underlying Data Type | can be ``DateInterval``, string or array (see the ``input`` option) | ++---------------------------+----------------------------------------------------------------------------------+ +| Rendered as | single text box, multiple text boxes or select fields - see the `widget`_ option | ++---------------------------+----------------------------------------------------------------------------------+ +| Default invalid message | Please choose a valid date interval. | ++---------------------------+----------------------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+----------------------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+----------------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateIntervalType` | ++---------------------------+----------------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -108,7 +80,7 @@ add a "blank" entry to the top of each select box:: Alternatively, you can specify a string to be displayed for the "blank" value:: $builder->add('remindEvery', DateIntervalType::class, [ - 'placeholder' => ['years' => 'Years', 'months' => 'Months', 'days' => 'Days'] + 'placeholder' => ['years' => 'Years', 'months' => 'Months', 'days' => 'Days'], ]); ``hours`` @@ -333,6 +305,11 @@ when the ``widget`` option is set to ``choice``:: // values displayed to users range from 1 to 100 (both inclusive) 'years' => array_combine(range(1, 100), range(1, 100)), +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -352,8 +329,6 @@ These options inherit from the :doc:`form ` type: .. include:: /reference/forms/types/options/inherit_data.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/mapped.rst.inc diff --git a/reference/forms/types/datetime.rst b/reference/forms/types/datetime.rst index ad56b6e2d52..8d1e43da07e 100644 --- a/reference/forms/types/datetime.rst +++ b/reference/forms/types/datetime.rst @@ -10,55 +10,19 @@ date and time (e.g. ``1984-06-05 12:15:30``). Can be rendered as a text input or select tags. The underlying format of the data can be a ``DateTime`` object, a string, a timestamp or an array. -+----------------------+-----------------------------------------------------------------------------+ -| Underlying Data Type | can be ``DateTime``, string, timestamp, or array (see the ``input`` option) | -+----------------------+-----------------------------------------------------------------------------+ -| Rendered as | single text box or three select fields | -+----------------------+-----------------------------------------------------------------------------+ -| Options | - `choice_translation_domain`_ | -| | - `date_format`_ | -| | - `date_label`_ | -| | - `date_widget`_ | -| | - `days`_ | -| | - `placeholder`_ | -| | - `format`_ | -| | - `hours`_ | -| | - `html5`_ | -| | - `input`_ | -| | - `input_format`_ | -| | - `minutes`_ | -| | - `model_timezone`_ | -| | - `months`_ | -| | - `seconds`_ | -| | - `time_label`_ | -| | - `time_widget`_ | -| | - `view_timezone`_ | -| | - `widget`_ | -| | - `with_minutes`_ | -| | - `with_seconds`_ | -| | - `years`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Overridden options | - `by_reference`_ | -| | - `compound`_ | -| | - `data_class`_ | -| | - `error_bubbling`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `inherit_data`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `mapped`_ | -| | - `row_attr`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+----------------------+-----------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateTimeType` | -+----------------------+-----------------------------------------------------------------------------+ ++---------------------------+-----------------------------------------------------------------------------+ +| Underlying Data Type | can be ``DateTime``, string, timestamp, or array (see the ``input`` option) | ++---------------------------+-----------------------------------------------------------------------------+ +| Rendered as | single text box or three select fields | ++---------------------------+-----------------------------------------------------------------------------+ +| Default invalid message | Please enter a valid date and time. | ++---------------------------+-----------------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+-----------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateTimeType` | ++---------------------------+-----------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -121,7 +85,7 @@ values for the year, month, day, hour, minute and second fields:: 'placeholder' => [ 'year' => 'Year', 'month' => 'Month', 'day' => 'Day', 'hour' => 'Hour', 'minute' => 'Minute', 'second' => 'Second', - ] + ], ]); format @@ -231,6 +195,8 @@ error_bubbling **default**: ``false`` +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -250,8 +216,6 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/inherit_data.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/mapped.rst.inc diff --git a/reference/forms/types/email.rst b/reference/forms/types/email.rst index 74eeaa95272..e27898386d4 100644 --- a/reference/forms/types/email.rst +++ b/reference/forms/types/email.rst @@ -7,33 +7,25 @@ EmailType Field The ``EmailType`` field is a text field that is rendered using the HTML5 ```` tag. -+-------------+---------------------------------------------------------------------+ -| Rendered as | ``input`` ``email`` field (a text box) | -+-------------+---------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `trim`_ | -+-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | -+-------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\EmailType` | -+-------------+---------------------------------------------------------------------+ ++---------------------------+---------------------------------------------------------------------+ +| Rendered as | ``input`` ``email`` field (a text box) | ++---------------------------+---------------------------------------------------------------------+ +| Default invalid message | Please enter a valid email address. | ++---------------------------+---------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+---------------------------------------------------------------------+ +| Parent type | :doc:`TextType ` | ++---------------------------+---------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\EmailType` | ++---------------------------+---------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -45,13 +37,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``''`` (the empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc diff --git a/reference/forms/types/entity.rst b/reference/forms/types/entity.rst index 21183ad4e57..6adaa9df79f 100644 --- a/reference/forms/types/entity.rst +++ b/reference/forms/types/entity.rst @@ -12,49 +12,6 @@ objects from the database. +-------------+------------------------------------------------------------------+ | Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | +-------------+------------------------------------------------------------------+ -| Options | - `choice_label`_ | -| | - `class`_ | -| | - `em`_ | -| | - `query_builder`_ | -+-------------+------------------------------------------------------------------+ -| Overridden | - `choice_name`_ | -| options | - `choice_value`_ | -| | - `choices`_ | -| | - `data_class`_ | -+-------------+------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType `: | -| options | | -| | - `choice_attr`_ | -| | - `choice_translation_domain`_ | -| | - `expanded`_ | -| | - `group_by`_ | -| | - `multiple`_ | -| | - `placeholder`_ | -| | - `preferred_choices`_ | -| | - `translation_domain`_ | -| | - `trim`_ | -| | | -| | from the :doc:`FormType `: | -| | | -| | - `attr`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `label_translation_parameters`_ | -| | - `attr_translation_parameters`_ | -| | - `help_translation_parameters`_ | -+-------------+------------------------------------------------------------------+ | Parent type | :doc:`ChoiceType ` | +-------------+------------------------------------------------------------------+ | Class | :class:`Symfony\\Bridge\\Doctrine\\Form\\Type\\EntityType` | @@ -182,7 +139,7 @@ more details, see the main :ref:`choice_label ` doc When passing a string, the ``choice_label`` option is a property path. So you can use anything supported by the - :doc:`PropertyAccessor component ` + :doc:`PropertyAccess component ` For example, if the translations property is actually an associative array of objects, each with a ``name`` property, then you could do this:: @@ -331,8 +288,7 @@ type: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The actual default value of this option depends on other field options: @@ -340,8 +296,7 @@ The actual default value of this option depends on other field options: (empty string); * Otherwise ``[]`` (empty array). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc diff --git a/reference/forms/types/enum.rst b/reference/forms/types/enum.rst new file mode 100644 index 00000000000..51fefe016f0 --- /dev/null +++ b/reference/forms/types/enum.rst @@ -0,0 +1,119 @@ +.. index:: + single: Forms; Fields; EnumType + +EnumType Field +============== + +.. versionadded:: 5.4 + + The ``EnumType`` form field was introduced in Symfony 5.4. + +A multi-purpose field used to allow the user to "choose" one or more options +defined in a `PHP enumeration`_. It extends the :doc:`ChoiceType ` +field and defines the same options. + ++---------------------------+----------------------------------------------------------------------+ +| Rendered as | can be various tags (see below) | ++---------------------------+----------------------------------------------------------------------+ +| Default invalid message | The selected choice is invalid. | ++---------------------------+----------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+----------------------------------------------------------------------+ +| Parent type | :doc:`ChoiceType ` | ++---------------------------+----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\EnumType` | ++---------------------------+----------------------------------------------------------------------+ + +.. include:: /reference/forms/types/options/_debug_form.rst.inc + +Example Usage +------------- + +Before using this field, you'll need to have some PHP enumeration (or "enum" for +short) defined somewhere in your application. This enum has to be of type +"backed enum", where each keyword defines a scalar value such as a string:: + + // src/Config/TextAlign.php + namespace App\Config; + + enum TextAlign + { + case Left = 'Left/Start aligned'; + case Center = 'Center/Middle aligned'; + case Right = 'Right/End aligned'; + } + +Instead of using the values of the enumeration in a ``choices`` option, the +``EnumType`` only requires to define the ``class`` option pointing to the enum:: + + use App\Config\TextAlign; + use Symfony\Component\Form\Extension\Core\Type\EnumType; + // ... + + $builder->add('alignment', EnumType::class, ['class' => TextAlign::class]); + +This will display a ```` or ````. + +Field Options +------------- + +class +~~~~~ + +**type**: ``string`` **default**: (it has no default) + +The fully-qualified class name (FQCN) of the PHP enum used to get the values +displayed by this form field. + +Inherited Options +----------------- + +These options inherit from the :doc:`ChoiceType `: + +.. include:: /reference/forms/types/options/error_bubbling.rst.inc + +.. include:: /reference/forms/types/options/error_mapping.rst.inc + +.. include:: /reference/forms/types/options/expanded.rst.inc + +.. include:: /reference/forms/types/options/multiple.rst.inc + +.. include:: /reference/forms/types/options/placeholder.rst.inc + +.. include:: /reference/forms/types/options/preferred_choices.rst.inc + +.. include:: /reference/forms/types/options/choice_type_trim.rst.inc + +These options inherit from the :doc:`FormType `: + +.. include:: /reference/forms/types/options/attr.rst.inc + +.. include:: /reference/forms/types/options/data.rst.inc + +.. include:: /reference/forms/types/options/disabled.rst.inc + +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc + +.. include:: /reference/forms/types/options/empty_data_description.rst.inc + +.. include:: /reference/forms/types/options/help.rst.inc + +.. include:: /reference/forms/types/options/help_attr.rst.inc + +.. include:: /reference/forms/types/options/help_html.rst.inc + +.. include:: /reference/forms/types/options/label.rst.inc + +.. include:: /reference/forms/types/options/label_attr.rst.inc + +.. include:: /reference/forms/types/options/label_format.rst.inc + +.. include:: /reference/forms/types/options/mapped.rst.inc + +.. include:: /reference/forms/types/options/required.rst.inc + +.. include:: /reference/forms/types/options/row_attr.rst.inc + +.. _`PHP enumeration`: https://www.php.net/manual/language.enumerations.php diff --git a/reference/forms/types/file.rst b/reference/forms/types/file.rst index 66a18560577..fc2836cd2cf 100644 --- a/reference/forms/types/file.rst +++ b/reference/forms/types/file.rst @@ -6,33 +6,17 @@ FileType Field The ``FileType`` represents a file input in your form. -+-------------+---------------------------------------------------------------------+ -| Rendered as | ``input`` ``file`` field | -+-------------+---------------------------------------------------------------------+ -| Options | - `multiple`_ | -+-------------+---------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | - `data_class`_ | -| | - `empty_data`_ | -+-------------+---------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `disabled`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\FileType` | -+-------------+---------------------------------------------------------------------+ ++---------------------------+--------------------------------------------------------------------+ +| Rendered as | ``input`` ``file`` field | ++---------------------------+--------------------------------------------------------------------+ +| Default invalid message | Please select a valid file. | ++---------------------------+--------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+--------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+--------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\FileType` | ++---------------------------+--------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -120,6 +104,11 @@ This option sets the appropriate file-related data mapper to be used by the type This option determines what value the field will return when the submitted value is empty. +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/form.rst b/reference/forms/types/form.rst index 8a0c219f410..b38fd5ac5b8 100644 --- a/reference/forms/types/form.rst +++ b/reference/forms/types/form.rst @@ -7,51 +7,15 @@ FormType Field The ``FormType`` predefines a couple of options that are then available on all types for which ``FormType`` is the parent. -+-----------+--------------------------------------------------------------------+ -| Options | - `action`_ | -| | - `allow_extra_fields`_ | -| | - `by_reference`_ | -| | - `compound`_ | -| | - `constraints`_ | -| | - `data`_ | -| | - `data_class`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `extra_fields_message`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `help_translation_parameters`_ | -| | - `inherit_data`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `method`_ | -| | - `post_max_size_message`_ | -| | - `property_path`_ | -| | - `required`_ | -| | - `trim`_ | -| | - `validation_groups`_ | -+-----------+--------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `auto_initialize`_ | -| | - `block_name`_ | -| | - `block_prefix`_ | -| | - `disabled`_ | -| | - `label`_ | -| | - `label_html`_ | -| | - `row_attr`_ | -| | - `translation_domain`_ | -| | - `label_translation_parameters`_ | -| | - `attr_translation_parameters`_ | -+-----------+--------------------------------------------------------------------+ -| Parent | none | -+-----------+--------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\FormType` | -+-----------+--------------------------------------------------------------------+ ++---------------------------+--------------------------------------------------------------------+ +| Default invalid message | This value is not valid. | ++---------------------------+--------------------------------------------------------------------+ +| Legacy invalid message | This value is not valid. | ++---------------------------+--------------------------------------------------------------------+ +| Parent | none | ++---------------------------+--------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\FormType` | ++---------------------------+--------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -89,8 +53,7 @@ option on the form. .. _reference-form-option-empty-data: -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The actual default value of this option depends on other field options: @@ -101,8 +64,7 @@ The actual default value of this option depends on other field options: * If ``data_class`` is not set and ``compound`` is ``false``, then ``''`` (empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. _reference-form-option-error-bubbling: @@ -112,6 +74,8 @@ The actual default value of this option depends on other field options: .. include:: /reference/forms/types/options/extra_fields_message.rst.inc +.. include:: /reference/forms/types/options/form_attr.rst.inc + .. include:: /reference/forms/types/options/help.rst.inc .. include:: /reference/forms/types/options/help_attr.rst.inc @@ -171,8 +135,12 @@ of the form type tree (i.e. it cannot be used as a form type on its own). .. include:: /reference/forms/types/options/disabled.rst.inc +.. _reference-form-option-label: + .. include:: /reference/forms/types/options/label.rst.inc +.. _reference-form-option-label-html: + .. include:: /reference/forms/types/options/label_html.rst.inc .. include:: /reference/forms/types/options/row_attr.rst.inc @@ -182,3 +150,5 @@ of the form type tree (i.e. it cannot be used as a form type on its own). .. include:: /reference/forms/types/options/label_translation_parameters.rst.inc .. include:: /reference/forms/types/options/attr_translation_parameters.rst.inc + +.. include:: /reference/forms/types/options/priority.rst.inc diff --git a/reference/forms/types/hidden.rst b/reference/forms/types/hidden.rst index 1a74e107555..4a5a449ae60 100644 --- a/reference/forms/types/hidden.rst +++ b/reference/forms/types/hidden.rst @@ -6,25 +6,17 @@ HiddenType Field The hidden type represents a hidden input field. -+-------------+----------------------------------------------------------------------+ -| Rendered as | ``input`` ``hidden`` field | -+-------------+----------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | - `error_bubbling`_ | -| | - `required`_ | -+-------------+----------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `empty_data`_ | -| | - `error_mapping`_ | -| | - `mapped`_ | -| | - `property_path`_ | -| | - `row_attr`_ | -+-------------+----------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+----------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\HiddenType` | -+-------------+----------------------------------------------------------------------+ ++---------------------------+----------------------------------------------------------------------+ +| Rendered as | ``input`` ``hidden`` field | ++---------------------------+----------------------------------------------------------------------+ +| Default invalid message | The hidden field is invalid. | ++---------------------------+----------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+----------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\HiddenType` | ++---------------------------+----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -40,6 +32,8 @@ Overridden Options Pass errors to the root form, otherwise they will not be visible. +.. include:: /reference/forms/types/options/invalid_message.rst.inc + ``required`` ~~~~~~~~~~~~ @@ -56,13 +50,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/data.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``''`` (the empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_mapping.rst.inc diff --git a/reference/forms/types/integer.rst b/reference/forms/types/integer.rst index fa5660158bc..f4654e96591 100644 --- a/reference/forms/types/integer.rst +++ b/reference/forms/types/integer.rst @@ -13,37 +13,17 @@ This field has different options on how to handle input values that aren't integers. By default, all non-integer values (e.g. 6.78) will round down (e.g. 6). -+-------------+-----------------------------------------------------------------------+ -| Rendered as | ``input`` ``number`` field | -+-------------+-----------------------------------------------------------------------+ -| Options | - `grouping`_ | -| | - `rounding_mode`_ | -+-------------+-----------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | | -+-------------+-----------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+-----------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+-----------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\IntegerType` | -+-------------+-----------------------------------------------------------------------+ ++---------------------------+-----------------------------------------------------------------------+ +| Rendered as | ``input`` ``number`` field | ++---------------------------+-----------------------------------------------------------------------+ +| Default invalid message | Please enter an integer. | ++---------------------------+-----------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+-----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\IntegerType` | ++---------------------------+-----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -55,37 +35,49 @@ Field Options ``rounding_mode`` ~~~~~~~~~~~~~~~~~ -**type**: ``integer`` **default**: ``IntegerToLocalizedStringTransformer::ROUND_DOWN`` +**type**: ``integer`` **default**: ``\NumberFormatter::ROUND_HALFUP`` By default, if the user enters a non-integer number, it will be rounded -down. There are several other rounding methods and each is a constant -on the :class:`Symfony\\Component\\Form\\Extension\\Core\\DataTransformer\\IntegerToLocalizedStringTransformer`: +down. You have several configurable options for that rounding. Each option +is a constant on the :phpclass:`NumberFormatter` class: -* ``IntegerToLocalizedStringTransformer::ROUND_DOWN`` Round towards zero. +* ``\NumberFormatter::ROUND_DOWN`` Round towards zero. It + rounds ``1.4`` to ``1`` and ``-1.4`` to ``-1``. -* ``IntegerToLocalizedStringTransformer::ROUND_FLOOR`` Round towards negative - infinity. +* ``\NumberFormatter::ROUND_FLOOR`` Round towards negative + infinity. It rounds ``1.4`` to ``1`` and ``-1.4`` to ``-2``. -* ``IntegerToLocalizedStringTransformer::ROUND_UP`` Round away from zero. +* ``\NumberFormatter::ROUND_UP`` Round away from zero. It + rounds ``1.4`` to ``2`` and ``-1.4`` to ``-2``. -* ``IntegerToLocalizedStringTransformer::ROUND_CEILING`` Round towards - positive infinity. +* ``\NumberFormatter::ROUND_CEILING`` Round towards positive + infinity. It rounds ``1.4`` to ``2`` and ``-1.4`` to ``-1``. -* ``IntegerToLocalizedStringTransformer::ROUND_HALF_DOWN`` Round towards the - "nearest neighbor". If both neighbors are equidistant, round down. +* ``\NumberFormatter::ROUND_HALFDOWN`` Round towards the + "nearest neighbor". If both neighbors are equidistant, round down. It rounds + ``2.5`` and ``1.6`` to ``2``, ``1.5`` and ``1.4`` to ``1``. -* ``IntegerToLocalizedStringTransformer::ROUND_HALF_EVEN`` Round towards the - "nearest neighbor". If both neighbors are equidistant, round towards the - even neighbor. +* ``\NumberFormatter::ROUND_HALFEVEN`` Round towards the + "nearest neighbor". If both neighbors are equidistant, round towards the even + neighbor. It rounds ``2.5``, ``1.6`` and ``1.5`` to ``2`` and ``1.4`` to ``1``. -* ``IntegerToLocalizedStringTransformer::ROUND_HALF_UP`` Round towards the - "nearest neighbor". If both neighbors are equidistant, round up. +* ``\NumberFormatter::ROUND_HALFUP`` Round towards the + "nearest neighbor". If both neighbors are equidistant, round up. It rounds + ``2.5`` to ``3``, ``1.6`` and ``1.5`` to ``2`` and ``1.4`` to ``1``. + +.. deprecated:: 5.1 + + In Symfony versions prior to 5.1, these constants were also defined as aliases + in the :class:`Symfony\\Component\\Form\\Extension\\Core\\DataTransformer\\NumberToLocalizedStringTransformer` + class, but they are now deprecated in favor of the :phpclass:`NumberFormatter` constants. Overridden Options ------------------ .. include:: /reference/forms/types/options/compound_type.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -97,13 +89,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``''`` (the empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc @@ -115,8 +105,6 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/help_html.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/label.rst.inc diff --git a/reference/forms/types/language.rst b/reference/forms/types/language.rst index 5fa38697701..d95bc28780a 100644 --- a/reference/forms/types/language.rst +++ b/reference/forms/types/language.rst @@ -20,46 +20,17 @@ Unlike the ``ChoiceType``, you don't need to specify a ``choices`` option as the field type automatically uses a large list of languages. You *can* specify the option manually, but then you should just use the ``ChoiceType`` directly. -+-------------+------------------------------------------------------------------------+ -| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | -+-------------+------------------------------------------------------------------------+ -| Options | - `alpha3`_ | -| | - `choice_self_translation`_ | -| | - `choice_translation_locale`_ | -+-------------+------------------------------------------------------------------------+ -| Overridden | - `choices`_ | -| options | - `choice_translation_domain`_ | -+-------------+------------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType ` | -| options | | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `expanded`_ | -| | - `multiple`_ | -| | - `placeholder`_ | -| | - `preferred_choices`_ | -| | - `trim`_ | -| | | -| | from the :doc:`FormType ` | -| | | -| | - `attr`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | -+-------------+------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\LanguageType` | -+-------------+------------------------------------------------------------------------+ ++---------------------------+------------------------------------------------------------------------+ +| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | ++---------------------------+------------------------------------------------------------------------+ +| Default invalid message | Please select a valid language. | ++---------------------------+------------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+------------------------------------------------------------------------+ +| Parent type | :doc:`ChoiceType ` | ++---------------------------+------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\LanguageType` | ++---------------------------+------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -71,7 +42,7 @@ alpha3 **type**: ``boolean`` **default**: ``false`` -If this option is ``true``, the choice values use the `ISO 639-2 alpha-3`_ +If this option is ``true``, the choice values use the `ISO 639-2 alpha-3 (2T)`_ three-letter codes (e.g. French = ``fra``) instead of the default `ISO 639-1 alpha-2`_ two-letter codes (e.g. French = ``fr``). @@ -114,6 +85,8 @@ The default locale is used to translate the languages names. .. include:: /reference/forms/types/options/choice_translation_domain_disabled.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -141,8 +114,7 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The actual default value of this option depends on other field options: @@ -150,8 +122,7 @@ The actual default value of this option depends on other field options: (empty string); * Otherwise ``[]`` (empty array). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/help.rst.inc @@ -172,5 +143,5 @@ The actual default value of this option depends on other field options: .. include:: /reference/forms/types/options/row_attr.rst.inc .. _`ISO 639-1 alpha-2`: https://en.wikipedia.org/wiki/ISO_639-1 -.. _`ISO 639-2 alpha-3`: https://en.wikipedia.org/wiki/ISO_639-2 +.. _`ISO 639-2 alpha-3 (2T)`: https://en.wikipedia.org/wiki/ISO_639-2 .. _`International Components for Unicode`: http://site.icu-project.org diff --git a/reference/forms/types/locale.rst b/reference/forms/types/locale.rst index 385cc4f6fd8..4ee77116489 100644 --- a/reference/forms/types/locale.rst +++ b/reference/forms/types/locale.rst @@ -21,44 +21,17 @@ Unlike the ``ChoiceType``, you don't need to specify a ``choices`` option as the field type automatically uses a large list of locales. You *can* specify these options manually, but then you should just use the ``ChoiceType`` directly. -+-------------+------------------------------------------------------------------------+ -| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | -+-------------+------------------------------------------------------------------------+ -| Options | - `choice_translation_locale`_ | -+-------------+------------------------------------------------------------------------+ -| Overridden | - `choices`_ | -| options | - `choice_translation_domain`_ | -+-------------+------------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType ` | -| options | | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `expanded`_ | -| | - `multiple`_ | -| | - `placeholder`_ | -| | - `preferred_choices`_ | -| | - `trim`_ | -| | | -| | from the :doc:`FormType ` | -| | | -| | - `attr`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | -+-------------+------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\LocaleType` | -+-------------+------------------------------------------------------------------------+ ++---------------------------+----------------------------------------------------------------------+ +| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | ++---------------------------+----------------------------------------------------------------------+ +| Default invalid message | Please select a valid locale. | ++---------------------------+----------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+----------------------------------------------------------------------+ +| Parent type | :doc:`ChoiceType ` | ++---------------------------+----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\LocaleType` | ++---------------------------+----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -85,6 +58,8 @@ specify the language. .. include:: /reference/forms/types/options/choice_translation_domain_disabled.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -112,8 +87,7 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The actual default value of this option depends on other field options: @@ -121,8 +95,7 @@ The actual default value of this option depends on other field options: (empty string); * Otherwise ``[]`` (empty array). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/help.rst.inc diff --git a/reference/forms/types/map.rst.inc b/reference/forms/types/map.rst.inc index 4036f2f7dce..4d1ed612c67 100644 --- a/reference/forms/types/map.rst.inc +++ b/reference/forms/types/map.rst.inc @@ -19,6 +19,7 @@ Choice Fields ~~~~~~~~~~~~~ * :doc:`ChoiceType ` +* :doc:`EnumType ` * :doc:`EntityType ` * :doc:`CountryType ` * :doc:`LanguageType ` @@ -43,6 +44,12 @@ Other Fields * :doc:`FileType ` * :doc:`RadioType ` +UID Fields +~~~~~~~~~~ + +* :doc:`UuidType ` +* :doc:`UlidType ` + Field Groups ~~~~~~~~~~~~ diff --git a/reference/forms/types/money.rst b/reference/forms/types/money.rst index bb91d0b08da..a7fa743846b 100644 --- a/reference/forms/types/money.rst +++ b/reference/forms/types/money.rst @@ -11,41 +11,17 @@ This field type allows you to specify a currency, whose symbol is rendered next to the text field. There are also several other options for customizing how the input and output of the data is handled. -+-------------+---------------------------------------------------------------------+ -| Rendered as | ``input`` ``text`` field | -+-------------+---------------------------------------------------------------------+ -| Options | - `currency`_ | -| | - `divisor`_ | -| | - `grouping`_ | -| | - `html5`_ | -| | - `rounding_mode`_ | -| | - `scale`_ | -+-------------+---------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | | -+-------------+---------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\MoneyType` | -+-------------+---------------------------------------------------------------------+ ++---------------------------+---------------------------------------------------------------------+ +| Rendered as | ``input`` ``text`` field | ++---------------------------+---------------------------------------------------------------------+ +| Default invalid message | Please enter a valid money amount. | ++---------------------------+---------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+---------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+---------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\MoneyType` | ++---------------------------+---------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -122,6 +98,8 @@ Overridden Options .. include:: /reference/forms/types/options/compound_type.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -133,13 +111,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``''`` (the empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc @@ -151,8 +127,6 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/help_html.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/label.rst.inc diff --git a/reference/forms/types/number.rst b/reference/forms/types/number.rst index 599d0efa4cd..eda9189f7e3 100644 --- a/reference/forms/types/number.rst +++ b/reference/forms/types/number.rst @@ -8,40 +8,17 @@ Renders an input text field and specializes in handling number input. This type offers different options for the scale, rounding and grouping that you want to use for your number. -+-------------+----------------------------------------------------------------------+ -| Rendered as | ``input`` ``text`` field | -+-------------+----------------------------------------------------------------------+ -| Options | - `grouping`_ | -| | - `html5`_ | -| | - `input`_ | -| | - `scale`_ | -| | - `rounding_mode`_ | -+-------------+----------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | | -+-------------+----------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+----------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+----------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\NumberType` | -+-------------+----------------------------------------------------------------------+ ++---------------------------+----------------------------------------------------------------------+ +| Rendered as | ``input`` ``text`` field | ++---------------------------+----------------------------------------------------------------------+ +| Default invalid message | Please enter a number. | ++---------------------------+----------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+----------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\NumberType` | ++---------------------------+----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -86,6 +63,8 @@ Overridden Options .. include:: /reference/forms/types/options/compound_type.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -97,13 +76,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``''`` (the empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc @@ -115,8 +92,6 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/help_html.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/label.rst.inc diff --git a/reference/forms/types/options/attr.rst.inc b/reference/forms/types/options/attr.rst.inc index 629902b4fc8..c4bb89d277e 100644 --- a/reference/forms/types/options/attr.rst.inc +++ b/reference/forms/types/options/attr.rst.inc @@ -13,5 +13,5 @@ as keys. This can be useful when you need to set a custom class for some widget: .. seealso:: - Use the ``row_attr`` option if you want to add these attributes to the + Use the ``row_attr`` option if you want to add these attributes to the :ref:`form type row ` element. diff --git a/reference/forms/types/options/choice_attr.rst.inc b/reference/forms/types/options/choice_attr.rst.inc index 1c9f5138d66..5a0add4f195 100644 --- a/reference/forms/types/options/choice_attr.rst.inc +++ b/reference/forms/types/options/choice_attr.rst.inc @@ -13,6 +13,20 @@ If an array, the keys of the ``choices`` array must be used as keys:: use Symfony\Component\Form\Extension\Core\Type\ChoiceType; // ... + $builder->add('fruits', ChoiceType::class, [ + 'choices' => [ + 'Apple' => 1, + 'Banana' => 2, + 'Durian' => 3, + ], + 'choice_attr' => [ + 'Apple' => ['data-color' => 'Red'], + 'Banana' => ['data-color' => 'Yellow'], + 'Durian' => ['data-color' => 'Green'], + ], + ]); + + // or use a callable $builder->add('attending', ChoiceType::class, [ 'choices' => [ 'Yes' => true, @@ -35,7 +49,7 @@ If an array, the keys of the ``choices`` array must be used as keys:: // ... $builder->add('choices', ChoiceType::class, [ - 'choice_label' => ChoiceList::attr($this, function (?Category $category) { + 'choice_attr' => ChoiceList::attr($this, function (?Category $category) { return $category ? ['data-uuid' => $category->getUuid()] : []; }), ]); diff --git a/reference/forms/types/options/choice_translation_parameters.rst.inc b/reference/forms/types/options/choice_translation_parameters.rst.inc new file mode 100644 index 00000000000..a384d38d487 --- /dev/null +++ b/reference/forms/types/options/choice_translation_parameters.rst.inc @@ -0,0 +1,80 @@ +choice_translation_parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``array``, ``callable``, ``string`` or :class:`Symfony\\Component\\PropertyAccess\\PropertyPath` **default**: ``[]`` + +The choice values are translated before displaying it, so it can contain +:ref:`translation placeholders `. +This option defines the values used to replace those placeholders. This can be +an associative array where the keys match the choice keys and the values +are the attributes for each choice, a callable or a property path +(just like `choice_label`_). + +Given this translation message: + +.. configuration-block:: + + .. code-block:: yaml + + # translations/messages.en.yaml + form.order.yes: 'I confirm my order to the company %company%' + form.order.no: 'I cancel my order' + + .. code-block:: xml + + + + + + + + form.order.yes + I confirm my order to the company %company% + + + form.order.no + I cancel my order + + + + + + .. code-block:: php + + // translations/messages.fr.php + return [ + 'form.order.yes' => "I confirm my order to the company %company%", + 'form.order.no' => "I cancel my order", + ]; + +You can specify the placeholder values as follows:: + + $builder->add('id', null, [ + 'choices' => [ + 'form.order.yes' => true, + 'form.order.no' => false, + ], + 'choice_translation_parameters' => function ($choice, $key, $value) { + if (false === $choice) { + return []; + } + + return ['%company%' => 'ACME Inc.'] + }, + ]); + +If an array, the keys of the ``choices`` array must be used as keys:: + + $builder->add('id', null, [ + 'choices' => [ + 'form.order.yes' => true, + 'form.order.no' => false, + ], + 'choice_translation_parameters' => [ + 'form.order.yes' => ['%company%' => 'ACME Inc.'], + 'form.order.no' => [], + ], + ]); + +The translation parameters of child fields are merged with the same option of +their parents, so children can reuse and/or override any of the parent placeholders. diff --git a/reference/forms/types/options/empty_data_declaration.rst.inc b/reference/forms/types/options/empty_data_declaration.rst.inc new file mode 100644 index 00000000000..4db2aa6723e --- /dev/null +++ b/reference/forms/types/options/empty_data_declaration.rst.inc @@ -0,0 +1,4 @@ +``empty_data`` +~~~~~~~~~~~~~~ + +**type**: ``mixed`` diff --git a/reference/forms/types/options/empty_data.rst.inc b/reference/forms/types/options/empty_data_description.rst.inc similarity index 84% rename from reference/forms/types/options/empty_data.rst.inc rename to reference/forms/types/options/empty_data_description.rst.inc index 5e0a23a70b9..90e111fb202 100644 --- a/reference/forms/types/options/empty_data.rst.inc +++ b/reference/forms/types/options/empty_data_description.rst.inc @@ -1,14 +1,3 @@ -``empty_data`` -~~~~~~~~~~~~~~ - -**type**: ``mixed`` - -.. This file should only be included with start-after or end-before that's - set to this placeholder value. Its purpose is to let us include only - part of this file. - -DEFAULT_PLACEHOLDER - This option determines what value the field will *return* when the submitted value is empty (or missing). It does not set an initial value if none is provided when the form is rendered in a view. diff --git a/reference/forms/types/options/form_attr.rst.inc b/reference/forms/types/options/form_attr.rst.inc new file mode 100644 index 00000000000..bb6cb1ca4fd --- /dev/null +++ b/reference/forms/types/options/form_attr.rst.inc @@ -0,0 +1,20 @@ +``form_attr`` +~~~~~~~~~~~~~ + +**type**: ``boolean`` or ``string`` **default**: ``false`` + +When ``true`` and used on a form element, it adds a `"form" attribute`_ to its HTML field representation with +its HTML form id. By doing this, a form element can be rendered outside the HTML form while still working as expected:: + + $builder->add('body', TextareaType::class, [ + 'form_attr' => true, + ]); + +This can be useful when you need to solve nested form problems. +You can also set this to ``true`` on a root form to automatically set the "form" attribute on all its children. + +.. note:: + + When the root form has no ID, ``form_attr`` is required to be a string identifier to be used as the form ID. + +.. _`"form" attribute`: https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fae-form diff --git a/reference/forms/types/options/help.rst.inc b/reference/forms/types/options/help.rst.inc index ded87842d8e..86f84111c88 100644 --- a/reference/forms/types/options/help.rst.inc +++ b/reference/forms/types/options/help.rst.inc @@ -1,11 +1,25 @@ help ~~~~ -**type**: ``string`` **default**: null +**type**: ``string`` or ``TranslatableMessage`` **default**: null Allows you to define a help message for the form field, which by default is rendered below the field:: - $builder->add('zipCode', null, [ - 'help' => 'The ZIP/Postal code for your credit card\'s billing address.', - ]); + use Symfony\Component\Translation\TranslatableMessage; + + $builder + ->add('zipCode', null, [ + 'help' => 'The ZIP/Postal code for your credit card\'s billing address.', + ]) + + // ... + + ->add('status', null, [ + 'help' => new TranslatableMessage('order.status', ['%order_id%' => $order->getId()], 'store'), + ]) + ; + +.. versionadded:: 5.4 + + Support for passing ``TranslatableMessage`` objects was introduced in Symfony 5.4. diff --git a/reference/forms/types/options/help_html.rst.inc b/reference/forms/types/options/help_html.rst.inc index 83bbe583ca6..2a5dccfb32e 100644 --- a/reference/forms/types/options/help_html.rst.inc +++ b/reference/forms/types/options/help_html.rst.inc @@ -1,7 +1,7 @@ help_html ~~~~~~~~~ -**type**: ``bool`` **default**: ``false`` +**type**: ``boolean`` **default**: ``false`` By default, the contents of the ``help`` option are escaped before rendering them in the template. Set this option to ``true`` to not escape them, which is diff --git a/reference/forms/types/options/label.rst.inc b/reference/forms/types/options/label.rst.inc index 9797b6264cf..3d9b6bd1674 100644 --- a/reference/forms/types/options/label.rst.inc +++ b/reference/forms/types/options/label.rst.inc @@ -3,8 +3,8 @@ **type**: ``string`` **default**: The label is "guessed" from the field name -Sets the label that will be used when rendering the field. Setting to false -will suppress the label. The label can also be directly set inside the template: +Sets the label that will be used when rendering the field. Setting to ``false`` +will suppress the label. The label can also be set in the template: .. configuration-block:: diff --git a/reference/forms/types/options/label_html.rst.inc b/reference/forms/types/options/label_html.rst.inc index 06568ed08f4..a87ad4ab6db 100644 --- a/reference/forms/types/options/label_html.rst.inc +++ b/reference/forms/types/options/label_html.rst.inc @@ -1,7 +1,7 @@ ``label_html`` ~~~~~~~~~~~~~~ -**type**: ``bool`` **default**: ``false`` +**type**: ``boolean`` **default**: ``false`` .. versionadded:: 5.1 diff --git a/reference/forms/types/options/preferred_choices.rst.inc b/reference/forms/types/options/preferred_choices.rst.inc index bffb021f864..8cb1278136d 100644 --- a/reference/forms/types/options/preferred_choices.rst.inc +++ b/reference/forms/types/options/preferred_choices.rst.inc @@ -58,7 +58,7 @@ when rendering the field: {{ form_widget(form.publishAt, { 'separator': '=====' }) }} - .. code-block:: php + .. code-block:: html+php widget($form['publishAt'], [ 'separator' => '=====', diff --git a/reference/forms/types/options/priority.rst.inc b/reference/forms/types/options/priority.rst.inc new file mode 100644 index 00000000000..8f53a05c9ab --- /dev/null +++ b/reference/forms/types/options/priority.rst.inc @@ -0,0 +1,16 @@ +priority +~~~~~~~~ + +**type**: ``integer`` **default**: ``0`` + +.. versionadded:: 5.3 + + The ``priority`` option was introduced in Symfony 5.3. + +Fields are rendered in the same order as they are included in the form. This +option changes the field rendering priority, allowing you to display fields +earlier or later than their original order. + +This option will affect the view order only. The higher this priority, the +earlier the field will be rendered. Priority can also be negative and fields +with the same priority will keep their original order. diff --git a/reference/forms/types/options/row_attr.rst.inc b/reference/forms/types/options/row_attr.rst.inc index e8cbaa6b564..f280fc3dfcc 100644 --- a/reference/forms/types/options/row_attr.rst.inc +++ b/reference/forms/types/options/row_attr.rst.inc @@ -12,5 +12,5 @@ to render the :ref:`form type row `:: .. seealso:: - Use the ``attr`` option if you want to add these attributes to the + Use the ``attr`` option if you want to add these attributes to the :ref:`form type widget ` element. diff --git a/reference/forms/types/options/scale.rst.inc b/reference/forms/types/options/scale.rst.inc deleted file mode 100644 index 0d2ec3d6dbc..00000000000 --- a/reference/forms/types/options/scale.rst.inc +++ /dev/null @@ -1,9 +0,0 @@ -``scale`` -~~~~~~~~~ - -**type**: ``integer`` **default**: Locale-specific (usually around ``3``) - -This specifies how many decimals will be allowed until the field rounds -the submitted value (via ``rounding_mode``). For example, if ``scale`` is set -to ``2``, a submitted value of ``20.123`` will be rounded to, for example, -``20.12`` (depending on your `rounding_mode`_). diff --git a/reference/forms/types/password.rst b/reference/forms/types/password.rst index 37acff1a616..d512be22594 100644 --- a/reference/forms/types/password.rst +++ b/reference/forms/types/password.rst @@ -6,33 +6,17 @@ PasswordType Field The ``PasswordType`` field renders an input password text box. -+-------------+------------------------------------------------------------------------+ -| Rendered as | ``input`` ``password`` field | -+-------------+------------------------------------------------------------------------+ -| Options | - `always_empty`_ | -+-------------+------------------------------------------------------------------------+ -| Overridden | - `trim`_ | -| options | | -+-------------+------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | -+-------------+------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\PasswordType` | -+-------------+------------------------------------------------------------------------+ ++---------------------------+------------------------------------------------------------------------+ +| Rendered as | ``input`` ``password`` field | ++---------------------------+------------------------------------------------------------------------+ +| Default invalid message | The password is invalid. | ++---------------------------+------------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+------------------------------------------------------------------------+ +| Parent type | :doc:`TextType ` | ++---------------------------+------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\PasswordType` | ++---------------------------+------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -54,6 +38,8 @@ entered into the box, set this to false and submit the form. Overridden Options ------------------ +.. include:: /reference/forms/types/options/invalid_message.rst.inc + ``trim`` ~~~~~~~~ @@ -73,13 +59,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``''`` (the empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc diff --git a/reference/forms/types/percent.rst b/reference/forms/types/percent.rst index 4b21f1f2856..0102f0c1d83 100644 --- a/reference/forms/types/percent.rst +++ b/reference/forms/types/percent.rst @@ -12,40 +12,17 @@ you can use this field out-of-the-box. If you store your data as a number When ``symbol`` is not ``false``, the field will render the given string after the input. -+-------------+-----------------------------------------------------------------------+ -| Rendered as | ``input`` ``text`` field | -+-------------+-----------------------------------------------------------------------+ -| Options | - `html5`_ | -| | - `rounding_mode`_ | -| | - `scale`_ | -| | - `symbol`_ | -| | - `type`_ | -+-------------+-----------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | | -+-------------+-----------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+-----------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+-----------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\PercentType` | -+-------------+-----------------------------------------------------------------------+ ++---------------------------+-----------------------------------------------------------------------+ +| Rendered as | ``input`` ``text`` field | ++---------------------------+-----------------------------------------------------------------------+ +| Default invalid message | Please enter a percentage value. | ++---------------------------+-----------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+-----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\PercentType` | ++---------------------------+-----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -115,6 +92,8 @@ Overridden Options .. include:: /reference/forms/types/options/compound_type.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -126,13 +105,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``''`` (the empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc @@ -144,8 +121,6 @@ The default value is ``''`` (the empty string). .. include:: /reference/forms/types/options/help_html.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/label.rst.inc diff --git a/reference/forms/types/radio.rst b/reference/forms/types/radio.rst index ae0d58d2fe4..de7a8bbde12 100644 --- a/reference/forms/types/radio.rst +++ b/reference/forms/types/radio.rst @@ -13,38 +13,25 @@ The ``RadioType`` isn't usually used directly. More commonly it's used internally by other types such as :doc:`ChoiceType `. If you want to have a boolean field, use :doc:`CheckboxType `. -+-------------+---------------------------------------------------------------------+ -| Rendered as | ``input`` ``radio`` field | -+-------------+---------------------------------------------------------------------+ -| Inherited | from the :doc:`CheckboxType `: | -| options | | -| | - `value`_ | -| | | -| | from the :doc:`FormType `: | -| | | -| | - `attr`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`CheckboxType ` | -+-------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RadioType` | -+-------------+---------------------------------------------------------------------+ ++---------------------------+---------------------------------------------------------------------+ +| Rendered as | ``input`` ``radio`` field | ++---------------------------+---------------------------------------------------------------------+ +| Default invalid message | Please select a valid option. | ++---------------------------+---------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+---------------------------------------------------------------------+ +| Parent type | :doc:`CheckboxType ` | ++---------------------------+---------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RadioType` | ++---------------------------+---------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- diff --git a/reference/forms/types/range.rst b/reference/forms/types/range.rst index e328a1bbe97..3d8730ed249 100644 --- a/reference/forms/types/range.rst +++ b/reference/forms/types/range.rst @@ -7,29 +7,17 @@ RangeType Field The ``RangeType`` field is a slider that is rendered using the HTML5 ```` tag. -+-------------+---------------------------------------------------------------------+ -| Rendered as | ``input`` ``range`` field (slider in HTML5 supported browser) | -+-------------+---------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `trim`_ | -+-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | -+-------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RangeType` | -+-------------+---------------------------------------------------------------------+ ++---------------------------+---------------------------------------------------------------------+ +| Rendered as | ``input`` ``range`` field (slider in HTML5 supported browser) | ++---------------------------+---------------------------------------------------------------------+ +| Default invalid message | Please choose a valid range. | ++---------------------------+---------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+---------------------------------------------------------------------+ +| Parent type | :doc:`TextType ` | ++---------------------------+---------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RangeType` | ++---------------------------+---------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -45,9 +33,14 @@ Basic Usage 'attr' => [ 'min' => 5, 'max' => 50 - ] + ], ]); +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -59,13 +52,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``''`` (the empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc diff --git a/reference/forms/types/repeated.rst b/reference/forms/types/repeated.rst index c78e6cc318e..04796df2c6b 100644 --- a/reference/forms/types/repeated.rst +++ b/reference/forms/types/repeated.rst @@ -9,34 +9,17 @@ values must match (or a validation error is thrown). The most common use is when you need the user to repeat their password or email to verify accuracy. -+-------------+------------------------------------------------------------------------+ -| Rendered as | input ``text`` field by default, but see `type`_ option | -+-------------+------------------------------------------------------------------------+ -| Options | - `first_name`_ | -| | - `first_options`_ | -| | - `options`_ | -| | - `second_name`_ | -| | - `second_options`_ | -| | - `type`_ | -+-------------+------------------------------------------------------------------------+ -| Overridden | - `error_bubbling`_ | -| options | | -+-------------+------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `mapped`_ | -| | - `row_attr`_ | -+-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+-------------+------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RepeatedType` | -+-------------+------------------------------------------------------------------------+ ++---------------------------+------------------------------------------------------------------------+ +| Rendered as | input ``text`` field by default, but see `type`_ option | ++---------------------------+------------------------------------------------------------------------+ +| Default invalid message | The values do not match. | ++---------------------------+------------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+------------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RepeatedType` | ++---------------------------+------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -184,6 +167,8 @@ Overridden Options **default**: ``false`` +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -201,8 +186,6 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/help_html.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/mapped.rst.inc diff --git a/reference/forms/types/reset.rst b/reference/forms/types/reset.rst index 914e4dfb428..6fd9b99d7fb 100644 --- a/reference/forms/types/reset.rst +++ b/reference/forms/types/reset.rst @@ -9,14 +9,6 @@ A button that resets all fields to their original values. +----------------------+---------------------------------------------------------------------+ | Rendered as | ``input`` ``reset`` tag | +----------------------+---------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `attr_translation_parameters`_ | -| | - `disabled`_ | -| | - `label`_ | -| | - `label_translation_parameters`_ | -| | - `row_attr`_ | -| | - `translation_domain`_ | -+----------------------+---------------------------------------------------------------------+ | Parent type | :doc:`ButtonType ` | +----------------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\ResetType` | diff --git a/reference/forms/types/search.rst b/reference/forms/types/search.rst index e0f8233aa5b..048dd535ab5 100644 --- a/reference/forms/types/search.rst +++ b/reference/forms/types/search.rst @@ -9,32 +9,25 @@ special functionality supported by some browsers. Read about the input search field at `DiveIntoHTML5.info`_ -+-------------+----------------------------------------------------------------------+ -| Rendered as | ``input search`` field | -+-------------+----------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `trim`_ | -+-------------+----------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | -+-------------+----------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\SearchType` | -+-------------+----------------------------------------------------------------------+ ++---------------------------+----------------------------------------------------------------------+ +| Rendered as | ``input search`` field | ++---------------------------+----------------------------------------------------------------------+ +| Default invalid message | Please enter a valid search term. | ++---------------------------+----------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+----------------------------------------------------------------------+ +| Parent type | :doc:`TextType ` | ++---------------------------+----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\SearchType` | ++---------------------------+----------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -44,13 +37,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``''`` (the empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc diff --git a/reference/forms/types/submit.rst b/reference/forms/types/submit.rst index 0554aef8a8e..0ac866d82e9 100644 --- a/reference/forms/types/submit.rst +++ b/reference/forms/types/submit.rst @@ -9,18 +9,6 @@ A submit button. +----------------------+----------------------------------------------------------------------+ | Rendered as | ``button`` ``submit`` tag | +----------------------+----------------------------------------------------------------------+ -| Options | - `validate`_ | -+----------------------+----------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `attr_translation_parameters`_ | -| | - `disabled`_ | -| | - `label`_ | -| | - `label_format`_ | -| | - `label_translation_parameters`_ | -| | - `row_attr`_ | -| | - `translation_domain`_ | -| | - `validation_groups`_ | -+----------------------+----------------------------------------------------------------------+ | Parent type | :doc:`ButtonType ` | +----------------------+----------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\SubmitType` | diff --git a/reference/forms/types/tel.rst b/reference/forms/types/tel.rst index f6c19391ada..8a99b6752c5 100644 --- a/reference/forms/types/tel.rst +++ b/reference/forms/types/tel.rst @@ -13,33 +13,25 @@ Nevertheless, it may be useful to use this type in web applications because some browsers (e.g. smartphone browsers) adapt the input keyboard to make it easier to input phone numbers. -+-------------+---------------------------------------------------------------------+ -| Rendered as | ``input`` ``tel`` field (a text box) | -+-------------+---------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `trim`_ | -+-------------+---------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | -+-------------+---------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TelType` | -+-------------+---------------------------------------------------------------------+ ++---------------------------+-------------------------------------------------------------------+ +| Rendered as | ``input`` ``tel`` field (a text box) | ++---------------------------+-------------------------------------------------------------------+ +| Default invalid message | Please provide a valid phone number. | ++---------------------------+-------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+-------------------------------------------------------------------+ +| Parent type | :doc:`TextType ` | ++---------------------------+-------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TelType` | ++---------------------------+-------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -51,13 +43,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``''`` (the empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc diff --git a/reference/forms/types/text.rst b/reference/forms/types/text.rst index a12af8e778f..204c496ce85 100644 --- a/reference/forms/types/text.rst +++ b/reference/forms/types/text.rst @@ -9,26 +9,6 @@ The TextType field represents the most basic input text field. +-------------+--------------------------------------------------------------------+ | Rendered as | ``input`` ``text`` field | +-------------+--------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `trim`_ | -+-------------+--------------------------------------------------------------------+ -| Overridden | - `compound`_ | -| options | | -+-------------+--------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +-------------+--------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TextType` | @@ -47,15 +27,13 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc From an HTTP perspective, submitted data is always a string or an array of strings. So by default, the form will treat any empty string as null. If you prefer to get an empty string, explicitly set the ``empty_data`` option to an empty string. -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc diff --git a/reference/forms/types/textarea.rst b/reference/forms/types/textarea.rst index 8a28262aec6..3e0ac8e0db9 100644 --- a/reference/forms/types/textarea.rst +++ b/reference/forms/types/textarea.rst @@ -9,23 +9,6 @@ Renders a ``textarea`` HTML element. +-------------+------------------------------------------------------------------------+ | Rendered as | ``textarea`` tag | +-------------+------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `trim`_ | -+-------------+------------------------------------------------------------------------+ | Parent type | :doc:`TextType ` | +-------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TextareaType` | @@ -50,13 +33,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``''`` (the empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc diff --git a/reference/forms/types/time.rst b/reference/forms/types/time.rst index 042e3e7da0c..dc84d9a29bc 100644 --- a/reference/forms/types/time.rst +++ b/reference/forms/types/time.rst @@ -10,48 +10,19 @@ This can be rendered as a text field, a series of text fields (e.g. hour, minute, second) or a series of select fields. The underlying data can be stored as a ``DateTime`` object, a string, a timestamp or an array. -+----------------------+-----------------------------------------------------------------------------+ -| Underlying Data Type | can be ``DateTime``, string, timestamp, or array (see the ``input`` option) | -+----------------------+-----------------------------------------------------------------------------+ -| Rendered as | can be various tags (see below) | -+----------------------+-----------------------------------------------------------------------------+ -| Options | - `choice_translation_domain`_ | -| | - `placeholder`_ | -| | - `hours`_ | -| | - `html5`_ | -| | - `input`_ | -| | - `input_format`_ | -| | - `minutes`_ | -| | - `model_timezone`_ | -| | - `reference_date`_ | -| | - `seconds`_ | -| | - `view_timezone`_ | -| | - `widget`_ | -| | - `with_minutes`_ | -| | - `with_seconds`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Overridden options | - `by_reference`_ | -| | - `compound`_ | -| | - `data_class`_ | -| | - `error_bubbling`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `inherit_data`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `mapped`_ | -| | - `row_attr`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Parent type | FormType | -+----------------------+-----------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TimeType` | -+----------------------+-----------------------------------------------------------------------------+ ++---------------------------+-----------------------------------------------------------------------------+ +| Underlying Data Type | can be ``DateTime``, string, timestamp, or array (see the ``input`` option) | ++---------------------------+-----------------------------------------------------------------------------+ +| Rendered as | can be various tags (see below) | ++---------------------------+-----------------------------------------------------------------------------+ +| Default invalid message | Please enter a valid time. | ++---------------------------+-----------------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------------+ +| Parent type | FormType | ++---------------------------+-----------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TimeType` | ++---------------------------+-----------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -111,7 +82,7 @@ values for the hour, minute and second fields:: $builder->add('startTime', 'time', [ 'placeholder' => [ 'hour' => 'Hour', 'minute' => 'Minute', 'second' => 'Second', - ] + ], ]); .. include:: /reference/forms/types/options/hours.rst.inc @@ -220,6 +191,8 @@ error_bubbling **default**: ``false`` +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -241,8 +214,6 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/inherit_data.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/mapped.rst.inc diff --git a/reference/forms/types/timezone.rst b/reference/forms/types/timezone.rst index c18cdbaf339..6dc0d793b3b 100644 --- a/reference/forms/types/timezone.rst +++ b/reference/forms/types/timezone.rst @@ -14,45 +14,17 @@ Unlike the ``ChoiceType``, you don't need to specify a ``choices`` option as the field type automatically uses a large list of timezones. You *can* specify the option manually, but then you should just use the ``ChoiceType`` directly. -+-------------+------------------------------------------------------------------------+ -| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | -+-------------+------------------------------------------------------------------------+ -| Options | - `input`_ | -| | - `intl`_ | -+-------------+------------------------------------------------------------------------+ -| Overridden | - `choices`_ | -| options | - `choice_translation_domain`_ | -+-------------+------------------------------------------------------------------------+ -| Inherited | from the :doc:`ChoiceType ` | -| options | | -| | - `expanded`_ | -| | - `multiple`_ | -| | - `placeholder`_ | -| | - `preferred_choices`_ | -| | - `trim`_ | -| | | -| | from the :doc:`FormType ` | -| | | -| | - `attr`_ | -| | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -+-------------+------------------------------------------------------------------------+ -| Parent type | :doc:`ChoiceType ` | -+-------------+------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TimezoneType` | -+-------------+------------------------------------------------------------------------+ ++---------------------------+------------------------------------------------------------------------+ +| Rendered as | can be various tags (see :ref:`forms-reference-choice-tags`) | ++---------------------------+------------------------------------------------------------------------+ +| Default invalid message | Please select a valid timezone. | ++---------------------------+------------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+------------------------------------------------------------------------+ +| Parent type | :doc:`ChoiceType ` | ++---------------------------+------------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TimezoneType` | ++---------------------------+------------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -107,6 +79,8 @@ The Timezone type defaults the choices to all timezones returned by .. include:: /reference/forms/types/options/choice_translation_domain_disabled.rst.inc +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -130,8 +104,7 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The actual default value of this option depends on other field options: @@ -139,8 +112,7 @@ The actual default value of this option depends on other field options: (empty string); * Otherwise ``[]`` (empty array). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc diff --git a/reference/forms/types/ulid.rst b/reference/forms/types/ulid.rst new file mode 100644 index 00000000000..90d2f33589b --- /dev/null +++ b/reference/forms/types/ulid.rst @@ -0,0 +1,74 @@ +.. index:: + single: Forms; Fields; UuidType + +UlidType Field +============== + +.. versionadded:: 5.3 + + The ``UlidType`` field was introduced in Symfony 5.3. + +Renders an input text field with the ULID string value and transforms it back to +a proper :ref:`Ulid object ` when submitting the form. + ++---------------------------+-----------------------------------------------------------------------+ +| Rendered as | ``input`` ``text`` field | ++---------------------------+-----------------------------------------------------------------------+ +| Default invalid message | Please enter a valid ULID. | ++---------------------------+-----------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+-----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\UlidType` | ++---------------------------+-----------------------------------------------------------------------+ + +.. include:: /reference/forms/types/options/_debug_form.rst.inc + +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/compound_type.rst.inc + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + +Inherited Options +----------------- + +These options inherit from the :doc:`FormType `: + +.. include:: /reference/forms/types/options/attr.rst.inc + +.. include:: /reference/forms/types/options/data.rst.inc + +.. include:: /reference/forms/types/options/disabled.rst.inc + +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc + +The default value is ``''`` (the empty string). + +.. include:: /reference/forms/types/options/empty_data_description.rst.inc + +.. include:: /reference/forms/types/options/error_bubbling.rst.inc + +.. include:: /reference/forms/types/options/error_mapping.rst.inc + +.. include:: /reference/forms/types/options/help.rst.inc + +.. include:: /reference/forms/types/options/help_attr.rst.inc + +.. include:: /reference/forms/types/options/help_html.rst.inc + +.. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc + +.. include:: /reference/forms/types/options/label.rst.inc + +.. include:: /reference/forms/types/options/label_attr.rst.inc + +.. include:: /reference/forms/types/options/label_format.rst.inc + +.. include:: /reference/forms/types/options/mapped.rst.inc + +.. include:: /reference/forms/types/options/required.rst.inc + +.. include:: /reference/forms/types/options/row_attr.rst.inc diff --git a/reference/forms/types/url.rst b/reference/forms/types/url.rst index a03f1532021..6a5d368c41c 100644 --- a/reference/forms/types/url.rst +++ b/reference/forms/types/url.rst @@ -8,32 +8,17 @@ The ``UrlType`` field is a text field that prepends the submitted value with a given protocol (e.g. ``http://``) if the submitted value doesn't already have a protocol. -+-------------+-------------------------------------------------------------------+ -| Rendered as | ``input url`` field | -+-------------+-------------------------------------------------------------------+ -| Options | - `default_protocol`_ | -+-------------+-------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -| | - `error_mapping`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `label`_ | -| | - `label_attr`_ | -| | - `label_format`_ | -| | - `mapped`_ | -| | - `required`_ | -| | - `row_attr`_ | -| | - `trim`_ | -+-------------+-------------------------------------------------------------------+ -| Parent type | :doc:`TextType ` | -+-------------+-------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\UrlType` | -+-------------+-------------------------------------------------------------------+ ++---------------------------+-------------------------------------------------------------------+ +| Rendered as | ``input url`` field | ++---------------------------+-------------------------------------------------------------------+ +| Default invalid message | Please enter a valid URL. | ++---------------------------+-------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+-------------------------------------------------------------------+ +| Parent type | :doc:`TextType ` | ++---------------------------+-------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\UrlType` | ++---------------------------+-------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -49,6 +34,11 @@ If a value is submitted that doesn't begin with some protocol (e.g. ``http://``, ``ftp://``, etc), this protocol will be prepended to the string when the data is submitted to the form. +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -60,13 +50,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/disabled.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The default value is ``''`` (the empty string). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc .. include:: /reference/forms/types/options/error_bubbling.rst.inc diff --git a/reference/forms/types/uuid.rst b/reference/forms/types/uuid.rst new file mode 100644 index 00000000000..c5d0827558e --- /dev/null +++ b/reference/forms/types/uuid.rst @@ -0,0 +1,74 @@ +.. index:: + single: Forms; Fields; UuidType + +UuidType Field +============== + +.. versionadded:: 5.3 + + The ``UuidType`` field was introduced in Symfony 5.3. + +Renders an input text field with the UUID string value and transforms it back to +a proper :ref:`Uuid object ` when submitting the form. + ++---------------------------+-----------------------------------------------------------------------+ +| Rendered as | ``input`` ``text`` field | ++---------------------------+-----------------------------------------------------------------------+ +| Default invalid message | Please enter a valid UUID. | ++---------------------------+-----------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+-----------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+-----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\UuidType` | ++---------------------------+-----------------------------------------------------------------------+ + +.. include:: /reference/forms/types/options/_debug_form.rst.inc + +Overridden Options +------------------ + +.. include:: /reference/forms/types/options/compound_type.rst.inc + +.. include:: /reference/forms/types/options/invalid_message.rst.inc + +Inherited Options +----------------- + +These options inherit from the :doc:`FormType `: + +.. include:: /reference/forms/types/options/attr.rst.inc + +.. include:: /reference/forms/types/options/data.rst.inc + +.. include:: /reference/forms/types/options/disabled.rst.inc + +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc + +The default value is ``''`` (the empty string). + +.. include:: /reference/forms/types/options/empty_data_description.rst.inc + +.. include:: /reference/forms/types/options/error_bubbling.rst.inc + +.. include:: /reference/forms/types/options/error_mapping.rst.inc + +.. include:: /reference/forms/types/options/help.rst.inc + +.. include:: /reference/forms/types/options/help_attr.rst.inc + +.. include:: /reference/forms/types/options/help_html.rst.inc + +.. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc + +.. include:: /reference/forms/types/options/label.rst.inc + +.. include:: /reference/forms/types/options/label_attr.rst.inc + +.. include:: /reference/forms/types/options/label_format.rst.inc + +.. include:: /reference/forms/types/options/mapped.rst.inc + +.. include:: /reference/forms/types/options/required.rst.inc + +.. include:: /reference/forms/types/options/row_attr.rst.inc diff --git a/reference/forms/types/week.rst b/reference/forms/types/week.rst index 6967df09bb7..045851adc96 100644 --- a/reference/forms/types/week.rst +++ b/reference/forms/types/week.rst @@ -10,39 +10,19 @@ This field type allows the user to modify data that represents a specific Can be rendered as a text input or select tags. The underlying format of the data can be a string or an array. -+----------------------+-----------------------------------------------------------------------------+ -| Underlying Data Type | can be a string, or array (see the ``input`` option) | -+----------------------+-----------------------------------------------------------------------------+ -| Rendered as | single text box, two text boxes or two select fields | -+----------------------+-----------------------------------------------------------------------------+ -| Options | - `choice_translation_domain`_ | -| | - `placeholder`_ | -| | - `html5`_ | -| | - `input`_ | -| | - `widget`_ | -| | - `weeks`_ | -| | - `years`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Overridden options | - `compound`_ | -| | - `empty_data`_ | -| | - `error_bubbling`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Inherited | - `attr`_ | -| options | - `data`_ | -| | - `disabled`_ | -| | - `help`_ | -| | - `help_attr`_ | -| | - `help_html`_ | -| | - `inherit_data`_ | -| | - `invalid_message`_ | -| | - `invalid_message_parameters`_ | -| | - `mapped`_ | -| | - `row_attr`_ | -+----------------------+-----------------------------------------------------------------------------+ -| Parent type | :doc:`FormType ` | -+----------------------+-----------------------------------------------------------------------------+ -| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\WeekType` | -+----------------------+-----------------------------------------------------------------------------+ ++---------------------------+--------------------------------------------------------------------+ +| Underlying Data Type | can be a string, or array (see the ``input`` option) | ++---------------------------+--------------------------------------------------------------------+ +| Rendered as | single text box, two text boxes or two select fields | ++---------------------------+--------------------------------------------------------------------+ +| Default invalid message | Please enter a valid week. | ++---------------------------+--------------------------------------------------------------------+ +| Legacy invalid message | The value {{ value }} is not valid. | ++---------------------------+--------------------------------------------------------------------+ +| Parent type | :doc:`FormType ` | ++---------------------------+--------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\WeekType` | ++---------------------------+--------------------------------------------------------------------+ .. include:: /reference/forms/types/options/_debug_form.rst.inc @@ -75,7 +55,7 @@ values for the year and week fields:: 'placeholder' => [ 'year' => 'Year', 'week' => 'Week', - ] + ], ]); .. include:: /reference/forms/types/options/html5.rst.inc @@ -122,22 +102,22 @@ Overridden Options .. include:: /reference/forms/types/options/compound_type.rst.inc -.. include:: /reference/forms/types/options/empty_data.rst.inc - :end-before: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_declaration.rst.inc The actual default value of this option depends on other field options: * If ``widget`` is ``single_text``, then ``''`` (empty string); * Otherwise ``[]`` (empty array). -.. include:: /reference/forms/types/options/empty_data.rst.inc - :start-after: DEFAULT_PLACEHOLDER +.. include:: /reference/forms/types/options/empty_data_description.rst.inc error_bubbling ~~~~~~~~~~~~~~ **default**: ``false`` +.. include:: /reference/forms/types/options/invalid_message.rst.inc + Inherited Options ----------------- @@ -157,8 +137,6 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/inherit_data.rst.inc -.. include:: /reference/forms/types/options/invalid_message.rst.inc - .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc .. include:: /reference/forms/types/options/mapped.rst.inc diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 270c9c678c8..d2246edef52 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -225,6 +225,8 @@ Returns the absolute URL (with scheme and host) for the given route. If Read more about :doc:`Symfony routing ` and about :ref:`creating links in Twig templates `. +.. _reference-twig-function-absolute-url: + absolute_url ~~~~~~~~~~~~ @@ -239,6 +241,8 @@ Returns the absolute URL (with scheme and host) from the passed relative path. C :ref:`asset() function ` to generate absolute URLs for web assets. Read more about :ref:`Linking to CSS, JavaScript and Image Assets `. +.. _reference-twig-function-relative-path: + relative_path ~~~~~~~~~~~~~ @@ -558,6 +562,29 @@ project's root directory: If the given file path is out of the project directory, a ``null`` value will be returned. +serialize +~~~~~~~~~ + +.. code-block:: twig + + {{ object|serialize(format = 'json', context = []) }} + +``object`` + **type**: ``mixed`` + +``format`` *(optional)* + **type**: ``string`` + +``context`` *(optional)* + **type**: ``array`` + +.. versionadded:: 5.3 + + The ``serialize`` filter was introduced in Symfony 5.3. + +Accepts any data that can be serialized by the :doc:`Serializer component ` +and returns a serialized string in the specified ``format``. + .. _reference-twig-tags: Tags diff --git a/routing.rst b/routing.rst index e51fb11c688..a600f706d85 100644 --- a/routing.rst +++ b/routing.rst @@ -47,7 +47,7 @@ This command also creates the following configuration file: # config/routes/annotations.yaml controllers: - resource: '../../src/Controller/' + resource: ../../src/Controller/ type: annotation kernel: @@ -178,6 +178,12 @@ the ``BlogController``: ; }; +.. versionadded:: 5.1 + + Starting from Symfony 5.1, by default Symfony only loads the routes defined + in YAML format. If you define routes in XML and/or PHP formats, update the + ``src/Kernel.php`` file to add support for the ``.xml`` and ``.php`` file extensions. + .. _routing-matching-http-methods: Matching HTTP Methods @@ -226,13 +232,13 @@ Use the ``methods`` option to restrict the verbs each route should respond to: class BlogApiController extends AbstractController { #[Route('/api/posts/{id}', methods: ['GET', 'HEAD'])] - public function show(int $id) + public function show(int $id): Response { // ... return a JSON response with the post } #[Route('/api/posts/{id}', methods: ['PUT'])] - public function edit(int $id) + public function edit(int $id): Response { // ... edit a post } @@ -322,7 +328,7 @@ arbitrary matching logic: * condition="context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'" * ) * - * expressions can also include config parameters: + * expressions can also include configuration parameters: * condition: "request.headers.get('User-Agent') matches '%app.allowed_browsers%'" */ public function contact(): Response @@ -337,6 +343,7 @@ arbitrary matching logic: namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; class DefaultController extends AbstractController @@ -348,7 +355,7 @@ arbitrary matching logic: )] // expressions can also include config parameters: // condition: "request.headers.get('User-Agent') matches '%app.allowed_browsers%'" - public function contact() + public function contact(): Response { // ... } @@ -361,7 +368,7 @@ arbitrary matching logic: path: /contact controller: 'App\Controller\DefaultController::contact' condition: "context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'" - # expressions can also include config parameters: + # expressions can also include configuration parameters: # condition: "request.headers.get('User-Agent') matches '%app.allowed_browsers%'" .. code-block:: xml @@ -375,7 +382,7 @@ arbitrary matching logic: context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i' - + @@ -390,7 +397,7 @@ arbitrary matching logic: $routes->add('contact', '/contact') ->controller([DefaultController::class, 'contact']) ->condition('context.getMethod() in ["GET", "HEAD"] and request.headers.get("User-Agent") matches "/firefox/i"') - // expressions can also include config parameters: + // expressions can also include configuration parameters: // 'request.headers.get("User-Agent") matches "%app.allowed_browsers%"' ; }; @@ -511,6 +518,7 @@ defined as ``/blog/{slug}``: namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; class BlogController extends AbstractController @@ -518,7 +526,7 @@ defined as ``/blog/{slug}``: // ... #[Route('/blog/{slug}', name: 'blog_show')] - public function show(string $slug) + public function show(string $slug): Response { // $slug will equal the dynamic part of the URL // e.g. at /blog/yay-routing, then $slug='yay-routing' @@ -617,18 +625,19 @@ the ``{page}`` parameter using the ``requirements`` option: namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; class BlogController extends AbstractController { #[Route('/blog/{page}', name: 'blog_list', requirements: ['page' => '\d+'])] - public function list(int $page) + public function list(int $page): Response { // ... } #[Route('/blog/{slug}', name: 'blog_show')] - public function show($slug) + public function show($slug): Response { // ... } @@ -696,7 +705,7 @@ URL Route Parameters .. tip:: Route requirements (and route paths too) can include - :ref:`container parameters `, which is useful to + :ref:`configuration parameters `, which is useful to define complex regular expressions once and reuse them in multiple routes. .. tip:: @@ -744,12 +753,13 @@ concise, but it can decrease route readability when requirements are complex: namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; class BlogController extends AbstractController { #[Route('/blog/{page<\d+>}', name: 'blog_list')] - public function list(int $page) + public function list(int $page): Response { // ... } @@ -798,7 +808,7 @@ visit ``/blog/1``, it will match. But if they visit ``/blog``, it will **not** match. As soon as you add a parameter to a route, it must have a value. You can make ``blog_list`` once again match when the user visits ``/blog`` by -adding a default value for the ``{page}`` parameter. When using annotations, +adding a default value for the ``{page}`` parameter. When using annotations or attributes, default values are defined in the arguments of the controller action. In the other configuration formats they are defined with the ``defaults`` option: @@ -830,12 +840,13 @@ other configuration formats they are defined with the ``defaults`` option: namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; class BlogController extends AbstractController { #[Route('/blog/{page}', name: 'blog_list', requirements: ['page' => '\d+'])] - public function list(int $page = 1) + public function list(int $page = 1): Response { // ... } @@ -934,12 +945,13 @@ parameter: namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; class BlogController extends AbstractController { #[Route('/blog/{page<\d+>?1}', name: 'blog_list')] - public function list(int $page) + public function list(int $page): Response { // ... } @@ -982,7 +994,9 @@ parameter: .. tip:: To give a ``null`` default value to any parameter, add nothing after the - ``?`` character (e.g. ``/blog/{page?}``). + ``?`` character (e.g. ``/blog/{page?}``). If you do this, don't forget to + update the types of the related controller arguments to allow passing + ``null`` values (e.g. replace ``int $page`` by ``?int $page``). Priority Parameter ~~~~~~~~~~~~~~~~~~ @@ -991,11 +1005,12 @@ Priority Parameter The ``priority`` parameter was introduced in Symfony 5.1 -When defining a greedy pattern that matches many routes, this may be at the -beginning of your routing collection and prevents any route defined after to be -matched. -A ``priority`` optional parameter is available in order to let you choose the -order of your routes, and it is only available when using annotations. +Symfony evaluates routes in the order they are defined. If the path of a route +matches many different patterns, it might prevent other routes from being +matched. In YAML and XML you can move the route definitions up or down in the +configuration file to control their priority. In routes defined as PHP +annotations or attributes this is much harder to do, so you can set the +optional ``priority`` parameter in those routes to control their priority: .. configuration-block:: @@ -1068,8 +1083,7 @@ Parameter Conversion A common routing need is to convert the value stored in some parameter (e.g. an integer acting as the user ID) into another value (e.g. the object that -represents the user). This feature is called "param converter" and is only -available when using annotations to define routes. +represents the user). This feature is called "param converter". To add support for "param converters" we need SensioFrameworkExtraBundle: @@ -1187,7 +1201,7 @@ and in route imports. Symfony defines some special attributes with the same name '_format' => 'html|xml', ], )] - public function search() + public function search(): Response { } } @@ -1220,7 +1234,7 @@ and in route imports. Symfony defines some special attributes with the same name format="html"> en|fr - html|rss + html|xml @@ -1239,7 +1253,7 @@ and in route imports. Symfony defines some special attributes with the same name ->format('html') ->requirements([ '_locale' => 'en|fr', - '_format' => 'html|rss', + '_format' => 'html|xml', ]) ; }; @@ -1278,12 +1292,14 @@ the controllers of the routes: // src/Controller/BlogController.php namespace App\Controller; + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; - class BlogController + class BlogController extends AbstractController { #[Route('/blog/{page}', name: 'blog_index', defaults: ['page' => 1, 'title' => 'Hello world!'])] - public function index(int $page, string $title) + public function index(int $page, string $title): Response { // ... } @@ -1368,13 +1384,15 @@ A possible solution is to change the parameter requirements to be more permissiv // src/Controller/DefaultController.php namespace App\Controller; - + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; - class DefaultController + class DefaultController extends AbstractController { #[Route('/share/{token}', name: 'share', requirements: ['token' => '.+'])] - public function share($token) + public function share($token): Response { // ... } @@ -1420,11 +1438,11 @@ A possible solution is to change the parameter requirements to be more permissiv .. note:: - If the route defines several parameter and you apply this permissive + If the route defines several parameters and you apply this permissive regular expression to all of them, you might get unexpected results. For example, if the route definition is ``/share/{path}/{token}`` and both - ``path`` and ``token`` accept ``/``. The ``token`` only get the last path - and the rest of the match is matched by the first argument (``path``). + ``path`` and ``token`` accept ``/``, then ``token`` will only get the last part + and the rest is matched by ``path``. .. note:: @@ -1486,20 +1504,22 @@ when importing the routes. // src/Controller/BlogController.php namespace App\Controller; - + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; #[Route('/blog', requirements: ['_locale' => 'en|es|fr'], name: 'blog_')] - class BlogController + class BlogController extends AbstractController { #[Route('/{_locale}', name: 'index')] - public function index() + public function index(): Response { // ... } #[Route('/{_locale}/posts/{slug}', name: 'show')] - public function show(Post $post) + public function show(Post $post): Response { // ... } @@ -1518,9 +1538,11 @@ when importing the routes. # these requirements are added to all imported routes requirements: _locale: 'en|es|fr' + # An imported route with an empty URL will become "/blog/" # Uncomment this option to make that URL "/blog" instead # trailing_slash_on_root: false + # you can optionally exclude some files/subdirectories when loading annotations # exclude: '../../src/Controller/{DebugEmailController}.php' @@ -1562,27 +1584,86 @@ when importing the routes. use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; return function (RoutingConfigurator $routes) { - // use the optional fifth argument of import() to exclude some files + // use the optional fourth argument of import() to exclude some files // or subdirectories when loading annotations $routes->import('../../src/Controller/', 'annotation') // this is added to the beginning of all imported route URLs ->prefix('/blog') + // An imported route with an empty URL will become "/blog/" // Pass FALSE as the second argument to make that URL "/blog" instead // ->prefix('/blog', false) + // this is added to the beginning of all imported route names ->namePrefix('blog_') + // these requirements are added to all imported routes ->requirements(['_locale' => 'en|es|fr']) + + // you can optionally exclude some files/subdirectories when loading annotations + ->exclude('../../src/Controller/{DebugEmailController}.php') ; }; In this example, the route of the ``index()`` action will be called ``blog_index`` -and its URL will be ``/blog/``. The route of the ``show()`` action will be called +and its URL will be ``/blog/{_locale}``. The route of the ``show()`` action will be called ``blog_show`` and its URL will be ``/blog/{_locale}/posts/{slug}``. Both routes will also validate that the ``_locale`` parameter matches the regular expression defined in the class annotation. +.. note:: + + If any of the prefixed routes defines an empty path, Symfony adds a trailing + slash to it. In the previous example, an empty path prefixed with ``/blog`` + will result in the ``/blog/`` URL. If you want to avoid this behavior, set + the ``trailing_slash_on_root`` option to ``false`` (this option is not + available when using PHP attributes or annotations): + + .. configuration-block:: + + .. code-block:: yaml + + # config/routes/annotations.yaml + controllers: + resource: '../../src/Controller/' + type: annotation + prefix: '/blog' + trailing_slash_on_root: false + # ... + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // config/routes/annotations.php + use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; + + return function (RoutingConfigurator $routes) { + $routes->import('../../src/Controller/', 'annotation') + // the second argument is the $trailingSlashOnRoot option + ->prefix('/blog', false) + + // ... + ; + }; + .. seealso:: Symfony can :doc:`import routes from different sources ` @@ -1822,18 +1903,19 @@ host name: namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; class MainController extends AbstractController { #[Route('/', name: 'mobile_homepage', host: 'm.example.com')] - public function mobileHomepage() + public function mobileHomepage(): Response { // ... } #[Route('/', name: 'homepage')] - public function homepage() + public function homepage(): Response { // ... } @@ -1931,6 +2013,7 @@ multi-tenant applications) and these parameters can be validated too with namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; class MainController extends AbstractController @@ -1942,13 +2025,13 @@ multi-tenant applications) and these parameters can be validated too with defaults: ['subdomain' => 'm'], requirements: ['subdomain' => 'm|mobile'], )] - public function mobileHomepage() + public function mobileHomepage(): Response { // ... } #[Route('/', name: 'homepage')] - public function homepage() + public function homepage(): Response { // ... } @@ -2013,7 +2096,7 @@ multi-tenant applications) and these parameters can be validated too with }; In the above example, the ``subdomain`` parameter defines a default value because -otherwise you need to include a domain value each time you generate a URL using +otherwise you need to include a subdomain value each time you generate a URL using these routes. .. tip:: @@ -2032,10 +2115,20 @@ these routes. [], [], ['HTTP_HOST' => 'm.example.com'] - // or get the value from some container parameter: - // ['HTTP_HOST' => 'm.' . $client->getContainer()->getParameter('domain')] + // or get the value from some configuration parameter: + // ['HTTP_HOST' => 'm.'.$client->getContainer()->getParameter('domain')] ); +.. tip:: + + You can also use the inline defaults and requirements format in the + ``host`` option: ``{subdomain?m}.example.com`` + +.. versionadded:: 5.2 + + Inline parameter default values support in hosts were introduced in + Symfony 5.2. Prior to Symfony 5.2, they were supported in the path only. + .. _i18n-routing: Localized Routes (i18n) @@ -2076,6 +2169,7 @@ avoids the need for duplicating routes, which also reduces the potential bugs: namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; class CompanyController extends AbstractController @@ -2084,7 +2178,7 @@ avoids the need for duplicating routes, which also reduces the potential bugs: 'en' => '/about-us', 'nl' => '/over-ons' ], name: 'about_us')] - public function about() + public function about(): Response { // ... } @@ -2185,7 +2279,54 @@ with a locale. This can be done by defining a different prefix for each locale ->prefix([ // don't prefix URLs for English, the default locale 'en' => '', - 'nl' => '/nl' + 'nl' => '/nl', + ]) + ; + }; + +Another common requirement is to host the website on a different domain +according to the locale. This can be done by defining a different host for each +locale. + +.. versionadded:: 5.1 + + The ability to define an array of hosts was introduced in Symfony 5.1. + +.. configuration-block:: + + .. code-block:: yaml + + # config/routes/annotations.yaml + controllers: + resource: '../../src/Controller/' + type: annotation + host: + en: 'https://www.example.com' + nl: 'https://www.example.nl' + + .. code-block:: xml + + + + + + https://www.example.com + https://www.example.nl + + + + .. code-block:: php + + // config/routes/annotations.php + use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; + return function (RoutingConfigurator $routes) { + $routes->import('../../src/Controller/', 'annotation') + ->host([ + 'en' => 'https://www.example.com', + 'nl' => 'https://www.example.nl', ]) ; }; @@ -2200,8 +2341,8 @@ Stateless Routes The ``stateless`` option was introduced in Symfony 5.1. Sometimes, when an HTTP response should be cached, it is important to ensure -that can happen. However, whenever session is started during a request, Symfony -turns the response into a private non-cacheable response. +that can happen. However, whenever a session is started during a request, +Symfony turns the response into a private non-cacheable response. For details, see :doc:`/http_cache`. @@ -2280,6 +2421,7 @@ session shouldn't be used when matching a request: Now, if the session is used, the application will report it based on your ``kernel.debug`` parameter: + * ``enabled``: will throw an :class:`Symfony\\Component\\HttpKernel\\Exception\\UnexpectedSessionUsageException` exception * ``disabled``: will log a warning @@ -2330,7 +2472,7 @@ use the ``generateUrl()`` helper:: // generate a URL with route arguments $userProfilePage = $this->generateUrl('user_profile', [ - 'username' => $user->getUsername(), + 'username' => $user->getUserIdentifier(), ]); // generated URLs are "absolute paths" by default. Pass a third optional @@ -2349,12 +2491,20 @@ use the ``generateUrl()`` helper:: If you pass to the ``generateUrl()`` method some parameters that are not part of the route definition, they are included in the generated URL as a - query string::: + query string:: $this->generateUrl('blog', ['page' => 2, 'category' => 'Symfony']); // the 'blog' route only defines the 'page' parameter; the generated URL is: // /blog/2?category=Symfony +.. caution:: + + While objects are converted to string when used as placeholders, they are not + converted when used as extra parameters. So, if you're passing an object (e.g. an Uuid) + as value of an extra parameter, you need to explicitly convert it to a string:: + + $this->generateUrl('blog', ['uuid' => (string) $entity->getUuid()]); + If your controller does not extend from ``AbstractController``, you'll need to :ref:`fetch services in your controller ` and follow the instructions of the next section. @@ -2392,7 +2542,7 @@ the :class:`Symfony\\Component\\Routing\\Generator\\UrlGeneratorInterface` class // generate a URL with route arguments $userProfilePage = $this->router->generate('user_profile', [ - 'username' => $user->getUsername(), + 'username' => $user->getUserIdentifier(), ]); // generated URLs are "absolute paths" by default. Pass a third optional @@ -2429,6 +2579,8 @@ If you need to generate URLs dynamically or if you are using pure JavaScript code, this solution doesn't work. In those cases, consider using the `FOSJsRoutingBundle`_. +.. _router-generate-urls-commands: + Generating URLs in Commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2473,12 +2625,11 @@ The solution is to configure the ``default_uri`` option to define the .. code-block:: php // config/packages/routing.php - $container->loadFromExtension('framework', [ - 'router' => [ - // ... - 'default_uri' => "https://example.org/my/path/", - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->router()->defaultUri('https://example.org/my/path/'); + }; .. versionadded:: 5.1 @@ -2514,7 +2665,7 @@ Now you'll get the expected results when generating URLs in your commands:: // generate a URL with route arguments $userProfilePage = $this->router->generate('user_profile', [ - 'username' => $user->getUsername(), + 'username' => $user->getUserIdentifier(), ]); // generated URLs are "absolute paths" by default. Pass a third optional @@ -2579,7 +2730,7 @@ method) or globally with these configuration parameters: .. code-block:: xml - + + `, run this command to -install the security feature before using it: +The easiest way to generate a user class is using the ``make:user`` command +from the `MakerBundle`_: .. code-block:: terminal - $ composer require symfony/security-bundle + $ php bin/console make:user + The name of the security user class (e.g. User) [User]: + > User + Do you want to store user data in the database (via Doctrine)? (yes/no) [yes]: + > yes -.. tip:: + Enter a property name that will be the unique "display" name for the user (e.g. email, username, uuid) [email]: + > email - A :doc:`new experimental Security ` - was introduced in Symfony 5.1, which will eventually replace security in - Symfony 6.0. This system is almost fully backwards compatible with the - current Symfony security, add this line to your security configuration to start - using it: + Will this app need to hash/check user passwords? Choose No if passwords are not needed or will be checked/hashed by some other system (e.g. a single sign-on server). - .. configuration-block:: + Does this app need to hash/check user passwords? (yes/no) [yes]: + > yes - .. code-block:: yaml + created: src/Entity/User.php + created: src/Repository/UserRepository.php + updated: src/Entity/User.php + updated: config/packages/security.yaml - # config/packages/security.yaml - security: - enable_authenticator_manager: true - # ... +.. code-block:: php - .. code-block:: xml + // src/Entity/User.php + namespace App\Entity; - - - + use App\Repository\UserRepository; + use Doctrine\ORM\Mapping as ORM; + use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; + use Symfony\Component\Security\Core\User\UserInterface; - - - - + /** + * @ORM\Entity(repositoryClass=UserRepository::class) + */ + class User implements UserInterface, PasswordAuthenticatedUserInterface + { + /** + * @ORM\Id + * @ORM\GeneratedValue + * @ORM\Column(type="integer") + */ + private $id; - .. code-block:: php + /** + * @ORM\Column(type="string", length=180, unique=true) + */ + private $email; - // config/packages/security.php - $container->loadFromExtension('security', [ - 'enable_authenticator_manager' => true, - // ... - ]); + /** + * @ORM\Column(type="json") + */ + private $roles = []; -.. _initial-security-yml-setup-authentication: -.. _initial-security-yaml-setup-authentication: -.. _create-user-class: + /** + * @var string The hashed password + * @ORM\Column(type="string") + */ + private $password; -2a) Create your User Class --------------------------- + public function getId(): ?int + { + return $this->id; + } -No matter *how* you will authenticate (e.g. login form or API tokens) or *where* -your user data will be stored (database, single sign-on), the next step is always the same: -create a "User" class. The easiest way is to use the `MakerBundle`_. + public function getEmail(): ?string + { + return $this->email; + } -Let's assume that you want to store your user data in the database with Doctrine: + public function setEmail(string $email): self + { + $this->email = $email; -.. code-block:: terminal + return $this; + } - $ php bin/console make:user + /** + * The public representation of the user (e.g. a username, an email address, etc.) + * + * @see UserInterface + */ + public function getUserIdentifier(): string + { + return (string) $this->email; + } + + /** + * @deprecated since Symfony 5.3 + */ + public function getUsername(): string + { + return (string) $this->email; + } + + /** + * @see UserInterface + */ + public function getRoles(): array + { + $roles = $this->roles; + // guarantee every user at least has ROLE_USER + $roles[] = 'ROLE_USER'; - The name of the security user class (e.g. User) [User]: - > User + return array_unique($roles); + } - Do you want to store user data in the database (via Doctrine)? (yes/no) [yes]: - > yes + public function setRoles(array $roles): self + { + $this->roles = $roles; - Enter a property name that will be the unique "display" name for the user (e.g. - email, username, uuid [email] - > email + return $this; + } - Does this app need to hash/check user passwords? (yes/no) [yes]: - > yes + /** + * @see PasswordAuthenticatedUserInterface + */ + public function getPassword(): string + { + return $this->password; + } - created: src/Entity/User.php - created: src/Repository/UserRepository.php - updated: src/Entity/User.php - updated: config/packages/security.yaml + public function setPassword(string $password): self + { + $this->password = $password; -That's it! The command asks several questions so that it can generate exactly what -you need. The most important is the ``User.php`` file itself. The *only* rule about -your ``User`` class is that it *must* implement :class:`Symfony\\Component\\Security\\Core\\User\\UserInterface`. -Feel free to add *any* other fields or logic you need. If your ``User`` class is -an entity (like in this example), you can use the :ref:`make:entity command ` -to add more fields. Also, make sure to make and run a migration for the new entity: + return $this; + } -.. code-block:: terminal + /** + * Returning a salt is only needed, if you are not using a modern + * hashing algorithm (e.g. bcrypt or sodium) in your security.yaml. + * + * @see UserInterface + */ + public function getSalt(): ?string + { + return null; + } - $ php bin/console make:migration - $ php bin/console doctrine:migrations:migrate + /** + * @see UserInterface + */ + public function eraseCredentials() + { + // If you store any temporary, sensitive data on the user, clear it here + // $this->plainPassword = null; + } + } -.. _security-user-providers: -.. _where-do-users-come-from-user-providers: +.. versionadded:: 5.3 -2b) The "User Provider" ------------------------ + The :class:`Symfony\\Component\\Security\\Core\\User\\PasswordAuthenticatedUserInterface` + interface and ``getUserIdentifier()`` method were introduced in Symfony 5.3. -In addition to your ``User`` class, you also need a "User provider": a class that -helps with a few things, like reloading the User data from the session and some -optional features, like :doc:`remember me ` and -:doc:`impersonation `. +If your user is a Doctrine entity, like in the example above, don't forget +to create the tables by :ref:`creating and running a migration `: -Fortunately, the ``make:user`` command already configured one for you in your -``security.yaml`` file under the ``providers`` key. +.. code-block:: terminal -If your ``User`` class is an entity, you don't need to do anything else. But if -your class is *not* an entity, then ``make:user`` will also have generated a -``UserProvider`` class that you need to finish. Learn more about user providers -here: :doc:`User Providers `. + $ php bin/console make:migration + $ php bin/console doctrine:migrations:migrate -.. _security-encoding-user-password: -.. _encoding-the-user-s-password: +.. _where-do-users-come-from-user-providers: +.. _security-user-providers: -2c) Encoding Passwords ----------------------- +Loading the User: The User Provider +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Not all applications have "users" that need passwords. *If* your users have passwords, -you can control how those passwords are encoded in ``security.yaml``. The ``make:user`` -command will pre-configure this for you: +Besides creating the entity, the ``make:user`` command also adds config +for a user provider in your security configuration: .. configuration-block:: @@ -164,18 +277,16 @@ command will pre-configure this for you: security: # ... - encoders: - # use your user class name here - App\Entity\User: - # Use native password encoder - # This value auto-selects the best possible hashing algorithm - # (i.e. Sodium when available). - algorithm: auto + providers: + app_user_provider: + entity: + class: App\Entity\User + property: email .. code-block:: xml - + - - - + + + @@ -199,88 +308,210 @@ command will pre-configure this for you: // config/packages/security.php use App\Entity\User; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ - // ... - - 'encoders' => [ - User::class => [ - 'algorithm' => 'auto', - 'cost' => 12, - ] - ], - + return static function (SecurityConfig $security) { // ... - ]); -Now that Symfony knows *how* you want to encode the passwords, you can use the -``UserPasswordEncoderInterface`` service to do this before saving your users to -the database. + $security->provider('app_user_provider') + ->entity() + ->class(User::class) + ->property('email') + ; + }; -.. _user-data-fixture: +This user provider knows how to (re)load users from a storage (e.g. a database) +based on a "user identifier" (e.g. the user's email address or username). +The configuration above uses Doctrine to load the ``User`` entity using the +``email`` property as "user identifier". + +User providers are used in a couple places during the security lifecycle: + +**Load the User based on an identifier** + During login (or any other authenticator), the provider loads the user + based on the user identifier. Some other features, like + :doc:`user impersonation ` and + :doc:`Remember Me ` also use this. + +**Reload the User from the session** + At the beginning of each request, the user is loaded from the + session (unless your firewall is ``stateless``). The provider + "refreshes" the user (e.g. the database is queried again for fresh + data) to make sure all user information is up to date (and if + necessary, the user is de-authenticated/logged out if something + changed). See :ref:`user_session_refresh` for more information about + this process. + +Symfony comes with several built-in user providers: + +:ref:`Entity User Provider ` + Loads users from a database using :doc:`Doctrine `; +:ref:`LDAP User Provider ` + Loads users from a LDAP server; +:ref:`Memory User Provider ` + Loads users from a configuration file; +:ref:`Chain User Provider ` + Merges two or more user providers into a new user provider. + +The built-in user providers cover the most common needs for applications, but you +can also create your own :ref:`custom user provider `. -For example, by using :ref:`DoctrineFixturesBundle `, you can -create dummy database users: +.. note:: -.. code-block:: terminal + Sometimes, you need to inject the user provider in another class (e.g. + in your custom authenticator). All user providers follow this pattern + for their service ID: ``security.user.provider.concrete.`` + (where ```` is the configuration key, e.g. + ``app_user_provider``). If you only have one user provider, you can autowire + it using the :class:`Symfony\\Component\\Security\\Core\\User\\UserProviderInterface` + type-hint. - $ php bin/console make:fixtures +.. _security-encoding-user-password: - The class name of the fixtures to create (e.g. AppFixtures): - > UserFixtures +Registering the User: Hashing Passwords +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Use this service to encode the passwords: +Many applications require a user to log in with a password. For these +applications, the SecurityBundle provides password hashing and verification +functionality. -.. code-block:: diff +First, make sure your User class implements the +:class:`Symfony\\Component\\Security\\Core\\User\\PasswordAuthenticatedUserInterface`:: - // src/DataFixtures/UserFixtures.php + // src/Entity/User.php - + use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; // ... + use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; - class UserFixtures extends Fixture + class User implements UserInterface, PasswordAuthenticatedUserInterface { - + private $passwordEncoder; - - + public function __construct(UserPasswordEncoderInterface $passwordEncoder) - + { - + $this->passwordEncoder = $passwordEncoder; - + } + // ... - public function load(ObjectManager $manager) + /** + * @return string the hashed password for this user + */ + public function getPassword(): string { - $user = new User(); + return $this->password; + } + } + +Then, configure which password hasher should be used for this class. If your +``security.yaml`` file wasn't already pre-configured, then ``make:user`` should +have done this for you: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + password_hashers: + # Use native password hasher, which auto-selects and migrates the best + # possible hashing algorithm (starting from Symfony 5.3 this is "bcrypt") + Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use App\Entity\User; + use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; + + return static function (SecurityConfig $security) { // ... - + $user->setPassword($this->passwordEncoder->encodePassword( - + $user, - + 'the_new_password' - + )); + // Use native password hasher, which auto-selects and migrates the best + // possible hashing algorithm (starting from Symfony 5.3 this is "bcrypt") + $security->passwordHasher(PasswordAuthenticatedUserInterface::class) + ->algorithm('auto') + ; + }; + +.. versionadded:: 5.3 + + The ``password_hashers`` option was introduced in Symfony 5.3. In previous + versions it was called ``encoders``. + +Now that Symfony knows *how* you want to hash the passwords, you can use the +``UserPasswordHasherInterface`` service to do this before saving your users to +the database:: + + // src/Controller/RegistrationController.php + namespace App\Controller; + + // ... + use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; + + class RegistrationController extends AbstractController + { + public function index(UserPasswordHasherInterface $passwordHasher) + { + // ... e.g. get the user data from a registration form + $user = new User(...); + $plaintextPassword = ...; + + // hash the password (based on the security.yaml config for the $user class) + $hashedPassword = $passwordHasher->hashPassword( + $user, + $plaintextPassword + ); + $user->setPassword($hashedPassword); // ... } } -You can manually encode a password by running: +.. tip:: -.. code-block:: terminal + The ``make:registration-form`` maker command can help you set-up the + registration controller and add features like email address + verification using the `SymfonyCastsVerifyEmailBundle`_. - $ php bin/console security:encode-password + .. code-block:: terminal -.. _security-yaml-firewalls: -.. _security-firewalls: -.. _firewalls-authentication: + $ composer require symfonycasts/verify-email-bundle + $ php bin/console make:registration-form -3a) Authentication & Firewalls ------------------------------- +You can also manually hash a password by running: -.. versionadded:: 5.1 +.. code-block:: terminal + + $ php bin/console security:hash-password - The ``lazy: true`` option was introduced in Symfony 5.1. Prior to version 5.1, - it was enabled using ``anonymous: lazy`` +Read more about all available hashers and password migration in +:doc:`security/passwords`. -The security system is configured in ``config/packages/security.yaml``. The *most* -important section is ``firewalls``: +.. _firewalls-authentication: +.. _a-authentication-firewalls: + +The Firewall +------------ + +The ``firewalls`` section of ``config/packages/security.yaml`` is the *most* +important section. A "firewall" is your authentication system: the firewall +defines which parts of your application are secured and *how* your users +will be able to authenticate (e.g. login form, API token, etc). .. configuration-block:: @@ -288,18 +519,25 @@ important section is ``firewalls``: # config/packages/security.yaml security: + # ... firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: - anonymous: true lazy: true + provider: users_in_memory + + # activate different ways to authenticate + # https://symfony.com/doc/current/security.html#firewalls-authentication + + # https://symfony.com/doc/current/security/impersonating_user.html + # switch_user: true .. code-block:: xml - + + - + + + + + .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'dev' => [ - 'pattern' => '^/(_(profiler|wdt)|css|images|js)/', - 'security' => false, - ], - 'main' => [ - 'anonymous' => true, - 'lazy' => true, - ], - ], - ]); - -A "firewall" is your authentication system: the configuration below it defines -*how* your users will be able to authenticate (e.g. login form, API token, etc). + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... + $security->firewall('dev') + ->pattern('^/(_(profiler|wdt)|css|images|js)/') + ->security(false) + ; + + $security->firewall('main') + ->lazy(true) + + // activate different ways to authenticate + // https://symfony.com/doc/current/security.html#firewalls-authentication + + // https://symfony.com/doc/current/security/impersonating_user.html + // ->switchUser(true) + ; + }; Only one firewall is active on each request: Symfony uses the ``pattern`` key -to find the first match (you can also :doc:`match by host or other things `). -The ``dev`` firewall is really a fake firewall: it makes sure that you don't -accidentally block Symfony's dev tools - which live under URLs like ``/_profiler`` -and ``/_wdt``. +to find the first match (you can also +:doc:`match by host or other things `). + +The ``dev`` firewall is really a fake firewall: it makes sure that you +don't accidentally block Symfony's dev tools - which live under URLs like +``/_profiler`` and ``/_wdt``. All *real* URLs are handled by the ``main`` firewall (no ``pattern`` key means it matches *all* URLs). A firewall can have many modes of authentication, -in other words many ways to ask the question "Who are you?". Often, the -user is unknown (i.e. not logged in) when they first visit your website. The -``anonymous`` mode, if enabled, is used for these requests. +in other words many ways to ask the question "Who are you?". -In fact, if you go to the homepage right now, you *will* have access and you'll -see that you're "authenticated" as ``anon.``. The firewall verified that it -does not know your identity, and so, you are anonymous: +Often, the user is unknown (i.e. not logged in) when they first visit your +website. If you visit your homepage right now, you *will* have access and +you'll see that you're visiting a page behind the firewall in the toolbar: .. image:: /_images/security/anonymous_wdt.png :align: center -It means any request can have an anonymous token to access some resource, -while some actions (i.e. some pages or buttons) can still require specific -privileges. A user can then access a form login without being authenticated -as a unique user (otherwise an infinite redirection loop would happen -asking the user to authenticate while trying to doing so). - -You'll learn later how to deny access to certain URLs, controllers, or part of -templates. +Visiting a URL under a firewall doesn't necessarily require you to be authenticated +(e.g. the login form has to be accessible or some parts of your application +are public). You'll learn how to restrict access to URLs, controllers or +anything else within your firewall in the :ref:`access control +` section. .. tip:: @@ -376,7 +620,8 @@ templates. .. note:: - If you do not see the toolbar, install the :doc:`profiler ` with: + If you do not see the toolbar, install the :doc:`profiler ` + with: .. code-block:: terminal @@ -385,117 +630,69 @@ templates. Now that we understand our firewall, the next step is to create a way for your users to authenticate! -.. _security-form-login: +.. _security-authenticators: -3b) Authenticating your Users ------------------------------ +Authenticating Users +-------------------- -Authentication in Symfony can feel a bit "magic" at first. That's because, instead -of building a route & controller to handle login, you'll activate an -*authentication provider*: some code that runs automatically *before* your controller -is called. +During authentication, the system tries to find a matching user for the +visitor of the webpage. Traditionally, this was done using a login form or +a HTTP basic dialog in the browser. However, the SecurityBundle comes with +many other authenticators: -Symfony has several :doc:`built-in authentication providers `. -If your use-case matches one of these *exactly*, great! But, in most cases - including -a login form - *we recommend building a Guard Authenticator*: a class that allows -you to control *every* part of the authentication process (see the next section). +* `Form Login`_ +* `JSON Login`_ +* `HTTP Basic`_ +* `Login Link`_ +* `X.509 Client Certificates`_ +* `Remote users`_ +* :doc:`Custom Authenticators ` .. tip:: - If your application logs users in via a third-party service such as Google, - Facebook or Twitter (social login), check out the `HWIOAuthBundle`_ community - bundle. - -Guard Authenticators -~~~~~~~~~~~~~~~~~~~~ + If your application logs users in via a third-party service such as + Google, Facebook or Twitter (social login), check out the `HWIOAuthBundle`_ + community bundle. -A Guard authenticator is a class that gives you *complete* control over your -authentication process. There are many different ways to build an authenticator; -here are a few common use-cases: +.. _security-form-login: -* :doc:`/security/form_login_setup` -* :doc:`/security/guard_authentication` – see this for the most detailed - description of authenticators and how they work +Form Login +~~~~~~~~~~ -.. _`security-authorization`: -.. _denying-access-roles-and-other-authorization: +Most websites have a login form where users authenticate using an +identifier (e.g. email address or username) and a password. This +functionality is provided by the *form login authenticator*. -4) Denying Access, Roles and other Authorization ------------------------------------------------- +First, create a controller for the login form: -Users can now log in to your app using your login form. Great! Now, you need to learn -how to deny access and work with the User object. This is called **authorization**, -and its job is to decide if a user can access some resource (a URL, a model object, -a method call, ...). +.. code-block:: terminal -The process of authorization has two different sides: + $ php bin/console make:controller Login -#. The user receives a specific set of roles when logging in (e.g. ``ROLE_ADMIN``). -#. You add code so that a resource (e.g. URL, controller) requires a specific - "attribute" (most commonly a role like ``ROLE_ADMIN``) in order to be - accessed. + created: src/Controller/LoginController.php + created: templates/login/index.html.twig -Roles -~~~~~ +.. code-block:: php -When a user logs in, Symfony calls the ``getRoles()`` method on your ``User`` -object to determine which roles this user has. In the ``User`` class that we -generated earlier, the roles are an array that's stored in the database, and -every user is *always* given at least one role: ``ROLE_USER``:: + // src/Controller/LoginController.php + namespace App\Controller; - // src/Entity/User.php + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\Routing\Annotation\Route; - // ... - class User + class LoginController extends AbstractController { - /** - * @ORM\Column(type="json") - */ - private $roles = []; - - // ... - public function getRoles(): array + #[Route('/login', name: 'login')] + public function index(): Response { - $roles = $this->roles; - // guarantee every user at least has ROLE_USER - $roles[] = 'ROLE_USER'; - - return array_unique($roles); + return $this->render('login/index.html.twig', [ + 'controller_name' => 'LoginController', + ]); } } -This is a nice default, but you can do *whatever* you want to determine which roles -a user should have. Here are a few guidelines: - -* Every role **must start with** ``ROLE_`` (otherwise, things won't work as expected) - -* Other than the above rule, a role is just a string and you can invent what you - need (e.g. ``ROLE_PRODUCT_ADMIN``). - -You'll use these roles next to grant access to specific sections of your site. -You can also use a :ref:`role hierarchy ` where having -some roles automatically give you other roles. - -.. _security-role-authorization: - -Add Code to Deny Access -~~~~~~~~~~~~~~~~~~~~~~~ - -There are **two** ways to deny access to something: - -#. :ref:`access_control in security.yaml ` - allows you to protect URL patterns (e.g. ``/admin/*``). Simpler, but less flexible; - -#. :ref:`in your controller (or other code) `. - -.. _security-authorization-access-control: - -Securing URL patterns (access_control) -...................................... - -The most basic way to secure part of your app is to secure an entire URL pattern -in ``security.yaml``. For example, to require ``ROLE_ADMIN`` for all URLs that -start with ``/admin``, you can: +Then, enable the form login authenticator using the ``form_login`` setting: .. configuration-block:: @@ -506,25 +703,1343 @@ start with ``/admin``, you can: # ... firewalls: - # ... main: # ... + form_login: + # "login" is the name of the route created previously + login_path: login + check_path: login - access_control: - # require ROLE_ADMIN for /admin* - - { path: '^/admin', roles: ROLE_ADMIN } - - # or require ROLE_ADMIN or IS_AUTHENTICATED_FULLY for /admin* - - { path: '^/admin', roles: [IS_AUTHENTICATED_FULLY, ROLE_ADMIN] } + .. code-block:: xml - # the 'path' value can be any valid regular expression - # (this one will match URLs like /api/post/7298 and /api/comment/528491) + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... + + $mainFirewall = $security->firewall('main'); + + // "login" is the name of the route created previously + $mainFirewall->formLogin() + ->loginPath('login') + ->checkPath('login') + ; + }; + +.. note:: + + The ``login_path`` and ``check_path`` support URLs and route names (but + cannot have mandatory wildcards - e.g. ``/login/{foo}`` where ``foo`` + has no default value). + +Once enabled, the security system redirects unauthenticated visitors to the +``login_path`` when they try to access a secured place (this behavior can +be customized using :ref:`authentication entry points `). + +Edit the login controller to render the login form: + +.. code-block:: diff + + // ... + + use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; + + class LoginController extends AbstractController + { + #[Route('/login', name: 'login')] + - public function index(): Response + + public function index(AuthenticationUtils $authenticationUtils): Response + { + + // get the login error if there is one + + $error = $authenticationUtils->getLastAuthenticationError(); + + + + // last username entered by the user + + $lastUsername = $authenticationUtils->getLastUsername(); + + + return $this->render('login/index.html.twig', [ + - 'controller_name' => 'LoginController', + + 'last_username' => $lastUsername, + + 'error' => $error, + ]); + } + } + +Don't let this controller confuse you. Its job is only to *render* the form: +the ``form_login`` authenticator will handle the form *submission* automatically. +If the user submits an invalid email or password, that authenticator will store +the error and redirect back to this controller, where we read the error (using +``AuthenticationUtils``) so that it can be displayed back to the user. + +Finally, create or update the template: + +.. code-block:: html+twig + + {# templates/login/index.html.twig #} + {% extends 'base.html.twig' %} + + {# ... #} + + {% block body %} + {% if error %} +
    {{ error.messageKey|trans(error.messageData, 'security') }}
    + {% endif %} + +
    + + + + + + + {# If you want to control the URL the user is redirected to on success + #} + + +
    + {% endblock %} + +.. caution:: + + The ``error`` variable passed into the template is an instance of + :class:`Symfony\\Component\\Security\\Core\\Exception\\AuthenticationException`. + It may contain sensitive information about the authentication failure. + *Never* use ``error.message``: use the ``messageKey`` property instead, + as shown in the example. This message is always safe to display. + +The form can look like anything, but it usually follows some conventions: + +* The ``
    `` element sends a ``POST`` request to the ``login`` route, since + that's what you configured as the ``check_path`` under the ``form_login`` key in + ``security.yaml``; +* The username (or whatever your user's "identifier" is, like an email) field has + the name ``_username`` and the password field has the name ``_password``. + +.. tip:: + + Actually, all of this can be configured under the ``form_login`` key. See + :ref:`reference-security-firewall-form-login` for more details. + +.. caution:: + + This login form is currently not protected against CSRF attacks. Read + :ref:`form_login-csrf` on how to protect your login form. + +And that's it! When you submit the form, the security system automatically +reads the ``_username`` and ``_password`` POST parameter, loads the user via +the user provider, checks the user's credentials and either authenticates the +user or sends them back to the login form where the error can be displayed. + +To review the whole process: + +#. The user tries to access a resource that is protected (e.g. ``/admin``); +#. The firewall initiates the authentication process by redirecting the + user to the login form (``/login``); +#. The ``/login`` page renders login form via the route and controller created + in this example; +#. The user submits the login form to ``/login``; +#. The security system (i.e. the ``form_login`` authenticator) intercepts the + request, checks the user's submitted credentials, authenticates the user if + they are correct, and sends the user back to the login form if they are not. + +.. seealso:: + + You can customize the responses on a successful or failed login + attempt. See :doc:`/security/form_login`. + +.. _form_login-csrf: + +CSRF Protection in Login Forms +.............................. + +`Login CSRF attacks`_ can be prevented using the same technique of adding hidden +CSRF tokens into the login forms. The Security component already provides CSRF +protection, but you need to configure some options before using it. + +First, you need to enable CSRF on the form login: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + + firewalls: + secured_area: + # ... + form_login: + # ... + enable_csrf: true + + .. code-block:: xml + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... + + $mainFirewall = $security->firewall('main'); + $mainFirewall->formLogin() + // ... + ->enableCsrf(true) + ; + }; + +.. _csrf-login-template: + +Then, use the ``csrf_token()`` function in the Twig template to generate a CSRF +token and store it as a hidden field of the form. By default, the HTML field +must be called ``_csrf_token`` and the string used to generate the value must +be ``authenticate``: + +.. code-block:: html+twig + + {# templates/security/login.html.twig #} + + {# ... #} + + {# ... the login fields #} + + + + +
    + +After this, you have protected your login form against CSRF attacks. + +.. tip:: + + You can change the name of the field by setting ``csrf_parameter`` and change + the token ID by setting ``csrf_token_id`` in your configuration. See + :ref:`reference-security-firewall-form-login` for more details. + +JSON Login +~~~~~~~~~~ + +Some applications provide an API that is secured using tokens. These +applications may use an endpoint that provides these tokens based on a +username (or email) and password. The JSON login authenticator helps you create +this functionality. + +Enable the authenticator using the ``json_login`` setting: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + + firewalls: + main: + # ... + json_login: + # api_login is a route we will create below + check_path: api_login + + .. code-block:: xml + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... + + $mainFirewall = $security->firewall('main'); + $mainFirewall->jsonLogin() + ->checkPath('api_login') + ; + }; + +.. note:: + + The ``check_path`` supports URLs and route names (but cannot have + mandatory wildcards - e.g. ``/login/{foo}`` where ``foo`` has no + default value). + +The authenticator runs when a client request the ``check_path``. First, +create a controller for this path: + +.. code-block:: terminal + + $ php bin/console make:controller --no-template ApiLogin + + created: src/Controller/ApiLoginController.php + +.. code-block:: php + + // src/Controller/ApiLoginController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\Routing\Annotation\Route; + + class ApiLoginController extends AbstractController + { + #[Route('/api/login', name: 'api_login')] + public function index(): Response + { + return $this->json([ + 'message' => 'Welcome to your new controller!', + 'path' => 'src/Controller/ApiLoginController.php', + ]); + } + } + +This login controller will be called after the authenticator successfully +authenticates the user. You can get the authenticated user, generate a +token (or whatever you need to return) and return the JSON response: + +.. code-block:: diff + + // ... + + use App\Entity\User; + + use Symfony\Component\Security\Http\Attribute\CurrentUser; + + class ApiLoginController extends AbstractController + { + #[Route('/api/login', name: 'api_login')] + - public function index(): Response + + public function index(#[CurrentUser] ?User $user): Response + { + + if (null === $user) { + + return $this->json([ + + 'message' => 'missing credentials', + + ], Response::HTTP_UNAUTHORIZED); + + } + + + + $token = ...; // somehow create an API token for $user + + + return $this->json([ + - 'message' => 'Welcome to your new controller!', + - 'path' => 'src/Controller/ApiLoginController.php', + + 'user' => $user->getUserIdentifier(), + + 'token' => $token, + ]); + } + } + +.. note:: + + The ``#[CurrentUser]`` can only be used in controller arguments to + retrieve the authenticated user. In services, you would use + :method:`Symfony\\Component\\Security\\Core\\Security::getUser`. + +That's it! To summarize the process: + +#. A client (e.g. the front-end) makes a *POST request* with the + ``Content-Type: application/json`` header to ``/api/login`` with + ``username`` (even if your identifier is actually an email) and + ``password`` keys: + + .. code-block:: json + + { + "username": "dunglas@example.com", + "password": "MyPassword" + } +#. The security system intercepts the request, checks the user's submitted + credentials and authenticates the user. If the credentials is incorrect, + an HTTP 401 Unauthorized JSON response is returned, otherwise your + controller is run; +#. Your controller creates the correct response: + + .. code-block:: json + + { + "user": "dunglas@example.com", + "token": "45be42..." + } + +.. tip:: + + The JSON request format can be configured under the ``json_login`` key. + See :ref:`reference-security-firewall-json-login` for more details. + +.. _security-http_basic: + +HTTP Basic +~~~~~~~~~~ + +`HTTP Basic authentication`_ is a standardized HTTP authentication +framework. It asks credentials (username and password) using a dialog in +the browser and the HTTP basic authenticator of Symfony will verify these +credentials. + +Add the ``http_basic`` key to your firewall to enable HTTP Basic +authentication: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + + firewalls: + main: + # ... + http_basic: + realm: Secured Area + + .. code-block:: xml + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $mainFirewall = $security->firewall('main'); + $mainFirewall->httpBasic() + ->realm('Secured Area') + ; + }; + +That's it! Whenever an unauthenticated user tries to visit a protected +page, Symfony will inform the browser that it needs to start HTTP basic +authentication (using the ``WWW-Authenticate`` response header). Then, the +authenticator verifies the credentials and authenticates the user. + +.. note:: + + You cannot use :ref:`log out ` with the HTTP + basic authenticator. Even if you log out from Symfony, your browser + "remembers" your credentials and will send them on every request. + +Login Link +~~~~~~~~~~ + +Login links are a passwordless authentication mechanism. The user will +receive a short-lived link (e.g. via email) which will authenticate them to the +website. + +You can learn all about this authenticator in :doc:`/security/login_link`. + +X.509 Client Certificates +~~~~~~~~~~~~~~~~~~~~~~~~~ + +When using client certificates, your web server does all the authentication +itself. The X.509 authenticator provided by Symfony extracts the email from +the "distinguished name" (DN) of the client certificate. Then, it uses this +email as user identifier in the user provider. + +First, configure your web server to enable client certificate verification +and to expose the certificate's DN to the Symfony application: + +.. configuration-block:: + + .. code-block:: nginx + + server { + # ... + + ssl_client_certificate /path/to/my-custom-CA.pem; + + # enable client certificate verification + ssl_verify_client optional; + ssl_verify_depth 1; + + location / { + # pass the DN as "SSL_CLIENT_S_DN" to the application + fastcgi_param SSL_CLIENT_S_DN $ssl_client_s_dn; + + # ... + } + } + + .. code-block:: apache + + # ... + SSLCACertificateFile "/path/to/my-custom-CA.pem" + SSLVerifyClient optional + SSLVerifyDepth 1 + + # pass the DN to the application + SSLOptions +StdEnvVars + +Then, enable the X.509 authenticator using ``x509`` on your firewall: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + + firewalls: + main: + # ... + x509: + provider: your_user_provider + + .. code-block:: xml + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $mainFirewall = $security->firewall('main'); + $mainFirewall->x509() + ->provider('your_user_provider') + ; + }; + +By default, Symfony extracts the email address from the DN in two different +ways: + +#. First, it tries the ``SSL_CLIENT_S_DN_Email`` server parameter, which is + exposed by Apache; +#. If it is not set (e.g. when using Nginx), it uses ``SSL_CLIENT_S_DN`` and + matches the value following ``emailAddress=``. + +You can customize the name of both parameters under the ``x509`` key. See +:ref:`the configuration reference ` for +more details. + +Remote Users +~~~~~~~~~~~~ + +Besides client certificate authentication, there are more web server +modules that pre-authenticate a user (e.g. kerberos). The remote user +authenticator provides a basic integration for these services. + +These modules often expose the authenticated user in the ``REMOTE_USER`` +environment variable. The remote user authenticator uses this value as the +user identifier to load the corresponding user. + +Enable remote user authentication using the ``remote_user`` key: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + firewalls: + main: + # ... + remote_user: + provider: your_user_provider + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $mainFirewall = $security->firewall('main'); + $mainFirewall->remoteUser() + ->provider('your_user_provider') + ; + }; + +.. tip:: + + You can customize the name of this server variable under the + ``remote_user`` key. See + :ref:`the configuration reference ` + for more details. + +Limiting Login Attempts +~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.2 + + Login throttling was introduced in Symfony 5.2. + +Symfony provides basic protection against `brute force login attacks`_. +You must enable this using the ``login_throttling`` setting: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # you must use the authenticator manager + enable_authenticator_manager: true + + firewalls: + # ... + + main: + # ... + + # by default, the feature allows 5 login attempts per minute + login_throttling: null + + # configure the maximum login attempts (per minute) + login_throttling: + max_attempts: 3 + + # configure the maximum login attempts in a custom period of time + login_throttling: + max_attempts: 3 + interval: '15 minutes' + + # use a custom rate limiter via its service ID + login_throttling: + limiter: app.my_login_rate_limiter + + .. code-block:: xml + + + + + + + + + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->enableAuthenticatorManager(true); + + $mainFirewall = $security->firewall('main'); + + // by default, the feature allows 5 login attempts per minute + $mainFirewall->loginThrottling(); + + // configure the maximum login attempts (per minute) + $mainFirewall->loginThrottling() + ->maxAttempts(3) + ; + + // configure the maximum login attempts in a custom period of time + $mainFirewall->loginThrottling() + ->maxAttempts(3) + ->interval('15 minutes') + ; + }; + +.. versionadded:: 5.3 + + The ``login_throttling.interval`` option was introduced in Symfony 5.3. + +By default, login attempts are limited on ``max_attempts`` (default: 5) +failed requests for ``IP address + username`` and ``5 * max_attempts`` +failed requests for ``IP address``. The second limit protects against an +attacker using multiple usernames from bypassing the first limit, without +disrupting normal users on big networks (such as offices). + +.. tip:: + + Limiting the failed login attempts is only one basic protection against + brute force attacks. The `OWASP Brute Force Attacks`_ guidelines mention + several other protections that you should consider depending on the + level of protection required. + +If you need a more complex limiting algorithm, create a class that implements +:class:`Symfony\\Component\\HttpFoundation\\RateLimiter\\RequestRateLimiterInterface` +(or use +:class:`Symfony\\Component\\Security\\Http\\RateLimiter\\DefaultLoginRateLimiter`) +and set the ``limiter`` option to its service ID: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + framework: + rate_limiter: + # define 2 rate limiters (one for username+IP, the other for IP) + username_ip_login: + policy: token_bucket + limit: 5 + rate: { interval: '5 minutes' } + + ip_login: + policy: sliding_window + limit: 50 + interval: '15 minutes' + + services: + # our custom login rate limiter + app.login_rate_limiter: + class: Symfony\Component\Security\Http\RateLimiter\DefaultLoginRateLimiter + arguments: + # globalFactory is the limiter for IP + $globalFactory: '@limiter.ip_login' + # localFactory is the limiter for username+IP + $localFactory: '@limiter.username_ip_login' + + security: + firewalls: + main: + # use a custom rate limiter via its service ID + login_throttling: + limiter: app.login_rate_limiter + + .. code-block:: xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Component\DependencyInjection\Reference; + use Symfony\Component\Security\Http\RateLimiter\DefaultLoginRateLimiter; + use Symfony\Config\FrameworkConfig; + use Symfony\Config\SecurityConfig; + + return static function (ContainerBuilder $container, FrameworkConfig $framework, SecurityConfig $security) { + $framework->rateLimiter() + ->limiter('username_ip_login') + ->policy('token_bucket') + ->limit(5) + ->rate() + ->interval('5 minutes') + ; + + $framework->rateLimiter() + ->limiter('ip_login') + ->policy('sliding_window') + ->limit(50) + ->interval('15 minutes') + ; + + $container->register('app.login_rate_limiter', DefaultLoginRateLimiter::class) + ->setArguments([ + // 1st argument is the limiter for IP + new Reference('limiter.ip_login'), + // 2nd argument is the limiter for username+IP + new Reference('limiter.username_ip_login'), + ]); + + $security->firewall('main') + ->loginThrottling() + ->limiter('app.login_rate_limiter') + ; + }; + +.. _security-logging-out: + +Logging Out +----------- + +To enable logging out, activate the ``logout`` config parameter under your firewall: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + + firewalls: + main: + # ... + logout: + path: app_logout + + # where to redirect after logout + # target: app_any_route + + .. code-block:: xml + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... + + $mainFirewall = $security->firewall('main'); + // ... + $mainFirewall->logout() + ->path('app_logout') + + // where to redirect after logout + // ->target('app_any_route') + ; + }; + +Next, you need to create a route for this URL (but not a controller): + +.. configuration-block:: + + .. code-block:: php-annotations + + // src/Controller/SecurityController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class SecurityController extends AbstractController + { + /** + * @Route("/logout", name="app_logout", methods={"GET"}) + */ + public function logout(): void + { + // controller can be blank: it will never be called! + throw new \Exception('Don\'t forget to activate logout in security.yaml'); + } + } + + .. code-block:: php-attributes + + // src/Controller/SecurityController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class SecurityController extends AbstractController + { + #[Route('/logout', name: 'app_logout', methods: ['GET'])] + public function logout() + { + // controller can be blank: it will never be called! + throw new \Exception('Don\'t forget to activate logout in security.yaml'); + } + } + + .. code-block:: yaml + + # config/routes.yaml + app_logout: + path: /logout + methods: GET + + .. code-block:: xml + + + + + + + + + .. code-block:: php + + // config/routes.php + use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; + + return function (RoutingConfigurator $routes) { + $routes->add('app_logout', '/logout') + ->methods(['GET']) + ; + }; + +That's it! By sending a user to the ``app_logout`` route (i.e. to ``/logout``) +Symfony will un-authenticate the current user and redirect them. + +Customizing Logout +~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.1 + + The ``LogoutEvent`` was introduced in Symfony 5.1. Prior to this + version, you had to use a + :ref:`logout success handler ` + to customize the logout. + +In some cases you need to run extra logic upon logout (e.g. invalidate +some tokens) or want to customize what happens after a logout. During +logout, a :class:`Symfony\\Component\\Security\\Http\\Event\\LogoutEvent` +is dispatched. Register an :doc:`event listener or subscriber ` +to run custom logic. The following information is available in the +event class: + +``getToken()`` + Returns the security token of the session that is about to be logged + out. +``getRequest()`` + Returns the current request. +``getResponse()`` + Returns a response, if it is already set by a custom listener. Use + ``setResponse()`` to configure a custom logout response. + +.. _retrieving-the-user-object: + +Fetching the User Object +------------------------ + +After authentication, the ``User`` object of the current user can be +accessed via the ``getUser()`` shortcut in the +:ref:`base controller `:: + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + + class ProfileController extends AbstractController + { + public function index(): Response + { + // usually you'll want to make sure the user is authenticated first, + // see "Authorization" below + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); + + // returns your User object, or null if the user is not authenticated + // use inline documentation to tell your editor your exact User class + /** @var \App\Entity\User $user */ + $user = $this->getUser(); + + // Call whatever methods you've added to your User class + // For example, if you added a getFirstName() method, you can use that. + return new Response('Well hi there '.$user->getFirstName()); + } + } + +Fetching the User from a Service +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you need to get the logged in user from a service, use the +:class:`Symfony\\Component\\Security\\Core\\Security` service:: + + // src/Service/ExampleService.php + // ... + + use Symfony\Component\Security\Core\Security; + + class ExampleService + { + private $security; + + public function __construct(Security $security) + { + // Avoid calling getUser() in the constructor: auth may not + // be complete yet. Instead, store the entire Security object. + $this->security = $security; + } + + public function someMethod() + { + // returns User object or null if not authenticated + $user = $this->security->getUser(); + + // ... + } + } + +Fetch the User in a Template +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In a Twig Template the user object is available via the ``app.user`` variable +thanks to the :ref:`Twig global app variable `: + +.. code-block:: html+twig + + {% if is_granted('IS_AUTHENTICATED_FULLY') %} +

    Email: {{ app.user.email }}

    + {% endif %} + +.. _denying-access-roles-and-other-authorization: +.. _security-access-control: + +Access Control (Authorization) +------------------------------ + +Users can now log in to your app using your login form. Great! Now, you need to learn +how to deny access and work with the User object. This is called **authorization**, +and its job is to decide if a user can access some resource (a URL, a model object, +a method call, ...). + +The process of authorization has two different sides: + +#. The user receives a specific role when logging in (e.g. ``ROLE_ADMIN``). +#. You add code so that a resource (e.g. URL, controller) requires a specific + "attribute" (e.g. a role like ``ROLE_ADMIN``) in order to be accessed. + +Roles +~~~~~ + +When a user logs in, Symfony calls the ``getRoles()`` method on your ``User`` +object to determine which roles this user has. In the ``User`` class that +was generated earlier, the roles are an array that's stored in the +database and every user is *always* given at least one role: ``ROLE_USER``:: + + // src/Entity/User.php + + // ... + class User + { + /** + * @ORM\Column(type="json") + */ + private $roles = []; + + // ... + public function getRoles(): array + { + $roles = $this->roles; + // guarantee every user at least has ROLE_USER + $roles[] = 'ROLE_USER'; + + return array_unique($roles); + } + } + +This is a nice default, but you can do *whatever* you want to determine which roles +a user should have. Here are a few guidelines: + +* Every role **must start with** ``ROLE_`` (otherwise, things won't work as expected) + +* Other than the above rule, a role is just a string and you can invent what you + need (e.g. ``ROLE_PRODUCT_ADMIN``). + +You'll use these roles next to grant access to specific sections of your site. + +.. _security-role-hierarchy: + +Hierarchical Roles +.................. + +Instead of giving many roles to each user, you can define role inheritance +rules by creating a role hierarchy: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + + role_hierarchy: + ROLE_ADMIN: ROLE_USER + ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] + + .. code-block:: xml + + + + + + + + + ROLE_USER + ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... + + $security->roleHierarchy('ROLE_ADMIN', ['ROLE_USER']); + $security->roleHierarchy('ROLE_SUPER_ADMIN', ['ROLE_ADMIN', 'ROLE_ALLOWED_TO_SWITCH']); + }; + +Users with the ``ROLE_ADMIN`` role will also have the ``ROLE_USER`` role. +Users with ``ROLE_SUPER_ADMIN``, will automatically have ``ROLE_ADMIN``, +``ROLE_ALLOWED_TO_SWITCH`` and ``ROLE_USER`` (inherited from +``ROLE_ADMIN``). + +.. caution:: + + For role hierarchy to work, do not use ``$user->getRoles()`` manually. + For example, in a controller extending from the :ref:`base controller `:: + + // BAD - $user->getRoles() will not know about the role hierarchy + $hasAccess = in_array('ROLE_ADMIN', $user->getRoles()); + + // GOOD - use of the normal security methods + $hasAccess = $this->isGranted('ROLE_ADMIN'); + $this->denyAccessUnlessGranted('ROLE_ADMIN'); + +.. note:: + + The ``role_hierarchy`` values are static - you can't, for example, store the + role hierarchy in a database. If you need that, create a custom + :doc:`security voter ` that looks for the user roles + in the database. + +.. _security-role-authorization: + +Add Code to Deny Access +~~~~~~~~~~~~~~~~~~~~~~~ + +There are **two** ways to deny access to something: + +#. :ref:`access_control in security.yaml ` + allows you to protect URL patterns (e.g. ``/admin/*``). Simpler, but less flexible; + +#. :ref:`in your controller (or other code) `. + +.. _security-authorization-access-control: + +Securing URL patterns (access_control) +...................................... + +The most basic way to secure part of your app is to secure an entire URL pattern +in ``security.yaml``. For example, to require ``ROLE_ADMIN`` for all URLs that +start with ``/admin``, you can: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + + firewalls: + # ... + main: + # ... + + access_control: + # require ROLE_ADMIN for /admin* + - { path: '^/admin', roles: ROLE_ADMIN } + + # or require ROLE_ADMIN or IS_AUTHENTICATED_FULLY for /admin* + - { path: '^/admin', roles: [IS_AUTHENTICATED_FULLY, ROLE_ADMIN] } + + # the 'path' value can be any valid regular expression + # (this one will match URLs like /api/post/7298 and /api/comment/528491) - { path: ^/api/(post|comment)/\d+$, roles: ROLE_USER } .. code-block:: xml - + loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->enableAuthenticatorManager(true); + // ... + $security->firewall('main') + // ... + ; - 'firewalls' => [ - // ... - 'main' => [ - // ... - ], - ], - 'access_control' => [ - // require ROLE_ADMIN for /admin* - ['path' => '^/admin', 'roles' => 'ROLE_ADMIN'], - - // require ROLE_ADMIN or IS_AUTHENTICATED_FULLY for /admin* - ['path' => '^/admin', 'roles' => ['ROLE_ADMIN', 'IS_AUTHENTICATED_FULLY']], - - // the 'path' value can be any valid regular expression - // (this one will match URLs like /api/post/7298 and /api/comment/528491) - ['path' => '^/api/(post|comment)/\d+$', 'roles' => 'ROLE_USER'], - ], - ]); + // require ROLE_ADMIN for /admin* + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_ADMIN']); + + // require ROLE_ADMIN or IS_AUTHENTICATED_FULLY for /admin* + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_ADMIN', 'IS_AUTHENTICATED_FULLY']); + + // the 'path' value can be any valid regular expression + // (this one will match URLs like /api/post/7298 and /api/comment/528491) + $security->accessControl() + ->path('^/api/(post|comment)/\d+$') + ->roles(['ROLE_USER']); + }; You can define as many URL patterns as you need - each is a regular expression. **BUT**, only **one** will be matched per request: Symfony starts at the top of @@ -602,7 +2122,7 @@ the list and stops when it finds the first match: .. code-block:: xml - + loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'access_control' => [ - ['path' => '^/admin/users', 'roles' => 'ROLE_SUPER_ADMIN'], - ['path' => '^/admin', 'roles' => 'ROLE_ADMIN'], - ], - ]); + $security->accessControl() + ->path('^/admin/users') + ->roles(['ROLE_SUPER_ADMIN']); + + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_ADMIN']); + }; Prepending the path with ``^`` means that only URLs *beginning* with the pattern are matched. For example, a path of ``/admin`` (without the ``^``) @@ -649,7 +2174,7 @@ You can deny access from inside a controller:: // src/Controller/AdminController.php // ... - public function adminDashboard() + public function adminDashboard(): Response { $this->denyAccessUnlessGranted('ROLE_ADMIN'); @@ -671,187 +2196,109 @@ will happen: .. _security-securing-controller-annotations: -Thanks to the SensioFrameworkExtraBundle, you can also secure your controller -using annotations: - -.. code-block:: diff - - // src/Controller/AdminController.php - // ... - - + use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted; - - + /** - + * Require ROLE_ADMIN for *every* controller method in this class. - + * - + * @IsGranted("ROLE_ADMIN") - + */ - class AdminController extends AbstractController - { - + /** - + * Require ROLE_ADMIN for only this controller method. - + * - + * @IsGranted("ROLE_ADMIN") - + */ - public function adminDashboard() - { - // ... - } - } - -For more information, see the `FrameworkExtraBundle documentation`_. - -.. _security-template: - -Access Control in Templates -........................... - -If you want to check if the current user has a certain role, you can use -the built-in ``is_granted()`` helper function in any Twig template: - -.. code-block:: html+twig - - {% if is_granted('ROLE_ADMIN') %} -
    Delete - {% endif %} - -Securing other Services -....................... - -See :doc:`/security/securing_services`. - -Setting Individual User Permissions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Most applications require more specific access rules. For instance, a user -should be able to only edit their *own* comments on a blog. Voters allow you -to write *whatever* business logic you need to determine access. Using -these voters is similar to the role-based access checks implemented in the -previous chapters. Read :doc:`/security/voters` to learn how to implement -your own voter. - -Checking to see if a User is Logged In (IS_AUTHENTICATED_FULLY) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you *only* want to check if a user is logged in (you don't care about roles), -you have two options. First, if you've given *every* user ``ROLE_USER``, you can -check for that role. Otherwise, you can use a special "attribute" in place of a -role:: - - // ... - - public function adminDashboard() - { - $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); - - // ... - } - -You can use ``IS_AUTHENTICATED_FULLY`` anywhere roles are used: like -``access_control`` or in Twig. - -``IS_AUTHENTICATED_FULLY`` isn't a role, but it kind of acts like one, and every -user that has logged in will have this. Actually, there are some special attributes -like this: - -* ``IS_AUTHENTICATED_REMEMBERED``: *All* logged in users have this, even - if they are logged in because of a "remember me cookie". Even if you don't - use the :doc:`remember me functionality `, - you can use this to check if the user is logged in. +Thanks to the SensioFrameworkExtraBundle, you can also secure your controller +using annotations: -* ``IS_AUTHENTICATED_FULLY``: This is similar to ``IS_AUTHENTICATED_REMEMBERED``, - but stronger. Users who are logged in only because of a "remember me cookie" - will have ``IS_AUTHENTICATED_REMEMBERED`` but will not have ``IS_AUTHENTICATED_FULLY``. +.. code-block:: diff -* ``IS_AUTHENTICATED_ANONYMOUSLY``: *All* users (even anonymous ones) have - this - this is useful when *whitelisting* URLs to guarantee access - some - details are in :doc:`/security/access_control`. + // src/Controller/AdminController.php + // ... -* ``IS_ANONYMOUS``: *Only* anonymous users are matched by this attribute. + + use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted; -* ``IS_REMEMBERED``: *Only* users authenticated using the - :doc:`remember me functionality `, (i.e. a - remember-me cookie). + + /** + + * Require ROLE_ADMIN for *every* controller method in this class. + + * + + * @IsGranted("ROLE_ADMIN") + + */ + class AdminController extends AbstractController + { + + /** + + * Require ROLE_ADMIN for only this controller method. + + * + + * @IsGranted("ROLE_ADMIN") + + */ + public function adminDashboard(): Response + { + // ... + } + } -* ``IS_IMPERSONATOR``: When the current user is - :doc:`impersonating ` another user in this - session, this attribute will match. +For more information, see the `FrameworkExtraBundle documentation`_. -.. versionadded:: 5.1 +.. _security-template: - The ``IS_ANONYMOUS``, ``IS_REMEMBERED`` and ``IS_IMPERSONATOR`` - attributes were introduced in Symfony 5.1. +Access Control in Templates +........................... -.. _retrieving-the-user-object: +If you want to check if the current user has a certain role, you can use +the built-in ``is_granted()`` helper function in any Twig template: -5a) Fetching the User Object ----------------------------- +.. code-block:: html+twig -After authentication, the ``User`` object of the current user can be accessed -via the ``getUser()`` shortcut:: + {% if is_granted('ROLE_ADMIN') %} + Delete + {% endif %} - public function index() - { - // usually you'll want to make sure the user is authenticated first - $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); +.. _security-isgranted: - // returns your User object, or null if the user is not authenticated - // use inline documentation to tell your editor your exact User class - /** @var \App\Entity\User $user */ - $user = $this->getUser(); +Securing other Services +....................... - // Call whatever methods you've added to your User class - // For example, if you added a getFirstName() method, you can use that. - return new Response('Well hi there '.$user->getFirstName()); - } +You can check access *anywhere* in your code by injecting the ``Security`` +service. For example, suppose you have a ``SalesReportManager`` service and you +want to include extra details only for users that have a ``ROLE_SALES_ADMIN`` role: -5b) Fetching the User from a Service ------------------------------------- +.. code-block:: diff -If you need to get the logged in user from a service, use the -:class:`Symfony\\Component\\Security\\Core\\Security` service:: + // src/SalesReport/SalesReportManager.php - // src/Service/ExampleService.php - // ... + // ... + use Symfony\Component\Security\Core\Exception\AccessDeniedException; + + use Symfony\Component\Security\Core\Security; - use Symfony\Component\Security\Core\Security; + class SalesReportManager + { + + private $security; - class ExampleService - { - private $security; + + public function __construct(Security $security) + + { + + $this->security = $security; + + } - public function __construct(Security $security) - { - // Avoid calling getUser() in the constructor: auth may not - // be complete yet. Instead, store the entire Security object. - $this->security = $security; - } + public function generateReport() + { + $salesData = []; - public function someMethod() - { - // returns User object or null if not authenticated - $user = $this->security->getUser(); - } - } + + if ($this->security->isGranted('ROLE_SALES_ADMIN')) { + + $salesData['top_secret_numbers'] = rand(); + + } -Fetch the User in a Template -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // ... + } -In a Twig Template the user object is available via the ``app.user`` variable -thanks to the :ref:`Twig global app variable `: + // ... + } -.. code-block:: html+twig +If you're using the :ref:`default services.yaml configuration `, +Symfony will automatically pass the ``security.helper`` to your service +thanks to autowiring and the ``Security`` type-hint. - {% if is_granted('IS_AUTHENTICATED_FULLY') %} -

    Email: {{ app.user.email }}

    - {% endif %} +You can also use a lower-level +:class:`Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationCheckerInterface` +service. It does the same thing as ``Security``, but allows you to type-hint a +more-specific interface. -.. _security-logging-out: +Allowing Unsecured Access (i.e. Anonymous Users) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Logging Out ------------ +When a visitor isn't yet logged in to your website, they are treated as +"unauthenticated" and don't have any roles. This will block them from +visiting your pages if you defined an ``access_control`` rule. -To enable logging out, activate the ``logout`` config parameter under your firewall: +In the ``access_control`` configuration, you can use the ``PUBLIC_ACCESS`` +security attribute to exclude some routes for unauthenticated access (e.g. +the login page): .. configuration-block:: @@ -859,16 +2306,15 @@ To enable logging out, activate the ``logout`` config parameter under your fire # config/packages/security.yaml security: - # ... + enable_authenticator_manager: true - firewalls: - main: - # ... - logout: - path: app_logout + # ... + access_control: + # allow unauthenticated users to access the login form + - { path: ^/admin/login, roles: PUBLIC_ACCESS } - # where to redirect after logout - # target: app_any_route + # but require authentication for all other admin routes + - { path: ^/admin, roles: ROLE_ADMIN } .. code-block:: xml @@ -882,121 +2328,181 @@ To enable logging out, activate the ``logout`` config parameter under your fire http://symfony.com/schema/dic/security https://symfony.com/schema/dic/security/security-1.0.xsd"> - + - - - - + + + + + + + .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - // ... + use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter; + use Symfony\Config\SecurityConfig; - 'firewalls' => [ - 'secured_area' => [ - // ... - 'logout' => ['path' => 'app_logout'], - ], - ], - ]); + return static function (SecurityConfig $security) { + $security->enableAuthenticatorManager(true); + // .... -Next, you'll need to create a route for this URL (but not a controller): + // allow unauthenticated users to access the login form + $security->accessControl() + ->path('^/admin/login') + ->roles([AuthenticatedVoter::PUBLIC_ACCESS]) + ; -.. configuration-block:: + // but require authentication for all other admin routes + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_ADMIN']) + ; + }; - .. code-block:: php-annotations +Granting Anonymous Users Access in a Custom Voter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // src/Controller/SecurityController.php - namespace App\Controller; +If you're using a :doc:`custom voter `, you can allow +anonymous users access by checking if there is no user set on the token:: - use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; - use Symfony\Component\Routing\Annotation\Route; + // src/Security/PostVoter.php + namespace App\Security; - class SecurityController extends AbstractController + // ... + use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + use Symfony\Component\Security\Core\Authentication\User\UserInterface; + use Symfony\Component\Security\Core\Authorization\Voter\Voter; + + class PostVoter extends Voter + { + // ... + + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool { - /** - * @Route("/logout", name="app_logout", methods={"GET"}) - */ - public function logout() - { - // controller can be blank: it will never be executed! - throw new \Exception('Don\'t forget to activate logout in security.yaml'); + // ... + + if (!$token->getUser() instanceof UserInterface) { + // the user is not authenticated, e.g. only allow them to + // see public posts + return $subject->isPublic(); } } + } - .. code-block:: yaml +Setting Individual User Permissions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - # config/routes.yaml - app_logout: - path: /logout - methods: GET +Most applications require more specific access rules. For instance, a user +should be able to only edit their *own* comments on a blog. Voters allow you +to write *whatever* business logic you need to determine access. Using +these voters is similar to the role-based access checks implemented in the +previous chapters. Read :doc:`/security/voters` to learn how to implement +your own voter. - .. code-block:: xml +Checking to see if a User is Logged In (IS_AUTHENTICATED_FULLY) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - - +If you *only* want to check if a user is logged in (you don't care about roles), +you have two options. First, if you've given *every* user ``ROLE_USER``, you can +check for that role. Otherwise, you can use a special "attribute" in place of a +role:: - - + // ... - .. code-block:: php + public function adminDashboard(): Response + { + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); - // config/routes.php - use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; + // ... + } - return function (RoutingConfigurator $routes) { - $routes->add('app_logout', '/logout') - ->methods(['GET']) - ; - }; +You can use ``IS_AUTHENTICATED_FULLY`` anywhere roles are used: like +``access_control`` or in Twig. -And that's it! By sending a user to the ``app_logout`` route (i.e. to ``/logout``) -Symfony will un-authenticate the current user and redirect them. +``IS_AUTHENTICATED_FULLY`` isn't a role, but it kind of acts like one, and every +user that has logged in will have this. Actually, there are some special attributes +like this: -Customizing Logout -~~~~~~~~~~~~~~~~~~ +* ``IS_AUTHENTICATED_REMEMBERED``: *All* logged in users have this, even + if they are logged in because of a "remember me cookie". Even if you don't + use the :doc:`remember me functionality `, + you can use this to check if the user is logged in. + +* ``IS_AUTHENTICATED_FULLY``: This is similar to ``IS_AUTHENTICATED_REMEMBERED``, + but stronger. Users who are logged in only because of a "remember me cookie" + will have ``IS_AUTHENTICATED_REMEMBERED`` but will not have ``IS_AUTHENTICATED_FULLY``. + +* ``IS_REMEMBERED``: *Only* users authenticated using the + :doc:`remember me functionality `, (i.e. a + remember-me cookie). + +* ``IS_IMPERSONATOR``: When the current user is + :doc:`impersonating ` another user in this + session, this attribute will match. .. versionadded:: 5.1 - The ``LogoutEvent`` was introduced in Symfony 5.1. Prior to this - version, you had to use a - :ref:`logout success handler ` - to customize the logout. + The ``IS_REMEMBERED`` and ``IS_IMPERSONATOR`` attributes were + introduced in Symfony 5.1. -In some cases you need to execute extra logic upon logout (e.g. invalidate -some tokens) or want to customize what happens after a logout. During -logout, a :class:`Symfony\\Component\\Security\\Http\\Event\\LogoutEvent` -is dispatched. Register an :doc:`event listener or subscriber ` -to execute custom logic. The following information is available in the -event class: +.. deprecated:: 5.3 -``getToken()`` - Returns the security token of the session that is about to be logged - out. -``getRequest()`` - Returns the current request. -``getResponse()`` - Returns a response, if it is already set by a custom listener. Use - ``setResponse()`` to configure a custom logout response. + The ``IS_ANONYMOUS`` and ``IS_AUTHENTICATED_ANONYMOUSLY`` attributes are + deprecated since Symfony 5.3. + +.. _user_session_refresh: + +Understanding how Users are Refreshed from the Session +------------------------------------------------------ + +At the end of every request (unless your firewall is ``stateless``), your +``User`` object is serialized to the session. At the beginning of the next +request, it's deserialized and then passed to your user provider to "refresh" it +(e.g. Doctrine queries for a fresh user). + +Then, the two User objects (the original from the session and the refreshed User +object) are "compared" to see if they are "equal". By default, the core +``AbstractToken`` class compares the return values of the ``getPassword()``, +``getSalt()`` and ``getUserIdentifier()`` methods. If any of these are different, +your user will be logged out. This is a security measure to make sure that malicious +users can be de-authenticated if core user data changes. + +However, in some cases, this process can cause unexpected authentication problems. +If you're having problems authenticating, it could be that you *are* authenticating +successfully, but you immediately lose authentication after the first redirect. + +In that case, review the serialization logic (e.g. ``SerializableInterface``) on +you user class (if you have any) to make sure that all the fields necessary are +serialized. + +Comparing Users Manually with EquatableInterface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Or, if you need more control over the "compare users" process, make your User class +implement :class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface`. +Then, your ``isEqualTo()`` method will be called when comparing users instead +of the core logic. + +Security Events +--------------- +During the authentication process, multiple events are dispatched that allow you +to hook into the process or customize the response sent back to the user. You +can do this by creating an :doc:`event listener or subscriber ` +for these events. .. tip:: Every Security firewall has its own event dispatcher - (``security.event_dispatcher.FIREWALLNAME``). The logout event is - dispatched on both the global and firewall dispatcher. You can register + (``security.event_dispatcher.FIREWALLNAME``). Events are dispatched on + both the global and the firewall-specific dispatcher. You can register on the firewall dispatcher if you want your listener to only be - executed for a specific firewall. For instance, if you have an ``api`` + called for a specific firewall. For instance, if you have an ``api`` and ``main`` firewall, use this configuration to register only on the logout event in the ``main`` firewall: @@ -1051,91 +2557,61 @@ event class: ]); }; -.. _security-role-hierarchy: - -Hierarchical Roles ------------------- - -Instead of giving many roles to each user, you can define role inheritance -rules by creating a role hierarchy: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - role_hierarchy: - ROLE_ADMIN: ROLE_USER - ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] - - .. code-block:: xml - - - - +Authentication Events +~~~~~~~~~~~~~~~~~~~~~ - - +.. raw:: html - ROLE_USER - ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH - - + - .. code-block:: php +:class:`Symfony\\Component\\Security\\Http\\Event\\CheckPassportEvent` + Dispatched after the authenticator created the :ref:`security passport `. + Listeners of this event do the actual authentication checks (like + checking the passport, validating the CSRF token, etc.) - // config/packages/security.php - $container->loadFromExtension('security', [ - // ... +:class:`Symfony\\Component\\Security\\Http\\Event\\AuthenticationTokenCreatedEvent` + Dispatched after the passport was validated and the authenticator + created the security token (and user). This can be used in advanced use-cases + where you need to modify the created token (e.g. for multi factor + authentication). - 'role_hierarchy' => [ - 'ROLE_ADMIN' => 'ROLE_USER', - 'ROLE_SUPER_ADMIN' => [ - 'ROLE_ADMIN', - 'ROLE_ALLOWED_TO_SWITCH', - ], - ], - ]); +:class:`Symfony\\Component\\Security\\Http\\Event\\AuthenticationSuccessEvent` + Dispatched when authentication is nearing success. This is the last + event that can make an authentication fail by throwing an + ``AuthenticationException``. -Users with the ``ROLE_ADMIN`` role will also have the -``ROLE_USER`` role. And users with ``ROLE_SUPER_ADMIN``, will automatically have -``ROLE_ADMIN``, ``ROLE_ALLOWED_TO_SWITCH`` and ``ROLE_USER`` (inherited from ``ROLE_ADMIN``). +:class:`Symfony\\Component\\Security\\Http\\Event\\LoginSuccessEvent` + Dispatched after authentication was fully successful. Listeners to this + event can modify the response sent back to the user. -For role hierarchy to work, do not try to call ``$user->getRoles()`` manually. -For example, in a controller extending from the :ref:`base controller `:: +:class:`Symfony\\Component\\Security\\Http\\Event\\LoginFailureEvent` + Dispatched after an ``AuthenticationException`` was thrown during + authentication. Listeners to this event can modify the error response + sent back to the user. - // BAD - $user->getRoles() will not know about the role hierarchy - $hasAccess = in_array('ROLE_ADMIN', $user->getRoles()); +Other Events +~~~~~~~~~~~~ - // GOOD - use of the normal security methods - $hasAccess = $this->isGranted('ROLE_ADMIN'); - $this->denyAccessUnlessGranted('ROLE_ADMIN'); +:class:`Symfony\\Component\\Security\\Http\\Event\\LogoutEvent` + Dispatched just before a user logs out of your application. See + :ref:`security-logging-out`. -.. note:: +:class:`Symfony\\Component\\Security\\Http\\Event\\TokenDeauthenticatedEvent` + Dispatched when a user is deauthenticated, for instance because the + password was changed. See :ref:`user_session_refresh`. - The ``role_hierarchy`` values are static - you can't, for example, store the - role hierarchy in a database. If you need that, create a custom - :doc:`security voter ` that looks for the user roles - in the database. +:class:`Symfony\\Component\\Security\\Http\\Event\\SwitchUserEvent` + Dispatched after impersonation is completed. See + :doc:`/security/impersonating_user`. Frequently Asked Questions -------------------------- **Can I have Multiple Firewalls?** Yes! But it's usually not necessary. Each firewall is like a separate security - system. And so, unless you have *very* different authentication needs, one - firewall usually works well. With :doc:`Guard authentication `, - you can create various, diverse ways of allowing authentication (e.g. form login, - API key authentication and LDAP) all under the same firewall. + system, being authenticated in one firewall doesn't make you authenticated in + another one. One firewall can have multiple diverse ways of allowing + authentication (e.g. form login, API key authentication and LDAP). **Can I Share Authentication Between Firewalls?** Yes, but only with some configuration. If you're using multiple firewalls and @@ -1172,23 +2648,16 @@ Authentication (Identifying/Logging in the User) .. toctree:: :maxdepth: 1 - security/experimental_authenticators - security/form_login_setup - security/reset_password - security/json_login_setup - security/guard_authentication - security/password_migration - security/auth_providers - security/user_provider + security/passwords security/ldap security/remember_me security/impersonating_user security/user_checkers - security/named_encoders - security/multiple_guard_authenticators security/firewall_restriction security/csrf - security/custom_authentication_provider + security/form_login + security/custom_authenticator + security/entry_point Authorization (Denying Access) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1197,13 +2666,16 @@ Authorization (Denying Access) :maxdepth: 1 security/voters - security/securing_services security/access_control security/access_denied_handler - security/acl security/force_https +.. _`5.2 version of this documentation`: https://symfony.com/doc/5.2/security.html .. _`FrameworkExtraBundle documentation`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html .. _`HWIOAuthBundle`: https://github.com/hwi/HWIOAuthBundle -.. _`Symfony Security screencast series`: https://symfonycasts.com/screencast/symfony-security +.. _`OWASP Brute Force Attacks`: https://owasp.org/www-community/controls/Blocking_Brute_Force_Attacks +.. _`brute force login attacks`: https://owasp.org/www-community/controls/Blocking_Brute_Force_Attacks .. _`MakerBundle`: https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html +.. _`SymfonyCastsVerifyEmailBundle`: https://github.com/symfonycasts/verify-email-bundle +.. _`HTTP Basic authentication`: https://en.wikipedia.org/wiki/Basic_access_authentication +.. _`Login CSRF attacks`: https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests diff --git a/security/_supportsToken.rst.inc b/security/_supportsToken.rst.inc deleted file mode 100644 index e4403123a01..00000000000 --- a/security/_supportsToken.rst.inc +++ /dev/null @@ -1,10 +0,0 @@ -After Symfony calls ``createToken()``, it will then call ``supportsToken()`` -on your class (and any other authentication listeners) to figure out who should -handle the token. This is just a way to allow several authentication mechanisms -to be used for the same firewall (that way, you can for instance first try -to authenticate the user via a certificate or an API key and fall back to -a form login). - -Essentially, you need to make sure that this method returns ``true`` for a -token that has been created by ``createToken()``. Your logic should probably -look exactly like this example. diff --git a/security/access_control.rst b/security/access_control.rst index 225687c02f6..0f32e30b427 100644 --- a/security/access_control.rst +++ b/security/access_control.rst @@ -43,8 +43,8 @@ Take the following ``access_control`` entries as an example: security: # ... access_control: - - { path: '^/admin', roles: ROLE_USER_IP, ip: 127.0.0.1 } - { path: '^/admin', roles: ROLE_USER_PORT, ip: 127.0.0.1, port: 8080 } + - { path: '^/admin', roles: ROLE_USER_IP, ip: 127.0.0.1 } - { path: '^/admin', roles: ROLE_USER_HOST, host: symfony\.com$ } - { path: '^/admin', roles: ROLE_USER_METHOD, methods: [POST, PUT] } @@ -55,7 +55,7 @@ Take the following ``access_control`` entries as an example: .. code-block:: xml - + - 10.0.0.1, 10.0.0.2 + 10.0.0.1, 10.0.0.2 - + @@ -88,49 +88,46 @@ Take the following ``access_control`` entries as an example: .. code-block:: php // config/packages/security.php - $container->setParameter('env(TRUSTED_IPS)', '10.0.0.1, 10.0.0.2'); - $container->loadFromExtension('security', [ + use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Config\SecurityConfig; + + return static function (ContainerBuilder $container, SecurityConfig $security) { + $container->setParameter('env(TRUSTED_IPS)', '10.0.0.1, 10.0.0.2'); // ... - 'access_control' => [ - [ - 'path' => '^/admin', - 'roles' => 'ROLE_USER_IP', - 'ips' => '127.0.0.1', - ], - [ - 'path' => '^/admin', - 'roles' => 'ROLE_USER_PORT', - 'ip' => '127.0.0.1', - 'port' => '8080', - ], - [ - 'path' => '^/admin', - 'roles' => 'ROLE_USER_HOST', - 'host' => 'symfony\.com$', - ], - [ - 'path' => '^/admin', - 'roles' => 'ROLE_USER_METHOD', - 'methods' => 'POST, PUT', - ], - - // ips can be comma-separated, which is especially useful when using env variables - [ - 'path' => '^/admin', - 'roles' => 'ROLE_USER_IP', - 'ips' => '%env(TRUSTED_IPS)%', - ], - [ - 'path' => '^/admin', - 'roles' => 'ROLE_USER_IP', - 'ips' => [ - '127.0.0.1', - '::1', - '%env(TRUSTED_IPS)%', - ], - ], - ], - ]); + + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_USER_PORT']) + ->ips(['127.0.0.1']) + ->port(8080) + ; + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_USER_IP']) + ->ips(['127.0.0.1']) + ; + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_USER_HOST']) + ->host('symfony\.com$') + ; + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_USER_METHOD']) + ->methods(['POST', 'PUT']) + ; + // ips can be comma-separated, which is especially useful when using env variables + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_USER_IP']) + ->ips(['%env(TRUSTED_IPS)%']) + ; + $security->accessControl() + ->path('^/admin') + ->roles(['ROLE_USER_IP']) + ->ips(['127.0.0.1', '::1', '%env(TRUSTED_IPS)%']) + ; + }; .. versionadded:: 5.2 @@ -145,13 +142,13 @@ if ``ip``, ``port``, ``host`` or ``method`` are not specified for an entry, that +-----------------+-------------+-------------+-------------+------------+--------------------------------+-------------------------------------------------------------+ | URI | IP | PORT | HOST | METHOD | ``access_control`` | Why? | +=================+=============+=============+=============+============+================================+=============================================================+ -| ``/admin/user`` | 127.0.0.1 | 80 | example.com | GET | rule #1 (``ROLE_USER_IP``) | The URI matches ``path`` and the IP matches ``ip``. | +| ``/admin/user`` | 127.0.0.1 | 80 | example.com | GET | rule #2 (``ROLE_USER_IP``) | The URI matches ``path`` and the IP matches ``ip``. | +-----------------+-------------+-------------+-------------+------------+--------------------------------+-------------------------------------------------------------+ -| ``/admin/user`` | 127.0.0.1 | 80 | symfony.com | GET | rule #1 (``ROLE_USER_IP``) | The ``path`` and ``ip`` still match. This would also match | +| ``/admin/user`` | 127.0.0.1 | 80 | symfony.com | GET | rule #2 (``ROLE_USER_IP``) | The ``path`` and ``ip`` still match. This would also match | | | | | | | | the ``ROLE_USER_HOST`` entry, but *only* the **first** | | | | | | | | ``access_control`` match is used. | +-----------------+-------------+-------------+-------------+------------+--------------------------------+-------------------------------------------------------------+ -| ``/admin/user`` | 127.0.0.1 | 8080 | symfony.com | GET | rule #2 (``ROLE_USER_PORT``) | The ``path``, ``ip`` and ``port`` match. | +| ``/admin/user`` | 127.0.0.1 | 8080 | symfony.com | GET | rule #1 (``ROLE_USER_PORT``) | The ``path``, ``ip`` and ``port`` match. | +-----------------+-------------+-------------+-------------+------------+--------------------------------+-------------------------------------------------------------+ | ``/admin/user`` | 168.0.0.1 | 80 | symfony.com | GET | rule #3 (``ROLE_USER_HOST``) | The ``ip`` doesn't match the first rule, so the second | | | | | | | | rule (which matches) is used. | @@ -250,7 +247,7 @@ pattern so that it is only accessible by requests from the local server itself: .. code-block:: xml - + loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'access_control' => [ - [ - 'path' => '^/internal', - 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY', - // the 'ips' option supports IP addresses and subnet masks - 'ips' => ['127.0.0.1', '::1'], - ], - [ - 'path' => '^/internal', - 'roles' => 'ROLE_NO_ACCESS', - ], - ], - ]); + + $security->accessControl() + ->path('^/internal') + ->roles(['IS_AUTHENTICATED_ANONYMOUSLY']) + // the 'ips' option supports IP addresses and subnet masks + ->ips(['127.0.0.1', '::1']) + ; + + $security->accessControl() + ->path('^/internal') + ->roles(['ROLE_NO_ACCESS']) + ; + }; Here is how it works when the path is ``/internal/something`` coming from the external IP address ``10.0.0.1``: @@ -331,7 +330,7 @@ key: access_control: - path: ^/_internal/secure - # the 'role' and 'allow-if' options work like an OR expression, so + # the 'roles' and 'allow_if' options work like an OR expression, so # access is granted if the expression is TRUE or the user has ROLE_ADMIN roles: 'ROLE_ADMIN' allow_if: "'127.0.0.1' == request.getClientIp() or request.headers.has('X-Secure-Access')" @@ -339,7 +338,7 @@ key: .. code-block:: xml - + loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'access_control' => [ - [ - 'path' => '^/_internal/secure', - // the 'role' and 'allow-if' options work like an OR expression, so - // access is granted if the expression is TRUE or the user has ROLE_ADMIN - 'roles' => 'ROLE_ADMIN', - 'allow_if' => '"127.0.0.1" == request.getClientIp() or request.headers.has("X-Secure-Access")', - ], - ], - ]); + + $security->accessControl() + ->path('^/_internal/secure') + // the 'role' and 'allow-if' options work like an OR expression, so + // access is granted if the expression is TRUE or the user has ROLE_ADMIN + ->roles(['ROLE_ADMIN']) + ->allowIf('"127.0.0.1" == request.getClientIp() or request.headers.has("X-Secure-Access")') + ; + }; In this case, when the user tries to access any URL starting with ``/_internal/secure``, they will only be granted access if the IP address is @@ -417,7 +417,7 @@ access those URLs via a specific port. This could be useful for example for .. code-block:: xml - + loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'access_control' => [ - [ - 'path' => '^/cart/checkout', - 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', - 'port' => '8080', - ], - ], - ]); + + $security->accessControl() + ->path('^/cart/checkout') + ->roles(['IS_AUTHENTICATED_ANONYMOUSLY']) + ->port(8080) + ; + }; Forcing a Channel (http, https) ------------------------------- @@ -470,7 +471,7 @@ the user will be redirected to ``https``: .. code-block:: xml - + loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'access_control' => [ - [ - 'path' => '^/cart/checkout', - 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY', - 'requires_channel' => 'https', - ], - ], - ]); + + $security->accessControl() + ->path('^/cart/checkout') + ->roles(['IS_AUTHENTICATED_ANONYMOUSLY']) + ->requiresChannel('https') + ; + }; diff --git a/security/access_denied_handler.rst b/security/access_denied_handler.rst index 59d6d6bb8d6..c880ec14065 100644 --- a/security/access_denied_handler.rst +++ b/security/access_denied_handler.rst @@ -15,6 +15,8 @@ generates a response based on the authentication state: * **If the user is authenticated, but does not have the required permissions**, a *403 Forbidden* response is generated. +.. _security-entry-point: + Customize the Unauthorized Response ----------------------------------- @@ -28,25 +30,23 @@ unauthenticated user tries to access a protected resource:: use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpFoundation\Session\SessionInterface; + use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; class AuthenticationEntryPoint implements AuthenticationEntryPointInterface { private $urlGenerator; - private $session; - public function __construct(UrlGeneratorInterface $urlGenerator, SessionInterface $session) + public function __construct(UrlGeneratorInterface $urlGenerator) { $this->urlGenerator = $urlGenerator; - $this->session = $session; } public function start(Request $request, AuthenticationException $authException = null): RedirectResponse { // add a custom flash message and redirect to the login page - $this->session->getFlashBag()->add('note', 'You have to login in order to access this page.'); + $request->getSession()->getFlashBag()->add('note', 'You have to login in order to access this page.'); return new RedirectResponse($this->urlGenerator->generate('security_login')); } @@ -72,7 +72,7 @@ Now, configure this service ID as the entry point for the firewall: .. code-block:: xml - + loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - // ... - 'entry_point' => AuthenticationEntryPoint::class, - ], - ], - ]); + return static function (SecurityConfig $security) { + $security->firewall('main') + // .... + ->entryPoint(AuthenticationEntryPoint::class) + ; + }; Customize the Forbidden Response -------------------------------- @@ -122,7 +121,7 @@ response):: class AccessDeniedHandler implements AccessDeniedHandlerInterface { - public function handle(Request $request, AccessDeniedException $accessDeniedException) + public function handle(Request $request, AccessDeniedException $accessDeniedException): ?Response { // ... @@ -149,7 +148,7 @@ configure it under your firewall: .. code-block:: xml - + loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - // ... - 'access_denied_handler' => AccessDeniedHandler::class, - ], - ], - ]); + return static function (SecurityConfig $security) { + $security->firewall('main') + // .... + ->accessDeniedHandler(AccessDeniedHandler::class) + ; + }; Customizing All Access Denied Responses --------------------------------------- @@ -209,7 +207,7 @@ configure a :ref:`kernel.exception listener `:: public function onKernelException(ExceptionEvent $event): void { - $exception = $event->getException(); + $exception = $event->getThrowable(); if (!$exception instanceof AccessDeniedException) { return; } diff --git a/security/acl.rst b/security/acl.rst deleted file mode 100644 index ffbf16c7c27..00000000000 --- a/security/acl.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. index:: - single: Security; Access Control Lists (ACLs) - -How to Use Access Control Lists (ACLs) -====================================== - -.. caution:: - - ACL support was removed in Symfony 4.0. Install the `Symfony ACL bundle`_ - and refer to its documentation if you want to keep using ACL. - - Consider using :doc:`security voters `, - the alternative to ACLs recommended by Symfony. - -.. _`Symfony ACL bundle`: https://github.com/symfony/acl-bundle diff --git a/security/auth_providers.rst b/security/auth_providers.rst deleted file mode 100644 index 349f16a219a..00000000000 --- a/security/auth_providers.rst +++ /dev/null @@ -1,241 +0,0 @@ -Built-in Authentication Providers -================================= - -If you need to add authentication to your app, we recommend using -:doc:`Guard authentication ` because it gives you -full control over the process. - -But, Symfony also offers a number of built-in authentication providers: systems -that are easier to implement, but harder to customize. If your authentication -use-case matches one of these exactly, they're a great option: - -.. toctree:: - :hidden: - - form_login - json_login_setup - -* :doc:`form_login ` -* :ref:`http_basic ` -* :doc:`LDAP via HTTP Basic or Form Login ` -* :doc:`json_login ` -* :ref:`X.509 Client Certificate Authentication (x509) ` -* :ref:`REMOTE_USER Based Authentication (remote_user) ` - -.. _security-http_basic: - -HTTP Basic Authentication -------------------------- - -`HTTP Basic authentication`_ asks credentials (username and password) using a dialog -in the browser. The credentials are sent without any hashing or encryption, so -it's recommended to use it with HTTPS. - -To support HTTP Basic authentication, add the ``http_basic`` key to your firewall: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - firewalls: - main: - # ... - http_basic: - realm: Secured Area - - .. code-block:: xml - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - $container->loadFromExtension('security', [ - // ... - - 'firewalls' => [ - 'main' => [ - 'http_basic' => [ - 'realm' => 'Secured Area', - ], - ], - ], - ]); - -That's it! Symfony will now be listening for any HTTP basic authentication data. -To load user information, it will use your configured :doc:`user provider `. - -Note: you cannot use the :ref:`log out ` with ``http_basic``. -Even if you log out, your browser "remembers" your credentials and will send them -on every request. - -.. _security-x509: - -X.509 Client Certificate Authentication ---------------------------------------- - -When using client certificates, your web server is doing all the authentication -process itself. With Apache, for example, you would use the -``SSLVerifyClient Require`` directive. - -Enable the x509 authentication for a particular firewall in the security configuration: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - firewalls: - main: - # ... - x509: - provider: your_user_provider - - .. code-block:: xml - - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - $container->loadFromExtension('security', [ - // ... - - 'firewalls' => [ - 'main' => [ - // ... - 'x509' => [ - 'provider' => 'your_user_provider', - ], - ], - ], - ]); - -By default, the firewall provides the ``SSL_CLIENT_S_DN_Email`` variable to -the user provider, and sets the ``SSL_CLIENT_S_DN`` as credentials in the -:class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\PreAuthenticatedToken`. -You can override these by setting the ``user`` and the ``credentials`` keys -in the x509 firewall configuration respectively. - -.. _security-pre-authenticated-user-provider-note: - -.. note:: - - An authentication provider will only inform the user provider of the username - that made the request. You will need to create (or use) a "user provider" that - is referenced by the ``provider`` configuration parameter (``your_user_provider`` - in the configuration example). This provider will turn the username into a User - object of your choice. For more information on creating or configuring a user - provider, see: - - * :doc:`/security/user_provider` - -.. _security-remote_user: - -REMOTE_USER Based Authentication --------------------------------- - -A lot of authentication modules, like ``auth_kerb`` for Apache, provide the username -using the ``REMOTE_USER`` environment variable. This variable can be trusted by -the application since the authentication happened before the request reached it. - -To configure Symfony using the ``REMOTE_USER`` environment variable, enable the -corresponding firewall in your security configuration: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - firewalls: - main: - # ... - remote_user: - provider: your_user_provider - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'remote_user' => [ - 'provider' => 'your_user_provider', - ], - ], - ], - ]); - -The firewall will then provide the ``REMOTE_USER`` environment variable to -your user provider. You can change the variable name used by setting the ``user`` -key in the ``remote_user`` firewall configuration. - -.. note:: - - Just like for X509 authentication, you will need to configure a "user provider". - See :ref:`the previous note ` - for more information. - -.. _`HTTP Basic authentication`: https://en.wikipedia.org/wiki/Basic_access_authentication diff --git a/security/csrf.rst b/security/csrf.rst index ac8e840c978..12a00ef185c 100644 --- a/security/csrf.rst +++ b/security/csrf.rst @@ -51,9 +51,13 @@ for more information): .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'csrf_protection' => null, - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->csrfProtection() + ->enabled(true) + ; + }; The tokens used for CSRF protection are meant to be different for every user and they are stored in the session. That's why a session is started automatically as @@ -85,7 +89,7 @@ this can be customized on a form-by-form basis:: // src/Form/TaskType.php namespace App\Form; - + // ... use App\Entity\Task; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -94,7 +98,7 @@ this can be customized on a form-by-form basis:: { // ... - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => Task::class, @@ -119,8 +123,8 @@ customize the entire form field contents). CSRF Protection in Login Forms ------------------------------ -See :doc:`/security/form_login_setup` for a login form that is protected from -CSRF attacks. You can also configure the +See :ref:`form_login-csrf` for a login form that is protected from CSRF +attacks. You can also configure the :ref:`CSRF protection for the logout action `. .. _csrf-protection-in-html-forms: @@ -147,12 +151,13 @@ generate a CSRF token in the template and store it as a hidden form field: Then, get the value of the CSRF token in the controller action and use the :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController::isCsrfTokenValid` -to check its validity:: +method to check its validity:: use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\HttpFoundation\Response; // ... - public function delete(Request $request) + public function delete(Request $request): Response { $submittedToken = $request->request->get('token'); @@ -162,4 +167,19 @@ to check its validity:: } } +CSRF Tokens and Compression Side-Channel Attacks +------------------------------------------------ + +`BREACH`_ and `CRIME`_ are security exploits against HTTPS when using HTTP +compression. Attackers can leverage information leaked by compression to recover +targeted parts of the plaintext. To mitigate these attacks, and prevent an +attacker from guessing the CSRF tokens, a random mask is prepended to the token +and used to scramble it. + +.. versionadded:: 5.3 + + The randomization of tokens was introduced in Symfony 5.3 + .. _`Cross-site request forgery`: https://en.wikipedia.org/wiki/Cross-site_request_forgery +.. _`BREACH`: https://en.wikipedia.org/wiki/BREACH +.. _`CRIME`: https://en.wikipedia.org/wiki/CRIME diff --git a/security/custom_authentication_provider.rst b/security/custom_authentication_provider.rst deleted file mode 100644 index 8c5581964ea..00000000000 --- a/security/custom_authentication_provider.rst +++ /dev/null @@ -1,653 +0,0 @@ -.. index:: - single: Security; Custom authentication provider - -How to Create a custom Authentication Provider -============================================== - -.. caution:: - - Creating a custom authentication system is hard, and almost definitely - **not** needed. Instead, see :doc:`/security/guard_authentication` for a - simple way to create an authentication system you will love. Do **not** - keep reading unless you want to learn the lowest level details of - authentication. - -Symfony provides support for the most -:doc:`common authentication mechanisms `. However, your -app may need to integrated with some proprietary single-sign-on system or some -legacy authentication mechanism. In those cases you could create a custom -authentication provider. This article discusses the core classes involved -in the authentication process, and how to implement a custom authentication -provider. Because authentication and authorization are separate concepts, -this extension will be user-provider agnostic, and will function with your -application's user providers, may they be based in memory, a database, or -wherever else you choose to store them. - -Meet WSSE ---------- - -The following article demonstrates how to create a custom authentication -provider for WSSE authentication. The security protocol for WSSE provides -several security benefits: - -#. Username / Password encryption -#. Safe guarding against replay attacks -#. No web server configuration required - -WSSE is very useful for the securing of web services, may they be SOAP or -REST. - -There is plenty of great documentation on `WSSE`_, but this article will -focus not on the security protocol, but rather the manner in which a custom -protocol can be added to your Symfony application. The basis of WSSE is -that a request header is checked for encrypted credentials, verified using -a timestamp and `nonce`_, and authenticated for the requested user using a -password digest. - -.. note:: - - WSSE also supports application key validation, which is useful for web - services, but is outside the scope of this article. - -The Token ---------- - -The role of the token in the Symfony security context is an important one. -A token represents the user authentication data present in the request. Once -a request is authenticated, the token retains the user's data, and delivers -this data across the security context. First, you'll create your token class. -This will allow the passing of all relevant information to your authentication -provider:: - - // src/Security/Authentication/Token/WsseUserToken.php - namespace App\Security\Authentication\Token; - - use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; - - class WsseUserToken extends AbstractToken - { - public $created; - public $digest; - public $nonce; - - public function __construct(array $roles = []) - { - parent::__construct($roles); - - // If the user has roles, consider it authenticated - $this->setAuthenticated(count($roles) > 0); - } - - public function getCredentials() - { - return ''; - } - } - -.. note:: - - The ``WsseUserToken`` class extends the Security component's - :class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\AbstractToken` - class, which provides basic token functionality. Implement the - :class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface` - on any class to use as a token. - -The Listener ------------- - -Next, you need a listener to listen on the firewall. The listener -is responsible for fielding requests to the firewall and calling the authentication -provider. Listener is a callable, so you have to implement an ``__invoke()`` method. -A security listener should handle the -:class:`Symfony\\Component\\HttpKernel\\Event\\RequestEvent` event, and -set an authenticated token in the token storage if successful:: - - // src/Security/Firewall/WsseListener.php - namespace App\Security\Firewall; - - use App\Security\Authentication\Token\WsseUserToken; - use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\HttpKernel\Event\RequestEvent; - use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; - use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; - use Symfony\Component\Security\Core\Exception\AuthenticationException; - - class WsseListener - { - protected $tokenStorage; - protected $authenticationManager; - - public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager) - { - $this->tokenStorage = $tokenStorage; - $this->authenticationManager = $authenticationManager; - } - - public function __invoke(RequestEvent $event) - { - $request = $event->getRequest(); - - $wsseRegex = '/UsernameToken Username="(?P[^"]+)", PasswordDigest="(?P[^"]+)", Nonce="(?P[a-zA-Z0-9+\/]+={0,2})", Created="(?P[^"]+)"/'; - if (!$request->headers->has('x-wsse') || 1 !== preg_match($wsseRegex, $request->headers->get('x-wsse'), $matches)) { - return; - } - - $token = new WsseUserToken(); - $token->setUser($matches['username']); - - $token->digest = $matches['digest']; - $token->nonce = $matches['nonce']; - $token->created = $matches['created']; - - try { - $authToken = $this->authenticationManager->authenticate($token); - $this->tokenStorage->setToken($authToken); - - return; - } catch (AuthenticationException $failed) { - // ... you might log something here - - // To deny the authentication clear the token. This will redirect to the login page. - // Make sure to only clear your token, not those of other authentication listeners. - // $token = $this->tokenStorage->getToken(); - // if ($token instanceof WsseUserToken && $this->providerKey === $token->getProviderKey()) { - // $this->tokenStorage->setToken(null); - // } - // return; - } - - // By default deny authorization - $response = new Response(); - $response->setStatusCode(Response::HTTP_FORBIDDEN); - $event->setResponse($response); - } - } - -This listener checks the request for the expected ``X-WSSE`` header, matches -the value returned for the expected WSSE information, creates a token using -that information, and passes the token on to the authentication manager. If -the proper information is not provided, or the authentication manager throws -an :class:`Symfony\\Component\\Security\\Core\\Exception\\AuthenticationException`, -a 401 Response is returned. - -.. note:: - - A class not used above, the - :class:`Symfony\\Component\\Security\\Http\\Firewall\\AbstractAuthenticationListener` - class, is a very useful base class which provides commonly needed functionality - for security extensions. This includes maintaining the token in the session, - providing success / failure handlers, login form URLs, and more. As WSSE - does not require maintaining authentication sessions or login forms, it - won't be used for this example. - -.. note:: - - Returning prematurely from the listener is relevant only if you want to chain - authentication providers (for example to allow anonymous users). If you want - to forbid access to anonymous users and have a 404 error, you should set - the status code of the response before returning. - -The Authentication Provider ---------------------------- - -The authentication provider will do the verification of the ``WsseUserToken``. -Namely, the provider will verify the ``Created`` header value is valid within -five minutes, the ``Nonce`` header value is unique within five minutes, and -the ``PasswordDigest`` header value matches with the user's password:: - - // src/Security/Authentication/Provider/WsseProvider.php - namespace App\Security\Authentication\Provider; - - use App\Security\Authentication\Token\WsseUserToken; - use Psr\Cache\CacheItemPoolInterface; - use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface; - use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; - use Symfony\Component\Security\Core\Exception\AuthenticationException; - use Symfony\Component\Security\Core\User\UserProviderInterface; - - class WsseProvider implements AuthenticationProviderInterface - { - private $userProvider; - private $cachePool; - - public function __construct(UserProviderInterface $userProvider, CacheItemPoolInterface $cachePool) - { - $this->userProvider = $userProvider; - $this->cachePool = $cachePool; - } - - public function authenticate(TokenInterface $token) - { - $user = $this->userProvider->loadUserByUsername($token->getUsername()); - - if ($user && $this->validateDigest($token->digest, $token->nonce, $token->created, $user->getPassword())) { - $authenticatedToken = new WsseUserToken($user->getRoles()); - $authenticatedToken->setUser($user); - - return $authenticatedToken; - } - - throw new AuthenticationException('The WSSE authentication failed.'); - } - - /** - * This function is specific to Wsse authentication and is only used to help this example - * - * For more information specific to the logic here, see - * https://github.com/symfony/symfony-docs/pull/3134#issuecomment-27699129 - */ - protected function validateDigest($digest, $nonce, $created, $secret) - { - // Check created time is not in the future - if (strtotime($created) > time()) { - return false; - } - - // Expire timestamp after 5 minutes - if (time() - strtotime($created) > 300) { - return false; - } - - // Try to fetch the cache item from pool - $cacheItem = $this->cachePool->getItem(md5($nonce)); - - // Validate that the nonce is *not* in cache - // if it is, this could be a replay attack - if ($cacheItem->isHit()) { - // In a real world application you should throw a custom - // exception extending the AuthenticationException - throw new AuthenticationException('Previously used nonce detected'); - } - - // Store the item in cache for 5 minutes - $cacheItem->set(null)->expiresAfter(300); - $this->cachePool->save($cacheItem); - - // Validate Secret - $expected = base64_encode(sha1(base64_decode($nonce).$created.$secret, true)); - - return hash_equals($expected, $digest); - } - - public function supports(TokenInterface $token) - { - return $token instanceof WsseUserToken; - } - } - -.. note:: - - The :class:`Symfony\\Component\\Security\\Core\\Authentication\\Provider\\AuthenticationProviderInterface` - requires an ``authenticate()`` method on the user token, and a ``supports()`` - method, which tells the authentication manager whether or not to use this - provider for the given token. In the case of multiple providers, the - authentication manager will then move to the next provider in the list. - -The Factory ------------ - -You have created a custom token, custom listener, and custom provider. Now -you need to tie them all together. How do you make a unique provider available -for every firewall? The answer is by using a *factory*. A factory -is where you hook into the Security component, telling it the name of your -provider and any configuration options available for it. First, you must -create a class which implements -:class:`Symfony\\Bundle\\SecurityBundle\\DependencyInjection\\Security\\Factory\\SecurityFactoryInterface`:: - - // src/DependencyInjection/Security/Factory/WsseFactory.php - namespace App\DependencyInjection\Security\Factory; - - use App\Security\Authentication\Provider\WsseProvider; - use App\Security\Firewall\WsseListener; - use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface; - use Symfony\Component\Config\Definition\Builder\NodeDefinition; - use Symfony\Component\DependencyInjection\ChildDefinition; - use Symfony\Component\DependencyInjection\ContainerBuilder; - use Symfony\Component\DependencyInjection\Reference; - - class WsseFactory implements SecurityFactoryInterface - { - public function create(ContainerBuilder $container, string $id, array $config, string $userProvider, ?string $defaultEntryPoint) - { - $providerId = 'security.authentication.provider.wsse.'.$id; - $container - ->setDefinition($providerId, new ChildDefinition(WsseProvider::class)) - ->setArgument(0, new Reference($userProvider)) - ; - - $listenerId = 'security.authentication.listener.wsse.'.$id; - $container->setDefinition($listenerId, new ChildDefinition(WsseListener::class)); - - return [$providerId, $listenerId, $defaultEntryPoint]; - } - - public function getPosition() - { - return 'pre_auth'; - } - - public function getKey() - { - return 'wsse'; - } - - public function addConfiguration(NodeDefinition $node) - { - } - } - -The :class:`Symfony\\Bundle\\SecurityBundle\\DependencyInjection\\Security\\Factory\\SecurityFactoryInterface` -requires the following methods: - -``create()`` - Method which adds the listener and authentication provider - to the DI container for the appropriate security context. - -``getPosition()`` - Returns when the provider should be called. This can be one of ``pre_auth``, - ``form``, ``http`` or ``remember_me``. - -``getKey()`` - Method which defines the configuration key used to reference - the provider in the firewall configuration. - -``addConfiguration()`` - Method which is used to define the configuration - options underneath the configuration key in your security configuration. - Setting configuration options are explained later in this article. - -.. note:: - - A class not used in this example, - :class:`Symfony\\Bundle\\SecurityBundle\\DependencyInjection\\Security\\Factory\\AbstractFactory`, - is a very useful base class which provides commonly needed functionality - for security factories. It may be useful when defining an authentication - provider of a different type. - -Now that you have created a factory class, the ``wsse`` key can be used as -a firewall in your security configuration. - -.. note:: - - You may be wondering "why do you need a special factory class to add listeners - and providers to the dependency injection container?". This is a very - good question. The reason is you can use your firewall multiple times, - to secure multiple parts of your application. Because of this, each - time your firewall is used, a new service is created in the DI container. - The factory is what creates these new services. - -Configuration -------------- - -It's time to see your authentication provider in action. You will need to -do a few things in order to make this work. The first thing is to add the -services above to the DI container. Your factory class above makes reference -to service ids that may not exist yet: ``App\Security\Authentication\Provider\WsseProvider`` and -``App\Security\Firewall\WsseListener``. It's time to define those services. - -.. configuration-block:: - - .. code-block:: yaml - - # config/services.yaml - services: - # ... - - App\Security\Authentication\Provider\WsseProvider: - arguments: - $cachePool: '@cache.app' - - App\Security\Firewall\WsseListener: - arguments: ['@security.token_storage', '@security.authentication.manager'] - - .. code-block:: xml - - - - - - - - - - - - - - - - - - .. code-block:: php - - // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; - - use App\Security\Authentication\Provider\WsseProvider; - use App\Security\Firewall\WsseListener; - use Symfony\Component\DependencyInjection\Reference; - - return function(ContainerConfigurator $configurator) { - $services = $configurator->services(); - - $services->set(WsseProvider::class) - ->arg('$cachePool', service('cache.app')) - ; - - $services->set(WsseListener::class) - ->args([ - // In versions earlier to Symfony 5.1 the service() function was called ref() - service('security.token_storage'), - service('security.authentication.manager'), - ]) - ; - }; - -Now that your services are defined, tell your security context about your -factory in the kernel:: - - // src/Kernel.php - namespace App; - - use App\DependencyInjection\Security\Factory\WsseFactory; - // ... - - class Kernel extends BaseKernel - { - public function build(ContainerBuilder $container) - { - $extension = $container->getExtension('security'); - $extension->addSecurityListenerFactory(new WsseFactory()); - } - - // ... - } - -You are finished! You can now define parts of your app as under WSSE protection. - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - firewalls: - wsse_secured: - pattern: ^/api/ - stateless: true - wsse: true - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - $container->loadFromExtension('security', [ - // ... - - 'firewalls' => [ - 'wsse_secured' => [ - 'pattern' => '^/api/', - 'stateless' => true, - 'wsse' => true, - ], - ], - ]); - -Congratulations! You have written your very own custom security authentication -provider! - -A little Extra --------------- - -How about making your WSSE authentication provider a bit more exciting? The -possibilities are endless. Why don't you start by adding some sparkle -to that shine? - -Configuration -~~~~~~~~~~~~~ - -You can add custom options under the ``wsse`` key in your security configuration. -For instance, the time allowed before expiring the ``Created`` header item, -by default, is 5 minutes. Make this configurable, so different firewalls -can have different timeout lengths. - -You will first need to edit ``WsseFactory`` and define the new option in -the ``addConfiguration()`` method:: - - // src/DependencyInjection/Security/Factory/WsseFactory.php - namespace App\DependencyInjection\Security\Factory; - - // ... - - class WsseFactory implements SecurityFactoryInterface - { - // ... - - public function addConfiguration(NodeDefinition $node) - { - $node - ->children() - ->scalarNode('lifetime')->defaultValue(300) - ->end(); - } - } - -Now, in the ``create()`` method of the factory, the ``$config`` argument will -contain a ``lifetime`` key, set to 5 minutes (300 seconds) unless otherwise -set in the configuration. Pass this argument to your authentication provider -in order to put it to use:: - - // src/DependencyInjection/Security/Factory/WsseFactory.php - namespace App\DependencyInjection\Security\Factory; - - use App\Security\Authentication\Provider\WsseProvider; - - class WsseFactory implements SecurityFactoryInterface - { - public function create(ContainerBuilder $container, string $id, array $config, string $userProvider, ?string $defaultEntryPoint) - { - $providerId = 'security.authentication.provider.wsse.'.$id; - $container - ->setDefinition($providerId, new ChildDefinition(WsseProvider::class)) - ->setArgument(0, new Reference($userProvider)) - ->setArgument(2, $config['lifetime']); - // ... - } - - // ... - } - -.. note:: - - The ``WsseProvider`` class will also now need to accept a third constructor argument - - the lifetime - which it should use instead of the hard-coded 300 seconds. This - step is not shown here. - -The lifetime of each WSSE request is now configurable, and can be -set to any desirable value per firewall. - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - firewalls: - wsse_secured: - pattern: ^/api/ - stateless: true - wsse: { lifetime: 30 } - - .. code-block:: xml - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - $container->loadFromExtension('security', [ - // ... - - 'firewalls' => [ - 'wsse_secured' => [ - 'pattern' => '^/api/', - 'stateless' => true, - 'wsse' => [ - 'lifetime' => 30, - ], - ], - ], - ]); - -The rest is up to you! Any relevant configuration items can be defined -in the factory and consumed or passed to the other classes in the container. - - -.. _`WSSE`: https://www.xml.com/pub/a/2003/12/17/dive.html -.. _`nonce`: https://en.wikipedia.org/wiki/Cryptographic_nonce diff --git a/security/custom_authenticator.rst b/security/custom_authenticator.rst new file mode 100644 index 00000000000..3f4809e23d0 --- /dev/null +++ b/security/custom_authenticator.rst @@ -0,0 +1,380 @@ +How to Write a Custom Authenticator +=================================== + +Symfony comes with :ref:`many authenticators ` and +third party bundles also implement more complex cases like JWT and oAuth +2.0. However, sometimes you need to implement a custom authentication +mechanism that doesn't exists yet or you need to customize one. In such +cases, you must create and use your own authenticator. + +Authenticators should implement the +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\AuthenticatorInterface`. +You can also extend +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\AbstractAuthenticator`, +which has a default implementation for the ``createAuthenticatedToken()`` +method that fits most use-cases:: + + // src/Security/ApiKeyAuthenticator.php + namespace App\Security; + + use Symfony\Component\HttpFoundation\JsonResponse; + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + use Symfony\Component\Security\Core\Exception\AuthenticationException; + use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; + use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; + use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; + use Symfony\Component\Security\Http\Authenticator\Passport\Passport; + use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport; + + class ApiKeyAuthenticator extends AbstractAuthenticator + { + /** + * Called on every request to decide if this authenticator should be + * used for the request. Returning `false` will cause this authenticator + * to be skipped. + */ + public function supports(Request $request): ?bool + { + return $request->headers->has('X-AUTH-TOKEN'); + } + + public function authenticate(Request $request): Passport + { + $apiToken = $request->headers->get('X-AUTH-TOKEN'); + if (null === $apiToken) { + // The token header was empty, authentication fails with HTTP Status + // Code 401 "Unauthorized" + throw new CustomUserMessageAuthenticationException('No API token provided'); + } + + return new SelfValidatingPassport(new UserBadge($apiToken)); + } + + public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response + { + // on success, let the request continue + return null; + } + + public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response + { + $data = [ + // you may want to customize or obfuscate the message first + 'message' => strtr($exception->getMessageKey(), $exception->getMessageData()) + + // or to translate this message + // $this->translator->trans($exception->getMessageKey(), $exception->getMessageData()) + ]; + + return new JsonResponse($data, Response::HTTP_UNAUTHORIZED); + } + } + +.. tip:: + + If your custom authenticator is a login form, you can extend from the + :class:`Symfony\\Component\\Security\\Http\\Authenticator\\AbstractLoginFormAuthenticator` + class instead to make your job easier. + +The authenticator can be enabled using the ``custom_authenticators`` setting: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + enable_authenticator_manager: true + + # ... + firewalls: + main: + custom_authenticators: + - App\Security\ApiKeyAuthenticator + + .. code-block:: xml + + + + + + + + + + App\Security\ApiKeyAuthenticator + + + + + .. code-block:: php + + // config/packages/security.php + use App\Security\ApiKeyAuthenticator; + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->enableAuthenticatorManager(true); + // .... + + $security->firewall('main') + ->customAuthenticators([ApiKeyAuthenticator::class]) + ; + }; + +.. versionadded:: 5.2 + + Starting with Symfony 5.2, the custom authenticator is automatically + registered as entry point if it implements ``AuthenticationEntryPointInterface``. + + Prior to 5.2, you had to configure the entry point separately using the + ``entry_point`` option. Read :doc:`/security/entry_point` for more + information. + +The ``authenticate()`` method is the most important method of the +authenticator. Its job is to extract credentials (e.g. username & +password, or API tokens) from the ``Request`` object and transform these +into a security +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Passport`. +See :ref:`security-passport` below for a detailed look into the +authentication process. + +After the authentication process finished, the user is either authenticated +or there was something wrong (e.g. incorrect password). The authenticator +can define what happens in these cases: + +``onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response`` + If the user is authenticated, this method is called with the + authenticated ``$token``. This method can return a response (e.g. + redirect the user to the homepage). + + If ``null`` is returned, the request continues like normal (i.e. the + controller matching the login route is called). This is useful for API + routes where each route is protected by an API key header. + +``onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response`` + If an ``AuthenticationException`` is thrown during authentication, the + process fails and this method is called. This method can return a + response (e.g. to return a 401 Unauthorized response in API routes). + + If ``null`` is returned, the request continues like normal. This is + useful for e.g. login forms, where the login controller is run again + with the login errors. + + **Caution**: Never use ``$exception->getMessage()`` for ``AuthenticationException`` + instances. This message might contain sensitive information that you + don't want to expose publicly. Instead, use ``$exception->getMessageKey()`` + and ``$exception->getMessageData()`` like shown in the full example + above. Use :class:`Symfony\\Component\\Security\\Core\\Exception\\CustomUserMessageAuthenticationException` + if you want to set custom error messages. + +.. _security-passport: + +Security Passports +------------------ + +.. versionadded:: 5.2 + + The ``UserBadge`` was introduced in Symfony 5.2. Prior to 5.2, the user + instance was provided directly to the passport. + +A passport is an object that contains the user that will be authenticated as +well as other pieces of information, like whether a password should be checked +or if "remember me" functionality should be enabled. + +The default +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Passport` +requires a user and some sort of "credentials" (e.g. a password). + +Use the +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\UserBadge` +to attach the user to the passport. The ``UserBadge`` requires a user +identifier (e.g. the username or email), which is used to load the user +using :ref:`the user provider `:: + + use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; + + // ... + $passport = new Passport(new UserBadge($email), $credentials); + +.. note:: + + You can optionally pass a user loader as second argument to the + ``UserBadge``. This callable receives the ``$userIdentifier`` + and must return a ``UserInterface`` object (otherwise a + ``UserNotFoundException`` is thrown):: + + // src/Security/CustomAuthenticator.php + namespace App\Security; + + use App\Repository\UserRepository; + // ... + + class CustomAuthenticator extends AbstractAuthenticator + { + private $userRepository; + + public function __construct(UserRepository $userRepository) + { + $this->userRepository = $userRepository; + } + + public function authenticate(Request $request): Passport + { + // ... + + return new Passport( + new UserBadge($email, function ($userIdentifier) { + return $this->userRepository->findOneBy(['email' => $userIdentifier]); + }), + $credentials + ); + } + } + +The following credential classes are supported by default: + +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Credentials\\PasswordCredentials` + This requires a plaintext ``$password``, which is validated using the + :ref:`password encoder configured for the user `:: + + use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials; + + // ... + return new Passport(new UserBadge($email), new PasswordCredentials($plaintextPassword)); + +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Credentials\\CustomCredentials` + Allows a custom closure to check credentials:: + + use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\CustomCredentials; + + // ... + return new Passport(new UserBadge($email), new CustomCredentials( + // If this function returns anything else than `true`, the credentials + // are marked as invalid. + // The $credentials parameter is equal to the next argument of this class + function ($credentials, UserInterface $user) { + return $user->getApiToken() === $credentials; + }, + + // The custom credentials + $apiToken + )); + + +Self Validating Passport +~~~~~~~~~~~~~~~~~~~~~~~~ + +If you don't need any credentials to be checked (e.g. when using API +tokens), you can use the +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\SelfValidatingPassport`. +This class only requires a ``UserBadge`` object and optionally `Passport Badges`_. + +Passport Badges +--------------- + +The ``Passport`` also optionally allows you to add *security badges*. +Badges attach more data to the passport (to extend security). By default, +the following badges are supported: + +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\RememberMeBadge` + When this badge is added to the passport, the authenticator indicates + remember me is supported. Whether remember me is actually used depends + on special ``remember_me`` configuration. Read + :doc:`/security/remember_me` for more information. + +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\PasswordUpgradeBadge` + This is used to automatically upgrade the password to a new hash upon + successful login (if needed). This badge requires the plaintext password and a + password upgrader (e.g. the user repository). See :ref:`security-password-migration`. + +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\CsrfTokenBadge` + Automatically validates CSRF tokens for this authenticator during + authentication. The constructor requires a token ID (unique per form) + and CSRF token (unique per request). See :doc:`/security/csrf`. + +:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\PreAuthenticatedUserBadge` + Indicates that this user was pre-authenticated (i.e. before Symfony was + initiated). This skips the + :doc:`pre-authentication user checker `. + +.. versionadded:: 5.2 + + Since 5.2, the ``PasswordUpgradeBadge`` is automatically added to + the passport if the passport has ``PasswordCredentials``. + +For instance, if you want to add CSRF to your custom authenticator, you +would initialize the passport like this:: + + // src/Service/LoginAuthenticator.php + namespace App\Service; + + // ... + use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; + use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge; + use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; + use Symfony\Component\Security\Http\Authenticator\Passport\Passport; + use Symfony\Component\Security\Http\Authenticator\Passport\Passport; + + class LoginAuthenticator extends AbstractAuthenticator + { + public function authenticate(Request $request): Passport + { + $password = $request->request->get('password'); + $username = $request->request->get('username'); + $csrfToken = $request->request->get('csrf_token'); + + // ... validate no parameter is empty + + return new Passport( + new UserBadge($username), + new PasswordCredentials($password), + [new CsrfTokenBadge('login', $csrfToken)] + ); + } + } + +.. tip:: + + Besides badges, passports can define attributes, which allows the + ``authenticate()`` method to store arbitrary information in the + passport to access it from other authenticator methods (e.g. + ``createAuthenticatedToken()``):: + + // ... + use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; + + class LoginAuthenticator extends AbstractAuthenticator + { + // ... + + public function authenticate(Request $request): Passport + { + // ... process the request + + $passport = new SelfValidatingPassport(new UserBadge($username), []); + + // set a custom attribute (e.g. scope) + $passport->setAttribute('scope', $oauthScope); + + return $passport; + } + + public function createToken(Passport $passport, string $firewallName): TokenInterface + { + // read the attribute value + return new CustomOauthToken($passport->getUser(), $passport->getAttribute('scope')); + } + } + +.. versionadded:: 5.2 + + Passport attributes were introduced in Symfony 5.2. diff --git a/security/entry_point.rst b/security/entry_point.rst new file mode 100644 index 00000000000..daee51493fa --- /dev/null +++ b/security/entry_point.rst @@ -0,0 +1,174 @@ +The Entry Point: Helping Users Start Authentication +=================================================== + +When an unauthenticated user tries to access a protected page, Symfony +gives them a suitable response to let them start authentication (e.g. +redirect to a login form or show a 401 Unauthorized HTTP response for +APIs). + +However sometimes, one firewall has multiple ways to authenticate (e.g. +both a form login and a social login). In these cases, it is required to +configure the *authentication entry point*. + +You can configure this using the ``entry_point`` setting: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + enable_authenticator_manager: true + + # ... + firewalls: + main: + # allow authentication using a form or a custom authenticator + form_login: ~ + custom_authenticators: + - App\Security\SocialConnectAuthenticator + + # 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 + use Symfony\Config\SecurityConfig; + use App\Security\SocialConnectAuthenticator; + + return static function (SecurityConfig $security) { + $security->enableAuthenticatorManager(true); + // .... + + + // allow authentication using a form or HTTP basic + $mainFirewall = $security->firewall('main'); + $mainFirewall + ->formLogin() + ->customAuthenticators([SocialConnectAuthenticator::class]) + + // configure the form authentication as the entry point for unauthenticated users + ->entryPoint('form_login'); + ; + }; + +.. note:: + + You can also create your own authentication entry point by creating a + class that implements + :class:`Symfony\\Component\\Security\\Http\\EntryPoint\\AuthenticationEntryPointInterface`. + You can then set ``entry_point`` to the service id (e.g. + ``entry_point: App\Security\CustomEntryPoint``) + +Multiple Authenticators with Separate Entry Points +-------------------------------------------------- + +However, there are use cases where you have authenticators that protect +different parts of your application. For example, you have a login form +that protects the main website and API end-points used by external parties +protected by API keys. + +As you can only configure one entry point per firewall, the solution is to +split the configuration into two separate firewalls: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + firewalls: + api: + pattern: ^/api/ + custom_authenticators: + - App\Security\ApiTokenAuthenticator + main: + lazy: true + form_login: ~ + + access_control: + - { path: '^/login', roles: PUBLIC_ACCESS } + - { path: '^/api', roles: ROLE_API_USER } + - { path: '^/', roles: ROLE_USER } + + .. code-block:: xml + + + + + + + + + App\Security\ApiTokenAuthenticator + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use App\Security\ApiTokenAuthenticator; + use App\Security\LoginFormAuthenticator; + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $apiFirewall = $security->firewall('api'); + $apiFirewall + ->pattern('^/api') + ->customAuthenticators([ApiTokenAuthenticator::class]) + ; + + $mainFirewall = $security->firewall('main'); + $mainFirewall + ->lazy(true) + ->formLogin(); + + $accessControl = $security->accessControl(); + $accessControl->path('^/login')->roles(['IS_AUTHENTICATED_ANONYMOUSLY']); + $accessControl->path('^/api')->roles(['ROLE_API_USER']); + $accessControl->path('^/')->roles(['ROLE_USER']); + }; diff --git a/security/experimental_authenticators.rst b/security/experimental_authenticators.rst deleted file mode 100644 index d0813795b12..00000000000 --- a/security/experimental_authenticators.rst +++ /dev/null @@ -1,504 +0,0 @@ -Using the new Authenticator-based Security -========================================== - -.. versionadded:: 5.1 - - Authenticator-based security was introduced as an - :doc:`experimental feature ` in - Symfony 5.1. - -In Symfony 5.1, a new authentication system was introduced. This system -changes the internals of Symfony Security, to make it more extensible -and more understandable. - -.. _security-enable-authenticator-manager: - -Enabling the System -------------------- - -The authenticator-based system can be enabled using the -``enable_authenticator_manager`` setting: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - enable_authenticator_manager: true - # ... - - .. code-block:: xml - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - $container->loadFromExtension('security', [ - 'enable_authenticator_manager' => true, - // ... - ]); - -The new system is backwards compatible with the current authentication -system, with some exceptions that will be explained in this article: - -* :ref:`Anonymous users no longer exist ` -* :ref:`Configuring the authentication entry point is required when more than one authenticator is used ` -* :ref:`The authentication providers are refactored into Authenticators ` - -.. _authenticators-removed-anonymous: - -Adding Support for Unsecured Access (i.e. Anonymous Users) ----------------------------------------------------------- - -In Symfony, visitors that haven't yet logged in to your website were called -:ref:`anonymous users `. The new system no longer -has anonymous authentication. Instead, these sessions are now treated as -unauthenticated (i.e. there is no security token). When using -``isGranted()``, the result will always be ``false`` (i.e. denied) as this -session is handled as a user without any privileges. - -In the ``access_control`` configuration, you can use the new -``PUBLIC_ACCESS`` security attribute to whitelist some routes for -unauthenticated access (e.g. the login page): - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - enable_authenticator_manager: true - - # ... - access_control: - # allow unauthenticated users to access the login form - - { path: ^/admin/login, roles: PUBLIC_ACCESS } - - # but require authentication for all other admin routes - - { path: ^/admin, roles: ROLE_ADMIN } - - .. code-block:: xml - - - - - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - use Symfony\Component\Security\Http\Firewall\AccessListener; - - $container->loadFromExtension('security', [ - 'enable_authenticator_manager' => true, - - // ... - 'access_control' => [ - // allow unauthenticated users to access the login form - ['path' => '^/admin/login', 'roles' => AccessListener::PUBLIC_ACCESS], - - // but require authentication for all other admin routes - ['path' => '^/admin', 'roles' => 'ROLE_ADMIN'], - ], - ]); - -.. _authenticators-required-entry-point: - -Configuring the Authentication Entry Point ------------------------------------------- - -Sometimes, one firewall has multiple ways to authenticate (e.g. both a form -login and an API token authentication). In these cases, it is now required -to configure the *authentication entry point*. The entry point is used to -generate a response when the user is not yet authenticated but tries to access -a page that requires authentication. This can be used for instance to redirect -the user to the login page. - -You can configure this using the ``entry_point`` setting: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - enable_authenticator_manager: true - - # ... - firewalls: - main: - # allow authentication using a form or HTTP basic - form_login: ~ - http_basic: ~ - - # configure the form authentication as the entry point for unauthenticated users - entry_point: form_login - - .. code-block:: xml - - - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - use Symfony\Component\Security\Http\Firewall\AccessListener; - - $container->loadFromExtension('security', [ - 'enable_authenticator_manager' => true, - - // ... - 'firewalls' => [ - 'main' => [ - // allow authentication using a form or HTTP basic - 'form_login' => null, - 'http_basic' => null, - - // configure the form authentication as the entry point for unauthenticated users - 'entry_point' => 'form_login' - ], - ], - ]); - -.. note:: - - You can also create your own authentication entry point by creating a - class that implements - :class:`Symfony\\Component\\Security\\Http\\EntryPoint\\AuthenticationEntryPointInterface`. - You can then set ``entry_point`` to the service id (e.g. - ``entry_point: App\Security\CustomEntryPoint``) - -.. _authenticators-removed-authentication-providers: - -Creating a Custom Authenticator -------------------------------- - -Security traditionally could be extended by writing -:doc:`custom authentication providers `. -The authenticator-based system dropped support for these providers and -introduced a new authenticator interface as a base for custom -authentication methods. - -.. tip:: - - :doc:`Guard authenticators ` are still - supported in the authenticator-based system. It is however recommended - to also update these when you're refactoring your application to the - new system. The new authenticator interface has many similarities with the - guard authenticator interface, making the rewrite easier. - -Authenticators should implement the -:class:`Symfony\\Component\\Security\\Http\\Authenticator\\AuthenticatorInterface`. -You can also extend -:class:`Symfony\\Component\\Security\\Http\\Authenticator\\AbstractAuthenticator`, -which has a default implementation for the ``createAuthenticatedToken()`` -method that fits most use-cases:: - - // src/Security/ApiKeyAuthenticator.php - namespace App\Security; - - use App\Entity\User; - use Doctrine\ORM\EntityManagerInterface; - use Symfony\Component\HttpFoundation\JsonResponse; - use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; - use Symfony\Component\Security\Core\Exception\AuthenticationException; - use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; - use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; - use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; - use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface; - use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport; - - class ApiKeyAuthenticator extends AbstractAuthenticator - { - private $entityManager; - - public function __construct(EntityManagerInterface $entityManager) - { - $this->entityManager = $entityManager; - } - - /** - * Called on every request to decide if this authenticator should be - * used for the request. Returning `false` will cause this authenticator - * to be skipped. - */ - public function supports(Request $request): ?bool - { - return $request->headers->has('X-AUTH-TOKEN'); - } - - public function authenticate(Request $request): PassportInterface - { - $apiToken = $request->headers->get('X-AUTH-TOKEN'); - if (null === $apiToken) { - // The token header was empty, authentication fails with HTTP Status - // Code 401 "Unauthorized" - throw new CustomUserMessageAuthenticationException('No API token provided'); - } - - $user = $this->entityManager->getRepository(User::class) - ->findOneBy(['apiToken' => $apiToken]) - ; - if (null === $user) { - throw new UsernameNotFoundException(); - } - - return new SelfValidatingPassport($user); - } - - public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response - { - // on success, let the request continue - return null; - } - - public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response - { - $data = [ - // you may want to customize or obfuscate the message first - 'message' => strtr($exception->getMessageKey(), $exception->getMessageData()) - - // or to translate this message - // $this->translator->trans($exception->getMessageKey(), $exception->getMessageData()) - ]; - - return new JsonResponse($data, Response::HTTP_UNAUTHORIZED); - } - } - -The authenticator can be enabled using the ``custom_authenticators`` setting: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - enable_authenticator_manager: true - - # ... - firewalls: - main: - custom_authenticators: - - App\Security\ApiKeyAuthenticator - - # don't forget to also configure the entry_point if the - # authenticator implements AuthenticatorEntryPointInterface - # entry_point: App\Security\CustomFormLoginAuthenticator - - .. code-block:: xml - - - - - - - - - - - - App\Security\ApiKeyAuthenticator - - - - - .. code-block:: php - - // config/packages/security.php - use App\Security\ApiKeyAuthenticator; - use Symfony\Component\Security\Http\Firewall\AccessListener; - - $container->loadFromExtension('security', [ - 'enable_authenticator_manager' => true, - - // ... - 'firewalls' => [ - 'main' => [ - 'custom_authenticators' => [ - ApiKeyAuthenticator::class, - ], - - // don't forget to also configure the entry_point if the - // authenticator implements AuthenticatorEntryPointInterface - // 'entry_point' => [App\Security\CustomFormLoginAuthenticator::class], - ], - ], - ]); - -The ``authenticate()`` method is the most important method of the -authenticator. Its job is to extract credentials (e.g. username & -password, or API tokens) from the ``Request`` object and transform these -into a security -:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Passport`. - -.. tip:: - - If you want to customize the login form, you can also extend from the - :class:`Symfony\\Component\\Security\\Http\\Authenticator\\AbstractLoginFormAuthenticator` - class instead. - -Security Passports -~~~~~~~~~~~~~~~~~~ - -A passport is an object that contains the user that will be authenticated as -well as other pieces of information, like whether a password should be checked -or if "remember me" functionality should be enabled. - -The default -:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Passport`. -requires a user object and credentials. The following credential classes -are supported by default: - - -:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Credentials\\PasswordCredentials` - This requires a plaintext ``$password``, which is validated using the - :ref:`password encoder configured for the user `. - -:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Credentials\\CustomCredentials` - Allows a custom closure to check credentials:: - - // ... - return new Passport($user, new CustomCredentials( - // If this function returns anything else than `true`, the credentials - // are marked as invalid. - // The $credentials parameter is equal to the next argument of this class - function ($credentials, UserInterface $user) { - return $user->getApiToken() === $credentials; - }, - - // The custom credentials - $apiToken - )); - -.. note:: - - If you don't need any credentials to be checked (e.g. a JWT token), you - can use the - :class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\SelfValidatingPassport`. - This class only requires a user and optionally `Passport Badges`_. - -Passport Badges -~~~~~~~~~~~~~~~ - -The ``Passport`` also optionally allows you to add *security badges*. -Badges attach more data to the passport (to extend security). By default, -the following badges are supported: - -:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\RememberMeBadge` - When this badge is added to the passport, the authenticator indicates - remember me is supported. Whether remember me is actually used depends - on special ``remember_me`` configuration. Read - :doc:`/security/remember_me` for more information. - -:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\PasswordUpgradeBadge` - This is used to automatically upgrade the password to a new hash upon - successful login. This badge requires the plaintext password and a - password upgrader (e.g. the user repository). See :doc:`/security/password_migration`. - -:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\CsrfTokenBadge` - Automatically validates CSRF tokens for this authenticator during - authentication. The constructor requires a token ID (unique per form) - and CSRF token (unique per request). See :doc:`/security/csrf`. - -:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\PreAuthenticatedUserBadge` - Indicates that this user was pre-authenticated (i.e. before Symfony was - initiated). This skips the - :doc:`pre-authentication user checker `. - -For instance, if you want to add CSRF and password migration to your custom -authenticator, you would initialize the passport like this:: - - // src/Service/LoginAuthenticator.php - namespace App\Service; - - // ... - use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; - use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge; - use Symfony\Component\Security\Http\Authenticator\Passport\Badge\PasswordUpgradeBadge; - use Symfony\Component\Security\Http\Authenticator\Passport\Passport; - use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface; - - class LoginAuthenticator extends AbstractAuthenticator - { - public function authenticate(Request $request): PassportInterface - { - $password = $request->request->get('password'); - $username = $request->request->get('username'); - $csrfToken = $request->request->get('csrf_token'); - - // ... get the $user from the $username and validate no - // parameter is empty - - return new Passport($user, new PasswordCredentials($password), [ - // $this->userRepository must implement PasswordUpgraderInterface - new PasswordUpgradeBadge($password, $this->userRepository), - new CsrfTokenBadge('login', $csrfToken), - ]); - } - } diff --git a/security/expressions.rst b/security/expressions.rst index fefee9bac17..c1bc9717a70 100644 --- a/security/expressions.rst +++ b/security/expressions.rst @@ -12,16 +12,23 @@ Security: Complex Access Controls with Expressions In addition to a role like ``ROLE_ADMIN``, the ``isGranted()`` method also accepts an :class:`Symfony\\Component\\ExpressionLanguage\\Expression` object:: + // src/Controller/MyController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\ExpressionLanguage\Expression; - // ... + use Symfony\Component\HttpFoundation\Response; - public function index() + class MyController extends AbstractController { - $this->denyAccessUnlessGranted(new Expression( - '"ROLE_ADMIN" in role_names or (not is_anonymous() and user.isSuperAdmin())' - )); + public function index(): Response + { + $this->denyAccessUnlessGranted(new Expression( + '"ROLE_ADMIN" in role_names or (not is_anonymous() and user.isSuperAdmin())' + )); - // ... + // ... + } } In this example, if the current user has ``ROLE_ADMIN`` or if the current @@ -38,12 +45,14 @@ Inside the expression, you have access to a number of variables: ``user`` The user object (or the string ``anon`` if you're not authenticated). -``roles`` - The array of roles the user has. This array includes any roles granted - indirectly via the :ref:`role hierarchy ` but it +``role_names`` + An array with the string representation of the roles the user has. This array + includes any roles granted indirectly via the :ref:`role hierarchy ` but it does not include the ``IS_AUTHENTICATED_*`` attributes (see the functions below). ``object`` The object (if any) that's passed as the second argument to ``isGranted()``. +``subject`` + It stores the same value as ``object``, so they are equivalent. ``token`` The token object. ``trust_resolver`` @@ -64,10 +73,10 @@ Additionally, you have access to a number of functions inside the expression: ``is_fully_authenticated()`` Equal to checking if the user has the ``IS_AUTHENTICATED_FULLY`` role. ``is_granted()`` - Checks if the user has the given permission. Optionally accepts a second argument - with the object where permission is checked on. It's equivalent to using - the :doc:`isGranted() method ` from the authorization - checker service. + Checks if the user has the given permission. Optionally accepts a + second argument with the object where permission is checked on. It's + equivalent to using the :ref:`isGranted() method ` + from the security service. .. sidebar:: ``is_remember_me()`` is different than checking ``IS_AUTHENTICATED_REMEMBERED`` @@ -80,7 +89,7 @@ Additionally, you have access to a number of functions inside the expression: use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; // ... - public function index(AuthorizationCheckerInterface $authorizationChecker) + public function index(AuthorizationCheckerInterface $authorizationChecker): Response { $access1 = $authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED'); diff --git a/security/firewall_restriction.rst b/security/firewall_restriction.rst index ee0950083bc..3638858efde 100644 --- a/security/firewall_restriction.rst +++ b/security/firewall_restriction.rst @@ -44,7 +44,7 @@ if the request path matches the configured ``pattern``. .. code-block:: xml - + loadFromExtension('security', [ - 'firewalls' => [ - 'secured_area' => [ - 'pattern' => '^/admin', - // ... - ], - ], - ]); + return static function (SecurityConfig $security) { + // .... + + $security->firewall('secured_area') + ->pattern('^/admin') + // ... + ; + }; The ``pattern`` is a regular expression. In this example, the firewall will only be activated if the path starts (due to the ``^`` regex character) with ``/admin``. If @@ -103,7 +103,7 @@ only initialize if the host from the request matches against the configuration. .. code-block:: xml - + loadFromExtension('security', [ - 'firewalls' => [ - 'secured_area' => [ - 'host' => '^admin\.example\.com$', - // ... - ], - ], - ]); + $security->firewall('secured_area') + ->host('^admin\.example\.com$') + // ... + ; + }; The ``host`` (like the ``pattern``) is a regular expression. In this example, the firewall will only be activated if the host is equal exactly (due to @@ -163,7 +163,7 @@ the provided HTTP methods. .. code-block:: xml - + loadFromExtension('security', [ - 'firewalls' => [ - 'secured_area' => [ - 'methods' => ['GET', 'POST'], - // ... - ], - ], - ]); + return static function (SecurityConfig $security) { + // .... + + $security->firewall('secured_area') + ->methods(['GET', 'POST']) + // ... + ; + }; In this example, the firewall will only be activated if the HTTP method of the request is either ``GET`` or ``POST``. If the method is not in the array of the @@ -221,7 +221,7 @@ If the above options don't fit your needs you can configure any service implemen .. code-block:: xml - + loadFromExtension('security', [ - 'firewalls' => [ - 'secured_area' => [ - 'request_matcher' => 'app.firewall.secured_area.request_matcher', - // ... - ], - ], - ]); + $security->firewall('secured_area') + ->requestMatcher('app.firewall.secured_area.request_matcher') + // ... + ; + }; diff --git a/security/force_https.rst b/security/force_https.rst index 9492e0fece0..2c2a8fe42c2 100644 --- a/security/force_https.rst +++ b/security/force_https.rst @@ -31,7 +31,7 @@ access control: .. code-block:: xml - + loadFromExtension('security', [ - // ... - - 'access_control' => [ - [ - 'path' => '^/secure', - 'roles' => 'ROLE_ADMIN', - 'requires_channel' => 'https', - ], - [ - 'path' => '^/login', - 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', - 'requires_channel' => 'https', - ], - [ - 'path' => '^/', - 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', - 'requires_channel' => 'https', - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // .... + + $security->accessControl() + ->path('^/secure') + ->roles(['ROLE_ADMIN']) + ->requiresChannel('https') + ; + + $security->accessControl() + ->path('^/login') + ->roles(['IS_AUTHENTICATED_ANONYMOUSLY']) + ->requiresChannel('https') + ; + + $security->accessControl() + ->path('^/') + ->roles(['IS_AUTHENTICATED_ANONYMOUSLY']) + ->requiresChannel('https') + ; + }; To make life easier while developing, you can also use an environment variable, like ``requires_channel: '%env(SECURE_SCHEME)%'``. In your ``.env`` file, set diff --git a/security/form_login.rst b/security/form_login.rst index 6400a62206b..4bace9cf2a8 100644 --- a/security/form_login.rst +++ b/security/form_login.rst @@ -1,405 +1,15 @@ .. index:: single: Security; Customizing form login redirect -Using the form_login Authentication Provider -============================================ +Customizing the Form Login Authenticator Responses +================================================== -.. caution:: +The form login authenticator creates a login form where users authenticate +using an identifier (e.g. email address or username) and a password. In +:ref:`security-form-login` the usage of this authenticator is explained. - To have complete control over your login form, we recommend building a - :doc:`form login authentication with Guard `. - -Symfony comes with a built-in ``form_login`` system that handles a login form -POST automatically. Before you start, make sure you've followed the -:doc:`Security Guide ` to create your User class. - -form_login Setup ----------------- - -First, enable ``form_login`` under your firewall: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - firewalls: - main: - anonymous: true - lazy: true - form_login: - login_path: login - check_path: login - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'anonymous' => true, - 'lazy' => true, - 'form_login' => [ - 'login_path' => 'login', - 'check_path' => 'login', - ], - ], - ], - ]); - -.. tip:: - - The ``login_path`` and ``check_path`` can also be route names (but cannot - have mandatory wildcards - e.g. ``/login/{foo}`` where ``foo`` has no - default value). - -Now, when the security system initiates the authentication process, it will -redirect the user to the login form ``/login``. Implementing this login form -is your job. First, create a new ``SecurityController``:: - - // src/Controller/SecurityController.php - namespace App\Controller; - - use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; - - class SecurityController extends AbstractController - { - } - -Next, configure the route that you earlier used under your ``form_login`` -configuration (``login``): - -.. configuration-block:: - - .. code-block:: php-annotations - - // src/Controller/SecurityController.php - namespace App\Controller; - - // ... - use Symfony\Component\Routing\Annotation\Route; - - class SecurityController extends AbstractController - { - /** - * @Route("/login", name="login", methods={"GET", "POST"}) - */ - public function login() - { - } - } - - .. code-block:: yaml - - # config/routes.yaml - login: - path: /login - controller: App\Controller\SecurityController::login - methods: GET|POST - - .. code-block:: xml - - - - - - - - - .. code-block:: php - - // config/routes.php - use App\Controller\SecurityController; - use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; - - return function (RoutingConfigurator $routes) { - $routes->add('login', '/login') - ->controller([SecurityController::class, 'login']) - ->methods(['GET', 'POST']) - ; - }; - -Great! Next, add the logic to ``login()`` that displays the login form:: - - // src/Controller/SecurityController.php - use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; - - public function login(AuthenticationUtils $authenticationUtils) - { - // get the login error if there is one - $error = $authenticationUtils->getLastAuthenticationError(); - - // last username entered by the user - $lastUsername = $authenticationUtils->getLastUsername(); - - return $this->render('security/login.html.twig', [ - 'last_username' => $lastUsername, - 'error' => $error, - ]); - } - -.. note:: - - If you get an error that the ``$authenticationUtils`` argument is missing, - it's probably because the controllers of your application are not defined as - services and tagged with the ``controller.service_arguments`` tag, as done - in the :ref:`default services.yaml configuration `. - -Don't let this controller confuse you. As you'll see in a moment, when the -user submits the form, the security system automatically handles the form -submission for you. If the user submits an invalid username or password, -this controller reads the form submission error from the security system, -so that it can be displayed back to the user. - -In other words, your job is to *display* the login form and any login errors -that may have occurred, but the security system itself takes care of checking -the submitted username and password and authenticating the user. - -Finally, create the template: - -.. code-block:: html+twig - - {# templates/security/login.html.twig #} - {# ... you will probably extend your base template, like base.html.twig #} - - {% if error %} -
    {{ error.messageKey|trans(error.messageData, 'security') }}
    - {% endif %} - -
    - - - - - - - {# - If you want to control the URL the user - is redirected to on success (more details below) - - #} - - -
    - -.. tip:: - - The ``error`` variable passed into the template is an instance of - :class:`Symfony\\Component\\Security\\Core\\Exception\\AuthenticationException`. - It may contain more information - or even sensitive information - about - the authentication failure, so use it wisely! - -The form can look like anything, but it usually follows some conventions: - -* The ``
    `` element sends a ``POST`` request to the ``login`` route, since - that's what you configured under the ``form_login`` key in ``security.yaml``; -* The username field has the name ``_username`` and the password field has the - name ``_password``. - -.. tip:: - - Actually, all of this can be configured under the ``form_login`` key. See - :ref:`reference-security-firewall-form-login` for more details. - -.. caution:: - - This login form is currently not protected against CSRF attacks. Read - :ref:`form_login-csrf` on how to protect your login form. - -And that's it! When you submit the form, the security system will automatically -check the user's credentials and either authenticate the user or send the -user back to the login form where the error can be displayed. - -To review the whole process: - -#. The user tries to access a resource that is protected; -#. The firewall initiates the authentication process by redirecting the - user to the login form (``/login``); -#. The ``/login`` page renders login form via the route and controller created - in this example; -#. The user submits the login form to ``/login``; -#. The security system intercepts the request, checks the user's submitted - credentials, authenticates the user if they are correct, and sends the - user back to the login form if they are not. - -.. _form_login-csrf: - -CSRF Protection in Login Forms ------------------------------- - -`Login CSRF attacks`_ can be prevented using the same technique of adding hidden -CSRF tokens into the login forms. The Security component already provides CSRF -protection, but you need to configure some options before using it. - -First, configure the CSRF token provider used by the form login in your security -configuration. You can set this to use the default provider available in the -security component: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - firewalls: - secured_area: - # ... - form_login: - # ... - csrf_token_generator: security.csrf.token_manager - - .. code-block:: xml - - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - $container->loadFromExtension('security', [ - // ... - - 'firewalls' => [ - 'secured_area' => [ - // ... - 'form_login' => [ - // ... - 'csrf_token_generator' => 'security.csrf.token_manager', - ], - ], - ], - ]); - -.. _csrf-login-template: - -Then, use the ``csrf_token()`` function in the Twig template to generate a CSRF -token and store it as a hidden field of the form. By default, the HTML field -must be called ``_csrf_token`` and the string used to generate the value must -be ``authenticate``: - -.. code-block:: html+twig - - {# templates/security/login.html.twig #} - - {# ... #} - - {# ... the login fields #} - - - - -
    - -After this, you have protected your login form against CSRF attacks. - -.. tip:: - - You can change the name of the field by setting ``csrf_parameter`` and change - the token ID by setting ``csrf_token_id`` in your configuration: - - .. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - firewalls: - secured_area: - # ... - form_login: - # ... - csrf_parameter: _csrf_security_token - csrf_token_id: a_private_string - - .. code-block:: xml - - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - $container->loadFromExtension('security', [ - // ... - - 'firewalls' => [ - 'secured_area' => [ - // ... - 'form_login' => [ - // ... - 'csrf_parameter' => '_csrf_security_token', - 'csrf_token_id' => 'a_private_string', - ], - ], - ], - ]); +This article describes how to customize the responses (success or failure) +of this authenticator. Redirecting after Success ------------------------- @@ -438,7 +48,7 @@ a relative/absolute URL or a Symfony route name: .. code-block:: xml - + loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'main' => [ + $security->firewall('main') + // ... + ->formLogin() // ... - - 'form_login' => [ - // ... - 'default_target_path' => 'after_login_route_name', - ], - ], - ], - ]); + ->defaultTargetPath('after_login_route_name') + ; + }; Always Redirect to the default Page ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -497,7 +105,7 @@ previously requested URL and always redirect to the default page: .. code-block:: xml - + loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'main' => [ + $security->firewall('main') + // ... + ->formLogin() // ... - - 'form_login' => [ - // ... - 'always_use_default_target_path' => true, - ], - ], - ], - ]); + ->alwaysUseDefaultTargetPath(true) + ; + }; .. _control-the-redirect-url-from-inside-the-form: @@ -587,7 +193,7 @@ parameter is included in the request, you may use the value of the .. code-block:: xml - + loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'main' => [ + $security->firewall('main') + // ... + ->formLogin() // ... - 'form_login' => [ - // ... - 'use_referer' => true, - ], - ], - ], - ]); + ->useReferer(true) + ; + }; .. note:: @@ -655,7 +260,7 @@ option to define a new target via a relative/absolute URL or a Symfony route nam .. code-block:: xml - + loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'main' => [ + $security->firewall('main') + // ... + ->formLogin() // ... - 'form_login' => [ - // ... - 'failure_path' => 'login_failure_route_name', - ], - ], - ], - ]); + ->failurePath('login_failure_route_name') + ; + }; This option can also be set via the ``_failure_path`` request parameter: @@ -732,7 +336,7 @@ redirects can be customized using the ``target_path_parameter`` and .. code-block:: xml - + loadFromExtension('security', [ + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'main' => [ + $security->firewall('main') + // ... + ->formLogin() // ... - 'form_login' => [ - 'target_path_parameter' => 'go_to', - 'failure_path_parameter' => 'back_to', - ], - ], - ], - ]); + ->targetPathParameter('go_to') + ->failurePathParameter('back_to') + ; + }; Using the above configuration, the query string parameters and hidden form fields are now fully customized: @@ -786,5 +390,3 @@ are now fully customized: - -.. _`Login CSRF attacks`: https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests diff --git a/security/form_login_setup.rst b/security/form_login_setup.rst deleted file mode 100644 index c7ea359c459..00000000000 --- a/security/form_login_setup.rst +++ /dev/null @@ -1,518 +0,0 @@ -How to Build a Login Form -========================= - -.. seealso:: - - If you're looking for the ``form_login`` firewall option, see - :doc:`/security/form_login`. - -Ready to create a login form? First, make sure you've followed the main -:doc:`Security Guide ` to install security and create your ``User`` -class. - -Generating the Login Form -------------------------- - -Creating a powerful login form can be bootstrapped with the ``make:auth`` command from -`MakerBundle`_. Depending on your setup, you may be asked different questions -and your generated code may be slightly different: - -.. code-block:: terminal - - $ php bin/console make:auth - - What style of authentication do you want? [Empty authenticator]: - [0] Empty authenticator - [1] Login form authenticator - > 1 - - The class name of the authenticator to create (e.g. AppCustomAuthenticator): - > LoginFormAuthenticator - - Choose a name for the controller class (e.g. SecurityController) [SecurityController]: - > SecurityController - - Do you want to generate a '/logout' URL? (yes/no) [yes]: - > yes - - created: src/Security/LoginFormAuthenticator.php - updated: config/packages/security.yaml - created: src/Controller/SecurityController.php - created: templates/security/login.html.twig - -.. versionadded:: 1.8 - - Support for login form authentication was added to ``make:auth`` in MakerBundle 1.8. - -This generates the following: 1) login/logout routes & controller, 2) a template that -renders the login form, 3) a :doc:`Guard authenticator ` -class that processes the login submit and 4) updates the main security config file. - -**Step 1.** The ``/login``/``/logout`` routes & controller:: - - // src/Controller/SecurityController.php - namespace App\Controller; - - use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; - use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\Routing\Annotation\Route; - use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; - - class SecurityController extends AbstractController - { - /** - * @Route("/login", name="app_login") - */ - public function login(AuthenticationUtils $authenticationUtils): Response - { - // if ($this->getUser()) { - // return $this->redirectToRoute('target_path'); - // } - - // get the login error if there is one - $error = $authenticationUtils->getLastAuthenticationError(); - // last username entered by the user - $lastUsername = $authenticationUtils->getLastUsername(); - - return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]); - } - - /** - * @Route("/logout", name="app_logout") - */ - public function logout() - { - throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.'); - } - } - -Edit the ``security.yaml`` file in order to declare the ``/logout`` path: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - firewalls: - main: - # ... - logout: - path: app_logout - # where to redirect after logout - # target: app_any_route - - .. code-block:: xml - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - $container->loadFromExtension('security', [ - // ... - 'firewalls' => [ - 'main' => [ - // ... - 'logout' => [ - 'path' => 'app_logout', - // where to redirect after logout - 'target' => 'app_any_route' - ], - ], - ], - ]); - -**Step 2.** The template has very little to do with security: it generates -a traditional HTML form that submits to ``/login``: - -.. code-block:: html+twig - - {% extends 'base.html.twig' %} - - {% block title %}Log in!{% endblock %} - - {% block body %} -
    - {% if error %} -
    {{ error.messageKey|trans(error.messageData, 'security') }}
    - {% endif %} - - {% if app.user %} -
    - You are logged in as {{ app.user.username }}, Logout -
    - {% endif %} - -

    Please sign in

    - - - - - - - - {# - Uncomment this section and add a remember_me option below your firewall to activate remember me functionality. - See https://symfony.com/doc/current/security/remember_me.html - -
    - -
    - #} - - -
    - {% endblock %} - -**Step 3.** The Guard authenticator processes the form submit:: - - // src/Security/LoginFormAuthenticator.php - namespace App\Security; - - use App\Entity\User; - use Doctrine\ORM\EntityManagerInterface; - use Symfony\Component\HttpFoundation\RedirectResponse; - use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\Routing\Generator\UrlGeneratorInterface; - use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; - use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; - use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; - use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; - use Symfony\Component\Security\Core\Security; - use Symfony\Component\Security\Core\User\UserInterface; - use Symfony\Component\Security\Core\User\UserProviderInterface; - use Symfony\Component\Security\Csrf\CsrfToken; - use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; - use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator; - use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface; - use Symfony\Component\Security\Http\Util\TargetPathTrait; - - class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface - { - use TargetPathTrait; - - public const LOGIN_ROUTE = 'app_login'; - - private $entityManager; - private $urlGenerator; - private $csrfTokenManager; - private $passwordEncoder; - - public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder) - { - $this->entityManager = $entityManager; - $this->urlGenerator = $urlGenerator; - $this->csrfTokenManager = $csrfTokenManager; - $this->passwordEncoder = $passwordEncoder; - } - - public function supports(Request $request) - { - return self::LOGIN_ROUTE === $request->attributes->get('_route') - && $request->isMethod('POST'); - } - - public function getCredentials(Request $request) - { - $credentials = [ - 'email' => $request->request->get('email'), - 'password' => $request->request->get('password'), - 'csrf_token' => $request->request->get('_csrf_token'), - ]; - $request->getSession()->set( - Security::LAST_USERNAME, - $credentials['email'] - ); - - return $credentials; - } - - public function getUser($credentials, UserProviderInterface $userProvider) - { - $token = new CsrfToken('authenticate', $credentials['csrf_token']); - if (!$this->csrfTokenManager->isTokenValid($token)) { - throw new InvalidCsrfTokenException(); - } - - $user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $credentials['email']]); - - if (!$user) { - // fail authentication with a custom error - throw new CustomUserMessageAuthenticationException('Email could not be found.'); - } - - return $user; - } - - public function checkCredentials($credentials, UserInterface $user) - { - return $this->passwordEncoder->isPasswordValid($user, $credentials['password']); - } - - /** - * Used to upgrade (rehash) the user's password automatically over time. - */ - public function getPassword($credentials): ?string - { - return $credentials['password']; - } - - public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) - { - if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) { - return new RedirectResponse($targetPath); - } - - // For example : return new RedirectResponse($this->urlGenerator->generate('some_route')); - throw new \Exception('TODO: provide a valid redirect inside '.__FILE__); - } - - protected function getLoginUrl() - { - return $this->urlGenerator->generate(self::LOGIN_ROUTE); - } - } - -**Step 4.** Updates the main security config file to enable the Guard authenticator and configure logout route: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - firewalls: - main: - # ... - guard: - authenticators: - - App\Security\LoginFormAuthenticator - logout: - path: app_logout - - .. code-block:: xml - - - - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - use App\Security\LoginFormAuthenticator; - - $container->loadFromExtension('security', [ - // ... - 'firewalls' => [ - 'main' => [ - // ..., - 'guard' => [ - 'authenticators' => [ - LoginFormAuthenticator::class, - ] - ], - 'logout' => [ - 'path' => 'app_logout', - ], - ], - ], - ]); - -Finishing the Login Form ------------------------- - -Woh. The ``make:auth`` command just did a *lot* of work for you. But, you're not done -yet. First, go to ``/login`` to see the new login form. Feel free to customize this -however you want. - -When you submit the form, the ``LoginFormAuthenticator`` will intercept the request, -read the email (or whatever field you're using) & password from the form, find the -``User`` object, validate the CSRF token and check the password. - -But, depending on your setup, you'll need to finish one or more TODOs before the -whole process works. You will *at least* need to fill in *where* you want your user to -be redirected after success: - -.. code-block:: diff - - // src/Security/LoginFormAuthenticator.php - - // ... - public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) - { - // ... - - - throw new \Exception('TODO: provide a valid redirect inside '.__FILE__); - + // redirect to some "app_homepage" route - of wherever you want - + return new RedirectResponse($this->urlGenerator->generate('app_homepage')); - } - -Unless you have any other TODOs in that file, that's it! If you're loading users -from the database, make sure you've loaded some :ref:`dummy users `. -Then, try to login. - -If you're successful, the web debug toolbar will tell you who you are and what roles -you have: - -.. image:: /_images/security/symfony_loggedin_wdt.png - :align: center - -The Guard authentication system is powerful, and you can customize your authenticator -class to do whatever you need. To learn more about what the individual methods do, -see :doc:`/security/guard_authentication`. - -Controlling Error Messages --------------------------- - -You can cause authentication to fail with a custom message at any step by throwing -a custom :class:`Symfony\\Component\\Security\\Core\\Exception\\CustomUserMessageAuthenticationException`. -But in some cases, like if you return ``false`` from ``checkCredentials()``, you -may see an error that comes from the core of Symfony - like ``Invalid credentials.``. - -To customize this message, you could throw a ``CustomUserMessageAuthenticationException`` -instead. Or, you can :doc:`translate ` the message through the ``security`` -domain: - -.. configuration-block:: - - .. code-block:: xml - - - - - - - - Invalid credentials. - The password you entered was invalid! - - - - - - .. code-block:: yaml - - # translations/security.en.yaml - 'Invalid credentials.': 'The password you entered was invalid!' - - .. code-block:: php - - // translations/security.en.php - return [ - 'Invalid credentials.' => 'The password you entered was invalid!', - ]; - -If the message isn't translated, make sure you've installed the ``translator`` -and try clearing your cache: - -.. code-block:: terminal - - $ php bin/console cache:clear - -Redirecting to the Last Accessed Page with ``TargetPathTrait`` --------------------------------------------------------------- - -The last request URI is stored in a session variable named -``_security..target_path`` (e.g. ``_security.main.target_path`` -if the name of your firewall is ``main``). Most of the times you don't have to -deal with this low level session variable. However, the -:class:`Symfony\\Component\\Security\\Http\\Util\\TargetPathTrait` utility -can be used to read (like in the example above) or set this value manually. - -When the user tries to access a restricted page, they are being redirected to -the login page. At that point target path will be set. After a successful login, -the user will be redirected to this previously set target path. - -If you also want to apply this behavior to public pages, you can create an -:doc:`event subscriber ` to set the target path manually -whenever the user browses a page:: - - // src/EventSubscriber/RequestSubscriber.php - namespace App\EventSubscriber; - - use Symfony\Component\EventDispatcher\EventSubscriberInterface; - use Symfony\Component\HttpFoundation\Session\SessionInterface; - use Symfony\Component\HttpKernel\Event\RequestEvent; - use Symfony\Component\HttpKernel\KernelEvents; - use Symfony\Component\Security\Http\Util\TargetPathTrait; - - class RequestSubscriber implements EventSubscriberInterface - { - use TargetPathTrait; - - private $session; - - public function __construct(SessionInterface $session) - { - $this->session = $session; - } - - public function onKernelRequest(RequestEvent $event): void - { - $request = $event->getRequest(); - if ( - !$event->isMasterRequest() - || $request->isXmlHttpRequest() - || 'app_login' === $request->attributes->get('_route') - ) { - return; - } - - $this->saveTargetPath($this->session, 'main', $request->getUri()); - } - - public static function getSubscribedEvents() - { - return [ - KernelEvents::REQUEST => ['onKernelRequest'] - ]; - } - } - -.. _`MakerBundle`: https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html diff --git a/security/guard_authentication.rst b/security/guard_authentication.rst deleted file mode 100644 index 99d86c6c781..00000000000 --- a/security/guard_authentication.rst +++ /dev/null @@ -1,582 +0,0 @@ -.. index:: - single: Security; Custom Authentication - -Custom Authentication System with Guard (API Token Example) -=========================================================== - -Guard authentication can be used to: - -* :doc:`Build a Login Form ` -* Create an API token authentication system (see below) -* `Social Authentication`_ (or use `HWIOAuthBundle`_ for a robust non-Guard solution) -* Integrate with some proprietary single-sign-on system - -and many more. In this example, we'll build an API token authentication -system, so we can learn more about Guard in detail. - -.. tip:: - - A :doc:`new experimental authenticator-based system ` - was introduced in Symfony 5.1, which will eventually replace Guards in Symfony 6.0. - -Step 1) Prepare your User Class -------------------------------- - -Suppose you want to build an API where your clients will send an ``X-AUTH-TOKEN`` header -on each request with their API token. Your job is to read this and find the associated -user (if any). - -First, make sure you've followed the main :doc:`Security Guide ` to -create your ``User`` class. Then add an ``apiToken`` property directly to -your ``User`` class (the ``make:entity`` command is a good way to do this): - -.. code-block:: diff - - // src/Entity/User.php - namespace App\Entity; - - // ... - - class User implements UserInterface - { - // ... - - + /** - + * @ORM\Column(type="string", unique=true, nullable=true) - + */ - + private $apiToken; - - // the getter and setter methods - } - -Don't forget to generate and run the migration: - -.. code-block:: terminal - - $ php bin/console make:migration - $ php bin/console doctrine:migrations:migrate - -Next, configure your "user provider" to use this new ``apiToken`` property: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - providers: - your_db_provider: - entity: - class: App\Entity\User - property: apiToken - - # ... - - .. code-block:: xml - - - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - $container->loadFromExtension('security', [ - // ... - - 'providers' => [ - 'your_db_provider' => [ - 'entity' => [ - 'class' => 'App\Entity\User', - 'property' => 'apiToken', - ], - ], - ], - - // ... - ]); - -Step 2) Create the Authenticator Class --------------------------------------- - -To create a custom authentication system, create a class and make it implement -:class:`Symfony\\Component\\Security\\Guard\\AuthenticatorInterface`. Or, extend -the simpler :class:`Symfony\\Component\\Security\\Guard\\AbstractGuardAuthenticator`. - -This requires you to implement several methods:: - - // src/Security/TokenAuthenticator.php - namespace App\Security; - - use App\Entity\User; - use Doctrine\ORM\EntityManagerInterface; - use Symfony\Component\HttpFoundation\JsonResponse; - use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; - use Symfony\Component\Security\Core\Exception\AuthenticationException; - use Symfony\Component\Security\Core\User\UserInterface; - use Symfony\Component\Security\Core\User\UserProviderInterface; - use Symfony\Component\Security\Guard\AbstractGuardAuthenticator; - - class TokenAuthenticator extends AbstractGuardAuthenticator - { - private $em; - - public function __construct(EntityManagerInterface $em) - { - $this->em = $em; - } - - /** - * Called on every request to decide if this authenticator should be - * used for the request. Returning `false` will cause this authenticator - * to be skipped. - */ - public function supports(Request $request) - { - return $request->headers->has('X-AUTH-TOKEN'); - } - - /** - * Called on every request. Return whatever credentials you want to - * be passed to getUser() as $credentials. - */ - public function getCredentials(Request $request) - { - return $request->headers->get('X-AUTH-TOKEN'); - } - - public function getUser($credentials, UserProviderInterface $userProvider) - { - if (null === $credentials) { - // The token header was empty, authentication fails with HTTP Status - // Code 401 "Unauthorized" - return null; - } - - // The "username" in this case is the apiToken, see the key `property` - // of `your_db_provider` in `security.yaml`. - // If this returns a user, checkCredentials() is called next: - return $userProvider->loadUserByUsername($credentials); - } - - public function checkCredentials($credentials, UserInterface $user) - { - // Check credentials - e.g. make sure the password is valid. - // In case of an API token, no credential check is needed. - - // Return `true` to cause authentication success - return true; - } - - public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) - { - // on success, let the request continue - return null; - } - - public function onAuthenticationFailure(Request $request, AuthenticationException $exception) - { - $data = [ - // you may want to customize or obfuscate the message first - 'message' => strtr($exception->getMessageKey(), $exception->getMessageData()) - - // or to translate this message - // $this->translator->trans($exception->getMessageKey(), $exception->getMessageData()) - ]; - - return new JsonResponse($data, Response::HTTP_UNAUTHORIZED); - } - - /** - * Called when authentication is needed, but it's not sent - */ - public function start(Request $request, AuthenticationException $authException = null) - { - $data = [ - // you might translate this message - 'message' => 'Authentication Required' - ]; - - return new JsonResponse($data, Response::HTTP_UNAUTHORIZED); - } - - public function supportsRememberMe() - { - return false; - } - } - -Nice work! Each method is explained below: :ref:`The Guard Authenticator Methods `. - -Step 3) Configure the Authenticator ------------------------------------ - -To finish this, make sure your authenticator is registered as a service. If you're -using the :ref:`default services.yaml configuration `, -that happens automatically. - -Finally, configure your ``firewalls`` key in ``security.yaml`` to use this authenticator: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - firewalls: - # ... - - main: - anonymous: true - lazy: true - logout: ~ - - guard: - authenticators: - - App\Security\TokenAuthenticator - - # if you want, disable storing the user in the session - # stateless: true - - # ... - - .. code-block:: xml - - - - - - - - - - - - - App\Security\TokenAuthenticator - - - - - - - - .. code-block:: php - - // config/packages/security.php - - // ... - use App\Security\TokenAuthenticator; - - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'pattern' => '^/', - 'anonymous' => true, - 'lazy' => true, - 'logout' => true, - 'guard' => [ - 'authenticators' => [ - TokenAuthenticator::class, - ], - ], - // if you want, disable storing the user in the session - // 'stateless' => true, - // ... - ], - ], - ]); - -You did it! You now have a fully-working API token authentication system. If your -homepage required ``ROLE_USER``, then you could test it under different conditions: - -.. code-block:: terminal - - # test with no token - curl http://localhost:8000/ - # {"message":"Authentication Required"} - - # test with a bad token - curl -H "X-AUTH-TOKEN: FAKE" http://localhost:8000/ - # {"message":"Username could not be found."} - - # test with a working token - curl -H "X-AUTH-TOKEN: REAL" http://localhost:8000/ - # the homepage controller is executed: the page loads normally - -Now, learn more about what each method does. - -.. _guard-auth-methods: - -The Guard Authenticator Methods -------------------------------- - -Each authenticator needs the following methods: - -**supports(Request $request)** - This is called on *every* request and your job is to decide if the - authenticator should be used for this request (return ``true``) or if it - should be skipped (return ``false``). - -**getCredentials(Request $request)** - Your job is to read the token (or whatever your "authentication" information is) - from the request and return it. These credentials are passed to ``getUser()``. - -**getUser($credentials, UserProviderInterface $userProvider)** - The ``$credentials`` argument is the value returned by ``getCredentials()``. - Your job is to return an object that implements ``UserInterface``. If you do, - then ``checkCredentials()`` will be called. If you return ``null`` (or throw - an :ref:`AuthenticationException `) authentication - will fail. - -**checkCredentials($credentials, UserInterface $user)** - If ``getUser()`` returns a User object, this method is called. Your job is to - verify if the credentials are correct. For a login form, this is where you would - check that the password is correct for the user. To pass authentication, return - ``true``. If you return ``false`` - (or throw an :ref:`AuthenticationException `), - authentication will fail. - -**onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey)** - This is called after successful authentication and your job is to either - return a :class:`Symfony\\Component\\HttpFoundation\\Response` object - that will be sent to the client or ``null`` to continue the request - (e.g. allow the route/controller to be called like normal). Since this - is an API where each request authenticates itself, you want to return - ``null``. - -**onAuthenticationFailure(Request $request, AuthenticationException $exception)** - This is called if authentication fails. Your job - is to return the :class:`Symfony\\Component\\HttpFoundation\\Response` - object that should be sent to the client. The ``$exception`` will tell you - *what* went wrong during authentication. - -**start(Request $request, AuthenticationException $authException = null)** - This is called if the client accesses a URI/resource that requires authentication, - but no authentication details were sent. Your job is to return a - :class:`Symfony\\Component\\HttpFoundation\\Response` object that helps - the user authenticate (e.g. a 401 response that says "token is missing!"). - -**supportsRememberMe()** - If you want to support "remember me" functionality, return ``true`` from this method. - You will still need to activate ``remember_me`` under your firewall for it to work. - Since this is a stateless API, you do not want to support "remember me" - functionality in this example. - -**createAuthenticatedToken(UserInterface $user, string $providerKey)** - If you are implementing the :class:`Symfony\\Component\\Security\\Guard\\AuthenticatorInterface` - instead of extending the :class:`Symfony\\Component\\Security\\Guard\\AbstractGuardAuthenticator` - class, you have to implement this method. It will be called - after a successful authentication to create and return the token (a - class implementing :class:`Symfony\\Component\\Security\\Guard\\Token\\GuardTokenInterface`) - for the user, who was supplied as the first argument. - -The picture below shows how Symfony calls Guard Authenticator methods: - -.. raw:: html - - - -.. _guard-customize-error: - -Customizing Error Messages --------------------------- - -When ``onAuthenticationFailure()`` is called, it is passed an ``AuthenticationException`` -that describes *how* authentication failed via its ``$exception->getMessageKey()`` (and -``$exception->getMessageData()``) method. The message will be different based on *where* -authentication fails (i.e. ``getUser()`` versus ``checkCredentials()``). - -But, you can also return a custom message by throwing a -:class:`Symfony\\Component\\Security\\Core\\Exception\\CustomUserMessageAuthenticationException`. -You can throw this from ``getCredentials()``, ``getUser()`` or ``checkCredentials()`` -to cause a failure:: - - // src/Security/TokenAuthenticator.php - namespace App\Security; - - // ... - - use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; - - class TokenAuthenticator extends AbstractGuardAuthenticator - { - // ... - - public function getCredentials(Request $request) - { - // ... - - if ($token == 'ILuvAPIs') { - throw new CustomUserMessageAuthenticationException( - 'ILuvAPIs is not a real API key: it\'s just a silly phrase' - ); - } - - // ... - } - - // ... - } - -In this case, since "ILuvAPIs" is a ridiculous API key, you could include an easter -egg to return a custom message if someone tries this: - -.. code-block:: terminal - - curl -H "X-AUTH-TOKEN: ILuvAPIs" http://localhost:8000/ - # {"message":"ILuvAPIs is not a real API key: it's just a silly phrase"} - -.. _guard-manual-auth: - -Manually Authenticating a User ------------------------------- - -Sometimes you might want to manually authenticate a user - like after the user -completes registration. To do that, use your authenticator and a service called -``GuardAuthenticatorHandler``:: - - // src/Controller/RegistrationController.php - namespace App\Controller; - - // ... - use App\Security\LoginFormAuthenticator; - use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\Security\Guard\GuardAuthenticatorHandler; - - class RegistrationController extends AbstractController - { - public function register(LoginFormAuthenticator $authenticator, GuardAuthenticatorHandler $guardHandler, Request $request) - { - // ... - - // after validating the user and saving them to the database - // authenticate the user and use onAuthenticationSuccess on the authenticator - return $guardHandler->authenticateUserAndHandleSuccess( - $user, // the User object you just created - $request, - $authenticator, // authenticator whose onAuthenticationSuccess you want to use - 'main' // the name of your firewall in security.yaml - ); - } - } - -Avoid Authenticating the Browser on Every Request -------------------------------------------------- - -If you create a Guard login system that's used by a browser and you're experiencing -problems with your session or CSRF tokens, the cause could be bad behavior by your -authenticator. When a Guard authenticator is meant to be used by a browser, you -should *not* authenticate the user on *every* request. In other words, you need to -make sure the ``supports()`` method *only* returns ``true`` when -you actually *need* to authenticate the user. Why? Because, when ``supports()`` -returns true (and authentication is ultimately successful), for security purposes, -the user's session is "migrated" to a new session id. - -This is an edge-case, and unless you're having session or CSRF token issues, you -can ignore this. Here is an example of good and bad behavior:: - - public function supports(Request $request) - { - // GOOD behavior: only authenticate (i.e. return true) on a specific route - return 'login_route' === $request->attributes->get('_route') && $request->isMethod('POST'); - - // e.g. your login system authenticates by the user's IP address - // BAD behavior: So, you decide to *always* return true so that - // you can check the user's IP address on every request - return true; - } - -The problem occurs when your browser-based authenticator tries to authenticate -the user on *every* request - like in the IP address-based example above. There -are two possible fixes: - -1. If you do *not* need authentication to be stored in the session, set - ``stateless: true`` under your firewall. -2. Update your authenticator to avoid authentication if the user is already - authenticated: - -.. code-block:: diff - - // src/Security/MyIpAuthenticator.php - // ... - - + use Symfony\Component\Security\Core\Security; - - class MyIpAuthenticator - { - + private $security; - - + public function __construct(Security $security) - + { - + $this->security = $security; - + } - - public function supports(Request $request) - { - + // if there is already an authenticated user (likely due to the session) - + // then return false and skip authentication: there is no need. - + if ($this->security->getUser()) { - + return false; - + } - - + // the user is not logged in, so the authenticator should continue - + return true; - } - } - -If you use autowiring, the ``Security`` service will automatically be passed to -your authenticator. - -Frequently Asked Questions --------------------------- - -**Can I have Multiple Authenticators?** - Yes! But when you do, you'll need to choose only *one* authenticator to be your - "entry_point". This means you'll need to choose *which* authenticator's ``start()`` - method should be called when an anonymous user tries to access a protected resource. - For more details, see :doc:`/security/multiple_guard_authenticators`. - -**Can I use this with form_login?** - Yes! ``form_login`` is *one* way to authenticate a user, so you could use - it *and* then add one or more authenticators. Using a guard authenticator doesn't - collide with other ways to authenticate. - -**Can I use this with FOSUserBundle?** - Yes! Actually, FOSUserBundle doesn't handle security: it only gives you a - ``User`` object and some routes and controllers to help with login, registration, - forgot password, etc. When you use FOSUserBundle, you typically use ``form_login`` - to actually authenticate the user. You can continue doing that (see previous - question) or use the ``User`` object from FOSUserBundle and create your own - authenticator(s) (like in this article). - -.. _`Social Authentication`: https://github.com/knpuniversity/oauth2-client-bundle#authenticating-with-guard -.. _`HWIOAuthBundle`: https://github.com/hwi/HWIOAuthBundle diff --git a/security/impersonating_user.rst b/security/impersonating_user.rst index 1269cbbdae1..f31474f238c 100644 --- a/security/impersonating_user.rst +++ b/security/impersonating_user.rst @@ -33,7 +33,7 @@ listener: .. code-block:: xml - + loadFromExtension('security', [ - // ... + use Symfony\Config\SecurityConfig; - 'firewalls' => [ - 'main'=> [ - // ... - 'switch_user' => true, - ], - ], - ]); + return static function (SecurityConfig $security) { + // ... + $security->firewall('main') + // ... + ->switchUser() + ; + }; To switch to another user, add a query string with the ``_switch_user`` parameter and the username (or whatever field our user provider uses to load users) @@ -170,7 +169,7 @@ also adjust the query parameter name via the ``parameter`` setting: .. code-block:: xml - + loadFromExtension('security', [ - // ... + use Symfony\Config\SecurityConfig; - 'firewalls' => [ - 'main'=> [ - // ... - 'switch_user' => [ - 'role' => 'ROLE_ADMIN', - 'parameter' => '_want_to_be_this_user', - ], - ], - ], - ]); + return static function (SecurityConfig $security) { + // ... + $security->firewall('main') + // ... + ->switchUser() + ->role('ROLE_ADMIN') + ->parameter('_want_to_be_this_user') + ; + }; Limiting User Switching ----------------------- @@ -229,7 +226,7 @@ be called): .. code-block:: xml - + loadFromExtension('security', [ - // ... + use Symfony\Config\SecurityConfig; - 'firewalls' => [ - 'main'=> [ - // ... - 'switch_user' => [ - 'role' => 'CAN_SWITCH_USER', - ], - ], - ], - ]); + return static function (SecurityConfig $security) { + // ... + $security->firewall('main') + // ... + ->switchUser() + ->role('CAN_SWITCH_USER') + ; + }; Then, create a voter class that responds to this role and includes whatever custom logic you want:: - // src/Service/Voter/SwitchToCustomerVoter.php + // src/Security/Voter/SwitchToCustomerVoter.php namespace App\Security\Voter; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -283,13 +278,13 @@ logic you want:: $this->security = $security; } - protected function supports($attribute, $subject) + protected function supports($attribute, $subject): bool { return in_array($attribute, ['CAN_SWITCH_USER']) && $subject instanceof UserInterface; } - protected function voteOnAttribute($attribute, $subject, TokenInterface $token) + protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool { $user = $token->getUser(); // if the user is anonymous or if the subject is not a user, do not grant access @@ -341,7 +336,7 @@ you switch users, add an event subscriber on this event:: class SwitchUserSubscriber implements EventSubscriberInterface { - public function onSwitchUser(SwitchUserEvent $event) + public function onSwitchUser(SwitchUserEvent $event): void { $request = $event->getRequest(); @@ -354,7 +349,7 @@ you switch users, add an event subscriber on this event:: } } - public static function getSubscribedEvents() + public static function getSubscribedEvents(): array { return [ // constant for security.switch_user diff --git a/security/json_login_setup.rst b/security/json_login_setup.rst deleted file mode 100644 index 97c76e1ab8a..00000000000 --- a/security/json_login_setup.rst +++ /dev/null @@ -1,213 +0,0 @@ -How to Build a JSON Authentication Endpoint -=========================================== - -In this entry, you'll build a JSON endpoint to log in your users. When the -user logs in, you can load your users from anywhere - like the database. -See :ref:`security-user-providers` for details. - -First, enable the JSON login under your firewall: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - firewalls: - main: - anonymous: true - lazy: true - json_login: - check_path: /login - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'anonymous' => true, - 'lazy' => true, - 'json_login' => [ - 'check_path' => '/login', - ], - ], - ], - ]); - -.. tip:: - - The ``check_path`` can also be a route name (but cannot have mandatory - wildcards - e.g. ``/login/{foo}`` where ``foo`` has no default value). - -The next step is to configure a route in your app matching this path: - -.. configuration-block:: - - .. code-block:: php-annotations - - // src/Controller/SecurityController.php - namespace App\Controller; - - // ... - use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; - use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\Routing\Annotation\Route; - - class SecurityController extends AbstractController - { - /** - * @Route("/login", name="login", methods={"POST"}) - */ - public function login(Request $request) - { - $user = $this->getUser(); - - return $this->json([ - 'username' => $user->getUsername(), - 'roles' => $user->getRoles(), - ]); - } - } - - .. code-block:: yaml - - # config/routes.yaml - login: - path: /login - controller: App\Controller\SecurityController::login - methods: POST - - .. code-block:: xml - - - - - - - - - .. code-block:: php - - // config/routes.php - use App\Controller\SecurityController; - use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; - - return function (RoutingConfigurator $routes) { - $routes->add('login', '/login') - ->controller([SecurityController::class, 'login']) - ->methods(['POST']) - ; - }; - -Now, when you make a ``POST`` request, with the header ``Content-Type: application/json``, -to the ``/login`` URL with the following JSON document as the body, the security -system intercepts the request and initiates the authentication process: - -.. code-block:: json - - { - "username": "dunglas", - "password": "MyPassword" - } - -Symfony takes care of authenticating the user with the submitted username and -password or triggers an error in case the authentication process fails. If the -authentication is successful, the controller defined earlier will be called. - -If the JSON document has a different structure, you can specify the path to -access the ``username`` and ``password`` properties using the ``username_path`` -and ``password_path`` keys (they default respectively to ``username`` and -``password``). For example, if the JSON document has the following structure: - -.. code-block:: json - - { - "security": { - "credentials": { - "login": "dunglas", - "password": "MyPassword" - } - } - } - -The security configuration should be: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - firewalls: - main: - anonymous: true - lazy: true - json_login: - check_path: login - username_path: security.credentials.login - password_path: security.credentials.password - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'anonymous' => true, - 'lazy' => true, - 'json_login' => [ - 'check_path' => 'login', - 'username_path' => 'security.credentials.login', - 'password_path' => 'security.credentials.password', - ], - ], - ], - ]); diff --git a/security/ldap.rst b/security/ldap.rst index ffbf5714b78..ff768969771 100644 --- a/security/ldap.rst +++ b/security/ldap.rst @@ -8,7 +8,7 @@ Symfony provides different means to work with an LDAP server. The Security component offers: -* The ``ldap`` :doc:`user provider `, using the +* The ``ldap`` :doc:`user provider `, using the :class:`Symfony\\Component\\Ldap\\Security\\LdapUserProvider` class. Like all other user providers, it can be used with any authentication provider. @@ -70,6 +70,8 @@ An LDAP client can be configured using the built-in services: Symfony\Component\Ldap\Ldap: arguments: ['@Symfony\Component\Ldap\Adapter\ExtLdap\Adapter'] + tags: + - ldap Symfony\Component\Ldap\Adapter\ExtLdap\Adapter: arguments: - host: my-server @@ -90,6 +92,7 @@ An LDAP client can be configured using the built-in + @@ -112,7 +115,8 @@ An LDAP client can be configured using the built-in use Symfony\Component\Ldap\Ldap; $container->register(Ldap::class) - ->addArgument(new Reference(Adapter::class)); + ->addArgument(new Reference(Adapter::class)) + ->tag('ldap'); $container ->register(Adapter::class) @@ -126,6 +130,8 @@ An LDAP client can be configured using the built-in ], ]); +.. _security-ldap-user-provider: + Fetching Users Using the LDAP User Provider ------------------------------------------- @@ -154,7 +160,7 @@ use the ``ldap`` user provider. .. code-block:: xml - + provider('ldap_users') + ->ldap() + ->service(Ldap::class) + ->baseDn('dc=example,dc=com') + ->searchDn('cn=read-only-admin,dc=example,dc=com') + ->searchPassword('password') + ->defaultRoles(['ROLE_USER']) + ->uidKey('uid') + ->extraFields(['email']) + ; + }; - $container->loadFromExtension('security', [ - 'providers' => [ - 'ldap_users' => [ - 'ldap' => [ - 'service' => Ldap::class, - 'base_dn' => 'dc=example,dc=com', - 'search_dn' => 'cn=read-only-admin,dc=example,dc=com', - 'search_password' => 'password', - 'default_roles' => 'ROLE_USER', - 'uid_key' => 'uid', - 'extra_fields' => ['email'], - ], - ], - ], - ]; .. caution:: @@ -376,7 +381,7 @@ Configuration example for form login .. code-block:: xml - + loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'form_login_ldap' => [ - 'service' => Ldap::class, - 'dn_string' => 'uid={username},dc=example,dc=com', - // ... - ], - ], - ] - ]; + return static function (SecurityConfig $security) { + $security->firewall('main') + ->formLoginLdap() + ->service(Ldap::class) + ->dnString('uid={username},dc=example,dc=com') + ; + }; Configuration example for HTTP Basic .................................... @@ -431,7 +433,7 @@ Configuration example for HTTP Basic .. code-block:: xml - + loadFromExtension('security', [ - // ... - - 'firewalls' => [ - 'main' => [ - 'http_basic_ldap' => [ - 'service' => Ldap::class, - 'dn_string' => 'uid={username},dc=example,dc=com', - ], - 'stateless' => true, - ], - ], - ]; + return static function (SecurityConfig $security) { + $security->firewall('main') + ->stateless(true) + ->formLoginLdap() + ->service(Ldap::class) + ->dnString('uid={username},dc=example,dc=com') + ; + }; Configuration example for form login and query_string ..................................................... @@ -493,7 +491,7 @@ Configuration example for form login and query_string .. code-block:: xml - + loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - // ... - 'form_login_ldap' => [ - 'service' => Ldap::class, - 'dn_string' => 'dc=example,dc=com', - 'query_string' => '(&(uid={username})(memberOf=cn=users,ou=Services,dc=example,dc=com))', - 'search_dn' => '...', - 'search_password' => 'the-raw-password', - ], - ], - ] - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->stateless(true) + ->formLoginLdap() + ->service(Ldap::class) + ->dnString('dc=example,dc=com') + ->queryString('(&(uid={username})(memberOf=cn=users,ou=Services,dc=example,dc=com))') + ->searchDn('...') + ->searchPassword('the-raw-password') + ; + }; .. _`LDAP PHP extension`: https://www.php.net/manual/en/intro.ldap.php .. _`RFC4515`: http://www.faqs.org/rfcs/rfc4515.html .. _`LDAP injection`: http://projects.webappsec.org/w/page/13246947/LDAP%20Injection + diff --git a/security/login_link.rst b/security/login_link.rst index b92dd694178..86406f9b316 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -14,10 +14,12 @@ This authentication method can help you eliminate most of the customer support related to authentication (e.g. I forgot my password, how can I change or reset my password, etc.) -Login links are supported by Symfony when using the experimental -authenticator system. You must -:ref:`enable the authenticator system ` -in your configuration to use this feature. +.. note:: + + Login links are only supported by Symfony when using the + :doc:`authenticator system `. Before using this + authenticator, make sure you have enabled it with + ``enable_authenticator_manager: true`` in your ``security.yaml`` file. Using the Login Link Authenticator ---------------------------------- @@ -67,15 +69,14 @@ under the firewall. You must configure a ``check_route`` and .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'login_link' => [ - 'check_route' => 'login_check', - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->loginLink() + ->checkRoute('login_check') + ; + }; The ``signature_properties`` are used to create a signed URL. This must contain at least one property of your ``User`` object that uniquely @@ -107,6 +108,23 @@ intercept requests to this route: throw new \LogicException('This code should never be reached'); } } + + .. code-block:: php-attributes + + // src/Controller/SecurityController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Routing\Annotation\Route; + + class SecurityController extends AbstractController + { + #[Route('/login_check', name: 'login_check')] + public function check() + { + throw new \LogicException('This code should never be reached'); + } + } .. code-block:: yaml @@ -373,17 +391,16 @@ seconds). You can customize this using the ``lifetime`` option: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'login_link' => [ - 'check_route' => 'login_check', - // lifetime in seconds - 'lifetime' => 300, - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->loginLink() + ->checkRoute('login_check') + // lifetime in seconds + ->lifetime(300) + ; + }; .. _security-login-link-signature: @@ -401,7 +418,7 @@ The signed URL contains 3 parameters: The UNIX timestamp when the link expires. ``user`` - The value returned from ``$user->getUsername()`` for this user. + The value returned from ``$user->getUserIdentifier()`` for this user. ``hash`` A hash of ``expires``, ``user`` and any configured signature @@ -448,16 +465,15 @@ You can add more properties to the ``hash`` by using the .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'login_link' => [ - 'check_route' => 'login_check', - 'signature_properties' => ['id', 'email'], - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->loginLink() + ->checkRoute('login_check') + ->signatureProperties(['id', 'email']) + ; + }; The properties are fetched from the user object using the :doc:`PropertyAccess component ` (e.g. using @@ -521,20 +537,20 @@ cache. Enable this support by setting the ``max_uses`` option: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'login_link' => [ - 'check_route' => 'login_check', - // only allow the link to be used 3 times - 'max_uses' => 3, - - // optionally, configure the cache pool - //'used_link_cache' => 'cache.redis', - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->loginLink() + ->checkRoute('login_check') + + // only allow the link to be used 3 times + ->maxUses(3) + + // optionally, configure the cache pool + //->usedLinkCache('cache.redis') + ; + }; Make sure there is enough space left in the cache, otherwise invalid links can no longer be stored (and thus become valid again). Expired invalid @@ -594,17 +610,16 @@ the authenticator only handle HTTP POST methods: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'firewalls' => [ - 'main' => [ - 'login_link' => [ - 'check_route' => 'login_check', - 'check_post_only' => true, - 'max_uses' => 1, - ], - ], - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->loginLink() + ->checkRoute('login_check') + ->checkPostOnly(true) + ->maxUses(1) + ; + }; Then, use the ``check_route`` controller to render a page that lets the user create this POST request (e.g. by clicking a button):: @@ -654,3 +669,138 @@ user create this POST request (e.g. by clicking a button):: {% endblock %} + +Customizing the Success Handler +------------------------------- + +Sometimes, the default success handling does not fit your use-case (e.g. +when you need to generate and return an API key). To customize how the +success handler behaves, create your own handler as a class that implements +:class:`Symfony\\Component\\Security\\Http\\Authentication\\AuthenticationSuccessHandlerInterface`:: + + // src/Security/Authentication/AuthenticationSuccessHandler.php + namespace App\Security\Authentication; + + use Symfony\Component\HttpFoundation\JsonResponse; + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; + + class AuthenticationSuccessHandler implements AuthenticationSuccessHandlerInterface + { + public function onAuthenticationSuccess(Request $request, TokenInterface $token): JsonResponse + { + $user = $token->getUser(); + $userApiToken = $user->getApiToken(); + + return new JsonResponse(['apiToken' => 'userApiToken']); + } + } + +Then, configure this service ID as the ``success_handler``: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + firewalls: + main: + login_link: + check_route: login_check + lifetime: 600 + max_uses: 1 + success_handler: App\Security\Authentication\AuthenticationSuccessHandler + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use App\Security\Authentication\AuthenticationSuccessHandler; + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->firewall('main') + ->loginLink() + ->checkRoute('login_check') + ->lifetime(600) + ->maxUses(1) + ->successHandler(AuthenticationSuccessHandler::class) + ; + }; + +.. tip:: + + If you want to customize the default failure handling, use the + ``failure_handler`` option and create a class that implements + :class:`Symfony\\Component\\Security\\Http\\Authentication\\AuthenticationFailureHandlerInterface`. + +Customizing the Login Link +-------------------------- + +.. versionadded:: 5.3 + + The possibility to customize the login link was introduced in Symfony 5.3. + +The ``createLoginLink()`` method accepts a second optional argument to pass the +``Request`` object used when generating the login link. This allows to customize +features such as the locale used to generate the link:: + + // src/Controller/SecurityController.php + namespace App\Controller; + + // ... + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\Security\Http\LoginLink\LoginLinkHandlerInterface; + + class SecurityController extends AbstractController + { + /** + * @Route("/login", name="login") + */ + public function requestLoginLink(LoginLinkHandlerInterface $loginLinkHandler, Request $request) + { + // check if login form is submitted + if ($request->isMethod('POST')) { + // ... load the user in some way + + // clone and customize Request + $userRequest = clone $request; + $userRequest->setLocale($user->getLocale() ?? $request->getDefaultLocale()); + + // create a login link for $user (this returns an instance of LoginLinkDetails) + $loginLinkDetails = $loginLinkHandler->createLoginLink($user, $userRequest); + $loginLink = $loginLinkDetails->getUrl(); + + // ... + } + + return $this->render('security/login.html.twig'); + } + + // ... + } diff --git a/security/multiple_guard_authenticators.rst b/security/multiple_guard_authenticators.rst deleted file mode 100644 index b6ea9ca5f11..00000000000 --- a/security/multiple_guard_authenticators.rst +++ /dev/null @@ -1,181 +0,0 @@ -How to Use Multiple Guard Authenticators -======================================== - -The Guard authentication component allows you to use many different -authenticators at a time. - -An entry point is a service id (of one of your authenticators) whose -``start()`` method is called to start the authentication process. - -Multiple Authenticators with Shared Entry Point ------------------------------------------------ - -Sometimes you want to offer your users different authentication mechanisms like -a form login and a Facebook login while both entry points redirect the user to -the same login page. -However, in your configuration you have to explicitly say which entry point -you want to use. - -This is how your security configuration can look in action: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - firewalls: - default: - anonymous: true - lazy: true - guard: - authenticators: - - App\Security\LoginFormAuthenticator - - App\Security\FacebookConnectAuthenticator - entry_point: App\Security\LoginFormAuthenticator - - .. code-block:: xml - - - - - - - - - - App\Security\LoginFormAuthenticator - App\Security\FacebookConnectAuthenticator - - - - - - .. code-block:: php - - // config/packages/security.php - use App\Security\FacebookConnectAuthenticator; - use App\Security\LoginFormAuthenticator; - - $container->loadFromExtension('security', [ - // ... - 'firewalls' => [ - 'default' => [ - 'anonymous' => true, - 'lazy' => true, - 'guard' => [ - 'entry_point' => LoginFormAuthenticator::class, - 'authenticators' => [ - LoginFormAuthenticator::class, - FacebookConnectAuthenticator::class, - ], - ], - ], - ], - ]); - -There is one limitation with this approach - you have to use exactly one entry point. - -Multiple Authenticators with Separate Entry Points --------------------------------------------------- - -However, there are use cases where you have authenticators that protect different -parts of your application. For example, you have a login form that protects -the secured area of your application front-end and API end points that are -protected with API tokens. As you can only configure one entry point per firewall, -the solution is to split the configuration into two separate firewalls: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - firewalls: - api: - pattern: ^/api/ - guard: - authenticators: - - App\Security\ApiTokenAuthenticator - default: - anonymous: true - lazy: true - guard: - authenticators: - - App\Security\LoginFormAuthenticator - access_control: - - { path: '^/login', roles: IS_AUTHENTICATED_ANONYMOUSLY } - - { path: '^/api', roles: ROLE_API_USER } - - { path: '^/', roles: ROLE_USER } - - .. code-block:: xml - - - - - - - - - - App\Security\ApiTokenAuthenticator - - - - - App\Security\LoginFormAuthenticator - - - - - - - - - .. code-block:: php - - // config/packages/security.php - use App\Security\ApiTokenAuthenticator; - use App\Security\LoginFormAuthenticator; - - $container->loadFromExtension('security', [ - // ... - 'firewalls' => [ - 'api' => [ - 'pattern' => '^/api', - 'guard' => [ - 'authenticators' => [ - ApiTokenAuthenticator::class, - ], - ], - ], - 'default' => [ - 'anonymous' => true, - 'lazy' => true, - 'guard' => [ - 'authenticators' => [ - LoginFormAuthenticator::class, - ], - ], - ], - ], - 'access_control' => [ - ['path' => '^/login', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'], - ['path' => '^/api', 'roles' => 'ROLE_API_USER'], - ['path' => '^/', 'roles' => 'ROLE_USER'], - ], - ]); diff --git a/security/named_encoders.rst b/security/named_encoders.rst deleted file mode 100644 index 29ca8c278d7..00000000000 --- a/security/named_encoders.rst +++ /dev/null @@ -1,195 +0,0 @@ -.. index:: - single: Security; Named Encoders - -How to Use A Different Password Encoder Algorithm Per User -========================================================== - -Usually, the same password encoder is used for all users by configuring it -to apply to all instances of a specific class: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - encoders: - App\Entity\User: - algorithm: auto - cost: 12 - - .. code-block:: xml - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - use App\Entity\User; - - $container->loadFromExtension('security', [ - // ... - 'encoders' => [ - User::class => [ - 'algorithm' => 'auto', - 'cost' => 12, - ], - ], - ]); - -Another option is to use a "named" encoder and then select which encoder -you want to use dynamically. - -In the previous example, you've set the ``auto`` algorithm for ``App\Entity\User``. -This may be secure enough for a regular user, but what if you want your admins -to have a stronger algorithm, for example ``auto`` with a higher cost. This can -be done with named encoders: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - encoders: - harsh: - algorithm: auto - cost: 15 - - .. code-block:: xml - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - $container->loadFromExtension('security', [ - // ... - 'encoders' => [ - 'harsh' => [ - 'algorithm' => 'auto', - 'cost' => '15', - ], - ], - ]); - -.. note:: - - If you are running PHP 7.2+ or have the `libsodium`_ extension installed, - then the recommended hashing algorithm to use is - :ref:`Sodium `. - -This creates an encoder named ``harsh``. In order for a ``User`` instance -to use it, the class must implement -:class:`Symfony\\Component\\Security\\Core\\Encoder\\EncoderAwareInterface`. -The interface requires one method - ``getEncoderName()`` - which should return -the name of the encoder to use:: - - // src/Entity/User.php - namespace App\Entity; - - use Symfony\Component\Security\Core\Encoder\EncoderAwareInterface; - use Symfony\Component\Security\Core\User\UserInterface; - - class User implements UserInterface, EncoderAwareInterface - { - public function getEncoderName() - { - if ($this->isAdmin()) { - return 'harsh'; - } - - return null; // use the default encoder - } - } - -If you created your own password encoder implementing the -:class:`Symfony\\Component\\Security\\Core\\Encoder\\PasswordEncoderInterface`, -you must register a service for it in order to use it as a named encoder: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - encoders: - app_encoder: - id: 'App\Security\Encoder\MyCustomPasswordEncoder' - - .. code-block:: xml - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - // ... - use App\Security\Encoder\MyCustomPasswordEncoder; - - $container->loadFromExtension('security', [ - // ... - 'encoders' => [ - 'app_encoder' => [ - 'id' => MyCustomPasswordEncoder::class, - ], - ], - ]); - -This creates an encoder named ``app_encoder`` from a service with the ID -``App\Security\Encoder\MyCustomPasswordEncoder``. - -.. _`libsodium`: https://pecl.php.net/package/libsodium diff --git a/security/password_migration.rst b/security/password_migration.rst deleted file mode 100644 index 2bdd6c83b95..00000000000 --- a/security/password_migration.rst +++ /dev/null @@ -1,248 +0,0 @@ -.. index:: - single: Security; How to Migrate a Password Hash - -How to Migrate a Password Hash -============================== - -In order to protect passwords, it is recommended to store them using the latest -hash algorithms. This means that if a better hash algorithm is supported on your -system, the user's password should be *rehashed* using the newer algorithm and -stored. That's possible with the ``migrate_from`` option: - -#. `Configure a new Encoder Using "migrate_from"`_ -#. `Upgrade the Password`_ -#. Optionally, `Trigger Password Migration From a Custom Encoder`_ - -Configure a new Encoder Using "migrate_from" ----------------------------------------------- - -When a better hashing algorithm becomes available, you should keep the existing -encoder(s), rename it, and then define the new one. Set the ``migrate_from`` option -on the new encoder to point to the old, legacy encoder(s): - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - encoders: - # an encoder used in the past for some users - legacy: - algorithm: sha256 - encode_as_base64: false - iterations: 1 - - App\Entity\User: - # the new encoder, along with its options - algorithm: sodium - migrate_from: - - bcrypt # uses the "bcrypt" encoder with the default options - - legacy # uses the "legacy" encoder configured above - - .. code-block:: xml - - - - - - - - - - - - - - bcrypt - - - legacy - - - - - .. code-block:: php - - // config/packages/security.php - $container->loadFromExtension('security', [ - // ... - - 'encoders' => [ - 'legacy' => [ - 'algorithm' => 'sha256', - 'encode_as_base64' => false, - 'iterations' => 1, - ], - - 'App\Entity\User' => [ - // the new encoder, along with its options - 'algorithm' => 'sodium', - 'migrate_from' => [ - 'bcrypt', // uses the "bcrypt" encoder with the default options - 'legacy', // uses the "legacy" encoder configured above - ], - ], - ], - ]); - -With this setup: - -* New users will be encoded with the new algorithm; -* Whenever a user logs in whose password is still stored using the old algorithm, - Symfony will verify the password with the old algorithm and then rehash - and update the password using the new algorithm. - -.. tip:: - - The *auto*, *native*, *bcrypt* and *argon* encoders automatically enable - password migration using the following list of ``migrate_from`` algorithms: - - #. :ref:`PBKDF2 ` (which uses :phpfunction:`hash_pbkdf2`); - #. Message digest (which uses :phpfunction:`hash`) - - Both use the ``hash_algorithm`` setting as the algorithm. It is recommended to - use ``migrate_from`` instead of ``hash_algorithm``, unless the *auto* - encoder is used. - -Upgrade the Password --------------------- - -Upon successful login, the Security system checks whether a better algorithm -is available to hash the user's password. If it is, it'll hash the correct -password using the new hash. If you use a Guard authenticator, you first need to -:ref:`provide the original password to the Security system `. - -You can enable the upgrade behavior by implementing how this newly hashed -password should be stored: - -* :ref:`When using Doctrine's entity user provider ` -* :ref:`When using a custom user provider ` - -After this, you're done and passwords are always hashed as secure as possible! - -.. _provide-the-password-guard: - -Provide the Password when using Guard -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -When you're using a custom :doc:`guard authenticator `, -you need to implement :class:`Symfony\\Component\\Security\\Guard\\PasswordAuthenticatedInterface`. -This interface defines a ``getPassword()`` method that returns the password -for this login request. This password is used in the migration process:: - - // src/Security/CustomAuthenticator.php - namespace App\Security; - - use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface; - // ... - - class CustomAuthenticator extends AbstractGuardAuthenticator implements PasswordAuthenticatedInterface - { - // ... - - public function getPassword($credentials): ?string - { - return $credentials['password']; - } - } - -.. _upgrade-the-password-doctrine: - -Upgrade the Password when using Doctrine -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -When using the :ref:`entity user provider `, implement -:class:`Symfony\\Component\\Security\\Core\\User\\PasswordUpgraderInterface` in -the ``UserRepository`` (see `the Doctrine docs for information`_ on how to -create this class if it's not already created). This interface implements -storing the newly created password hash:: - - // src/Repository/UserRepository.php - namespace App\Repository; - - // ... - use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; - - class UserRepository extends EntityRepository implements PasswordUpgraderInterface - { - // ... - - public function upgradePassword(UserInterface $user, string $newEncodedPassword): void - { - // set the new encoded password on the User object - $user->setPassword($newEncodedPassword); - - // execute the queries on the database - $this->getEntityManager()->flush(); - } - } - -.. _upgrade-the-password-custom-provider: - -Upgrade the Password when using a Custom User Provider -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you're using a :ref:`custom user provider `, implement the -:class:`Symfony\\Component\\Security\\Core\\User\\PasswordUpgraderInterface` in -the user provider:: - - // src/Security/UserProvider.php - namespace App\Security; - - // ... - use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; - - class UserProvider implements UserProviderInterface, PasswordUpgraderInterface - { - // ... - - public function upgradePassword(UserInterface $user, string $newEncodedPassword): void - { - // set the new encoded password on the User object - $user->setPassword($newEncodedPassword); - - // ... store the new password - } - } - -Trigger Password Migration From a Custom Encoder ------------------------------------------------- - -If you're using a custom password encoder, you can trigger the password -migration by returning ``true`` in the ``needsRehash()`` method:: - - // src/Security/CustomPasswordEncoder.php - namespace App\Security; - - // ... - use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface; - - class CustomPasswordEncoder implements PasswordEncoderInterface - { - // ... - - public function needsRehash(string $encoded): bool - { - // check whether the current password is hash using an outdated encoder - $hashIsOutdated = ...; - - return $hashIsOutdated; - } - } - -.. _`the Doctrine docs for information`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/working-with-objects.html#custom-repositories diff --git a/security/passwords.rst b/security/passwords.rst new file mode 100644 index 00000000000..521be799277 --- /dev/null +++ b/security/passwords.rst @@ -0,0 +1,782 @@ +Password Hashing and Verification +================================= + +Most applications use passwords to login users. These passwords should be +hashed to securely store them. Symfony's PasswordHasher component provides +all utilities to safely hash and verify passwords. + +Make sure it is installed by running: + +.. code-block:: terminal + + $ composer require symfony/password-hasher + +.. versionadded:: 5.3 + + The PasswordHasher component was introduced in 5.3. Prior to this + version, password hashing functionality was provided by the Security + component. + +Configuring a Password Hasher +----------------------------- + +Before hashing passwords, you must configure a hasher using the +``password_hashers`` option. You must configure the *hashing algorithm* and +optionally some *algorithm options*: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + + password_hashers: + # auto hasher with default options for the User class (and children) + App\Entity\User: 'auto' + + # auto hasher with custom options for all PasswordAuthenticatedUserInterface instances + Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: + algorithm: 'auto' + cost: 15 + + .. code-block:: xml + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use App\Entity\User; + use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... + + // auto hasher with default options for the User class (and children) + $security->passwordHasher(User::class) + ->algorithm('auto'); + + // auto hasher with custom options for all PasswordAuthenticatedUserInterface instances + $security->passwordHasher(PasswordAuthenticatedUserInterface::class) + ->algorithm('auto') + ->cost(15); + }; + + .. code-block:: php-standalone + + use App\Entity\User; + use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactory; + use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; + + $passwordHasherFactory = new PasswordHasherFactory([ + // auto hasher with default options for the User class (and children) + User::class => ['algorithm' => 'auto'], + + // auto hasher with custom options for all PasswordAuthenticatedUserInterface instances + User::class => [ + 'algorithm' => 'auto', + 'cost' => 15, + ], + ]); + +.. versionadded:: 5.3 + + The ``password_hashers`` option was introduced in Symfony 5.3. In previous + versions it was called ``encoders``. + +In this example, the "auto" algorithm is used. This hasher automatically +selects the most secure algorithm available on your system. Combined with +:ref:`password migration `, this allows you to +always secure passwords in the safest way possible (even when new +algorithms are introduced in future PHP releases). + +Further in this article, you can find a +:ref:`full reference of all supported algorithms `. + +.. tip:: + + Hashing passwords is resource intensive and takes time in order to + generate secure password hashes. In general, this makes your password + hashing more secure. + + In tests however, secure hashes are not important, so you can change + the password hasher configuration in ``test`` environment to run tests + faster: + + .. configuration-block:: + + .. code-block:: yaml + + # config/packages/test/security.yaml + password_hashers: + # Use your user class name here + App\Entity\User: + algorithm: plaintext # disable hashing (only do this in tests!) + + # or use the lowest possible values + App\Entity\User: + algorithm: auto # This should be the same value as in config/packages/security.yaml + cost: 4 # Lowest possible value for bcrypt + time_cost: 3 # Lowest possible value for argon + memory_cost: 10 # Lowest possible value for argon + + .. code-block:: xml + + + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/test/security.php + use App\Entity\User; + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... + + // Use your user class name here + $security->passwordHasher(User::class) + ->algorithm('plaintext'); // disable hashing (only do this in tests!) + + // or use the lowest possible values + $security->passwordHasher(User::class) + ->algorithm('auto') // This should be the same value as in config/packages/security.yaml + ->cost(4) // Lowest possible value for bcrypt + ->timeCost(2) // Lowest possible value for argon + ->memoryCost(10) // Lowest possible value for argon + ; + }; + +Hashing the Password +-------------------- + +After configuring the correct algorithm, you can use the +``UserPasswordHasherInterface`` to hash and verify the passwords: + +.. configuration-block:: + + .. code-block:: php-symfony + + // src/Controller/RegistrationController.php + namespace App\Controller; + + // ... + use + Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; + use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; + + class UserController extends AbstractController + { + public function registration(UserPasswordHasherInterface $passwordHasher) + { + // ... e.g. get the user data from a registration form + $user = new User(...); + $plaintextPassword = ...; + + // hash the password (based on the security.yaml config for the $user class) + $hashedPassword = $passwordHasher->hashPassword( + $user, + $plaintextPassword + ); + $user->setPassword($hashedPassword); + + // ... + } + + public function delete(UserPasswordHasherInterface $passwordHasher, UserInterface $user) + { + // ... e.g. get the password from a "confirm deletion" dialog + $plaintextPassword = ...; + + if (!$passwordHasher->isPasswordValid($user, $plaintextPassword)) { + throw new AccessDeniedHttpException(); + } + } + } + + .. code-block:: php-standalone + + // ... + $passwordHasher = new UserPasswordHasher($passwordHasherFactory); + + // Get the user password (e.g. from a registration form) + $user = new User(...); + $plaintextPassword = ...; + + // hash the password (based on the password hasher factory config for the $user class) + $hashedPassword = $passwordHasher->hashPassword( + $user, + $plaintextPassword + ); + $user->setPassword($hashedPassword); + + // In another action (e.g. to confirm deletion), you can verify the password + $plaintextPassword = ...; + if (!$passwordHasher->isPasswordValid($user, $plaintextPassword)) { + throw new \Exception('Bad credentials, cannot delete this user.'); + } + +Reset Password +-------------- + +Using `MakerBundle`_ and `SymfonyCastsResetPasswordBundle`_, you can create +a secure out of the box solution to handle forgotten passwords. First, +install the SymfonyCastsResetPasswordBundle: + +.. code-block:: terminal + + $ composer require symfonycasts/reset-password-bundle + +Then, use the ``make:reset-password`` command. This asks you a few +questions about your app and generates all the files you need! After, +you'll see a success message and a list of any other steps you need to do. + +.. code-block:: terminal + + $ php bin/console make:reset-password + +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. + +.. _security-password-migration: + +Password Migration +------------------ + +In order to protect passwords, it is recommended to store them using the latest +hash algorithms. This means that if a better hash algorithm is supported on your +system, the user's password should be *rehashed* using the newer algorithm and +stored. That's possible with the ``migrate_from`` option: + +#. `Configure a new Hasher Using "migrate_from"`_ +#. `Upgrade the Password`_ +#. Optionally, `Trigger Password Migration From a Custom Hasher`_ + +Configure a new Hasher Using "migrate_from" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When a better hashing algorithm becomes available, you should keep the existing +hasher(s), rename it, and then define the new one. Set the ``migrate_from`` option +on the new hasher to point to the old, legacy hasher(s): + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + + password_hashers: + # a hasher used in the past for some users + legacy: + algorithm: sha256 + encode_as_base64: false + iterations: 1 + + App\Entity\User: + # the new hasher, along with its options + algorithm: sodium + migrate_from: + - 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 + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... + $security->passwordHasher('legacy') + ->algorithm('sha256') + ->encodeAsBase64(true) + ->iterations(1) + ; + + $security->passwordHasher('App\Entity\User') + // the new hasher, along with its options + ->algorithm('sodium') + ->migrateFrom([ + 'bcrypt', // uses the "bcrypt" hasher with the default options + 'legacy', // uses the "legacy" hasher configured above + ]) + ; + }; + + .. code-block:: php-standalone + + // ... + $passwordHasherFactory = new PasswordHasherFactory([ + 'legacy' => [ + 'algorithm' => 'sha256', + 'encode_as_base64' => true, + 'iterations' => 1, + ], + + User::class => [ + // the new hasher, along with its options + 'algorithm' => 'sodium', + 'migrate_from' => [ + 'bcrypt', // uses the "bcrypt" hasher with the default options + 'legacy', // uses the "legacy" hasher configured above + ], + ], + ]); + +With this setup: + +* New users will be hashed with the new algorithm; +* Whenever a user logs in whose password is still stored using the old algorithm, + Symfony will verify the password with the old algorithm and then rehash + and update the password using the new algorithm. + +.. tip:: + + The *auto*, *native*, *bcrypt* and *argon* hashers automatically enable + password migration using the following list of ``migrate_from`` algorithms: + + #. :ref:`PBKDF2 ` (which uses :phpfunction:`hash_pbkdf2`); + #. Message digest (which uses :phpfunction:`hash`) + + Both use the ``hash_algorithm`` setting as the algorithm. It is recommended to + use ``migrate_from`` instead of ``hash_algorithm``, unless the *auto* + hasher is used. + +Upgrade the Password +~~~~~~~~~~~~~~~~~~~~ + +Upon successful login, the Security system checks whether a better algorithm +is available to hash the user's password. If it is, it'll hash the correct +password using the new hash. When using a custom authenticator, you must +use the ``PasswordCredentials`` in the :ref:`security passport `. + +You can enable the upgrade behavior by implementing how this newly hashed +password should be stored: + +* :ref:`When using Doctrine's entity user provider ` +* :ref:`When using a custom user provider ` + +After this, you're done and passwords are always hashed as secure as possible! + +.. note:: + + When using the PasswordHasher component outside a Symfony application, + you must manually use the ``PasswordHasherInterface::needsRehash()`` + method to check if a rehash is needed and ``PasswordHasherInterface::hash()`` + method to rehash the plaintext password using the new algorithm. + +.. _upgrade-the-password-doctrine: + +Upgrade the Password when using Doctrine +........................................ + +When using the :ref:`entity user provider `, implement +:class:`Symfony\\Component\\Security\\Core\\User\\PasswordUpgraderInterface` in +the ``UserRepository`` (see `the Doctrine docs for information`_ on how to +create this class if it's not already created). This interface implements +storing the newly created password hash:: + + // src/Repository/UserRepository.php + namespace App\Repository; + + // ... + use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; + + class UserRepository extends EntityRepository implements PasswordUpgraderInterface + { + // ... + + public function upgradePassword(UserInterface $user, string $newHashedPassword): void + { + // set the new hashed password on the User object + $user->setPassword($newHashedPassword); + + // execute the queries on the database + $this->getEntityManager()->flush(); + } + } + +.. _upgrade-the-password-custom-provider: + +Upgrade the Password when using a Custom User Provider +...................................................... + +If you're using a :ref:`custom user provider `, implement the +:class:`Symfony\\Component\\Security\\Core\\User\\PasswordUpgraderInterface` in +the user provider:: + + // src/Security/UserProvider.php + namespace App\Security; + + // ... + use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; + + class UserProvider implements UserProviderInterface, PasswordUpgraderInterface + { + // ... + + public function upgradePassword(UserInterface $user, string $newHashedPassword): void + { + // set the new hashed password on the User object + $user->setPassword($newHashedPassword); + + // ... store the new password + } + } + +Trigger Password Migration From a Custom Hasher +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you're using a custom password hasher, you can trigger the password +migration by returning ``true`` in the ``needsRehash()`` method:: + + // src/Security/CustomPasswordHasher.php + namespace App\Security; + + // ... + use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; + + class CustomPasswordHasher implements UserPasswordHasherInterface + { + // ... + + public function needsRehash(string $hashed): bool + { + // check whether the current password is hashed using an outdated hasher + $hashIsOutdated = ...; + + return $hashIsOutdated; + } + } + +Named Password Hashers +---------------------- + +Usually, the same password hasher is used for all users by configuring it +to apply to all instances of a specific class. Another option is to use a +"named" hasher and then select which hasher you want to use dynamically. + +By default (as shown at the start of the article), the ``auto`` algorithm +is used for ``App\Entity\User``. + +This may be secure enough for a regular user, but what if you want your +admins to have a stronger algorithm, for example ``auto`` with a higher +cost. This can be done with named hashers: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + password_hashers: + harsh: + algorithm: auto + cost: 15 + + .. code-block:: xml + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... + $security->passwordHasher('harsh') + ->algorithm('auto') + ->cost(15) + ; + }; + + .. code-block:: php-standalone + + use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactory; + + $passwordHasherFactory = new PasswordHasherFactory([ + // ... + 'harsh' => [ + 'algorithm' => 'auto', + 'cost' => 15 + ], + ]); + +This creates a hasher named ``harsh``. In order for a ``User`` instance +to use it, the class must implement +:class:`Symfony\\Component\\PasswordHasher\\Hasher\\PasswordHasherAwareInterface`. +The interface requires one method - ``getPasswordHasherName()`` - which should return +the name of the hasher to use:: + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\PasswordHasher\Hasher\PasswordHasherAwareInterface; + use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; + use Symfony\Component\Security\Core\User\UserInterface; + + class User implements + UserInterface, + PasswordAuthenticatedUserInterface, + PasswordHasherAwareInterface + { + // ... + + public function getPasswordHasherName(): ?string + { + if ($this->isAdmin()) { + return 'harsh'; + } + + return null; // use the default hasher + } + } + +If you created your own password hasher implementing the +:class:`Symfony\\Component\\PasswordHasher\\PasswordHasherInterface`, +you must register a service for it in order to use it as a named hasher: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + password_hashers: + app_hasher: + id: 'App\Security\Hasher\MyCustomPasswordHasher' + + .. code-block:: xml + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use App\Security\Hasher\MyCustomPasswordHasher; + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... + $security->passwordHasher('app_hasher') + ->id(MyCustomPasswordHasher::class) + ; + }; + +This creates a hasher named ``app_hasher`` from a service with the ID +``App\Security\Hasher\MyCustomPasswordHasher``. + +.. _passwordhasher-supported-algorithms: + +Supported Algorithms +-------------------- + +* :ref:`auto ` +* :ref:`bcrypt ` +* :ref:`sodium ` +* :ref:`PBKDF2 ` + +.. TODO missing: + * :ref:`Message Digest ` + * :ref:`Native ` + * :ref:`Plaintext ` + +.. _reference-security-encoder-auto: + +The "auto" Hasher +~~~~~~~~~~~~~~~~~~ + +It automatically selects the best available hasher. Starting from Symfony 5.3, +it uses the Bcrypt hasher. If PHP or Symfony adds new password hashers in the +future, it might select a different hasher. + +Because of this, the length of the hashed passwords may change in the future, so +make sure to allocate enough space for them to be persisted (``varchar(255)`` +should be a good setting). + +.. _reference-security-encoder-bcrypt: + +The Bcrypt Password Hasher +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It produces hashed passwords with the `bcrypt password hashing function`_. +Hashed passwords are ``60`` characters long, so make sure to +allocate enough space for them to be persisted. Also, passwords include the +`cryptographic salt`_ inside them (it's generated automatically for each new +password) so you don't have to deal with it. + +Its only configuration option is ``cost``, which is an integer in the range of +``4-31`` (by default, ``13``). Each single increment of the cost **doubles the +time** it takes to hash a password. It's designed this way so the password +strength can be adapted to the future improvements in computation power. + +You can change the cost at any time — even if you already have some passwords +hashed using a different cost. New passwords will be hashed using the new +cost, while the already hashed ones will be validated using a cost that was +used back when they were hashed. + +.. tip:: + + A simple technique to make tests much faster when using BCrypt is to set + the cost to ``4``, which is the minimum value allowed, in the ``test`` + environment configuration. + +.. _reference-security-sodium: + +The Sodium Password Hasher +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It uses the `Argon2 key derivation function`_. Argon2 support was introduced +in PHP 7.2 by bundeling the `libsodium`_ extension. + +The hashed passwords are ``96`` characters long, but due to the hashing +requirements saved in the resulting hash this may change in the future, so make +sure to allocate enough space for them to be persisted. Also, passwords include +the `cryptographic salt`_ inside them (it's generated automatically for each new +password) so you don't have to deal with it. + +.. _reference-security-pbkdf2: + +The PBKDF2 Hasher +~~~~~~~~~~~~~~~~~ + +Using the `PBKDF2`_ hasher is no longer recommended since PHP added support for +Sodium and BCrypt. Legacy application still using it are encouraged to upgrade +to those newer hashing algorithms. + +.. _`MakerBundle`: https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html +.. _`PBKDF2`: https://en.wikipedia.org/wiki/PBKDF2 +.. _`libsodium`: https://pecl.php.net/package/libsodium +.. _`Argon2 key derivation function`: https://en.wikipedia.org/wiki/Argon2 +.. _`bcrypt password hashing function`: https://en.wikipedia.org/wiki/Bcrypt +.. _`cryptographic salt`: https://en.wikipedia.org/wiki/Salt_(cryptography) +.. _`the Doctrine docs for information`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/working-with-objects.html#custom-repositories +.. _`SymfonyCastsResetPasswordBundle`: https://github.com/symfonycasts/reset-password-bundle diff --git a/security/remember_me.rst b/security/remember_me.rst index de9f51afddf..b14b012202f 100644 --- a/security/remember_me.rst +++ b/security/remember_me.rst @@ -63,24 +63,23 @@ the session lasts using a cookie with the ``remember_me`` firewall option: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - // ... + use Symfony\Config\SecurityConfig; - 'firewalls' => [ - 'main' => [ - // ... - 'remember_me' => [ - 'secret' => '%kernel.secret%', - 'lifetime' => 604800, // 1 week in seconds - 'path' => '/', - // by default, the feature is enabled by checking a - // checkbox in the login form (see below), uncomment - // the following line to always enable it. - //'always_remember_me' => true, - ], - ], - ], - ]); + return static function (SecurityConfig $security) { + // ... + $security->firewall('main') + // ... + ->rememberMe() + ->secret('%kernel.secret%') + ->lifetime(604800) // 1 week in seconds + ->path('/') + + // by default, the feature is enabled by checking a + // checkbox in the login form (see below), uncomment + // the following line to always enable it. + // ->alwaysRememberMe(true) + ; + }; The ``remember_me`` firewall defines the following configuration options: @@ -184,7 +183,7 @@ users to change their password. You can do this by leveraging a few special // src/Controller/AccountController.php // ... - public function accountInfo() + public function accountInfo(): Response { // allow any authenticated user - we don't care if they just // logged in, or are logged in via a remember me cookie @@ -193,7 +192,7 @@ users to change their password. You can do this by leveraging a few special // ... } - public function resetPassword() + public function resetPassword(): Response { // require the user to log in during *this* session // if they were only logged in via a remember me cookie, they @@ -283,19 +282,19 @@ so ``DoctrineTokenProvider`` can store the tokens: .. code-block:: xml - # config/packages/doctrine.xml + .. code-block:: php - # config/packages/doctrine.php - $container->loadFromExtension('doctrine', [ - 'dbal' => [ - 'schema_filter' => '~^(?!rememberme_token)~', - // ... - ], + // config/packages/doctrine.php + use Symfony\Config\DoctrineConfig; + + return static function (DoctrineConfig $doctrine) { + $dbalDefault = $doctrine->dbal()->connection('default'); // ... - ]); + $dbalDefault->schemaFilter('~^(?!rememberme_token)~'); + }; Finally, set the ``token_provider`` option of the ``remember_me`` config to the service you created before: @@ -344,16 +343,14 @@ service you created before: // config/packages/security.php use Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider; - $container->loadFromExtension('security', [ - // ... + use Symfony\Config\SecurityConfig; - 'firewalls' => [ - 'main' => [ + return static function (SecurityConfig $security) { + // ... + $security->firewall('main') + // ... + ->rememberMe() // ... - 'remember_me' => [ - // ... - 'token_provider' => DoctrineTokenProvider::class, - ], - ], - ], - ]); + ->tokenProvider(DoctrineTokenProvider::class) + ; + }; diff --git a/security/reset_password.rst b/security/reset_password.rst deleted file mode 100644 index bbde221f015..00000000000 --- a/security/reset_password.rst +++ /dev/null @@ -1,28 +0,0 @@ -How to Add a Reset Password Feature -=================================== - -Using `MakerBundle`_ & `SymfonyCastsResetPasswordBundle`_ you can create a -secure out of the box solution to handle forgotten passwords. - -First, make sure you have a security ``User`` class. Follow -the :doc:`Security Guide ` if you don't have one already. - -Generating the Reset Password Code ----------------------------------- - -.. code-block:: terminal - - $ composer require symfonycasts/reset-password-bundle - ..... - $ php bin/console make:reset-password - -The `make:reset-password` command will ask you a few questions about your app and -generate all the files you need! After, you'll see a success message and a list -of any other steps you need to do. - -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. - -.. _`MakerBundle`: https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html -.. _`SymfonyCastsResetPasswordBundle`: https://github.com/symfonycasts/reset-password-bundle diff --git a/security/securing_services.rst b/security/securing_services.rst deleted file mode 100644 index 67b37dd792e..00000000000 --- a/security/securing_services.rst +++ /dev/null @@ -1,53 +0,0 @@ -.. index:: - single: Security; Securing any service - single: Security; Securing any method - -How to Secure any Service or Method in your Application -======================================================= - -In the security article, you learned how to -:ref:`secure a controller ` via a shortcut method. - -But, you can check access *anywhere* in your code by injecting the ``Security`` -service. For example, suppose you have a ``SalesReportManager`` service and you -want to include extra details only for users that have a ``ROLE_SALES_ADMIN`` role: - -.. code-block:: diff - - // src/Newsletter/NewsletterManager.php - - // ... - use Symfony\Component\Security\Core\Exception\AccessDeniedException; - + use Symfony\Component\Security\Core\Security; - - class SalesReportManager - { - + private $security; - - + public function __construct(Security $security) - + { - + $this->security = $security; - + } - - public function sendNewsletter() - { - $salesData = []; - - + if ($this->security->isGranted('ROLE_SALES_ADMIN')) { - + $salesData['top_secret_numbers'] = rand(); - + } - - // ... - } - - // ... - } - -If you're using the :ref:`default services.yaml configuration `, -Symfony will automatically pass the ``security.helper`` to your service -thanks to autowiring and the ``Security`` type-hint. - -You can also use a lower-level -:class:`Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationCheckerInterface` -service. It does the same thing as ``Security``, but allows you to type-hint a -more-specific interface. diff --git a/security/user_checkers.rst b/security/user_checkers.rst index 9ded2a00449..a404a668932 100644 --- a/security/user_checkers.rst +++ b/security/user_checkers.rst @@ -23,7 +23,7 @@ displayed to the user:: namespace App\Security; - use App\Security\User as AppUser; + use App\Entity\User as AppUser; use Symfony\Component\Security\Core\Exception\AccountExpiredException; use Symfony\Component\Security\Core\Exception\CustomUserMessageAccountStatusException; use Symfony\Component\Security\Core\User\UserCheckerInterface; @@ -31,7 +31,7 @@ displayed to the user:: class UserChecker implements UserCheckerInterface { - public function checkPreAuth(UserInterface $user) + public function checkPreAuth(UserInterface $user): void { if (!$user instanceof AppUser) { return; @@ -43,7 +43,7 @@ displayed to the user:: } } - public function checkPostAuth(UserInterface $user) + public function checkPostAuth(UserInterface $user): void { if (!$user instanceof AppUser) { return; @@ -87,7 +87,7 @@ is the service id of your user checker: .. code-block:: xml - + loadFromExtension('security', [ + return static function (SecurityConfig $security) { // ... - 'firewalls' => [ - 'main' => [ - 'pattern' => '^/', - 'user_checker' => UserChecker::class, - // ... - ], - ], - ]); + $security->firewall('main') + ->pattern('^/') + ->userChecker(UserChecker::class) + // ... + ; + }; diff --git a/security/user_provider.rst b/security/user_provider.rst deleted file mode 100644 index 00e7c5a58d8..00000000000 --- a/security/user_provider.rst +++ /dev/null @@ -1,533 +0,0 @@ -Security User Providers -======================= - -User providers are PHP classes related to Symfony Security that have two jobs: - -**Reload the User from the Session** - At the beginning of each request (unless your firewall is ``stateless``), Symfony - loads the ``User`` object from the session. To make sure it's not out-of-date, - the user provider "refreshes it". The Doctrine user provider, for example, - queries the database for fresh data. Symfony then checks to see if the user - has "changed" and de-authenticates the user if they have (see :ref:`user_session_refresh`). - -**Load the User for some Feature** - Some features, like :doc:`user impersonation `, - :doc:`Remember Me ` and many of the built-in - :doc:`authentication providers `, use the user provider - to load a User object via its "username" (or email, or whatever field you want). - -Symfony comes with several built-in user providers: - -* :ref:`Entity User Provider ` (loads users from - a database); -* :ref:`LDAP User Provider ` (loads users from a - LDAP server); -* :ref:`Memory User Provider ` (loads users from - a configuration file); -* :ref:`Chain User Provider ` (merges two or more - user providers into a new user provider). - -The built-in user providers cover all the needs for most applications, but you -can also create your own :ref:`custom user provider `. - -.. _security-entity-user-provider: - -Entity User Provider --------------------- - -This is the most common user provider for traditional web applications. Users -are stored in a database and the user provider uses :doc:`Doctrine ` -to retrieve them: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - # ... - - providers: - users: - entity: - # the class of the entity that represents users - class: 'App\Entity\User' - # the property to query by - e.g. username, email, etc - property: 'username' - # optional: if you're using multiple Doctrine entity - # managers, this option defines which one to use - # manager_name: 'customer' - - # ... - - .. code-block:: xml - - - - - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - use App\Entity\User; - - $container->loadFromExtension('security', [ - 'providers' => [ - 'users' => [ - 'entity' => [ - // the class of the entity that represents users - 'class' => User::class, - // the property to query by - e.g. username, email, etc - 'property' => 'username', - // optional: if you're using multiple Doctrine entity - // managers, this option defines which one to use - // 'manager_name' => 'customer', - ], - ], - ], - - // ... - ]); - -The ``providers`` section creates a "user provider" called ``users`` that knows -how to query from your ``App\Entity\User`` entity by the ``username`` property. -You can choose any name for the user provider, but it's recommended to pick a -descriptive name because this will be later used in the firewall configuration. - -.. _authenticating-someone-with-a-custom-entity-provider: - -Using a Custom Query to Load the User -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The ``entity`` provider can only query from one *specific* field, specified by -the ``property`` config key. If you want a bit more control over this - e.g. you -want to find a user by ``email`` *or* ``username``, you can do that by making -your ``UserRepository`` implement the -:class:`Symfony\\Bridge\\Doctrine\\Security\\User\\UserLoaderInterface`. This -interface only requires one method: ``loadUserByUsername($username)``:: - - // src/Repository/UserRepository.php - namespace App\Repository; - - use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; - use Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface; - - class UserRepository extends ServiceEntityRepository implements UserLoaderInterface - { - // ... - - public function loadUserByUsername(string $usernameOrEmail) - { - $entityManager = $this->getEntityManager(); - - return $entityManager->createQuery( - 'SELECT u - FROM App\Entity\User u - WHERE u.username = :query - OR u.email = :query' - ) - ->setParameter('query', $usernameOrEmail) - ->getOneOrNullResult(); - } - } - -To finish this, remove the ``property`` key from the user provider in -``security.yaml``: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - - providers: - users: - entity: - class: App\Entity\User - - .. code-block:: xml - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - use App\Entity\User; - - $container->loadFromExtension('security', [ - // ... - - 'providers' => [ - 'users' => [ - 'entity' => [ - 'class' => User::class, - ], - ], - ], - ]); - -This tells Symfony to *not* query automatically for the User. Instead, when -needed (e.g. because :doc:`user impersonation `, -:doc:`Remember Me `, or some other security feature is -activated), the ``loadUserByUsername()`` method on ``UserRepository`` will be called. - -.. _security-memory-user-provider: - -Memory User Provider --------------------- - -It's not recommended to use this provider in real applications because of its -limitations and how difficult it is to manage users. It may be useful in application -prototypes and for limited applications that don't store users in databases. - -This user provider stores all user information in a configuration file, -including their passwords. That's why the first step is to configure how these -users will encode their passwords: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - encoders: - # this internal class is used by Symfony to represent in-memory users - Symfony\Component\Security\Core\User\User: 'auto' - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // config/packages/security.php - - // this internal class is used by Symfony to represent in-memory users - use Symfony\Component\Security\Core\User\User; - - $container->loadFromExtension('security', [ - // ... - 'encoders' => [ - User::class => [ - 'algorithm' => 'auto', - ], - ], - ]); - -Then, run this command to encode the plain text passwords of your users: - -.. code-block:: terminal - - $ php bin/console security:encode-password - -Now you can configure all the user information in ``config/packages/security.yaml``: - -.. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - providers: - backend_users: - memory: - users: - john_admin: { password: '$2y$13$jxGxc ... IuqDju', roles: ['ROLE_ADMIN'] } - jane_admin: { password: '$2y$13$PFi1I ... rGwXCZ', roles: ['ROLE_ADMIN', 'ROLE_SUPER_ADMIN'] } - -.. caution:: - - When using a ``memory`` provider, and not the ``auto`` algorithm, you have - to choose an encoding without salt (i.e. ``bcrypt``). - -.. _security-ldap-user-provider: - -LDAP User Provider ------------------- - -This user provider requires installing certain dependencies and using some -special authentication providers, so it's explained in a separate article: -:doc:`/security/ldap`. - -.. _security-chain-user-provider: - -Chain User Provider -------------------- - -This user provider combines two or more of the other provider types (``entity``, -``memory`` and ``ldap``) to create a new user provider. The order in which -providers are configured is important because Symfony will look for users -starting from the first provider and will keep looking for in the other -providers until the user is found: - -.. code-block:: yaml - - # config/packages/security.yaml - security: - # ... - providers: - backend_users: - memory: - # ... - - legacy_users: - entity: - # ... - - users: - entity: - # ... - - all_users: - chain: - providers: ['legacy_users', 'users', 'backend_users'] - -.. _custom-user-provider: - -Creating a Custom User Provider -------------------------------- - -Most applications don't need to create a custom provider. If you store users in -a database, a LDAP server or a configuration file, Symfony supports that. -However, if you're loading users from a custom location (e.g. via an API or -legacy database connection), you'll need to create a custom user provider. - -First, make sure you've followed the :doc:`Security Guide ` to create -your ``User`` class. - -If you used the ``make:user`` command to create your ``User`` class (and you -answered the questions indicating that you need a custom user provider), that -command will generate a nice skeleton to get you started:: - - // src/Security/UserProvider.php - namespace App\Security; - - use Symfony\Component\Security\Core\Exception\UnsupportedUserException; - use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; - use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; - use Symfony\Component\Security\Core\User\UserInterface; - use Symfony\Component\Security\Core\User\UserProviderInterface; - - class UserProvider implements UserProviderInterface, PasswordUpgraderInterface - { - /** - * Symfony calls this method if you use features like switch_user - * or remember_me. - * - * If you're not using these features, you do not need to implement - * this method. - * - * @return UserInterface - * - * @throws UsernameNotFoundException if the user is not found - */ - public function loadUserByUsername(string $username) - { - // Load a User object from your data source or throw UsernameNotFoundException. - // The $username argument may not actually be a username: - // it is whatever value is being returned by the getUsername() - // method in your User class. - throw new \Exception('TODO: fill in loadUserByUsername() inside '.__FILE__); - } - - /** - * Refreshes the user after being reloaded from the session. - * - * When a user is logged in, at the beginning of each request, the - * User object is loaded from the session and then this method is - * called. Your job is to make sure the user's data is still fresh by, - * for example, re-querying for fresh User data. - * - * If your firewall is "stateless: true" (for a pure API), this - * method is not called. - * - * @return UserInterface - */ - public function refreshUser(UserInterface $user) - { - if (!$user instanceof User) { - throw new UnsupportedUserException(sprintf('Invalid user class "%s".', get_class($user))); - } - - // Return a User object after making sure its data is "fresh". - // Or throw a UsernameNotFoundException if the user no longer exists. - throw new \Exception('TODO: fill in refreshUser() inside '.__FILE__); - } - - /** - * Tells Symfony to use this provider for this User class. - */ - public function supportsClass(string $class) - { - return User::class === $class || is_subclass_of($class, User::class); - } - - /** - * Upgrades the encoded password of a user, typically for using a better hash algorithm. - */ - public function upgradePassword(UserInterface $user, string $newEncodedPassword): void - { - // TODO: when encoded passwords are in use, this method should: - // 1. persist the new password in the user storage - // 2. update the $user object with $user->setPassword($newEncodedPassword); - } - } - -Most of the work is already done! Read the comments in the code and update the -TODO sections to finish the user provider. When you're done, tell Symfony about -the user provider by adding it in ``security.yaml``: - -.. code-block:: yaml - - # config/packages/security.yaml - security: - providers: - # the name of your user provider can be anything - your_custom_user_provider: - id: App\Security\UserProvider - -Lastly, update the ``config/packages/security.yaml`` file to set the -``provider`` key to ``your_custom_user_provider`` in all the firewalls which -will use this custom user provider. - -.. _user_session_refresh: - -Understanding how Users are Refreshed from the Session ------------------------------------------------------- - -At the end of every request (unless your firewall is ``stateless``), your -``User`` object is serialized to the session. At the beginning of the next -request, it's deserialized and then passed to your user provider to "refresh" it -(e.g. Doctrine queries for a fresh user). - -Then, the two User objects (the original from the session and the refreshed User -object) are "compared" to see if they are "equal". By default, the core -``AbstractToken`` class compares the return values of the ``getPassword()``, -``getSalt()`` and ``getUsername()`` methods. If any of these are different, your -user will be logged out. This is a security measure to make sure that malicious -users can be de-authenticated if core user data changes. - -However, in some cases, this process can cause unexpected authentication problems. -If you're having problems authenticating, it could be that you *are* authenticating -successfully, but you immediately lose authentication after the first redirect. - -In that case, review the serialization logic (e.g. ``SerializableInterface``) if -you have any, to make sure that all the fields necessary are serialized. - -Comparing Users Manually with EquatableInterface ------------------------------------------------- - -Or, if you need more control over the "compare users" process, make your User class -implement :class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface`. -Then, your ``isEqualTo()`` method will be called when comparing users. - -Injecting a User Provider in your Services ------------------------------------------- - -Symfony defines several services related to user providers: - -.. code-block:: terminal - - $ php bin/console debug:container user.provider - - Select one of the following services to display its information: - [0] security.user.provider.in_memory - [1] security.user.provider.ldap - [2] security.user.provider.chain - ... - -Most of these services are abstract and cannot be injected in your services. -Instead, you must inject the normal service that Symfony creates for each of -your user providers. The names of these services follow this pattern: -``security.user.provider.concrete.``. - -For example, if you are :doc:`building a form login ` -and want to inject in your ``LoginFormAuthenticator`` a user provider of type -``memory`` and called ``backend_users``, do the following:: - - // src/Security/LoginFormAuthenticator.php - namespace App\Security; - - use Symfony\Component\Security\Core\User\InMemoryUserProvider; - use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator; - - class LoginFormAuthenticator extends AbstractFormLoginAuthenticator - { - private $userProvider; - - // change the 'InMemoryUserProvider' type-hint in the constructor if - // you are injecting a different type of user provider - public function __construct(InMemoryUserProvider $userProvider, /* ... */) - { - $this->userProvider = $userProvider; - // ... - } - } - -Then, inject the concrete service created by Symfony for the ``backend_users`` -user provider: - -.. code-block:: yaml - - # config/services.yaml - services: - # ... - - App\Security\LoginFormAuthenticator: - $userProvider: '@security.user.provider.concrete.backend_users' diff --git a/security/user_providers.rst b/security/user_providers.rst new file mode 100644 index 00000000000..5d3be052121 --- /dev/null +++ b/security/user_providers.rst @@ -0,0 +1,375 @@ +User Providers +============== + +User providers (re)load users from a storage (e.g. a database) based on a +"user identifier" (e.g. the user's email address or username). See +:ref:`security-user-providers` for more detailed information when a user +provider is used. + +Symfony provides several user providers: + +:ref:`Entity User Provider ` + Loads users from a database using :doc:`Doctrine `; +:ref:`LDAP User Provider ` + Loads users from a LDAP server; +:ref:`Memory User Provider ` + Loads users from a configuration file; +:ref:`Chain User Provider ` + Merges two or more user providers into a new user provider. + +.. _security-entity-user-provider: + +Entity User Provider +-------------------- + +This is the most common user provider. Users are stored in a database and +the user provider uses :doc:`Doctrine ` to retrieve them. + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + providers: + users: + entity: + # the class of the entity that represents users + class: 'App\Entity\User' + # the property to query by - e.g. email, username, etc + property: 'email' + + # optional: if you're using multiple Doctrine entity + # managers, this option defines which one to use + #manager_name: 'customer' + + # ... + + .. code-block:: xml + + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use App\Entity\User; + use Symfony\Config\SecurityConfig; + + $container->loadFromExtension('security', [ + 'providers' => [ + 'users' => [ + 'entity' => [ + // the class of the entity that represents users + 'class' => User::class, + // the property to query by - e.g. email, username, etc + 'property' => 'email', + + // optional: if you're using multiple Doctrine entity + // managers, this option defines which one to use + //'manager_name' => 'customer', + ], + ], + ], + + // ... + ]); + +.. _authenticating-someone-with-a-custom-entity-provider: + +Using a Custom Query to Load the User +..................................... + +The entity provider can only query from one *specific* field, specified by +the ``property`` config key. If you want a bit more control over this - e.g. you +want to find a user by ``email`` *or* ``username``, you can do that by +implenting :class:`Symfony\\Bridge\\Doctrine\\Security\\User\\UserLoaderInterface` +in your :ref:`Doctrine repository ` (e.g. ``UserRepository``):: + + // src/Repository/UserRepository.php + namespace App\Repository; + + use App\Entity\User; + use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; + use Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface; + + class UserRepository extends ServiceEntityRepository implements UserLoaderInterface + { + // ... + + public function loadUserByIdentifier(string $usernameOrEmail): ?User + { + $entityManager = $this->getEntityManager(); + + return $entityManager->createQuery( + 'SELECT u + FROM App\Entity\User u + WHERE u.username = :query + OR u.email = :query' + ) + ->setParameter('query', $usernameOrEmail) + ->getOneOrNullResult(); + } + + /** @deprecated since Symfony 5.3 */ + public function loadUserByUsername(string $usernameOrEmail): ?User + { + return $this->loadUserByIdentifier($usernameOrEmail); + } + } + +.. versionadded:: 5.3 + + The method ``loadUserByIdentifier()`` was introduced to the + ``UserLoaderInterface`` in Symfony 5.3. + +To finish this, remove the ``property`` key from the user provider in +``security.yaml``: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + providers: + users: + entity: + class: App\Entity\User + + # ... + + .. code-block:: xml + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use App\Entity\User; + + $container->loadFromExtension('security', [ + 'providers' => [ + 'users' => [ + 'entity' => [ + 'class' => User::class, + ], + ], + ], + + // ... + ]); + +Now, whenever Symfony uses the user provider, the ``loadUserByIdentifier()`` +method on your ``UserRepository`` will be called. + +.. _security-memory-user-provider: + +Memory User Provider +-------------------- + +It's not recommended to use this provider in real applications because of its +limitations and how difficult it is to manage users. It may be useful in application +prototypes and for limited applications that don't store users in databases. + +This user provider stores all user information in a configuration file, +including their passwords. Make sure the passwords are hashed properly. See +:doc:`/security/passwords` for more information. + +After setting up hashing, you can configure all the user information in +``security.yaml``: + +.. code-block:: yaml + + # config/packages/security.yaml + security: + providers: + backend_users: + memory: + users: + john_admin: { password: '$2y$13$jxGxc ... IuqDju', roles: ['ROLE_ADMIN'] } + jane_admin: { password: '$2y$13$PFi1I ... rGwXCZ', roles: ['ROLE_ADMIN', 'ROLE_SUPER_ADMIN'] } + + # ... + +.. caution:: + + When using a ``memory`` provider, and not the ``auto`` algorithm, you have + to choose an encoding without salt (i.e. ``bcrypt``). + +.. _security-chain-user-provider: + +Chain User Provider +------------------- + +This user provider combines two or more of the other provider types (e.g. +``entity`` and ``ldap``) to create a new user provider. The order in which +providers are configured is important because Symfony will look for users +starting from the first provider and will keep looking for in the other +providers until the user is found: + +.. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + providers: + backend_users: + ldap: + # ... + + legacy_users: + entity: + # ... + + users: + entity: + # ... + + all_users: + chain: + providers: ['legacy_users', 'users', 'backend_users'] + +.. _security-custom-user-provider: + +Creating a Custom User Provider +------------------------------- + +Most applications don't need to create a custom provider. If you store users in +a database, a LDAP server or a configuration file, Symfony supports that. +However, if you're loading users from a custom location (e.g. via an API or +legacy database connection), you'll need to create a custom user provider. + +First, make sure you've followed the :doc:`Security Guide ` to create +your ``User`` class. + +If you used the ``make:user`` command to create your ``User`` class (and you +answered the questions indicating that you need a custom user provider), that +command will generate a nice skeleton to get you started:: + + // src/Security/UserProvider.php + namespace App\Security; + + use Symfony\Component\Security\Core\Exception\UnsupportedUserException; + use Symfony\Component\Security\Core\Exception\UserNotFoundException; + use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; + use Symfony\Component\Security\Core\User\UserInterface; + use Symfony\Component\Security\Core\User\UserProviderInterface; + + class UserProvider implements UserProviderInterface, PasswordUpgraderInterface + { + /** + * The loadUserByIdentifier() method was introduced in Symfony 5.3. + * In previous versions it was called loadUserByUsername() + * + * Symfony calls this method if you use features like switch_user + * or remember_me. If you're not using these features, you do not + * need to implement this method. + * + * @throws UserNotFoundException if the user is not found + */ + public function loadUserByIdentifier(string $identifier): UserInterface + { + // Load a User object from your data source or throw UserNotFoundException. + // The $identifier argument is whatever value is being returned by the + // getUserIdentifier() method in your User class. + throw new \Exception('TODO: fill in loadUserByIdentifier() inside '.__FILE__); + } + + /** + * Refreshes the user after being reloaded from the session. + * + * When a user is logged in, at the beginning of each request, the + * User object is loaded from the session and then this method is + * called. Your job is to make sure the user's data is still fresh by, + * for example, re-querying for fresh User data. + * + * If your firewall is "stateless: true" (for a pure API), this + * method is not called. + * + * @return UserInterface + */ + public function refreshUser(UserInterface $user) + { + if (!$user instanceof User) { + throw new UnsupportedUserException(sprintf('Invalid user class "%s".', get_class($user))); + } + + // Return a User object after making sure its data is "fresh". + // Or throw a UserNotFoundException if the user no longer exists. + throw new \Exception('TODO: fill in refreshUser() inside '.__FILE__); + } + + /** + * Tells Symfony to use this provider for this User class. + */ + public function supportsClass(string $class) + { + return User::class === $class || is_subclass_of($class, User::class); + } + + /** + * Upgrades the encoded password of a user, typically for using a better hash algorithm. + */ + public function upgradePassword(UserInterface $user, string $newEncodedPassword): void + { + // TODO: when encoded passwords are in use, this method should: + // 1. persist the new password in the user storage + // 2. update the $user object with $user->setPassword($newEncodedPassword); + } + } + +Most of the work is already done! Read the comments in the code and update the +TODO sections to finish the user provider. When you're done, tell Symfony about +the user provider by adding it in ``security.yaml``: + +.. code-block:: yaml + + # config/packages/security.yaml + security: + providers: + # the name of your user provider can be anything + your_custom_user_provider: + id: App\Security\UserProvider + +Lastly, update the ``config/packages/security.yaml`` file to set the +``provider`` key to ``your_custom_user_provider`` in all the firewalls which +will use this custom user provider. diff --git a/security/voters.rst b/security/voters.rst index 8970289aaff..87b5249e996 100644 --- a/security/voters.rst +++ b/security/voters.rst @@ -62,6 +62,18 @@ which makes creating a voter even easier:: .. _how-to-use-the-voter-in-a-controller: +.. tip:: + + Checking each voter several times can be time consumming for applications + that perform a lot of permission checks. To improve performance in those cases, + you can make your voters implement the :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\CacheableVoterInterface`. + This allows the access decision manager to remember the attribute and type + of subject supported by the voter, to only call the needed voters each time. + + .. versionadded:: 5.4 + + The ``CacheableVoterInterface`` interface was introduced in Symfony 5.4. + Setup: Checking for Access in a Controller ------------------------------------------ @@ -70,14 +82,14 @@ user can *edit* or *view* the object. In your controller, you'll check access wi code like this:: // src/Controller/PostController.php - // ... + // ... class PostController extends AbstractController { /** * @Route("/posts/{id}", name="post_show") */ - public function show($id) + public function show($id): Response { // get a Post object - e.g. query for it $post = ...; @@ -91,7 +103,7 @@ code like this:: /** * @Route("/posts/{id}/edit", name="post_edit") */ - public function edit($id) + public function edit($id): Response { // get a Post object - e.g. query for it $post = ...; @@ -130,7 +142,7 @@ would look like this:: const VIEW = 'view'; const EDIT = 'edit'; - protected function supports(string $attribute, $subject) + protected function supports(string $attribute, $subject): bool { // if the attribute isn't one we support, return false if (!in_array($attribute, [self::VIEW, self::EDIT])) { @@ -145,7 +157,7 @@ would look like this:: return true; } - protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token) + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool { $user = $token->getUser(); @@ -168,7 +180,7 @@ would look like this:: throw new \LogicException('This code should not be reached!'); } - private function canView(Post $post, User $user) + private function canView(Post $post, User $user): bool { // if they can edit, they can view if ($this->canEdit($post, $user)) { @@ -179,7 +191,7 @@ would look like this:: return !$post->isPrivate(); } - private function canEdit(Post $post, User $user) + private function canEdit(Post $post, User $user): bool { // this assumes that the Post object has a `getOwner()` method return $user === $post->getOwner(); @@ -243,7 +255,7 @@ with ``ROLE_SUPER_ADMIN``:: $this->security = $security; } - protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token) + protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool { // ... @@ -278,12 +290,12 @@ There are three strategies available: This grants access as soon as there is *one* voter granting access; ``consensus`` - This grants access if there are more voters granting access than denying; + This grants access if there are more voters granting access than + denying. In case of a tie the decision is based on the + ``allow_if_equal_granted_denied`` config option (defaulting to ``true``); ``unanimous`` - This only grants access if there is no voter denying access. If all voters - abstained from voting, the decision is based on the ``allow_if_all_abstain`` - config option (which defaults to ``false``); + This only grants access if there is no voter denying access. ``priority`` This grants or denies access by the first voter that does not abstain, @@ -293,6 +305,10 @@ There are three strategies available: The ``priority`` version strategy was introduced in Symfony 5.1. +Regardless the chosen strategy, if all voters abstained from voting, the +decision is based on the ``allow_if_all_abstain`` config option (which +defaults to ``false``). + In the above scenario, both voters should grant access in order to grant access to the user to read the post. In this case, the default strategy is no longer valid and ``unanimous`` should be used instead. You can set this in the @@ -329,17 +345,70 @@ security configuration: .. code-block:: php // config/packages/security.php - $container->loadFromExtension('security', [ - 'access_decision_manager' => [ - 'strategy' => 'unanimous', - 'allow_if_all_abstain' => false, - ], - ]); + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->accessDecisionManager() + ->strategy('unanimous') + ->allowIfAllAbstain(false) + ; + }; Custom Access Decision Strategy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If none of the built-in strategies fits your use case, define the ``service`` +.. versionadded:: 5.4 + + The ``strategy_service`` option was introduced in Symfony 5.4. + +If none of the built-in strategies fits your use case, define the ``strategy_service`` +option to use a custom service (your service must implement the +:class:`Symfony\\Component\\Security\\Core\Authorization\\Strategy\\AccessDecisionStrategyInterface`): + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + access_decision_manager: + strategy_service: App\Security\MyCustomAccessDecisionStrategy + # ... + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use App\Security\MyCustomAccessDecisionStrategy; + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + $security->accessDecisionManager() + ->strategyService(MyCustomAccessDecisionStrategy::class) + // ... + ; + }; + +Custom Access Decision Manager +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you need to provide an entirely custom access decision manager, define the ``service`` option to use a custom service as the Access Decision Manager (your service must implement the :class:`Symfony\\Component\\Security\\Core\\Authorization\\AccessDecisionManagerInterface`): @@ -374,10 +443,11 @@ must implement the :class:`Symfony\\Component\\Security\\Core\\Authorization\\Ac // config/packages/security.php use App\Security\MyCustomAccessDecisionManager; + use Symfony\Config\SecurityConfig; - $container->loadFromExtension('security', [ - 'access_decision_manager' => [ - 'service' => MyCustomAccessDecisionManager::class, + return static function (SecurityConfig $security) { + $security->accessDecisionManager() + ->service(MyCustomAccessDecisionManager::class) // ... - ], - ]); + ; + }; diff --git a/serializer.rst b/serializer.rst index b4dd7e03d52..92250d2f5a9 100644 --- a/serializer.rst +++ b/serializer.rst @@ -41,6 +41,19 @@ you need it or it can be used in a controller:: } } +Or you can use the ``serialize`` Twig filter in a template: + +.. code-block:: twig + + {{ object|serialize(format = 'json') }} + +See the :doc:`twig reference ` for +more information. + +.. versionadded:: 5.3 + + A ``serialize`` filter was introduced in Symfony 5.3 that uses the Serializer component. + Adding Normalizers and Encoders ------------------------------- @@ -107,7 +120,7 @@ properties and setters (``setXxx()``) to change properties: .. code-block:: xml - + notifyOfSiteUpdate()) { - $this->addFlash('success', 'Notification mail was sent successfully.'); - } + if ($siteUpdateManager->notifyOfSiteUpdate()) { + $this->addFlash('success', 'Notification mail was sent successfully.'); + } - // ... + // ... + } } Thanks to autowiring and your type-hints in ``__construct()``, the container creates @@ -369,38 +368,38 @@ example, suppose you want to make the admin email configurable: .. code-block:: diff - // src/Service/SiteUpdateManager.php - // ... + // src/Service/SiteUpdateManager.php + // ... - class SiteUpdateManager - { - // ... + class SiteUpdateManager + { + // ... + private $adminEmail; - public function __construct(MessageGenerator $messageGenerator, MailerInterface $mailer) - + public function __construct(MessageGenerator $messageGenerator, MailerInterface $mailer, $adminEmail) - { - // ... + + public function __construct(MessageGenerator $messageGenerator, MailerInterface $mailer, string $adminEmail) + { + // ... + $this->adminEmail = $adminEmail; - } + } - public function notifyOfSiteUpdate(): bool - { - // ... + public function notifyOfSiteUpdate(): bool + { + // ... - $email = (new Email()) - // ... + $email = (new Email()) + // ... - ->to('manager@example.com') + ->to($this->adminEmail) - // ... - ; - // ... - } - } + // ... + ; + // ... + } + } If you make this change and refresh, you'll see an error: - Cannot autowire service "App\Service\SiteUpdateManager": argument "$adminEmail" + Cannot autowire service "App\\Service\\SiteUpdateManager": argument "$adminEmail" of method "__construct()" must have a type-hint or be given a value explicitly. That makes sense! There is no way that the container knows what value you want to @@ -500,13 +499,14 @@ parameter and in PHP config use the ``service()`` function: # config/services.yaml services: App\Service\MessageGenerator: - # this is not a string, but a reference to a service called 'logger' - arguments: ['@logger'] + arguments: + # this is not a string, but a reference to a service called 'logger' + - '@logger' - # if the value of a string parameter starts with '@', you need to escape - # it by adding another '@' so Symfony doesn't consider it a service - # (this will be parsed as the string '@securepassword') - mailer_password: '@@securepassword' + # if the value of a string argument starts with '@', you need to escape + # it by adding another '@' so Symfony doesn't consider it a service + # the following example would be parsed as the string '@securepassword' + # - '@@securepassword' .. code-block:: xml @@ -642,7 +642,7 @@ But, you can control this and pass in a different logger: // ... same code as before // explicitly configure the service - $services->set(SiteUpdateManager::class) + $services->set(MessageGenerator::class) ->arg('$logger', service('monolog.logger.request')) ; }; @@ -994,7 +994,6 @@ for classes under the same namespace: - diff --git a/service_container/3.3-di-changes.rst b/service_container/3.3-di-changes.rst deleted file mode 100644 index d57be2c0e5b..00000000000 --- a/service_container/3.3-di-changes.rst +++ /dev/null @@ -1,873 +0,0 @@ -The Symfony 3.3 DI Container Changes Explained (autowiring, _defaults, etc) -=========================================================================== - -If you look at the ``services.yaml`` file in a new Symfony 3.3 or newer project, you'll -notice some big changes: ``_defaults``, ``autowiring``, ``autoconfigure`` and more. -These features are designed to *automate* configuration and make development faster, -without sacrificing predictability, which is very important! Another goal is to make -controllers and services behave more consistently. In Symfony 3.3, controllers *are* -services by default. - -The documentation has already been updated to assume you have these new features -enabled. If you're an existing Symfony user and want to understand the "what" -and "why" behind these changes, this article is for you! - -All Changes are Optional ------------------------- - -Most importantly, **you can upgrade to Symfony 3.3 today without making any changes to your app**. -Symfony has a strict :doc:`backwards compatibility promise `, -which means it's always safe to upgrade across minor versions. - -All of the new features are **optional**: they are not enabled by default, so you -need to actually change your configuration files to use them. - -.. _`service-33-default_definition`: - -The new Default services.yaml File ----------------------------------- - -To understand the changes, look at the new default ``services.yaml`` file (this is -what the file looks like in Symfony 4): - -.. configuration-block:: - - .. code-block:: yaml - - # config/services.yaml - services: - # default configuration for services in *this* file - _defaults: - autowire: true # Automatically injects dependencies in your services. - autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. - public: false # Allows optimizing the container by removing unused services; this also means - # fetching services directly from the container via $container->get() won't work. - # The best practice is to be explicit about your dependencies anyway. - - # makes classes in src/ available to be used as services - # this creates a service per class whose id is the fully-qualified class name - App\: - resource: '../src/*' - exclude: '../src/{Entity,Migrations,Tests}' - - # controllers are imported separately to make sure services can be injected - # as action arguments even if you don't extend any base controller class - App\Controller\: - resource: '../src/Controller' - tags: ['controller.service_arguments'] - - # add more service definitions when explicit configuration is needed - # please note that last definitions always *replace* previous ones - - .. code-block:: xml - - - - - - - - - - - - - - - - - - - .. code-block:: php - - // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; - - return function(ContainerConfigurator $configurator) { - // default configuration for services in *this* file - $services = $configurator->services() - ->defaults() - ->autowire() // Automatically injects dependencies in your services. - ->autoconfigure() // Automatically registers your services as commands, event subscribers, etc. - ; - - // makes classes in src/ available to be used as services - // this creates a service per class whose id is the fully-qualified class name - $services->load('App\\', '../src/*') - ->exclude('../src/{Entity,Migrations,Tests}'); - - // controllers are imported separately to make sure services can be injected - // as action arguments even if you don't extend any base controller class - $services->load('App\\Controller\\', '../src/Controller') - ->tag('controller.service_arguments'); - - // add more service definitions when explicit configuration is needed - // please note that last definitions always *replace* previous ones - }; - -This small bit of configuration contains a paradigm shift of how services -are configured in Symfony. - -.. _`service-33-changes-automatic-registration`: - -1) Services are Loaded Automatically ------------------------------------- - -.. seealso:: - - Read the documentation for :ref:`automatic service loading `. - -The first big change is that services do *not* need to be defined one-by-one anymore, -thanks to the following config: - -.. configuration-block:: - - .. code-block:: yaml - - # config/services.yaml - services: - # ... - - # makes classes in src/ available to be used as services - # this creates a service per class whose id is the fully-qualified class name - App\: - resource: '../src/*' - exclude: '../src/{Entity,Migrations,Tests}' - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; - - return function(ContainerConfigurator $configurator) { - // ... - - // makes classes in src/ available to be used as services - // this creates a service per class whose id is the fully-qualified class name - $services->load('App\\', '../src/*') - ->exclude('../src/{Entity,Migrations,Tests}'); - }; - -This means that every class in ``src/`` is *available* to be used as a -service. And thanks to the ``_defaults`` section at the top of the file, all of -these services are **autowired** and **private** (i.e. ``public: false``). - -The service ids are equal to the class name (e.g. ``App\Service\InvoiceGenerator``). -And that's another change you'll notice in Symfony 3.3: we recommend that you use -the class name as your service id, unless you have :ref:`multiple services for the same class `. - - But how does the container know the arguments to my services? - -Since each service is :ref:`autowired `, the container is able -to determine most arguments automatically. But, you can always override the service -and :ref:`manually configure arguments ` or anything -else special about your service. - - But wait, if I have some model (non-service) classes in my ``src/`` - directory, doesn't this mean that *they* will also be registered as services? - Isn't that a problem? - -Actually, this is *not* a problem. Since all the new services are :ref:`private ` -(thanks to ``_defaults``), if any of the services are *not* used in your code, they're -automatically removed from the compiled container. This means that the number of -services in your container should be the *same* whether your explicitly configure -each service or load them all at once with this method. - - Ok, but can I exclude some paths that I *know* won't contain services? - -Yes! The ``exclude`` key is a glob pattern that can be used to *ignore* paths -that you do *not* want to be included as services. But, since unused services are -automatically removed from the container, ``exclude`` is not that important. The -biggest benefit is that those paths are not *tracked* by the container, and so may -result in the container needing to be rebuilt less-often in the ``dev`` environment. - -2) Autowiring by Default: Use Type-hint instead of Service id -------------------------------------------------------------- - -The second big change is that autowiring is enabled (via ``_defaults``) for all -services you register. This also means that service id's are now *less* important -and "types" (i.e. class or interface names) are now *more* important. - -For example, before Symfony 3.3 (and this is still allowed), you could pass one -service as an argument to another with the following config: - -.. configuration-block:: - - .. code-block:: yaml - - # config/services.yaml - services: - app.invoice_generator: - class: App\Service\InvoiceGenerator - - app.invoice_mailer: - class: App\Service\InvoiceMailer - arguments: - - '@app.invoice_generator' - - .. code-block:: xml - - - - - - - - - - - - - - - - .. code-block:: php - - // config/services.php - use App\Service\InvoiceGenerator; - use App\Service\InvoiceMailer; - use Symfony\Component\DependencyInjection\Reference; - - $container->register('app.invoice_generator', InvoiceGenerator::class); - $container->register('app.invoice_mailer', InvoiceMailer::class) - ->setArguments([new Reference('app.invoice_generator')]); - -To pass the ``InvoiceGenerator`` as an argument to ``InvoiceMailer``, you needed -to specify the service's *id* as an argument: ``app.invoice_generator``. Service -id's were the main way that you configured things. - -But in Symfony 3.3, thanks to autowiring, all you need to do is type-hint the -argument with ``InvoiceGenerator``:: - - // src/Service/InvoiceMailer.php - namespace App\Service; - - // ... - - class InvoiceMailer - { - private $generator; - - public function __construct(InvoiceGenerator $generator) - { - $this->generator = $generator - } - - // ... - } - -That's it! Both services are :ref:`automatically registered ` -and set to autowire. Without *any* configuration, the container knows to pass the -auto-registered ``App\Service\InvoiceGenerator`` as the first argument. As -you can see, the *type* of the class - ``App\Service\InvoiceGenerator`` - is -what's most important, not the id. You request an *instance* of a specific type and -the container automatically passes you the correct service. - - Isn't that magic? How does it know which service to pass me exactly? What if - I have multiple services of the same instance? - -The autowiring system was designed to be *super* predictable. It first works by looking -for a service whose id *exactly* matches the type-hint. This means you're in full -control of what type-hint maps to what service. You can even use service aliases -to get more control. If you have multiple services for a specific type, *you* choose -which should be used for autowiring. For full details on the autowiring logic, see :ref:`autowiring-logic-explained`. - - But what if I have a scalar (e.g. string) argument? How does it autowire that? - -If you have an argument that is *not* an object, it can't be autowired. But that's -ok! Symfony will give you a clear exception (on the next refresh of *any* page) telling -you which argument of which service could not be autowired. To fix it, you can -:ref:`manually configure *just* that one argument `. -This is the philosophy of autowiring: only configure the parts that you need to. -Most configuration is automated. - - Ok, but autowiring makes your applications less stable. If you change one thing - or make a mistake, unexpected things might happen. Isn't that a problem? - -Symfony has always valued stability, security and predictability first. Autowiring -was designed with that in mind. Specifically: - -* If there is a problem wiring *any* argument to *any* service, a clear exception - is thrown on the next refresh of *any* page, even if you don't use that service - on that page. That's *powerful*: it is *not* possible to make an autowiring mistake - and not realize it. - -* The container determines *which* service to pass in an explicit way: it looks for - a service whose id matches the type-hint exactly. It does *not* scan all services - looking for objects that have that class/interface. - -Autowiring aims to *automate* configuration without magic. - -3) Controllers are Registered as Services ------------------------------------------ - -The third big change is that, in a new Symfony 3.3 project, your controllers are *services*: - -.. configuration-block:: - - .. code-block:: yaml - - # config/services.yaml - services: - # ... - - # controllers are imported separately to make sure they're public - # and have a tag that allows actions to type-hint services - App\Controller\: - resource: '../src/Controller' - tags: ['controller.service_arguments'] - - .. code-block:: xml - - - - - - - - - - - - - - - .. code-block:: php - - // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; - - return function(ContainerConfigurator $configurator) { - // ... - - // controllers are imported separately to make sure they're public - // and have a tag that allows actions to type-hint services - $services->load('App\\Controller\\', '../src/Controller') - ->tag('controller.service_arguments'); - }; - - -But, you might not even notice this. First, your controllers *can* still extend -the same base controller class (``AbstractController``). -This means you have access to all of the same shortcuts as before. Additionally, -the ``@Route`` annotation and ``_controller`` syntax (e.g. ``App:Default:homepage``) -used in routing will automatically use your controller as a service (as long as its -service id matches its class name, which it *does* in this case). See :doc:`/controller/service` -for more details. You can even create :ref:`invokable controllers ` - -In other words, everything works the same. You can even add the above configuration -to your existing project without any issues: your controllers will behave the same -as before. But now that your controllers are services, you can use dependency injection -and autowiring like any other service. - -To make life even easier, it's now possible to autowire arguments to your controller -action methods, like you can with the constructor of services. For example:: - - // src/Controller/InvoiceController.php - namespace App\Controller; - - use Psr\Log\LoggerInterface; - - class InvoiceController extends AbstractController - { - public function listInvoices(LoggerInterface $logger) - { - $logger->info('A new way to access services!'); - } - } - -This is *only* possible in a controller, and your controller service must be tagged -with ``controller.service_arguments`` to make it happen. This new feature is used -throughout the documentation. - -In general, the new best practice is to use normal constructor dependency injection -(or "action" injection in controllers) instead of fetching public services via -``$this->get()`` (though that does still work). - -.. _service_autoconfigure: - -4) Auto-tagging with autoconfigure ----------------------------------- - -The fourth big change is the ``autoconfigure`` key, which is set to ``true`` under -``_defaults``. Thanks to this, the container will auto-tag services registered in -this file. For example, suppose you want to create an event subscriber. First, you -create the class:: - - // src/EventSubscriber/SetHeaderSusbcriber.php - namespace App\EventSubscriber; - - // ... - - use Symfony\Component\EventDispatcher\EventSubscriberInterface; - use Symfony\Component\HttpKernel\Event\ResponseEvent; - use Symfony\Component\HttpKernel\KernelEvents; - - class SetHeaderSusbcriber implements EventSubscriberInterface - { - public function onKernelResponse(ResponseEvent $event) - { - $event->getResponse()->headers->set('X-SYMFONY-3.3', 'Less config'); - } - - public static function getSubscribedEvents() - { - return [ - KernelEvents::RESPONSE => 'onKernelResponse' - ]; - } - } - -Great! In Symfony 3.2 or lower, you would now need to register this as a service -in ``services.yaml`` and tag it with ``kernel.event_subscriber``. In Symfony 3.3, -you're already done! - -The service is :ref:`automatically registered `. -And thanks to ``autoconfigure``, Symfony automatically tags the service because -it implements ``EventSubscriberInterface``. - - That sounds like magic - it *automatically* tags my services? - -In this case, you've created a class that implements ``EventSubscriberInterface`` -and registered it as a service. This is more than enough for the container to know -that you want this to be used as an event subscriber: more configuration is not needed. -And the tags system is its own, Symfony-specific mechanism. And you can -always set ``autoconfigure`` to ``false`` in ``services.yaml``, or disable it -for a specific service. - - Does this mean tags are dead? Does this work for all tags? - -This does *not* work for all tags. Many tags have *required* attributes, like event -*listeners*, where you also need to specify the event name and method in your tag. -Autoconfigure works only for tags without any required tag attributes, and as you -read the docs for a feature, it'll tell you whether or not the tag is needed. You -can also look at the extension classes (e.g. `FrameworkExtension for 3.3.0`_) to -see what it autoconfigures. - - What if I need to add a priority to my tag? - -Many autoconfigured tags have an optional priority. If you need to specify a priority -(or any other optional tag attribute), no problem! :ref:`Manually configure your service ` -and add the tag. Your tag will take precedence over the one added by auto-configuration. - -5) Auto-configure with _instanceof ----------------------------------- - -And the final big change is ``_instanceof``. It acts as a default definition -template (see `service-33-default_definition`_), but only for services whose -class matches a defined one. - -This can be very useful when many services share some tag that cannot be -inherited from an abstract definition: - -.. configuration-block:: - - .. code-block:: yaml - - # config/services.yaml - services: - # ... - - _instanceof: - App\Domain\LoaderInterface: - public: true - tags: ['app.domain_loader'] - - .. code-block:: xml - - - - - - - - - - - - - - - .. code-block:: php - - // config/services.php - namespace Symfony\Component\DependencyInjection\Loader\Configurator; - - use App\Domain\LoaderInterface; - - return function(ContainerConfigurator $configurator) { - // ... - - $services->instanceof(LoaderInterface::class) - ->public() - ->tag('app.domain_loader'); - }; - -What about Performance ----------------------- - -Symfony is unique because it has a *compiled* container. This means that there is -*no* runtime performance impact for using any of these features. That's also why -the autowiring system can give you such clear errors. - -However, there is some performance impact in the ``dev`` environment. Most importantly, -your container will likely be rebuilt more often when you modify your service classes. -This is because it needs to rebuild whenever you add a new argument to a service, -or add an interface to your class that should be autoconfigured. - -In very big projects, this may be a problem. If it is, you can always opt to *not* -use autowiring. If you think the cache rebuilding system could be smarter in some -situation, please open an issue! - -Upgrading to the new Symfony 3.3 Configuration ----------------------------------------------- - -Ready to upgrade your existing project? Great! Suppose you have the following configuration: - -.. code-block:: yaml - - # config/services.yaml - services: - app.github_notifier: - class: App\Service\GitHubNotifier - arguments: - - '@app.api_client_github' - - markdown_transformer: - class: App\Service\MarkdownTransformer - - app.api_client_github: - class: App\Service\ApiClient - arguments: - - 'https://api.github.com' - - app.api_client_sl_connect: - class: App\Service\ApiClient - arguments: - - 'https://connect.symfony.com/api' - -It's optional, but let's upgrade this to the new Symfony 3.3 configuration step-by-step, -*without* breaking our application. - -Step 1): Adding _defaults -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Start by adding a ``_defaults`` section with ``autowire`` and ``autoconfigure``. - -.. code-block:: diff - - # config/services.yaml - services: - + _defaults: - + autowire: true - + autoconfigure: true - - # ... - -You're already *explicitly* configuring all of your services. So, ``autowire`` -does nothing. You're also already tagging your services, so ``autoconfigure`` -also doesn't change any existing services. - -You have not added ``public: false`` yet. That will come in a minute. - -Step 2) Using Class Service id's -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Right now, the service ids are machine names - e.g. ``app.github_notifier``. To -work well with the new configuration system, your service ids should be class names, -except when you have multiple instances of the same service. - -Start by updating the service ids to class names: - -.. code-block:: diff - - # config/services.yaml - services: - # ... - - - app.github_notifier: - - class: App\Service\GitHubNotifier - + App\Service\GitHubNotifier: - arguments: - - '@app.api_client_github' - - - markdown_transformer: - - class: App\Service\MarkdownTransformer - + App\Service\MarkdownTransformer: ~ - - # keep these ids because there are multiple instances per class - app.api_client_github: - # ... - app.api_client_sl_connect: - # ... - -.. caution:: - - Services associated with global PHP classes (i.e. not using PHP namespaces) - must maintain the ``class`` parameter. For example, when using the old Twig - classes (e.g. ``Twig_Extensions_Extension_Intl`` instead of ``Twig\Extensions\IntlExtension``), - you can't redefine the service as ``Twig_Extensions_Extension_Intl: ~`` and - you must keep the original ``class`` parameter. - -.. caution:: - - If a service is processed by a :doc:`compiler pass `, - you could face a "You have requested a non-existent service" error. - To get rid of this, be sure that the Compiler Pass is using ``findDefinition()`` - instead of ``getDefinition()``. The latter won't take aliases into - account when looking up for services. - Furthermore it is always recommended to check for definition existence - using ``has()`` function. - -.. note:: - - If you get rid of deprecations and make your controllers extend from - ``AbstractController`` instead of ``Controller``, you can skip the rest of - this step because ``AbstractController`` doesn't provide a container where - you can get the services from. All services need to be injected as explained - in the :ref:`step 5 of this article `. - -But, this change will break our app! The old service ids (e.g. ``app.github_notifier``) -no longer exist. The simplest way to fix this is to find all your old service ids -and update them to the new class id: ``app.github_notifier`` to ``App\Service\GitHubNotifier``. - -In large projects, there's a better way: create legacy aliases that map the old id -to the new id. Create a new ``legacy_aliases.yaml`` file: - -.. code-block:: yaml - - # config/legacy_aliases.yaml - services: - _defaults: - public: true - # aliases so that the old service ids can still be accessed - # remove these if/when you are not fetching these directly - # from the container via $container->get() - app.github_notifier: '@App\Service\GitHubNotifier' - markdown_transformer: '@App\Service\MarkdownTransformer' - -Then import this at the top of ``services.yaml``: - -.. code-block:: diff - - # config/services.yaml - + imports: - + - { resource: legacy_aliases.yaml } - - # ... - -That's it! The old service ids still work. Later, (see the cleanup step below), you -can remove these from your app. - -Step 3) Make the Services Private -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Now you're ready to default all services to be private: - -.. code-block:: diff - - # config/services.yaml - # ... - - services: - _defaults: - autowire: true - autoconfigure: true - + public: false - -Thanks to this, any services created in this file cannot be fetched directly from -the container. But, since the old service id's are aliases in a separate file (``legacy_aliases.yaml``), -these *are* still public. This makes sure the app keeps working. - -If you did *not* change the id of some of your services (because there are multiple -instances of the same class), you may need to make those public: - -.. code-block:: diff - - # config/services.yaml - # ... - - services: - # ... - - app.api_client_github: - # ... - - + # remove this if/when you are not fetching this - + # directly from the container via $container->get() - + public: true - - app.api_client_sl_connect: - # ... - + public: true - -This is to guarantee that the application doesn't break. If you're not fetching -these services directly from the container, this isn't needed. In a minute, you'll -clean that up. - -Step 4) Auto-registering Services -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -You're now ready to automatically register all services in ``src/`` -(and/or any other directory/bundle you have): - -.. code-block:: diff - - # config/services.yaml - - services: - _defaults: - # ... - - + App\: - + resource: '../src/*' - + exclude: '../src/{Entity,Migrations,Tests}' - + - + App\Controller\: - + resource: '../src/Controller' - + tags: ['controller.service_arguments'] - - # ... - -That's it! Actually, you're already overriding and reconfiguring all the services -you're using (``App\Service\GitHubNotifier`` and ``App\Service\MarkdownTransformer``). -But now, you won't need to manually register future services. - -Once again, there is one extra complication if you have multiple services of the -same class: - -.. code-block:: diff - - # config/services.yaml - - services: - # ... - - + # alias ApiClient to one of our services below - + # app.api_client_github will be used to autowire ApiClient type-hints - + App\Service\ApiClient: '@app.api_client_github' - - app.api_client_github: - # ... - app.api_client_sl_connect: - # ... - -This guarantees that if you try to autowire an ``ApiClient`` instance, the ``app.api_client_github`` -will be used. If you *don't* have this, the auto-registration feature will try to -register a third ``ApiClient`` service and use that for autowiring (which will fail, -because the class has a non-autowireable argument). - -.. _step-5: - -Step 5) Cleanup! -~~~~~~~~~~~~~~~~ - -To make sure your application didn't break, you did some extra work. Now it's time -to clean things up! First, update your application to *not* use the old service id's (the -ones in ``legacy_aliases.yaml``). This means updating any service arguments (e.g. -``@app.github_notifier`` to ``@App\Service\GitHubNotifier``) and updating your -code to not fetch this service directly from the container. For example: - -.. code-block:: diff - - - public function index() - + public function index(GitHubNotifier $gitHubNotifier, MarkdownTransformer $markdownTransformer) - { - - // the old way of fetching services - - $githubNotifier = $this->container->get('app.github_notifier'); - - $markdownTransformer = $this->container->get('markdown_transformer'); - - // ... - } - -As soon as you do this, you can delete ``legacy_aliases.yaml`` and remove its import. -You should do the same thing for any services that you made public, like -``app.api_client_github`` and ``app.api_client_sl_connect``. Once you're not fetching -these directly from the container, you can remove the ``public: true`` flag: - -.. code-block:: diff - - # config/services.yaml - services: - # ... - - app.api_client_github: - # ... - - public: true - - app.api_client_sl_connect: - # ... - - public: true - -Finally, you can optionally remove any services from ``services.yaml`` whose arguments -can be autowired. The final configuration looks like this: - -.. code-block:: yaml - - services: - _defaults: - autowire: true - autoconfigure: true - public: false - - App\: - resource: '../src/*' - exclude: '../src/{Entity,Migrations,Tests}' - - App\Controller\: - resource: '../src/Controller' - tags: ['controller.service_arguments'] - - App\Service\GitHubNotifier: - # this could be deleted, or I can keep being explicit - arguments: - - '@app.api_client_github' - - # alias ApiClient to one of our services below - # app.api_client_github will be used to autowire ApiClient type-hints - App\Service\ApiClient: '@app.api_client_github' - - # keep these ids because there are multiple instances per class - app.api_client_github: - class: App\Service\ApiClient - arguments: - - 'https://api.github.com' - - app.api_client_sl_connect: - class: App\Service\ApiClient - arguments: - - 'https://connect.symfony.com/api' - -You can now take advantage of the new features going forward. - -.. _`FrameworkExtension for 3.3.0`: https://github.com/symfony/symfony/blob/7938fdeceb03cc1df277a249cf3da70f0b50eb98/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php#L247-L284 diff --git a/service_container/alias_private.rst b/service_container/alias_private.rst index 6e032b10a6f..f216855d292 100644 --- a/service_container/alias_private.rst +++ b/service_container/alias_private.rst @@ -172,7 +172,7 @@ or you decided not to maintain it anymore), you can deprecate its definition: .. code-block:: yaml app.mailer: - alias: '@App\Mail\PhpMailer' + alias: 'App\Mail\PhpMailer' # this outputs the following generic deprecation message: # Since acme/package 1.2: The "app.mailer" service alias is deprecated. You should stop using it, as it will be removed in the future @@ -283,7 +283,7 @@ The following example shows how to inject an anonymous service into another serv $services->set(Foo::class) // In versions earlier to Symfony 5.1 the inline_service() function was called inline() - ->args([inline_service(AnonymousBar::class)]) + ->args([inline_service(AnonymousBar::class)]); }; .. note:: @@ -334,7 +334,7 @@ Using an anonymous service as a factory looks like this: $services = $configurator->services(); $services->set(Foo::class) - ->factory([inline_service(AnonymousBar::class), 'constructFoo']) + ->factory([inline_service(AnonymousBar::class), 'constructFoo']); }; Deprecating Services diff --git a/service_container/autowiring.rst b/service_container/autowiring.rst index e62f75f7513..13e224aed72 100644 --- a/service_container/autowiring.rst +++ b/service_container/autowiring.rst @@ -29,7 +29,7 @@ Start by creating a ROT13 transformer class:: class Rot13Transformer { - public function transform($value) + public function transform(string $value): string { return str_rot13($value); } @@ -41,6 +41,7 @@ And now a Twitter client using this transformer:: namespace App\Service; use App\Util\Rot13Transformer; + // ... class TwitterClient { @@ -51,7 +52,7 @@ And now a Twitter client using this transformer:: $this->transformer = $transformer; } - public function tweet($user, $key, $status) + public function tweet(User $user, string $key, string $status): void { $transformedStatus = $this->transformer->transform($status); @@ -129,6 +130,8 @@ Now, you can use the ``TwitterClient`` service immediately in a controller:: use App\Service\TwitterClient; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; class DefaultController extends AbstractController @@ -136,7 +139,7 @@ Now, you can use the ``TwitterClient`` service immediately in a controller:: /** * @Route("/tweet", methods={"POST"}) */ - public function tweet(TwitterClient $twitterClient) + public function tweet(TwitterClient $twitterClient, Request $request): Response { // fetch $user, $key, $status from the POST'ed data @@ -283,7 +286,7 @@ To follow this best practice, suppose you decide to create a ``TransformerInterf interface TransformerInterface { - public function transform($value); + public function transform(string $value): string; } Then, you update ``Rot13Transformer`` to implement it:: @@ -383,7 +386,7 @@ Suppose you create a second class - ``UppercaseTransformer`` that implements class UppercaseTransformer implements TransformerInterface { - public function transform($value) + public function transform(string $value): string { return strtoupper($value); } @@ -421,7 +424,7 @@ the injection:: $this->transformer = $shoutyTransformer; } - public function toot($user, $key, $status) + public function toot(User $user, string $key, string $status): void { $transformedStatus = $this->transformer->transform($status); @@ -518,6 +521,7 @@ the injection:: // want to use a named autowiring alias, wire it manually: // ->arg('$transformer', service(UppercaseTransformer::class)) // ... + ; }; Thanks to the ``App\Util\TransformerInterface`` alias, any argument type-hinted @@ -558,14 +562,14 @@ to inject the ``logger`` service, and decide to use setter-injection: private $logger; /** - * @required - */ - public function setLogger(LoggerInterface $logger) + * @required + */ + public function setLogger(LoggerInterface $logger): void { $this->logger = $logger; } - public function transform($value) + public function transform($value): string { $this->logger->info('Transforming '.$value); // ... @@ -584,12 +588,12 @@ to inject the ``logger`` service, and decide to use setter-injection: private $logger; #[Required] - public function setLogger(LoggerInterface $logger) + public function setLogger(LoggerInterface $logger): void { $this->logger = $logger; } - public function transform($value) + public function transform($value): string { $this->logger->info('Transforming '.$value); // ... diff --git a/service_container/calls.rst b/service_container/calls.rst index df33cecc989..9f7ac768976 100644 --- a/service_container/calls.rst +++ b/service_container/calls.rst @@ -22,7 +22,7 @@ example:: { private $logger; - public function setLogger(LoggerInterface $logger) + public function setLogger(LoggerInterface $logger): void { $this->logger = $logger; } @@ -90,10 +90,7 @@ instead of mutating the object they were called on:: { private $logger; - /** - * @return static - */ - public function withLogger(LoggerInterface $logger) + public function withLogger(LoggerInterface $logger): self { $new = clone $this; $new->logger = $logger; @@ -146,3 +143,31 @@ The configuration to tell the container it should do so would be like: $container->register(MessageGenerator::class) ->addMethodCall('withLogger', [new Reference('logger')], true); + +.. tip:: + + If autowire is enabled, you can also use annotations; with the previous + example it would be:: + + /** + * @required + * @return static + */ + public function withLogger(LoggerInterface $logger) + { + $new = clone $this; + $new->logger = $logger; + + return $new; + } + + You can also leverage the PHP 8 ``static`` return type instead of the + ``@return static`` annotation. If you don't want a method with a + PHP 8 ``static`` return type and a ``@required`` annotation to behave as + a wither, you can add a ``@return $this`` annotation to disable the + *returns clone* feature. + + .. versionadded:: 5.1 + + Support for the PHP 8 ``static`` return type was introduced in + Symfony 5.1. diff --git a/service_container/compiler_passes.rst b/service_container/compiler_passes.rst index 4d959e93dc6..79f666a4237 100644 --- a/service_container/compiler_passes.rst +++ b/service_container/compiler_passes.rst @@ -52,7 +52,7 @@ and process the services inside the ``process()`` method:: // ... - public function process(ContainerBuilder $container) + public function process(ContainerBuilder $container): void { // in this method you can manipulate the service container: // for example, changing some container service: @@ -81,7 +81,7 @@ method in the extension):: class MyBundle extends Bundle { - public function build(ContainerBuilder $container) + public function build(ContainerBuilder $container): void { parent::build($container); diff --git a/service_container/configurators.rst b/service_container/configurators.rst index 6e76784a284..1ade37244c3 100644 --- a/service_container/configurators.rst +++ b/service_container/configurators.rst @@ -28,7 +28,7 @@ You start defining a ``NewsletterManager`` class like this:: { private $enabledFormatters; - public function setEnabledFormatters(array $enabledFormatters) + public function setEnabledFormatters(array $enabledFormatters): void { $this->enabledFormatters = $enabledFormatters; } @@ -45,7 +45,7 @@ and also a ``GreetingCardManager`` class:: { private $enabledFormatters; - public function setEnabledFormatters(array $enabledFormatters) + public function setEnabledFormatters(array $enabledFormatters): void { $this->enabledFormatters = $enabledFormatters; } @@ -65,7 +65,7 @@ in the application:: { // ... - public function getEnabledFormatters() + public function getEnabledFormatters(): array { // code to configure which formatters to use $enabledFormatters = [...]; @@ -92,7 +92,7 @@ to create a configurator class to configure these instances:: $this->formatterManager = $formatterManager; } - public function configure(EmailFormatterAwareInterface $emailManager) + public function configure(EmailFormatterAwareInterface $emailManager): void { $emailManager->setEnabledFormatters( $this->formatterManager->getEnabledFormatters() diff --git a/service_container/debug.rst b/service_container/debug.rst index 635bbdfa9ae..e949f6234f9 100644 --- a/service_container/debug.rst +++ b/service_container/debug.rst @@ -29,7 +29,7 @@ its id: .. code-block:: terminal - $ php bin/console debug:container 'App\Service\Mailer' + $ php bin/console debug:container App\Service\Mailer # to show the service arguments: - $ php bin/console debug:container 'App\Service\Mailer' --show-arguments + $ php bin/console debug:container App\Service\Mailer --show-arguments diff --git a/service_container/definitions.rst b/service_container/definitions.rst index f90a185e1c5..160f92c8315 100644 --- a/service_container/definitions.rst +++ b/service_container/definitions.rst @@ -90,12 +90,12 @@ fetched from the container:: // gets a specific argument $firstArgument = $definition->getArgument(0); - // adds a new argument with the name of the argument - // $argumentName = the name of the argument in the constructor - $argument = $definition->setArgument('$argumentName', $argumentValue); + // adds a new named argument + // '$argumentName' = the name of the argument in the constructor, including the '$' symbol + $definition = $definition->setArgument('$argumentName', $argumentValue); // adds a new argument - $definition->addArgument($argument); + $definition->addArgument($argumentValue); // replaces argument on a specific index (0 = first argument) $definition->replaceArgument($index, $argument); diff --git a/service_container/expression_language.rst b/service_container/expression_language.rst index 9ba64eee074..972d7286c88 100644 --- a/service_container/expression_language.rst +++ b/service_container/expression_language.rst @@ -67,7 +67,8 @@ to another service: ``App\Mailer``. One way to do this is with an expression: $services->set(MailerConfiguration::class); $services->set(Mailer::class) - ->args([expr("service('App\\Mail\\MailerConfiguration').getMailerMethod()")]); + // because of the escaping applied by PHP, you must add 4 backslashes for each original backslash + ->args([expr("service('App\\\\Mail\\\\MailerConfiguration').getMailerMethod()")]); }; To learn more about the expression language syntax, see :doc:`/components/expression_language/syntax`. diff --git a/service_container/factories.rst b/service_container/factories.rst index 515e93f64b5..d2fda053923 100644 --- a/service_container/factories.rst +++ b/service_container/factories.rst @@ -26,7 +26,7 @@ object by calling the static ``createNewsletterManager()`` method:: class NewsletterManagerStaticFactory { - public static function createNewsletterManager() + public static function createNewsletterManager(): NewsletterManager { $newsletterManager = new NewsletterManager(); @@ -181,7 +181,7 @@ factory service can be used as a callback:: // ... class InvokableNewsletterManagerFactory { - public function __invoke() + public function __invoke(): NewsletterManager { $newsletterManager = new NewsletterManager(); @@ -204,7 +204,7 @@ method name: App\Email\NewsletterManager: class: App\Email\NewsletterManager - factory: '@App\Email\NewsletterManagerFactory' + factory: '@App\Email\InvokableNewsletterManagerFactory' .. code-block:: xml @@ -220,7 +220,7 @@ method name: - + @@ -237,7 +237,7 @@ method name: $services = $configurator->services(); $services->set(NewsletterManager::class) - ->factory(service(NewsletterManagerFactory::class)); + ->factory(service(InvokableNewsletterManagerFactory::class)); }; .. _factories-passing-arguments-factory-method: diff --git a/service_container/import.rst b/service_container/import.rst index f38c2a33525..b37c8360388 100644 --- a/service_container/import.rst +++ b/service_container/import.rst @@ -80,7 +80,8 @@ a relative or absolute path to the imported file: # config/services.yaml imports: - { resource: services/mailer.yaml } - + # If you want to import a whole directory: + - { resource: services/ } services: _defaults: autowire: true @@ -103,6 +104,8 @@ a relative or absolute path to the imported file: + + @@ -122,6 +125,8 @@ a relative or absolute path to the imported file: return function(ContainerConfigurator $configurator) { $configurator->import('services/mailer.php'); + // If you want to import a whole directory: + $configurator->import('services/'); $services = $configurator->services() ->defaults() diff --git a/service_container/injection_types.rst b/service_container/injection_types.rst index e4723faa610..1a0c5351d02 100644 --- a/service_container/injection_types.rst +++ b/service_container/injection_types.rst @@ -126,7 +126,7 @@ by cloning the original service, this approach allows you to make a service immu * @required * @return static */ - public function withMailer(MailerInterface $mailer) + public function withMailer(MailerInterface $mailer): self { $new = clone $this; $new->mailer = $mailer; @@ -220,7 +220,7 @@ that accepts the dependency:: // src/Mail/NewsletterManager.php namespace App\Mail; - + // ... class NewsletterManager { @@ -229,7 +229,7 @@ that accepts the dependency:: /** * @required */ - public function setMailer(MailerInterface $mailer) + public function setMailer(MailerInterface $mailer): void { $this->mailer = $mailer; } diff --git a/service_container/lazy_services.rst b/service_container/lazy_services.rst index 936316bb029..7b33bcdfcac 100644 --- a/service_container/lazy_services.rst +++ b/service_container/lazy_services.rst @@ -93,9 +93,9 @@ To check if your proxy works you can check the interface of the received object: .. note:: - If you don't install the `ProxyManager bridge`_ and the - `ocramius/proxy-manager`_, the container will skip over the ``lazy`` - flag and directly instantiate the service as it would normally do. + If you don't install the `ProxyManager bridge`_ , the container will skip + over the ``lazy`` flag and directly instantiate the service as it would + normally do. Additional Resources -------------------- @@ -106,5 +106,4 @@ in the `documentation of ProxyManager`_. .. _`ProxyManager bridge`: https://github.com/symfony/symfony/tree/master/src/Symfony/Bridge/ProxyManager .. _`proxy`: https://en.wikipedia.org/wiki/Proxy_pattern .. _`documentation of ProxyManager`: https://github.com/Ocramius/ProxyManager/blob/master/docs/lazy-loading-value-holder.md -.. _`ocramius/proxy-manager`: https://github.com/Ocramius/ProxyManager .. _`final`: https://www.php.net/manual/en/language.oop5.final.php diff --git a/service_container/optional_dependencies.rst b/service_container/optional_dependencies.rst index ddafa1bb9d5..e05e050ba9c 100644 --- a/service_container/optional_dependencies.rst +++ b/service_container/optional_dependencies.rst @@ -113,7 +113,7 @@ In YAML, the special ``@?`` syntax tells the service container that the dependency is optional. The ``NewsletterManager`` must also be rewritten by adding a ``setLogger()`` method:: - public function setLogger(LoggerInterface $logger) + public function setLogger(LoggerInterface $logger): void { // ... } diff --git a/service_container/parent_services.rst b/service_container/parent_services.rst index 619ac11452c..7df74b37a43 100644 --- a/service_container/parent_services.rst +++ b/service_container/parent_services.rst @@ -26,7 +26,7 @@ you may have multiple repository classes which need the $this->objectManager = $objectManager; } - public function setLogger(LoggerInterface $logger) + public function setLogger(LoggerInterface $logger): void { $this->logger = $logger; } diff --git a/service_container/service_subscribers_locators.rst b/service_container/service_subscribers_locators.rst index e228799e478..2459139ed70 100644 --- a/service_container/service_subscribers_locators.rst +++ b/service_container/service_subscribers_locators.rst @@ -87,7 +87,7 @@ a PSR-11 ``ContainerInterface``:: $this->locator = $locator; } - public static function getSubscribedServices() + public static function getSubscribedServices(): array { return [ 'App\FooCommand' => FooHandler::class, @@ -130,7 +130,7 @@ service locator:: use Psr\Log\LoggerInterface; - public static function getSubscribedServices() + public static function getSubscribedServices(): array { return [ // ... @@ -142,7 +142,7 @@ Service types can also be keyed by a service name for internal use:: use Psr\Log\LoggerInterface; - public static function getSubscribedServices() + public static function getSubscribedServices(): array { return [ // ... @@ -159,7 +159,7 @@ typically happens when extending ``AbstractController``:: class MyController extends AbstractController { - public static function getSubscribedServices() + public static function getSubscribedServices(): array { return array_merge(parent::getSubscribedServices(), [ // ... @@ -176,7 +176,7 @@ errors if there's no matching service found in the service container:: use Psr\Log\LoggerInterface; - public static function getSubscribedServices() + public static function getSubscribedServices(): array { return [ // ... @@ -246,9 +246,70 @@ service type to a service. Defining a Service Locator -------------------------- -To manually define a service locator, create a new service definition and add -the ``container.service_locator`` tag to it. Use the first argument of the -service definition to pass a collection of services to the service locator: +To manually define a service locator and inject it to another service, create an +argument of type ``service_locator``: + +.. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + App\CommandBus: + arguments: !service_locator + App\FooCommand: '@app.command_handler.foo' + App\BarCommand: '@app.command_handler.bar' + + .. code-block:: xml + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use App\CommandBus; + + return function(ContainerConfigurator $configurator) { + $services = $configurator->services(); + + $services->set(CommandBus::class) + ->args([service_locator([ + 'App\FooCommand' => ref('app.command_handler.foo'), + 'App\BarCommand' => ref('app.command_handler.bar'), + // if the element has no key, the ID of the original service is used + ref('app.command_handler.baz'), + ])]); + }; + +As shown in the previous sections, the constructor of the ``CommandBus`` class +must type-hint its argument with ``ContainerInterface``. Then, you can get any of +the service locator services via their ID (e.g. ``$this->locator->get('App\FooCommand')``). + +Reusing a Service Locator in Multiple Services +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you inject the same service locator in several services, it's better to +define the service locator as a stand-alone service and then inject it in the +other services. To do so, create a new service definition using the +``ServiceLocator`` class: .. configuration-block:: @@ -334,7 +395,7 @@ service definition to pass a collection of services to the service locator: The services defined in the service locator argument must include keys, which later become their unique identifiers inside the locator. -Now you can use the service locator by injecting it in any other service: +Now you can inject the service locator in any other services: .. configuration-block:: @@ -376,6 +437,9 @@ Now you can use the service locator by injecting it in any other service: ->args([service('app.command_handler_locator')]); }; +Using Service Locators in Compiler Passes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + In :doc:`compiler passes ` it's recommended to use the :method:`Symfony\\Component\\DependencyInjection\\Compiler\\ServiceLocatorTagPass::register` method to create the service locators. This will save you some boilerplate and @@ -385,7 +449,7 @@ will share identical locators among all the services referencing them:: use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; - public function process(ContainerBuilder $container) + public function process(ContainerBuilder $container): void { // ... @@ -421,7 +485,7 @@ of the ``key`` tag attribute (as defined in the ``index_by`` locator option): tags: - { name: 'app.handler', key: 'handler_two' } - App\HandlerCollection: + App\Handler\HandlerCollection: # inject all services tagged with app.handler as first argument arguments: [!tagged_locator { tag: 'app.handler', index_by: 'key' }] @@ -563,8 +627,9 @@ Service Subscriber Trait The :class:`Symfony\\Contracts\\Service\\ServiceSubscriberTrait` provides an implementation for :class:`Symfony\\Contracts\\Service\\ServiceSubscriberInterface` -that looks through all methods in your class that have no arguments and a return -type. It provides a ``ServiceLocator`` for the services of those return types. +that looks through all methods in your class that are marked with the +:class:`Symfony\\Contracts\\Service\\Attribute\\SubscribedService` attribute. It +provides a ``ServiceLocator`` for the services of each method's return type. The service id is ``__METHOD__``. This allows you to add dependencies to your services based on type-hinted helper methods:: @@ -573,6 +638,7 @@ services based on type-hinted helper methods:: use Psr\Log\LoggerInterface; use Symfony\Component\Routing\RouterInterface; + use Symfony\Contracts\Service\Attribute\SubscribedService; use Symfony\Contracts\Service\ServiceSubscriberInterface; use Symfony\Contracts\Service\ServiceSubscriberTrait; @@ -586,11 +652,13 @@ services based on type-hinted helper methods:: // $this->logger() ... } + #[SubscribedService] private function router(): RouterInterface { return $this->container->get(__METHOD__); } + #[SubscribedService] private function logger(): LoggerInterface { return $this->container->get(__METHOD__); @@ -604,9 +672,11 @@ and compose your services with them:: namespace App\Service; use Psr\Log\LoggerInterface; + use Symfony\Contracts\Service\Attribute\SubscribedService; trait LoggerAware { + #[SubscribedService] private function logger(): LoggerInterface { return $this->container->get(__CLASS__.'::'.__FUNCTION__); @@ -617,9 +687,11 @@ and compose your services with them:: namespace App\Service; use Symfony\Component\Routing\RouterInterface; + use Symfony\Contracts\Service\Attribute\SubscribedService; trait RouterAware { + #[SubscribedService] private function router(): RouterInterface { return $this->container->get(__CLASS__.'::'.__FUNCTION__); @@ -649,4 +721,12 @@ and compose your services with them:: as this will include the trait name, not the class name. Instead, use ``__CLASS__.'::'.__FUNCTION__`` as the service id. +.. deprecated:: 5.4 + + Defining your *subscribed service* methods with the + :class:`Symfony\\Contracts\\Service\\Attribute\\SubscribedService` attribute + was added in Symfony 5.4. Previously, any methods with no arguments and a + return type were *subscribed*. This still works in 5.4 but is deprecated (only + when using PHP 8) and will be removed in 6.0. + .. _`Command pattern`: https://en.wikipedia.org/wiki/Command_pattern diff --git a/service_container/synthetic_services.rst b/service_container/synthetic_services.rst index 5a3ea59d276..59869d5d7f3 100644 --- a/service_container/synthetic_services.rst +++ b/service_container/synthetic_services.rst @@ -18,7 +18,7 @@ from within the ``Kernel`` class:: { // ... - protected function initializeContainer() + protected function initializeContainer(): void { // ... $this->container->set('kernel', $this); diff --git a/service_container/tags.rst b/service_container/tags.rst index 1c26f286237..94d7d2036b3 100644 --- a/service_container/tags.rst +++ b/service_container/tags.rst @@ -60,6 +60,8 @@ and many tags require additional arguments (beyond the ``name`` parameter). **For most users, this is all you need to know**. If you want to go further and learn how to create your own custom tags, keep reading. +.. _di-instanceof: + Autoconfiguring Tags -------------------- @@ -87,7 +89,7 @@ If you want to apply tags automatically for your own services, use the .. code-block:: xml - + @@ -126,7 +128,7 @@ In a Symfony application, call this method in your kernel class:: { // ... - protected function build(ContainerBuilder $container) + protected function build(ContainerBuilder $container): void { $container->registerForAutoconfiguration(CustomInterface::class) ->addTag('app.custom_tag') @@ -142,7 +144,7 @@ In a Symfony bundle, call this method in the ``load()`` method of the { // ... - public function load(array $configs, ContainerBuilder $container) + public function load(array $configs, ContainerBuilder $container): void { $container->registerForAutoconfiguration(CustomInterface::class) ->addTag('app.custom_tag') @@ -178,7 +180,7 @@ To begin with, define the ``TransportChain`` class:: $this->transports = []; } - public function addTransport(\Swift_Transport $transport) + public function addTransport(\Swift_Transport $transport): void { $this->transports[] = $transport; } @@ -305,7 +307,7 @@ container for any services with the ``app.mail_transport`` tag:: class MailTransportPass implements CompilerPassInterface { - public function process(ContainerBuilder $container) + public function process(ContainerBuilder $container): void { // always first check if the primary service is defined if (!$container->has(TransportChain::class)) { @@ -342,7 +344,7 @@ or from your kernel:: { // ... - protected function build(ContainerBuilder $container) + protected function build(ContainerBuilder $container): void { $container->addCompilerPass(new MailTransportPass()); } @@ -373,16 +375,18 @@ To begin with, change the ``TransportChain`` class:: $this->transports = []; } - public function addTransport(\Swift_Transport $transport, $alias) + public function addTransport(\Swift_Transport $transport, $alias): void { $this->transports[$alias] = $transport; } - public function getTransport($alias) + public function getTransport($alias): ?\Swift_Transport { if (array_key_exists($alias, $this->transports)) { return $this->transports[$alias]; } + + return null; } } @@ -478,7 +482,7 @@ use this, update the compiler:: class TransportCompilerPass implements CompilerPassInterface { - public function process(ContainerBuilder $container) + public function process(ContainerBuilder $container): void { // ... @@ -488,7 +492,7 @@ use this, update the compiler:: foreach ($tags as $attributes) { $definition->addMethodCall('addTransport', [ new Reference($id), - $attributes['alias'] + $attributes['alias'], ]); } } @@ -594,8 +598,9 @@ application handlers:: Tagged Services with Priority ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The tagged services can be prioritized using the ``priority`` attribute, -thus providing a way to inject a sorted collection of services: +The tagged services can be prioritized using the ``priority`` attribute. The +priority is a positive or negative integer that defaults to ``0``. The higher +the number, the earlier the tagged service will be located in the collection: .. configuration-block:: @@ -653,7 +658,7 @@ service itself:: } } -If you want to have another method defining the priority +If you want to have another method defining the priority (e.g. ``getPriority()`` rather than ``getDefaultPriority()``), you can define it in the configuration of the collecting service: @@ -780,9 +785,9 @@ indexed by the ``key`` attribute: }; After compilation the ``HandlerCollection`` is able to iterate over your -application handlers. To retrieve a specific service by it's ``key`` attribute -from the iterator, we can use ``iterator_to_array`` and retrieve the ``handler_two``: -to get an array and then retrieve the ``handler_two`` handler:: +application handlers. To retrieve a specific service from the iterator, call the +``iterator_to_array()`` function and then use the ``key`` attribute to get the +array element. For example, to retrieve the ``handler_two`` handler:: // src/Handler/HandlerCollection.php namespace App\Handler; @@ -791,16 +796,16 @@ to get an array and then retrieve the ``handler_two`` handler:: { public function __construct(iterable $handlers) { - $handlers = iterator_to_array($handlers); + $handlers = $handlers instanceof \Traversable ? iterator_to_array($handlers) : $handlers; - $handlerTwo = $handlers['handler_two']: + $handlerTwo = $handlers['handler_two']; } } .. tip:: Just like the priority, you can also implement a static - ``getDefaultIndexAttributeName()`` method in the handlers and omit the + ``getDefaultIndexName()`` method in the handlers and omit the index attribute (``key``):: // src/Handler/One.php @@ -840,7 +845,7 @@ to get an array and then retrieve the ``handler_two`` handler:: https://symfony.com/schema/dic/services/services-1.0.xsd"> - + diff --git a/session.rst b/session.rst index 47e8cc3d269..de422ca6792 100644 --- a/session.rst +++ b/session.rst @@ -55,18 +55,20 @@ sessions, check their default configuration: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'session' => [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->session() // enables the support of sessions in the app - 'enabled' => true, + ->enabled(true) // ID of the service used for session storage // NULL means that Symfony uses PHP default session mechanism - 'handler_id' => null, + ->handlerId(null) // improves the security of the cookies used for sessions - 'cookie_secure' => 'auto', - 'cookie_samesite' => 'lax', - ], - ]); + ->cookieSecure('auto') + ->cookieSamesite('lax') + ; + }; Setting the ``handler_id`` config option to ``null`` means that Symfony will use the native PHP session mechanism. The session metadata files will be stored @@ -112,13 +114,15 @@ session metadata files: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'session' => [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->session() // ... - 'handler_id' => 'session.handler.native_file', - 'save_path' => '%kernel.project_dir%/var/sessions/%kernel.environment%', - ], - ]); + ->handlerId('session.handler.native_file') + ->savePath('%kernel.project_dir%/var/sessions/%kernel.environment%') + ; + }; Check out the Symfony config reference to learn more about the other available :ref:`Session configuration options `. You can also @@ -127,65 +131,122 @@ Check out the Symfony config reference to learn more about the other available Basic Usage ----------- -Symfony provides a session service that is injected in your services and +The session is available through the Request and the RequestStack. +Symfony provides a request_stack service that is injected in your services and controllers if you type-hint an argument with -:class:`Symfony\\Component\\HttpFoundation\\Session\\SessionInterface`:: +:class:`Symfony\\Component\\HttpFoundation\\RequestStack`:: - use Symfony\Component\HttpFoundation\Session\SessionInterface; + use Symfony\Component\HttpFoundation\RequestStack; class SomeService { - private $session; + private $requestStack; - public function __construct(SessionInterface $session) + public function __construct(RequestStack $requestStack) { - $this->session = $session; + $this->requestStack = $requestStack; } public function someMethod() { + $session = $this->requestStack->getSession(); + // stores an attribute in the session for later reuse - $this->session->set('attribute-name', 'attribute-value'); + $session->set('attribute-name', 'attribute-value'); // gets an attribute by name - $foo = $this->session->get('foo'); + $foo = $session->get('foo'); // the second argument is the value returned when the attribute doesn't exist - $filters = $this->session->get('filters', []); + $filters = $session->get('filters', []); // ... } } -.. tip:: +.. deprecated:: 5.3 - Every ``SessionInterface`` implementation is supported. If you have your - own implementation, type-hint this in the argument instead. + The ``SessionInterface`` and ``session`` service were deprecated in + Symfony 5.3. Instead, inject the ``RequestStack`` service to get the session + object of the current request. Stored attributes remain in the session for the remainder of that user's session. By default, session attributes are key-value pairs managed with the :class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBag` class. +.. deprecated:: 5.3 + + The ``NamespacedAttributeBag`` class is deprecated since Symfony 5.3. + If you need this feature, you will have to implement the class yourself. + If your application needs are complex, you may prefer to use :ref:`namespaced session attributes ` which are managed with the :class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\NamespacedAttributeBag` -class. Before using them, override the ``session`` service definition to replace -the default ``AttributeBag`` by the ``NamespacedAttributeBag``: +class. Before using them, override the ``session_listener`` service definition to build +your ``Session`` object with the default ``AttributeBag`` by the ``NamespacedAttributeBag``: .. configuration-block:: .. code-block:: yaml # config/services.yaml - session: - public: true - class: Symfony\Component\HttpFoundation\Session\Session - arguments: ['@session.storage', '@session.namespacedattributebag'] + session.factory: + autoconfigure: true + class: App\Session\SessionFactory + arguments: + - '@request_stack' + - '@session.storage.factory' + - ['@session_listener', 'onSessionUsage'] + - '@session.namespacedattributebag' session.namespacedattributebag: class: Symfony\Component\HttpFoundation\Session\Attribute\NamespacedAttributeBag + .. code-block:: xml + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use Symfony\Component\HttpFoundation\Session\Attribute\NamespacedAttributeBag; + use Symfony\Component\HttpFoundation\Session\Session; + + return function(ContainerConfigurator $configurator) { + $services = $configurator->services(); + + $services->set('session', Session::class) + ->public() + ->args([ + ref('session.storage'), + ref('session.namespacedattributebag'), + ref('session.flash_bag'), + ]) + ; + + $services->set('session.namespacedattributebag', NamespacedAttributeBag::class); + }; + .. _session-avoid-start: Avoid Starting Sessions for Anonymous Users @@ -196,22 +257,6 @@ the existence of data in the session. This may hurt your application performance because all users will receive a session cookie. In order to prevent that, you must *completely* avoid accessing the session. -For example, if your templates include some code to display the -:ref:`flash messages `, sessions will start even if the user -is not logged in and even if you haven't created any flash messages. To avoid -this behavior, add a check before trying to access the flash messages: - -.. code-block:: html+twig - - {# this check prevents starting a session when there are no flash messages #} - {% if app.request.hasPreviousSession %} - {% for message in app.flashes('notice') %} -
    - {{ message }} -
    - {% endfor %} - {% endif %} - More about Sessions ------------------- diff --git a/session/database.rst b/session/database.rst index e01d32c6d79..16715c2b150 100644 --- a/session/database.rst +++ b/session/database.rst @@ -5,7 +5,7 @@ Store Sessions in a Database ============================ Symfony stores sessions in files by default. If your application is served by -multiple servers, you'll need to use instead a database to make sessions work +multiple servers, you'll need to use a database instead to make sessions work across different servers. Symfony can store sessions in all kinds of databases (relational, NoSQL and @@ -63,8 +63,6 @@ First, define a Symfony service for the connection to the Redis server: .. code-block:: php - use Symfony\Component\DependencyInjection\Reference; - // ... $container // you can also use \RedisArray, \RedisCluster or \Predis\Client classes @@ -89,9 +87,10 @@ and ``RedisProxy``: Symfony\Component\HttpFoundation\Session\Storage\Handler\RedisSessionHandler: arguments: - '@Redis' - # you can optionally pass an array of options. The only option is 'prefix', - # which defines the prefix to use for the keys to avoid collision on the Redis server - # - { prefix: 'my_prefix' } + # you can optionally pass an array of options. The only options are 'prefix' and 'ttl', + # which define the prefix to use for the keys to avoid collision on the Redis server + # and the expiration time for any given entry (in seconds), defaults are 'sf_s' and null: + # - { 'prefix': 'my_prefix', 'ttl': 600 } .. code-block:: xml @@ -99,10 +98,12 @@ and ``RedisProxy``: - @@ -110,15 +111,17 @@ and ``RedisProxy``: .. code-block:: php // config/services.php + use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpFoundation\Session\Storage\Handler\RedisSessionHandler; $container ->register(RedisSessionHandler::class) ->addArgument( new Reference('Redis'), - // you can optionally pass an array of options. The only option is 'prefix', - // which defines the prefix to use for the keys to avoid collision on the Redis server: - // ['prefix' => 'my_prefix'], + // you can optionally pass an array of options. The only options are 'prefix' and 'ttl', + // which define the prefix to use for the keys to avoid collision on the Redis server + // and the expiration time for any given entry (in seconds), defaults are 'sf_s' and null: + // ['prefix' => 'my_prefix', 'ttl' => 600], ); Next, use the :ref:`handler_id ` @@ -146,14 +149,14 @@ configuration option to tell Symfony to use this service as the session handler: // config/packages/framework.php use Symfony\Component\HttpFoundation\Session\Storage\Handler\RedisSessionHandler; + use Symfony\Config\FrameworkConfig; - // ... - $container->loadFromExtension('framework', [ + return static function (FrameworkConfig $framework) { // ... - 'session' => [ - 'handler_id' => RedisSessionHandler::class, - ], - ]); + $framework->session() + ->handlerId(RedisSessionHandler::class) + ; + }; That's all! Symfony will now use your Redis server to read and write the session data. The main drawback of this solution is that Redis does not perform session @@ -166,11 +169,11 @@ parallel and only the first one stored the CSRF token in the session. If you use Memcached instead of Redis, follow a similar approach but replace ``RedisSessionHandler`` by :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\MemcachedSessionHandler`. -Store Sessions in a Relational Database (MySQL, PostgreSQL) ------------------------------------------------------------ +Store Sessions in a Relational Database (MariaDB, MySQL, PostgreSQL) +-------------------------------------------------------------------- Symfony includes a :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\PdoSessionHandler` -to store sessions in relational databases like MySQL and PostgreSQL. To use it, +to store sessions in relational databases like MariaDB, MySQL and PostgreSQL. To use it, first register a new handler service with your database credentials: .. configuration-block:: @@ -205,7 +208,7 @@ first register a new handler service with your database credentials: %env(DATABASE_URL)% - static/privacy.html.twig + + 200 + 86400 86400 @@ -541,6 +573,9 @@ provided by Symfony: // the path of the template to render 'template' => 'static/privacy.html.twig', + // the response status code (default: 200) + 'statusCode' => 200, + // special options defined by Symfony to set the page cache 'maxAge' => 86400, 'sharedAge' => 86400, @@ -561,6 +596,10 @@ provided by Symfony: The ``context`` option was introduced in Symfony 5.1. +.. versionadded:: 5.4 + + The ``statusCode`` option was introduced in Symfony 5.4. + Checking if a Template Exists ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -569,11 +608,14 @@ also provides a method to check for template existence. First, get the loader:: use Twig\Environment; - // this code assumes that your service uses autowiring to inject dependencies - // otherwise, inject the service called 'twig' manually - public function __construct(Environment $twig) + class YourService { - $loader = $twig->getLoader(); + // this code assumes that your service uses autowiring to inject dependencies + // otherwise, inject the service called 'twig' manually + public function __construct(Environment $twig) + { + $loader = $twig->getLoader(); + } } Then, pass the path of the Twig template to the ``exists()`` method of the loader:: @@ -607,6 +649,17 @@ errors. It's useful to run it before deploying your application to production # you can also show the deprecated features used in your templates $ php bin/console lint:twig --show-deprecations templates/email/ +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: + +.. code-block:: terminal + + $ php bin/console lint:twig --format=github + +.. versionadded:: 5.4 + + The ``github`` output format was introduced in Symfony 5.4. + Inspecting Twig Information ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -822,10 +875,12 @@ template fragments. Configure that special URL in the ``fragments`` option: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'fragments' => ['path' => '/_fragment'], - ]); + $framework->fragments()->path('/_fragment'); + }; .. caution:: @@ -1041,15 +1096,16 @@ the ``value`` is the Twig namespace, which is explained later: .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { // ... - 'paths' => [ - // directories are relative to the project root dir (but you - // can also use absolute directories) - 'email/default/templates' => null, - 'backend/templates' => null, - ], - ]); + + // directories are relative to the project root dir (but you + // can also use absolute directories) + $twig->path('email/default/templates', null); + $twig->path('backend/templates', null); + }; When rendering a template, Symfony looks for it first in the ``twig.paths`` directories that don't define a namespace and then falls back to the default @@ -1096,13 +1152,14 @@ configuration to define a namespace for each template directory: .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { // ... - 'paths' => [ - 'email/default/templates' => 'email', - 'backend/templates' => 'admin', - ], - ]); + + $twig->path('email/default/templates', 'email'); + $twig->path('backend/templates', 'admin'); + }; Now, if you render the ``layout.html.twig`` template, Symfony will render the ``templates/layout.html.twig`` file. Use the special syntax ``@`` + namespace to @@ -1154,3 +1211,4 @@ Learn more .. _`Twig template inheritance`: https://twig.symfony.com/doc/2.x/tags/extends.html .. _`Twig block tag`: https://twig.symfony.com/doc/2.x/tags/block.html .. _`Cross-Site Scripting`: https://en.wikipedia.org/wiki/Cross-site_scripting +.. _`GitHub Actions`: https://docs.github.com/en/free-pro-team@latest/actions diff --git a/templating/global_variables.rst b/templating/global_variables.rst index 2e2c841812c..bd8342fed8e 100644 --- a/templating/global_variables.rst +++ b/templating/global_variables.rst @@ -39,12 +39,13 @@ main Twig configuration file: .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ + use Symfony\Config\TwigConfig; + + return static function (TwigConfig $twig) { // ... - 'globals' => [ - 'ga_tracking' => 'UA-xxxxx-x', - ], - ]); + + $twig->global('ga_tracking')->value('UA-xxxxx-x'); + }; Now, the variable ``ga_tracking`` is available in all Twig templates, so you can use it without having to pass it explicitly from the controller or service @@ -91,19 +92,21 @@ the ``@`` character, which is the usual syntax to - @App\Generator\UuidGenerator +
    .. code-block:: php // config/packages/twig.php - $container->loadFromExtension('twig', [ + use Symfony\Config\TwigConfig; + use function Symfony\Component\DependencyInjection\Loader\Configurator\service; + + return static function (TwigConfig $twig) { // ... - 'globals' => [ - 'uuid' => '@App\Generator\UuidGenerator', - ], - ]); + + $twig->global('uuid')->value(service('App\Generator\UuidGenerator')); + }; Now you can use the ``uuid`` variable in any Twig template to access to the ``UuidGenerator`` service: diff --git a/templating/hinclude.rst b/templating/hinclude.rst index eed8f09b5e7..3a117148983 100644 --- a/templating/hinclude.rst +++ b/templating/hinclude.rst @@ -60,12 +60,14 @@ default content rendering some template: .. code-block:: php // config/packages/framework.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'fragments' => [ - 'hinclude_default_template' => 'hinclude.html.twig', - ], - ]); + $framework->fragments() + ->hincludeDefaultTemplate('hinclude.html.twig') + ; + }; You can define default templates per ``render()`` function (which will override any global default template that is defined): @@ -88,7 +90,7 @@ Use the ``attributes`` option to define the value of hinclude.js options: {# by default, cross-site requests don't use credentials such as cookies, authorization headers or TLS client certificates; set this option to 'true' to use them #} - {{ render_hinclude(controller('...'), {attributes: {data-with-credentials: 'true'}}) }} + {{ render_hinclude(controller('...'), {attributes: {'data-with-credentials': 'true'}}) }} {# by default, the JavaScript code included in the loaded contents is not run; set this option to 'true' to run that JavaScript code #} diff --git a/testing.rst b/testing.rst index ead9a1a702b..a70857dc0ee 100644 --- a/testing.rst +++ b/testing.rst @@ -11,598 +11,585 @@ using both functional and unit tests. The PHPUnit Testing Framework ----------------------------- -Symfony integrates with an independent library called `PHPUnit`_ to give you a -rich testing framework. This article won't cover PHPUnit itself, which has its -own excellent `documentation`_. +Symfony integrates with an independent library called `PHPUnit`_ to give +you a rich testing framework. This article won't cover PHPUnit itself, +which has its own excellent `documentation`_. -Before creating your first test, install the `PHPUnit Bridge component`_, which -wraps the original PHPUnit binary to provide additional features: +Before creating your first test, install ``phpunit/phpunit`` and the +``symfony/test-pack``, which installs some other packages providing useful +Symfony test utilities: .. code-block:: terminal - $ composer require --dev symfony/phpunit-bridge + $ composer require --dev phpunit/phpunit symfony/test-pack -After the library downloads, try executing PHPUnit by running (the first time -you run this, it will download PHPUnit itself and make its classes available in -your app): +After the library is installed, try running PHPUnit: .. code-block:: terminal - $ ./bin/phpunit + $ php ./vendor/bin/phpunit + +This commands automatically runs your application's tests. Each test is a +PHP class ending with "Test" (e.g. ``BlogControllerTest``) that lives in +the ``tests/`` directory of your application. + +PHPUnit is configured by the ``phpunit.xml.dist`` file in the root of your +application. The default configuration provided by Symfony Flex will be +enough in most cases. Read the `PHPUnit documentation`_ to discover all +possible configuration options (e.g. to enable code coverage or to split +your test into multiple "test suites"). .. note:: - The ``./bin/phpunit`` command is created by :ref:`Symfony Flex ` - when installing the ``phpunit-bridge`` package. If the command is missing, you - can remove the package (``composer remove symfony/phpunit-bridge``) and install - it again. Another solution is to remove the project's ``symfony.lock`` file and - run ``composer install`` to force the execution of all Symfony Flex recipes. + :ref:`Symfony Flex ` automatically creates + ``phpunit.xml.dist`` and ``tests/bootstrap.php``. If these files are + missing, you can try running the recipe again using + ``composer recipes:install phpunit/phpunit --force -v``. -Each test - whether it's a unit test or a functional test - is a PHP class -that should live in the ``tests/`` directory of your application. If you follow -this rule, then you can run all of your application's tests with the same -command as before. +Types of Tests +-------------- -PHPUnit is configured by the ``phpunit.xml.dist`` file in the root of your -Symfony application. +There are many types of automated tests and precise definitions often +differ from project to project. In Symfony, the following definitions are +used. If you have learned something different, that is not necessarily +wrong, just different from what the Symfony documentation is using. -.. tip:: +`Unit Tests`_ + These tests ensure that *individual* units of source code (e.g. a single + class) behave as intended. - Use the ``--coverage-*`` command options to generate code coverage reports. - Read the PHPUnit manual to learn more about `code coverage analysis`_. +`Integration Tests`_ + These tests test a combination of classes and commonly interact with + Symfony's service container. These tests do not yet cover the fully + working application, those are called *Application tests*. -.. index:: - single: Tests; Unit tests +`Application Tests`_ + Application tests test the behavior of a complete application. They + make HTTP requests (both real and simulated ones) and test that the + response is as expected. Unit Tests ---------- -A `unit test`_ ensures that individual units of source code (e.g. a single class -or some specific method in some class) meet their design and behave as intended. -If you want to test an entire feature of your application (e.g. registering as a -user or generating an invoice), see the section about :ref:`Functional Tests `. +A `unit test`_ ensures that individual units of source code (e.g. a single +class or some specific method in some class) meet their design and behave +as intended. Writing unit tests in a Symfony application is no different +from writing standard PHPUnit unit tests. You can learn about it in the +PHPUnit documentation: `Writing Tests for PHPUnit`_. -Writing Symfony unit tests is no different from writing standard PHPUnit -unit tests. Suppose, for example, that you have an class called ``Calculator`` -in the ``src/Util/`` directory of the app:: +By convention, the ``tests/`` directory should replicate the directory +of your application for unit tests. So, if you're testing a class in the +``src/Form/`` directory, put the test in the ``tests/Form/`` directory. +Autoloading is automatically enabled via the ``vendor/autoload.php`` file +(as configured by default in the ``phpunit.xml.dist`` file). - // src/Util/Calculator.php - namespace App\Util; +You can run tests using the ``./vendor/bin/phpunit`` command: - class Calculator - { - public function add($a, $b) - { - return $a + $b; - } - } +.. code-block:: terminal + + # run all tests of the application + $ php ./vendor/bin/phpunit -To test this, create a ``CalculatorTest`` file in the ``tests/Util`` directory -of your application:: + # run all tests in the Form/ directory + $ php ./vendor/bin/phpunit tests/Form - // tests/Util/CalculatorTest.php - namespace App\Tests\Util; + # run tests for the UserType class + $ php ./vendor/bin/phpunit tests/Form/UserTypeTest.php - use App\Util\Calculator; - use PHPUnit\Framework\TestCase; +.. tip:: + + In large test suites, it can make sense to create subdirectories for + each type of tests (e.g. ``tests/Unit/`` and ``test/Functional/``). + +.. _integration-tests: + +Integration Tests +----------------- + +An integration test will test a larger part of your application compared to +a unit test (e.g. a combination of services). Integration tests might want +to use the Symfony Kernel to fetch a service from the dependency injection +container. + +Symfony provides a :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\KernelTestCase` +class to help you creating and booting the kernel in your tests using +``bootKernel()``:: + + // tests/Service/NewsletterGeneratorTest.php + namespace App\Tests\Service; - class CalculatorTest extends TestCase + use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; + + class NewsletterGeneratorTest extends KernelTestCase { - public function testAdd() + public function testSomething() { - $calculator = new Calculator(); - $result = $calculator->add(30, 12); + self::bootKernel(); - // assert that your calculator added the numbers correctly! - $this->assertEquals(42, $result); + // ... } } +The ``KernelTestCase`` also makes sure your kernel is rebooted for each +test. This assures that each test is run independently from each other. + +To run your application tests, the ``KernelTestCase`` class needs to +find the application kernel to initialize. The kernel class is +usually defined in the ``KERNEL_CLASS`` environment variable +(included in the default ``.env.test`` file provided by Symfony Flex): + +.. code-block:: env + + # .env.test + KERNEL_CLASS=App\Kernel + .. note:: - By convention, the ``tests/`` directory should replicate the directory - of your application for unit tests. So, if you're testing a class in the - ``src/Util/`` directory, put the test in the ``tests/Util/`` - directory. + If your use case is more complex, you can also override the + ``getKernelClass()`` or ``createKernel()`` methods of your functional + test, which take precedence over the ``KERNEL_CLASS`` env var. -Like in your real application - autoloading is automatically enabled via the -``vendor/autoload.php`` file (as configured by default in the -``phpunit.xml.dist`` file). +Set-up your Test Environment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can also limit a test run to a directory or a specific test file: +The tests create a kernel that runs in the ``test`` +:ref:`environment `. This allows to have +special settings for your tests inside ``config/packages/test/``. -.. code-block:: terminal +If you have Symfony Flex installed, some packages already installed some +useful test configuration. For example, by default, the Twig bundle is +configured to be especially strict to catch errors before deploying your +code to production: - # run all tests of the application - $ php bin/phpunit +.. configuration-block:: - # run all tests in the Util/ directory - $ php bin/phpunit tests/Util + .. code-block:: yaml - # run tests for the Calculator class - $ php bin/phpunit tests/Util/CalculatorTest.php + # config/packages/test/twig.yaml + twig: + strict_variables: true -.. index:: - single: Tests; Functional tests + .. code-block:: xml -.. _functional-tests: + + + -Functional Tests ----------------- + + -Functional tests check the integration of the different layers of an -application (from the routing to the views). They are no different from unit -tests as far as PHPUnit is concerned, but they have a very specific workflow: + .. code-block:: php -* Make a request; -* Click on a link or submit a form; -* Test the response; -* Rinse and repeat. + // config/packages/test/twig.php + use Symfony\Config\TwigConfig; -Before creating your first test, install these packages that provide some of the -utilities used in the functional tests: + return static function (TwigConfig $twig) { + $twig->strictVariables(true); + }; -.. code-block:: terminal +You can also use a different environment entirely, or override the default +debug mode (``true``) by passing each as options to the ``bootKernel()`` +method:: - $ composer require --dev symfony/browser-kit symfony/css-selector + self::bootKernel([ + 'environment' => 'my_test_env', + 'debug' => false, + ]); -Your First Functional Test -~~~~~~~~~~~~~~~~~~~~~~~~~~ -Functional tests are PHP files that typically live in the ``tests/Controller`` -directory of your application. If you want to test the pages handled by your -``PostController`` class, start by creating a new ``PostControllerTest.php`` -file that extends a special ``WebTestCase`` class. +.. tip:: -As an example, a test could look like this:: + It is recommended to run your test with ``debug`` set to ``false`` on + your CI server, as it significantly improves test performance. This + disables clearing the cache. If your tests don't run in a clean + environment each time, you have to manually clear it using for instance + this code in ``tests/bootstrap.php``:: - // tests/Controller/PostControllerTest.php - namespace App\Tests\Controller; + // ... - use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; + // ensure a fresh cache when debug mode is disabled + (new \Symfony\Component\Filesystem\Filesystem())->remove(__DIR__.'/../var/cache/test'); - class PostControllerTest extends WebTestCase +Customizing Environment Variables +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you need to customize some environment variables for your tests (e.g. the +``DATABASE_URL`` used by Doctrine), you can do that by overriding anything you +need in your ``.env.test`` file: + +.. code-block:: text + + # .env.test + + # ... + DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name_test?serverVersion=5.7" + +In the test environment, these env files are read (if vars are duplicated +in them, files lower in the list override previous items): + +#. ``.env``: containing env vars with application defaults; +#. ``.env.test``: overriding/setting specific test values or vars; +#. ``.env.test.local``: overriding settings specific for this machine. + +.. caution:: + + The ``.env.local`` file is **not** used in the test environment, to + make each test set-up as consistent as possible. + +Retrieving Services in the Test +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In your integration tests, you often need to fetch the service from the +service container to call a specific method. After booting the kernel, +the container is stored in ``static::getContainer()``:: + + // tests/Service/NewsletterGeneratorTest.php + namespace App\Tests\Service; + + use App\Service\NewsletterGenerator; + use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; + + class NewsletterGeneratorTest extends KernelTestCase { - public function testShowPost() + public function testSomething() { - $client = static::createClient(); + // (1) boot the Symfony kernel + self::bootKernel(); - $client->request('GET', '/post/hello-world'); + // (2) use static::getContainer() to access the service container + $container = static::getContainer(); - $this->assertEquals(200, $client->getResponse()->getStatusCode()); + // (3) run some service & test the result + $newsletterGenerator = $container->get(NewsletterGenerator::class); + $newsletter = $newsletterGenerator->generateMonthlyNews(...); + + $this->assertEquals(..., $newsletter->getContent()); } } -.. tip:: +The container in ``static::getContainer()`` is actually a special test container. +It gives you access to both the public services and the non-removed +:ref:`private services ` services. + +.. note:: - To run your functional tests, the ``WebTestCase`` class needs to know which - is the application kernel to bootstrap it. The kernel class is usually - defined in the ``KERNEL_CLASS`` environment variable (included in the - default ``.env.test`` file provided by Symfony): + If you need to test private services that have been removed (those who + are not used by any other services), you need to declare those private + services as public in the ``config/services_test.yaml`` file. - If your use case is more complex, you can also override the - ``createKernel()`` or ``getKernelClass()`` methods of your functional test, - which take precedence over the ``KERNEL_CLASS`` env var. +.. _testing-databases: -In the above example, you validated that the HTTP response was successful. The -next step is to validate that the page actually contains the expected content. -The ``createClient()`` method returns a client, which is like a browser that -you'll use to crawl your site:: +Configuring a Database for Tests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - $crawler = $client->request('GET', '/post/hello-world'); +Tests that interact with the database should use their own separate +database to not mess with the databases used in the other +:ref:`configuration environments `. -The ``request()`` method (read -:ref:`more about the request method `) -returns a :class:`Symfony\\Component\\DomCrawler\\Crawler` object which can -be used to select elements in the response, click on links and submit forms. +To do that, edit or create the ``.env.test.local`` file at the root +directory of your project and define the new value for the ``DATABASE_URL`` +env var: -.. tip:: +.. code-block:: env - The ``Crawler`` only works when the response is an XML or an HTML document. - To get the raw content response, call ``$client->getResponse()->getContent()``. + # .env.test.local + DATABASE_URL="mysql://USERNAME:PASSWORD@127.0.0.1:3306/DB_NAME?serverVersion=5.7" -The crawler integrates with the ``symfony/css-selector`` component to give you the -power of CSS selectors to find content in a page. To install the CSS selector -component, run: +This assumes that each developer/machine uses a different database for the +tests. If the test set-up is the same on each machine, use the ``.env.test`` +file instead and commit it to the shared repository. Learn more about +:ref:`using multiple .env files in Symfony applications `. -.. code-block:: terminal +After that, you can create the test database and all tables using: - $ composer require --dev symfony/css-selector +.. code-block:: terminal -Now you can use CSS selectors with the crawler. To assert that the phrase -"Hello World" is present in the page's main title, you can use this assertion:: + # create the test database + $ php bin/console --env=test doctrine:database:create - $this->assertSelectorTextContains('html h1.title', 'Hello World'); + # create the tables/columns in the test database + $ php bin/console --env=test doctrine:schema:create -This assertion checks if the first element matching the CSS selector contains -the given text. This assert calls ``$crawler->filter('html h1.title')`` -internally, which allows you to use CSS selectors to filter any HTML element in -the page and check for its existence, attributes, text, etc. +.. tip:: -The ``assertSelectorTextContains`` method is not a native PHPUnit assertion and is -available thanks to the ``WebTestCase`` class. + A common practice is to append the ``_test`` suffix to the original + database names in tests. If the database name in production is called + ``project_acme`` the name of the testing database could be + ``project_acme_test``. -The crawler can also be used to interact with the page. Click on a link by first -selecting it with the crawler using either an XPath expression or a CSS selector, -then use the client to click on it:: +Resetting the Database Automatically Before each Test +..................................................... - $link = $crawler - ->filter('a:contains("Greet")') // find all links with the text "Greet" - ->eq(1) // select the second link in the list - ->link() - ; +Tests should be independent from each other to avoid side effects. For +example, if some test modifies the database (by adding or removing an +entity) it could change the results of other tests. - // and click it - $crawler = $client->click($link); +The `DAMADoctrineTestBundle`_ uses Doctrine transactions to let each test +interact with an unmodified database. Install it using: -Submitting a form is very similar: select a form button, optionally override -some form values and submit the corresponding form:: +.. code-block:: terminal - $form = $crawler->selectButton('submit')->form(); + $ composer require --dev dama/doctrine-test-bundle - // set some values - $form['name'] = 'Lucas'; - $form['form_name[subject]'] = 'Hey there!'; +Now, enable it as a PHPUnit extension: - // submit the form - $crawler = $client->submit($form); +.. code-block:: xml -.. tip:: + + + - The form can also handle uploads and contains methods to fill in different types - of form fields (e.g. ``select()`` and ``tick()``). For details, see the - `Forms`_ section below. + + + + -Now that you can navigate through an application, use assertions to test -that it actually does what you expect it to. Use the Crawler to make assertions -on the DOM:: +That's it! This bundle uses a clever trick: it begins a database +transaction before every test and rolls it back automatically after the +test finishes to undo all changes. Read more in the documentation of the +`DAMADoctrineTestBundle`_. - // asserts that the response matches a given CSS selector. - $this->assertGreaterThan(0, $crawler->filter('h1')->count()); +.. _doctrine-fixtures: -Or test against the response content directly if you just want to assert that -the content contains some text or in case that the response is not an XML/HTML -document:: +Load Dummy Data Fixtures +........................ - $this->assertStringContainsString( - 'Hello World', - $client->getResponse()->getContent() - ); +Instead of using the real data from the production database, it's common to +use fake or dummy data in the test database. This is usually called +*"fixtures data"* and Doctrine provides a library to create and load them. +Install it with: -.. tip:: +.. code-block:: terminal - Instead of installing each testing dependency individually, you can use the - ``test`` :ref:`Symfony pack ` to install all those dependencies at once: + $ composer require --dev doctrine/doctrine-fixtures-bundle - .. code-block:: terminal +Then, use the ``make:fixtures`` command of the `SymfonyMakerBundle`_ to +generate an empty fixture class: - $ composer require --dev symfony/test-pack +.. code-block:: terminal -.. index:: - single: Tests; Assertions + $ php bin/console make:fixtures -.. sidebar:: Useful Assertions + The class name of the fixtures to create (e.g. AppFixtures): + > ProductFixture - To get you started faster, here is a list of the most common and - useful test assertions:: +Then you modify use this class to load new entities in the database. For +instance, to load ``Product`` objects into Doctrine, use:: - use Symfony\Component\HttpFoundation\Response; + // src/DataFixtures/ProductFixture.php + namespace App\DataFixtures; - // ... + use App\Entity\Product; + use Doctrine\Bundle\FixturesBundle\Fixture; + use Doctrine\Persistence\ObjectManager; - // asserts that there is at least one h2 tag with the class "subtitle" - // the third argument is an optional message shown on failed tests - $this->assertGreaterThan(0, $crawler->filter('h2.subtitle')->count(), - 'There is at least one subtitle' - ); - - // asserts that there are exactly 4 h2 tags on the page - $this->assertCount(4, $crawler->filter('h2')); - - // asserts that the "Content-Type" header is "application/json" - $this->assertResponseHeaderSame('Content-Type', 'application/json'); - // equivalent to: - $this->assertTrue($client->getResponse()->headers->contains( - 'Content-Type', 'application/json' - )); - - // asserts that the response content contains a string - $this->assertStringContainsString('foo', $client->getResponse()->getContent()); - // ...or matches a regex - $this->assertRegExp('/foo(bar)?/', $client->getResponse()->getContent()); - - // asserts that the response status code is 2xx - $this->assertResponseIsSuccessful(); - // equivalent to: - $this->assertTrue($client->getResponse()->isSuccessful()); - - // asserts that the response status code is 404 Not Found - $this->assertTrue($client->getResponse()->isNotFound()); - - // asserts a specific status code - $this->assertResponseStatusCodeSame(201); - // HTTP status numbers are available as constants too: - // e.g. 201 === Symfony\Component\HttpFoundation\Response::HTTP_CREATED - // equivalent to: - $this->assertEquals(201, $client->getResponse()->getStatusCode()); - - // asserts that the response is a redirect to /demo/contact - $this->assertResponseRedirects('/demo/contact'); - // equivalent to: - $this->assertTrue($client->getResponse()->isRedirect('/demo/contact')); - // ...or check that the response is a redirect to any URL - $this->assertResponseRedirects(); - -.. _testing-data-providers: - -Testing against Different Sets of Data --------------------------------------- - -It's common to have to execute the same test against different sets of data to -check the multiple conditions code must handle. This is solved with PHPUnit's -`data providers`_, which work both for unit and functional tests. - -First, add one or more arguments to your test method and use them inside the -test code. Then, define another method which returns a nested array with the -arguments to use on each test run. Lastly, add the ``@dataProvider`` annotation -to associate both methods:: - - /** - * @dataProvider provideUrls - */ - public function testPageIsSuccessful($url) + class ProductFixture extends Fixture { - $client = self::createClient(); - $client->request('GET', $url); + public function load(ObjectManager $manager) + { + $product = new Product(); + $product->setName('Priceless widget'); + $product->setPrice(14.50); + $product->setDescription('Ok, I guess it *does* have a price'); + $manager->persist($product); - $this->assertTrue($client->getResponse()->isSuccessful()); - } + // add more products - public function provideUrls() - { - return [ - ['/'], - ['/blog'], - ['/contact'], - // ... - ]; + $manager->flush(); + } } -.. index:: - single: Tests; Client +Empty the database and reload *all* the fixture classes with: -Working with the Test Client ----------------------------- +.. code-block:: terminal -The test client simulates an HTTP client like a browser and makes requests -into your Symfony application:: + $ php bin/console doctrine:fixtures:load - $crawler = $client->request('GET', '/post/hello-world'); +For more information, read the `DoctrineFixturesBundle documentation`_. -The ``request()`` method takes the HTTP method and a URL as arguments and -returns a ``Crawler`` instance. +.. _functional-tests: -.. tip:: +Application Tests +----------------- - Hardcoding the request URLs is a best practice for functional tests. If the - test generates URLs using the Symfony router, it won't detect any change - made to the application URLs which may impact the end users. - -.. _testing-request-method-sidebar: - -.. sidebar:: More about the ``request()`` Method: - - The full signature of the ``request()`` method is:: - - request( - string $method, - string $uri, - array $parameters = [], - array $files = [], - array $server = [], - string $content = null, - bool $changeHistory = true - ) - - The ``server`` array is the raw values that you'd expect to normally - find in the PHP `$_SERVER`_ superglobal. For example, to set the - ``Content-Type`` and ``Referer`` HTTP headers, you'd pass the following (mind - the ``HTTP_`` prefix for non standard headers):: - - $client->request( - 'GET', - '/post/hello-world', - [], - [], - [ - 'CONTENT_TYPE' => 'application/json', - 'HTTP_REFERER' => '/foo/bar', - ] - ); - -Use the crawler to find DOM elements in the response. These elements can then -be used to click on links and submit forms:: - - $crawler = $client->clickLink('Go elsewhere...'); - - $crawler = $client->submitForm('validate', ['name' => 'Fabien']); - -The ``clickLink()`` and ``submitForm()`` methods both return a ``Crawler`` object. -These methods are the best way to browse your application as it takes care -of a lot of things for you, like detecting the HTTP method from a form and -giving you a nice API for uploading files. - -The ``request()`` method can also be used to simulate form submissions directly -or perform more complex requests. Some useful examples:: - - // submits a form directly (but using the Crawler is easier!) - $client->request('POST', '/submit', ['name' => 'Fabien']); - - // submits a raw JSON string in the request body - $client->request( - 'POST', - '/submit', - [], - [], - ['CONTENT_TYPE' => 'application/json'], - '{"name":"Fabien"}' - ); - - // Form submission with a file upload - use Symfony\Component\HttpFoundation\File\UploadedFile; - - $photo = new UploadedFile( - '/path/to/photo.jpg', - 'photo.jpg', - 'image/jpeg', - null - ); - $client->request( - 'POST', - '/submit', - ['name' => 'Fabien'], - ['photo' => $photo] - ); - - // Perform a DELETE request and pass HTTP headers - $client->request( - 'DELETE', - '/post/12', - [], - [], - ['PHP_AUTH_USER' => 'username', 'PHP_AUTH_PW' => 'pa$$word'] - ); - -Last but not least, you can force each request to be executed in its own PHP -process to avoid any side effects when working with several clients in the same -script:: - - $client->insulate(); - -AJAX Requests -~~~~~~~~~~~~~ - -The Client provides a :method:`Symfony\\Component\\BrowserKit\\AbstractBrowser::xmlHttpRequest` -method, which has the same arguments as the ``request()`` method, and it's a -shortcut to make AJAX requests:: +Application tests check the integration of all the different layers of the +application (from the routing to the views). They are no different from +unit tests or integration tests as far as PHPUnit is concerned, but they +have a very specific workflow: - // the required HTTP_X_REQUESTED_WITH header is added automatically - $client->xmlHttpRequest('POST', '/submit', ['name' => 'Fabien']); +#. :ref:`Make a request `; +#. :ref:`Interact with the page ` (e.g. click on a link or submit a form); +#. :ref:`Test the response `; +#. Rinse and repeat. -Browsing -~~~~~~~~ +.. note:: -The Client supports many operations that can be done in a real browser:: + The tools used in this section can be installed via the ``symfony/test-pack``, + use ``composer require symfony/test-pack`` if you haven't done so already. - $client->back(); - $client->forward(); - $client->reload(); +Write Your First Application Test +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // clears all cookies and the history - $client->restart(); +Application tests are PHP files that typically live in the ``tests/Controller/`` +directory of your application. They often extend +:class:`Symfony\\Bundle\\FrameworkBundle\\Test\\WebTestCase`. This class +adds special logic on top of the ``KernelTestCase``. You can read more +about that in the above :ref:`section on integration tests `. -.. note:: +If you want to test the pages handled by your +``PostController`` class, start by creating a new ``PostControllerTest`` +using the ``make:test`` command of the `SymfonyMakerBundle`_: - The ``back()`` and ``forward()`` methods skip the redirects that may have - occurred when requesting a URL, as normal browsers do. +.. code-block:: terminal -Accessing Internal Objects -~~~~~~~~~~~~~~~~~~~~~~~~~~ + $ php bin/console make:test -If you use the client to test your application, you might want to access the -client's internal objects:: + Which test type would you like?: + > WebTestCase - $history = $client->getHistory(); - $cookieJar = $client->getCookieJar(); + The name of the test class (e.g. BlogPostTest): + > Controller\PostControllerTest -You can also get the objects related to the latest request:: +This creates the following test class:: - // the HttpKernel request instance - $request = $client->getRequest(); + // tests/Controller/PostControllerTest.php + namespace App\Tests\Controller; - // the BrowserKit request instance - $request = $client->getInternalRequest(); + use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; - // the HttpKernel response instance - $response = $client->getResponse(); + class PostControllerTest extends WebTestCase + { + public function testSomething(): void + { + // This calls KernelTestCase::bootKernel(), and creates a + // "client" that is acting as the browser + $client = static::createClient(); - // the BrowserKit response instance - $response = $client->getInternalResponse(); + // Request a specific page + $crawler = $client->request('GET', '/'); - // the Crawler instance - $crawler = $client->getCrawler(); + // Validate a successful response and some content + $this->assertResponseIsSuccessful(); + $this->assertSelectorTextContains('h1', 'Hello World'); + } + } -Accessing the Container -~~~~~~~~~~~~~~~~~~~~~~~ +In the above example, the test validates that the HTTP response was successful +and the request body contains a ``

    `` tag with ``"Hello world"``. -Functional tests should only test the response (e.g. its contents or its HTTP -status code). However, in some rare circumstances you may need to access the -container to use some service. +The ``request()`` method also returns a crawler, which you can use to +create more complex assertions in your tests:: -First, you can get the same container used in the application, which only -includes the public services:: + $crawler = $client->request('GET', '/post/hello-world'); - public function testSomething() - { - $client = self::createClient(); - $container = $client->getContainer(); - // $someService = $container->get('the-service-ID'); + // for instance, count the number of ``.comment`` elements on the page + $this->assertCount(4, $crawler->filter('.comment')); - // ... - } +You can learn more about the crawler in :doc:`/testing/dom_crawler`. -Symfony tests also have access to a special container that includes both the -public services and the non-removed :ref:`private services ` -services:: +.. _testing-applications-arrange: - public function testSomething() - { - // this call is needed; otherwise the container will be empty - self::bootKernel(); +Making Requests +~~~~~~~~~~~~~~~ - $container = self::$container; - // $someService = $container->get('the-service-ID'); +The test client simulates an HTTP client like a browser and makes requests +into your Symfony application:: - // ... - } + $crawler = $client->request('GET', '/post/hello-world'); -Finally, for the most rare edge-cases, Symfony includes a special container -which provides access to all services, public and private. This special -container is a service that can be get via the normal container:: +The ``request()`` method takes the HTTP method and a URL as arguments and +returns a ``Crawler`` instance. - public function testSomething() - { - $client = self::createClient(); - $normalContainer = $client->getContainer(); - $specialContainer = $normalContainer->get('test.service_container'); +.. tip:: - // $somePrivateService = $specialContainer->get('the-service-ID'); + Hardcoding the request URLs is a best practice for application tests. + If the test generates URLs using the Symfony router, it won't detect + any change made to the application URLs which may impact the end users. - // ... - } +The full signature of the ``request()`` method is:: + + request( + $method, + $uri, + array $parameters = [], + array $files = [], + array $server = [], + $content = null, + $changeHistory = true + ) + +This allows you to create all types of requests you can think of: + +.. contents:: + :local: + :depth: 1 .. tip:: - If the information you need to check is available from the profiler, use - it instead. + The test client is available as the ``test.client`` service in the + container in the ``test`` environment (or wherever the + :ref:`framework.test ` option is enabled). + This means you can override the service entirely if you need to. + +Browsing the Site +................. + +The Client supports many operations that can be done in a real browser:: + + $client->back(); + $client->forward(); + $client->reload(); + + // clears all cookies and the history + $client->restart(); + +.. note:: + + The ``back()`` and ``forward()`` methods skip the redirects that may have + occurred when requesting a URL, as normal browsers do. + +Redirecting +........... + +When a request returns a redirect response, the client does not follow +it automatically. You can examine the response and force a redirection +afterwards with the ``followRedirect()`` method:: + + $crawler = $client->followRedirect(); + +If you want the client to automatically follow all redirects, you can +force them by calling the ``followRedirects()`` method before performing the request:: + + $client->followRedirects(); + +If you pass ``false`` to the ``followRedirects()`` method, the redirects +will no longer be followed:: + + $client->followRedirects(false); .. _testing_logging_in_users: Logging in Users (Authentication) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +................................. .. versionadded:: 5.1 The ``loginUser()`` method was introduced in Symfony 5.1. -When you want to add functional tests for protected pages, you have to +When you want to add application tests for protected pages, you have to first "login" as a user. Reproducing the actual steps - such as submitting a login form - make a test very slow. For this reason, Symfony provides a ``loginUser()`` method to simulate logging in in your functional tests. -Instead of login in with real users, it's recommended to create a user only for -tests. You can do that with Doctrine :ref:`data fixtures `, -to load the testing users only in the test database. +Instead of logging in with real users, it's recommended to create a user +only for tests. You can do that with `Doctrine data fixtures`_ to load the +testing users only in the test database. After loading users in your database, use your user repository to fetch this user and use @@ -622,7 +609,7 @@ to simulate a login request:: public function testVisitingWhileLoggedIn() { $client = static::createClient(); - $userRepository = static::$container->get(UserRepository::class); + $userRepository = static::getContainer()->get(UserRepository::class); // retrieve the test user $testUser = $userRepository->findOneByEmail('john.doe@example.com'); @@ -643,156 +630,115 @@ You can pass any :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\TestBrowserToken` object and stores in the session of the test client. -Accessing the Profiler Data -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -On each request, you can enable the Symfony profiler to collect data about the -internal handling of that request. For example, the profiler could be used to -verify that a given page runs less than a certain number of database -queries when loading. - -To get the Profiler for the last request, do the following:: +Making AJAX Requests +.................... - // enables the profiler for the very next request - $client->enableProfiler(); +The client provides an +:method:`Symfony\\Component\\BrowserKit\\AbstractBrowser::xmlHttpRequest` +method, which has the same arguments as the ``request()`` method and is +a shortcut to make AJAX requests:: - $crawler = $client->request('GET', '/profiler'); - - // gets the profile - $profile = $client->getProfile(); - -For specific details on using the profiler inside a test, see the -:doc:`/testing/profiling` article. + // the required HTTP_X_REQUESTED_WITH header is added automatically + $client->xmlHttpRequest('POST', '/submit', ['name' => 'Fabien']); -Redirecting -~~~~~~~~~~~ +Sending Custom Headers +...................... -When a request returns a redirect response, the client does not follow -it automatically. You can examine the response and force a redirection -afterwards with the ``followRedirect()`` method:: +If your application behaves according to some HTTP headers, pass them as the +second argument of ``createClient()``:: - $crawler = $client->followRedirect(); + $client = static::createClient([], [ + 'HTTP_HOST' => 'en.example.com', + 'HTTP_USER_AGENT' => 'MySuperBrowser/1.0', + ]); -If you want the client to automatically follow all redirects, you can -force them by calling the ``followRedirects()`` method before performing the request:: +You can also override HTTP headers on a per request basis:: - $client->followRedirects(); + $client->request('GET', '/', [], [], [ + 'HTTP_HOST' => 'en.example.com', + 'HTTP_USER_AGENT' => 'MySuperBrowser/1.0', + ]); -If you pass ``false`` to the ``followRedirects()`` method, the redirects -will no longer be followed:: +.. caution:: - $client->followRedirects(false); + The name of your custom headers must follow the syntax defined in the + `section 4.1.18 of RFC 3875`_: replace ``-`` by ``_``, transform it into + uppercase and prefix the result with ``HTTP_``. For example, if your + header name is ``X-Session-Token``, pass ``HTTP_X_SESSION_TOKEN``. Reporting Exceptions -~~~~~~~~~~~~~~~~~~~~ +.................... -Debugging exceptions in functional tests may be difficult because by default +Debugging exceptions in application tests may be difficult because by default they are caught and you need to look at the logs to see which exception was thrown. Disabling catching of exceptions in the test client allows the exception to be reported by PHPUnit:: $client->catchExceptions(false); -.. index:: - single: Tests; Crawler - -.. _testing-crawler: - -The Crawler ------------ - -A Crawler instance is returned each time you make a request with the Client. -It allows you to traverse HTML documents, select nodes, find links and forms. - -Traversing -~~~~~~~~~~ - -Like jQuery, the Crawler has methods to traverse the DOM of an HTML/XML -document. For example, the following finds all ``input[type=submit]`` elements, -selects the last one on the page, and then selects its immediate parent element:: - - $newCrawler = $crawler->filter('input[type=submit]') - ->last() - ->parents() - ->first() - ; - -Many other methods are also available: - -``filter('h1.title')`` - Nodes that match the CSS selector. -``filterXpath('h1')`` - Nodes that match the XPath expression. -``eq(1)`` - Node for the specified index. -``first()`` - First node. -``last()`` - Last node. -``siblings()`` - Siblings. -``nextAll()`` - All following siblings. -``previousAll()`` - All preceding siblings. -``parents()`` - Returns the parent nodes. -``children()`` - Returns children nodes. -``reduce($lambda)`` - Nodes for which the callable does not return false. - -Since each of these methods returns a new ``Crawler`` instance, you can -narrow down your node selection by chaining the method calls:: - - $crawler - ->filter('h1') - ->reduce(function ($node, $i) { - if (!$node->attr('class')) { - return false; - } - }) - ->first() - ; +Accessing Internal Objects +.......................... -.. tip:: +If you use the client to test your application, you might want to access the +client's internal objects:: - Use the ``count()`` function to get the number of nodes stored in a Crawler: - ``count($crawler)`` + $history = $client->getHistory(); + $cookieJar = $client->getCookieJar(); -Extracting Information -~~~~~~~~~~~~~~~~~~~~~~ +You can also get the objects related to the latest request:: -The Crawler can extract information from the nodes:: + // the HttpKernel request instance + $request = $client->getRequest(); - use Symfony\Component\DomCrawler\Crawler; - - // returns the attribute value for the first node - $crawler->attr('class'); + // the BrowserKit request instance + $request = $client->getInternalRequest(); - // returns the node value for the first node - $crawler->text(); + // the HttpKernel response instance + $response = $client->getResponse(); + + // the BrowserKit response instance + $response = $client->getInternalResponse(); + + // the Crawler instance + $crawler = $client->getCrawler(); + +Accessing the Profiler Data +........................... + +On each request, you can enable the Symfony profiler to collect data about the +internal handling of that request. For example, the profiler could be used to +verify that a given page runs less than a certain number of database +queries when loading. + +To get the profiler for the last request, do the following:: + + // enables the profiler for the very next request + $client->enableProfiler(); + + $crawler = $client->request('GET', '/profiler'); + + // gets the profile + $profile = $client->getProfile(); + +For specific details on using the profiler inside a test, see the +:doc:`/testing/profiling` article. + +.. _testing-applications-act: - // returns the default text if the node does not exist - $crawler->text('Default text content'); +Interacting with the Response +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // pass TRUE as the second argument of text() to remove all extra white spaces, including - // the internal ones (e.g. " foo\n bar baz \n " is returned as "foo bar baz") - $crawler->text(null, true); +Like a real browser, the Client and Crawler objects can be used to interact +with the page you're served: - // extracts an array of attributes for all nodes - // (_text returns the node value) - // returns an array for each element in crawler, - // each with the value and href - $info = $crawler->extract(['_text', 'href']); +.. contents:: + :local: + :depth: 1 - // executes a lambda for each node and return an array of results - $data = $crawler->each(function (Crawler $node, $i) { - return $node->attr('href'); - }); +.. _testing-links: -Links -~~~~~ +Clicking on Links +................. Use the ``clickLink()`` method to click on the first link that contains the given text (or the first clickable image with that ``alt`` attribute):: @@ -804,16 +750,21 @@ given text (or the first clickable image with that ``alt`` attribute):: If you need access to the :class:`Symfony\\Component\\DomCrawler\\Link` object that provides helpful methods specific to links (such as ``getMethod()`` and -``getUri()``), use the ``selectLink()`` method instead:: +``getUri()``), use the ``Crawler::selectLink()`` method instead:: $client = static::createClient(); $crawler = $client->request('GET', '/post/hello-world'); $link = $crawler->selectLink('Click here')->link(); + // ... + + // use click() if you want to click the selected link $client->click($link); -Forms -~~~~~ +.. _testing-forms: + +Submitting Forms +................ Use the ``submitForm()`` method to submit the form that contains the given button:: @@ -830,60 +781,48 @@ The second optional argument is used to override the default form field values. .. note:: - Notice that you select form buttons and not forms as a form can have several - buttons; if you use the traversing API, keep in mind that you must look for a + Notice that you select form buttons and not forms, as a form can have several + buttons. If you use the traversing API, keep in mind that you must look for a button. If you need access to the :class:`Symfony\\Component\\DomCrawler\\Form` object that provides helpful methods specific to forms (such as ``getUri()``, -``getValues()`` and ``getFields()``) use the ``selectButton()`` method instead:: +``getValues()`` and ``getFields()``) use the ``Crawler::selectButton()`` method instead:: $client = static::createClient(); $crawler = $client->request('GET', '/post/hello-world'); + // select the button $buttonCrawlerNode = $crawler->selectButton('submit'); - // select the form that contains this button + // retrieve the Form object for the form belonging to this button $form = $buttonCrawlerNode->form(); - // you can also pass an array of field values that overrides the default ones - $form = $buttonCrawlerNode->form([ - 'my_form[name]' => 'Fabien', - 'my_form[subject]' => 'Symfony rocks!', - ]); - - // you can pass a second argument to override the form HTTP method - $form = $buttonCrawlerNode->form([], 'DELETE'); + // set values on a form object + $form['my_form[name]'] = 'Fabien'; + $form['my_form[subject]'] = 'Symfony rocks!'; // submit the Form object $client->submit($form); -The field values can also be passed as a second argument of the ``submit()`` -method:: - + // optionally, you can combine the last 2 steps by passing an array of + // field values while submitting the form: $client->submit($form, [ 'my_form[name]' => 'Fabien', 'my_form[subject]' => 'Symfony rocks!', ]); -For more complex situations, use the ``Form`` instance as an array to set the -value of each field individually:: - - // changes the value of a field - $form['my_form[name]'] = 'Fabien'; - $form['my_form[subject]'] = 'Symfony rocks!'; - -There is also a nice API to manipulate the values of the fields according to -their type:: +Based on the form type, you can use different methods to fill in the +input:: // selects an option or a radio - $form['country']->select('France'); + $form['my_form[country]']->select('France'); // ticks a checkbox - $form['like_symfony']->tick(); + $form['my_form[like_symfony]']->tick(); // uploads a file - $form['photo']->upload('/path/to/lucas.jpg'); + $form['my_form[photo]']->upload('/path/to/lucas.jpg'); // In the case of a multiple file upload $form['my_form[field][0]']->upload('/path/to/lucas.jpg'); @@ -918,228 +857,165 @@ their type:: $client->submit($form, [], ['HTTP_ACCEPT_LANGUAGE' => 'es']); $client->submitForm($button, [], 'POST', ['HTTP_ACCEPT_LANGUAGE' => 'es']); -Adding and Removing Forms to a Collection -......................................... - -If you use a :doc:`Collection of Forms `, -you can't add fields to an existing form with -``$form['task[tags][0][name]'] = 'foo';``. This results in an error -``Unreachable field "…"`` because ``$form`` can only be used in order to -set values of existing fields. In order to add new fields, you have to -add the values to the raw data array:: - - // gets the form - $form = $crawler->filter('button')->form(); - - // gets the raw values - $values = $form->getPhpValues(); - - // adds fields to the raw values - $values['task']['tags'][0]['name'] = 'foo'; - $values['task']['tags'][1]['name'] = 'bar'; - - // submits the form with the existing and new values - $crawler = $client->request($form->getMethod(), $form->getUri(), $values, - $form->getPhpFiles()); - - // the 2 tags have been added to the collection - $this->assertEquals(2, $crawler->filter('ul.tags > li')->count()); - -Where ``task[tags][0][name]`` is the name of a field created -with JavaScript. - -You can remove an existing field, e.g. a tag:: - - // gets the values of the form - $values = $form->getPhpValues(); - - // removes the first tag - unset($values['task']['tags'][0]); +.. _testing-application-assertions: - // submits the data - $crawler = $client->request($form->getMethod(), $form->getUri(), - $values, $form->getPhpFiles()); - - // the tag has been removed - $this->assertEquals(0, $crawler->filter('ul.tags > li')->count()); - -.. index:: - pair: Tests; Configuration - -Testing Configuration ---------------------- - -The Client used by functional tests creates a Kernel that runs in a special -``test`` environment. Since Symfony loads the ``config/packages/test/*.yaml`` -in the ``test`` environment, you can tweak any of your application's settings -specifically for testing. - -For example, by default, the Swift Mailer is configured to *not* actually -deliver emails in the ``test`` environment. You can see this under the ``swiftmailer`` -configuration option: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/test/swiftmailer.yaml - - # ... - swiftmailer: - disable_delivery: true - - .. code-block:: xml - - - - - - - - - - .. code-block:: php - - // config/packages/test/swiftmailer.php - - // ... - $container->loadFromExtension('swiftmailer', [ - 'disable_delivery' => true, - ]); - -You can also use a different environment entirely, or override the default -debug mode (``true``) by passing each as options to the ``createClient()`` -method:: - - $client = static::createClient([ - 'environment' => 'my_test_env', - 'debug' => false, - ]); - -Customizing Database URL / Environment Variables -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you need to customize some environment variables for your tests (e.g. the -``DATABASE_URL`` used by Doctrine), you can do that by overriding anything you -need in your ``.env.test`` file: - -.. code-block:: text - - # .env.test - DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name_test" - - # use SQLITE - # DATABASE_URL="sqlite:///%kernel.project_dir%/var/app.db" - -This file is automatically read in the ``test`` environment: any keys here override -the defaults in ``.env``. - -.. caution:: - - Applications created before November 2018 had a slightly different system, - involving a ``.env.dist`` file. For information about upgrading, see: - :doc:`configuration/dot-env-changes`. - -Sending Custom Headers -~~~~~~~~~~~~~~~~~~~~~~ - -If your application behaves according to some HTTP headers, pass them as the -second argument of ``createClient()``:: - - $client = static::createClient([], [ - 'HTTP_HOST' => 'en.example.com', - 'HTTP_USER_AGENT' => 'MySuperBrowser/1.0', - ]); - -You can also override HTTP headers on a per request basis:: - - $client->request('GET', '/', [], [], [ - 'HTTP_HOST' => 'en.example.com', - 'HTTP_USER_AGENT' => 'MySuperBrowser/1.0', - ]); - -.. tip:: - - The test client is available as a service in the container in the ``test`` - environment (or wherever the :ref:`framework.test ` - option is enabled). This means you can override the service entirely - if you need to. - -.. index:: - pair: PHPUnit; Configuration - -PHPUnit Configuration -~~~~~~~~~~~~~~~~~~~~~ - -Each application has its own PHPUnit configuration, stored in the -``phpunit.xml.dist`` file. You can edit this file to change the defaults or -create a ``phpunit.xml`` file to set up a configuration for your local machine -only. - -.. tip:: - - Store the ``phpunit.xml.dist`` file in your code repository and ignore - the ``phpunit.xml`` file. - -By default, only the tests stored in ``tests/`` are run via the ``phpunit`` command, -as configured in the ``phpunit.xml.dist`` file: - -.. code-block:: xml - - - - - - - tests - - - - - -But you can add more directories. For instance, the following -configuration adds tests from a custom ``lib/tests`` directory: - -.. code-block:: xml +Testing the Response (Assertions) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - - - - - - lib/tests - - - - +Now that the tests have visited a page and interacted with it (e.g. filled +in a form), it is time to verify that the expected output is shown. + +As all tests are based on PHPUnit, you can use any `PHPUnit Assertion`_ in +your tests. Combined with test Client and the Crawler, this allows you to +check anything you want. + +However, Symfony provides useful shortcut methods for the most common cases: + +.. contents:: + :local: + :depth: 1 + +Response Assertions +................... + +``assertResponseIsSuccessful(string $message = '')`` + Asserts that the response was successful (HTTP status is 2xx). +``assertResponseStatusCodeSame(int $expectedCode, string $message = '')`` + Asserts a specific HTTP status code. +``assertResponseRedirects(string $expectedLocation = null, int $expectedCode = null, string $message = '')`` + Asserts the response is a redirect response (optionally, you can check + the target location and status code). +``assertResponseHasHeader(string $headerName, string $message = '')``/``assertResponseNotHasHeader(string $headerName, string $message = '')`` + Asserts the given header is (not) available on the response. +``assertResponseHeaderSame(string $headerName, string $expectedValue, string $message = '')``/``assertResponseHeaderNotSame(string $headerName, string $expectedValue, string $message = '')`` + Asserts the given header does (not) contain the expected value on the + response. +``assertResponseHasCookie(string $name, string $path = '/', string $domain = null, string $message = '')``/``assertResponseNotHasCookie(string $name, string $path = '/', string $domain = null, string $message = '')`` + Asserts the given cookie is present in the response (optionally + checking for a specific cookie path or domain). +``assertResponseCookieValueSame(string $name, string $expectedValue, string $path = '/', string $domain = null, string $message = '')`` + Asserts the given cookie is present and set to the expected value. +``assertResponseFormatSame(?string $expectedFormat, string $message = '')`` + Asserts the response format returned by the + :method:`Symfony\\Component\\HttpFoundation\\Response::getFormat` method + is the same as the expected value. +``assertResponseIsUnprocessable(string $message = '')`` + Asserts the response is unprocessable (HTTP status is 422) + +.. versionadded:: 5.3 + + The ``assertResponseFormatSame()`` method was introduced in Symfony 5.3. + +.. versionadded:: 5.4 + + The ``assertResponseIsUnprocessable()`` method was introduced in Symfony 5.4. + +Request Assertions +.................. + +``assertRequestAttributeValueSame(string $name, string $expectedValue, string $message = '')`` + Asserts the given :ref:`request attribute ` + is set to the expected value. +``assertRouteSame($expectedRoute, array $parameters = [], string $message = '')`` + Asserts the request matched the given route and optionally route parameters. + +Browser Assertions +.................. + +``assertBrowserHasCookie(string $name, string $path = '/', string $domain = null, string $message = '')``/``assertBrowserNotHasCookie(string $name, string $path = '/', string $domain = null, string $message = '')`` + Asserts that the test Client does (not) have the given cookie set + (meaning, the cookie was set by any response in the test). +``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. +``assertThatForClient(Constraint $constraint, string $message = '')`` + Asserts the given Constraint in the Client. Useful to use your custom asserts + in the same way of built-in asserts (i.e. without passing the Client as argument):: + + // add this method in some custom class imported in your tests + protected static function assertMyOwnCustomAssert(): void + { + self::assertThatForClient(new SomeCustomConstraint()); + } -To include other directories in the code coverage, also edit the ```` -section: +.. versionadded:: 5.4 + + The ``assertThatForClient()`` method was introduced in Symfony 5.4. + +Crawler Assertions +.................. + +``assertSelectorExists(string $selector, string $message = '')``/``assertSelectorNotExists(string $selector, string $message = '')`` + Asserts that the given selector does (not) match at least one element + in the response. +``assertSelectorTextContains(string $selector, string $text, string $message = '')``/``assertSelectorTextNotContains(string $selector, string $text, string $message = '')`` + Asserts that the first element matching the given selector does (not) + contain the expected text. +``assertSelectorTextSame(string $selector, string $text, string $message = '')`` + Asserts that the contents of the first element matching the given + selector does (not) equal the expected text. +``assertPageTitleSame(string $expectedTitle, string $message = '')`` + Asserts that the ```` element is equal to the given title. +``assertPageTitleContains(string $expectedTitle, string $message = '')`` + Asserts that the ``<title>`` element contains the given title. +``assertInputValueSame(string $fieldName, string $expectedValue, string $message = '')``/``assertInputValueNotSame(string $fieldName, string $expectedValue, string $message = '')`` + Asserts that value of the form input with the given name does (not) + equal the expected value. +``assertCheckboxChecked(string $fieldName, string $message = '')``/``assertCheckboxNotChecked(string $fieldName, string $message = '')`` + Asserts that the checkbox with the given name is (not) checked. +``assertFormValue(string $formSelector, string $fieldName, string $value, string $message = '')``/``assertNoFormValue(string $formSelector, string $fieldName, string $message = '')`` + Asserts that value of the field of the first form matching the given + selector does (not) equal the expected value. + +.. versionadded:: 5.2 + + The ``assertCheckboxChecked()``, ``assertCheckboxNotChecked()``, + ``assertFormValue()`` and ``assertNoFormValue()`` methods were introduced + in Symfony 5.2. + +Mailer Assertions +................. -.. code-block:: xml +.. versionadded:: 5.1 - <!-- phpunit.xml.dist --> - <phpunit> - <!-- ... --> - <filter> - <whitelist> - <!-- ... --> - <directory>lib</directory> - <exclude> - <!-- ... --> - <directory>lib/tests</directory> - </exclude> - </whitelist> - </filter> - <!-- ... --> - </phpunit> + Starting from Symfony 5.1, the following assertions no longer require to make + a request with the ``Client`` in a test case extending the ``WebTestCase`` class. + +``assertEmailCount(int $count, string $transport = null, string $message = '')`` + Asserts that the expected number of emails was sent. +``assertQueuedEmailCount(int $count, string $transport = null, string $message = '')`` + Asserts that the expected number of emails was queued (e.g. using the + Messenger component). +``assertEmailIsQueued(MessageEvent $event, string $message = '')``/``assertEmailIsNotQueued(MessageEvent $event, string $message = '')`` + Asserts that the given mailer event is (not) queued. Use + ``getMailerEvent(int $index = 0, string $transport = null)`` to + retrieve a mailer event by index. +``assertEmailAttachmentCount(RawMessage $email, int $count, string $message = '')`` + Asserts that the given email has the expected number of attachments. Use + ``getMailerMessage(int $index = 0, string $transport = null)`` to + retrievea specific email by index. +``assertEmailTextBodyContains(RawMessage $email, string $text, string $message = '')``/``assertEmailTextBodyNotContains(RawMessage $email, string $text, string $message = '')`` + Asserts that the text body of the given email does (not) contain the + expected text. +``assertEmailHtmlBodyContains(RawMessage $email, string $text, string $message = '')``/``assertEmailHtmlBodyNotContains(RawMessage $email, string $text, string $message = '')`` + Asserts that the HTML body of the given email does (not) contain the + expected text. +``assertEmailHasHeader(RawMessage $email, string $headerName, string $message = '')``/``assertEmailNotHasHeader(RawMessage $email, string $headerName, string $message = '')`` + Asserts that the given email does (not) have the expected header set. +``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 + address. This assertion normalizes addresses like ``Jane Smith + <jane@example.com>`` into ``jane@example.com``. + +.. TODO +.. End to End Tests (E2E) +.. ---------------------- +.. * panther +.. * testing javascript +.. * UX or form collections as example? Learn more ---------- @@ -1154,8 +1030,12 @@ Learn more .. _`PHPUnit`: https://phpunit.de/ .. _`documentation`: https://phpunit.readthedocs.io/ -.. _`PHPUnit Bridge component`: https://symfony.com/components/PHPUnit%20Bridge +.. _`Writing Tests for PHPUnit`: https://phpunit.readthedocs.io/en/stable/writing-tests-for-phpunit.html +.. _`PHPUnit documentation`: https://phpunit.readthedocs.io/en/stable/configuration.html .. _`unit test`: https://en.wikipedia.org/wiki/Unit_testing -.. _`$_SERVER`: https://www.php.net/manual/en/reserved.variables.server.php -.. _`data providers`: https://phpunit.de/manual/current/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.data-providers -.. _`code coverage analysis`: https://phpunit.readthedocs.io/en/9.1/code-coverage-analysis.html +.. _`DAMADoctrineTestBundle`: https://github.com/dmaicher/doctrine-test-bundle +.. _`Doctrine data fixtures`: https://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html +.. _`DoctrineFixturesBundle documentation`: https://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html +.. _`SymfonyMakerBundle`: https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html +.. _`PHPUnit Assertion`: https://phpunit.readthedocs.io/en/stable/assertions.html +.. _`section 4.1.18 of RFC 3875`: https://tools.ietf.org/html/rfc3875#section-4.1.18 diff --git a/testing/bootstrap.rst b/testing/bootstrap.rst index bdd7448a519..7acdd6e78cc 100644 --- a/testing/bootstrap.rst +++ b/testing/bootstrap.rst @@ -26,7 +26,7 @@ before running the tests: .. code-block:: xml <!-- phpunit.xml.dist --> - <?xml version="1.0" encoding="UTF-8"?> + <?xml version="1.0" encoding="UTF-8" ?> <phpunit bootstrap="tests/bootstrap.php" > @@ -39,7 +39,7 @@ cache to be cleared: .. code-block:: xml <!-- phpunit.xml.dist --> - <?xml version="1.0" encoding="UTF-8"?> + <?xml version="1.0" encoding="UTF-8" ?> <phpunit> <!-- ... --> diff --git a/testing/database.rst b/testing/database.rst index 5720125ca53..0bd0d03af62 100644 --- a/testing/database.rst +++ b/testing/database.rst @@ -1,123 +1,14 @@ .. index:: single: Tests; Database -How to Test Code that Interacts with the Database -================================================= +How to Test A Doctrine Repository +================================= -Configuring a Database for Tests --------------------------------- +.. seealso:: -Tests that interact with the database should use their own separate database to -not mess with the databases used in the other :ref:`configuration environments <configuration-environments>`. -To do that, edit or create the ``.env.test.local`` file at the root directory of -your project and define the new value for the ``DATABASE_URL`` env var: - -.. code-block:: bash - - # .env.test.local - DATABASE_URL=mysql://USERNAME:PASSWORD@127.0.0.1:3306/DB_NAME?serverVersion=5.7 - -.. tip:: - - A common practice is to append the ``_test`` suffix to the original database - names in tests. If the database name in production is called ``project_acme`` - the name of the testing database could be ``project_acme_test``. - -The above assumes that each developer/machine uses a different database for the -tests. If the entire team uses the same settings for tests, edit or create the -``.env.test`` file instead and commit it to the shared repository. Learn more -about :ref:`using multiple .env files in Symfony applications <configuration-multiple-env-files>`. - -Resetting the Database Automatically Before each Test ------------------------------------------------------ - -Tests should be independent from each other to avoid side effects. For example, -if some test modifies the database (by adding or removing an entity) it could -change the results of other tests. Run the following command to install a bundle -that ensures that each test is run with the same unmodified database: - -.. code-block:: terminal - - $ composer require --dev dama/doctrine-test-bundle - -Now, enable it as a PHPUnit extension or listener: - -.. code-block:: xml - - <!-- phpunit.xml.dist --> - <phpunit> - <!-- ... --> - - <!-- Add this for PHPUnit 7.5 or higher --> - <extensions> - <extension class="DAMA\DoctrineTestBundle\PHPUnit\PHPUnitExtension"/> - </extensions> - - <!-- Add this for PHPUnit 7.0 until 7.4 --> - <listeners> - <listener class="\DAMA\DoctrineTestBundle\PHPUnit\PHPUnitListener"/> - </listeners> - </phpunit> - -This bundle uses a clever trick to avoid side effects without sacrificing -performance: it begins a database transaction before every test and rolls it -back automatically after the test finishes to undo all changes. Read more in the -documentation of the `DAMADoctrineTestBundle`_. - -.. _doctrine-fixtures: - -Dummy Data Fixtures -------------------- - -Instead of using the real data from the production database, it's common to use -fake or dummy data in the test database. This is usually called *"fixtures data"* -and Doctrine provides a library to create and load them. Install it with: - -.. code-block:: terminal - - $ composer require --dev doctrine/doctrine-fixtures-bundle - -Then, use the ``make:fixtures`` command to generate an empty fixture class: - -.. code-block:: terminal - - $ php bin/console make:fixtures - - The class name of the fixtures to create (e.g. AppFixtures): - > ProductFixture - -Customize the new class to load ``Product`` objects into Doctrine:: - - // src/DataFixtures/ProductFixture.php - namespace App\DataFixtures; - - use App\Entity\Product; - use Doctrine\Bundle\FixturesBundle\Fixture; - use Doctrine\Persistence\ObjectManager; - - class ProductFixture extends Fixture - { - public function load(ObjectManager $manager) - { - $product = new Product(); - $product->setName('Priceless widget'); - $product->setPrice(14.50); - $product->setDescription('Ok, I guess it *does* have a price'); - $manager->persist($product); - - // add more products - - $manager->flush(); - } - } - -Empty the database and reload *all* the fixture classes with: - -.. code-block:: terminal - - $ php bin/console doctrine:fixtures:load - -For more information, read the `DoctrineFixturesBundle documentation`_. + The :ref:`main Testing guide <testing-databases>` describes how to use + and set-up a database for your automated tests. The contents of this + article show ways to test your Doctrine repositories. Mocking a Doctrine Repository in Unit Tests ------------------------------------------- @@ -249,6 +140,3 @@ so, get the entity manager via the service container as follows:: $this->entityManager = null; } } - -.. _`DAMADoctrineTestBundle`: https://github.com/dmaicher/doctrine-test-bundle -.. _`DoctrineFixturesBundle documentation`: https://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html diff --git a/testing/dom_crawler.rst b/testing/dom_crawler.rst new file mode 100644 index 00000000000..7b47487d09f --- /dev/null +++ b/testing/dom_crawler.rst @@ -0,0 +1,94 @@ +.. index:: + single: Tests; Crawler + +The DOM Crawler +=============== + +A Crawler instance is returned each time you make a request with the Client. +It allows you to traverse HTML or XML documents: select nodes, find links +and forms, and retrieve attributes or contents. + +Traversing +---------- + +Like jQuery, the Crawler has methods to traverse the DOM of an HTML/XML +document. For example, the following finds all ``input[type=submit]`` elements, +selects the last one on the page, and then selects its immediate parent element:: + + $newCrawler = $crawler->filter('input[type=submit]') + ->last() + ->parents() + ->first() + ; + +Many other methods are also available: + +``filter('h1.title')`` + Nodes that match the CSS selector. +``filterXpath('h1')`` + Nodes that match the XPath expression. +``eq(1)`` + Node for the specified index. +``first()`` + First node. +``last()`` + Last node. +``siblings()`` + Siblings. +``nextAll()`` + All following siblings. +``previousAll()`` + All preceding siblings. +``parents()`` + Returns the parent nodes. +``children()`` + Returns children nodes. +``reduce($lambda)`` + Nodes for which the callable does not return false. + +Since each of these methods returns a new ``Crawler`` instance, you can +narrow down your node selection by chaining the method calls:: + + $crawler + ->filter('h1') + ->reduce(function ($node, $i) { + if (!$node->attr('class')) { + return false; + } + }) + ->first() + ; + +.. tip:: + + Use the ``count()`` function to get the number of nodes stored in a Crawler: + ``count($crawler)`` + +Extracting Information +---------------------- + +The Crawler can extract information from the nodes:: + + // returns the attribute value for the first node + $crawler->attr('class'); + + // returns the node value for the first node + $crawler->text(); + + // returns the default text if the node does not exist + $crawler->text('Default text content'); + + // pass TRUE as the second argument of text() to remove all extra white spaces, including + // the internal ones (e.g. " foo\n bar baz \n " is returned as "foo bar baz") + $crawler->text(null, true); + + // extracts an array of attributes for all nodes + // (_text returns the node value) + // returns an array for each element in crawler, + // each with the value and href + $info = $crawler->extract(['_text', 'href']); + + // executes a lambda for each node and return an array of results + $data = $crawler->each(function ($node, $i) { + return $node->attr('href'); + }); diff --git a/testing/functional_tests_assertions.rst b/testing/functional_tests_assertions.rst deleted file mode 100644 index 457d8c39021..00000000000 --- a/testing/functional_tests_assertions.rst +++ /dev/null @@ -1,118 +0,0 @@ -.. index:: - single: Tests; Assertions - -Functional Test specific Assertions -=================================== - -When doing functional tests, sometimes you need to make complex assertions in -order to check whether the ``Request``, the ``Response`` or the ``Crawler`` -contain the expected information to make your test succeed. - -The following example uses plain PHPUnit to assert that the response redirects -to a certain URL:: - - $this->assertSame(301, $client->getResponse()->getStatusCode()); - $this->assertSame('https://example.com', $client->getResponse()->headers->get('Location')); - -This is the same example using the assertions provided by Symfony:: - - $this->assertResponseRedirects('https://example.com', 301); - -Assertions Reference ---------------------- - -Response -~~~~~~~~ - -.. note:: - - The following assertions only work if a request has been made with the - ``Client`` in a test case extending the ``WebTestCase`` class. - -- ``assertResponseIsSuccessful()`` -- ``assertResponseStatusCodeSame()`` -- ``assertResponseRedirects()`` -- ``assertResponseHasHeader()`` -- ``assertResponseNotHasHeader()`` -- ``assertResponseHeaderSame()`` -- ``assertResponseHeaderNotSame()`` -- ``assertResponseHasCookie()`` -- ``assertResponseNotHasCookie()`` -- ``assertResponseCookieValueSame()`` - -Request -~~~~~~~ - -.. note:: - - The following assertions only work if a request has been made with the - ``Client`` in a test case extending the ``WebTestCase`` class. - -- ``assertRequestAttributeValueSame()`` -- ``assertRouteSame()`` - -Browser -~~~~~~~ - -.. note:: - - The following assertions only work if a request has been made with the - ``Client`` in a test case extending the ``WebTestCase`` class. - -- ``assertBrowserHasCookie()`` -- ``assertBrowserNotHasCookie()`` -- ``assertBrowserCookieValueSame()`` - -Crawler -~~~~~~~ - -.. note:: - - The following assertions only work if a request has been made with the - ``Client`` in a test case extending the ``WebTestCase`` class. In addition, - they are not available when using `symfony/panther`_ for end-to-end testing. - -- ``assertSelectorExists()`` -- ``assertSelectorNotExists()`` -- ``assertSelectorTextContains()`` (note: it only checks the first selector occurrence) -- ``assertSelectorTextSame()`` (note: it only checks the first selector occurrence) -- ``assertSelectorTextNotContains()`` (note: it only checks the first selector occurrence) -- ``assertPageTitleSame()`` -- ``assertPageTitleContains()`` -- ``assertInputValueSame()`` -- ``assertInputValueNotSame()`` -- ``assertCheckboxChecked()`` -- ``assertCheckboxNotChecked()`` -- ``assertFormValue()`` -- ``assertNoFormValue()`` - -.. versionadded:: 5.2 - - The ``assertCheckboxChecked()``, ``assertCheckboxNotChecked()``, - ``assertFormValue()`` and ``assertNoFormValue()`` methods were introduced - in Symfony 5.2. - -Mailer -~~~~~~ - -.. versionadded:: 5.1 - - Starting from Symfony 5.1, the following assertions no longer require to make - a request with the ``Client`` in a test case extending the ``WebTestCase`` class. - -- ``assertEmailCount()`` -- ``assertQueuedEmailCount()`` -- ``assertEmailIsQueued()`` -- ``assertEmailIsNotQueued()`` -- ``assertEmailAttachementCount()`` -- ``assertEmailTextBodyContains()`` -- ``assertEmailTextBodyNotContains()`` -- ``assertEmailHtmlBodyContains()`` -- ``assertEmailHtmlBodyNotContains()`` -- ``assertEmailHasHeader()`` -- ``assertEmailNotHasHeader()`` -- ``assertEmailHeaderSame()`` -- ``assertEmailHeaderNotSame()`` -- ``assertEmailAddressContains()`` - -.. _`symfony/panther`: https://github.com/symfony/panther diff --git a/testing/profiling.rst b/testing/profiling.rst index d3fa71f8e76..db7714b9d1f 100644 --- a/testing/profiling.rst +++ b/testing/profiling.rst @@ -47,15 +47,15 @@ tests significantly. That's why Symfony disables it by default: .. code-block:: php // config/packages/test/web_profiler.php + use Symfony\Config\FrameworkConfig; - // ... - $container->loadFromExtension('framework', [ + return static function (FrameworkConfig $framework) { // ... - 'profiler' => [ - 'enabled' => true, - 'collect' => false, - ], - ]); + $framework->profiler() + ->enabled(true) + ->collect(false) + ; + }; Setting ``collect`` to ``true`` enables the profiler for all tests. However, if you need the profiler only in a few tests, you can keep it disabled globally and @@ -71,7 +71,7 @@ provided by the collectors obtained through the ``$client->getProfile()`` call:: // tests/Controller/LuckyControllerTest.php namespace App\Tests\Controller; - + use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class LuckyControllerTest extends WebTestCase diff --git a/translation.rst b/translation.rst index 4c4b4b9a07b..53e0ae45d4a 100644 --- a/translation.rst +++ b/translation.rst @@ -92,11 +92,16 @@ are located: .. code-block:: php // config/packages/translation.php - $container->loadFromExtension('framework', [ - 'default_locale' => 'en', - 'translator' => ['default_path' => '%kernel.project_dir%/translations'], + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - ]); + $framework + ->defaultLocale('en') + ->translator() + ->defaultPath('%kernel.project_dir%/translations') + ; + }; The locale used in translations is the one stored on the request. This is typically set via a ``_locale`` attribute on your routes (see :ref:`translation-locale-url`). @@ -141,7 +146,7 @@ different formats: .. code-block:: xml <!-- translations/messages.fr.xlf --> - <?xml version="1.0"?> + <?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> @@ -292,6 +297,24 @@ To manage these situations, Symfony follows the `ICU MessageFormat`_ syntax by using PHP's :phpclass:`MessageFormatter` class. Read more about this in :doc:`/translation/message_format`. +.. tip:: + + If you don't use the ICU MessageFormat syntax in your translation files, + pass a parameter named "%count%" to select the best plural form of the message: + + .. code-block:: twig + + {{ message|trans({'%name%': '...', '%count%': 1}, 'app') }} + + The ``message`` variable must include all the different versions of this + message based on the value of the ``count`` parameter. For example: + + .. code-block:: text + + {0}%name% has no apples|{1}%name% has one apple|]1,Inf[ %name% has %count% apples + +.. _translatable-objects: + Translatable Objects -------------------- @@ -337,14 +360,92 @@ Translations in Templates ------------------------- Most of the time, translation occurs in templates. Symfony provides native -support for both Twig and PHP templates: +support for both Twig and PHP templates. -.. code-block:: html+twig +.. _translation-tags: + +Using Twig Tags +~~~~~~~~~~~~~~~ + +Symfony provides a specialized Twig tag ``trans`` to help with message +translation of *static blocks of text*: + +.. code-block:: twig + + {% trans %}Hello %name%{% endtrans %} + +.. caution:: + + The ``%var%`` notation of placeholders is required when translating in + Twig templates using the tag. + +.. tip:: + + If you need to use the percent character (``%``) in a string, escape it by + doubling it: ``{% trans %}Percent: %percent%%%{% endtrans %}`` + +You can also specify the message domain and pass some additional variables: + +.. code-block:: twig + + {% trans with {'%name%': 'Fabien'} from 'app' %}Hello %name%{% endtrans %} + + {% trans with {'%name%': 'Fabien'} from 'app' into 'fr' %}Hello %name%{% endtrans %} + +.. _translation-filters: + +Using Twig Filters +~~~~~~~~~~~~~~~~~~ + +The ``trans`` filter can be used to translate *variable texts* and complex expressions: + +.. code-block:: twig - <h1>{% trans %}Symfony is great!{% endtrans %}</h1> + {{ message|trans }} -Read :doc:`/translation/templates` for more information about the Twig tags and -filters for translation. + {{ message|trans({'%name%': 'Fabien'}, 'app') }} + +.. tip:: + + Using the translation tags or filters have the same effect, but with + one subtle difference: automatic output escaping is only applied to + translations using a filter. In other words, if you need to be sure + that your translated message is *not* output escaped, you must apply + the ``raw`` filter after the translation filter: + + .. code-block:: html+twig + + {# text translated between tags is never escaped #} + {% trans %} + <h3>foo</h3> + {% endtrans %} + + {% set message = '<h3>foo</h3>' %} + + {# strings and variables translated via a filter are escaped by default #} + {{ message|trans|raw }} + {{ '<h3>bar</h3>'|trans|raw }} + +.. tip:: + + You can set the translation domain for an entire Twig template with a single tag: + + .. code-block:: twig + + {% trans_default_domain 'app' %} + + Note that this only influences the current template, not any "included" + template (in order to avoid side effects). + +PHP Templates +~~~~~~~~~~~~~ + +The translator service is accessible in PHP templates through the +``translator`` helper: + +.. code-block:: html+php + + <?= $view['translator']->trans('Symfony is great') ?> Forcing the Translator Locale ----------------------------- @@ -365,27 +466,41 @@ Extracting Translation Contents and Updating Catalogs Automatically The most time-consuming tasks when translating an application is to extract all the template contents to be translated and to keep all the translation files in -sync. Symfony includes a command called ``translation:update`` that helps you +sync. Symfony includes a command called ``translation:extract`` that helps you with these tasks: .. code-block:: terminal # shows all the messages that should be translated for the French language - $ php bin/console translation:update --dump-messages fr + $ php bin/console translation:extract --dump-messages fr # updates the French translation files with the missing strings for that locale - $ php bin/console translation:update --force fr + $ php bin/console translation:extract --force fr # check out the command help to see its options (prefix, output format, domain, sorting, etc.) - $ php bin/console translation:update --help + $ php bin/console translation:extract --help + +.. deprecated:: 5.4 -The ``translation:update`` command looks for missing translations in: + In previous Symfony versions, the ``translation:extract`` command was called + ``translation:update``, but that name was deprecated in Symfony 5.4 + and it will be removed in Symfony 6.0. + +The ``translation:extract`` command looks for missing translations in: * Templates stored in the ``templates/`` directory (or any other directory defined in the :ref:`twig.default_path <config-twig-default-path>` and :ref:`twig.paths <config-twig-paths>` config options); * Any PHP file/class that injects or :doc:`autowires </service_container/autowiring>` - the ``translator`` service and makes calls to the ``trans()`` function. + the ``translator`` service and makes calls to the ``trans()`` method. +* Any PHP file/class stored in the ``src/`` directory that creates + :ref:`translatable-objects` using the constructor or the ``t()`` method or calls + the ``trans()`` method. + +.. versionadded:: 5.3 + + Support for extracting Translatable objects has been introduced in + Symfony 5.3. .. _translation-resource-locations: @@ -483,13 +598,13 @@ if you're generating translations with specialized programs or teams. .. code-block:: php // config/packages/translation.php - $container->loadFromExtension('framework', [ - 'translator' => [ - 'paths' => [ - '%kernel.project_dir%/custom/path/to/translations', - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->translator() + ->paths(['%kernel.project_dir%/custom/path/to/translations']) + ; + }; .. note:: @@ -498,6 +613,173 @@ if you're generating translations with specialized programs or teams. :class:`Symfony\\Component\\Translation\\Loader\\LoaderInterface` interface. See the :ref:`dic-tags-translation-loader` tag for more information. +.. _translation-providers: + +Translation Providers +--------------------- + +.. versionadded:: 5.3 + + Translation providers were introduced in Symfony 5.3. + +When using external translators to translate your application, you must send +them the new contents to translate frequently and merge the results back in the +application. + +Instead of doing this manually, Symfony provides integration with several +third-party translation services (e.g. Crowdin or Lokalise). You can upload and +download (called "push" and "pull") translations to/from these services and +merge the results automatically in the application. + +Installing and Configuring a Third Party Provider +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before pushing/pulling translations to a third-party provider, you must install +the package that provides integration with that provider: + +==================== =========================================================== +Provider Install with +==================== =========================================================== +Crowdin ``composer require symfony/crowdin-translation-provider`` +Loco (localise.biz) ``composer require symfony/loco-translation-provider`` +Lokalise ``composer require symfony/lokalise-translation-provider`` +==================== =========================================================== + +Each library includes a :ref:`Symfony Flex recipe <symfony-flex>` that will add +a configuration example to your ``.env`` file. For example, suppose you want to +use Loco. First, install it: + +.. code-block:: terminal + + $ composer require symfony/loco-translation-provider + +You'll now have a new line in your ``.env`` file that you can uncomment: + +.. code-block:: env + + # .env + LOCO_DSN=loco://API_KEY@default + +The ``LOCO_DSN`` isn't a *real* address: it's a convenient format that offloads +most of the configuration work to Symfony. The ``loco`` scheme activates the +Loco provider that you just installed, which knows all about how to push and +pull translations via Loco. The *only* part you need to change is the +``API_KEY`` placeholder. + +This table shows the full list of available DSN formats for each provider: + +===================== ========================================================== +Provider DSN +===================== ========================================================== +Crowdin crowdin://PROJECT_ID:API_TOKEN@ORGANIZATION_DOMAIN.default +Loco (localise.biz) loco://API_KEY@default +Lokalise lokalise://PROJECT_ID:API_KEY@default +===================== ========================================================== + +To enable a translation provider, add the correct DSN in your ``.env`` file and +configure the ``providers`` option: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/translation.yaml + framework: + translator: + providers: + loco: + dsn: '%env(LOCO_DSN)%' + domains: ['messages'] + locales: ['en', 'fr'] + + .. code-block:: xml + + <!-- config/packages/translation.xml --> + <?xml version="1.0" encoding="UTF-8" ?> + <container xmlns="http://symfony.com/schema/dic/services" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:framework="http://symfony.com/schema/dic/symfony" + xsi:schemaLocation="http://symfony.com/schema/dic/services + https://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/symfony + https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> + + <framework:config> + <framework:translator> + <framework:provider name="loco" dsn="%env(LOCO_DSN)%"> + <framework:domain>messages</framework:domain> + <!-- ... --> + <framework:locale>en</framework:locale> + <framework:locale>fr</framework:locale> + <!-- ... --> + </framework:provider> + </framework:translator> + </framework:config> + </container> + + .. code-block:: php + + # config/packages/translation.php + $container->loadFromExtension('framework', [ + 'translator' => [ + 'providers' => [ + 'loco' => [ + 'dsn' => '%env(LOCO_DSN)%', + 'domains' => ['messages'], + 'locales' => ['en', 'fr'], + ], + ], + ], + ]); + +.. tip:: + + If you use Lokalise as provider and a locale format following the `ISO 639-1`_ (e.g., "en" or "fr"), + you have to set the `Custom Language Name setting`_ in Lokalise for each of your locales, + in order to override the default value (which follow the `ISO 639-1`_ succeeded by a sub-code + in capital letters that specifies the national variety (e.g., "GB" or "US" according to `ISO 3166-1 alpha-2`_)). + +Pushing and Pulling Translations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +After configuring the credentials to access the translation provider, you can +now use the following commands to push (upload) and pull (download) translations: + +.. code-block:: terminal + + # push all local translations to the Loco provider for the locales and domains + # configured in config/packages/translation.yaml file. + # it will update existing translations already on the provider. + $ php bin/console translation:push loco --force + + # push new local translations to the Loco provider for the French locale + # and the validators domain. + # it will **not** update existing translations already on the provider. + $ php bin/console translation:push loco --locales fr --domain validators + + # push new local translations and delete provider's translations that not + # exists anymore in local files for the French locale and the validators domain. + # it will **not** update existing translations already on the provider. + $ php bin/console translation:push loco --delete-missing --locales fr --domain validators + + # check out the command help to see its options (format, domains, locales, etc.) + $ php bin/console translation:push --help + +.. code-block:: terminal + + # pull all provider's translations to local files for the locales and domains + # configured in config/packages/translation.yaml file. + # it will overwrite completely your local files. + $ php bin/console translation:pull loco --force + + # pull new translations from the Loco provider to local files for the French + # locale and the validators domain. + # it will **not** overwrite your local files, only add new translations. + $ php bin/console translation:pull loco --locales fr --domain validators + + # check out the command help to see its options (format, domains, locales, intl-icu, etc.) + $ php bin/console translation:pull --help + Handling the User's Locale -------------------------- @@ -559,10 +841,14 @@ checks translation resources for several locales: .. code-block:: php // config/packages/translation.php - $container->loadFromExtension('framework', [ - 'translator' => ['fallbacks' => ['en']], - // ... - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + // ... + $framework->translator() + ->fallbacks(['en']) + ; + }; .. note:: @@ -608,15 +894,15 @@ Learn more :maxdepth: 1 translation/message_format - translation/templates translation/locale translation/debug translation/lint translation/xliff .. _`i18n`: https://en.wikipedia.org/wiki/Internationalization_and_localization -.. _`ICU MessageFormat`: http://userguide.icu-project.org/formatparse/messages +.. _`ICU MessageFormat`: https://unicode-org.github.io/icu/userguide/format_parse/messages/ .. _`ISO 3166-1 alpha-2`: https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes .. _`ISO 639-1`: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes -.. _`Translatable Extension`: http://atlantic18.github.io/DoctrineExtensions/doc/translatable.html +.. _`Translatable Extension`: https://github.com/doctrine-extensions/DoctrineExtensions/blob/main/doc/translatable.md .. _`Translatable Behavior`: https://github.com/KnpLabs/DoctrineBehaviors +.. _`Custom Language Name setting`: https://docs.lokalise.com/en/articles/1400492-uploading-files#custom-language-codes diff --git a/translation/debug.rst b/translation/debug.rst index 74e52783245..e0668c4ae3e 100644 --- a/translation/debug.rst +++ b/translation/debug.rst @@ -19,9 +19,11 @@ command helps you to find these missing or unused translation messages templates .. caution:: - The extractors can't find messages translated outside templates, like form - labels or controllers. Dynamic translations using variables or expressions - in templates are not detected either: + The extractors can't find messages translated outside templates (like form + labels or controllers) unless using :ref:`translatable-objects` or calling + the ``trans()`` method on a translator (since Symfony 5.3). Dynamic + translations using variables or expressions in templates are not + detected either: .. code-block:: twig @@ -39,7 +41,7 @@ you've already setup some translations for the ``fr`` locale: .. code-block:: xml <!-- translations/messages.fr.xlf --> - <?xml version="1.0"?> + <?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> @@ -70,7 +72,7 @@ and for the ``en`` locale: .. code-block:: xml <!-- translations/messages.en.xlf --> - <?xml version="1.0"?> + <?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> diff --git a/translation/lint.rst b/translation/lint.rst index d9129a79108..e6987538aeb 100644 --- a/translation/lint.rst +++ b/translation/lint.rst @@ -33,6 +33,19 @@ The linter results can be exported to JSON using the ``--format`` option: $ php bin/console lint:yaml translations/ --format=json $ php bin/console lint:xliff translations/ --format=json +When running these linters inside `GitHub Actions`_, the output is automatically +adapted to the format required by GitHub, but you can force that format too: + +.. code-block:: terminal + + $ php bin/console lint:yaml translations/ --format=github + $ php bin/console lint:xliff translations/ --format=github + +.. versionadded:: 5.3 + + The ``github`` output format was introduced in Symfony 5.3 for ``lint:yaml`` + and in Symfony 5.4 for ``lint:xliff``. + .. tip:: The Yaml component provides a stand-alone ``yaml-lint`` binary allowing @@ -45,3 +58,5 @@ The linter results can be exported to JSON using the ``--format`` option: .. versionadded:: 5.1 The ``yaml-lint`` binary was introduced in Symfony 5.1. + +.. _`GitHub Actions`: https://docs.github.com/en/free-pro-team@latest/actions diff --git a/translation/locale.rst b/translation/locale.rst index 87f973a146a..79a9d45ce39 100644 --- a/translation/locale.rst +++ b/translation/locale.rst @@ -65,7 +65,7 @@ A better policy is to include the locale in the URL using the .. configuration-block:: .. code-block:: php-annotations - + // src/Controller/ContactController.php namespace App\Controller; @@ -177,6 +177,8 @@ the framework: .. code-block:: php // config/packages/translation.php - $container->loadFromExtension('framework', [ - 'default_locale' => 'en', - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework->defaultLocale('en'); + }; diff --git a/translation/message_format.rst b/translation/message_format.rst index 8f8fea5296c..b5a350acfcf 100644 --- a/translation/message_format.rst +++ b/translation/message_format.rst @@ -47,7 +47,7 @@ The basic usage of the MessageFormat allows you to use placeholders (called .. code-block:: xml <!-- translations/messages+intl-icu.en.xlf --> - <?xml version="1.0"?> + <?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> @@ -108,7 +108,7 @@ typical usage of this is gender: .. code-block:: xml <!-- translations/messages+intl-icu.en.xlf --> - <?xml version="1.0"?> + <?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> @@ -173,6 +173,22 @@ you to use literal text in the select statements: readable for translators and, as you can see in the ``other`` case, other parts of the sentence might be influenced by the variables. +.. tip:: + + It's possible to translate ICU MessageFormat messages directly in code, + without having to define them in any file:: + + $invitation = '{organizer_gender, select, + female {{organizer_name} has invited you for her party!} + male {{organizer_name} has invited you for his party!} + other {{organizer_name} have invited you for their party!} + }'; + + // prints "Ryan has invited you for his party!" + echo $translator->trans($invitation, [ + 'organizer_name' => 'Ryan', + 'organizer_gender' => 'male', + ]); .. _component-translation-pluralization: @@ -198,7 +214,7 @@ handle pluralization in your messages (e.g. ``There are 3 apples`` vs .. code-block:: xml <!-- translations/messages+intl-icu.en.xlf --> - <?xml version="1.0"?> + <?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> @@ -255,27 +271,24 @@ Usage of this string is the same as with variables and select:: .. code-block:: text {gender_of_host, select, - female { - {num_guests, plural, offset:1 + female {{num_guests, plural, offset:1 =0 {{host} does not give a party.} =1 {{host} invites {guest} to her party.} =2 {{host} invites {guest} and one other person to her party.} - other {{host} invites {guest} and # other people to her party.}} - } - male { - {num_guests, plural, offset:1 + other {{host} invites {guest} and # other people to her party.} + }} + male {{num_guests, plural, offset:1 =0 {{host} does not give a party.} =1 {{host} invites {guest} to his party.} =2 {{host} invites {guest} and one other person to his party.} - other {{host} invites {guest} and # other people to his party.}} - } - other { - {num_guests, plural, offset:1 + other {{host} invites {guest} and # other people to his party.} + }} + other {{num_guests, plural, offset:1 =0 {{host} does not give a party.} =1 {{host} invites {guest} to their party.} =2 {{host} invites {guest} and one other person to their party.} - other {{host} invites {guest} and # other people to their party.}} - } + other {{host} invites {guest} and # other people to their party.} + }} } .. sidebar:: Using Ranges in Messages @@ -329,7 +342,7 @@ Similar to ``plural``, ``selectordinal`` allows you to use numbers as ordinal sc .. code-block:: xml <!-- translations/messages+intl-icu.en.xlf --> - <?xml version="1.0"?> + <?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> @@ -393,7 +406,7 @@ using the :phpclass:`IntlDateFormatter`: .. code-block:: xml <!-- translations/messages+intl-icu.en.xlf --> - <?xml version="1.0"?> + <?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> @@ -435,7 +448,7 @@ The ``number`` formatter allows you to format numbers using Intl's :phpclass:`Nu .. code-block:: xml <!-- translations/messages+intl-icu.en.xlf --> - <?xml version="1.0"?> + <?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> @@ -473,7 +486,7 @@ The ``number`` formatter allows you to format numbers using Intl's :phpclass:`Nu echo $translator->trans('value_of_object', ['value' => 9988776.65]); .. _`online editor`: http://format-message.github.io/icu-message-format-for-translators/ -.. _`ICU MessageFormat`: http://userguide.icu-project.org/formatparse/messages +.. _`ICU MessageFormat`: https://unicode-org.github.io/icu/userguide/format_parse/messages/ .. _`switch statement`: https://www.php.net/control-structures.switch .. _`Language Plural Rules`: http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html .. _`constants defined by the IntlDateFormatter class`: https://www.php.net/manual/en/class.intldateformatter.php diff --git a/translation/templates.rst b/translation/templates.rst deleted file mode 100644 index b820bfb0fba..00000000000 --- a/translation/templates.rst +++ /dev/null @@ -1,89 +0,0 @@ -Using Translation in Templates -============================== - -Twig Templates --------------- - -.. _translation-tags: - -Using Twig Tags -~~~~~~~~~~~~~~~ - -Symfony provides a specialized Twig tag ``trans`` to help with message -translation of *static blocks of text*: - -.. code-block:: twig - - {% trans %}Hello %name%{% endtrans %} - -.. caution:: - - The ``%var%`` notation of placeholders is required when translating in - Twig templates using the tag. - -.. tip:: - - If you need to use the percent character (``%``) in a string, escape it by - doubling it: ``{% trans %}Percent: %percent%%%{% endtrans %}`` - -You can also specify the message domain and pass some additional variables: - -.. code-block:: twig - - {% trans with {'%name%': 'Fabien'} from 'app' %}Hello %name%{% endtrans %} - - {% trans with {'%name%': 'Fabien'} from 'app' into 'fr' %}Hello %name%{% endtrans %} - -.. _translation-filters: - -Using Twig Filters -~~~~~~~~~~~~~~~~~~ - -The ``trans`` filter can be used to translate *variable texts* and complex expressions: - -.. code-block:: twig - - {{ message|trans }} - - {{ message|trans({'%name%': 'Fabien'}, 'app') }} - -.. tip:: - - Using the translation tags or filters have the same effect, but with - one subtle difference: automatic output escaping is only applied to - translations using a filter. In other words, if you need to be sure - that your translated message is *not* output escaped, you must apply - the ``raw`` filter after the translation filter: - - .. code-block:: html+twig - - {# text translated between tags is never escaped #} - {% trans %} - <h3>foo</h3> - {% endtrans %} - - {% set message = '<h3>foo</h3>' %} - - {# strings and variables translated via a filter are escaped by default #} - {{ message|trans|raw }} - {{ '<h3>bar</h3>'|trans|raw }} - -.. tip:: - - You can set the translation domain for an entire Twig template with a single tag: - - .. code-block:: twig - - {% trans_default_domain 'app' %} - - Note that this only influences the current template, not any "included" - template (in order to avoid side effects). - -PHP Templates -------------- - -The translator service is accessible in PHP templates through the -``translator`` helper:: - - <?= $view['translator']->trans('Symfony is great') ?> - diff --git a/translation/xliff.rst b/translation/xliff.rst index a3c3daab43e..d5fb90e3586 100644 --- a/translation/xliff.rst +++ b/translation/xliff.rst @@ -19,7 +19,7 @@ loaded/dumped inside a Symfony application: .. code-block:: xml - <?xml version="1.0" encoding="UTF-8"?> + <?xml version="1.0" encoding="UTF-8" ?> <xliff xmlns="urn:oasis:names:tc:xliff:document:2.1" version="2.1" srcLang="fr-FR" trgLang="en-US"> <file id="messages.en_US"> diff --git a/validation.rst b/validation.rst index 837514f55c5..e7288763de6 100644 --- a/validation.rst +++ b/validation.rst @@ -11,6 +11,10 @@ into a database or passed to a web service. Symfony provides a `Validator`_ component to handle this for you. This component is based on the `JSR303 Bean Validation specification`_. +.. index:: + pair: Validation; Installation + pair: Validation; Configuration + Installation ------------ @@ -21,6 +25,12 @@ install the validator before using it: $ composer require symfony/validator doctrine/annotations +.. note:: + + If your application doesn't use Symfony Flex, you might need to do some + manual configuration to enable validation. Check out the + :ref:`Validation configuration reference <reference-validation>`. + .. index:: single: Validation; The basics @@ -47,7 +57,7 @@ order to be valid. These rules are usually defined using PHP code or annotations but they can also be defined as ``.yaml`` or ``.xml`` files inside the ``config/validator/`` directory: -For example, to guarantee that the ``$name`` property is not empty, add the +For example, to indicate that the ``$name`` property must not be empty, add the following: .. configuration-block:: @@ -68,6 +78,20 @@ following: private $name; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + // ... + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\NotBlank] + private $name; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -110,6 +134,11 @@ following: } } +Adding this configuration by itself does not yet guarantee that the value will +not be blank; you can still set it to a blank value if you want. +To actually guarantee that the value adheres to the constraint, the object must +be passed to the validator service to be checked. + .. tip:: Symfony's validator uses PHP reflection, as well as *"getter"* methods, to @@ -164,7 +193,7 @@ message: .. code-block:: text Object(App\Entity\Author).name: - This value should not be blank + This value should not be blank. If you insert a value into the ``name`` property, the happy success message will appear. @@ -202,88 +231,29 @@ Inside the template, you can output the list of errors exactly as needed: a :class:`Symfony\\Component\\Validator\\ConstraintViolation` object. .. index:: - pair: Validation; Configuration + single: Validation; Callables -Configuration -------------- +Validation Callables +~~~~~~~~~~~~~~~~~~~~ -Before using the Symfony validator, make sure it's enabled in the main config -file: +The ``Validation`` also allows you to create a closure to validate values +against a set of constraints (useful for example when +:ref:`validating Console command answers <console-validate-question-answer>` or +when :ref:`validating OptionsResolver values <optionsresolver-validate-value>`): -.. configuration-block:: +:method:`Symfony\\Component\\Validator\\Validation::createCallable` + This returns a closure that throws ``ValidationFailedException`` when the + constraints aren't matched. +:method:`Symfony\\Component\\Validator\\Validation::createIsValidCallable` + This returns a closure that returns ``false`` when the constraints aren't matched. - .. code-block:: yaml - - # config/packages/framework.yaml - framework: - validation: { enabled: true } +.. versionadded:: 5.1 - .. code-block:: xml + ``Validation::createCallable()`` was introduced in Symfony 5.1. - <!-- config/packages/framework.xml --> - <?xml version="1.0" encoding="UTF-8" ?> - <container xmlns="http://symfony.com/schema/dic/services" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:framework="http://symfony.com/schema/dic/symfony" - xsi:schemaLocation="http://symfony.com/schema/dic/services - https://symfony.com/schema/dic/services/services-1.0.xsd - http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> +.. versionadded:: 5.3 - <framework:config> - <framework:validation enabled="true"/> - </framework:config> - </container> - - .. code-block:: php - - // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'validation' => [ - 'enabled' => true, - ], - ]); - -Besides, if you plan to use annotations to configure validation, replace the -previous configuration by the following: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/framework.yaml - framework: - validation: { enable_annotations: true } - - .. code-block:: xml - - <!-- config/packages/framework.xml --> - <?xml version="1.0" encoding="UTF-8" ?> - <container xmlns="http://symfony.com/schema/dic/services" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:framework="http://symfony.com/schema/dic/symfony" - xsi:schemaLocation="http://symfony.com/schema/dic/services - https://symfony.com/schema/dic/services/services-1.0.xsd - http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - - <framework:config> - <framework:validation enable-annotations="true"/> - </framework:config> - </container> - - .. code-block:: php - - // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'validation' => [ - 'enable_annotations' => true, - ], - ]); - -.. tip:: - - When using PHP, YAML, and XML files instead of annotations, Symfony looks - for by default in the ``config/validator/`` directory, but you can configure - other directories with the :ref:`validation.mapping.paths <reference-validation-mapping>` option. + ``Validation::createIsValidCallable()`` was introduced in Symfony 5.3. .. index:: single: Validation; Constraints @@ -298,7 +268,7 @@ rules). In order to validate an object, simply map one or more constraints to its class and then pass it to the ``validator`` service. Behind the scenes, a constraint is simply a PHP object that makes an assertive -statement. In real life, a constraint could be: 'The cake must not be burned'. +statement. In real life, a constraint could be: ``'The cake must not be burned'``. In Symfony, constraints are similar: they are assertions that a condition is true. Given a value, a constraint will tell you if that value adheres to the rules of the constraint. @@ -342,7 +312,7 @@ literature genre mostly associated with the author, which can be set to either { /** * @Assert\Choice( - * choices = { "fiction", "non-fiction" }, + * choices = {"fiction", "non-fiction"}, * message = "Choose a valid genre." * ) */ @@ -351,6 +321,25 @@ literature genre mostly associated with the author, which can be set to either // ... } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + // ... + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Choice( + choices: ['fiction', 'non-fiction'], + message: 'Choose a valid genre.', + )] + private $genre; + + // ... + } + .. code-block:: yaml # config/validator/validation.yaml @@ -437,6 +426,22 @@ options can be specified in this way. // ... } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + // ... + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\Choice(['fiction', 'non-fiction'])] + private $genre; + + // ... + } + .. code-block:: yaml # config/validator/validation.yaml @@ -509,7 +514,7 @@ of the form fields:: $builder ->add('myField', TextType::class, [ 'required' => true, - 'constraints' => [new Length(['min' => 3])] + 'constraints' => [new Length(['min' => 3])], ]) ; } @@ -559,6 +564,20 @@ class to have at least 3 characters. private $firstName; } + .. code-block:: php-attributes + + // src/Entity/Author.php + + // ... + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\NotBlank] + #[Assert\Length(min: 3)] + private $firstName; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -606,11 +625,17 @@ class to have at least 3 characters. $metadata->addPropertyConstraint('firstName', new Assert\NotBlank()); $metadata->addPropertyConstraint( 'firstName', - new Assert\Length(["min" => 3]) + new Assert\Length(['min' => 3]) ); } } +.. caution:: + + The validator will use a value ``null`` if a typed property is uninitialized. + This can cause unexpected behavior if the property holds a value when initialized. + In order to avoid this, make sure all properties are initialized before validating them. + .. index:: single: Validation; Getter constraints @@ -649,6 +674,23 @@ this method must return ``true``: } } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + // ... + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\IsTrue(message: 'The password cannot match your first name')] + public function isPasswordSafe() + { + // ... return true or false + } + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/validation/custom_constraint.rst b/validation/custom_constraint.rst index a569e5c6bfa..07fc8c85a73 100644 --- a/validation/custom_constraint.rst +++ b/validation/custom_constraint.rst @@ -1,7 +1,7 @@ .. index:: single: Validation; Custom constraints -How to Create a custom Validation Constraint +How to Create a Custom Validation Constraint ============================================ You can create a custom constraint by extending the base constraint class, @@ -12,27 +12,47 @@ alphanumeric characters. Creating the Constraint Class ----------------------------- -First you need to create a Constraint class and extend :class:`Symfony\\Component\\Validator\\Constraint`:: +First you need to create a Constraint class and extend :class:`Symfony\\Component\\Validator\\Constraint`: - // src/Validator/Constraints/ContainsAlphanumeric.php - namespace App\Validator\Constraints; +.. configuration-block:: - use Symfony\Component\Validator\Constraint; + .. code-block:: php-annotations - /** - * @Annotation - */ - class ContainsAlphanumeric extends Constraint - { - public $message = 'The string "{{ string }}" contains an illegal character: it can only contain letters or numbers.'; - } + // src/Validator/ContainsAlphanumeric.php + namespace App\Validator; + + use Symfony\Component\Validator\Constraint; + + /** + * @Annotation + */ + class ContainsAlphanumeric extends Constraint + { + public $message = 'The string "{{ string }}" contains an illegal character: it can only contain letters or numbers.'; + public $mode = 'strict'; // If the constraint has configuration options, define them as public properties + } + + .. code-block:: php-attributes -.. note:: + // src/Validator/ContainsAlphanumeric.php + namespace App\Validator; - The ``@Annotation`` annotation is necessary for this new constraint in - order to make it available for use in classes via annotations. - Options for your constraint are represented as public properties on the - constraint class. + use Symfony\Component\Validator\Constraint; + + #[\Attribute] + class ContainsAlphanumeric extends Constraint + { + public $message = 'The string "{{ string }}" contains an illegal character: it can only contain letters or numbers.'; + } + +Add ``@Annotation`` or ``#[\Attribute]`` to the constraint class if you want to +use it as an annotation/attribute in other classes. + +.. versionadded:: 5.2 + + The ability to use PHP attributes to configure constraints was introduced in + Symfony 5.2. Prior to this, Doctrine Annotations were the only way to + annotate constraints. Creating the Validator itself ----------------------------- @@ -54,8 +74,8 @@ when actually performing the validation. The validator class only has one required method ``validate()``:: - // src/Validator/Constraints/ContainsAlphanumericValidator.php - namespace App\Validator\Constraints; + // src/Validator/ContainsAlphanumericValidator.php + namespace App\Validator; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; @@ -71,7 +91,7 @@ The validator class only has one required method ``validate()``:: } // custom constraints should ignore null and empty values to allow - // other constraints (NotBlank, NotNull, etc.) take care of that + // other constraints (NotBlank, NotNull, etc.) to take care of that if (null === $value || '' === $value) { return; } @@ -83,6 +103,11 @@ The validator class only has one required method ``validate()``:: // separate multiple types using pipes // throw new UnexpectedValueException($value, 'string|int'); } + + // access your configuration options like this: + if ('strict' === $constraint->mode) { + // ... + } if (!preg_match('/^[a-zA-Z0-9]+$/', $value, $matches)) { // the argument must be a string or an object implementing __toString() @@ -112,7 +137,7 @@ You can use custom validators like the ones provided by Symfony itself: // src/Entity/AcmeEntity.php namespace App\Entity; - use App\Validator\Constraints as AcmeAssert; + use App\Validator as AcmeAssert; use Symfony\Component\Validator\Constraints as Assert; class AcmeEntity @@ -121,13 +146,32 @@ You can use custom validators like the ones provided by Symfony itself: /** * @Assert\NotBlank - * @AcmeAssert\ContainsAlphanumeric + * @AcmeAssert\ContainsAlphanumeric(mode="loose") */ protected $name; // ... } + .. code-block:: php-attributes + + // src/Entity/AcmeEntity.php + namespace App\Entity; + + use App\Validator as AcmeAssert; + use Symfony\Component\Validator\Constraints as Assert; + + class AcmeEntity + { + // ... + + #[Assert\NotBlank] + #[AcmeAssert\ContainsAlphanumeric(options: ['mode' => 'loose'])] + protected $name; + + // ... + } + .. code-block:: yaml # config/validator/validation.yaml @@ -135,7 +179,7 @@ You can use custom validators like the ones provided by Symfony itself: properties: name: - NotBlank: ~ - - App\Validator\Constraints\ContainsAlphanumeric: ~ + - App\Validator\ContainsAlphanumeric: ~ .. code-block:: xml @@ -148,7 +192,7 @@ You can use custom validators like the ones provided by Symfony itself: <class name="App\Entity\AcmeEntity"> <property name="name"> <constraint name="NotBlank"/> - <constraint name="App\Validator\Constraints\ContainsAlphanumeric"/> + <constraint name="App\Validator\ContainsAlphanumeric"/> </property> </class> </constraint-mapping> @@ -158,7 +202,7 @@ You can use custom validators like the ones provided by Symfony itself: // src/Entity/AcmeEntity.php namespace App\Entity; - use App\Validator\Constraints\ContainsAlphanumeric; + use App\Validator\ContainsAlphanumeric; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Mapping\ClassMetadata; @@ -233,6 +277,11 @@ not to the property: .. code-block:: php-annotations + // src/Entity/AcmeEntity.php + namespace App\Entity; + + use App\Validator as AcmeAssert; + /** * @AcmeAssert\ProtocolClass */ @@ -241,18 +290,31 @@ not to the property: // ... } + .. code-block:: php-attributes + + // src/Entity/AcmeEntity.php + namespace App\Entity; + + use App\Validator as AcmeAssert; + + #[AcmeAssert\ProtocolClass] + class AcmeEntity + { + // ... + } + .. code-block:: yaml # config/validator/validation.yaml App\Entity\AcmeEntity: constraints: - - App\Validator\Constraints\ProtocolClass: ~ + - App\Validator\ProtocolClass: ~ .. code-block:: xml <!-- config/validator/validation.xml --> <class name="App\Entity\AcmeEntity"> - <constraint name="App\Validator\Constraints\ProtocolClass"/> + <constraint name="App\Validator\ProtocolClass"/> </class> .. code-block:: php @@ -260,7 +322,7 @@ not to the property: // src/Entity/AcmeEntity.php namespace App\Entity; - use App\Validator\Constraints\ProtocolClass; + use App\Validator\ProtocolClass; use Symfony\Component\Validator\Mapping\ClassMetadata; class AcmeEntity diff --git a/validation/groups.rst b/validation/groups.rst index b25c82236fc..70dcc975655 100644 --- a/validation/groups.rst +++ b/validation/groups.rst @@ -42,6 +42,27 @@ user registers and when a user updates their contact information later: private $city; } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Security\Core\User\UserInterface; + use Symfony\Component\Validator\Constraints as Assert; + + class User implements UserInterface + { + #[Assert\Email(groups: ['registration'])] + private $email; + + #[Assert\NotBlank(groups: ['registration'])] + #[Assert\Length(min: 7, groups: ['registration'])] + private $password; + + #[Assert\Length(min: 2)] + private $city; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -123,7 +144,7 @@ user registers and when a user updates their contact information later: ])); $metadata->addPropertyConstraint('city', new Assert\Length([ - "min" => 2, + 'min' => 2, ])); } } diff --git a/validation/raw_values.rst b/validation/raw_values.rst index cd25bec0653..3565de902d8 100644 --- a/validation/raw_values.rst +++ b/validation/raw_values.rst @@ -25,7 +25,7 @@ address. From inside a controller, it looks like this:: $emailConstraint ); - if (0 === count($errors)) { + if (!$errors->count()) { // ... this IS a valid email address, do something } else { // this is *not* a valid email address @@ -88,7 +88,7 @@ Validation of arrays is possible using the ``Collection`` constraint:: new Assert\Collection([ 'slug' => [ new Assert\NotBlank(), - new Assert\Type(['type' => 'string']) + new Assert\Type(['type' => 'string']), ], 'label' => [ new Assert\NotBlank(), @@ -105,3 +105,10 @@ The ``validate()`` method returns a :class:`Symfony\\Component\\Validator\\Const object, which acts like an array of errors. Each error in the collection is a :class:`Symfony\\Component\\Validator\\ConstraintViolation` object, which holds the error message on its ``getMessage()`` method. + +.. note:: + + When using groups with the + :doc:`Collection </reference/constraints/Collection>` constraint, be sure to + use the ``Optional`` constraint when appropriate as explained in its + reference documentation. diff --git a/validation/sequence_provider.rst b/validation/sequence_provider.rst index 503c50f67e5..699711b661d 100644 --- a/validation/sequence_provider.rst +++ b/validation/sequence_provider.rst @@ -47,6 +47,33 @@ username and the password are different only if all other validation passes } } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Security\Core\User\UserInterface; + use Symfony\Component\Validator\Constraints as Assert; + + #[Assert\GroupSequence(['User', 'Strict'])] + class User implements UserInterface + { + #[Assert\NotBlank] + private $username; + + #[Assert\NotBlank] + private $password; + + #[Assert\IsTrue( + message: 'The password cannot match your username', + groups: ['Strict'], + )] + public function isPasswordSafe() + { + return ($this->username !== $this->password); + } + } + .. code-block:: yaml # config/validator/validation.yaml @@ -151,7 +178,7 @@ You can also define a group sequence in the ``validation_groups`` form option:: // src/Form/MyType.php namespace App\Form; - + use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Validator\Constraints\GroupSequence; @@ -204,6 +231,27 @@ entity and a new constraint group called ``Premium``: // ... } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class User + { + #[Assert\NotBlank] + private $name; + + #[Assert\CardScheme( + schemes: [Assert\CardScheme::VISA], + groups: ['Premium'], + )] + private $creditCard; + + // ... + } + .. code-block:: yaml # config/validator/validation.yaml @@ -263,7 +311,7 @@ entity and a new constraint group called ``Premium``: { $metadata->addPropertyConstraint('name', new Assert\NotBlank()); $metadata->addPropertyConstraint('creditCard', new Assert\CardScheme([ - 'schemes' => ['VISA'], + 'schemes' => [Assert\CardScheme::VISA], 'groups' => ['Premium'], ])); } @@ -319,6 +367,19 @@ provides a sequence of groups to be validated: // ... } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + // ... + + #[Assert\GroupSequenceProvider] + class User implements GroupSequenceProviderInterface + { + // ... + } + .. code-block:: yaml # config/validator/validation.yaml diff --git a/validation/severity.rst b/validation/severity.rst index 23b81145ee9..7df7746c7f2 100644 --- a/validation/severity.rst +++ b/validation/severity.rst @@ -50,6 +50,25 @@ Use the ``payload`` option to configure the error level for each constraint: protected $bankAccountNumber; } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class User + { + #[Assert\NotBlank(payload: ['severity' => 'error'])] + protected $username; + + #[Assert\NotBlank(payload: ['severity' => 'error'])] + protected $password; + + #[Assert\Iban(payload: ['severity' => 'warning'])] + protected $bankAccountNumber; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -137,7 +156,7 @@ method. Each constraint exposes the attached payload as a public property:: // Symfony\Component\Validator\ConstraintViolation $constraintViolation = ...; $constraint = $constraintViolation->getConstraint(); - $severity = isset($constraint->payload['severity']) ? $constraint->payload['severity'] : null; + $severity = $constraint->payload['severity'] ?? null; For example, you can leverage this to customize the ``form_errors`` block so that the severity is added as an additional HTML class: diff --git a/validation/translations.rst b/validation/translations.rst index 5c22f9362c3..10ce5b11275 100644 --- a/validation/translations.rst +++ b/validation/translations.rst @@ -4,12 +4,19 @@ How to Translate Validation Constraint Messages =============================================== -If you're using validation constraints with the Form component, you can translate -the error messages by creating a translation resource for the -``validators`` :ref:`domain <translation-resource-locations>`. +The validation constraints used in forms can translate their error messages by +creating a translation resource for the ``validators`` +:ref:`translation domain <translation-resource-locations>`. -To start, suppose you've created a plain-old-PHP object that you need to -use somewhere in your application:: +First of all, install the Symfony translation component (if it's not already +installed in your application) running the following command: + +.. code-block:: terminal + + $ composer require symfony/translation + +Suppose you've created a plain-old-PHP object that you need to use somewhere in +your application:: // src/Entity/Author.php namespace App\Entity; @@ -40,6 +47,19 @@ property is not empty, add the following: public $name; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class Author + { + #[Assert\NotBlank(message: 'author.name.not_blank')] + public $name; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -93,8 +113,8 @@ Now, create a ``validators`` catalog file in the ``translations/`` directory: .. code-block:: xml - <!-- translations/validators.en.xlf --> - <?xml version="1.0"?> + <!-- translations/validators/validators.en.xlf --> + <?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> @@ -108,12 +128,12 @@ Now, create a ``validators`` catalog file in the ``translations/`` directory: .. code-block:: yaml - # translations/validators.en.yaml + # translations/validators/validators.en.yaml author.name.not_blank: Please enter an author name. .. code-block:: php - // translations/validators.en.php + // translations/validators/validators.en.php return [ 'author.name.not_blank' => 'Please enter an author name.', ]; diff --git a/web_link.rst b/web_link.rst index 1c802a518da..dd8ce736e89 100644 --- a/web_link.rst +++ b/web_link.rst @@ -62,7 +62,7 @@ correct prioritization and the content security policy: <head> <!-- ... --> - <link rel="stylesheet" href="{{ preload('/app.css', { as: 'style' }) }}"> + <link rel="preload" href="{{ preload('/app.css', { as: 'style' }) }}"> </head> If you reload the page, the perceived performance will improve because the @@ -77,7 +77,7 @@ requested the HTML page. <head> <!-- ... --> - <link rel="stylesheet" href="{{ preload(asset('build/app.css')) }}"> + <link rel="preload" href="{{ preload(asset('build/app.css')) }}"> </head> Additionally, according to `the Priority Hints specification`_, you can signal @@ -87,7 +87,7 @@ the priority of the resource to download using the ``importance`` attribute: <head> <!-- ... --> - <link rel="stylesheet" href="{{ preload('/app.css', { as: 'style', importance: 'low' }) }}"> + <link rel="preload" href="{{ preload('/app.css', { as: 'style', importance: 'low' }) }}"> </head> How does it work? @@ -111,7 +111,7 @@ issuing an early separate HTTP request, use the ``nopush`` option: <head> <!-- ... --> - <link rel="stylesheet" href="{{ preload('/app.css', { as: 'style', nopush: true }) }}"> + <link rel="preload" href="{{ preload('/app.css', { as: 'style', nopush: true }) }}"> </head> Resource Hints @@ -145,7 +145,7 @@ any link implementing the `PSR-13`_ standard. For instance, any <head> <!-- ... --> <link rel="alternate" href="{{ link('/index.jsonld', 'alternate') }}"> - <link rel="stylesheet" href="{{ preload('/app.css', { as: 'style', nopush: true }) }}"> + <link rel="preload" href="{{ preload('/app.css', { as: 'style', nopush: true }) }}"> </head> The previous snippet will result in this HTTP header being sent to the client: diff --git a/workflow.rst b/workflow.rst index 43593eb739d..263b8997861 100644 --- a/workflow.rst +++ b/workflow.rst @@ -120,50 +120,47 @@ like this: // config/packages/workflow.php use App\Entity\BlogPost; - - $container->loadFromExtension('framework', [ - 'workflows' => [ - 'blog_publishing' => [ - 'type' => 'workflow', // or 'state_machine' - 'audit_trail' => [ - 'enabled' => true - ], - 'marking_store' => [ - 'type' => 'method', - 'property' => 'currentPlace', - ], - 'supports' => [BlogPost::class], - 'initial_marking' => 'draft', - 'places' => [ - 'draft', - 'reviewed', - 'rejected', - 'published', - ], - 'transitions' => [ - 'to_review' => [ - 'from' => 'draft', - 'to' => 'reviewed', - ], - 'publish' => [ - 'from' => 'reviewed', - 'to' => 'published', - ], - 'reject' => [ - 'from' => 'reviewed', - 'to' => 'rejected', - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $blogPublishing = $framework->workflows()->workflows('blog_publishing'); + $blogPublishing + ->type('workflow') // or 'state_machine' + ->supports([BlogPost::class]) + ->initialMarking(['draft']); + + $blogPublishing->auditTrail()->enabled(true); + $blogPublishing->markingStore() + ->type('method') + ->property('currentPlace'); + + $blogPublishing->place()->name('draft'); + $blogPublishing->place()->name('reviewed'); + $blogPublishing->place()->name('rejected'); + $blogPublishing->place()->name('published'); + + $blogPublishing->transition() + ->name('to_review') + ->from(['draft']) + ->to(['reviewed']); + + $blogPublishing->transition() + ->name('publish') + ->from(['reviewed']) + ->to(['published']); + + $blogPublishing->transition() + ->name('reject') + ->from(['reviewed']) + ->to(['rejected']); + }; .. tip:: If you are creating your first workflows, consider using the ``workflow:dump`` command to :doc:`debug the workflow contents </workflow/dumping-workflows>`. -The configured property will be used via it's implemented getter/setter methods by the marking store:: +The configured property will be used via its implemented getter/setter methods by the marking store:: // src/Entity/BlogPost.php namespace App\Entity; @@ -232,13 +229,16 @@ what actions are allowed on a blog post:: // See all the available transitions for the post in the current state $transitions = $workflow->getEnabledTransitions($post); + // See a specific available transition for the post in the current state + $transition = $workflow->getEnabledTransition($post, 'publish'); Accessing the Workflow in a Class --------------------------------- You can use the workflow inside a class by using :doc:`service autowiring </service_container/autowiring>` and using -``camelCased workflow name + Workflow`` as parameter name:: +``camelCased workflow name + Workflow`` as parameter name. If it is a state +machine type, use ``camelCased workflow name + StateMachine``:: use App\Entity\BlogPost; use Symfony\Component\Workflow\WorkflowInterface; @@ -247,7 +247,7 @@ You can use the workflow inside a class by using { private $blogPublishingWorkflow; - // this injects the blog_publishing workflow configured before + // Symfony will inject the 'blog_publishing' workflow configured before public function __construct(WorkflowInterface $blogPublishingWorkflow) { $this->blogPublishingWorkflow = $blogPublishingWorkflow; @@ -378,11 +378,37 @@ order: * ``workflow.[workflow name].announce`` * ``workflow.[workflow name].announce.[transition name]`` + You can avoid triggering those events by using the context:: + + $workflow->apply($subject, $transitionName, [Workflow::DISABLE_ANNOUNCE_EVENT => true]); + + .. versionadded:: 5.1 + + The ``Workflow::DISABLE_ANNOUNCE_EVENT`` constant was introduced in Symfony 5.1. + + .. versionadded:: 5.2 + + In Symfony 5.2, the context is customizable for all events except for + ``workflow.guard`` events, which will not receive the custom ``$context``:: + + // $context must be an array + $context = ['context_key' => 'context_value']; + $workflow->apply($subject, $transitionName, $context); + + // in an event listener + $context = $event->getContext(); // returns ['context'] + .. note:: The leaving and entering events are triggered even for transitions that stay in same place. +.. note:: + + If you initialize the marking by calling ``$workflow->getMarking($object);``, + then the ``workflow.[workflow_name].entered.[initial_place_name]`` event will + be called with the default context (``Workflow::DEFAULT_INITIAL_CONTEXT``). + Here is an example of how to enable logging for every time a "blog_publishing" workflow leaves a place:: @@ -421,6 +447,18 @@ workflow leaves a place:: } } +If some listeners update the context during a transition, you can retrieve +it via the marking:: + + $marking = $workflow->apply($post, 'to_review'); + + // contains the new value + $marking->getContext(); + +.. versionadded:: 5.4 + + The ability to get the new value from the marking was introduced in Symfony 5.4. + .. _workflow-usage-guard-events: Guard Events @@ -525,23 +563,25 @@ to :ref:`Guard events <workflow-usage-guard-events>`, which are always fired: .. code-block:: php // config/packages/workflow.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'workflows' => [ - 'blog_publishing' => [ - // you can pass one or more event names - 'events_to_dispatch' => [ - 'workflow.leave', - 'workflow.completed', - ], - - // pass an empty array to not dispatch any event - 'events_to_dispatch' => [], - - // ... - ], - ], - ]); + + $blogPublishing = $framework->workflows()->workflows('blog_publishing'); + + // ... + // you can pass one or more event names + $blogPublishing->eventsToDispatch([ + 'workflow.leave', + 'workflow.completed', + ]); + + // pass an empty array to not dispatch any event + $blogPublishing->eventsToDispatch([]); + + // ... + }; You can also disable a specific event from being fired when applying a transition:: @@ -703,36 +743,33 @@ transition. The value of this option is any valid expression created with the .. code-block:: php // config/packages/workflow.php - use App\Entity\BlogPost; - - $container->loadFromExtension('framework', [ - 'workflows' => [ - 'blog_publishing' => [ - // ... previous configuration - - 'transitions' => [ - 'to_review' => [ - // the transition is allowed only if the current user has the ROLE_REVIEWER role. - 'guard' => 'is_granted("ROLE_REVIEWER")', - 'from' => 'draft', - 'to' => 'reviewed', - ], - 'publish' => [ - // or "is_anonymous", "is_remember_me", "is_fully_authenticated", "is_granted" - 'guard' => 'is_authenticated', - 'from' => 'reviewed', - 'to' => 'published', - ], - 'reject' => [ - // or any valid expression language with "subject" referring to the post - 'guard' => 'is_granted("ROLE_ADMIN") and subject.isStatusReviewed()', - 'from' => 'reviewed', - 'to' => 'rejected', - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $blogPublishing = $framework->workflows()->workflows('blog_publishing'); + // ... previous configuration + + $blogPublishing->transition() + ->name('to_review') + // the transition is allowed only if the current user has the ROLE_REVIEWER role. + ->guard('is_granted("ROLE_REVIEWER")') + ->from(['draft']) + ->to(['reviewed']); + + $blogPublishing->transition() + ->name('publish') + // or "is_anonymous", "is_remember_me", "is_fully_authenticated", "is_granted" + ->guard('is_authenticated') + ->from(['reviewed']) + ->to(['published']); + + $blogPublishing->transition() + ->name('reject') + // or any valid expression language with "subject" referring to the post + ->guard('is_granted("ROLE_ADMIN") and subject.isStatusReviewed()') + ->from(['reviewed']) + ->to(['rejected']); + }; You can also use transition blockers to block and return a user-friendly error message when you stop a transition from happening. @@ -788,6 +825,9 @@ of domain logic in your templates: ``workflow_transitions()`` Returns an array with all the transitions enabled for the given object. +``workflow_transition()`` + Returns a specific transition enabled for the given object and transition name. + ``workflow_marked_places()`` Returns an array with the place names of the given marking. @@ -914,42 +954,43 @@ be only the title of the workflow or very complex objects: .. code-block:: php // config/packages/workflow.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $blogPublishing = $framework->workflows()->workflows('blog_publishing'); + // ... previous configuration + + $blogPublishing->metadata([ + 'title' => 'Blog Publishing Workflow' + ]); + + // ... + + $blogPublishing->place() + ->name('draft') + ->metadata([ + 'max_num_of_words' => 500, + ]); + // ... - 'workflows' => [ - 'blog_publishing' => [ - 'metadata' => [ - 'title' => 'Blog Publishing Workflow', - ], - // ... - 'places' => [ - 'draft' => [ - 'metadata' => [ - 'max_num_of_words' => 500, - ], - ], - // ... - ], - 'transitions' => [ - 'to_review' => [ - 'from' => 'draft', - 'to' => 'review', - 'metadata' => [ - 'priority' => 0.5, - ], - ], - 'publish' => [ - 'from' => 'reviewed', - 'to' => 'published', - 'metadata' => [ - 'hour_limit' => 20, - 'explanation' => 'You can not publish after 8 PM.', - ], - ], - ], - ], - ], - ]); + + $blogPublishing->transition() + ->name('to_review') + ->from(['draft']) + ->to(['reviewed']) + ->metadata([ + 'priority' => 0.5, + ]); + + $blogPublishing->transition() + ->name('publish') + ->from(['reviewed']) + ->to(['published']) + ->metadata([ + 'hour_limit' => 20, + 'explanation' => 'You can not publish after 8 PM.', + ]); + }; Then you can access this metadata in your controller as follows:: @@ -1031,6 +1072,15 @@ In Twig templates, metadata is available via the ``workflow_metadata()`` functio {% endfor %} </ul> </p> + <p> + <strong>to_review Priority</strong> + <ul> + <li> + to_review: + <code>{{ workflow_metadata(blog_post, 'priority', workflow_transition(blog_post, 'to_review')) }}</code> + </li> + </ul> + </p> Learn more ---------- diff --git a/workflow/dumping-workflows.rst b/workflow/dumping-workflows.rst index d1749603155..98e5911561f 100644 --- a/workflow/dumping-workflows.rst +++ b/workflow/dumping-workflows.rst @@ -9,8 +9,13 @@ them as SVG or PNG images. First, install any of these free and open source applications needed to generate the images: * `Graphviz`_, provides the ``dot`` command; +* `Mermaid CLI`_, provides the ``mmdc`` command; * `PlantUML`_, provides the ``plantuml.jar`` file (which requires Java). +.. versionadded:: 5.3 + + The ``mermaid`` dump format was introduced in Symfony 5.3. + If you are defining the workflow inside a Symfony application, run this command to dump it as an image: @@ -28,10 +33,17 @@ to dump it as an image: # highlight 'place1' and 'place2' in the dumped workflow $ php bin/console workflow:dump workflow-name place1 place2 | dot -Tsvg -o graph.svg + # using Mermaid.js CLI + $ php bin/console workflow:dump workflow_name --dump-format=mermaid | mmdc -o graph.svg + The DOT image will look like this: .. image:: /_images/components/workflow/blogpost.png +The Mermaid image will look like this: + +.. image:: /_images/components/workflow/blogpost_mermaid.png + The PlantUML image will look like this: .. image:: /_images/components/workflow/blogpost_puml.png @@ -63,7 +75,7 @@ You can use ``metadata`` with the following keys to style the workflow: * ``bg_color``: a color; * ``description``: a string that describes the state. - + * for transitions: * ``label``: a string that replaces the name of the transition; @@ -76,6 +88,11 @@ Colors can be defined as: * a color name from `PlantUML's color list`_; * an hexadecimal color (both ``#AABBCC`` and ``#ABC`` formats are supported). +.. note:: + + The Mermaid dumper does not support coloring the arrow heads + with ``arrow_color`` as there is no support in Mermaid for doing so. + Below is the configuration for the pull request state machine with styling added. .. configuration-block:: @@ -169,7 +186,6 @@ Below is the configuration for the pull request state machine with styling added <framework:bg_color>DeepSkyBlue</framework:bg_color> </framework:metadata> </framework:place> - </framework:place> <framework:transition name="submit"> <framework:from>start</framework:from> @@ -235,80 +251,76 @@ Below is the configuration for the pull request state machine with styling added .. code-block:: php // config/packages/workflow.php - $container->loadFromExtension('framework', [ + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { // ... - 'workflows' => [ - 'pull_request' => [ - 'type' => 'state_machine', - 'marking_store' => [ - type: 'method', - property: 'currentPlace', - ], - 'supports' => ['App\Entity\PullRequest'], - 'initial_marking' => 'start', - 'places' => [ - 'start', - 'coding', - 'test', - 'review' => [ - 'metadata' => [ - 'description' => 'Human review', - ], - ], - 'merged', - 'closed' => [ - 'metadata' => [ - 'bg_color' => 'DeepSkyBlue', - ], - ], - ], - 'transitions' => [ - 'submit'=> [ - 'from' => 'start', - 'to' => 'test', - ], - 'update'=> [ - 'from' => ['coding', 'test', 'review'], - 'to' => 'test', - 'metadata' => [ - 'arrow_color' => 'Turquoise', - ], - ], - 'wait_for_review'=> [ - 'from' => 'test', - 'to' => 'review', - 'metadata' => [ - 'color' => 'Orange', - ], - ], - 'request_change'=> [ - 'from' => 'review', - 'to' => 'coding', - ], - 'accept'=> [ - 'from' => 'review', - 'to' => 'merged', - 'metadata' => [ - 'label' => 'Accept PR', - ], - ], - 'reject'=> [ - 'from' => 'review', - 'to' => 'closed', - ], - 'reopen'=> [ - 'from' => 'start', - 'to' => 'review', - ], - ], - ], - ], - ]); + $pullRequest = $framework->workflows()->workflows('pull_request'); + + $pullRequest + ->type('state_machine') + ->supports(['App\Entity\PullRequest']) + ->initialMarking(['start']); + + $pullRequest->markingStore() + ->type('method') + ->property('currentPlace'); + + $pullRequest->place()->name('start'); + $pullRequest->place()->name('coding'); + $pullRequest->place()->name('test'); + $pullRequest->place() + ->name('review') + ->metadata(['description' => 'Human review']); + $pullRequest->place()->name('merged'); + $pullRequest->place() + ->name('closed') + ->metadata(['bg_color' => 'DeepSkyBlue',]); + + $pullRequest->transition() + ->name('submit') + ->from(['start']) + ->to(['test']); + + $pullRequest->transition() + ->name('update') + ->from(['coding', 'test', 'review']) + ->to(['test']) + ->metadata(['arrow_color' => 'Turquoise']); + + $pullRequest->transition() + ->name('wait_for_review') + ->from(['test']) + ->to(['review']) + ->metadata(['color' => 'Orange']); + + $pullRequest->transition() + ->name('request_change') + ->from(['review']) + ->to(['coding']); + + $pullRequest->transition() + ->name('accept') + ->from(['review']) + ->to(['merged']) + ->metadata(['label' => 'Accept PR']); + + $pullRequest->transition() + ->name('reject') + ->from(['review']) + ->to(['closed']); + + $pullRequest->transition() + ->name('accept') + ->from(['closed']) + ->to(['review']); + }; The PlantUML image will look like this: .. image:: /_images/components/workflow/pull_request_puml_styled.png .. _`Graphviz`: https://www.graphviz.org +.. _`Mermaid CLI`: https://github.com/mermaid-js/mermaid-cli .. _`PlantUML`: https://plantuml.com/ .. _`PlantUML's color list`: https://plantuml.com/color diff --git a/workflow/workflow-and-state-machine.rst b/workflow/workflow-and-state-machine.rst index 730cf66bccc..6ef73aa60cf 100644 --- a/workflow/workflow-and-state-machine.rst +++ b/workflow/workflow-and-state-machine.rst @@ -192,58 +192,62 @@ Below is the configuration for the pull request state machine. .. code-block:: php // config/packages/workflow.php - $container->loadFromExtension('framework', [ - // ... - 'workflows' => [ - 'pull_request' => [ - 'type' => 'state_machine', - 'marking_store' => [ - 'type' => 'method', - 'property' => 'currentPlace', - ], - 'supports' => ['App\Entity\PullRequest'], - 'initial_marking' => 'start', - 'places' => [ - 'start', - 'coding', - 'test', - 'review', - 'merged', - 'closed', - ], - 'transitions' => [ - 'submit'=> [ - 'from' => 'start', - 'to' => 'test', - ], - 'update'=> [ - 'from' => ['coding', 'test', 'review'], - 'to' => 'test', - ], - 'wait_for_review'=> [ - 'from' => 'test', - 'to' => 'review', - ], - 'request_change'=> [ - 'from' => 'review', - 'to' => 'coding', - ], - 'accept'=> [ - 'from' => 'review', - 'to' => 'merged', - ], - 'reject'=> [ - 'from' => 'review', - 'to' => 'closed', - ], - 'reopen'=> [ - 'from' => 'start', - 'to' => 'review', - ], - ], - ], - ], - ]); + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $pullRequest = $framework->workflows()->workflows('pull_request'); + + $pullRequest + ->type('state_machine') + ->supports(['App\Entity\PullRequest']) + ->initialMarking(['start']); + + $pullRequest->markingStore() + ->type('method') + ->property('currentPlace'); + + $pullRequest->place()->name('start'); + $pullRequest->place()->name('coding'); + $pullRequest->place()->name('test'); + $pullRequest->place()->name('review'); + $pullRequest->place()->name('merged'); + $pullRequest->place()->name('closed'); + + $pullRequest->transition() + ->name('submit') + ->from(['start']) + ->to(['test']); + + $pullRequest->transition() + ->name('update') + ->from(['coding', 'test', 'review']) + ->to(['test']); + + $pullRequest->transition() + ->name('wait_for_review') + ->from(['test']) + ->to(['review']); + + $pullRequest->transition() + ->name('request_change') + ->from(['review']) + ->to(['coding']); + + $pullRequest->transition() + ->name('accept') + ->from(['review']) + ->to(['merged']); + + $pullRequest->transition() + ->name('reject') + ->from(['review']) + ->to(['closed']); + + $pullRequest->transition() + ->name('accept') + ->from(['closed']) + ->to(['review']); + }; In a Symfony application using the :ref:`default services.yaml configuration <service-container-services-load-example>`, From ed7debadffe1af408f4c35b4a83b3df09baa5595 Mon Sep 17 00:00:00 2001 From: JohJohan <johan.vlaar.1994@gmail.com> Date: Mon, 11 Oct 2021 21:21:02 +0200 Subject: [PATCH 1319/1519] [HttpKernel] 15874 framework exceptions --- reference/configuration/framework.rst | 74 +++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index ddaed96d025..9fd42aeb177 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -3316,6 +3316,80 @@ Defines the kind of workflow that is going to be created, which can be either a normal workflow or a state machine. Read :doc:`this article </workflow/workflow-and-state-machine>` to know their differences. +exceptions +"""""""""" + +**type**: ``array`` + +Defines what ``log_level`` and ``status_code`` should be returned by exception class: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/exceptions.yaml + framework: + exceptions: + Symfony\Component\HttpKernel\Exception\BadRequestHttpException: + log_level: debug + status_code: 422 + + .. code-block:: xml + + <!-- config/packages/exceptions.xml --> + <?xml version="1.0" encoding="UTF-8" ?> + <container xmlns="http://symfony.com/schema/dic/services" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:framework="http://symfony.com/schema/dic/symfony" + xsi:schemaLocation="http://symfony.com/schema/dic/services + https://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> + + <framework:config> + <framework:exceptions> + <exception id="Symfony\Component\HttpKernel\Exception\BadRequestHttpException"> + <framework:log_level>debug</framework:log_level> + <framework:status_code>422</framework:status_code> + </exception> + </framework:exceptions> + <!-- ... --> + </framework:config> + </container> + + .. code-block:: php + + // config/packages/exceptions.php + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework) { + $framework + ->exceptions('Symfony\Component\HttpKernel\Exception\BadRequestHttpException') + ->log_level('debug'); + + $framework + ->exceptions('Symfony\Component\HttpKernel\Exception\BadRequestHttpException') + ->status_code(422); + ; + }; + +.. note:: + + When defining exceptions the order is important as it will use the first exception that matches ``instanceof`` + +Example with ``\RuntimeException`` and ``\Exception``: + +.. code-block:: yaml + + # config/packages/exceptions.yaml + framework: + exceptions: + Exception: + log_level: debug + status_code: 404 + RuntimeException: # This will never be used as \RuntimeException extends \Exception + log_level: debug + status_code: 422 + .. _`HTTP Host header attacks`: https://www.skeletonscribe.net/2013/05/practical-http-host-header-attacks.html .. _`Security Advisory Blog post`: https://symfony.com/blog/security-releases-symfony-2-0-24-2-1-12-2-2-5-and-2-3-3-released#cve-2013-4752-request-gethost-poisoning .. _`Doctrine Cache`: https://www.doctrine-project.org/projects/doctrine-cache/en/current/index.html From 3fabd6f9d880581914c32a29b489ec2e8d5388fb Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Tue, 7 Dec 2021 11:27:34 +0100 Subject: [PATCH 1320/1519] Minor tweaks --- reference/configuration/framework.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 2fe23b6f8be..a5b250de8f9 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -3363,7 +3363,8 @@ exceptions **type**: ``array`` -Defines what ``log_level`` and ``status_code`` should be returned by exception class: +Defines the :ref:`log level </logging>` and HTTP status code applied to the +exceptions that match the given exception class: .. configuration-block:: @@ -3373,7 +3374,7 @@ Defines what ``log_level`` and ``status_code`` should be returned by exception c framework: exceptions: Symfony\Component\HttpKernel\Exception\BadRequestHttpException: - log_level: debug + log_level: 'debug' status_code: 422 .. code-block:: xml @@ -3401,24 +3402,22 @@ Defines what ``log_level`` and ``status_code`` should be returned by exception c .. code-block:: php // config/packages/exceptions.php + use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Config\FrameworkConfig; return static function (FrameworkConfig $framework) { $framework - ->exceptions('Symfony\Component\HttpKernel\Exception\BadRequestHttpException') + ->exceptions(BadRequestHttpException::class) ->log_level('debug'); $framework - ->exceptions('Symfony\Component\HttpKernel\Exception\BadRequestHttpException') + ->exceptions(BadRequestHttpException::class) ->status_code(422); ; }; -.. note:: - - When defining exceptions the order is important as it will use the first exception that matches ``instanceof`` - -Example with ``\RuntimeException`` and ``\Exception``: +The order in which you configure exceptions is important because Symfony will +use the configuration of the first exception that matches ``instanceof``: .. code-block:: yaml @@ -3426,10 +3425,11 @@ Example with ``\RuntimeException`` and ``\Exception``: framework: exceptions: Exception: - log_level: debug + log_level: 'debug' status_code: 404 - RuntimeException: # This will never be used as \RuntimeException extends \Exception - log_level: debug + # The following configuration will never be used because \RuntimeException extends \Exception + RuntimeException: + log_level: 'debug' status_code: 422 .. _`HTTP Host header attacks`: https://www.skeletonscribe.net/2013/05/practical-http-host-header-attacks.html From 752f702c8fb64ba366388d245c79dc964c9a27dc Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Tue, 7 Dec 2021 11:28:05 +0100 Subject: [PATCH 1321/1519] Add the versionadded directive --- reference/configuration/framework.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index a5b250de8f9..6f09d0cb7b6 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -3363,6 +3363,10 @@ exceptions **type**: ``array`` +.. versionadded:: 5.4 + + The ``exceptions`` option was introduced in Symfony 5.4. + Defines the :ref:`log level </logging>` and HTTP status code applied to the exceptions that match the given exception class: From a540576e774d6f1a070718923a0fef2cb87d54b6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Tue, 7 Dec 2021 11:28:38 +0100 Subject: [PATCH 1322/1519] Remove the versionadded directive --- reference/configuration/framework.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 49b1929201b..f429b55a027 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -3225,10 +3225,6 @@ exceptions **type**: ``array`` -.. versionadded:: 5.4 - - The ``exceptions`` option was introduced in Symfony 5.4. - Defines the :ref:`log level </logging>` and HTTP status code applied to the exceptions that match the given exception class: From f2b39ea17dad815cf8f8f99e105368ccb32da03c Mon Sep 17 00:00:00 2001 From: DKravtsov <dmitriy.kravtsov@systemsdk.com> Date: Wed, 8 Dec 2021 00:38:18 +0200 Subject: [PATCH 1323/1519] added example for limit consuming to specific queue / queues --- messenger.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index ee922bf4019..30a4e4423bf 100644 --- a/messenger.rst +++ b/messenger.rst @@ -604,12 +604,18 @@ transport is always bound to an exchange. By default, the worker consumes from a queues attached to the exchange of the specified transport. However, there are use cases to want a worker to only consume from specific queues. -You can limit the worker to only process messages from specific queues: +You can limit the worker to only process messages from specific queue: .. code-block:: terminal $ php bin/console messenger:consume my_transport --queues=fasttrack +Or you can limit the worker to only process messages from specific queues: + +.. code-block:: terminal + + $ php bin/console messenger:consume my_transport --queues=fasttrack1 --queues=fasttrack2 + To allow using the ``queues`` option, the receiver must implement the :class:`Symfony\\Component\\Messenger\\Transport\\Receiver\\QueueReceiverInterface`. From e16818e446ee53865d21b16f7a4fd8043fae7c0d Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Wed, 8 Dec 2021 10:09:55 +0100 Subject: [PATCH 1324/1519] Minor tweak --- messenger.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/messenger.rst b/messenger.rst index 30a4e4423bf..fa58b415dcc 100644 --- a/messenger.rst +++ b/messenger.rst @@ -604,16 +604,13 @@ transport is always bound to an exchange. By default, the worker consumes from a queues attached to the exchange of the specified transport. However, there are use cases to want a worker to only consume from specific queues. -You can limit the worker to only process messages from specific queue: +You can limit the worker to only process messages from specific queue(s): .. code-block:: terminal $ php bin/console messenger:consume my_transport --queues=fasttrack -Or you can limit the worker to only process messages from specific queues: - -.. code-block:: terminal - + # you can pass the --queues option more than once to process multiple queues $ php bin/console messenger:consume my_transport --queues=fasttrack1 --queues=fasttrack2 To allow using the ``queues`` option, the receiver must implement the From 62ba2e4bdbe925a5f847c418a356644b6ef1d205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= <jerome@tamarelle.net> Date: Fri, 10 Dec 2021 10:38:17 +0100 Subject: [PATCH 1325/1519] [Lock] Add new Doctrine DBAL stores --- components/lock.rst | 108 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 21 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index a765fa4edc7..d3b92c83885 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -350,18 +350,20 @@ Locks are created and managed in ``Stores``, which are classes that implement The component includes the following built-in store types: -============================================ ====== ======== ======== ======= -Store Scope Blocking Expiring Sharing -============================================ ====== ======== ======== ======= -:ref:`FlockStore <lock-store-flock>` local yes no yes -:ref:`MemcachedStore <lock-store-memcached>` remote no yes no -:ref:`MongoDbStore <lock-store-mongodb>` remote no yes no -:ref:`PdoStore <lock-store-pdo>` remote no yes no -:ref:`PostgreSqlStore <lock-store-pgsql>` remote yes no yes -:ref:`RedisStore <lock-store-redis>` remote no yes yes -:ref:`SemaphoreStore <lock-store-semaphore>` local yes no no -:ref:`ZookeeperStore <lock-store-zookeeper>` remote no no no -============================================ ====== ======== ======== ======= +========================================================= ====== ======== ======== ======= +Store Scope Blocking Expiring Sharing +========================================================= ====== ======== ======== ======= +:ref:`FlockStore <lock-store-flock>` local yes no yes +:ref:`MemcachedStore <lock-store-memcached>` remote no yes no +:ref:`MongoDbStore <lock-store-mongodb>` remote no yes no +:ref:`PdoStore <lock-store-pdo>` remote no yes no +:ref:`DoctrineDbalStore <lock-store-dbal>` remote no yes no +:ref:`PostgreSqlStore <lock-store-pgsql>` remote yes no yes +:ref:`DoctrineDbalPostgreSqlStore <lock-store-dbal-pgsql>` remote yes no yes +:ref:`RedisStore <lock-store-redis>` remote no yes yes +:ref:`SemaphoreStore <lock-store-semaphore>` local yes no no +:ref:`ZookeeperStore <lock-store-zookeeper>` remote no no no +========================================================= ====== ======== ======== ======= .. _lock-store-flock: @@ -471,13 +473,13 @@ MongoDB Connection String: PdoStore ~~~~~~~~ -The PdoStore saves locks in an SQL database. It requires a `PDO`_ connection, a -`Doctrine DBAL Connection`_, or a `Data Source Name (DSN)`_. This store does not +The PdoStore saves locks in an SQL database. It is identical to DoctrineDbalStore but requires +a `PDO`_ connection or a `Data Source Name (DSN)`_. This store does not support blocking, and expects a TTL to avoid stalled locks:: use Symfony\Component\Lock\Store\PdoStore; - // a PDO, a Doctrine DBAL connection or DSN for lazy connecting through PDO + // a PDO or DSN for lazy connecting through PDO $databaseConnectionOrDSN = 'mysql:host=127.0.0.1;dbname=app'; $store = new PdoStore($databaseConnectionOrDSN, ['db_username' => 'myuser', 'db_password' => 'mypassword']); @@ -491,21 +493,56 @@ You can also create this table explicitly by calling the :method:`Symfony\\Component\\Lock\\Store\\PdoStore::createTable` method in your code. +.. deprecated:: 5.4 + + Using ``PdoStore`` with Doctrine DBAL is deprecated in Symfony 5.4. Use ``DoctrineDbalStore`` instead. + +.. _lock-store-dbal: + +DoctrineDbalStore +~~~~~~~~~~~~~~~~~ + +The DoctrineDbalStore saves locks in an SQL database. It is identical to PdoStore but requires a +`Doctrine DBAL Connection`_, or a `Doctrine DBAL URL`_. This store does not +support blocking, and expects a TTL to avoid stalled locks:: + + use Symfony\Component\Lock\Store\PdoStore; + + // a PDO, a Doctrine DBAL connection or DSN for lazy connecting through PDO + $connectionOrURL = 'mysql://myuser:mypassword@127.0.0.1/app'; + $store = new PdoStore($connectionOrURL); + +.. note:: + + This store does not support TTL lower than 1 second. + +The table where values are stored is created automatically on the first call to +the :method:`Symfony\\Component\\Lock\\Store\\DoctrineDbalStore::save` method. +You can also add this table to your schema by calling +:method:`Symfony\\Component\\Lock\\Store\\DoctrineDbalStore::configureSchema` method +in your code or create this table explicitly by calling the +:method:`Symfony\\Component\\Lock\\Store\\DoctrineDbalStore::createTable` method. + +.. versionadded:: 5.4 + + The ``DoctrineDbalStore`` was introduced in Symfony 5.4 to replace ``PdoStore`` when + used with Doctrine DBAL. + .. _lock-store-pgsql: PostgreSqlStore ~~~~~~~~~~~~~~~ -The PostgreSqlStore uses `Advisory Locks`_ provided by PostgreSQL. It requires a -`PDO`_ connection, a `Doctrine DBAL Connection`_, or a -`Data Source Name (DSN)`_. It supports native blocking, as well as sharing +The PostgreSqlStore and DoctrineDbalPostgreSqlStore uses `Advisory Locks`_ provided by PostgreSQL. +It is identical to DoctrineDbalPostgreSqlStore but requires `PDO`_ connection or +a `Data Source Name (DSN)`_. It supports native blocking, as well as sharing locks:: use Symfony\Component\Lock\Store\PostgreSqlStore; - // a PDO, a Doctrine DBAL connection or DSN for lazy connecting through PDO - $databaseConnectionOrDSN = 'postgresql://myuser:mypassword@localhost:5634/lock'; - $store = new PostgreSqlStore($databaseConnectionOrDSN); + // a PDO instance or DSN for lazy connecting through PDO + $databaseConnectionOrDSN = 'pgsql:host=localhost;port=5634;dbname=lock'; + $store = new PostgreSqlStore($databaseConnectionOrDSN, ['db_username' => 'myuser', 'db_password' => 'mypassword']); In opposite to the ``PdoStore``, the ``PostgreSqlStore`` does not need a table to store locks and does not expire. @@ -514,6 +551,34 @@ store locks and does not expire. The ``PostgreSqlStore`` was introduced in Symfony 5.2. +.. deprecated:: 5.4 + + Using ``PostgreSqlStore`` with Doctrine DBAL is deprecated in Symfony 5.4. Use ``DoctrineDbalPostgreSqlStore`` instead. + +.. _lock-store-dbal-pgsql: + +DoctrineDbalPostgreSqlStore +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The DoctrineDbalPostgreSqlStore uses `Advisory Locks`_ provided by PostgreSQL. It is identical to PostgreSqlStore +but requires a `Doctrine DBAL Connection`_ or a `Doctrine DBAL URL`_. +It supports native blocking, as well as sharing +locks:: + + use Symfony\Component\Lock\Store\PostgreSqlStore; + + // a PDO instance or DSN for lazy connecting through PDO + $databaseConnectionOrDSN = 'pgsql:host=localhost;port=5634;dbname=lock'; + $store = new PostgreSqlStore($databaseConnectionOrDSN, ['db_username' => 'myuser', 'db_password' => 'mypassword']); + +In opposite to the ``DoctrineDbalStore``, the ``DoctrineDbalPostgreSqlStore`` does not need a table to +store locks and does not expire. + +.. versionadded:: 5.4 + + The ``DoctrineDbalPostgreSqlStore`` was introduced in Symfony 5.4 to replace ``PostgreSqlStore`` when + used with Doctrine DBAL. + .. _lock-store-redis: RedisStore @@ -940,6 +1005,7 @@ are still running. .. _`Advisory Locks`: https://www.postgresql.org/docs/current/explicit-locking.html .. _`Data Source Name (DSN)`: https://en.wikipedia.org/wiki/Data_source_name .. _`Doctrine DBAL Connection`: https://github.com/doctrine/dbal/blob/master/src/Connection.php +.. _`Doctrine DBAL URL`: https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url .. _`Expire Data from Collections by Setting TTL`: https://docs.mongodb.com/manual/tutorial/expire-data/ .. _`locks`: https://en.wikipedia.org/wiki/Lock_(computer_science) .. _`MongoDB Connection String`: https://docs.mongodb.com/manual/reference/connection-string/ From df2463772c3f70b61a1be1df494de0c088cf5c6f Mon Sep 17 00:00:00 2001 From: Alexander Schranz <alexander@sulu.io> Date: Fri, 10 Dec 2021 14:57:30 +0100 Subject: [PATCH 1326/1519] Remove "enable_authenticator_manager" from Symfony 6 docs --- security.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/security.rst b/security.rst index 034b26bc4ae..136afc537da 100644 --- a/security.rst +++ b/security.rst @@ -27,7 +27,6 @@ creates a ``security.yaml`` configuration file for you: # config/packages/security.yaml security: - enable_authenticator_manager: true # https://symfony.com/doc/current/security.html#c-hashing-passwords password_hashers: Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' From 374732440b37a938b1d27955341f5dde628e2457 Mon Sep 17 00:00:00 2001 From: Alex Ghiban <drew7721@gmail.com> Date: Thu, 9 Dec 2021 16:41:51 -0500 Subject: [PATCH 1327/1519] Import jquery as the $ variable. If we want to use the `$` for jQuery we need to import it as such. --- frontend/encore/simple-example.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/encore/simple-example.rst b/frontend/encore/simple-example.rst index bed5c73c865..1e82c489104 100644 --- a/frontend/encore/simple-example.rst +++ b/frontend/encore/simple-example.rst @@ -182,7 +182,7 @@ Great! Use ``import`` to import ``jquery`` and ``greet.js``: // ... + // loads the jquery package from node_modules - + import jquery from 'jquery'; + + import $ from 'jquery'; + // import the function from greet.js (the .js extension is optional) + // ./ (or ../) means to look for a local file From b4221fbc8e6cffc336cc38dde34aded2f3899f55 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Sat, 11 Dec 2021 15:16:03 +0100 Subject: [PATCH 1328/1519] Add a warning about native://default for Mailer --- mailer.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mailer.rst b/mailer.rst index 97ad6215fa9..04079f9326c 100644 --- a/mailer.rst +++ b/mailer.rst @@ -93,6 +93,11 @@ native ``native://default`` Mailer uses the sendmail in the ``sendmail_path`` setting of ``php.ini``. On Windows hosts, Mailer fallbacks to ``smtp`` and ``smtp_port`` ``php.ini`` settings when ``sendmail_path`` is not configured. + Be warned that if ``php.ini`` uses the ``sendmail -t`` command, + you won't have error reporting and ``Bcc`` headers won't be removed. + It's highly recommended to NOT use this DSN as you cannot control + how sendmail is configured (prefer using ``sendmail://default`` + if possible). ============ ======================================== ============================================================== Using a 3rd Party Transport From 846e5b1219cab53f154f9d23b98b9869f8191486 Mon Sep 17 00:00:00 2001 From: gnito-org <70450336+gnito-org@users.noreply.github.com> Date: Sun, 12 Dec 2021 07:55:59 -0400 Subject: [PATCH 1329/1519] Upgrade Bootstrap 4 theme references to Bootstrap 5 theme --- form/form_customization.rst | 2 +- form/form_themes.rst | 6 +++--- forms.rst | 12 ++++++------ reference/configuration/twig.rst | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/form/form_customization.rst b/form/form_customization.rst index 120f4d52178..78434c258d7 100644 --- a/form/form_customization.rst +++ b/form/form_customization.rst @@ -258,7 +258,7 @@ Renders any errors for the given field. .. caution:: - In the :ref:`error messages of Bootstrap 4 Form Theme <reference-forms-bootstrap4-error-messages>`, + In the :ref:`error messages of Bootstrap 5 Form Theme <reference-forms-bootstrap5-error-messages>`, ``form_errors()`` is already included in ``form_label()``. .. _reference-forms-twig-widget: diff --git a/form/form_themes.rst b/form/form_themes.rst index 8c32184afb0..d8a264ede7c 100644 --- a/form/form_themes.rst +++ b/form/form_themes.rst @@ -76,7 +76,7 @@ want to use another theme for all the forms of your app, configure it in the # config/packages/twig.yaml twig: - form_themes: ['bootstrap_4_horizontal_layout.html.twig'] + form_themes: ['bootstrap_5_horizontal_layout.html.twig'] # ... .. code-block:: xml @@ -91,7 +91,7 @@ want to use another theme for all the forms of your app, configure it in the http://symfony.com/schema/dic/twig https://symfony.com/schema/dic/twig/twig-1.0.xsd"> <twig:config> - <twig:form-theme>bootstrap_4_horizontal_layout.html.twig</twig:form-theme> + <twig:form-theme>bootstrap_5_horizontal_layout.html.twig</twig:form-theme> <!-- ... --> </twig:config> </container> @@ -103,7 +103,7 @@ want to use another theme for all the forms of your app, configure it in the return static function (TwigConfig $twig) { $twig->formThemes([ - 'bootstrap_4_horizontal_layout.html.twig', + 'bootstrap_5_horizontal_layout.html.twig', ]); // ... diff --git a/forms.rst b/forms.rst index 74fef0b6600..aa7ae514213 100644 --- a/forms.rst +++ b/forms.rst @@ -320,8 +320,8 @@ suitable for being rendered in an HTML form. As short as this rendering is, it's not very flexible. Usually, you'll need more control about how the entire form or some of its fields look. For example, thanks -to the :doc:`Bootstrap 4 integration with Symfony forms </form/bootstrap4>` you -can set this option to generate forms compatible with the Bootstrap 4 CSS framework: +to the :doc:`Bootstrap 5 integration with Symfony forms </form/bootstrap5>` you +can set this option to generate forms compatible with the Bootstrap 5 CSS framework: .. configuration-block:: @@ -329,7 +329,7 @@ can set this option to generate forms compatible with the Bootstrap 4 CSS framew # config/packages/twig.yaml twig: - form_themes: ['bootstrap_4_layout.html.twig'] + form_themes: ['bootstrap_5_layout.html.twig'] .. code-block:: xml @@ -344,7 +344,7 @@ can set this option to generate forms compatible with the Bootstrap 4 CSS framew https://symfony.com/schema/dic/twig/twig-1.0.xsd"> <twig:config> - <twig:form-theme>bootstrap_4_layout.html.twig</twig:form-theme> + <twig:form-theme>bootstrap_5_layout.html.twig</twig:form-theme> <!-- ... --> </twig:config> </container> @@ -355,13 +355,13 @@ can set this option to generate forms compatible with the Bootstrap 4 CSS framew use Symfony\Config\TwigConfig; return static function (TwigConfig $twig) { - $twig->formThemes(['bootstrap_4_layout.html.twig']); + $twig->formThemes(['bootstrap_5_layout.html.twig']); // ... }; The :ref:`built-in Symfony form themes <symfony-builtin-forms>` include -Bootstrap 3 and 4 as well as Foundation 5 and 6. You can also +Bootstrap 3, 4 and 5, Foundation 5 and 6, as well as Tailwind 2. You can also :ref:`create your own Symfony form theme <create-your-own-form-theme>`. In addition to form themes, Symfony allows you to diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst index b4893beabae..c673bf7fca8 100644 --- a/reference/configuration/twig.rst +++ b/reference/configuration/twig.rst @@ -182,7 +182,7 @@ all the forms of the application: # config/packages/twig.yaml twig: - form_themes: ['bootstrap_4_layout.html.twig', 'form/my_theme.html.twig'] + form_themes: ['bootstrap_5_layout.html.twig', 'form/my_theme.html.twig'] # ... .. code-block:: xml @@ -197,7 +197,7 @@ all the forms of the application: http://symfony.com/schema/dic/twig https://symfony.com/schema/dic/twig/twig-1.0.xsd"> <twig:config> - <twig:form-theme>bootstrap_4_layout.html.twig</twig:form-theme> + <twig:form-theme>bootstrap_5_layout.html.twig</twig:form-theme> <twig:form-theme>form/my_theme.html.twig</twig:form-theme> <!-- ... --> </twig:config> @@ -210,7 +210,7 @@ all the forms of the application: return static function (TwigConfig $twig) { $twig->formThemes([ - 'bootstrap_4_layout.html.twig', + 'bootstrap_5_layout.html.twig', 'form/my_theme.html.twig', ]); From a0f9329cff33b3b0cdbe9e2ba700d51b1d573777 Mon Sep 17 00:00:00 2001 From: gnito-org <70450336+gnito-org@users.noreply.github.com> Date: Sun, 12 Dec 2021 10:38:27 -0400 Subject: [PATCH 1330/1519] Change upgrade-minor.rst to reference Symfony 5 --- setup/upgrade_minor.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/setup/upgrade_minor.rst b/setup/upgrade_minor.rst index 09508c0469d..a6a23b787f1 100644 --- a/setup/upgrade_minor.rst +++ b/setup/upgrade_minor.rst @@ -1,7 +1,7 @@ .. index:: single: Upgrading; Minor Version -Upgrading a Minor Version (e.g. 4.0.0 to 4.1.0) +Upgrading a Minor Version (e.g. 5.0.0 to 5.1.0) =============================================== If you're upgrading a minor version (where the middle number changes), then @@ -24,7 +24,7 @@ There are two steps to upgrading a minor version: The ``composer.json`` file is configured to allow Symfony packages to be upgraded to patch versions. But to upgrade to a new minor version, you will probably need to update the version constraint next to each library starting -``symfony/``. Suppose you are upgrading from Symfony 4.3 to 4.4: +``symfony/``. Suppose you are upgrading from Symfony 5.3 to 5.4: .. code-block:: diff @@ -32,12 +32,12 @@ probably need to update the version constraint next to each library starting "...": "...", "require": { - - "symfony/cache": "4.3.*", - + "symfony/cache": "4.4.*", - - "symfony/config": "4.3.*", - + "symfony/config": "4.4.*", - - "symfony/console": "4.3.*", - + "symfony/console": "4.4.*", + - "symfony/cache": "5.3.*", + + "symfony/cache": "5.4.*", + - "symfony/config": "5.3.*", + + "symfony/config": "5.4.*", + - "symfony/console": "5.3.*", + + "symfony/console": "5.4.*", "...": "...", "...": "A few libraries starting with @@ -57,8 +57,8 @@ Your ``composer.json`` file should also have an ``extra`` block that you will "extra": { "symfony": { "...": "...", - - "require": "4.3.*" - + "require": "4.4.*" + - "require": "5.3.*" + + "require": "5.4.*" } } @@ -82,7 +82,7 @@ to your code to get everything working. Additionally, some features you're using might still work, but might now be deprecated. While that's fine, if you know about these deprecations, you can start to fix them over time. -Every version of Symfony comes with an UPGRADE file (e.g. `UPGRADE-4.4.md`_) +Every version of Symfony comes with an UPGRADE file (e.g. `UPGRADE-5.4.md`_) included in the Symfony directory that describes these changes. If you follow the instructions in the document and update your code accordingly, it should be safe to update in the future. @@ -94,4 +94,4 @@ These documents can also be found in the `Symfony Repository`_. .. include:: /setup/_update_recipes.rst.inc .. _`Symfony Repository`: https://github.com/symfony/symfony -.. _`UPGRADE-4.4.md`: https://github.com/symfony/symfony/blob/4.4/UPGRADE-4.4.md +.. _`UPGRADE-5.4.md`: https://github.com/symfony/symfony/blob/5.4/UPGRADE-5.4.md From d186765328282c6748b6873e2d236b605ddd2564 Mon Sep 17 00:00:00 2001 From: gnito-org <70450336+gnito-org@users.noreply.github.com> Date: Sun, 12 Dec 2021 10:41:45 -0400 Subject: [PATCH 1331/1519] Change upgrade_patch.rst to reference Symfony 6 --- setup/upgrade_patch.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/upgrade_patch.rst b/setup/upgrade_patch.rst index 632f6602550..ee59a811871 100644 --- a/setup/upgrade_patch.rst +++ b/setup/upgrade_patch.rst @@ -1,7 +1,7 @@ .. index:: single: Upgrading; Patch Version -Upgrading a Patch Version (e.g. 5.0.0 to 5.0.1) +Upgrading a Patch Version (e.g. 6.0.0 to 6.0.1) =============================================== When a new patch version is released (only the last number changed), it is a From 68fed1b5c0dd81e70a3a9299094f31084f7ec0ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20TAMARELLE?= <jerome@tamarelle.net> Date: Thu, 7 Oct 2021 22:45:09 +0200 Subject: [PATCH 1332/1519] [Cache] Split PdoAdapter to DoctrineDbalAdapter --- .../adapters/pdo_doctrine_dbal_adapter.rst | 66 ++++++++++++++++--- 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/components/cache/adapters/pdo_doctrine_dbal_adapter.rst b/components/cache/adapters/pdo_doctrine_dbal_adapter.rst index b840da76de7..1f1cd08c8d5 100644 --- a/components/cache/adapters/pdo_doctrine_dbal_adapter.rst +++ b/components/cache/adapters/pdo_doctrine_dbal_adapter.rst @@ -7,16 +7,26 @@ PDO & Doctrine DBAL Cache Adapter ================================= -This adapter stores the cache items in an SQL database. It requires a :phpclass:`PDO`, -`Doctrine DBAL Connection`_, or `Data Source Name (DSN)`_ as its first parameter, and -optionally a namespace, default cache lifetime, and options array as its second, -third, and forth parameters:: +The PDO and Doctrine DBAL adapters store the cache items in a table of an SQL database. + +.. note:: + + Adapters implement :class:`Symfony\\Component\\Cache\\PruneableInterface`, + allowing for manual :ref:`pruning of expired cache entries <component-cache-cache-pool-prune>` by + calling the ``prune()`` method. + +Using :phpclass:`PDO` +--------------------- + +The :class:`Symfony\\Component\\Cache\\Adapter\\PdoAdapter` requires a :phpclass:`PDO`, +or `Data Source Name (DSN)`_ as its first parameter, and optionally a namespace, +default cache lifetime, and options array as its second, third, and forth parameters:: use Symfony\Component\Cache\Adapter\PdoAdapter; $cache = new PdoAdapter( - // a PDO, a Doctrine DBAL connection or DSN for lazy connecting through PDO + // a PDO connection or DSN for lazy connecting through PDO $databaseConnectionOrDSN, // the string prefixed to the keys of the items stored in this cache @@ -37,16 +47,54 @@ You can also create this table explicitly by calling the :method:`Symfony\\Component\\Cache\\Adapter\\PdoAdapter::createTable` method in your code. +.. deprecated:: 5.4 + + Using :class:`Symfony\\Component\\Cache\\Adapter\\PdoAdapter` with a + :class:`Doctrine\\DBAL\\Connection` or a DBAL URL is deprecated since Symfony 5.4 + and will be removed in Symfony 6.0. + Use :class:`Symfony\\Component\\Cache\\Adapter\\DoctrineDbalAdapter` instead. + .. tip:: When passed a `Data Source Name (DSN)`_ string (instead of a database connection - class instance), the connection will be lazy-loaded when needed. + class instance), the connection will be lazy-loaded when needed. DBAL Connection + are lazy-loaded by default; some additional options may be necessary to detect + the database engine and version without opening the connection. + + +Using Doctrine DBAL +------------------- + +The :class:`Symfony\\Component\\Cache\\Adapter\\DoctrineDbalAdapter` requires a +`Doctrine DBAL Connection`_, or `Doctrine DBAL URL`_ as its first parameter, and +optionally a namespace, default cache lifetime, and options array as its second, +third, and forth parameters:: + + use Symfony\Component\Cache\Adapter\DoctrineDbalAdapter; + + $cache = new DoctrineDbalAdapter( + + // a Doctrine DBAL connection or DBAL URL + $databaseConnectionOrURL, + + // the string prefixed to the keys of the items stored in this cache + $namespace = '', + + // the default lifetime (in seconds) for cache items that do not define their + // own lifetime, with a value 0 causing items to be stored indefinitely (i.e. + // until the database table is truncated or its rows are otherwise deleted) + $defaultLifetime = 0, + + // an array of options for configuring the database table and connection + $options = [] + ); .. note:: - This adapter implements :class:`Symfony\\Component\\Cache\\PruneableInterface`, - allowing for manual :ref:`pruning of expired cache entries <component-cache-cache-pool-prune>` by - calling its ``prune()`` method. + DBAL Connection are lazy-loaded by default; some additional options may be + necessary to detect the database engine and version without opening the + connection. .. _`Doctrine DBAL Connection`: https://github.com/doctrine/dbal/blob/master/src/Connection.php +.. _`Doctrine DBAL URL`: https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url .. _`Data Source Name (DSN)`: https://en.wikipedia.org/wiki/Data_source_name From 474f858f9309aaed95da1cfbebcef0c7d9e5ed82 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Mon, 13 Dec 2021 12:41:34 +0100 Subject: [PATCH 1333/1519] Move the contents to a caution admonition --- mailer.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/mailer.rst b/mailer.rst index 04079f9326c..081a88dea24 100644 --- a/mailer.rst +++ b/mailer.rst @@ -93,13 +93,15 @@ native ``native://default`` Mailer uses the sendmail in the ``sendmail_path`` setting of ``php.ini``. On Windows hosts, Mailer fallbacks to ``smtp`` and ``smtp_port`` ``php.ini`` settings when ``sendmail_path`` is not configured. - Be warned that if ``php.ini`` uses the ``sendmail -t`` command, - you won't have error reporting and ``Bcc`` headers won't be removed. - It's highly recommended to NOT use this DSN as you cannot control - how sendmail is configured (prefer using ``sendmail://default`` - if possible). ============ ======================================== ============================================================== +.. caution:: + + When using ``native://default``, if ``php.ini`` uses the ``sendmail -t`` + command, you won't have error reporting and ``Bcc`` headers won't be removed. + It's highly recommended to NOT use ``native://default`` as you cannot control + how sendmail is configured (prefer using ``sendmail://default`` if possible). + Using a 3rd Party Transport ~~~~~~~~~~~~~~~~~~~~~~~~~~~ From c4e19eb6fed4983470af73823d5ce63a92a7d0d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20TAMARELLE?= <jerome@tamarelle.net> Date: Wed, 14 Oct 2020 22:26:13 +0200 Subject: [PATCH 1334/1519] [Assets] Add doc for strict mode strategy --- components/asset.rst | 20 ++++++++++++++++++++ reference/configuration/framework.rst | 25 +++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/components/asset.rst b/components/asset.rst index 5044ef2dab9..cacb8bbe6c8 100644 --- a/components/asset.rst +++ b/components/asset.rst @@ -167,6 +167,26 @@ In those cases, use the echo $package->getUrl('css/app.css'); // result: build/css/app.b916426ea1d10021f3f17ce8031f93c2.css +If you request an asset that is *not found* in the ``rev-manifest.json`` file, the original - +*unmodified* - asset path will be returned. +The ``$strictMode`` argument helps for debugging as it throws an exception when the asset is +not listed in the manifest:: + + use Symfony\Component\Asset\Package; + use Symfony\Component\Asset\VersionStrategy\JsonManifestVersionStrategy; + + // The value of $strictMode can be specific per environment "true" for debugging and "false" for stability. + $strictMode = true; + // assumes the JSON file above is called "rev-manifest.json" + $package = new Package(new JsonManifestVersionStrategy(__DIR__.'/rev-manifest.json', null, $strictMode)); + + echo $package->getUrl('not-found.css'); + // error: + +.. versionadded:: 5.4 + + The ``$strictMode`` option was introduced in Symfony 5.4. + If your JSON file is not on your local filesystem but is accessible over HTTP, use the :class:`Symfony\\Component\\Asset\\VersionStrategy\\RemoteJsonManifestVersionStrategy` with the :doc:`HttpClient component </http_client>`:: diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 6f09d0cb7b6..20687485b16 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1879,6 +1879,7 @@ Each package can configure the following options: * :ref:`version <reference-framework-assets-version>` * :ref:`version_format <reference-assets-version-format>` * :ref:`json_manifest_path <reference-assets-json-manifest-path>` +* :ref:`strict_mode <reference-assets-strict-mode>` .. _reference-framework-assets-version: .. _ref-framework-assets-version: @@ -2122,6 +2123,8 @@ package: foo_package: # this package uses its own manifest (the default file is ignored) json_manifest_path: "%kernel.project_dir%/public/build/a_different_manifest.json" + # Throws an exception when an asset is not found in the manifest + strict_mode: %kernel.debug% bar_package: # this package uses the global manifest (the default file is used) base_path: '/images' @@ -2142,9 +2145,10 @@ package: <!-- you can use absolute URLs too and Symfony will download them automatically --> <!-- <framework:assets json-manifest-path="https://cdn.example.com/manifest.json"> --> <!-- this package uses its own manifest (the default file is ignored) --> + <!-- Throws an exception when an asset is not found in the manifest --> <framework:package name="foo_package" - json-manifest-path="%kernel.project_dir%/public/build/a_different_manifest.json"/> + json-manifest-path="%kernel.project_dir%/public/build/a_different_manifest.json" strict-mode="%kernel.debug%"/> <!-- this package uses the global manifest (the default file is used) --> <framework:package name="bar_package" @@ -2168,7 +2172,9 @@ package: // 'json_manifest_path' => 'https://cdn.example.com/manifest.json', $framework->assets()->package('foo_package') // this package uses its own manifest (the default file is ignored) - ->jsonManifestPath('%kernel.project_dir%/public/build/a_different_manifest.json'); + ->jsonManifestPath('%kernel.project_dir%/public/build/a_different_manifest.json') + // Throws an exception when an asset is not found in the manifest + ->setStrictMode('%kernel.debug%'); $framework->assets()->package('bar_package') // this package uses the global manifest (the default file is used) @@ -2190,11 +2196,26 @@ package: If you request an asset that is *not found* in the ``manifest.json`` file, the original - *unmodified* - asset path will be returned. + Since Symfony 5.4, you can set ``strict_mode`` to ``true`` to get an exception when an asset is *not found*. .. note:: If an URL is set, the JSON manifest is downloaded on each request using the `http_client`_. +.. _reference-assets-strict-mode: + +strict_mode +........... + +**type**: ``boolean`` **default**: ``false`` + +When enabled, the strict mode assert that all requested assets are in the manifest file. +This option is useful to detect typo or missing assets, the recommended value is ``%kernel.debug%``. + +.. versionadded:: 5.4 + + This option was introduced in Symfony 5.4. + translator ~~~~~~~~~~ From 3e4cd5e9e5e0b23a8eabf2469f5e62d296ffeca2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Mon, 13 Dec 2021 17:24:35 +0100 Subject: [PATCH 1335/1519] Tweaks --- components/asset.rst | 8 ++++---- reference/configuration/framework.rst | 9 +++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/components/asset.rst b/components/asset.rst index cacb8bbe6c8..92de7ec5ef7 100644 --- a/components/asset.rst +++ b/components/asset.rst @@ -167,10 +167,10 @@ In those cases, use the echo $package->getUrl('css/app.css'); // result: build/css/app.b916426ea1d10021f3f17ce8031f93c2.css -If you request an asset that is *not found* in the ``rev-manifest.json`` file, the original - -*unmodified* - asset path will be returned. -The ``$strictMode`` argument helps for debugging as it throws an exception when the asset is -not listed in the manifest:: +If you request an asset that is *not found* in the ``rev-manifest.json`` file, +the original - *unmodified* - asset path will be returned. The ``$strictMode`` +argument helps debug issues because it throws an exception when the asset is not +listed in the manifest:: use Symfony\Component\Asset\Package; use Symfony\Component\Asset\VersionStrategy\JsonManifestVersionStrategy; diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 20687485b16..25ad2caaa1d 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -2209,12 +2209,13 @@ strict_mode **type**: ``boolean`` **default**: ``false`` -When enabled, the strict mode assert that all requested assets are in the manifest file. -This option is useful to detect typo or missing assets, the recommended value is ``%kernel.debug%``. - .. versionadded:: 5.4 - This option was introduced in Symfony 5.4. + The ``strict_mode`` option was introduced in Symfony 5.4. + +When enabled, the strict mode asserts that all requested assets are in the +manifest file. This option is useful to detect typos or missing assets, the +recommended value is ``%kernel.debug%``. translator ~~~~~~~~~~ From f2e2bca4e421fc9fd192cc80fcc39fdd897f6308 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Mon, 13 Dec 2021 17:25:14 +0100 Subject: [PATCH 1336/1519] Remove the versionadded directive --- components/asset.rst | 4 ---- reference/configuration/framework.rst | 4 ---- 2 files changed, 8 deletions(-) diff --git a/components/asset.rst b/components/asset.rst index a629392c27b..9301c091164 100644 --- a/components/asset.rst +++ b/components/asset.rst @@ -183,10 +183,6 @@ listed in the manifest:: echo $package->getUrl('not-found.css'); // error: -.. versionadded:: 5.4 - - The ``$strictMode`` option was introduced in Symfony 5.4. - If your JSON file is not on your local filesystem but is accessible over HTTP, use the :class:`Symfony\\Component\\Asset\\VersionStrategy\\RemoteJsonManifestVersionStrategy` with the :doc:`HttpClient component </http_client>`:: diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index bd17a7c4344..9e3fc066d5d 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -2123,10 +2123,6 @@ strict_mode **type**: ``boolean`` **default**: ``false`` -.. versionadded:: 5.4 - - The ``strict_mode`` option was introduced in Symfony 5.4. - When enabled, the strict mode asserts that all requested assets are in the manifest file. This option is useful to detect typos or missing assets, the recommended value is ``%kernel.debug%``. From 16d036e76bed4857fc514167868248bffd7231db Mon Sep 17 00:00:00 2001 From: Antoine Makdessi <amakdessi@me.com> Date: Thu, 16 Dec 2021 12:40:44 +0100 Subject: [PATCH 1337/1519] Update twig_extension.rst --- templating/twig_extension.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templating/twig_extension.rst b/templating/twig_extension.rst index 03fcd7a9471..ad6e6cda31b 100644 --- a/templating/twig_extension.rst +++ b/templating/twig_extension.rst @@ -42,7 +42,7 @@ Create a class that extends ``AbstractExtension`` and fill in the logic:: ]; } - public function formatPrice($number, $decimals = 0, $decPoint = '.', $thousandsSep = ',') + public function formatPrice(float $number, int $decimals = 0, string $decPoint = '.', string $thousandsSep = ','): string { $price = number_format($number, $decimals, $decPoint, $thousandsSep); $price = '$'.$price; @@ -69,7 +69,7 @@ If you want to create a function instead of a filter, define the ]; } - public function calculateArea(int $width, int $length) + public function calculateArea(int $width, int $length): int { return $width * $length; } @@ -157,7 +157,7 @@ previous ``formatPrice()`` method:: // extensions, you'll need to inject services using this constructor } - public function formatPrice($number, $decimals = 0, $decPoint = '.', $thousandsSep = ',') + public function formatPrice(float $number, int $decimals = 0, string $decPoint = '.', string $thousandsSep = ','): string { $price = number_format($number, $decimals, $decPoint, $thousandsSep); $price = '$'.$price; From f948ab29ffebf4673c585d5f41a6eecb8c8d5aeb Mon Sep 17 00:00:00 2001 From: tchap <tchapi@users.noreply.github.com> Date: Wed, 24 Nov 2021 09:53:39 +0100 Subject: [PATCH 1338/1519] Update mercure.rst regarding JWT token secret :wave: The documentation for the configuration of mercure seems quite wrong: it has a big "caution" block stating that the `MERCURE_JWT_SECRET` should contain an _actual JWT_ ... instead of a secret, which is weird (and definitely not how it works). I propose to remove these (maybe out of date?) parts to prevent further confusion (_I spent a full day examining the actual source to understand what was really needed in the env var_). Also, added a tip on how setting the cookies twice would not work. PS: I created this PR against the 5.3 (current) branch since the 4.4 branch does not have the same paragraphs. Hope it's good. --- mercure.rst | 41 +++++++++-------------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/mercure.rst b/mercure.rst index 205b426a922..c2435a826d7 100644 --- a/mercure.rst +++ b/mercure.rst @@ -111,38 +111,7 @@ the publicly available URL (e.g. ``https://example.com/.well-known/mercure``). The clients must also bear a `JSON Web Token`_ (JWT) to the Mercure Hub to be authorized to publish updates and, sometimes, to subscribe. -This JWT should be stored in the ``MERCURE_JWT_SECRET`` environment variable. - -The JWT must be signed with the same secret key as the one used by -the Hub to verify the JWT (``!ChangeMe!`` in you use the Local Web Server or -Symfony Docker). -Its payload must contain at least the following structure to be allowed to -publish: - -.. code-block:: json - - { - "mercure": { - "publish": [] - } - } - -Because the array is empty, the Symfony app will only be authorized to publish -public updates (see the authorization_ section for further information). - -.. tip:: - - The jwt.io website is a convenient way to create and sign JWTs. - Checkout this `example JWT`_, that grants publishing rights for all *topics* - (notice the star in the array). - Don't forget to set your secret key properly in the bottom of the right panel of the form! - -.. caution:: - - Don't put the secret key in ``MERCURE_JWT_SECRET``, it will not work! - This environment variable must contain a JWT, signed with the secret key. - - Also, be sure to keep both the secret key and the JWTs... secrets! +This token must be signed with the same secret key as the one used by the Hub to verify the JWT (``!ChangeMe!`` in you use the Local Web Server or Symfony Docker), which should be stored in the ``MERCURE_JWT_SECRET`` environment variable. If you don't want to use the provided environment variables, use the following configuration: @@ -482,6 +451,14 @@ And here is the controller:: } } + +.. tip:: + + You cannot use the ``mercure()`` helper and the ``setCookie()`` + method at the same time (it would set the cookie twice on a single request). Choose + either one method or the other. + + Programmatically Generating The JWT Used to Publish --------------------------------------------------- From 123ad73a49070838267d884ef37949ad54852ec9 Mon Sep 17 00:00:00 2001 From: tchap <tchapi@users.noreply.github.com> Date: Wed, 24 Nov 2021 10:47:51 +0100 Subject: [PATCH 1339/1519] Remove unneeded JWT reference --- mercure.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/mercure.rst b/mercure.rst index c2435a826d7..874e5d3bb12 100644 --- a/mercure.rst +++ b/mercure.rst @@ -711,7 +711,6 @@ Going further .. _`Symfony Docker`: https://github.com/dunglas/symfony-docker/ .. _`API Platform distribution`: https://api-platform.com/docs/distribution/ .. _`JSON Web Token`: https://tools.ietf.org/html/rfc7519 -.. _`example JWT`: https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOlsiKiJdfX0.iHLdpAEjX4BqCsHJEegxRmO-Y6sMxXwNATrQyRNt3GY .. _`IRI`: https://tools.ietf.org/html/rfc3987 .. _`practical UI`: https://twitter.com/ChromeDevTools/status/562324683194785792 .. _`the dedicated API Platform documentation`: https://api-platform.com/docs/core/mercure/ From 142a6f9ac8387f58b5f313ba6a70404851a63024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= <kevin@dunglas.fr> Date: Thu, 16 Dec 2021 14:12:40 +0100 Subject: [PATCH 1340/1519] [mercure] Compatibility with the Docker integration and various improvements --- mercure.rst | 161 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 111 insertions(+), 50 deletions(-) diff --git a/mercure.rst b/mercure.rst index 874e5d3bb12..e84749d148d 100644 --- a/mercure.rst +++ b/mercure.rst @@ -17,12 +17,12 @@ requiring "push" capabilities. Symfony provides a straightforward component, built on top of `the Mercure protocol`_, specifically designed for this class of use cases. -Mercure is an open protocol designed from the ground to publish updates from +Mercure is an open protocol designed from the ground up to publish updates from server to clients. It is a modern and efficient alternative to timer-based polling and to WebSocket. Because it is built on top `Server-Sent Events (SSE)`_, Mercure is supported -out of the box in most modern browsers (old versions of Edge and IE require +out of the box in modern browsers (old versions of Edge and IE require `a polyfill`_) and has `high-level implementations`_ in many programming languages. @@ -42,49 +42,44 @@ generated using the API Platform client generator. Installation ------------ -Running a Mercure Hub -~~~~~~~~~~~~~~~~~~~~~ +Installing the Symfony Bundle +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Run this command to install the Mercure support: + +.. code-block:: terminal + + $ composer require mercure To manage persistent connections, Mercure relies on a Hub: a dedicated server that handles persistent SSE connections with the clients. The Symfony app publishes the updates to the hub, that will broadcast them to clients. -.. image:: /_images/mercure/schema.png - -An official and open source (AGPL) Hub based on the Caddy web server -can be downloaded as a static binary from `Mercure.rocks`_. -A Docker image, a Helm chart for Kubernetes -and a managed, High Availability Hub are also provided. - -If you use `Symfony Docker`_ or the `API Platform distribution`_, a Mercure Hub -is automatically installed and your Symfony application is automatically -configured to use it. You can jump directly to the next section. +Thanks to :ref:`the Docker integration of Symfony </setup/docker>`, +:ref:`Flex <symfony-flex>` proposes to install a Mercure hub. +Run ``docker-compose up`` to start the hub if you have chosen this option. If you use the :doc:`Symfony Local Web Server </setup/symfony_server>`, -a Mercure hub will be automatically available as a Docker service thanks to its -:ref:`Docker integration <symfony-server-docker>. - -Be sure that recent versions of Docker and Docker Compose are properly installed -on your computer and to start the Symfony Local Web Server with the ``--no-tls`` -option: +you must start it with the ``--no-tls`` option. .. code-block:: terminal $ symfony server:start --no-tls -d -Installing the Symfony Bundle -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Run this command to install the Mercure support before using it: +Running a Mercure Hub +~~~~~~~~~~~~~~~~~~~~~ -.. code-block:: terminal +.. image:: /_images/mercure/schema.png - $ composer require mercure +If you use the Docker integration, a hub is already up and running, +and you can go straight to the next section. -:ref:`Symfony Flex <symfony-flex>` has automatically installed and configured -MercureBundle. It also created (if needed) and configured a Docker Compose -definition that provides a Mercure service. Run ``docker-compose up`` to start it. +Otherwise, and in production, you have to install a hub by yourself. +An official and open source (AGPL) Hub based on the Caddy web server +can be downloaded as a static binary from `Mercure.rocks`_. +A Docker image, a Helm chart for Kubernetes +and a managed, High Availability Hub are also provided. Configuration ------------- @@ -95,23 +90,26 @@ The preferred way to configure MercureBundle is using When MercureBundle has been installed, the ``.env`` file of your project has been updated by the Flex recipe to include the available env vars. -If you use the Symfony Local Web Server, Symfony Docker or the API Platform -distribution, the Symfony app is automatically configured and you can skip -straight to the next section. +Also, if you are using the Docker integration with the Symfony Local Web Server, +`Symfony Docker`_ or the `API Platform distribution`_, +the proper environment variables have been automatically set. +Skip straight to the next section. Otherwise, set the URL of your hub as the value of the ``MERCURE_URL`` and ``MERCURE_PUBLIC_URL`` env vars. Sometimes a different URL must be called by the Symfony app (usually to publish), and the JavaScript client (usually to subscribe). It's especially common when the Symfony app must use a local URL and the client-side JavaScript code a public one. -In this case, ``MERCURE_URL`` must contain the local URL that will be used by the +In this case, ``MERCURE_URL`` must contain the local URL used by the Symfony app (e.g. ``https://mercure/.well-known/mercure``), and ``MERCURE_PUBLIC_URL`` the publicly available URL (e.g. ``https://example.com/.well-known/mercure``). The clients must also bear a `JSON Web Token`_ (JWT) to the Mercure Hub to be authorized to publish updates and, sometimes, to subscribe. -This token must be signed with the same secret key as the one used by the Hub to verify the JWT (``!ChangeMe!`` in you use the Local Web Server or Symfony Docker), which should be stored in the ``MERCURE_JWT_SECRET`` environment variable. +This token must be signed with the same secret key as the one used by the Hub to verify the JWT (``!ChangeMe!`` in you use the Docker integration). +This secret key must be stored in the ``MERCURE_JWT_SECRET`` environment variable. +MercureBundle will use it to automatically generate and sign the needed JWTs. If you don't want to use the provided environment variables, use the following configuration: @@ -155,6 +153,68 @@ use the following configuration: ], ]); +Alternatively, it's also possible to pass directly the JWT to use: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/mercure.yaml + mercure: + hubs: + default: + url: https://mercure-hub.example.com/.well-known/mercure + jwt: + value: 'the.JWT' + + .. code-block:: xml + + <!-- config/packages/mercure.xml --> + <?xml version="1.0" encoding="UTF-8" ?> + <config> + <hub + name="default" + url="https://mercure-hub.example.com/.well-known/mercure" + > + <jwt value="the.JWT"/> + </hub> + </config> + + .. code-block:: php + + // config/packages/mercure.php + $container->loadFromExtension('mercure', [ + 'hubs' => [ + 'default' => [ + 'url' => 'https://mercure-hub.example.com/.well-known/mercure', + 'jwt' => [ + 'value' => 'the.JWT', + ], + ], + ], + ]); + + +The JWT payload must contain at least the following structure to be allowed to +publish: + +.. code-block:: json + + { + "mercure": { + "publish": [] + } + } + +Because the array is empty, the Symfony app will only be authorized to publish +public updates (see the authorization_ section for further information). + +.. tip:: + + The jwt.io website is a convenient way to create and sign JWTs. + Checkout this `example JWT`_, that grants publishing rights for all *topics* + (notice the star in the array). + Don't forget to set your secret key properly in the bottom of the right panel of the form! Basic Usage ----------- @@ -222,8 +282,8 @@ Subscribing to updates in JavaScript from a Twig template is straightforward: } </script> -The ``mercure()`` Twig function will generate the URL of the Mercure hub -according to the configuration. The URL will include the ``topic`` query +The ``mercure()`` Twig function generates the URL of the Mercure hub +according to the configuration. The URL includes the ``topic`` query parameters corresponding to the topics passed as first argument. If you want to access to this URL from an external JavaScript file, generate the @@ -302,9 +362,9 @@ by using the ``AbstractController::addLink`` helper method:: class DiscoverController extends AbstractController { - public function __invoke(Request $request, Discovery $discovery): JsonResponse + public function discover(Request $request, Discovery $discovery): JsonResponse { - // Link: <http://localhost:3000/.well-known/mercure>; rel="mercure" + // Link: <http://hub.example.com/.well-known/mercure>; rel="mercure" $discovery->addLink($request); return $this->json([ @@ -320,7 +380,7 @@ and to subscribe to it: .. code-block:: javascript // Fetch the original resource served by the Symfony web API - fetch('/books/1') // Has Link: <http://localhost:3000/.well-known/mercure>; rel="mercure" + fetch('/books/1') // Has Link: <http://hub.example.com/.well-known/mercure>; rel="mercure" .then(response => { // Extract the hub URL from the Link header const hubUrl = response.headers.get('Link').match(/<([^>]+)>;\s+rel=(?:mercure|"[^"]*mercure[^"]*")/)[1]; @@ -373,9 +433,9 @@ To provide this JWT, the subscriber can use a cookie, or a ``Authorization`` HTTP header. Cookies can be set automatically by Symfony by passing the appropriate options -to the ``mercure()`` Twig function. Cookies set by Symfony will be automatically +to the ``mercure()`` Twig function. Cookies set by Symfony are automatically passed by the browsers to the Mercure hub if the ``withCredentials`` attribute -of the ``EventSource`` class is set to ``true``. Then, the Hub will verify the +of the ``EventSource`` class is set to ``true``. Then, the Hub verifies the validity of the provided JWT, and extract the topic selectors from it. .. code-block:: twig @@ -572,9 +632,9 @@ its Mercure support. Testing -------- -During unit testing there is no need to send updates to Mercure. +During unit testing it's usually not needed to send updates to Mercure. -You can instead make use of the `MockHub`:: +You can instead make use of the `MockHub` class:: // tests/FunctionalTest.php namespace App\Tests\Unit\Controller; @@ -601,10 +661,10 @@ You can instead make use of the `MockHub`:: } } -During functional testing you can instead decorate the Hub:: +During functional testing you can instead create a stub of the Hub:: - // tests/Functional/Fixtures/HubStub.php - namespace App\Tests\Functional\Fixtures; + // tests/Functional/Stub/HubStub.php + namespace App\Tests\Functional\Stub; use Symfony\Component\Mercure\HubInterface; use Symfony\Component\Mercure\Update; @@ -619,14 +679,14 @@ During functional testing you can instead decorate the Hub:: // implement rest of HubInterface methods here } -HubStub decorates the default hub service so no updates are actually -sent. Here is the HubStub implementation: +Use ``HubStub`` to replace the default hub service so no updates are actually +sent: .. code-block:: yaml # config/services_test.yaml - App\Tests\Functional\Fixtures\HubStub: - decorates: mercure.hub.default + mercure.hub.default: + class: App\Tests\Functional\Stub\HubStub .. tip:: @@ -711,6 +771,7 @@ Going further .. _`Symfony Docker`: https://github.com/dunglas/symfony-docker/ .. _`API Platform distribution`: https://api-platform.com/docs/distribution/ .. _`JSON Web Token`: https://tools.ietf.org/html/rfc7519 +.. _`example JWT`: https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOlsiKiJdfX0.iHLdpAEjX4BqCsHJEegxRmO-Y6sMxXwNATrQyRNt3GY .. _`IRI`: https://tools.ietf.org/html/rfc3987 .. _`practical UI`: https://twitter.com/ChromeDevTools/status/562324683194785792 .. _`the dedicated API Platform documentation`: https://api-platform.com/docs/core/mercure/ From 74961497f5a672cb8c89606cdc31ec4822480037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= <kevin@dunglas.fr> Date: Thu, 16 Dec 2021 15:20:34 +0100 Subject: [PATCH 1341/1519] review --- mercure.rst | 107 ++++++++++++++++++++++++---------------------------- 1 file changed, 50 insertions(+), 57 deletions(-) diff --git a/mercure.rst b/mercure.rst index e84749d148d..47b4577f5cd 100644 --- a/mercure.rst +++ b/mercure.rst @@ -111,8 +111,16 @@ This token must be signed with the same secret key as the one used by the Hub to This secret key must be stored in the ``MERCURE_JWT_SECRET`` environment variable. MercureBundle will use it to automatically generate and sign the needed JWTs. -If you don't want to use the provided environment variables, -use the following configuration: +In addition to these environment variables, +MercureBundle provides a more advanced configuration configuration: + +* ``secret``: the key to use to sign the JWT +* ``publish``: a list of topics to allow publishing to when generating the JWT +* ``subscribe``: a list of topics to allow subscribing to when generating the JWT +* ``algorithm``: The algorithm to use to sign the JWT +* ``provider``: The ID of a service to call to provide the JWT +* ``factory``: The ID of a service to call to create the JWT +* ``value``: the raw JWT to use (all other options will be ignored) .. configuration-block:: @@ -125,6 +133,12 @@ use the following configuration: url: https://mercure-hub.example.com/.well-known/mercure jwt: secret: '!ChangeMe!' + publish: ['foo', 'https://example.com/foo'] + subscribe: ['bar', 'https://example.com/bar'] + algorithm: 'hmac.sha256' + provider: 'My\Provider' + factory: 'My\Factory' + value: 'my.jwt' .. code-block:: xml @@ -135,7 +149,18 @@ use the following configuration: name="default" url="https://mercure-hub.example.com/.well-known/mercure" > - <jwt secret="!ChangeMe!"/> + <jwt + secret="!ChangeMe!" + algorithm="hmac.sha256" + provider="My\Provider" + factory="My\Factory" + value="my.jwt" + > + <publish>foo</publish> + <publish>https://example.com/foo</publish> + <subscribe>bar</subscribe> + <subscribe>https://example.com/bar</subscribe> + </jwt> </hub> </config> @@ -148,68 +173,32 @@ use the following configuration: 'url' => 'https://mercure-hub.example.com/.well-known/mercure', 'jwt' => [ 'secret' => '!ChangeMe!', + 'publish' => ['foo', 'https://example.com/foo'], + 'subscribe' => ['bar', 'https://example.com/bar'], + 'algorithm' => 'hmac.sha256', + 'provider' => 'My\Provider', + 'factory' => 'My\Factory', + 'value' => 'my.jwt', ], ], ], ]); -Alternatively, it's also possible to pass directly the JWT to use: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/mercure.yaml - mercure: - hubs: - default: - url: https://mercure-hub.example.com/.well-known/mercure - jwt: - value: 'the.JWT' - - .. code-block:: xml - - <!-- config/packages/mercure.xml --> - <?xml version="1.0" encoding="UTF-8" ?> - <config> - <hub - name="default" - url="https://mercure-hub.example.com/.well-known/mercure" - > - <jwt value="the.JWT"/> - </hub> - </config> - - .. code-block:: php - - // config/packages/mercure.php - $container->loadFromExtension('mercure', [ - 'hubs' => [ - 'default' => [ - 'url' => 'https://mercure-hub.example.com/.well-known/mercure', - 'jwt' => [ - 'value' => 'the.JWT', - ], - ], - ], - ]); - +.. tip:: -The JWT payload must contain at least the following structure to be allowed to -publish: + The JWT payload must contain at least the following structure to be allowed to + publish: -.. code-block:: json + .. code-block:: json - { - "mercure": { - "publish": [] + { + "mercure": { + "publish": [] + } } - } - -Because the array is empty, the Symfony app will only be authorized to publish -public updates (see the authorization_ section for further information). -.. tip:: + Because the array is empty, the Symfony app will only be authorized to publish + public updates (see the authorization_ section for further information). The jwt.io website is a convenient way to create and sign JWTs. Checkout this `example JWT`_, that grants publishing rights for all *topics* @@ -364,7 +353,7 @@ by using the ``AbstractController::addLink`` helper method:: { public function discover(Request $request, Discovery $discovery): JsonResponse { - // Link: <http://hub.example.com/.well-known/mercure>; rel="mercure" + // Link: <https://hub.example.com/.well-known/mercure>; rel="mercure" $discovery->addLink($request); return $this->json([ @@ -380,7 +369,7 @@ and to subscribe to it: .. code-block:: javascript // Fetch the original resource served by the Symfony web API - fetch('/books/1') // Has Link: <http://hub.example.com/.well-known/mercure>; rel="mercure" + fetch('/books/1') // Has Link: <https://hub.example.com/.well-known/mercure>; rel="mercure" .then(response => { // Extract the hub URL from the Link header const hubUrl = response.headers.get('Link').match(/<([^>]+)>;\s+rel=(?:mercure|"[^"]*mercure[^"]*")/)[1]; @@ -688,6 +677,10 @@ sent: mercure.hub.default: class: App\Tests\Functional\Stub\HubStub +As MercureBundle support multiple hubs, you may have to replace +the other service definitions accordingly. + + .. tip:: Symfony Panther has `a feature to test applications using Mercure`_. From e35f1cc895621aa21a391aae7df9f9f1feb1a780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= <kevin@dunglas.fr> Date: Thu, 16 Dec 2021 15:21:32 +0100 Subject: [PATCH 1342/1519] Update mercure.rst Co-authored-by: Robin Chalas <chalasr@users.noreply.github.com> --- mercure.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mercure.rst b/mercure.rst index 47b4577f5cd..b3ba56900ee 100644 --- a/mercure.rst +++ b/mercure.rst @@ -650,7 +650,7 @@ You can instead make use of the `MockHub` class:: } } -During functional testing you can instead create a stub of the Hub:: +For functional testing, you can instead create a stub of the Hub:: // tests/Functional/Stub/HubStub.php namespace App\Tests\Functional\Stub; @@ -680,7 +680,6 @@ sent: As MercureBundle support multiple hubs, you may have to replace the other service definitions accordingly. - .. tip:: Symfony Panther has `a feature to test applications using Mercure`_. From 81c1387c76deeb8be285f6cbc0372629fdc3ae88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= <kevin@dunglas.fr> Date: Thu, 16 Dec 2021 15:38:19 +0100 Subject: [PATCH 1343/1519] Update mercure.rst Co-authored-by: Saif Eddin Gmati <29315886+azjezz@users.noreply.github.com> --- mercure.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mercure.rst b/mercure.rst index b3ba56900ee..e61250c8d47 100644 --- a/mercure.rst +++ b/mercure.rst @@ -119,7 +119,7 @@ MercureBundle provides a more advanced configuration configuration: * ``subscribe``: a list of topics to allow subscribing to when generating the JWT * ``algorithm``: The algorithm to use to sign the JWT * ``provider``: The ID of a service to call to provide the JWT -* ``factory``: The ID of a service to call to create the JWT +* ``factory``: The ID of a service to call to create the JWT (all other options, beside `subscribe`, and `publish` will be ignored) * ``value``: the raw JWT to use (all other options will be ignored) .. configuration-block:: From 3ca1aa14662e08d85fd565b0cb0ee275b89b4e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= <kevin@dunglas.fr> Date: Thu, 16 Dec 2021 15:38:25 +0100 Subject: [PATCH 1344/1519] Update mercure.rst Co-authored-by: Saif Eddin Gmati <29315886+azjezz@users.noreply.github.com> --- mercure.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mercure.rst b/mercure.rst index e61250c8d47..e1b85979550 100644 --- a/mercure.rst +++ b/mercure.rst @@ -117,7 +117,7 @@ MercureBundle provides a more advanced configuration configuration: * ``secret``: the key to use to sign the JWT * ``publish``: a list of topics to allow publishing to when generating the JWT * ``subscribe``: a list of topics to allow subscribing to when generating the JWT -* ``algorithm``: The algorithm to use to sign the JWT +* ``algorithm``: The algorithm to use to sign the JWT (only usable when `secret` is provided ) * ``provider``: The ID of a service to call to provide the JWT * ``factory``: The ID of a service to call to create the JWT (all other options, beside `subscribe`, and `publish` will be ignored) * ``value``: the raw JWT to use (all other options will be ignored) From b4fb9fbe889f9e37bf02ab6e03a4219acd068e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= <kevin@dunglas.fr> Date: Thu, 16 Dec 2021 15:38:33 +0100 Subject: [PATCH 1345/1519] Update mercure.rst Co-authored-by: Saif Eddin Gmati <29315886+azjezz@users.noreply.github.com> --- mercure.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mercure.rst b/mercure.rst index e1b85979550..41d5e51b03b 100644 --- a/mercure.rst +++ b/mercure.rst @@ -116,7 +116,7 @@ MercureBundle provides a more advanced configuration configuration: * ``secret``: the key to use to sign the JWT * ``publish``: a list of topics to allow publishing to when generating the JWT -* ``subscribe``: a list of topics to allow subscribing to when generating the JWT +* ``subscribe``: a list of topics to allow subscribing to when generating the JWT (only usable when `secret`, or `factory` are provided ) * ``algorithm``: The algorithm to use to sign the JWT (only usable when `secret` is provided ) * ``provider``: The ID of a service to call to provide the JWT * ``factory``: The ID of a service to call to create the JWT (all other options, beside `subscribe`, and `publish` will be ignored) From ec8708560d9535b976a4ea3074b01667e8d40f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= <kevin@dunglas.fr> Date: Thu, 16 Dec 2021 15:38:52 +0100 Subject: [PATCH 1346/1519] Update mercure.rst Co-authored-by: Saif Eddin Gmati <29315886+azjezz@users.noreply.github.com> --- mercure.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mercure.rst b/mercure.rst index 41d5e51b03b..92e770f1089 100644 --- a/mercure.rst +++ b/mercure.rst @@ -115,7 +115,7 @@ In addition to these environment variables, MercureBundle provides a more advanced configuration configuration: * ``secret``: the key to use to sign the JWT -* ``publish``: a list of topics to allow publishing to when generating the JWT +* ``publish``: a list of topics to allow publishing to when generating the JWT (only usable when `secret`, or `factory` are provided ) * ``subscribe``: a list of topics to allow subscribing to when generating the JWT (only usable when `secret`, or `factory` are provided ) * ``algorithm``: The algorithm to use to sign the JWT (only usable when `secret` is provided ) * ``provider``: The ID of a service to call to provide the JWT From daaa3f13adaf5bca6ebd5919149afff935ea946d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= <kevin@dunglas.fr> Date: Thu, 16 Dec 2021 15:39:02 +0100 Subject: [PATCH 1347/1519] Update mercure.rst Co-authored-by: Saif Eddin Gmati <29315886+azjezz@users.noreply.github.com> --- mercure.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mercure.rst b/mercure.rst index 92e770f1089..58e9dc6dbd0 100644 --- a/mercure.rst +++ b/mercure.rst @@ -118,7 +118,7 @@ MercureBundle provides a more advanced configuration configuration: * ``publish``: a list of topics to allow publishing to when generating the JWT (only usable when `secret`, or `factory` are provided ) * ``subscribe``: a list of topics to allow subscribing to when generating the JWT (only usable when `secret`, or `factory` are provided ) * ``algorithm``: The algorithm to use to sign the JWT (only usable when `secret` is provided ) -* ``provider``: The ID of a service to call to provide the JWT +* ``provider``: The ID of a service to call to provide the JWT (all other options will be ignored) * ``factory``: The ID of a service to call to create the JWT (all other options, beside `subscribe`, and `publish` will be ignored) * ``value``: the raw JWT to use (all other options will be ignored) From adf49ef56839d3aea9c4508d4d432a44595f3197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= <kevin@dunglas.fr> Date: Thu, 16 Dec 2021 15:39:11 +0100 Subject: [PATCH 1348/1519] Update mercure.rst Co-authored-by: Saif Eddin Gmati <29315886+azjezz@users.noreply.github.com> --- mercure.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mercure.rst b/mercure.rst index 58e9dc6dbd0..3a93fb0ec80 100644 --- a/mercure.rst +++ b/mercure.rst @@ -114,7 +114,7 @@ MercureBundle will use it to automatically generate and sign the needed JWTs. In addition to these environment variables, MercureBundle provides a more advanced configuration configuration: -* ``secret``: the key to use to sign the JWT +* ``secret``: the key to use to sign the JWT (all other options, beside `algorithm`, `subscribe`, and `publish` will be ignored) * ``publish``: a list of topics to allow publishing to when generating the JWT (only usable when `secret`, or `factory` are provided ) * ``subscribe``: a list of topics to allow subscribing to when generating the JWT (only usable when `secret`, or `factory` are provided ) * ``algorithm``: The algorithm to use to sign the JWT (only usable when `secret` is provided ) From ad0cbe5c6a2e9949d401a2a32b1cd9ddb04d1141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= <kevin@dunglas.fr> Date: Thu, 16 Dec 2021 15:41:09 +0100 Subject: [PATCH 1349/1519] nitpicking --- mercure.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mercure.rst b/mercure.rst index 3a93fb0ec80..365e3de9391 100644 --- a/mercure.rst +++ b/mercure.rst @@ -115,9 +115,9 @@ In addition to these environment variables, MercureBundle provides a more advanced configuration configuration: * ``secret``: the key to use to sign the JWT (all other options, beside `algorithm`, `subscribe`, and `publish` will be ignored) -* ``publish``: a list of topics to allow publishing to when generating the JWT (only usable when `secret`, or `factory` are provided ) -* ``subscribe``: a list of topics to allow subscribing to when generating the JWT (only usable when `secret`, or `factory` are provided ) -* ``algorithm``: The algorithm to use to sign the JWT (only usable when `secret` is provided ) +* ``publish``: a list of topics to allow publishing to when generating the JWT (only usable when `secret`, or `factory` are provided) +* ``subscribe``: a list of topics to allow subscribing to when generating the JWT (only usable when `secret`, or `factory` are provided) +* ``algorithm``: The algorithm to use to sign the JWT (only usable when `secret` is provided) * ``provider``: The ID of a service to call to provide the JWT (all other options will be ignored) * ``factory``: The ID of a service to call to create the JWT (all other options, beside `subscribe`, and `publish` will be ignored) * ``value``: the raw JWT to use (all other options will be ignored) From ccfad390b28c4864c4da0239aace1289ebc12e3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= <kevin@dunglas.fr> Date: Thu, 16 Dec 2021 16:52:14 +0100 Subject: [PATCH 1350/1519] Ask to open PRs for new features in 6.x --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ddeb73add51..17cec7af7c3 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,6 +4,6 @@ If your pull request fixes a BUG, use the oldest maintained branch that contains the bug (see https://symfony.com/releases for the list of maintained branches). If your pull request documents a NEW FEATURE, use the same Symfony branch where -the feature was introduced (and `5.x` for features of unreleased versions). +the feature was introduced (and `6.x` for features of unreleased versions). --> From 16b1f1bf6a5c151dc29f3e70709719568e36a609 Mon Sep 17 00:00:00 2001 From: gnito-org <70450336+gnito-org@users.noreply.github.com> Date: Sun, 12 Dec 2021 10:19:27 -0400 Subject: [PATCH 1351/1519] [CLI] Add link in setup.rst to Symfony CLI source repo --- setup.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/setup.rst b/setup.rst index c795feab42e..154ccae9e8b 100644 --- a/setup.rst +++ b/setup.rst @@ -39,8 +39,8 @@ requirements. Open your console terminal and run this command: .. note:: - The Symfony binary is developed internally at Symfony. If you want to - report a bug or suggest a new feature, please create an issue on + The Symfony CLI source is available at the `Symfony CLI organization repository`_. If + you want to report a bug or suggest a new feature, please create an issue on `symfony/cli`_. .. _creating-symfony-applications: @@ -319,6 +319,7 @@ Learn More .. _`Install Composer`: https://getcomposer.org/download/ .. _`install Symfony CLI`: https://symfony.com/download .. _`symfony/cli`: https://github.com/symfony/cli +.. _`Symfony CLI organization repository`: https://github.com/symfony-cli .. _`The Symfony Demo Application`: https://github.com/symfony/demo .. _`Symfony Flex`: https://github.com/symfony/flex .. _`PHP security advisories database`: https://github.com/FriendsOfPHP/security-advisories From 534486b8408cd3874704d11cad1ee2149f2e2317 Mon Sep 17 00:00:00 2001 From: gnito-org <70450336+gnito-org@users.noreply.github.com> Date: Sat, 18 Dec 2021 08:35:27 -0400 Subject: [PATCH 1352/1519] Correct spelling & grammar in 5.3 --- cache.rst | 4 ++-- components/browser_kit.rst | 2 +- components/http_foundation.rst | 4 ++-- components/lock.rst | 4 ++-- components/messenger.rst | 2 +- components/phpunit_bridge.rst | 2 +- components/runtime.rst | 2 +- components/semaphore.rst | 4 ++-- components/string.rst | 2 +- components/uid.rst | 2 +- components/var_dumper.rst | 2 +- notifier.rst | 6 +++--- rate_limiter.rst | 14 +++++++------- security/custom_authenticator.rst | 6 +++--- security/login_link.rst | 4 ++-- security/passwords.rst | 4 ++-- security/remember_me.rst | 4 ++-- security/user_providers.rst | 2 +- service_container/autowiring.rst | 2 +- testing.rst | 2 +- validation/custom_constraint.rst | 4 ++-- 21 files changed, 39 insertions(+), 39 deletions(-) diff --git a/cache.rst b/cache.rst index 70c1a863103..9c3ed9ed88e 100644 --- a/cache.rst +++ b/cache.rst @@ -800,5 +800,5 @@ Then, register the ``SodiumMarshaller`` service using this key: When configuring multiple keys, the first key will be used for reading and writing, and the additional key(s) will only be used for reading. Once all -cache items encrypted with the old key have expired, you can remove -``OLD_CACHE_DECRYPTION_KEY`` completely. +cache items encrypted with the old key have expired, you can completely remove +``OLD_CACHE_DECRYPTION_KEY``. diff --git a/components/browser_kit.rst b/components/browser_kit.rst index 9648afc31e4..e7c05067185 100644 --- a/components/browser_kit.rst +++ b/components/browser_kit.rst @@ -185,7 +185,7 @@ Custom Header Handling The optional HTTP headers passed to the ``request()`` method follows the FastCGI request format (uppercase, underscores instead of dashes and prefixed with ``HTTP_``). Before saving those headers to the request, they are lower-cased, with ``HTTP_`` -stripped, and underscores turned to dashes. +stripped, and underscores converted into dashes. If you're making a request to an application that has special rules about header capitalization or punctuation, override the ``getHeaders()`` method, which must diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 6154119e715..1913f59f818 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -81,7 +81,7 @@ can be accessed via several public properties: (``$request->headers->get('User-Agent')``). Each property is a :class:`Symfony\\Component\\HttpFoundation\\ParameterBag` -instance (or a sub-class of), which is a data holder class: +instance (or a subclass of), which is a data holder class: * ``request``: :class:`Symfony\\Component\\HttpFoundation\\ParameterBag` or :class:`Symfony\\Component\\HttpFoundation\\InputBag` if the data is @@ -726,7 +726,7 @@ The ``JsonResponse`` class sets the ``Content-Type`` header to .. caution:: To avoid XSSI `JSON Hijacking`_, you should pass an associative array - as the outer-most array to ``JsonResponse`` and not an indexed array so + as the outermost array to ``JsonResponse`` and not an indexed array so that the final result is an object (e.g. ``{"object": "not inside an array"}``) instead of an array (e.g. ``[{"object": "inside an array"}]``). Read the `OWASP guidelines`_ for more information. diff --git a/components/lock.rst b/components/lock.rst index c10f86d1f3d..8f81b7cce59 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -210,7 +210,7 @@ as seconds) and ``isExpired()`` (which returns a boolean). Automatically Releasing The Lock ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Locks are automatically released when their Lock objects are destructed. This is +Locks are automatically released when their Lock objects are destroyed. This is an implementation detail that will be important when sharing Locks between processes. In the example below, ``pcntl_fork()`` creates two processes and the Lock will be released automatically as soon as one process finishes:: @@ -508,7 +508,7 @@ locks:: $store = new PostgreSqlStore($databaseConnectionOrDSN); In opposite to the ``PdoStore``, the ``PostgreSqlStore`` does not need a table to -store locks and does not expire. +store locks and it does not expire. .. versionadded:: 5.2 diff --git a/components/messenger.rst b/components/messenger.rst index 7e1af990db1..2e853f69ab6 100644 --- a/components/messenger.rst +++ b/components/messenger.rst @@ -77,7 +77,7 @@ middleware stack. The component comes with a set of middleware that you can use. When using the message bus with Symfony's FrameworkBundle, the following middleware are configured for you: -#. :class:`Symfony\\Component\\Messenger\\Middleware\\SendMessageMiddleware` (enables asynchronous processing, logs the processing of your messages if you pass a logger) +#. :class:`Symfony\\Component\\Messenger\\Middleware\\SendMessageMiddleware` (enables asynchronous processing, logs the processing of your messages if you provide a logger) #. :class:`Symfony\\Component\\Messenger\\Middleware\\HandleMessageMiddleware` (calls the registered handler(s)) Example:: diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 7658acba17f..714157d1531 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -295,7 +295,7 @@ Baseline Deprecations If your application has some deprecations that you can't fix for some reasons, you can tell Symfony to ignore them. The trick is to create a file with the allowed deprecations and define it as the "deprecation baseline". Deprecations -inside that file are ignore but the rest of deprecations are still reported. +inside that file are ignored but the rest of deprecations are still reported. First, generate the file with the allowed deprecations (run the same command whenever you want to update the existing file): diff --git a/components/runtime.rst b/components/runtime.rst index e716ec6eb38..f9d76bff0c5 100644 --- a/components/runtime.rst +++ b/components/runtime.rst @@ -383,7 +383,7 @@ application outside of the global state in 6 steps: that knows how to "run" the application object. #. The ``RunnerInterface::run(object $application)`` is called and it returns the exit status code as `int`. -#. The PHP engine is exited with this status code. +#. The PHP engine is terminated with this status code. When creating a new runtime, there are two things to consider: First, what arguments will the end user use? Second, what will the user's application look like? diff --git a/components/semaphore.rst b/components/semaphore.rst index ebae3df89e8..810d12f76d2 100644 --- a/components/semaphore.rst +++ b/components/semaphore.rst @@ -45,7 +45,7 @@ class, which in turn requires another class to manage the storage:: The semaphore is created by calling the :method:`Symfony\\Component\\Semaphore\\SemaphoreFactory::createSemaphore` method. Its first argument is an arbitrary string that represents the locked -resource. Its second argument is the maximum number of process allowed. Then, a +resource. Its second argument is the maximum number of processes allowed. Then, a call to the :method:`Symfony\\Component\\Semaphore\\SemaphoreInterface::acquire` method will try to acquire the semaphore:: @@ -54,7 +54,7 @@ method will try to acquire the semaphore:: if ($semaphore->acquire()) { // The resource "pdf-invoice-generation" is locked. - // You can compute and generate invoice safely here. + // Here you can safely compute and generate the invoice. $semaphore->release(); } diff --git a/components/string.rst b/components/string.rst index 48f17f0b3e9..f754bfdb7ea 100644 --- a/components/string.rst +++ b/components/string.rst @@ -36,7 +36,7 @@ However, other languages require thousands of symbols to display their contents. They need complex encoding standards such as `Unicode`_ and concepts like "character" no longer make sense. Instead, you have to deal with these terms: -* `Code points`_: they are the atomic unit of information. A string is a series +* `Code points`_: they are the atomic units of information. A string is a series of code points. Each code point is a number whose meaning is given by the `Unicode`_ standard. For example, the English letter ``A`` is the ``U+0041`` code point and the Japanese *kana* ``の`` is the ``U+306E`` code point. diff --git a/components/uid.rst b/components/uid.rst index d6b3692be45..c0fdb8822e3 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -331,7 +331,7 @@ type, which converts to/from ULID objects automatically:: // ... } -There's also a Doctrine generator to help autogenerate ULID values for the +There's also a Doctrine generator to help auto-generate ULID values for the entity primary keys:: use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator; diff --git a/components/var_dumper.rst b/components/var_dumper.rst index b661bd7a44a..fc64d5607b7 100644 --- a/components/var_dumper.rst +++ b/components/var_dumper.rst @@ -258,7 +258,7 @@ option. Read more about this and other options in finished, press ``Esc.`` to hide the box again. If you want to use your browser search input, press ``Ctrl. + F`` or - ``Cmd. + F`` again while having focus on VarDumper's search input. + ``Cmd. + F`` again while focusing on VarDumper's search input. Using the VarDumper Component in your PHPUnit Test Suite -------------------------------------------------------- diff --git a/notifier.rst b/notifier.rst index 0280a04f8ad..7d12e04386f 100644 --- a/notifier.rst +++ b/notifier.rst @@ -39,7 +39,7 @@ The notifier component supports the following channels: .. tip:: - Use :doc:`secrets </configuration/secrets>` to securily store your + Use :doc:`secrets </configuration/secrets>` to securely store your API's tokens. .. _notifier-sms-channel: @@ -422,10 +422,10 @@ Symfony provides the following recipients: :class:`Symfony\\Component\\Notifier\\Recipient\\NoRecipient` This is the default and is useful when there is no need to have information about the receiver. For example, the browser channel uses - the current requests's :ref:`session flashbag <flash-messages>`; + the current requests' :ref:`session flashbag <flash-messages>`; :class:`Symfony\\Component\\Notifier\\Recipient\\Recipient` - This can contain both email address and phonenumber of the user. This + This can contain both the email address and the phone number of the user. This recipient can be used for all channels (depending on whether they are actually set). diff --git a/rate_limiter.rst b/rate_limiter.rst index 4f2d20b2b18..676d16f0a99 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -50,7 +50,7 @@ squares). Its main drawback is that resource usage is not evenly distributed in time and it can overload the server at the window edges. In the previous example, -there are 6 accepted requests between 11:00 and 12:00. +there were 6 accepted requests between 11:00 and 12:00. This is more significant with bigger limits. For instance, with 5,000 requests per hour, a user could make the 4,999 requests in the last minute of some @@ -80,15 +80,15 @@ the previous hour and 500 requests this hour. 15 minutes in to the current hour (25% of the window) the hit count would be calculated as: 75% * 4,000 + 500 = 3,500. At this point in time the user can only do 1,500 more requests. -The math shows that the closer the last window is, the more will the hit count -of the last window effect the current limit. This will make sure that a user can -do 5,000 requests per hour but only if they are spread out evenly. +The math shows that the closer the last window is, the more the hit count +of the last window will affect the current limit. This will make sure that a user can +do 5,000 requests per hour but only if they are evenly spread out. Token Bucket Rate Limiter ~~~~~~~~~~~~~~~~~~~~~~~~~ -This technique implements the `token bucket algorithm`_, which defines a -continuously updating budget of resource usage. It roughly works like this: +This technique implements the `token bucket algorithm`_, which defines +continuously updating the budget of resource usage. It roughly works like this: * A bucket is created with an initial set of tokens; * A new token is added to the bucket with a predefined frequency (e.g. every second); @@ -103,7 +103,7 @@ of 1 token per 15 minutes: <object data="_images/rate_limiter/token_bucket.svg" type="image/svg+xml"></object> -This algorithm handles more complex back-off algorithm to manage bursts. +This algorithm handles more complex back-off burst management. For instance, it can allow a user to try a password 5 times and then only allow 1 every 15 minutes (unless the user waits 75 minutes and they will be allowed 5 tries again). diff --git a/security/custom_authenticator.rst b/security/custom_authenticator.rst index 03f5820cec3..cd18e7bbd81 100644 --- a/security/custom_authenticator.rst +++ b/security/custom_authenticator.rst @@ -4,7 +4,7 @@ How to Write a Custom Authenticator Symfony comes with :ref:`many authenticators <security-authenticators>` and third party bundles also implement more complex cases like JWT and oAuth 2.0. However, sometimes you need to implement a custom authentication -mechanism that doesn't exists yet or you need to customize one. In such +mechanism that doesn't exist yet or you need to customize one. In such cases, you must create and use your own authenticator. Authenticators should implement the @@ -133,7 +133,7 @@ The authenticator can be enabled using the ``custom_authenticators`` setting: .. versionadded:: 5.2 Starting with Symfony 5.2, the custom authenticator is automatically - registered as entry point if it implements ``AuthenticationEntryPointInterface``. + registered as an entry point if it implements ``AuthenticationEntryPointInterface``. Prior to 5.2, you had to configure the entry point separately using the ``entry_point`` option. Read :doc:`/security/entry_point` for more @@ -171,7 +171,7 @@ can define what happens in these cases: **Caution**: Never use ``$exception->getMessage()`` for ``AuthenticationException`` instances. This message might contain sensitive information that you - don't want to expose publicly. Instead, use ``$exception->getMessageKey()`` + don't want to be publicly exposed. Instead, use ``$exception->getMessageKey()`` and ``$exception->getMessageData()`` like shown in the full example above. Use :class:`Symfony\\Component\\Security\\Core\\Exception\\CustomUserMessageAuthenticationException` if you want to set custom error messages. diff --git a/security/login_link.rst b/security/login_link.rst index 86406f9b316..045c9a7963f 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -219,7 +219,7 @@ this interface:: </form> {% endblock %} -In this controller, the user is submitting their e-mail address to the +In this controller, the user is submitting their email address to the controller. Based on this property, the correct user is loaded and a login link is created using :method:`Symfony\\Component\\Security\\Http\\LoginLink\\LoginLinkHandlerInterface::createLoginLink`. @@ -235,7 +235,7 @@ link is created using 3) Send the Login Link to the User ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Now the link is created, it needs to be send to the user. Anyone with the +Now the link is created, it needs to be sent to the user. Anyone with the link is able to login as this user, so you need to make sure to send it to a known device of them (e.g. using e-mail or SMS). diff --git a/security/passwords.rst b/security/passwords.rst index 521be799277..7f1f5b605b8 100644 --- a/security/passwords.rst +++ b/security/passwords.rst @@ -448,7 +448,7 @@ password should be stored: * :ref:`When using Doctrine's entity user provider <upgrade-the-password-doctrine>` * :ref:`When using a custom user provider <upgrade-the-password-custom-provider>` -After this, you're done and passwords are always hashed as secure as possible! +After this, you're done and passwords are always hashed as securely as possible! .. note:: @@ -755,7 +755,7 @@ The Sodium Password Hasher ~~~~~~~~~~~~~~~~~~~~~~~~~~ It uses the `Argon2 key derivation function`_. Argon2 support was introduced -in PHP 7.2 by bundeling the `libsodium`_ extension. +in PHP 7.2 by bundling the `libsodium`_ extension. The hashed passwords are ``96`` characters long, but due to the hashing requirements saved in the resulting hash this may change in the future, so make diff --git a/security/remember_me.rst b/security/remember_me.rst index b14b012202f..f9fd2e62dab 100644 --- a/security/remember_me.rst +++ b/security/remember_me.rst @@ -135,7 +135,7 @@ The ``remember_me`` firewall defines the following configuration options: ``service`` (default value: ``null``) Defines the ID of the service used to handle the Remember Me feature. It's - useful if you need to overwrite the current behavior entirely. + useful if you need to overwrite the current behavior. .. versionadded:: 5.1 @@ -204,7 +204,7 @@ users to change their password. You can do this by leveraging a few special .. tip:: - There is also a ``IS_REMEMBERED`` attribute that grants *only* when the + There is also a ``IS_REMEMBERED`` attribute that grants access *only* when the user is authenticated via the remember me mechanism. .. versionadded:: 5.1 diff --git a/security/user_providers.rst b/security/user_providers.rst index 5d3be052121..07212acbf0b 100644 --- a/security/user_providers.rst +++ b/security/user_providers.rst @@ -104,7 +104,7 @@ Using a Custom Query to Load the User The entity provider can only query from one *specific* field, specified by the ``property`` config key. If you want a bit more control over this - e.g. you want to find a user by ``email`` *or* ``username``, you can do that by -implenting :class:`Symfony\\Bridge\\Doctrine\\Security\\User\\UserLoaderInterface` +implementing :class:`Symfony\\Bridge\\Doctrine\\Security\\User\\UserLoaderInterface` in your :ref:`Doctrine repository <doctrine-queries>` (e.g. ``UserRepository``):: // src/Repository/UserRepository.php diff --git a/service_container/autowiring.rst b/service_container/autowiring.rst index a7407f51b1d..aa5d25ad83b 100644 --- a/service_container/autowiring.rst +++ b/service_container/autowiring.rst @@ -611,7 +611,7 @@ you can use the ``@required`` annotation instead. The ``#[Required]`` attribute was introduced in Symfony 5.2. -Despite property injection has some :ref:`drawbacks <property-injection>`, +Despite property injection having some :ref:`drawbacks <property-injection>`, autowiring with ``#[Required]`` or ``@required`` can also be applied to public typed properties: diff --git a/testing.rst b/testing.rst index 5390b7aefd8..4147ab361a0 100644 --- a/testing.rst +++ b/testing.rst @@ -583,7 +583,7 @@ Logging in Users (Authentication) When you want to add application tests for protected pages, you have to first "login" as a user. Reproducing the actual steps - such as -submitting a login form - make a test very slow. For this reason, Symfony +submitting a login form - makes a test very slow. For this reason, Symfony provides a ``loginUser()`` method to simulate logging in in your functional tests. diff --git a/validation/custom_constraint.rst b/validation/custom_constraint.rst index f462c773e74..41753fc02c0 100644 --- a/validation/custom_constraint.rst +++ b/validation/custom_constraint.rst @@ -232,8 +232,8 @@ with the necessary ``validator.constraint_validator``. This means you can Create a Reusable Set of Constraints ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In case you need to apply some common set of constraints in different places -consistently across your application, you can extend the :doc:`Compound constraint </reference/constraints/Compound>`. +In case you need to consistently apply a common set of constraints +across your application, you can extend the :doc:`Compound constraint </reference/constraints/Compound>`. .. versionadded:: 5.1 From 11481a2bc15fad0b2f316c95a09659e30c769f8a Mon Sep 17 00:00:00 2001 From: Ippei Sumida <ippey.s@gmail.com> Date: Sat, 18 Dec 2021 08:29:00 +0900 Subject: [PATCH 1353/1519] Change "createAuthenticatedToken" to "createToken" --- security/custom_authenticator.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/custom_authenticator.rst b/security/custom_authenticator.rst index e936ba27493..0ca4913b247 100644 --- a/security/custom_authenticator.rst +++ b/security/custom_authenticator.rst @@ -11,7 +11,7 @@ Authenticators should implement the :class:`Symfony\\Component\\Security\\Http\\Authenticator\\AuthenticatorInterface`. You can also extend :class:`Symfony\\Component\\Security\\Http\\Authenticator\\AbstractAuthenticator`, -which has a default implementation for the ``createAuthenticatedToken()`` +which has a default implementation for the ``createToken()`` method that fits most use-cases:: // src/Security/ApiKeyAuthenticator.php @@ -347,7 +347,7 @@ would initialize the passport like this:: Besides badges, passports can define attributes, which allows the ``authenticate()`` method to store arbitrary information in the passport to access it from other authenticator methods (e.g. - ``createAuthenticatedToken()``):: + ``createToken()``):: // ... use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; From 2778bc3c86d186dd5d229b7fd4ec4748e9fa920e Mon Sep 17 00:00:00 2001 From: gnito-org <70450336+gnito-org@users.noreply.github.com> Date: Mon, 20 Dec 2021 07:58:13 -0400 Subject: [PATCH 1354/1519] Fix minor spelling and grammar issues in 5.4 --- components/security/authorization.rst | 10 +++++----- console/style.rst | 2 +- mailer.rst | 2 +- messenger.rst | 6 +++--- serializer.rst | 4 ++-- testing.rst | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/components/security/authorization.rst b/components/security/authorization.rst index 3effc3d0794..5444b5254c2 100644 --- a/components/security/authorization.rst +++ b/components/security/authorization.rst @@ -67,15 +67,15 @@ Strategies The following strategies are bundled with the component: ``AffirmativeStrategy`` (default) - grant access as soon as there is one voter granting access; + grants access as soon as there is one voter granting access; ``ConsensusStrategy`` - grant access if there are more voters granting access than there are denying; + grants access if there are more voters granting access than there are denying; if there is a draw between votes, the decision is made based on the ``$allowIfEqualGrantedDeniedDecisions`` constructor parameter which defaults to ``true``. ``UnanimousStrategy`` - only grant access if none of the voters has denied access. + only grants access if none of the voters has denied access. ``PriorityStrategy`` grants or denies access by the first voter that does not abstain; @@ -85,10 +85,10 @@ The following strategies are bundled with the component: The "priority" version strategy was introduced in Symfony 5.1. If all voters abstained from voting, the decision is based on the ``$allowIfAllAbstainDecisions`` -constructor parameter which is supported by all of the built-in strategies and defaults to ``false``. +constructor parameter which is supported by all the built-in strategies and defaults to ``false``. If none of the built-in strategies seem to fit, a custom strategy may be provided. The strategy will -receive a stream of votes and may return as soon as it has seen enough votes to come to a conclusion. +receive a stream of votes and may return as soon as it has seen enough votes to reach a conclusion. :: diff --git a/console/style.rst b/console/style.rst index 33f1ff59cc5..4a10639aee6 100644 --- a/console/style.rst +++ b/console/style.rst @@ -168,7 +168,7 @@ Content Methods :method:`Symfony\\Component\\Console\\Style\\SymfonyStyle::createTable` Creates an instance of :class:`Symfony\\Component\\Console\\Helper\\Table` styled according to the Symfony Style Guide, which allows you to use - features such as appending rows dynamically. + features such as dynamically appending rows. .. versionadded:: 5.4 diff --git a/mailer.rst b/mailer.rst index 66a64159c22..dc7c3249669 100644 --- a/mailer.rst +++ b/mailer.rst @@ -189,7 +189,7 @@ OhMySMTP ohmysmtp+smtp://API_TOKEN@default n/a .. caution:: - If you want to use ``ses+smtp`` transport together with :doc:`Messenger </messenger>` + If you want to use the ``ses+smtp`` transport together with :doc:`Messenger </messenger>` to :ref:`send messages in background <mailer-sending-messages-async>`, you need to add the ``ping_threshold`` parameter to your ``MAILER_DSN`` with a value lower than ``10``: ``ses+smtp://USERNAME:PASSWORD@default?ping_threshold=9`` diff --git a/messenger.rst b/messenger.rst index e2565fab518..5761deac446 100644 --- a/messenger.rst +++ b/messenger.rst @@ -706,9 +706,9 @@ PHP is designed to be stateless, there are no shared resources across different requests. In HTTP context PHP cleans everything after sending the response, so you can decide to not take care of services that may leak memory. -On the other hand, workers usually run in long-running CLI processes, which don't -finish after processing a message. That's why you need to be careful about services -state to not leak information and/or memory from one message to another message. +On the other hand, workers usually sequentially process messages in long-running CLI processes, which don't +finish after processing a single message. That's why you must be careful about service +states to prevent information and/or memory leakage. However, certain Symfony services, such as the Monolog :ref:`fingers crossed handler <logging-handler-fingers_crossed>`, leak by design. diff --git a/serializer.rst b/serializer.rst index 92250d2f5a9..1d47e7a2de2 100644 --- a/serializer.rst +++ b/serializer.rst @@ -151,7 +151,7 @@ properties and setters (``setXxx()``) to change properties: Serializer Context ------------------ -The serializer can define a context to control how the (de)serialization of +The serializer can define a context to control the (de)serialization of resources. This context is passed to all normalizers. For example: * :class:`Symfony\\Component\\Serializer\\Normalizer\\DateTimeNormalizer` uses @@ -165,7 +165,7 @@ resources. This context is passed to all normalizers. For example: The usage of the ``empty_array_as_object`` option by default in the Serializer was introduced in Symfony 5.4. -You can pass the context like following:: +You can pass the context as follows:: $serializer->serialize($something, 'json', [ DateTimeNormalizer::FORMAT_KEY => 'Y-m-d H:i:s', diff --git a/testing.rst b/testing.rst index 5ff21c1fb95..91a8bd3fa25 100644 --- a/testing.rst +++ b/testing.rst @@ -929,8 +929,8 @@ Browser Assertions Asserts the given cookie in the test Client is set to the expected value. ``assertThatForClient(Constraint $constraint, string $message = '')`` - Asserts the given Constraint in the Client. Useful to use your custom asserts - in the same way of built-in asserts (i.e. without passing the Client as argument):: + 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):: // add this method in some custom class imported in your tests protected static function assertMyOwnCustomAssert(): void From 45cc1cf2ebbd31b781fbd25f41873377f1b6464b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Wed, 22 Dec 2021 09:56:40 +0100 Subject: [PATCH 1355/1519] [Testing] Minor tweaks in the main testing article --- testing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing.rst b/testing.rst index 4147ab361a0..884e0943b8c 100644 --- a/testing.rst +++ b/testing.rst @@ -222,7 +222,7 @@ If you need to customize some environment variables for your tests (e.g. the ``DATABASE_URL`` used by Doctrine), you can do that by overriding anything you need in your ``.env.test`` file: -.. code-block:: text +.. code-block:: env # .env.test @@ -268,7 +268,7 @@ the container is stored in ``static::getContainer()``:: $newsletterGenerator = $container->get(NewsletterGenerator::class); $newsletter = $newsletterGenerator->generateMonthlyNews(...); - $this->assertEquals(..., $newsletter->getContent()); + $this->assertEquals('...', $newsletter->getContent()); } } From fc546909b5fd02b2ffb5c43f370de728cacb7e9b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Tue, 21 Dec 2021 17:41:22 +0100 Subject: [PATCH 1356/1519] [Security] Add PHP attributes to a PHP annotations example --- security.rst | 67 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/security.rst b/security.rst index 3412b678322..39965fd1530 100644 --- a/security.rst +++ b/security.rst @@ -2199,30 +2199,55 @@ will happen: Thanks to the SensioFrameworkExtraBundle, you can also secure your controller using annotations: -.. code-block:: diff +.. configuration-block:: - // src/Controller/AdminController.php - // ... + .. code-block:: php-annotations - + use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted; + // src/Controller/AdminController.php + // ... - + /** - + * Require ROLE_ADMIN for *every* controller method in this class. - + * - + * @IsGranted("ROLE_ADMIN") - + */ - class AdminController extends AbstractController - { - + /** - + * Require ROLE_ADMIN for only this controller method. - + * - + * @IsGranted("ROLE_ADMIN") - + */ - public function adminDashboard(): Response - { - // ... - } - } + use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted; + + /** + * Require ROLE_ADMIN for all the actions of this controller + * + * @IsGranted("ROLE_ADMIN") + */ + class AdminController extends AbstractController + { + /** + * Require ROLE_SUPER_ADMIN only for this action + * + * @IsGranted("ROLE_SUPER_ADMIN") + */ + public function adminDashboard(): Response + { + // ... + } + } + + .. code-block:: php-attributes + + // src/Controller/AdminController.php + // ... + + use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted; + + /** + * Require ROLE_ADMIN for all the actions of this controller + */ + #[IsGranted('ROLE_ADMIN')] + class AdminController extends AbstractController + { + /** + * Require ROLE_SUPER_ADMIN only for this action + */ + #[IsGranted('ROLE_SUPER_ADMIN')] + public function adminDashboard(): Response + { + // ... + } + } For more information, see the `FrameworkExtraBundle documentation`_. From 085c6535e7b113a1b4beb3f0e67aee14f7aea178 Mon Sep 17 00:00:00 2001 From: Bruno Baguette <bruno.baguette@gmail.com> Date: Wed, 22 Dec 2021 20:14:39 +0100 Subject: [PATCH 1357/1519] Fix wrong path (aka 404 error) for security_events.svg diagram MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "../" ➤ "./" --- security.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security.rst b/security.rst index 39965fd1530..16442d23b58 100644 --- a/security.rst +++ b/security.rst @@ -2589,7 +2589,7 @@ Authentication Events .. raw:: html - <object data="../_images/security/security_events.svg" type="image/svg+xml"></object> + <object data="./_images/security/security_events.svg" type="image/svg+xml"></object> :class:`Symfony\\Component\\Security\\Http\\Event\\CheckPassportEvent` Dispatched after the authenticator created the :ref:`security passport <security-passport>`. From 990b413b62049185c623133c8894a85f4c63686d Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Thu, 23 Dec 2021 09:03:16 +0100 Subject: [PATCH 1358/1519] Minor formatting tweaks --- components/lock.rst | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index ff173f88252..4069a238ee5 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -473,9 +473,9 @@ MongoDB Connection String: PdoStore ~~~~~~~~ -The PdoStore saves locks in an SQL database. It is identical to DoctrineDbalStore but requires -a `PDO`_ connection or a `Data Source Name (DSN)`_. This store does not -support blocking, and expects a TTL to avoid stalled locks:: +The PdoStore saves locks in an SQL database. It is identical to DoctrineDbalStore +but requires a `PDO`_ connection or a `Data Source Name (DSN)`_. This store does +not support blocking, and expects a TTL to avoid stalled locks:: use Symfony\Component\Lock\Store\PdoStore; @@ -495,16 +495,17 @@ your code. .. deprecated:: 5.4 - Using ``PdoStore`` with Doctrine DBAL is deprecated in Symfony 5.4. Use ``DoctrineDbalStore`` instead. + Using ``PdoStore`` with Doctrine DBAL is deprecated in Symfony 5.4. + Use ``DoctrineDbalStore`` instead. .. _lock-store-dbal: DoctrineDbalStore ~~~~~~~~~~~~~~~~~ -The DoctrineDbalStore saves locks in an SQL database. It is identical to PdoStore but requires a -`Doctrine DBAL Connection`_, or a `Doctrine DBAL URL`_. This store does not -support blocking, and expects a TTL to avoid stalled locks:: +The DoctrineDbalStore saves locks in an SQL database. It is identical to PdoStore +but requires a `Doctrine DBAL Connection`_, or a `Doctrine DBAL URL`_. This store +does not support blocking, and expects a TTL to avoid stalled locks:: use Symfony\Component\Lock\Store\PdoStore; @@ -525,8 +526,8 @@ in your code or create this table explicitly by calling the .. versionadded:: 5.4 - The ``DoctrineDbalStore`` was introduced in Symfony 5.4 to replace ``PdoStore`` when - used with Doctrine DBAL. + The ``DoctrineDbalStore`` was introduced in Symfony 5.4 to replace ``PdoStore`` + when used with Doctrine DBAL. .. _lock-store-pgsql: @@ -553,17 +554,17 @@ store locks and it does not expire. .. deprecated:: 5.4 - Using ``PostgreSqlStore`` with Doctrine DBAL is deprecated in Symfony 5.4. Use ``DoctrineDbalPostgreSqlStore`` instead. + Using ``PostgreSqlStore`` with Doctrine DBAL is deprecated in Symfony 5.4. + Use ``DoctrineDbalPostgreSqlStore`` instead. .. _lock-store-dbal-pgsql: DoctrineDbalPostgreSqlStore ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The DoctrineDbalPostgreSqlStore uses `Advisory Locks`_ provided by PostgreSQL. It is identical to PostgreSqlStore -but requires a `Doctrine DBAL Connection`_ or a `Doctrine DBAL URL`_. -It supports native blocking, as well as sharing -locks:: +The DoctrineDbalPostgreSqlStore uses `Advisory Locks`_ provided by PostgreSQL. +It is identical to PostgreSqlStore but requires a `Doctrine DBAL Connection`_ or +a `Doctrine DBAL URL`_. It supports native blocking, as well as sharing locks:: use Symfony\Component\Lock\Store\PostgreSqlStore; @@ -576,8 +577,8 @@ store locks and does not expire. .. versionadded:: 5.4 - The ``DoctrineDbalPostgreSqlStore`` was introduced in Symfony 5.4 to replace ``PostgreSqlStore`` when - used with Doctrine DBAL. + The ``DoctrineDbalPostgreSqlStore`` was introduced in Symfony 5.4 to replace + ``PostgreSqlStore`` when used with Doctrine DBAL. .. _lock-store-redis: From b8602c42aa4c1b77c313a182b44c2e5758d2e45f Mon Sep 17 00:00:00 2001 From: Andrii Dembitskyi <andrew.dembitskiy@gmail.com> Date: Thu, 23 Dec 2021 04:00:35 -0500 Subject: [PATCH 1359/1519] Remove mention to unsupported `prefetch_count` config option --- messenger.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index 2c58714f813..d14ae50564d 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1187,7 +1187,6 @@ The transport has a number of options: ``password`` Password to use to connect to the AMQP service ``persistent`` ``'false'`` ``port`` Port of the AMQP service -``prefetch_count`` ``read_timeout`` Timeout in for income activity. Note: 0 or greater seconds. May be fractional. ``retry`` From 94bd8d257d0d1ed7da5c8e7ca57b466623948159 Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Thu, 23 Dec 2021 20:17:17 +0100 Subject: [PATCH 1360/1519] Merge standalone Security component docs with Security guide --- components/security.rst | 65 ----- components/security/authentication.rst | 334 ---------------------- components/security/authorization.rst | 281 ------------------ components/security/firewall.rst | 164 ----------- components/security/secure_tools.rst | 56 ---- controller/argument_value_resolver.rst | 2 +- introduction/from_flat_php_to_symfony.rst | 7 +- reference/configuration/security.rst | 2 +- security/passwords.rst | 113 +++++++- security/voters.rst | 23 +- 10 files changed, 121 insertions(+), 926 deletions(-) delete mode 100644 components/security.rst delete mode 100644 components/security/authentication.rst delete mode 100644 components/security/authorization.rst delete mode 100644 components/security/firewall.rst delete mode 100644 components/security/secure_tools.rst diff --git a/components/security.rst b/components/security.rst deleted file mode 100644 index 9985b611c63..00000000000 --- a/components/security.rst +++ /dev/null @@ -1,65 +0,0 @@ -.. index:: - single: Security - -The Security Component -====================== - - The Security component provides a complete security system for your web - application. It ships with facilities for authenticating using HTTP basic - authentication, interactive form login or X.509 certificate login, but also - allows you to implement your own authentication strategies. Furthermore, the - component provides ways to authorize authenticated users based on their - roles. - -Installation ------------- - -The Security component is divided into several smaller sub-components which can -be used separately: - -``symfony/security-core`` - It provides all the common security features, from authentication to - authorization and from encoding passwords to loading users. - -``symfony/security-http`` - It integrates the core sub-component with the HTTP protocol to handle HTTP - requests and responses. - -``symfony/security-csrf`` - It provides protection against `CSRF attacks`_. - -``symfony/security-guard`` - It brings many layers of authentication together, allowing the creation - of complex authentication systems. - -You can install each of them separately in your project: - -.. code-block:: terminal - - $ composer require symfony/security-core - $ composer require symfony/security-http - $ composer require symfony/security-csrf - $ composer require symfony/security-guard - -.. include:: /components/require_autoload.rst.inc - -.. seealso:: - - This article explains how to use the Security features as an independent - component in any PHP application. Read the :doc:`/security` article to learn - about how to use it in Symfony applications. - -Learn More ----------- - -.. toctree:: - :maxdepth: 1 - :glob: - - /components/security/* - /security - /security/* - /reference/configuration/security - /reference/constraints/UserPassword - -.. _`CSRF attacks`: https://en.wikipedia.org/wiki/Cross-site_request_forgery diff --git a/components/security/authentication.rst b/components/security/authentication.rst deleted file mode 100644 index ad89cd785c2..00000000000 --- a/components/security/authentication.rst +++ /dev/null @@ -1,334 +0,0 @@ -.. index:: - single: Security, Authentication - -Authentication -============== - -When a request points to a secured area, and one of the listeners from the -firewall map is able to extract the user's credentials from the current -:class:`Symfony\\Component\\HttpFoundation\\Request` object, it should create -a token, containing these credentials. The next thing the listener should -do is ask the authentication manager to validate the given token, and return -an *authenticated* token if the supplied credentials were found to be valid. -The listener should then store the authenticated token using -:class:`the token storage <Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorageInterface>`:: - - use Symfony\Component\HttpKernel\Event\RequestEvent; - use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; - use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; - use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; - - class SomeAuthenticationListener - { - /** - * @var TokenStorageInterface - */ - private $tokenStorage; - - /** - * @var AuthenticationManagerInterface - */ - private $authenticationManager; - - /** - * @var string Uniquely identifies the secured area - */ - private $providerKey; - - // ... - - public function __invoke(RequestEvent $event) - { - $request = $event->getRequest(); - - $username = ...; - $password = ...; - - $unauthenticatedToken = new UsernamePasswordToken( - $username, - $password, - $this->providerKey - ); - - $authenticatedToken = $this - ->authenticationManager - ->authenticate($unauthenticatedToken); - - $this->tokenStorage->setToken($authenticatedToken); - } - } - -.. note:: - - A token can be of any class, as long as it implements - :class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface`. - -The Authentication Manager --------------------------- - -The default authentication manager is an instance of -:class:`Symfony\\Component\\Security\\Core\\Authentication\\AuthenticationProviderManager`:: - - use Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager; - use Symfony\Component\Security\Core\Exception\AuthenticationException; - - // instances of Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface - $providers = [...]; - - $authenticationManager = new AuthenticationProviderManager($providers); - - try { - $authenticatedToken = $authenticationManager - ->authenticate($unauthenticatedToken); - } catch (AuthenticationException $exception) { - // authentication failed - } - -The ``AuthenticationProviderManager``, when instantiated, receives several -authentication providers, each supporting a different type of token. - -.. note:: - - You may write your own authentication manager, the only requirement is that - it implements :class:`Symfony\\Component\\Security\\Core\\Authentication\\AuthenticationManagerInterface`. - -.. _authentication_providers: - -Authentication Providers ------------------------- - -Each provider (since it implements -:class:`Symfony\\Component\\Security\\Core\\Authentication\\Provider\\AuthenticationProviderInterface`) -has a :method:`Symfony\\Component\\Security\\Core\\Authentication\\Provider\\AuthenticationProviderInterface::supports` method -by which the ``AuthenticationProviderManager`` -can determine if it supports the given token. If this is the case, the -manager then calls the provider's :method:`Symfony\\Component\\Security\\Core\\Authentication\\Provider\\AuthenticationProviderInterface::authenticate` method. -This method should return an authenticated token or throw an -:class:`Symfony\\Component\\Security\\Core\\Exception\\AuthenticationException` -(or any other exception extending it). - -Authenticating Users by their Username and Password -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -An authentication provider will attempt to authenticate a user based on -the credentials they provided. Usually these are a username and a password. -Most web applications store their user's username and a hash of the user's -password combined with a randomly generated salt. This means that the average -authentication would consist of fetching the salt and the hashed password -from the user data storage, hash the password the user has just provided -(e.g. using a login form) with the salt and compare both to determine if -the given password is valid. - -This functionality is offered by the :class:`Symfony\\Component\\Security\\Core\\Authentication\\Provider\\DaoAuthenticationProvider`. -It fetches the user's data from a :class:`Symfony\\Component\\Security\\Core\\User\\UserProviderInterface`, -uses a :class:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface` -to create a hash of the password and returns an authenticated token if the -password was valid:: - - use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface; - use Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider; - use Symfony\Component\Security\Core\User\InMemoryUserProvider; - use Symfony\Component\Security\Core\User\UserChecker; - - // The 'InMemoryUser' class was introduced in Symfony 5.3. - // In previous versions it was called 'User' - $userProvider = new InMemoryUserProvider( - [ - 'admin' => [ - // password is "foo" - 'password' => '5FZ2Z8QIkA7UTZ4BYkoC+GsReLf569mSKDsfods6LYQ8t+a8EW9oaircfMpmaLbPBh4FOBiiFyLfuZmTSUwzZg==', - 'roles' => ['ROLE_ADMIN'], - ], - ] - ); - - // for some extra checks: is account enabled, locked, expired, etc. - $userChecker = new UserChecker(); - - // an array of password hashers (see below) - $hasherFactory = new PasswordHasherFactoryInterface(...); - - $daoProvider = new DaoAuthenticationProvider( - $userProvider, - $userChecker, - 'secured_area', - $hasherFactory - ); - - $daoProvider->authenticate($unauthenticatedToken); - -.. note:: - - The example above demonstrates the use of the "in-memory" user provider, - but you may use any user provider, as long as it implements - :class:`Symfony\\Component\\Security\\Core\\User\\UserProviderInterface`. - It is also possible to let multiple user providers try to find the user's - data, using the :class:`Symfony\\Component\\Security\\Core\\User\\ChainUserProvider`. - -.. _the-password-encoder-factory: - -The Password Hasher Factory -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The :class:`Symfony\\Component\\Security\\Core\\Authentication\\Provider\\DaoAuthenticationProvider` -uses a factory to create a password hasher for a given type of user. This allows -you to use different hashing strategies for different types of users. -The default :class:`Symfony\\Component\\PasswordHasher\\Hasher\\PasswordHasherFactory` -receives an array of hashers:: - - use Acme\Entity\LegacyUser; - use Symfony\Component\PasswordHasher\Hasher\MessageDigestPasswordHasher; - use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactory; - use Symfony\Component\Security\Core\User\InMemoryUser; - - $defaultHasher = new MessageDigestPasswordHasher('sha512', true, 5000); - $weakHasher = new MessageDigestPasswordHasher('md5', true, 1); - - $hashers = [ - InMemoryUser::class => $defaultHasher, - LegacyUser::class => $weakHasher, - // ... - ]; - $hasherFactory = new PasswordHasherFactory($hashers); - -Each hasher should implement :class:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface` -or be an array with a ``class`` and an ``arguments`` key, which allows the -hasher factory to construct the hasher only when it is needed. - -.. _creating-a-custom-password-encoder: - -Creating a custom Password Hasher -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -There are many built-in password hasher. But if you need to create your -own, it needs to follow these rules: - -#. The class must implement :class:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface` - (you can also extend :class:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasher`); - -#. The implementations of - :method:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface::hashPassword` - and - :method:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface::isPasswordValid` - must first of all make sure the password is not too long, i.e. the password length is no longer - than 4096 characters. This is for security reasons (see `CVE-2013-5750`_), and you can use the - :method:`Symfony\\Component\\PasswordHasher\\Hasher\\CheckPasswordLengthTrait::isPasswordTooLong` - method for this check:: - - use Symfony\Component\PasswordHasher\Hasher\CheckPasswordLengthTrait; - use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasher; - use Symfony\Component\Security\Core\Exception\BadCredentialsException; - - class FoobarHasher extends UserPasswordHasher - { - use CheckPasswordLengthTrait; - - public function hashPassword(UserInterface $user, string $plainPassword): string - { - if ($this->isPasswordTooLong($user->getPassword())) { - throw new BadCredentialsException('Invalid password.'); - } - - // ... - } - - public function isPasswordValid(UserInterface $user, string $plainPassword) - { - if ($this->isPasswordTooLong($user->getPassword())) { - return false; - } - - // ... - } - } - -.. _using-password-encoders: - -Using Password Hashers -~~~~~~~~~~~~~~~~~~~~~~ - -When the :method:`Symfony\\Component\\PasswordHasher\\Hasher\\PasswordHasherFactory::getPasswordHasher` -method of the password hasher factory is called with the user object as -its first argument, it will return a hasher of type :class:`Symfony\\Component\\PasswordHasher\\PasswordHasherInterface` -which should be used to hash this user's password:: - - // a Acme\Entity\LegacyUser instance - $user = ...; - - // the password that was submitted, e.g. when registering - $plainPassword = ...; - - $hasher = $hasherFactory->getPasswordHasher($user); - - // returns $weakHasher (see above) - $hashedPassword = $hasher->hashPassword($user, $plainPassword); - - $user->setPassword($hashedPassword); - - // ... save the user - -Now, when you want to check if the submitted password (e.g. when trying to log -in) is correct, you can use:: - - // fetch the Acme\Entity\LegacyUser - $user = ...; - - // the submitted password, e.g. from the login form - $plainPassword = ...; - - $validPassword = $hasher->isPasswordValid($user, $plainPassword); - -Authentication Events ---------------------- - -The security component provides the following authentication events: - -=============================== ======================================================================== ============================================================================== -Name Event Constant Argument Passed to the Listener -=============================== ======================================================================== ============================================================================== -security.authentication.success ``AuthenticationEvents::AUTHENTICATION_SUCCESS`` :class:`Symfony\\Component\\Security\\Core\\Event\\AuthenticationSuccessEvent` -security.authentication.failure ``AuthenticationEvents::AUTHENTICATION_FAILURE`` :class:`Symfony\\Component\\Security\\Core\\Event\\AuthenticationFailureEvent` -security.interactive_login ``SecurityEvents::INTERACTIVE_LOGIN`` :class:`Symfony\\Component\\Security\\Http\\Event\\InteractiveLoginEvent` -security.switch_user ``SecurityEvents::SWITCH_USER`` :class:`Symfony\\Component\\Security\\Http\\Event\\SwitchUserEvent` -security.logout_on_change ``Symfony\Component\Security\Http\Event\DeauthenticatedEvent::class`` :class:`Symfony\\Component\\Security\\Http\\Event\\DeauthenticatedEvent` -=============================== ======================================================================== ============================================================================== - -Authentication Success and Failure Events -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -When a provider authenticates the user, a ``security.authentication.success`` -event is dispatched. But beware - this event may fire, for example, on *every* -request if you have session-based authentication, if ``always_authenticate_before_granting`` -is enabled or if the token is not authenticated before AccessListener is invoked. -See ``security.interactive_login`` below if you need to do something when a user *actually* logs in. - -When a provider attempts authentication but fails (i.e. throws an ``AuthenticationException``), -a ``security.authentication.failure`` event is dispatched. You could listen on -the ``security.authentication.failure`` event, for example, in order to log -failed login attempts. - -Security Events -~~~~~~~~~~~~~~~ - -The ``security.interactive_login`` event is triggered after a user has actively -logged into your website. It is important to distinguish this action from -non-interactive authentication methods, such as: - -* authentication based on your session. -* authentication using a HTTP basic header. - -You could listen on the ``security.interactive_login`` event, for example, in -order to give your user a welcome flash message every time they log in. - -The ``security.switch_user`` event is triggered every time you activate -the ``switch_user`` firewall listener. - -The ``Symfony\Component\Security\Http\Event\DeauthenticatedEvent`` event is triggered when a token has been deauthenticated -because of a user change. It can help you perform clean-up tasks. - -.. seealso:: - - For more information on switching users, see - :doc:`/security/impersonating_user`. - -.. _`CVE-2013-5750`: https://symfony.com/blog/cve-2013-5750-security-issue-in-fosuserbundle-login-form diff --git a/components/security/authorization.rst b/components/security/authorization.rst deleted file mode 100644 index ffc4edc278a..00000000000 --- a/components/security/authorization.rst +++ /dev/null @@ -1,281 +0,0 @@ -.. index:: - single: Security, Authorization - -Authorization -============= - -When any of the authentication providers (see :ref:`authentication_providers`) -has verified the still-unauthenticated token, an authenticated token will -be returned. The authentication listener should set this token directly -in the :class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorageInterface` -using its :method:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorageInterface::setToken` -method. - -From then on, the user is authenticated, i.e. identified. Now, other parts -of the application can use the token to decide whether or not the user may -request a certain URI, or modify a certain object. This decision will be made -by an instance of :class:`Symfony\\Component\\Security\\Core\\Authorization\\AccessDecisionManagerInterface`. - -An authorization decision will always be based on a few things: - -* The current token - For instance, the token's :method:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface::getRoleNames` - method may be used to retrieve the roles of the current user (e.g. - ``ROLE_SUPER_ADMIN``), or a decision may be based on the class of the token. -* A set of attributes - Each attribute stands for a certain right the user should have, e.g. - ``ROLE_ADMIN`` to make sure the user is an administrator. -* An object (optional) - Any object for which access control needs to be checked, like - an article or a comment object. - -.. _components-security-access-decision-manager: - -Access Decision Manager ------------------------ - -Since deciding whether or not a user is authorized to perform a certain -action can be a complicated process, the standard :class:`Symfony\\Component\\Security\\Core\\Authorization\\AccessDecisionManager` -itself depends on multiple voters, and makes a final verdict based on all -the votes (either positive, negative or neutral) it has received. It -recognizes several strategies: - -``affirmative`` (default) - grant access as soon as there is one voter granting access; - -``consensus`` - grant access if there are more voters granting access than there are denying; - -``unanimous`` - only grant access if none of the voters has denied access. If all voters - abstained from voting, the decision is based on the ``allow_if_all_abstain`` - config option (which defaults to ``false``). - -``priority`` - grants or denies access by the first voter that does not abstain; - - .. versionadded:: 5.1 - - The ``priority`` version strategy was introduced in Symfony 5.1. - -Usage of the available options in detail:: - - use Symfony\Component\Security\Core\Authorization\AccessDecisionManager; - - // instances of Symfony\Component\Security\Core\Authorization\Voter\VoterInterface - $voters = [...]; - - // one of "affirmative", "consensus", "unanimous", "priority" - $strategy = ...; - - // whether or not to grant access when all voters abstain - $allowIfAllAbstainDecisions = ...; - - // whether or not to grant access when there is no majority (applies only to the "consensus" strategy) - $allowIfEqualGrantedDeniedDecisions = ...; - - $accessDecisionManager = new AccessDecisionManager( - $voters, - $strategy, - $allowIfAllAbstainDecisions, - $allowIfEqualGrantedDeniedDecisions - ); - -.. seealso:: - - You can change the default strategy in the - :ref:`configuration <security-voters-change-strategy>`. - -Voters ------- - -Voters are instances -of :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface`, -which means they have to implement a few methods which allows the decision -manager to use them: - -``vote(TokenInterface $token, $object, array $attributes)`` - this method will do the actual voting and return a value equal to one - of the class constants of :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface`, - i.e. ``VoterInterface::ACCESS_GRANTED``, ``VoterInterface::ACCESS_DENIED`` - or ``VoterInterface::ACCESS_ABSTAIN``; - -The Security component contains some standard voters which cover many use -cases: - -AuthenticatedVoter -~~~~~~~~~~~~~~~~~~ - -The :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\AuthenticatedVoter` -voter supports the attributes ``IS_AUTHENTICATED_FULLY``, -``IS_AUTHENTICATED_REMEMBERED``, ``IS_AUTHENTICATED_ANONYMOUSLY``, -to grant access based on the current level of authentication, i.e. is the -user fully authenticated, or only based on a "remember-me" cookie, or even -authenticated anonymously? - -It also supports the attributes ``IS_ANONYMOUS``, ``IS_REMEMBERED``, -``IS_IMPERSONATOR`` to grant access based on a specific state of -authentication. - -.. versionadded:: 5.1 - - The ``IS_ANONYMOUS``, ``IS_REMEMBERED`` and ``IS_IMPERSONATOR`` - attributes were introduced in Symfony 5.1. - -:: - - use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver; - - $trustResolver = new AuthenticationTrustResolver(); - - $authenticatedVoter = new AuthenticatedVoter($trustResolver); - - // instance of Symfony\Component\Security\Core\Authentication\Token\TokenInterface - $token = ...; - - // any object - $object = ...; - - $vote = $authenticatedVoter->vote($token, $object, ['IS_AUTHENTICATED_FULLY']); - -RoleVoter -~~~~~~~~~ - -The :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\RoleVoter` -supports attributes starting with ``ROLE_`` and grants access to the user -when at least one required ``ROLE_*`` attribute can be found in the array of -roles returned by the token's :method:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface::getRoleNames` -method:: - - use Symfony\Component\Security\Core\Authorization\Voter\RoleVoter; - - $roleVoter = new RoleVoter('ROLE_'); - - $roleVoter->vote($token, $object, ['ROLE_ADMIN']); - -RoleHierarchyVoter -~~~~~~~~~~~~~~~~~~ - -The :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\RoleHierarchyVoter` -extends :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\RoleVoter` -and provides some additional functionality: it knows how to handle a -hierarchy of roles. For instance, a ``ROLE_SUPER_ADMIN`` role may have sub-roles -``ROLE_ADMIN`` and ``ROLE_USER``, so that when a certain object requires the -user to have the ``ROLE_ADMIN`` role, it grants access to users who in fact -have the ``ROLE_ADMIN`` role, but also to users having the ``ROLE_SUPER_ADMIN`` -role:: - - use Symfony\Component\Security\Core\Authorization\Voter\RoleHierarchyVoter; - use Symfony\Component\Security\Core\Role\RoleHierarchy; - - $hierarchy = [ - 'ROLE_SUPER_ADMIN' => ['ROLE_ADMIN', 'ROLE_USER'], - ]; - - $roleHierarchy = new RoleHierarchy($hierarchy); - - $roleHierarchyVoter = new RoleHierarchyVoter($roleHierarchy); - -ExpressionVoter -~~~~~~~~~~~~~~~ - -The :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\ExpressionVoter` -grants access based on the evaluation of expressions created with the -:doc:`ExpressionLanguage component </components/expression_language>`. These -expressions have access to a number of -:ref:`special security variables <security-expression-variables>`:: - - use Symfony\Component\ExpressionLanguage\Expression; - use Symfony\Component\Security\Core\Authorization\Voter\ExpressionVoter; - - // Symfony\Component\Security\Core\Authorization\ExpressionLanguage; - $expressionLanguage = ...; - - // instance of Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface - $trustResolver = ...; - - // Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface - $authorizationChecker = ...; - - $expressionVoter = new ExpressionVoter($expressionLanguage, $trustResolver, $authorizationChecker); - - // instance of Symfony\Component\Security\Core\Authentication\Token\TokenInterface - $token = ...; - - // any object - $object = ...; - - $expression = new Expression( - '"ROLE_ADMIN" in role_names or (not is_anonymous() and user.isSuperAdmin())' - ); - - $vote = $expressionVoter->vote($token, $object, [$expression]); - -.. note:: - - When you make your own voter, you can use its constructor to inject any - dependencies it needs to come to a decision. - -Roles ------ - -Roles are strings that give expression to a certain right the user has (e.g. -*"edit a blog post"*, *"create an invoice"*). You can freely choose those -strings. The only requirement is that they must start with the ``ROLE_`` prefix -(e.g. ``ROLE_POST_EDIT``, ``ROLE_INVOICE_CREATE``). - -Using the Decision Manager --------------------------- - -The Access Listener -~~~~~~~~~~~~~~~~~~~ - -The access decision manager can be used at any point in a request to decide whether -or not the current user is entitled to access a given resource. One optional, -but useful, method for restricting access based on a URL pattern is the -:class:`Symfony\\Component\\Security\\Http\\Firewall\\AccessListener`, -which is one of the firewall listeners (see :ref:`firewall_listeners`) that -is triggered for each request matching the firewall map (see :ref:`firewall`). - -It uses an access map (which should be an instance of :class:`Symfony\\Component\\Security\\Http\\AccessMapInterface`) -which contains request matchers and a corresponding set of attributes that -are required for the current user to get access to the application:: - - use Symfony\Component\HttpFoundation\RequestMatcher; - use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; - use Symfony\Component\Security\Http\AccessMap; - use Symfony\Component\Security\Http\Firewall\AccessListener; - - $accessMap = new AccessMap(); - $tokenStorage = new TokenStorage(); - $requestMatcher = new RequestMatcher('^/admin'); - $accessMap->add($requestMatcher, ['ROLE_ADMIN']); - - $accessListener = new AccessListener( - $tokenStorage, - $accessDecisionManager, - $accessMap, - $authenticationManager - ); - -Authorization Checker -~~~~~~~~~~~~~~~~~~~~~ - -The access decision manager is also available to other parts of the application -via the :method:`Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationChecker::isGranted` -method of the :class:`Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationChecker`. -A call to this method will directly delegate the question to the access -decision manager:: - - use Symfony\Component\Security\Core\Authorization\AuthorizationChecker; - use Symfony\Component\Security\Core\Exception\AccessDeniedException; - - $authorizationChecker = new AuthorizationChecker( - $tokenStorage, - $authenticationManager, - $accessDecisionManager - ); - - if (!$authorizationChecker->isGranted('ROLE_ADMIN')) { - throw new AccessDeniedException(); - } diff --git a/components/security/firewall.rst b/components/security/firewall.rst deleted file mode 100644 index adb0fae6e4a..00000000000 --- a/components/security/firewall.rst +++ /dev/null @@ -1,164 +0,0 @@ -.. index:: - single: Security, Firewall - -The Firewall and Authorization -============================== - -Central to the Security component is authorization. This is handled by an instance -of :class:`Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationCheckerInterface`. -When all steps in the process of authenticating the user have been taken successfully, -you can ask the authorization checker if the authenticated user has access to a -certain action or resource of the application:: - - use Symfony\Component\Security\Core\Authorization\AuthorizationChecker; - use Symfony\Component\Security\Core\Exception\AccessDeniedException; - - // instance of Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface - $tokenStorage = ...; - - // instance of Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface - $authenticationManager = ...; - - // instance of Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface - $accessDecisionManager = ...; - - $authorizationChecker = new AuthorizationChecker( - $tokenStorage, - $authenticationManager, - $accessDecisionManager - ); - - // ... authenticate the user - - if (!$authorizationChecker->isGranted('ROLE_ADMIN')) { - throw new AccessDeniedException(); - } - -.. note:: - - Read the dedicated articles to learn more about :doc:`/components/security/authentication` - and :doc:`/components/security/authorization`. - -.. _firewall: - -A Firewall for HTTP Requests ----------------------------- - -Authenticating a user is done by the firewall. An application may have -multiple secured areas, so the firewall is configured using a map of these -secured areas. For each of these areas, the map contains a request matcher -and a collection of listeners. The request matcher gives the firewall the -ability to find out if the current request points to a secured area. -The listeners are then asked if the current request can be used to authenticate -the user:: - - use Symfony\Component\HttpFoundation\RequestMatcher; - use Symfony\Component\Security\Http\Firewall\ExceptionListener; - use Symfony\Component\Security\Http\FirewallMap; - - $firewallMap = new FirewallMap(); - - $requestMatcher = new RequestMatcher('^/secured-area/'); - - // array of callables - $listeners = [...]; - - $exceptionListener = new ExceptionListener(...); - - $firewallMap->add($requestMatcher, $listeners, $exceptionListener); - -The firewall map will be given to the firewall as its first argument, together -with the event dispatcher that is used by the :class:`Symfony\\Component\\HttpKernel\\HttpKernel`:: - - use Symfony\Component\HttpKernel\KernelEvents; - use Symfony\Component\Security\Http\Firewall; - - // the EventDispatcher used by the HttpKernel - $dispatcher = ...; - - $firewall = new Firewall($firewallMap, $dispatcher); - - $dispatcher->addListener( - KernelEvents::REQUEST, - [$firewall, 'onKernelRequest'] - ); - -The firewall is registered to listen to the ``kernel.request`` event that -will be dispatched by the HttpKernel at the beginning of each request -it processes. This way, the firewall may prevent the user from going any -further than allowed. - -Firewall Config -~~~~~~~~~~~~~~~ - -The information about a given firewall, such as its name, provider, context, -entry point and access denied URL, is provided by instances of the -:class:`Symfony\\Bundle\\SecurityBundle\\Security\\FirewallConfig` class. - -This object can be accessed through the ``getFirewallConfig(Request $request)`` -method of the :class:`Symfony\\Bundle\\SecurityBundle\\Security\\FirewallMap` class and -through the ``getConfig()`` method of the -:class:`Symfony\\Bundle\\SecurityBundle\\Security\\FirewallContext` class. - -.. _firewall_listeners: - -Firewall Listeners -~~~~~~~~~~~~~~~~~~ - -When the firewall gets notified of the ``kernel.request`` event, it asks -the firewall map if the request matches one of the secured areas. The first -secured area that matches the request will return a set of corresponding -firewall listeners (which each is a callable). -These listeners will all be asked to handle the current request. This basically -means: find out if the current request contains any information by which -the user might be authenticated (for instance the Basic HTTP authentication -listener checks if the request has a header called ``PHP_AUTH_USER``). - -Exception Listener -~~~~~~~~~~~~~~~~~~ - -If any of the listeners throws an :class:`Symfony\\Component\\Security\\Core\\Exception\\AuthenticationException`, -the exception listener that was provided when adding secured areas to the -firewall map will jump in. - -The exception listener determines what happens next, based on the arguments -it received when it was created. It may start the authentication procedure, -perhaps ask the user to supply their credentials again (when they have only been -authenticated based on a "remember-me" cookie), or transform the exception -into an :class:`Symfony\\Component\\HttpKernel\\Exception\\AccessDeniedHttpException`, -which will eventually result in an "HTTP/1.1 403: Access Denied" response. - -Entry Points -~~~~~~~~~~~~ - -When the user is not authenticated at all (i.e. when the token storage -has no token yet), the firewall's entry point will be called to "start" -the authentication process. An entry point should implement -:class:`Symfony\\Component\\Security\\Http\\EntryPoint\\AuthenticationEntryPointInterface`, -which has only one method: :method:`Symfony\\Component\\Security\\Http\\EntryPoint\\AuthenticationEntryPointInterface::start`. -This method receives the current :class:`Symfony\\Component\\HttpFoundation\\Request` -object and the exception by which the exception listener was triggered. -The method should return a :class:`Symfony\\Component\\HttpFoundation\\Response` -object. This could be, for instance, the page containing the login form or, -in the case of Basic HTTP authentication, a response with a ``WWW-Authenticate`` -header, which will prompt the user to supply their username and password. - -Flow: Firewall, Authentication, Authorization ---------------------------------------------- - -Hopefully you can now see a little bit about how the "flow" of the security -context works: - -#. The Firewall is registered as a listener on the ``kernel.request`` event; -#. At the beginning of the request, the Firewall checks the firewall map - to see if any firewall should be active for this URL; -#. If a firewall is found in the map for this URL, its listeners are notified; -#. Each listener checks to see if the current request contains any authentication - information - a listener may (a) authenticate a user, (b) throw an - ``AuthenticationException``, or (c) do nothing (because there is no - authentication information on the request); -#. Once a user is authenticated, you'll use :doc:`/components/security/authorization` - to deny access to certain resources. - -Read the next articles to find out more about :doc:`/components/security/authentication` -and :doc:`/components/security/authorization`. diff --git a/components/security/secure_tools.rst b/components/security/secure_tools.rst deleted file mode 100644 index a9d6e0fec3a..00000000000 --- a/components/security/secure_tools.rst +++ /dev/null @@ -1,56 +0,0 @@ -Securely Generating Random Values -================================= - -The Symfony Security component comes with a collection of nice utilities -related to security. These utilities are used by Symfony, but you should -also use them if you want to solve the problem they address. - -.. note:: - - The functions described in this article were introduced in PHP 5.6 or 7. - For older PHP versions, a polyfill is provided by the - `Symfony Polyfill Component`_. - -Comparing Strings -~~~~~~~~~~~~~~~~~ - -The time it takes to compare two strings depends on their differences. This -can be used by an attacker when the two strings represent a password for -instance; it is known as a `Timing attack`_. - -When comparing two passwords, you should use the :phpfunction:`hash_equals` -function:: - - if (hash_equals($knownString, $userInput)) { - // ... - } - -Generating a Secure Random String -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Whenever you need to generate a secure random string, you are highly -encouraged to use the :phpfunction:`random_bytes` function:: - - $random = random_bytes(10); - -The function returns a random string, suitable for cryptographic use, of -the number bytes passed as an argument (10 in the above example). - -.. tip:: - - The ``random_bytes()`` function returns a binary string which may contain - the ``\0`` character. This can cause trouble in several common scenarios, - such as storing this value in a database or including it as part of the - URL. The solution is to hash the value returned by ``random_bytes()`` with - a hashing function such as :phpfunction:`md5` or :phpfunction:`sha1`. - -Generating a Secure Random Number -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you need to generate a cryptographically secure random integer, you should -use the :phpfunction:`random_int` function:: - - $random = random_int(1, 10); - -.. _`Timing attack`: https://en.wikipedia.org/wiki/Timing_attack -.. _`Symfony Polyfill Component`: https://github.com/symfony/polyfill diff --git a/controller/argument_value_resolver.rst b/controller/argument_value_resolver.rst index ebc59a02bf5..da212517f0c 100644 --- a/controller/argument_value_resolver.rst +++ b/controller/argument_value_resolver.rst @@ -51,7 +51,7 @@ In addition, some components and official bundles provide other value resolvers: Injects the object that represents the current logged in user if type-hinted with ``UserInterface``. Default value can be set to ``null`` in case the controller can be accessed by anonymous users. It requires installing - the :doc:`Security component </components/security>`. + the :doc:`SecurityBundle </security>`. ``Psr7ServerRequestResolver`` Injects a `PSR-7`_ compliant version of the current request if type-hinted diff --git a/introduction/from_flat_php_to_symfony.rst b/introduction/from_flat_php_to_symfony.rst index b2840d1a17d..6507463455f 100644 --- a/introduction/from_flat_php_to_symfony.rst +++ b/introduction/from_flat_php_to_symfony.rst @@ -681,11 +681,8 @@ migrating the blog from flat PHP to Symfony has improved your life: :doc:`routing </routing>`, or rendering :doc:`controllers </controller>`; * Symfony gives you **access to open source tools** such as `Doctrine`_ and the - `Templating`_, - :doc:`Security </components/security>`, - :doc:`Form </components/form>`, `Validator`_ and - `Translation`_ components (to name - a few); + `Templating`_, :doc:`Security </security>`, :doc:`Form </components/form>`, + `Validator`_ and `Translation`_ components (to name a few); * The application now enjoys **fully-flexible URLs** thanks to the Routing component; diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index 5210d782ed3..0036347f776 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -4,7 +4,7 @@ Security Configuration Reference (SecurityBundle) ================================================= -The SecurityBundle integrates the :doc:`Security component </components/security>` +The SecurityBundle integrates the :doc:`Security component </security>` in Symfony applications. All these options are configured under the ``security`` key in your application configuration. diff --git a/security/passwords.rst b/security/passwords.rst index 7f1f5b605b8..6bf37d51806 100644 --- a/security/passwords.rst +++ b/security/passwords.rst @@ -704,10 +704,12 @@ Supported Algorithms * :ref:`sodium <reference-security-sodium>` * :ref:`PBKDF2 <reference-security-pbkdf2>` +* :ref:`Or create a custom password hasher <custom-password-hasher>` + .. TODO missing: - * :ref:`Message Digest <reference-security-message-digest>` - * :ref:`Native <reference-security-native>` - * :ref:`Plaintext <reference-security-plaintext>` +.. * :ref:`Message Digest <reference-security-message-digest>` +.. * :ref:`Native <reference-security-native>` +.. * :ref:`Plaintext <reference-security-plaintext>` .. _reference-security-encoder-auto: @@ -772,6 +774,110 @@ Using the `PBKDF2`_ hasher is no longer recommended since PHP added support for Sodium and BCrypt. Legacy application still using it are encouraged to upgrade to those newer hashing algorithms. +.. _custom-password-hasher: + +Creating a custom Password Hasher +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you need to create your own, it needs to follow these rules: + +#. The class must implement :class:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface` + (you can also extend :class:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasher`); + +#. The implementations of + :method:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface::hashPassword` + and :method:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface::isPasswordValid` + **must validate that the password length is no longer than 4096 + characters.** This is for security reasons (see `CVE-2013-5750`_). + + You can use the :method:`Symfony\\Component\\PasswordHasher\\Hasher\\CheckPasswordLengthTrait::isPasswordTooLong` + method for this check. + +.. code-block:: php + + // src/Security/CustomVerySecureHasher.php + namespace App\Security; + + use Symfony\Component\PasswordHasher\Hasher\CheckPasswordLengthTrait; + use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasher; + use Symfony\Component\Security\Core\Exception\BadCredentialsException; + + class CustomVerySecureHasher extends UserPasswordHasher + { + use CheckPasswordLengthTrait; + + public function hashPassword(UserInterface $user, string $plainPassword): string + { + if ($this->isPasswordTooLong($user->getPassword())) { + throw new BadCredentialsException('Invalid password.'); + } + + // ... hash the plain password in a secure way + + return $hashedPassword; + } + + public function isPasswordValid(UserInterface $user, string $plainPassword): bool + { + if ($this->isPasswordTooLong($user->getPassword())) { + return false; + } + + // ... validate if the password equals the user's password in a secure way + + return $passwordIsValid; + } + } + +Now, define a password hasher using the ``id`` setting: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + password_hashers: + app_hasher: + # the service ID of your custom hasher (the FQCN using the default services.yaml) + id: 'App\Security\Hasher\MyCustomPasswordHasher' + + .. code-block:: xml + + <!-- config/packages/security.xml --> + <?xml version="1.0" encoding="UTF-8" ?> + <srv:container xmlns="http://symfony.com/schema/dic/security" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:srv="http://symfony.com/schema/dic/services" + xsi:schemaLocation="http://symfony.com/schema/dic/services + https://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/security + https://symfony.com/schema/dic/security/security-1.0.xsd" + > + + <config> + <!-- ... --> + <!-- id: the service ID of your custom hasher (the FQCN using the default services.yaml) --> + <security:password_hasher class="app_hasher" + id="App\Security\Hasher\MyCustomPasswordHasher"/> + </config> + </srv:container> + + .. code-block:: php + + // config/packages/security.php + use App\Security\Hasher\MyCustomPasswordHasher; + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... + $security->passwordHasher('app_hasher') + // the service ID of your custom hasher (the FQCN using the default services.yaml) + ->id(MyCustomPasswordHasher::class) + ; + }; + .. _`MakerBundle`: https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html .. _`PBKDF2`: https://en.wikipedia.org/wiki/PBKDF2 .. _`libsodium`: https://pecl.php.net/package/libsodium @@ -780,3 +886,4 @@ to those newer hashing algorithms. .. _`cryptographic salt`: https://en.wikipedia.org/wiki/Salt_(cryptography) .. _`the Doctrine docs for information`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/working-with-objects.html#custom-repositories .. _`SymfonyCastsResetPasswordBundle`: https://github.com/symfonycasts/reset-password-bundle +.. _`CVE-2013-5750`: https://symfony.com/blog/cve-2013-5750-security-issue-in-fosuserbundle-login-form diff --git a/security/voters.rst b/security/voters.rst index 3755f9e3665..40d5de58b4e 100644 --- a/security/voters.rst +++ b/security/voters.rst @@ -24,24 +24,15 @@ this could look like, if you want to make a route accessible to the "owner" only In that sense, the following example used throughout this page is a minimal example for voters. -.. tip:: - - Take a look at the - :doc:`authorization </components/security/authorization>` - article for an even deeper understanding of voters. - -Here's how Symfony works with voters: -All voters are called each time you use the ``isGranted()`` method on Symfony's -authorization checker or call ``denyAccessUnlessGranted()`` in a controller (which -uses the authorization checker), or by -:ref:`access controls <security-access-control-enforcement-options>`. +Here's how Symfony works with voters: All voters are called each time you +use the ``isGranted()`` method on Symfony's authorization checker or call +``denyAccessUnlessGranted()`` in a controller (which uses the authorization +checker), or by :ref:`access controls <security-access-control-enforcement-options>`. Ultimately, Symfony takes the responses from all voters and makes the final -decision (to allow or deny access to the resource) according to the strategy defined -in the application, which can be: affirmative, consensus, unanimous or priority. - -For more information take a look at -:ref:`the section about access decision managers <components-security-access-decision-manager>`. +decision (to allow or deny access to the resource) according to +:ref:`the strategy defined in the application <security-voters-change-strategy>`, +which can be: affirmative, consensus, unanimous or priority. The Voter Interface ------------------- From 356ae6ae0b418b8b7800105d293e0efde390922f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Mon, 27 Dec 2021 12:39:32 +0100 Subject: [PATCH 1361/1519] Add redirections for deleted pages --- _build/redirection_map | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/_build/redirection_map b/_build/redirection_map index 1acae2a1667..0f5ae7c07c4 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -532,3 +532,8 @@ /security/authenticator_manager /security /security/multiple_guard_authenticators /security/entry_point /security/guard_authentication /security/custom_authenticator +/components/security/authentication /security#authenticating-users +/components/security/authorization /security#access-control-authorization +/components/security/firewall /security#the-firewall +/components/security/secure_tools /security/passwords +/components/security /security From 041b040114d04f12e32dd7f69fcafabb2b12d606 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Mon, 27 Dec 2021 17:17:58 +0100 Subject: [PATCH 1362/1519] Minor tweaks --- .../adapters/pdo_doctrine_dbal_adapter.rst | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/components/cache/adapters/pdo_doctrine_dbal_adapter.rst b/components/cache/adapters/pdo_doctrine_dbal_adapter.rst index 1f1cd08c8d5..e1bf8ab5540 100644 --- a/components/cache/adapters/pdo_doctrine_dbal_adapter.rst +++ b/components/cache/adapters/pdo_doctrine_dbal_adapter.rst @@ -11,16 +11,16 @@ The PDO and Doctrine DBAL adapters store the cache items in a table of an SQL da .. note:: - Adapters implement :class:`Symfony\\Component\\Cache\\PruneableInterface`, - allowing for manual :ref:`pruning of expired cache entries <component-cache-cache-pool-prune>` by - calling the ``prune()`` method. + These adapters implement :class:`Symfony\\Component\\Cache\\PruneableInterface`, + allowing for manual :ref:`pruning of expired cache entries <component-cache-cache-pool-prune>` + by calling the ``prune()`` method. -Using :phpclass:`PDO` ---------------------- +Using PHP PDO +------------- The :class:`Symfony\\Component\\Cache\\Adapter\\PdoAdapter` requires a :phpclass:`PDO`, -or `Data Source Name (DSN)`_ as its first parameter, and optionally a namespace, -default cache lifetime, and options array as its second, third, and forth parameters:: +or `Data Source Name (DSN)`_ as its first parameter. You can pass a namespace, +default cache lifetime, and options array as the other optional arguments:: use Symfony\Component\Cache\Adapter\PdoAdapter; @@ -61,14 +61,13 @@ your code. are lazy-loaded by default; some additional options may be necessary to detect the database engine and version without opening the connection. - Using Doctrine DBAL ------------------- The :class:`Symfony\\Component\\Cache\\Adapter\\DoctrineDbalAdapter` requires a -`Doctrine DBAL Connection`_, or `Doctrine DBAL URL`_ as its first parameter, and -optionally a namespace, default cache lifetime, and options array as its second, -third, and forth parameters:: +`Doctrine DBAL Connection`_, or `Doctrine DBAL URL`_ as its first parameter. +You can pass a namespace, default cache lifetime, and options array as the other +optional arguments:: use Symfony\Component\Cache\Adapter\DoctrineDbalAdapter; From 86f4e930f3603f119a27d530b71ceb01e90786a2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Mon, 27 Dec 2021 17:18:52 +0100 Subject: [PATCH 1363/1519] Remove a deprecated comment --- components/cache/adapters/pdo_doctrine_dbal_adapter.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/components/cache/adapters/pdo_doctrine_dbal_adapter.rst b/components/cache/adapters/pdo_doctrine_dbal_adapter.rst index e1bf8ab5540..9239f276f6a 100644 --- a/components/cache/adapters/pdo_doctrine_dbal_adapter.rst +++ b/components/cache/adapters/pdo_doctrine_dbal_adapter.rst @@ -47,13 +47,6 @@ You can also create this table explicitly by calling the :method:`Symfony\\Component\\Cache\\Adapter\\PdoAdapter::createTable` method in your code. -.. deprecated:: 5.4 - - Using :class:`Symfony\\Component\\Cache\\Adapter\\PdoAdapter` with a - :class:`Doctrine\\DBAL\\Connection` or a DBAL URL is deprecated since Symfony 5.4 - and will be removed in Symfony 6.0. - Use :class:`Symfony\\Component\\Cache\\Adapter\\DoctrineDbalAdapter` instead. - .. tip:: When passed a `Data Source Name (DSN)`_ string (instead of a database connection From eb0802d9c60bb0acb9f144851a5546a98156ea10 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Mon, 27 Dec 2021 17:34:27 +0100 Subject: [PATCH 1364/1519] Remove a deprecated admonition --- components/lock.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index a70ba793d7f..5b0ab55a1b0 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -479,11 +479,6 @@ You can also create this table explicitly by calling the :method:`Symfony\\Component\\Lock\\Store\\PdoStore::createTable` method in your code. -.. deprecated:: 5.4 - - Using ``PdoStore`` with Doctrine DBAL is deprecated in Symfony 5.4. - Use ``DoctrineDbalStore`` instead. - .. _lock-store-dbal: DoctrineDbalStore From 742b475d510ae18b836837a8958808fa67dd4058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= <kevin@dunglas.fr> Date: Mon, 27 Dec 2021 21:53:40 +0100 Subject: [PATCH 1365/1519] [Mercure] fix some typos and outdates sentences --- mercure.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mercure.rst b/mercure.rst index 365e3de9391..5dcda7951ec 100644 --- a/mercure.rst +++ b/mercure.rst @@ -112,14 +112,14 @@ This secret key must be stored in the ``MERCURE_JWT_SECRET`` environment variabl MercureBundle will use it to automatically generate and sign the needed JWTs. In addition to these environment variables, -MercureBundle provides a more advanced configuration configuration: +MercureBundle provides a more advanced configuration: -* ``secret``: the key to use to sign the JWT (all other options, beside `algorithm`, `subscribe`, and `publish` will be ignored) -* ``publish``: a list of topics to allow publishing to when generating the JWT (only usable when `secret`, or `factory` are provided) -* ``subscribe``: a list of topics to allow subscribing to when generating the JWT (only usable when `secret`, or `factory` are provided) -* ``algorithm``: The algorithm to use to sign the JWT (only usable when `secret` is provided) +* ``secret``: the key to use to sign the JWT (all other options, beside ``algorithm``, ``subscribe``, and ``publish`` will be ignored) +* ``publish``: a list of topics to allow publishing to when generating the JWT (only usable when ``secret``, or ``factory`` are provided) +* ``subscribe``: a list of topics to allow subscribing to when generating the JWT (only usable when ``secret``, or ``factory`` are provided) +* ``algorithm``: The algorithm to use to sign the JWT (only usable when ``secret`` is provided) * ``provider``: The ID of a service to call to provide the JWT (all other options will be ignored) -* ``factory``: The ID of a service to call to create the JWT (all other options, beside `subscribe`, and `publish` will be ignored) +* ``factory``: The ID of a service to call to create the JWT (all other options, beside ``subscribe``, and ``publish`` will be ignored) * ``value``: the raw JWT to use (all other options will be ignored) .. configuration-block:: @@ -186,7 +186,7 @@ MercureBundle provides a more advanced configuration configuration: .. tip:: - The JWT payload must contain at least the following structure to be allowed to + The JWT payload must contain at least the following structure for the client to be allowed to publish: .. code-block:: json @@ -338,8 +338,8 @@ in a ``Link`` HTTP header. .. image:: /_images/mercure/discovery.png -You can create ``Link`` headers with the :doc:`WebLink Component </web_link>`, -by using the ``AbstractController::addLink`` helper method:: +You can create ``Link`` headers with the ``Discovery`` helper class +(under the hood, it uses the :doc:`WebLink Component </web_link>`):: // src/Controller/DiscoverController.php namespace App\Controller; @@ -416,10 +416,10 @@ of the ``Update`` constructor to ``true``:: } To subscribe to private updates, subscribers must provide to the Hub -a JWT containing a topic selector matching by the update's topic. +a JWT containing a topic selector matching by the topic of the update. To provide this JWT, the subscriber can use a cookie, -or a ``Authorization`` HTTP header. +or an ``Authorization`` HTTP header. Cookies can be set automatically by Symfony by passing the appropriate options to the ``mercure()`` Twig function. Cookies set by Symfony are automatically @@ -470,7 +470,7 @@ Programmatically Setting The Cookie Sometimes, it can be convenient to set the authorization cookie from your code instead of using the Twig function. MercureBundle provides a convenient service, -:class:`Symfony\\Component\\Mercure\\Authorization`, to do so. +``Authorization``, to do so. In the following example controller, the added cookie contains a JWT, itself containing the appropriate topic selector. From b909ecefd2958eb8bcbea5eb8d510fa07bae1df3 Mon Sep 17 00:00:00 2001 From: Antoine Makdessi <amakdessi@me.com> Date: Tue, 28 Dec 2021 16:48:03 +0100 Subject: [PATCH 1366/1519] Update best_practices.rst --- best_practices.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/best_practices.rst b/best_practices.rst index f18c756c2fc..537bdc4637f 100644 --- a/best_practices.rst +++ b/best_practices.rst @@ -378,7 +378,8 @@ Use Voters to Implement Fine-grained Security Restrictions If your security logic is complex, you should create custom :doc:`security voters </security/voters>` instead of defining long expressions -inside the ``@Security`` annotation. +inside the ``Security`` attribute +(or annotation if your PHP version doesn't support attributes yet). Web Assets ---------- From da844ef4c7625cd48e0b5826ec3a286a29d32d26 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Wed, 29 Dec 2021 15:38:59 +0100 Subject: [PATCH 1367/1519] Minor tweak --- best_practices.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/best_practices.rst b/best_practices.rst index 537bdc4637f..ccdc8d17852 100644 --- a/best_practices.rst +++ b/best_practices.rst @@ -378,8 +378,8 @@ Use Voters to Implement Fine-grained Security Restrictions If your security logic is complex, you should create custom :doc:`security voters </security/voters>` instead of defining long expressions -inside the ``Security`` attribute -(or annotation if your PHP version doesn't support attributes yet). +inside the ``#[Security]`` attribute (or in the ``@Security`` annotation if your +PHP version doesn't support attributes yet). Web Assets ---------- From caaa569de3987e85a194ba6136bebdda97759f8c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Wed, 29 Dec 2021 17:40:39 +0100 Subject: [PATCH 1368/1519] Minor tweak --- frontend/encore/simple-example.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/encore/simple-example.rst b/frontend/encore/simple-example.rst index 16cf9b2e1ef..306bf38560c 100644 --- a/frontend/encore/simple-example.rst +++ b/frontend/encore/simple-example.rst @@ -43,7 +43,7 @@ of your project. It already holds the basic config you need: .addEntry('app', './assets/app.js') - // Don't forget to uncomment If you want use following JQuery example code + // uncomment this if you want use jQuery in the following example .autoProvidejQuery() ; From 87bd12023e617781a60533b567d887ccb333c191 Mon Sep 17 00:00:00 2001 From: Antoine Makdessi <amakdessi@me.com> Date: Wed, 29 Dec 2021 14:39:37 +0100 Subject: [PATCH 1369/1519] Improvements around documentation images --- .../contributing/docs-github-create-pr.png | Bin 66585 -> 171073 bytes .../contributing/docs-github-edit-page.png | Bin 63974 -> 62133 bytes .../docs-pull-request-change-base.png | Bin 5849 -> 17589 bytes .../exceptions-in-dev-environment.png | Bin 62791 -> 82684 bytes _images/install/deprecations-in-profiler.png | Bin 60991 -> 103758 bytes _images/profiler/web-interface.png | Bin 75628 -> 126397 bytes _images/quick_tour/no_routes_page.png | Bin 576466 -> 62109 bytes _images/quick_tour/web_debug_toolbar.png | Bin 59618 -> 0 bytes _images/release-process.jpg | Bin 315886 -> 0 bytes 9 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 _images/quick_tour/web_debug_toolbar.png delete mode 100644 _images/release-process.jpg diff --git a/_images/contributing/docs-github-create-pr.png b/_images/contributing/docs-github-create-pr.png index 29fe22f5dbdae49c0fc445fee88a3dffe366356b..43b6842ffc248555ab9174d2bbbb6357e9f42e4f 100644 GIT binary patch literal 171073 zcmeFa2UwHI_Bb3sz)F)U0xBXZz4w430wTsnlO|FX0qGD3pn!BD9VtOXM7j`q2_Q{s zKx*hc^p;Q(ieEt8>)ze_-*Vl(zwdc=PM-Ija^}p;ne$FPGx^;6c?3Xp?W*!s01*)Y zKtuq*=YD_};2^;qI(X>t;X}tLj#3;uPEAEcef%UXJpoQ~F|#ofeq85xIoLUP&s`DW z;}f}Z<1+B_4Sh8=eMf7@xVUzr|CYe#4*=?eWV1(TNQlk=h^dK4sEIz;0E7t{Bqkx+ z%j-8oa)5}Kl#Ki!!E@hy^Cy&snB)K{+2=mMQ4&HdDiSI}(5BOnoaD{$$}d<%As%}c ztDL={|A9dc0nHb<OWjA9fG;t8Z=7xiEZQWHJ3>&aj(y9nYU^%(%l6rMY{wuSk*<)! zK1zSY8iu_An1hn$(H^L7Li7tP*Q0>q2I~Qe)%up3fs|$lo(-5TjH{vwUyK{vK*q6N z=-4{F>@&D4Y^!e(y=gd~aFTyZA!#(b&{fBKy~(F)$S2oHV^EyD(d*UU$p9us@^*nr zd{Dw+j!3?2t8y5Z=cmyGyMBwuo6ugw>2+r}>&0E`C8)@{e$bAwtkh2Sn7e^Kbyw*; zG~VSi;P~RPU5@qPXKYuJ9sJg;THReY4{Z#`yJVkmL@2MZMI<DD1_--_Y!ApPxY_Se zxVfyu*xTZl6sN$ZEr=}~W~siuRJY$mLKk)kEBh<4ceSy|cob?C5!Kj)g}Cw^oSk!- zF`b&SKL2+z2>`$&8+@jjWM#P5<8BD*xA7sHWE?9tU-Zw(o>l2s{|pde&0ZXS2}B#& zY|}abhjAm2QjkAo!8V9w_|8hw!e;;#Wv*+QclE;Zz$j`_Rsb?Ll8bnW5w38puc8O< z7Pfls;jp5oKLZl#how1@KK;9=*o<&$M|}E6i>u)SZq{4+RmNMp2_&o=`KwPiWDvB( zH~&r^91Z-E8tBW5qrCZR>MAbLe`h|vq;-UK44F{A!(Ny2>~;+q&B1=9%gr_9*QX>0 z;OgU7ir8hIj(5~NO1LZ>Eerx^B5YU|nbIyXLwuo1&UvA9s7jU8*O!<dDjjQK9_gAD zN6WnQWyT9Nmvd5O#87E+m5ZH4!v#nLsX5xZq_3vaeQ>|+gfYCk5_8VCy2BZ+=06hm zl+P9O@PNf60r%yx^)q67$#``Ys4`E}On4*SvU=v2`e<kK`n|t0V3u&3-S*1LiR8}q znKD%BkT~yWfI5=C_0#n5*@ygQy^s2ClNp_{6jovK9-5idCgh`V!0SNB^VJAcZ#&{? zo)>qs+|Xsf@vD#4S?_umOenJ-Z80JZg+ElHG4eY%LHexpp%U}rWfL9FXCG?LrDEAt zn7o#wK>+ZDt<}{gs^z&fecc{b0p7C0*R@YL{#adotd!9>0a7syTwk7eI0XqII|FNa ze2{$-kAZe1F-?>VsD!R3r_Ma$Re!;0szVvS!+_Sm5}8(B(gGCAr<0UEP_7M~j*9g) zmZW-8s^}oIIpY#R`39(q)sJ_1_#j5+qC54Xt1txAXvc@Lk=dMtc{4&8W~Gx+kP|)k zT2(K`9fGJfOyx#2CVj+blg@C=Zi3QXGuC5NuVoobvUd)~m`lXpyQ`9;5gv8?k#=ef z>6UO7oA3tW$goQI9aQtGZFkg6S@CG@iP+@Pog--0&T&WFM#j{}@sq7=^0g}1>=;6h z6|=ArOIoY$_M?!D;@G;az8nop8vW9?krSKQDpSe$AZ@zGDN{SbTn-ZKAm(Y;jaQK% zWeoH+iu7KAAN8!0yJO>g<`5+71elG-4JXzLLB>S+&1`QZN{Sf1wuTh?tWQ}jZ#kI8 zx4nImgw=D<hUjVVV|Q9PO+KDPq#6bYU%6>|WNPO#pv5iVgw<>05&h!o)^cM#hOYUE zTT}h%d6vEBowAc$r(|}tUGb@N&Kn)^Dk+!-h+^crp5}URgo?zj=hM?oOYed9SWtY^ z(tWu6?DpI(O>}%v0Y(b>K1td1c4o|pxFyA)Gr7nY=!%DrGG!In67XzNShgsvq^n*F zWy%QJBp)i~5{Bc`E?c<gE^BIjqbC%eiCM~UEp3`!zj;Z+8GB-e(@log7;+>;YYeT6 zB*JEM)u%*hWnv&Be@w23*QhPU$@**fI@+|<X^_{gY&?j&^J}8p?sXS|02Q|d&aROb zjnEigYD-}Zb0Uo}Fck5GkOrJwDM++DuMlCt5pyZ-P}?E9PLK>WaP6v*ug+U$-B%nP zx1_OGrVs24i^`xwUc(a=?-m+n&|Kxy@G>O=h6MXaGfW@L=%nvDuuPhkXbLuvCK3EV z$b#ml(*=q1t}U0!OU`^K>QlP<xa;^B^^C+o75E_O$20U}UZ8w~muG0k_&0!zDjWtT z=WAzU4%xSX%5MQr)6YF3(C1M*u5uHceUV{@`~`)Nw1wphxF!cII;NJ|1VKn``qc5J z>nc3A9u!&Gc;1nrcrt7jB1tqay+*F*GVluhsrlAx=Z6`phqb$eHLivmg<hMns5+6= z9jN=}O8YFITF{+WSGz9;tUXZgd->`Qahi#dh|nkn{R4j$2LJ$O(@UlQz+c4yxvz7B zKP2^k1v0T}#vAVRqk)3_AFJ8_dHo(1X!0!Hq<P6m+Tze%xmP7Z#V0QPd0@7F{Znja z3%O&fS6}=Jgx%R279VS&Ir!<nhW?=MsN8QOvAyz4_%}iH$zD-^%WyukjpG0uiCM_> zpct*THxUmUAwondueDkJAW$aTqRqZraN=0sufV#m!m-Bt003#~t=K%~9}80gF%Sx8 zTi2T3QxcV{t;vLZ{H8fH5{Eu?J&<^+)ciiB)tC&O_MFq=BM3QqsH67X<redEm0($k zMbJ?^!^zd`)MY3Qo`<~}k+h1TOssSg>%?(BgB*T2rhg^N3D}c2*%Ldl!|u&`3#&?* zAk*sO=VGah{shU}w4DaC$wC4|U2TwE@8YZ|*Ze3$5PmbD0AR8l4xNP+g@yr9wZMCL zwktU8`IrP?eOnPZlI>m_PJXVP?Hq(S93e2YULUi{W`z-TMXe24W5hmL@inqyKGbEW zrB7ZTV>T~V@6x{NF{|(iTi?oBn(I2ch_7#g)wi>8gKr4j>05S7)jyrwpUUd#y(XKW zH5CPf^VPvHRURhsjrV6Goj(IqFzQZ)Ntn>5ZW8POtefr3cHc7SEhed|d?@8P)-B3# zDy5S$3gKgh3!6TkAnsz0ZiP+Rw#W}HCh)lgq_o0zpN<dJ8P-VAHd-ZNK(u%^Gu-hx zHOgoijU1p7e#uLEt{?1=J2H%)*bJK)yfY5XUZsphjE_?i<26E}k|*5K`{AQYN%DNi z;RjkP{htB1-Z(EYuSt<NuqiKO*A3sDN|1ptBkNzT>G^y@ttcV9Q3SefO{?e*8`m2A zbpm6S!d^VnbC-wNoryf9$%XK2mJXPv1JU4>aPYo$%9k>g%S-khKqEY@Pph6M(x)fV z)q7z_3j<?AZF07hyT6XZNzDxdqrB&Ftl_IChn3|ffgPiuQ)H!&)PGZy2neu4txv)M zyygW3fQ1$Ew(SD!;|&BuoAa|*5hnRz_hpdJ+2muVHi4y+u9lQpD?o_njJ{YMrS+W# z%9M88XMhtn#z_hK`tHh!1nsHqVe))vJ>_dv4CF?3Iw3UY{7fbD4s@KEb!%u_tQ#fl zM#on&v;7f5UcP!Pedd<y2!yX<ML#haDq9!|TpE!EJ;uAkFhDcB0_9Qt3}<&%V7}ov z9+sYsnOh;OE%@NA7);Hl**KajEJs|c=^_5mrY8_)Hc6FrzF<>wwMKwghfQW$K@ib2 zgs;`cWf9#V2%$`0eVlM5A9EBI0KExLuwEI(o-d=q50g~+Bx5d{$sO$|zHaeu115@C zqw?UZKYO2bbhN%p9C#jL8jA^JQ>kxxzsH8lu~Rr;0B01YzAPUT1l68%Qw$qW9U(`+ z39iKLnVdCHg2T3RPs&XQo8LrzUztS(OlvKzLZEZ&z-PdT&UKwE8hvZUMrfhlChOxZ z%Bbb!4L#_D{K76@^&<$o_oP()>$Qs0Z(#k?!&KOmt0~?pi{J!7)~$+F9%#zyHWgm~ z-KKjPya|PwaZ4WD^hdt2+f~e2^H1PML69Yz>UD(|k}4_z9B8Zr`tpSb^l8wfRq5xH zuX~nbU<JcItV{W;t+=6u?Pv&l)R<3u9&UOGx4gwG4GM$L?SQ;T@Bx#xc(>00zRvZs zCDGt|#U@JSsp?LgE8xV!vv<Ekm<}x8u=RR-mB>~%|2+YnGzP^pZsGe=-*dmcsQpyX zp9ZK!TFgMAS>sO~-_N?w>nA#f<p2QUZR=ikrJq3A^XmBT>8O6AEAy1z5()OYcVoYg z4I}eA@bEtaS&Z`a%HPYZSKoN`J0kprDF0S*e_=|$gY<r8zGDmv6YNO|Fa)y*G-K^= z&{cQnUZKA~tgE%Ag`Q;Y?Ve>S`B0a8IY)=5TSUt@=z*X}^f85$<i#GOURvN2)Id;C z`?=@GFSDi~BVLAkBPMt@PM<q%+6_}6_+Bv(J{9K?_w=Qb_B1QJ`9;_ZKn(k_I;aA= zMV-s5?*vES2g}qNI}?dRulZwyG%__pEu!0A1o0{<e`Hp=JZwX6a*Fd57<uk@l<JS6 z><@_q`S-^}gqTFqEW1ky4UK7|6i}%FbH~ltwK9D%aQ8z~8jXBy?RncwYau8X78$j} z+%ca{yC#ks!yv+1@DSLpyR2<3Cfnw$Ipo^44zVG}{LIjYLhV!iW6BeHK1c{(?z)>0 z3Ojtf9oG`vW9rkNc`8LIW~a}13ARPa#2Ra1$g}1g;XjlR@0tio9sxauU!MY7@wM@q zM2u}noeaw!-Gz?an2+|&9!`IfX#>2_u{=~?&!&+1AYS29N_5iXmK{ig@>-&*yP>6; zuc~AElUY;0;<k~Y5<3YQcNw*kxU4+Gh)?hA1llrnaP0EV5}fgPzSeTTp6tsZZ8K_Z zF^oluZ(-$)=%LgMWs015$^-~W^GSmrzUKX1KS*FWv6<3gxYn6k>j(F)gfLllwfT)` zbCetsir2Vfp?h}a5npFuD40#S6@reO5@=k|WpP0QQWLdHFNt>52Fh_OG8SJy2Yb<{ zbfw_J5xNf#Q-e0VR5Kn-T9Ee1Rmho4o(AR|N<2by=LnYU3B!Fa?e6yxR27QEMrVx9 zOzJAUd(FUQ##?pp<-zq`uA4E`qGt%}IbvoqvY-!X+IOi+l|a67e@vWy8=KgPQ{uxN zc0h4fU+-^Y|HT;lnYjtb;kl3z67u{i6QhyAKd;}#0>8wpM;wCue{uc%PV&dK4r82O zmz~c(%=N*4`5()#Gok!h==7VC3%vd+uYZ?i@!B8fX7L@#$`(R*qA^mR{rq>$$$w`R z|2Z_~rDK_<zS4Rx05gW-Ys-I*$PbJ~^e8hE?JEroWB=b|2q`atmJGb1{Z7L2)ntih z<SfPi(;A&+_*Nn~dP;I1Gu1OXRA&ByNq)Sk|Nn}mBt3SHP|WZF3CzFMN=J=L_64jP zlpg|mov+@FsbOVP4)L(di34u}ia|5CCL~ysdQ~t(eA)hG=_t${B=BjK^lZHm2Km}q zJ`m3tATa}3!PHxIvPpy6t1{P+(JIXjTis5kxoxYIiiwmAsN4F&8*%bT8CeMlF2n#1 z4f?co!R`E7{yYZcJW`!9k37bZz0kDUW7Uot(eo*C;>;h9<80e5u7NN##F-*6=p#9G z>xw}T%20&Tmh$SOgsX}z_*e(7dZ5q5op2ZU2N?x;olN|lCZJaoIt!fwM?>#in9yq! z!5|H5pyGJG0C*gpFG?Kr3e!{1>L)$d*~vb(#b?UbFt!l|jVyIlp|sL<^&ZY}o?f=! zO&+6Q@9)SyzupBsi|6#Z)^F~3`yfOtX6VV9Yo=)^Rx*w}k=1!lg8V!-x+k{WrQKn2 zM6a;Lc1CyJNz|6*P)?T043OmQ#S-0O*RW)SNMpII?OW+dHpB5`nX}}F=A~=Y!L#>Z z&RvGCDe@Jz6Aa}<6MAqdWGL9pP2}Ur5|4kYpWkv4Va1aJF#50q7TKtc;R!Xj)XMJd zJAF17B(gju>}A%5j!G8EyuN73xQq`J$zF&mS+NWXL<d<VEf)4nMF2BbUxu|?amKi~ z3);f6%w26un_DlIxILe%Eh)dUij>D%tZjbSq0oDx7{2DFF}OGh&0eEV>l<?Nteyc- zL<&Lm0c<L`l%kduHc+NIuVMTJn@*h>*Mv6FQPkAVdKm^@HPfco<G1E!Ex|fhyY=jm z{WRYLH#Q}oj}Xo&b?`7B3ggq~EPTPF&)G6Fo_7P9&u8<7_3lRGw!RY%nz6D|j<zyr zsI$^29?xtVz_}xEbtxS{>**bCTX9H&klw~M8EF*PrB+G!@<x_e`#ak+SQlJJm$MsE z6nPB06up%;Z3-=ON=V-B7*dD1bZmA^i;An;f`_C&J((ZH50kE)Sk{|+*%q``e@4qG z()mP!B4&rR+e#2t5ZrU3CtjkQFyBUXVnyIJEt6Y3MUnQ{3FvXGdmOkA&w0ENe00!Z zG9wd|KgHGWis^AmnxR+2*nWWX#OWK3K<HfDbS?F)RGP37qAs8W7sTnY#op8&mR8f$ z@h$1{*(?n`$CA72-FBn>Q@B#p9BwfNm;G>Drq042Z!w3lE?1+VlvypG1ghKT&y03k zk3&phn2jatEe1TMMz|zifY{AQXJsg=#kridU%D@TbFD<UsIS$f7@pc<{z)XgdFHCo zxV>@W4Q<yFyP}PBd-SAF>&Bmuu{Y2?8H<{A=fw9|nKpnclrYM}3!AZn5Vx=ftn<vY z_(qYBRiS)D7A#;wZ)3{UwL)bTmJ7k=e@vdW#5E156|X`GRRD#~v)XI~4O_jd*Kf32 znB%EO4eRrbmUCJ`qb#FB7MJoO%M|rYSo2-kcsf#=SGV84bk<j!gbXce;t6YazoQ#q z^+YC3!zhXlfBSNHdndnHfBu%VV>dq?Pw<l*h|Fbb`+4B+b3qPEk7L{u4!zhzC+T%& zxz}q-uu&S1f3X0hv(s00KLhNE))23|w6&2`PLNYXpQ`3Y_9Fa^hTOEx$uz8G5k}V( zRpNAOF=y1L80pPAGpe}fg3-F9{6|Nj7wf_(d8yN-#UUyef@6u57HlQrlikSz=26Qp zTOs%PWOSc}+msdYH<sr=B=s#rfd4c3foH5J1`rs;yymnRJzv!Na=xfKcbuXrP>Pp- z-^%`eJh(boib8x|eEj!Y4PQtu%FUtwaJ)Z~#{Wg!J-!K+er4TvT>L*_ZMnwXHvXsD zk^dmhf8Lv*0C(?VhJVwU+>aT#T-^Uy{&!5cMGXLOSIOM}^OgC7Vv?3bUaKU`F-0=E ze@T)23R=j+v6ZCVc~5|e2E|qKJbsDwb03P@1jQ-te(&imALPqEUDmBi?<~|*{3eAs zfTjBR9xes?=+C44!bMUs1h3*%i@I$?Ub6fO0N@SxaLgCKfBXff$1iZ{&9%4)yzGW+ z{vwFQ5_Dy4pmZ%?5~%$Nr#ZO;nvB0QUBQ9xX#g3Q4Jj?z2{dHlb=fGudWK2#Ia)?# zFh4MYp~K1dklZhb{oI4{iFF3Htg*nnX`@I4<9@}>am&4id;MnDTl*9^_??YQ+<5(# zKHcJ2A*crYOz&7}O`N+tokHW()<MrlQS;+=OSVyA-P7CaGVXrsyQh95y#pyl6JQFH zw^4Hr$ESeRjSBIQtr1zPO>dYFJb~7s)MeAKaM~{Q7M}OqwH57^km(&C;zvI5-M*t6 z=a=X?(M#GOZbkB76OW%40+6rXph<R>$Rt0e^4~%TYpGo~i3cyuxxN5DbbXDy)Uo1O z*pd;IZ0ajzd1|4^vrzxHb!KHYh_yxU%&7%px*8z$J`{l><X~R@b=Tk%^{J~35Cz^d zB~fM5>v35`+}I*NH>j+4wy9#~IJri}SiP0+wO?fEXCA~0ryX86n02yHIJrP6SoGz` z)a@X$J}eSN4KB9MqcdgQ<W|LF^x(8Oq6OC;X|T4NG+1)`ve(au5FGG(4VnM~3w(qA zJ>>6q=c}V`l3fMBHMP{~)x0ANjQ_Fx@0ieX>k(t+-!B8dmZH&pLK{f?e<Cxb*KVHz z0OsPn+B^UNa+MeW0C2=xOfin&(2q1LeHMKT?{jK8Zeola6iq)%2>lxkflZX=dbXvg z<rx*wyUh*{4wBxE*-dSk!sAg3*K}NVUyRi^O`ja<+zQWelbi$x>)qhgj+i#Ap0Ul+ z9YJ@{rrGCZQ!lwP6b4&qeAt3}n|JhNGYyuHJzy;qJp>WE!6#)3S6k3p9pvtAEtlR^ z8A2h;KMX8lEH|qMtX=dD;5AxgDt!OmQw;?E%0wWE;h7B_01D*m<p7yTn4HU^V<<z` z3Ju;TN^6!?2ONkqn9bfa=y)Eg@6xo|BqQJC17Go8AE=N7nHKu9rlgG2#+HRwTwN^_ zfuVu4U?^Yr1S~0YL{YobiF$6q$zY)@{x&{=TkdbHO#pz2ks$V;N^bwHiT;Pgh!?n$ zPyL6mzt8($91)E+`}>mpm6UpvCoU4ai5wz6y&#MgwAJK(1?jKwI!pcLx1s74fP?y9 zAml-sR<JkB1psuD?cVHl`Yrd#-Jh;+0Z$K)K*}~fXLfAI`BbqaHO`b}o8wdKh=g{a z5Zfm(XM?^1t}~@eQr*>f8sX(?F<YLqvVoE|7*8<7UBAttnV>&{!k~L3I9v6NmpP*$ zj=oN%p8<Bb#EDG=5|zN@BCF~8bnP?X#ieP4w>~rE3=ShXY`2`^N#pUuxkHkUoI%Bz ziG2qgU5US@*^MxyOI>rmT~f9i|J>8zC$I#mzr1^Ge?&xR*7LH$JplCP_tF4c(CTtE znBgM7)A-=_@Jw8j45)5=W5wM^{m#JlRz9Y7c83cc|6#axHx|RbxJx-bV1CAlu!Lvs zSGf^sfWi^YO1l@V+H68qE!o>~R?by2rpMzaDc@)mP9Qb<#%|r{@rRdeL8CwmN7^=B ze3CaeialCmRzVL@m_ZU*@p)}&@$etcEx@@MTd=wrQE^K46gI<Z{Be{sFt)i7z&wNS zAnA9Q9Mg4cg^v&Q1!E?M&`<g37Rn+;w6IX2o`iVtf>8GPjiI}fP`+2>T<MKkVAs|d zGXTYeDN6@}Fjq>oOuc#S%i#K7eALPS5S>l2YC(DJO{Q4GT0AH%#uQUmE3pVO7fHk~ zr!POQ#0Lg>t**5YGzFzhz;ROQPZq#^Myw`XT5=>1u{NU4Nqp9}nPaNL{OY<h{`L@r z^7-0HOI;UM5DMpN{%Lc!=Ll@a3O2jUg{rFH>Ozk~Bd`FQlCsx&2|{np4lGkTj>^!P ziw|`m?Som)+@!NmyLd=_e^&Obd1x_LlRI90zZ(DoL|zyHoUMATe0YA|EbIY2J{rXI z+UYuHC*c^_v0O8fZ#vl&?+GWfl8y$-P{JtX!N^mD-SIh_Kp_wNU={YGBTW28RXM*$ zwe5GZ@KA{kA~WRarzxlf`3tQ@Y4Jn=5h8Z_TWksqjqqG74sv(@0O7^{H|jK*YPsrr zYW-ij1=5&qbAU>q<z>Lxy7u_&r0s-h2U{7%5WGaP{*lEytTy$pBoIjra<&g~<^k(B zILV9R7a7bw_2S2prC1ZH96sW7U^OM%Nxe>(0gUA*$+eA4UDZwEwOy(u%)5Xdr>Kr3 zIvI-0!=e;Xt!|!}8A}%!x#qIlTs7FXf}G{{y7=XJD(tnvV6#%OizN=?f?E1)Sa;He z2aM6_FRW;8t`d}r8h>1SLz3LWl0s+tu$Co-)*<dzpS2>vT1e$6G8Ww7FLmSmf_PHi zuUHKOxw|>+iV0yE-(wVcrZ;`K`DGUWy}Zzy8$EEPn!4!)fH0#^eXEM^-^5n8CKT}B z`}{TbBWjN$Jobj*rPpSZ0EAuVr@H6;{(&FH0srn$y1km)XD^`t*2UBRz>nhq!ehUk z()8G4@jnKz_aOrSY)bE4%hxCYwjO(~zs;0g;uz#k%e$C)IQ?>38^JO*gqC^V^)u+v z61|Xh=cn-w$t;^Jo{W+it9TTLb(E@)fH*=;k#_j{r@<HNAG*#ZQr}jV2^r1l568?% zrNHbZ43>=6ac-{qt6($b_VwLhHX(=NlTv02n8z9O=B6B`iF`~pqxCvN_dt%7OZA?7 zR)i}6_@TWHB0!T;)28W(cnTMER*fPXVhEXFHCujZHAOz*!a6S`fk#SkCBBhVb*JJ6 zGFo-oE!@>4<<n9EXU@=U{WGxSktT<1m{y3-n=v|=XUwhPRIDBD&>}-M0=F#11fMlt z6@XY(qtNFH*NQe{6Fc=q*Sn9`-Now%iMP(H)Pt>nmw!+-5Oq!3%e{wC;rgc&WJFZv zkrdc|R^7N`*n!tX(@@D7Fneub19K-{ehQ>Jd5k%Tb)yQPe07cPAR+xPN_fCT<QhV* zn3nZD?pO)Xciqi4-J$6Ph7_SNSFac_wS&4ktXR!y-U8MS%SJiLTrwRSw%80YAKu1H z6BO~;S`hG6tMo@tr1+QSFgJa?=ZoxNQuYv-r5Ej$xbhNdu);7#*K%MY0J&kDJ-)N? zbaeyXi;2IX>*9%;m{+aO?oW8OQ6V|!=D4ucZ;5IiHE)Sbfsf2OxGAquM#WdSW3pc- zaBOkbeFi8*x-PjlpcLC`b$UvVC3#AptZs&oH{uT&mq&BQMsY?2)0q!)tgR7L4+gjE z9rS8HN*1`e#n9UmPG$H)D#qv`a6hZJVH;)jH{On|xF|kaiU~|_p1>Csw@=y4p0~6O z7GdLCNXDsjIcv%NnED~ti0C4&?{w3}uCl%rGK%1wjCFKv2}7^(-ibiOhRdxFaTb{N z528_nDK!kGL)Z0|oPi;IXlqGMmr?!4o6$54SJ$Y1x&(k%wT0z;DuDZv2ML5Q9W|Yi z<zf8{s017xF$Iu40f1qIvqKeP`Vr~KVQztp5deuqCt+cs5<p@h$NY%-5x|rPQ3N0= zctzG*2_Wlxjz2mgRPZ#8tS>14$CQ>pg+))}=EwKsZ!q@>_rtuMr20bm=MwkB68n9G zXlf*1PEw?YOJ?1iEtXH)w-!$Xq+OnUQSyd2^~iUY|3e+e{}l~c0*{%aW1QxH-fsWn z`tuwJKH^eK^$PIipfrzK9;wIgljHvu>+BG_$=B5n$m<e~>!-g!cU>)AOtttxojtS2 z&%lt#k9{vq)uZ*&U-zd7YhQAEb9Z7h2$4P%n;olufF8m$@u`M+4IV56zisz=rV89~ zudb*YRICP^R7-ocM}UC8q5ynz<MY0qhPp(0gtU1>C1k~E9X!l2zy07B`&9dgf8s&J zeY*zWATjCa^869$tXL3WcD3A^O*R5M2h_y6+1wOOc6c$Y+9DKO+ycHdxzg)3^>#K+ zp-&C~a1fue4UF+1w5q~FCs)n`z6_m?s96x*2RMpDDsGv+9CawlecCe|fa0uouhJ^; zDlFZGI-7b-=_T<HP7!X~&dUmoHH?)<1+4DuMzLqt&TYkj7qU^?q|PI`ie-10R)><B zplPnzb15ehKxx*T@Kk;6XHhM?ewbqYOSp~pM)kDe98l1V3edK#RV{r0hZ`K-*yPl( zQmNuoo3^3IZYoCx`a&Qj_3tpBR=GYo6EylX@hJ_6%+=^hee;%ziHzA*8Qs;wfTd;H zQ-6YczZ&JxgUHhzQ%c|^<|S#>&@Bp4kT{24l2aR{?gYfbnYZFJYey}9nB%@mK3Cpz zyye585xn5om>wH*#Z<;xyPdQJtS71VL_Y@d0Qea|(H^)e=>=5mz<IY?M|ZM@rf}Zr zb7o<e*?1btf1s_|w&vBBOnmt)`fm~z<_HHM<w%$S0wIAOgfL14v>c`BIC<LYt978b z3){(~Muw*VjC+rL8vyLL{j3~93EV^eF@{+4trzi?2Tp)}i6SgufeXVm-eS%Y<#UDC z5lYN`8SfE!YA>y$lb(C8uOH0b`t{yw@%|UH=l>TQ!u>29SH42zyW9-!^dlEPG`@$& zB#9Hc_+OqY-|zH~%L^dCt(FwtUWgiG__TtFr*5@VlxRPRzGC}xYrTr*IR7eGu(FAS z`{?_BUi&N%RJhP^QqluJ*vuxF(rXJa4@fp)uaF1~+&(Gk+&&x)0Q6WGk3kdW0819E zkih}Wn1>9D<~VnMmL^5EgS1(qQN|Mcv*8>aITki~RuS&I_Ez<=4m>bxVPRDXW$sB~ zcsOeQq^bPnP;Jt)uotT%VtKbMg|&L$P3wyv%ZOmUcOkQrG&jlI_-t4N%McYW?Wfi| zx-%yae2O^kaD%w@@Ju54&B+pm8#IG*MAMYOHJDD&gQ9b%!TQoy;hGGM6wN85mN{v? z?-rLm$gcBNUM|(~vx(O6@S7GtmmXeuB)pQ+c<Oan_bSD;$$MQ6Im~U=N*erkwKE>A z?aIkOgOA)i!F$+po4TI%o>$PEbQMjFk+~#Q#-q!`u2dO^=U9?jJ)&%i{($ron(?Lv zR?EsSQFuR<n!aK)pYi~Zr1F^I#p{YGqQsn!0En{s>S<j+1Maitb{*C#EYV3zp?c(4 zfSJZ(ZbxcUt$@+7_Cl%6*zJ<rJ@gLcl-?D5>Pu&^iej(@R!41_OpwHE(Q!p_4af9` zoLK9|yqgo~6QNsHEYrr5E^G{gLBgpmGPJ_rtB*Qn;t$8o`dq$YKi+ceM&TVFKM322 z8{u~MlaP9yclqAvW^;6&nsauWK|gGvcnhibTf1HD81%;O?Sx&Rv)%?73|Z$A>J3x< zIALF;+lbkP`{aCzg8HV+I2By95*r?&DC8_ODVNOScphbPL?SDN`(C<4S9yItpUOu( zNK{5Yd@24~DJCgp0>T%Qq7lIXd+zkkWWD%=g<eXXV_6(H;lixz;1w*)vOW<r$XMEl zb){Q#O?3*HmtGipIJd3%3Pb*GN_!kuQST^?I+j*wFH;z_<UG(Pf2U9kmct8XxnW@0 z8uxLwssXMG<w8xu;7yKYRWl=DQ4Fr=%#j}bX8huz`68E9!%xm`=y+~L<#*)o$Lvx~ zn(DD9@$(N(w6~{FO{;ktB7;C$JW6md^{S8hH9?rpBd}fy>*Ha5kv~)SU&crOs{DN# z-@c<g$GL#L=OJp3z1PnS>A$P^5Fwr^RsIa+&pHm|sPLV2F8vxkU%kB~>@8sq@ov>J z<+Op4?rny<-d$X0gDys?jq#2}M;w=op!yEzm8nO*bABK6kNrCiMAmX~7!aD!FI{Mh zImdmX{&zXXPV@J~&)ft!Y{nnvz8W#JQFQUk{1W(dbk}bN<2p-%oY`C0_}dIYmFo4o zuc>Kenxz56nhgqG5oW%xLiq`Umwn@6MKi>$A@ttki}UY!(x;)g2r2DPA_*Hd*D3+< zoLi<3UI74FTs*Vt+TSw0pPOSX`!5nh^(Xrl0KmfY=*U;=kAHpL{@5c-$eRBvl0r3^ zSoIq8scQg=;p0gvl0DZkCEMOVRpi-4Ou4BWs}K+!W-8XMlhhLxfIr4)Ql{SqbYH?P zRjzL)Ty8Dnu^c|0pxEwazqDnYGWB4cJbZe6X%0x=^QL!YsN(4iC1?NYt`GCLRbhs- zMS`m6%7la-VeQ0bc5W5ur+2vm?&-RnAYa(q?W*Da$y(BO)ov#_OV`z8w+X7#>aH!` zS#}8LG@QGFz*NnhuKpvv*&pH{4`Hv35Mh7emY}B^;X$@Qh9hjn9m6u`(d-W}_Q|nO zCT>@_ZG(5A=;^gVeHiy5UN#|l4xgRCF^2~oB<vu!cYE=e<Mtwp%b?yEF*^o(#U zVasfgcf?+>zO8_<`XCwm+i;`PU{;AT7ci@?X-<C~rKw^ILvQUw!|;TL?ab_^-3eH1 z^UK7&Ln42PA>RAAzfy+ZYrhMicep5Yfl&7ZIql+)`MQ2YKzRIU@9vDh%Y2p5e|<kB z`F9@9*W95X?9H=e@m+0sY$V?@Z~d=xH7>|QYkZ(sG%Zs0)lchne|c^R?N8|Yuc_>} zKccOk7D<GII1sYUPUXG%#}^~x7-Gfnkg4rA)J(sj|A6<`di^pcF1|4~tmTZzHxAL7 zne3L1?dk*3<|40sr<-5E^C&Ja7@_pjMJ&H|8Q9~?zjlMz_kLk#Rj5PuRAy4zzPrTb zoKo1MU%7hh`-uNPw=43Vy`ePoRT>FuN?mhMJ`~A}G!wYoH9>kK?$OJ+TE=-owUX%O z-*B26m(hs=%BlWT%~oqx;SizzkyR%6r>OdJ-N#l>KP@<xS`#kON;E;TShYD=SHxjU zdQ8gD6qB-I$=v$4XOL3@gu7U8mr7ebvbkv3fkjU~217)kLQv)Rt1!6gc#GyDGTs@% z*|mEMnO<C-Ute)M!Q?X_sR^BFUu2Aw?S!&Ow%x`;ic~Pjbk}Ujt~jTi*3ST<43`^_ zIlW<07<ooYPbAPCi-av>!BFZ2R}J2Bn3#D0@}2FESG6Qonkb$KhRFc{A1euLVYo1$ zSGl_Lf}@XEh3XZ-gD`=+1C!jW+_UZ*6029+D?L!h8yEF@^y@_uKot=zunk|9EyQ&P zJWNjajm>-vHTM-6P^1+LFEZR57?VQfu!yssOT~4;VhRuOr6*QLA}`&EI*KTLS;J}d zQWpkGZ#IK>-Wtn-xW^~w%x*{awGhtb*)MFyiQUjcdN!&oNIUpJG$KFfTaRvZ+?25Y zmX{y)COT`Qv#JO>^@SioCo07tDy-$Z+bvAXt%zm>tm44KoaY1zQn($ys|garuLB+m zFQiNlRD4R(FnT7~FeRtaetiEZxXnqQ>$WVs_CsWO05U-U;6TpaKxr>6vLCD15P88o zT&(Te=%-KPPOdcU)LuFeHZ*Gm7}^9m@>JKI95rqt(yt|9SonHsx2~%~gk}$A-&m|A zgb}`n$(2>jX_X1Rw@1yNcFt{-U~n5*XifM>oh1j`?07qTln`O|N!Fz=Yu5(3<Ae*B zC1}rOCvIbA^;}o1o7P>6oRNz3_#S5I1l>3c?I^Fpr<q5~TzH<I0F`bhX>=#f%6!c0 zb`vUvJ>L-36Qwb<vIYb3b&qKeG50ETNGm}o1hTB+@ld3#bI-KJ)Y6>vMhbX)d&o2q zGq5&SCI(-zUvMgC!egd4DHEM$oLcf%!11g$$V8_lc@Sy}t3$E2yZvr6`{9R4gpc<+ zg3HGe$(&P<evkgvXM8L0fAJ<vh;$MWm0u_j6j<X!CRX+wB#;9!vjB5~kT_yh^1cM` zJ&*1jN8c#h%2^3rF9iyirVKY`%;PDKN)1w;(ObGxe*{aRZS`6=pFD5H)-WNz6tnKU z)#@I`S(=0Suyq8;n4mbh`C*Gsezi$`C!o?9ufD}9%M=WW-@Iu*oal_U*aGq~Iuwj1 zZ|G34YptJjlhg;1Ck$ZYb|0G-jz6Kdo2f)s7*5zd0=FKcUMvG94QyIq75c7Q4LUCh zWy?BG;AS9be-H5RS(B}VV~FsR>;KC6e{I{B%ieEtnO1O}>+NH%fc@*pHR$PTy{!%O zP_H#T!QS51XGC(@Y5svf$^p$3vozW-^|Y@9OBl78)0-m%t*^WSELej@GK2hJeCGZK zUj5f~`Ns+TY(%uLc4{gah$gg|LQf0$MF|_V{{!>=RBTUa7*HG<+B(S(02JKS4a_LM z{{P6*xgWM^^NU0XYPc6YzI`Tplh-fR7{d@O_hs~*pHnEqw}Ss}j!2*(iXGCQ9^7<x z7Eic41T<VMR?klmqGPkDFN~VATUeW%LSu$7k}KOt$59C^7$k;emVN_+ruRcVquTJc zQ?AfV*Qh9sPi_|21=EBn83?Sb3<#0YgNVm&Ou<{!*T8%U9c_(I9^zweH6_nK)|!~! zau<u&Um48e13qo~*@XHRCHgNsxV!f!gnJbBb@RwH2^;!^9e?Aeao<xVgY<aWp{=@{ z5(lD?6!k7O8EY(*6uC?CUUge>f*OuqQia>G&e&{W8NL{S6h|+aqr19g_^3$ERIIyD zl-8PvYro{0os+Ulfppti-u5ceVDgNq9=yTB@c#G7{7C!$bnojn=zb~5OipPI5E#kC zpTJ?ici-*L&CzJU{t|`Y{XLxqf_&U3JV?$F9$&^1f(H8>IpnKV325*D0HVDKZj1l6 zV!kSf?<KN7H)n~#ESN+-XdCyFBSMWkTs%}Tcowr0EdFg1We<^H2<pz3SoGBv_l!9p zbEgwXw<juQosQmlF)D0}%zi|2!!<v;Q2n}<XJPv}cq3kxeWnm9mh!gFerhNHTsQ`K ze6K!Y#zDG*H?Q3B)fg5%3YK27t*(dy$6?X+Gs`>Y;8SNdPC63?AX3xrQj=X>lP=W} z4Qt@_@kxsf(bhCO$$q@_t~?S9>!H|nfiAd;TDf~J>^czc@{k=Kv7J7NcL6atMBT7N zODel1VV3NhHk_OW^s>{(`=@r8cHZ<v^eyS9@S6Hy-F%oa18j-TFC7wR-5~L1g!ONC zLgBiHc>3{djgpvI!ri{Ucq^og!=SUZGi#x%6}0b@>Ue`;@9p|)ditoOMhBVt7GD{Y zAt^~bXE1ifVO%zL-U$JbQMIy=&%OwBFe`Q_MoaBRNJmO!$rvzBf8pStdlFh%1wxzp zW!||jVa87*38Y%Td^bNQI((_O-+xHTX)KuVcP{5TvGm)o)`Z31nNmQcWS}SKkX;X_ z4iQcixrn<)1jw+71-8Ox%08I)-o>aI_FHeVqin=I+cn0Jd_~Jll?y9OJyvdqkuGTQ zOw$h4iTYxUbk$-RlG{a}_UnfP9wKG94&iIWO|7^jqX#yYBw$))4%yBQ_DinW0;VOH zxTlL{Iu{^TVIOYRq01Z1f$2@N@FCnHv-7&Eo}f%78-I3+>l|H2eys$yKm8+XdSj%+ zz@_d&w9h+FB=;KF**+d75cJ&c=cW9EuKiV~FL4M8-vthL5cRE3#s3{VwI!QAST2LH zmcj(s`^$o;tK$TiZ7<pL*n>=hXVSjsUcdz5X4O3?w)+~q7wb!$z2N@@d(pl|$^4Gm z_vl|Jm*iRM{*>Uvw>aPO@@wy3&GfG!?)iO7{D)GGRW=Nj-thpC?CV+RCOaVIfIWo8 zSQg$#dTDQ*x)9c7-X1^g9sa?3`~m1c-|YBqXLDvGiH#yp(M@h|K_SW?=$`QdQv0JM zXll93LZ%3-8eet^7A|C9XC7?n3xA<QR%*^i7lm9K{pVW7@2+L!=n-7?iTyVHGchA2 zOgeNlzs^4XvHUIE5I#ka&@Y<Ve^lguIKDgK&jDqr07M6fi3xxEM@C9=fS8Dc^Z?<{ z0!fLElhM*p(@~u|OD-rREFwqGFCgl1`pgq{v77f9UdeMP-hOe8^U`I){{#~LLl8i8 z5bznmRR6Y+qsWd_1ICtOz8-C<8)r~lXB{^#+Z-&x;l_0GJ&5cHs-n8gkhfJJSfDyR z^+VOV&rV8r6|W|XqEvE;yHcxdbz+89vBoa)nT}d#pDK@!a9&nksq-m!p{MQ+>U{Zp zT^^qSl;ZqH#X`LaQTvse$u-zMxaV<3D04it@0!$#1w06<+^oGB9W#7V)@$I(XMjb; zD?#7+K*d92cMEBk&bK?c)4cPi*B#nPP`^PEkaWb`IxQqIbbFDcp8HvIK8RlF*b{g^ zBu>47u{qO<c?(FiNtLCz?jUr<IlS2rHkA`0YZ`Id=b6>%aUEi0BLHVg9|etIOZiH^ zZPSq^jg?+!<(_1zrQ-dQ+aEF{(;K{~D@?o2-3mC>Oo&w6OWUfv4nA_}MWaI@ufvHx zS@^5d#}5ov1T0H|PJ0}gU(G$-u<Bmzw~SjF!o7(K+DXumB8hTbcR29Ds04T@a6Gbm zTspuXYWtAL^hn(<61sNshCz+~C2m{!TX)sUy-pu(rK_H)H_T-FPy{JLLUhZuL`08! zskkB2t|!r7dRbRQYWw~|T-ZF8-t%<$f~C&9NS?c?+~sqJO5GVo9ANSQ2GpbxUD(9t zsqmL$&rU4CXRj?UD~yY$kQN#RW>2^}rIF;RR&P33!B3xUQdze=S+0!JAZC=)H@>rb zeCMTc(S(qp?89gW30h}l{rvlL#@#09SZ$D@n<0yuk*d}*qio;#c80ofAvP2D{%m#A zkO$5j$aTHzxoYtwI4yYWNA5u}l)-IW-x1io0kNorKwFiEY3~lk97RjC+9tr6AEId+ zaaIEJWkrQmhK5bfu2hQtyG%`W{0|;%fh>jOfEuWT^|`J@jAk#b&aesFzyZEI(BiXO z-N)6JpEDd8LKh?5QK>e_OJ{FeAKrXBC7_UyxAk!4e1vt*QqY3Sg~t>5W9>|Q)k22B zPaIT^hAMMILvQf3aK3tGJzU!yxC@pD*?Fh+qBY3&6wKhQzmu~|pZmcVDL3__uH5ws zFwk$p2{=pY9j`0qP;KJmT)0$JJN;5oQ&sx|qYj@73@!5+V3OP<b09>yhHES~x|ZIp zV<DyHwOU<0LM(qi86MgbaK)&?<f)(w%G6!#&7_#Rs@bb2yJkc$=w<u(GZTVFe0E|P z4s<fnMV67g@DmPxPND4%(vESi_~6E2(pS2y<le_~wBDQ4qmj`VraAh&-mATHrT9AE zd`9HMJSLkqWAYHKx|OTZxdyDPkh2CW(*B6%&wxU`_>Ejd<7WWpqwEUZLVe?e1h`Jc zR^=M9GJHq^_(0#-qbX491lpGe-6ue;((L@W%;n5;s)4!46ZgmE*W-7}iMNDy2f>a* zja&S?BOH*|?shcA3_E3;kSMoco3R7A6jpJv3s(-^d%`(t-H0>a4CGf`&iCt)W|-+> zV9F~WezE!Djt0h~CU!w(?LLsfeSIc<zVY2{Wno+~Umu-sq>&dn#pFr<sf8CI>q+=t z^APubqz}q*8qIr3<<u0edbd+9B8AwE;beAXg>UtNVdDvb$f+uraRZJ=r1QlkXdbIt z+&E)}Y#bs>b0Iy=S-efO7vT13=@ho=CIbHQrty-4-~gKGGvLr>f~>C@J8`c+?;*>b zg{N_Bf#X7oO~rPFtGSHtEPdbP`t}+NJ-4ZP-Ei9HgLtdn9cM>Q2rjS*h_pznPIOg} z!cRhCP#On#!c<B_B`ht@Lg#yzFN@aJuKJB|M!Xb0`E2#XCGT^t)<Z<boR-W8ePspR zPw$coW3oofX|;>ox#<~NDxO=@BW}92^Q1K=JwNUC9p!jNM#r#^8dB#U6rWrTf>@}D z9hkd{XyxG|NfQ+OczOlZe1*=n8mh0cX0gnM8sv^2(CBw5KZ@RV0tx$P$y(-c1}~dy z<r;z}wygqtj3i;FT$r2Wg@^MzpNTee`erVqC6B0{03K_&pCoD4nEPhb(Pje2l`S42 z;Mv)|lXQZqkXTw}?onzH=RJ{i>xY^ww?ZN>Q3kg@IF&wi5{$1%xANF+oiSP*L-Y?$ zo64wbhG;&S3T}e2H&z9+*S#6Zvl*$k)w|c!aE9>)W%K2u*VVLCsy8KWPxvl4t5LG0 zwLru+&B@0<AUX(AS+{HNta@}**$x}0AK9aDN`5Dz5|tAwVZ3I+A~Z|1<Nf~%C3F@> zXZ^IFH*8P8jUgXX(zmx|muA~K|DEGAU~P@+p~^Yxu`|443Zn-WvXc<cbb40WAAA(+ zO(3C;ULU=B;dWu8^td=dX*DrY!>RVH;D;rqdp%O(=Ekf}5Ycg_R_j2e3j$&k5qF7( zB@eQhYc4}!2Z!o&Q09ZQfz>uUHpVZ({)gVSTGNIoA1^bKt0F0i2uFQ<Qy}xwTxY`| z^L|Z3ltD=C*{qddC1dX)!MQMQ%nim!AsPvz+c~VwZFLR2#70riWW^M(3dKyJ#qDl3 z36(tvz3{*>Ffdq|<$12Ai4RaP?S!b-NJjJK8>o0qAXO^U6w>P^NEC9$g|*%|+n>qA zG4Qqm_l=d1Ok4Q#f?K{mjLoSzN>h^yMpj`!?iI%<|FLR;4aUG{wJ)cbQp8(n4XL?o zrkCp{cNu{`B%RN6bRHl`GW40wn!hM6S%pdiW8Eleqx*dtYDS-%JLKN}Su{-GxI~>D zXsY{yK@5XaV|Vdl^}Q9ppceCi9ubsz^l6Yu-TCL|)F<0DD9N1iGqP39<Kskf{jZDH z8SiB$&<s-?9Fk5e-a-MoVIDJ|-%3>gH$)tzeaRG+dp?1Exo-8aXg4)8Ibmes7-%C; zC{`48L!|NMEZuYuSL3;!5k-pV`j7J>p;f{X*a%SxHXq|4#;E$2Cz5DWwb9I)8&b#2 zW2U5dY{x@oK{7T@&fCH*v&|P2VQi|I!HOcS=GsxFj8@D~v&!f%%+|4NXY|H7@OK25 zYcWqClTJu48oqgaQ&rT~H{oPRDUS;yj^%kyHC6qX*cg+}HvG_vGFwWVJhiA$bX<>^ zg!$`d&hVMzNiHm7O9pjjHeg$wfypeL$CsM(gK17@7;P+3mxV_g4C<2!#Gx6h$3vy@ zGC3coid%x2j0trn&&~U_aQm{dAK8#~!yqH@!P%x9R_i!Z@#gRH!tNSet;K!3I_`mv zp+u{IZ!JvX)nL=;bLOj}=LD7<1NhFz>OU2f+RJk8EwoRERaMBfZ7FV0u+k3y`oX(_ z7}K{9$nkMk=M}dzVcgBps^%~P8~3W)IuI>hca||a)<@~%M3_W1qX3N%pXrCwA7gt2 zB(f}ReQX#{`M>pRuaU-pXKi)rjk5?ck9>1m;VePu4FC0!*fsU!h-5iD>3;t}Z#yU2 zUqd;YrdpU#NF5j>*y&AOGf*MqaE*)LzR*-Dhw)Z3oeY&aYD5@6TKh%r@u=om*zqSb z^jEm3=bJRqrN_)k&s{G)8hl|-7OJEr>Nx5I=f@et9~jgL@d^+svc~f`g}_S<rc8tG zCu43`Z8_Yo2A@`rWwP6stv=2*69%ed#RX^13=K?~iev{X4UTR2-(m8p*aeI>n`ddq z^()~lC~Qa0K26A_IL#|WIsosnsh)zfUO1b=dgI=xTJ}YL!#9k)av!-LRu=`=AV=Sm zP)T;U`w{UAiN`tBK3omp>B^u2k@heir&5nFX{_e+<77u^KX1$MXNtSKdOyd@40jAQ z4-bEAbAMSk+35YM@5s3{T{5vVE8w<%YvXMhs{FNOx?siY=7)4_oD|1RK_XT>qK0F> zSzdA&>LmY-P}&PMWE`rgPkQcy%L;1nTqm_}(Nu{S8v%Vnm>#%aZ@idjZEJ?JZQ+)3 zbMo>Za~2o!botmsR%h^RqOUnU1AgZNMCM77nlg1{XL3PfNSI>15RcXdr_mwLLY=EM zsrS!2b~ebKD)Qk>XlnIEG4gSG*<2zUq7y4Rc9YC3EAx%8=6yjYP)Zi<qtr8kec=Tt z>rp+HvjzO>)HX)BM=b7(9uN;%snJ8_80zev`&eE3biyRN<E4RrQC1KC#p^7Mfs8l< zhR7>is@VdPQ@gGT3vp3`)hwzp@RIke!Ffeb3r_J)8ID<x)1@?X7plL%B+Z}_P{}{a zV!=O9GY}CNCAU1>@W#p1CW#EFsW2IGxWl~pMsY;~wTmf_XY;iVjtMcE?klWh4KGW_ z6_wPk8oYZI+Cy6w9+q*MalWU<UEo4!lyQTm`7+PWl`EQE*ZNy8iD>Z<BjiyAwNTDc z(A&4qw2f68l*PNfAm=T}Bcg?PaHnrezkg+(+auCj+vT%d2hy?53E_#TdXEv>a<Uu9 zMNrM(+k6x)HScLaKWW3?RCoCzZg<X;WODs&0M`}&x1B}i?`8C~4Gk0w11trk4coO^ z&JLvYX&HvtxY&C6ie65&ILOFQrNhg^ZT|RFp$=Cy1-z+xG6nd7?95DEY^3M`=WYKp z7%GPO%1?I(#?}iD*xceD()GPg^hVwp7C|b<sO|tm-O}K;D=0=7h^*6EPhGTBU^V*; z(9G7{-D*tTU6#;vbFHnG)oje0;6Mt{jk5%t2zgEsH+=~H3T6&43Wf&ruivy`%AgFi zeI#4DKrI^`ZzJFmX_u5P$a^_d;G)Dqq+lpB&AAPtG(ZboZB6o}0}5la)tiQ#uMdX5 zoPep-xNCc>_tKGboY%z3<m57HQV{rM&@zGW=~ll7XIe*`&A7hH3=km66x)1poJ25v z>)N1ob`Oz`=UP$^&CV0!hmA*R>YPX>pVVD_6yQ6r*%`=hhn7=~KY-CBmJqSyzYbu` z$!C1ADBiYwfFtP5s7-EzsJQA>LVDdZVGpH;B&z{?tdu|5JdPzs9^+_Qj2E%@yJ=)& z>dEEH<oh^IsQz86Gd&lE{Xy}hv%fsfxt*Dvw8G2AAg$0RW;c_DVe9N?fCr^N6e?Kt z+NOLn<_K75jLgPHMp<K$X8Q4F84v4jH~n}N15@B*=}OI4`PE5Q&`9a>u~|(6W5x5{ zn7e?7(otA9V1}*P`KM#SQw`mk^h}G~6+W-&5eVX(k266AT*3T=29wu_@+IxeYCnY} z-9ym=GNH|(`ogJ9B3258Ynt1hp>(>Yr$z_+vGPY(k_CEnZW8`$NAQ$Wz%>Zp1@4X* zCglCRflvo=Z9O%C6^YeD2g`aLY9S5&RAcf-i5k+zmsR!1xHF%h=Zb=JyS#+S7<w4R z3f!gpc#WeC)pj=^AXcLZW??vhseGeB*H{&IWbyh<A1X%Mh+vUxN3OojL!R+Xn`1pC z#n^v6r^oTZ1GB}V$4{oDF5I^t?2V3*N&$n>9p1eW{gsC=2b7gQFG|n4q3T?G;7GjK zNidi3!zcK(n5gPniny(@1{gK@xZzY~EALhAtdD0=yb|YyKF-m+@xN^n%C@r`zO8|x zkk57+JrFvco?g^xs372|V=GX^s~A07aW`8bmQkmkrpc;yJ~=1GfG@xM7U|tAqR{PA z!DP`)=ZS^KQ`3%cYXy)ciHZAW=&qo))Xwz;@>uaix*wXijf+vtW^>W9A&GB%)a<*e z+CuV*_YLv6@i!Yy1@vxr^_U+?3+SsgIaG0*Kc&Xfb{~%}8p+@bijzv)%#3|(V9h7W zF7cu@;Kgnp*!HpRC2jv(in-4tdj_uTHon)nv(`?hd{c0DUIJddPznwwI!MWR(7Kp& z&Xmh);hLSx`~u);qn|v&KkwONu7~rwdeyVNb4S~IAFMseC=^PdN%jYGz3YYe9M5Z5 zT`QIvr6@oo`%Ai1zIq0ZMgM>7y$4j2O}9T91eM-9NN>_1v`|HQ2kAvRgbpDVkY1!q zCsY9eQF^b^TYyjmqy!OxgrXo)1cS62-|ziS`QPuXb<Vlxf6w{f`>ws7<e9x@=9$^E zCo|de+xyWelq2gXJeRwND_&ywy`+XMpAb|oouWw|Y3|>_73S9FGHj5gZvJ2i1RZZ6 zr@_$j;U`K$K5fTtgE~i`4rj+SwaMG`pCPyJ!ulu4U=0%$)lOr8L`5;P_bV$6Q=S!- zg#RqHUijoHv%^95Lx%^40nhWt2MJIIB)55B6xB+Kjx94QD5ib3P4OkrtD^-_mSj>G z@cg7Q<J{xhgK?qPf|<vrkdgT%Wl*&g+gVy*<^jlBF9Vn5$YZZc9L!!UiV7<3d?&eL zxWiJJg9w%8_T+0vqAb*nnzuw(Eu0T?&jvziHV_U&wxTPZGr7%ggh|;w(?2qIbuGm= zI2+-~5en0@ybtt#go(3tNvrqE^%bt+YrF5a@16Ko0HV!zYB;+b^g{ZydwMY4oW}kR zgoEAcNx*18`CFD{3ev~v8?64HaL;CpwnpfLS+u-yHt!&r>DZZP92hzIw<0}?y*5!~ z-ibm2qnpot+p}`a=Eae7W{#vv#*#`NBk&iRbFaGSB)WXYiDY;LSU(4vDy`nGBAd=> z2k$bdDv2%W@d!0|I^dVj<#4ai7#lcB(7!`b5RoyXMq+}r#XAGmw|E_n4|Oz_v{(G^ zTih9z_`2iy<&C@K(;Le~786Bx6xIxt74(i@Pv41M*&T)r#&tPV?dVA$hl~d>yfC^$ z)`j)^VNW~!l@_KjkX|Cj!LMAKuO+ufxXb}#q2wC4y2P0{jDahV94XjBcR^5!1qqmf z`-p5I#m3;IKdblaf<S7o*uvqMn0KNzzM51)zwlaRUJyN(_;d<E!c0FpuRP~U0+U?Z zR233N+mN(VXeV)Ls}##w%ikxvp*o7}K}FR2C~2$N%vo6U+df2sr*FiV4@&qqnkQ0W zgBqc3*Lx-@29ff*XKe2J-*o^mc8>U4MG0<Gzt^fu?~TpIdusuCI^sl0-k!^P;@pI? zm~KXH^d$KxM@d`04}(4w47m{Y{gpaOqOdOgX>iP0sJ#~5phI_u6x6|5?jiHDuGyb( zYv^l_h5*v|A$!}r|EGE##x>QDo08F6!U~mBamz_jgVoNQ?^h*d$SslPZ5XM~Z57ru zxE(ji4UeW5CvA#;_{dg<H4D>N$kcDp(^1<vju7$1ix>2hpieWJjRL)3f`R4NfS~9O z)?M&hZmGFsf`tA)^fEZ-Cl~~6DinwZ>bQivJx5zeKYl6Z2TZlSEfwJ1>-&J5yl>Ni zSeo<F>xZ8&S|V#M7XI~hslyX9lN0CVr$n?VnCEpbVJ9u5ik<|!*d;j5>I~^)TR6iQ zV7F_boYNO5teJkERA?Ig9M@yS_%LVJ4r__gLm{F<EAQ8|BpgQ1TgHxzJ<i4H$ttL& zvZQEQ5T8rU2i#0#i=L1#I>)qX#HUb<%gi1pPpD=PIeY0rbGEuO^d!DdWT=2$@B)%~ zN6%QZM?uet3ef(<g4HN475M|DDM~?7?jB&H#>j;ts74U%>Xg0CK7ycSPZy6*kRE0> z)+5eIzsr?w-l=t4qCeyrnp#VE@QofH?EVhpt`6^T#SB7F#4AmUE4_PG6Eu>Tv=&_W z<jJqKbZgw=p+5@qc7G2lyaqgJUaZj&OjBso;A))ssU<MReke|t?BKW!VvZsdkQpPV z)|^5Vvki>@*yBT|ORpbJ8F6*g7Rp)6lny~Urh*!`*{5Z^0{SJ6u_#ectY`zYAX)i2 zO@VXVYZ%@7p@ECNiaZZS--v6oqv$40oVX%;VF2qkQNgyH@T0OcMTYnWuuEKv<9)4k zDK)NJIa0tlU;);e=<qui0qt$d&kS=mTklA{V6X>GHmTF{WXI2^pf9s!A7~a44=pt{ z4p}v@bB!@^q&sSH!l48lGDTE(yA#}a82dyqmqzsBI-KH=A?nhWret|_IB5Eb&5oeK zoxHVux^=EF{C{eq<Rk%A@-;vPm@Nl_X5OR(Htw(r)@6uyFDxXdSoaWPiz|3R3x2vx zxsNn5_svX6*nn}-$4xDw=}z$n4XTiOcut8*jz!0m#!uV}bl3o;R@Af(6t>MUG&iMk zv6V18PJhU3kanab5=3}6we!{=V@&sZ2u^~WsG`e8qgmW7M(~rhI6_&OVNb*{Uf;5N z>vJr1bLSfV=r1Mjohv`E@Du-SQuoMTC)<4K4`U5*sFE*JjjeQdQ(wz&xaxQ~Hz-bx zXf{!8aYc%+OejR4qz4Gf^PX;L#mcWYpz!9V<u10uOVpn{#MKqbkbUyoYFjWU|6Ykw zC4SrM;~`h0_D?O2H<Nl2ENf@4gO9Z&qH+weUBZt3l(?#~4$%Rotf?VuF9@BkWxG8_ zJ*UjW_56Eq3iR_`F5OWi-&T%DovnX7_tK*S@_XNp!=okz==+I-P)}IKs;j|1OoC`~ zm5Xg7W-qZVzG4o@=WU$Zd1hkqUrEAc<-9HgqN5x0sTW(>#k;Ihsh_k$G~!Tyh&*!W z5V?L!S7@e(m(TULu}HIC28Nj?KJLSgn4OE`8G}HnX#4BnhKez^Scl`cdwY(FCcb>x z150-7Toa>6L0aCVX?*TH_oD1^P&v`=VnK=4lRL7`DKEYSL#-_JC!r2O-L>8B=~_%5 zIeGHj(GwZkT0n7`O$XIRy1t15DVZcEDQlg(8}kAzr=U9LR+zD5P1XqgmjjhDn3nAq zuJH6*VFh@F5bOXNrpbIq;_mGg32;MKe|ArYy<6U0D1}*+{W%x4L8=LRUH<wKb^1eC zfgW-hBP}SW2{!U9?BY2J$NOLb`mYKhpBrz3rhcpHp1Ny0H_Wmqmpd~Z?B$hrLzCew zm?UWVLZLCwc~)G@xuprF;IHy~2=8x$_7N|!Ml;pHhecm%cC8oMYJ9C$Te>};Eu8$7 z{7V}Deai6p*kKC(W9ek;q+!=-0bVCvlVZ)%su0-i^=t{tn*7bINwM|)&GdS9{0Gx% zG5<Hynx$*?H}kK;e+le=lajDr1K#(ija~!Z&9OfkeJD<+`~0t)zl8ArYfaFneR2)3 z%foL~niI(eT?5pw0f`pS{7cp(eYo5f>w)GqfKKDW74`e}>WNrE&4d3w5_<5P{@3SM zH%wmjGOO`~l~<VkJBapgd91du-QHYJdHQ3X|9=Q^%>Sl;(3%N<r(YKk=G?2i*H-^| zD*NZMmLrhMuv7M4h9c2xK%~a8#YFd#j{=15+zH9?d!7DcmHyir{oj=ws=LZ9lxmyV z({*L{p>@s>_;<HysAKw<qFX)OY3@vPWJTKPSTOg$w=4g)2pa@*9yBxpMLgnPyvPY^ z`mbmxlH+8k_gmT?;tp*48sNZmn0riy;R<ds;kIlzYF#L(?4U=6m$B843n51!MY<P} zmp`%jbf<r%@Tage0tt10Vb{kM#8qkA88%#)x=PCB1J;uadW_yxI+zvX-*XPU1~iah zCeC6nC>5;;h7>!s1JA@tT}sWBjmJ1Ay&A@rT~6*EQ5+HdEIX6=CbQ5)K6VXo(ihTV z;H0I=L?b(c$u8DL0$q}TAa0VI5{#T@wL7>~uPX$$Q4#^~8g}JU2{ai5W9rVBeZuAJ zYu*%{<z5hE+9fh(eD6hR6Kf#v3AQ?pFrZUdj{?3E7w%|ep0oYp&Ey??aY*o;Jui60 zJjf-DJ^1L#j+L963--X}d!xOslxysf(*E#~)m##dx4Y5B<QpdW$ES7(W~<nF1NrxJ zS(080B$q#^ajpS`1`wr53!*&(YAJsY55ky}kt+?#Qp&wEIL{MD&}IrNBKDB!py=@7 zc{m@5V)IA*9%k2YIf!?85lUsCTBvmBXvO^ecMH&$JJ*1Jo@9vOFslfg(8{pEl+gIV zqr~6hQQFc|UU@L;DUdHCIo}oWKAkzONG>K1RxJ3rKz^7GS4>{2z^B?PNiV5^7?Fb? z-X<;d#5%8hVQ{40;c-LasJC>_ZP8g~t{;-A${~(i^(znRFU-X*{E3hB%elKMA_pZg zuyDQ(wgZ^~PTD{RfuwtQTUG&nDEh-K)*Ira%1~0E(55aeL*1Zz3|S@#lTVFjbYM8q zD4g+G=PrA#Jxga~mx~KGQ<aJvM6wPh)j4u&R@9;@RyGP#Z%*vX;(OTTAa!dYYl?>^ z+{#ENNRryCp`_+rat!T{owL&DSXc(bPYR=rh2`udJrcKz){>3}vlW~%gV)7eU|@!Z zCH;q|DCo1CpqA)}ab<#NL!-n|3!!Y$w^fBBPt0l8H#ab)_55F3g=viF+L04s6fWK| zAO>zD28}Tbd(zj<C2dmAVh%bsBFD#HrPkXTk8VT({jDf!9-78L)^^Y8{Ti)1*?gPK z>GT`x@+EXr;Q1GRYfS;vZOqX-{MsnG5;Ar?vq4jMzyxjC?9u|##D-dgv97xA701P| zFJI2WM+kUXs%xvtgpWparo<lMKwgdr#KyjG9re-lc3_jHYJ($KOfFOsS8mO!w{I}p z7D!X-bOkq|4yM<1OD-%v6op&^SOk9Uc#M3lCIZ>p<TZ;CQwF?}2zF0m;<slS?T@-O z-WT^s{DJ8r(mI374-}KSwjJ#;zB>kQkmEp)9SPmhZ9O$4V5U7(%3Pd#KBi>XVrn{v zECTp-j^lj);s)4aU4dzm#%QP9R_>GeLJpUZFHB6Hg~yd(5NE-`?%~OOnAr5Gca-t; zhG7Kvs&^a#HdCJyulDTN%Wu(e>mD!HGYKmt%H$B;4QJJ0tBvt!uSVM1r#`<0*rY+N z-P4OhddjQ~k|o|%$&W{fCM@Mu=0xR7;v^p?b_7LvkKVLT!1wG9&z-21s{9!sZaA07 zRIMZ1Gg5nGiIbl)mzbzSA1Bz~M0{wqh{fByOsc&xD}OjPKFk)Lb57)6wde7jJC&jR zlNZI3b%N^R2{Ol`7@cJ?-1mYt&9#w;e;xSbS6gn<!eY2yd}<sppoT_W^!%f+vQ91_ zp)LQz;HPRXqGujwdv0&pmC|NRmbMyTnK(G(6)$f~MACyOAcLXgMyn7rVA{%qSq9O1 zwV^ZO84bZ;$4a9P&Hg2wr>Z2U9wpti<<*;MQho$+$5t%v9=J^TETs3EOJJuSd`KrX z>!){!fe^p#t#rV|_=Kh7yIUG|!yOXevL%@nk1suacF4-|WX8K=#46fbBw%{p@~QWP zv>pj>=GdbSu{#WA8Nqp}=6xq`CilG^FE8-xBmsUtp9c6w)oAm|Xy<4Lb%TvRkI}}| zX>$0&eE;Z9AMI@B`!kx?LN}vzQ_==a2tLq>9ux9xT+k9sM91jxe|<J_aHW;9J94AC zu9zRQe-~ozV<|p7?0#Q%;Qd^c$lLG9lQtg;4EcP#kG$mHBrPHM-W+_*tJrRT+1iSu zNg%pXD>o7_xzyvO6m^()=*(Afe9JXMV}NYfcOY!|>5!%zH`$FQ;k-PH`wo$F$YsFz zM<zn6l4UBN%Bb*P1L_^Zu(zWn=KAI3>C$cKF{B(-qSj;X9uH|vN3%v|2R-Oj0e$vv z!RhU0M7Cb$8FMB*f{wNAZoAw~k51k%eaPU9Oi!fYZqCGYS6MG!V&wb^3UPRkO3W~m zLCZ-227O1S1#2aJsW1(*sO0B%fnXOOlfU;u{no^hx_H8J!jIg_;{>7`US4>3tI|*K zzjM_B106$7*cy+n0sA_V26uGJr39odUmCunhXyJ<ylIj{EfR0{OzAStcLY44w3c>s zILpDZ0!Ca&3uZ$N6z1hypeTF_KozB^Rx7ULwzl-B$Z7_9?HZ6Pi93wE6AhLiV$(ry zYDO}y3J8uuRikUQ?BRfqhV|;+n8O2ovH62F0f=LsC+|C9=u6l&z*zypM2{=(<~sav zmp7;!<?m>HPPf4#xQMi0P`pq-3K{p|&8=Rs_9ncw{0rX@_fw2cqbXjgj&C5_g|M52 z7DS%@7%t-E0ENg;x^8?-q$k;obR?QyAhWTYVYSiox+q(nZ*Cuc!F0cdctS1iSTG<{ zJNZ7(&Br22f_J^uzb3gs&6LNu)}UHSSX<~_rC$G(t80K`H}<2}rg#N+(osaZzzLI@ z<1GLRe07i8l>W23QpJr9x>JQ48)T8InY0vI(%r|old7XabpqT&i#TJ-pm#(a#I~OK zfHNrkZF&7n|204Zow)b$glZA*YSYHx9FbZp>3!3VGu?f3t(IqVyNMQM39V<8Ec%&* zC>qBEk~hLZui%y<-1bkvQNS(gWVI(Il*%%O%HsjW#cDd5<5octpGP(+cVAH4`(+h} z3BI+2d{2oD?8z#gZhr9I!xO=?`@$qk!BwjqeLO}+JGw|%xHb-D)Lf*yWkbKAh1ovf zF$xv*FzC4kq|jVGl5`nS7@2y&_D=q`^*l*Fy^zb@jKQ&2EJ1lY+xR;DguXenCx`w5 zx0-04R=?cO16V_z%JZ#vKA)0BF~7(Zr@lCxQZsh&r6#vU%T4K!I2%&167>j6YK?t0 z=wReKn-9-e8s+lH$V3{e$cs+P59x8u1-o4IC<<XueL6~LMcC<Z7~P<Fx>1vV>^%IH z-oMRMLf+(^csL(0XJ$KMm^B&KSSryMIVpYjiKUKRf#pI|S|59aB@uqGzEP<SV&7C) z7VJ@IwNys?fgM~3Pf;PhaBFvcTQ<zJEx*h}k@VA0v$FW~0hj#pmYTQ6qi<AFI7#|G zyT>W(L`wP!%wR)iT(>4-`lb@`$|$5}>Tv+lLU?2^i66wKSbxJc>#VhX>fvMageFl% z9EnuIxK|}xk}%yN>6Mt)NSrm{(l|w;XNDH4%;|zq-en!|z#VrF)Ck&q4V*UHDy%Y8 z<PF}39Qm?tDDtAFmD)#*{5^L{ogs%*+R`urkXhI&kYkHbI6zn{TxX|FT)7y#tF)HX zx;)Pe`*}`r`rh<-0s%6)fO*nQfo_;1j~HG7rB@zgU-B!A!!tga4S}UNZk)+;>e85V zl0u+%lgSh-k)VizHB@zWdehz}@^OF1H1XBm{cAv2hru<#zrMzc!Ft+7?5DhvbgN7g zZaNZgm!GgfaYo5D9xC!}RlI#-V0q3oN4a&=z+bJva#KE5X)y_HT`O)%gehV=#X2Y) zoQsx<uQqpvGJn+(@t4g=TYUNWDc*q}esrFDO~9soIV{vO?;LQ~3o>SSJIltzg(zfH z|J}=!BGm1TwsobAcN^3g=6>+w8oKUjinY|`N;yAq$s(r7hISd9L3PMHfD8-qHhTfJ z8?H0|TnafEtq57L5F?pN$ix3yZ{nImZds1T#%EbrhlWk#S7<|i<ls5Nn+SUX1@D)- zn{pRr(gf4m&;!s_)nL+^deMD>T>Opn6w@37)})66VfaHl4{R2M#d0dDz1;+h*C>c2 z=By5;dXh~e+He0Pb~{(u{q9r1@bo9oJq*FR-O33f8!I-;3xST1mJsK@A?y(m;^m>h zca49szxPPYjpUb}baGUSC(U!{u(re#;zGH~RA^;yNUvsWo=m@aGYFart3<pkGBC{s zeO^Rm%gKxY;Wfoo{FdeEx*bPgqOsLNB{JS;POQ8c-SVOAcBTtB8&of|<%FLOl49)% z_H?)A*v7I~ia9(vDl5;dezq;bQA+%82+RHWFvFPUqz33>Mpv*Y4s{genRka0d&rlh zpinz$4Cca<)poG>aSA6IwRB7J@zX(uDd28ORN>F<d4w>u>FXX?W(t_}`{b)AUnxR7 z@zCi($j^(MDaa*VZHR&*i~f&8jLX!NSkg5>)((L}dltYYC-dB~>aFv8#vVI?Mne1= z3Q&vm7T7Y1y4#@XTD5i-M#|ln1y~fOc;mL*+`P-w^a*BjYWhtjI5t0cqPH%&^&WqZ z<(a9BDKJ94{^xp!4;{Aop~2grA17z>pHQen)DuTjt08x(81y+6kp;9N2}P4q=kQ*3 zFzpDkhs)U6yE(YJ0;b1ktT*Hf2I`qe9L>)Lixr?0+p%YOzcyXIW1C#vfgBOb+y)^} zo=*N&KIx5j=)spMHVzI`Bfz9!%OW~yfz*%vZn~8H1=|9PGABPUPN0F`<+s;NF-;I7 zez9!OY9Y2`MK;0y+hF>UupIN%6zn4L=O4x}37c!chbg)r*MQm2S2L@*MRaZaHqR73 zcjRBPJB4Kxoh0x&T?330FM-(?+}8k`^=kmei=*j94*Y6J8U_5rT;u~R05gnmC)@R| z&Hp3X_=ntol=Huy_Y%9ZnCl2TPY;0dVe9DuK&83<s((L$o)_)ray?2$G+pGl9-Me~ zb3Fak_HPv*{ts0AZ`JW%!yl0kvveJ?UK^%f8VqJdv4p*eGXFaz{?pyxIsbugGnZtM zj^D@m&}%^bi@%u%l!j;iZehZ7{;3mKYohvvYw+L|0qe%j=cMVJuzt>qhkq(vD13Qh zM`rIr;H|(f@+aC6gA@{E_{tAQTysB(pM0}<##i3*JpG8iBxb=?jb2@MTBhJPlD#46 zos5qd95pHJttj1a=5&O!1THlDjX8!J)=4#J;T<Xw!;FZYw+C0TF)sveCIx+pX?O+O z-jdp2c*xV*b-y&o;*2AmH(-qXpX%(vVS+o+@=!Y4c!}Y0A7~kx4ntKsY0lcE#Ew?l zK!c?TmJd<Pe|Qo&v2u1<a)}QYX^F19lNoejj)NqPw`Y=1IssjFDLBg}LUT`kSg-{5 z+KR*1&s?3E<9>s;S1-1S?a`Vm-3el&Ssjl8e>>^PXIdZ=TKl;k41H(#=eiI{V9<}j z5e}*KY0P7-K`9prN89P&4i6z>5!=v{^}`-%mpavcQkmih8_IF<?T->~WaOMWt<$4* zk~;tJn8+SE1=ELercELaZgOf>NxbP!aSgVe(T2(|*UO)Uat@ZH)g3%aHJ~eBXqlQ4 zMcytHbP_k3Zyf4=&`BH}D#ktI2Xh@QWsbMb*1%5aDIonZB56xna&pRVSCbulr!p<O zbZC5Be&|#o_b`+*LkMxuqH{IO1yn0=G$&PIi0yEG0AZPEsSU;A&HY)iZWeH^<iixs z)WzK=Sm^v5h`K<d>24|csh8J#<zya-rE35z=1(P=ax0U)tv|1)3vc4R1NA?@jokyr zuhg?JBbnr%KHdWhQW>SCCGZZjvLc1RJef^7@=K&*fx5C|Br*PPG`J(A#q^i@(Hl~R z?9!s+J1)s)8xu+Ie=f3u+i4%>QXF;I23ZzbP#aDYP%MTPQ}(olcoxrr4uf>fe99Xi z_YJEX(9|UYDOJ{`PDW6a`qV1^_FM`3C-Xy&^!yLWTb!-5j7Mz)tC^#s918OA(e*rA zcR$k07pQCF@ob~QesNP4U)s|=9@QosFd9TZL)6qX7!N&G3m9Bb<oI@X-1`NP2h2Lr z5^J5G>Poo~4JI%Uil!;E&gP1;Vv)Kjks~&!^x!4cxOVs(bzY80g4~B-GLCn7tpO;; z^7)xeldo^{XEh(0$$QZD2Z4zo;|WQvtpXnHJm?aY#L)Zq)X<_nLN^-e15H0QXO-gQ zFk08PpH1=qtH(gridm*+xpsrze-;+pgx=vw2GbA{#IxldPmp~JTpQ%K^QJJA{g|#J z#UhEB8GdRl03t!3Y;I5pxegcI2|pu`5oHm)%TSI67TRfkt+Y^zBZ|=yJmVok<RWn5 zoY?dDnpn78oga6jml8h)nke31%;gok7}b7r?)u4OIhUK^SoTG2M_VAzBx33tSoBCN z7E!gwhJFfMq`*4AcqSQ>cvV$%cUCn=j|&jTAP*Ew+HNVj3CVP*syPVxi%$#+ImCEE z7=8KZpIRSL;)t+EdAr?AMQMM3+79EhHXU;eZn>AE)_XcH+nsf=aQMY?++u*^#yBVN zTbI3251vJ5XJn&A)i=2lu1xPchfjFA9_;Y1g>;++Vf&yvSR^AxFdi`>9UPseTcB(S z<a3M3BUK6%ig>2;`UZ#3-gXu&ID^MwS~%6~NEtO;#489b3)gAn;C-PiZ+G<m&)>JR z4{Zv}odk#QsvLE_$CHRX)>@@l3OW*Z9z}gySNLxIln~|=f0){65`Lm(KB7r|YM`i- zlx%v7v!H!w(<c}f@o-%Ky{|o=A<BWUljSEv-{IlP4{hP*ILs>&g^p<<aS%A%)f}t8 zTS_?;RF}oWgP~s#iMdR?qUPsdjy+7d<l&L1Lm2<1Ie&PXUR8+K{0Gj3eCjzy8%O^D zR_<bR|BPm)B|>VMC6yhP@dDPv-b>1O!_ay{v{H3mjZ({3qp5}_y!&6vD3AD$@D)4D z2icmxF34QW7A1CCz7~(UH%!}`G5YgV`-zP%(gt{PcP7}ee?*DXpLall=5f-NT}5B} z0&8B>uScbJ_T8-#b}QLLtYL(Et+z*a!6BbnBr*yOpL{qlBa|)@JkQcj{K3?sBT;TR zN?)>g6v%Ql8R7-w&cnDjjFxf=);G+27O5K=e;!TA)jROyWsN3aHxiwiJP@-9WaWg6 zDVdi4*zB$9a5|S(!cqQys9fw#gHuv4n^e&naS^w;_3X-Q_93(Rp#ctsih_Cylq{rK zKF_#d24u`U-npgtt1I8_o*-Y<>pGMf#Uz|_Ok!aG4sZPR&i$s8&s}ijCuW;;H^*U@ zM>dEP845dOpRmxGXO>$0@jZ2cx3Qhh-(iT9?iw@{#j`+rr^|oR!y0!}MgP1<-kn#z zc=Qcn!^zA1oDS;e(g1(H&4h5x&9<xMH#Uhs@@Vdle)Djx$<D})^k!u;T|7PEe|@#u zi3K(1WHCU7pZWlg?GU2+)#_u8=)OUrpS!o&^At`ba5j?jWSbN;ON3==Yhpq@&s+)S zV<__W@5^bmqRc2Q^svy}W<^N=CWKwL(i;}GnfCW3`S?inES4O+F-VjwKQzqne3-@Q z#p}!^C{f7J<+BeD5LgJ<Yb+iq8$lC)&@=$T0uVQk__R2Pw?%v0oioIHrC^re$SG*% zA}HB2UkuNnz|{+8{Awmgn=4F6QUB=3vbhl<4`gl}y3k^7(gR*>zD`d&=)oOkjO+}i zu9+T=n10z{QA8v<iiT;~WsjxDPcQ-xQq#GeA!E$xs;51_pV)CE6Uj=&9(*%X3Yx<! zSOQI&#^Fld>m)$%73m!!xC{nSc|&K&b@AwU_!B!kDc-(m{DPky$e?l#|2wf*+}OR} zxG^XDGbYYb!M9~t+*n*eti#-(eK7Gsj22hcS#Wx)>J@!%GzGJ7vdm^W@A~1SWANTV zZn`2C|A=r5o;b)}--p?<5G^Y9RGdmtVqc(2ZBpx0mKXRYtl(3m#16*3q=AWJXn}W{ zrNh`;FmL+S?>$gKwWWolkVPP#787UiZALl&C2@ybubK&CJ=_CKd7=B~M%QIa$wCsu z%YrjkM_%@&;4`+Qfh8aXmrCpgA3odDv;KUlPr}^O`4?Ru%5$Y-kZ<yyo=uWO8~_Ix z{ul}I@d23=v7uB<K2f1ES$vw}ef+Gn#(S*hni6F#Q_z)dkbFAVi!_DbJ$sR+CqXv2 z4qe^e-2Z8<M0WFUgOaW#uyQ7ld*4EqfQ&jbIkiAf;B}r>(>^Seh4q%Dg$7HxbNWM4 z_9;zH(GB8j0D?0VsOWGFz)LxN^rs!|O88&y^m;{)98#v3F)I_lz!%n2kKozht)zG- zc)6U<!#3fM*}ej;n;-qZbv!wG_ZQ<YdHjDz9af64v!h@e40?JExQ{8$vl~2}GjGl7 zZl3>EUgs?t<X-hr&vx14FXmqY`F~d#Uf8a9oTALz7`xl&zm16aNCrU?KPK6(IR0kR zcefA!W{UkYlkPvn?E15KVB*IK+f~QYW4gAS?!Pnt=|TUn&VSXUs*f-Jcg~Ii9B+6n zGzq1cd!`yirL(g=wRa6@DcYE`J-tL)MwSHi*!K$Ch7G^R+Ph+$wup{K!V+Iyxhmy| zAQ-NMW6$EQ?0W^lm`>g;hU1%OPD%q4zkRx6OqP0C+E1;y_ZD=JUfE5SA})=#lg{0+ zu^`Fx|2*6Ek4o~!f)vtEgShujb&z}6O-PZyvHxCoUXY;EycTtuoKOau>X`T}@}i+= z-NoLE@s{@9Ht4DsQ?ZuReoWmsvQrl9gNZ$h3GNTIm_BH<aUz=%y9Ok6jEFgFyctrO zfdB50qT%i&Xx}~;_4FIO);Yn#c4w0`a$@-?CF)eN<ux*MMzxUOcA*>B*{kBF!b)q+ zt6--^nSqu!iY0FA(pz<P{G;td)URC0b7S()az>y9PP8ASOfalG7g<>`Rx}aOd35~} z^<&JwFm-jrGabS}$E4{c^KjF62)<DGO>;WF=V5%ZL_p8+`UvyIEN2@>Lc=+H-9f#h z#ebQ)h!L9(vKTAQ2?R2Ko(O?>5dt4xteDfK`g{B>fyHf1Vv^4+umK0e(j&cykMmDS z0NW(#dGAU6kav5V+b=a!Qvcp#yC#DVUR0o79;d@B`6wu<l$QQm(q&sYZ<!ATx*r`1 zt!n}tly4lzyh4FjH81h}ZnS70xMRN1Hdrc@D5q;P2U|i0Z?q>@%7+wbCABhWy=r1v zr160xf8-z>V6*j|rCj819nu4xVt7J|^cOTDzwPL~1x04?BG*$VUt*mV$019$d;#%` zqU~8Dm|PljQHDE<yHW`;FrB7GE|-J&en6y7`MT>;d=&WII^2{fiopraLs-nDet4yz zuy+inU$?pj5Lr-=+@@3f?wnTCHxaExKq#yr_<?Fg1K!?YUVZn_#KgcIOix@-Rs!Jw zhntBTqm<-3VQiBHTSxnn3f)OmTR-D+4S__%|FRAOlMnem)@l^j0C2{$uPO1jH06hk zv>Mipb3GtbtA_cS#`avHc;>dClpYk=s7L7VfC?R_HQ!6f2Vf5PVH3PNaEJWpvWTjn z?S{2c#zW6<?TLE_DfkDblMFvL*BtHFR2}gPL%y@fCc7=&-voSA=5`{>*gF_?o!Z^! zaFN*)AdF1FTK(hBHXiTQY$6$&4lKtca(P?IW%K$=rpE<*ay{suH-&4jh()g$=jywv z-NorA&XJ<^{!Xo!$2a;|iAZ)xmq`*%DBG@^e^Z1;e20>d(XMIZ*KC(V&vZgs($JA1 z1Ifx`D%9SO5j|nT-i_E<u?)rRI3^Eay^vmFK|q1ukBfUB6ZUeX4>}}aEk<!64=ZdE z{O()>;In~ls`Jc3$)07{P9<ru`W&YeX~}W&DuLgKO+fcCkjD;dJ88ksjCKawhQT!A zBL(kdFqgzXUysY1hA(%<Y#9YSmoPF~`t{zlu`bvA9)g7i1dF9m*raHFE_K7y?zTkV zl7o4$%&%AV)-u?fGyg_T4~%lmtwHUc4GrV_1EyiO6$iRF9Yo^E5k^&!*8tQPV73Z_ zqdo(W_<qf$Dh)!(B5Z(^U+0x`^s;f5#i@54stl$`kUk!sYTqw(JDJuGLPh+8A!!EB zDWKq6P=i8^vSfNo23z|K9`OLUsf4G8N5AAo5UI#RJn=(uiEdP~AUd^w15TcONq_b= zff*B-H`RSI+z#HV)HRhFCNdm(PbsX&bR&a{zN#i94HS_E5eFvuHdgVp2CFI5m}I4^ z!e5xO(+o4kV6{wv=Cbg1pT4-IBeAaP%p}A67^Q>g&rqtkd+2s|hM~A2UC1rSz#yTc zD@UcKfVz^T<O3@`F5TK1o{<nyrMT&hi~Eug=j;zD7=7K%na0Q(Ow&nz`a&ZIz6kDN z{3kppjk~U?k7cgXnpQ8xXF(a<nD;{}l|ApB*~&>=#@`OIthw!mg?HS#1VtrTQ#tDe z-|`bUWP3DfL?9YNs)R-F__LC6-M-VrKaV{wgD_`AY*xK})zpzTNjey1hl9I4{u;IY zsq;yU$c<he+VR9n8P0kNX$g%72x6BP@M?m}!dcO<Zyj!|=U#RLy@?+!0VuWB4Ok1O zGDyXbR9W64L+UZ_JVo(%55rSepjLbrU8<}5#-trfeG7fMI=<EmVH}6nx58yTukQN^ z92Glvw7zb5TST5~IapgA>p-!581(FoN~Fd*(w89<B)A)2EoC@%CLH#F6HRt3cJcdH zKYMTPglfSY&#Cw=`j!q{squ`ltfK^&(wgw0N5U;jZCZPbi)`;x9b@ana-*MSuwcA) zVwQoB6fpnUgj1SjYgIwA=Xf<LIC?J+Z*KW;)sS6kXaUl5|A`)MdaTc#<SN-XQl3!@ zWu+7o(Soh*mm3N;o`UDvg*He$S)Bdsy{*YQbmOQ9QE?<$Q##mXVz71hBwy|H@vrmw zG0F_D;3ogRir0}{D#{{B3lEThRjKb!Hx_;%aaIxi33tt|0UxU#6VqVUP7X5QWg8z< z^#pCKj9%ntny6^o%6ub{&Y_v8K-=Vv9gUtjr)wM-?AtGLTx~SjxkC{d_wJY~0YeIH z#18uHlF94{<e%vasjAKnJLTN5_t9888~tGu-R>ZmL+D_1m<SXCh2v$9kHSJ#TyjCS zyx8OKZW!|;*DdBF7E|)1^(=3?yfgtm88pdy3Ka8`_xZd?s&CUrhUXg@RAg*5GdZOh z-&p5=W?i@;9&7=#R!k7qhBIW@2}cwC@&)B3TdizM54MYPP`lsw1EJ33JGVRSn)0Q( zAw_#rnmyBD?S6Gyc|q?Oil%{0m?vN;@bX>O2l`~PM1RL4`-?K7RK0lEqZtj!Zm$O+ zB^h%2r4ciqkm3y|p5GX?*u4#nE(>(HmRbn)#U!E*_Eos-!0AeKXFkL{PyOTHOmmEg zO}i~F69C6TckB$fo*xjojgm%J?2N!R-pWGSzq2Lu6vxM$D>TDcST7M4@omXPFY{~~ zAH09ag7V;tsE^8*lC#y<McW}|J+-)id#64Ap)=s@fr4PjVy8aEDCe`1=?=elohMe- zck@TwU)t~loM;H}%0tgZ(rPJw@$%X*ofq8vyKGCFByZCfDswtNf5CJ$3(jA;LE{(5 z#gl#kYS-8)c<JZ6??)%VVR=RZbKa!ye{7?Cd~|qMyTHOruFFeU%*pajJeA7nQ}Z}X z)`~>yyKV2ALTSn32|GbJ)nf_$W>+PIn?=<M4@Sm>ls&(zS8@G(vX@wON}8!xk+nvA zuDNzgSPo2I1Ji7OdM@*Gmt9yxV6$Ch{2MYOWv=_HRV>=!laDI<@UV`3U7kg|7b9k3 z7Val!X-TYyZr%5qo4iZ*@-%Q_0;Q^j^$oU2Q#zOBB0GH^I~W&QljSMjWJ!A_Y`Y;d z>2(ZcortasYZaOcYbs2*n#NtTY1A0P8I*Bi*mMxK;1<B|r-%8GqUY0<N4H?s{tcYv zFdxRfG4N%TNjrEu-o~Xt3O1mDdy`&mNEI8#!B$NSvQgeXAg*RXK}W|O@%)H&;e~33 zRtPgg;a2Amd-32k;E&%pE(RZ-MB#HiuMQX8BEt69$*WD2&~xYz+r43w-&itxr=lWt zi(1cpF`C4{EEu19X-D!ZF41;vFmv2p_H%8HfFg^fuecL7d~U<2lAcQUbLli?n&GJ1 z=fEi@p;~`m-p<M9*V6goASC>SoqJJHtx3`8={znr$YbKYu#ZlP%oY{6>$fvl$+@cZ z)o@d~D+Lj}<5L#>BvqBkwqYJ_V&UWkluL8FdU3Tkf6;tJv93sJkGhSWtKp;{S#3-! zF@OdAW)IcH!Cfpyy7U|V6d-SJb#=ZQTGPmNW2_sr#^zCQwp|6q(e1OGKX&Gb{(XVU z7vd`QyvRY|X8x5K*9oTLO<7wlUDCsw3R(raoiR9``GwLdCVpAW;Izd)9O~1JtbVtb z?2eFHJ$$KceYgEJQ&;t1+Mn~3M{lQxQZEa~&4XxztEoEhM|8N9z>Qg}aKYZ>{o(XM zW%q=92feY5wVQO@1zkN?wKJI=RQbyhp04t15fD2v;zlgA;F7)hMS0ho)^!sumq;r; z=2P$_9dXmG+VvquucXX@GH2<6C#Tg8BKp8Mvju%2Fm0;~_RW+!6W?(fGud||+iDY^ zFD>*$rJD4-`jPFG9WmGFUW{6psOx1$2G%UW-VlZRg8XhB#*h)BS|Rf`_|9GB`r<n0 zCtVw>Jqvx75moJVQL!J*5z3?dc80%nT6OxqASK>wU#2VU#vk!K$dcksVFf#8M=jBD zQu;X1RM0sOn07~yTOP4JW45kvHn{cfW$R6U&tE{yPDI3b&2F`Tn*&|qig|>27><qh z@<`{6<GiX>nU7+QW$06X(_>q-`dHt7`FDd5U-h&5F>jL&h`co9It<wAMA<y5%!N8? z8uDHaK!Xg0yx;}o!UF5-Fw<!p?W4E%sy)5Fyg)Ut6akf;1fdp8g29zroddFhL}R{R z3DJ`9`>J-}^2v`jy{Y|=48JjgSgDiJGCm#(Yl?nv>*{<JQ$+ove)aI<@~f!syr0Q4 zrs;QRB)k2(tk4YYk5f&vW!T0>pZ}yH|HyPt2vozh?yqqO{N_Tta1BT`9@Jgd)~sot z{3MEF-5)p<{-&h{Pv_YV#^|ID<w{Dj#FZg5sSa`gPmF{V4S5PW)o<42r}z7S(hmeG z4g%$?(xUw~7R;b>&vrEy(EM@<>oW68#<fg-LZ+oFV9xITg2WzP3G_VdF^a@a%hyJP zzLPNYPS8W^{ToX+445i5mC5fQMYDYERhbhux|aEIG)A!hQDq)~rbpjPLNtAU>rwHh zs$_k!Wxi)kD4Yw@S!hCm^C^SC>=aLV)W>t86on!_uN52ZXJ|8vg@{&`-6$Ve?et-? ze8|dFUxRniIqKy{PLe#r8d%Y?36fp-GGE&)AQ?V7`hwPcNo%;8V2p}(nVo_8q>KhG zEIKycB3yK1g!@sf(Z@Jp(va88lD8sxyzr(O-L!M!)S74mYqsO^Im%<k`?S6YsHb4h zfRolTWG)BUG6%lh?M_NnC0u=#=@e~P2FWYvN(=AI@zf|dV;BM#am#LfzeOt-D_SV+ zoioNWwNP%QdyAVp%hNNyR(^|s;X$)L`>$3b*1=m@Txh$GeLfM<sbA$FxB6!-XVvuW zIUM^8*5Ba8)l*z}-CItqr_`6l_bP2U9XR?a%fg-;gkPoEJ<Bn`A1datl?6JESEA#r zuyZog)A9836qMPtMkg~01Sn6SGDq9vW}lF^nl3fN{MmhJs9_Au*)r*eFi=-sYBhSs z`6*q!vu{ZETj3jo@3EUj=+}#jmZv6dKW64_ZjQ(d>rTp4C2P>YIcr|_y79!gyse{4 zd^kU8pg>b5{}c;HxKFZSKF_vl0Tz0@F@Fj{PENld&kx_EJ-P5rkHBF-EmEIKSeCT9 zkdah4Hx;OCqz4w!Az=!xtrlhL3p}#JUDIhv5aqs``2n8=sPD6i1qayjIs(`Wi2`u$ zx61*n`v_^q3l5yt7Mv6#7bR&+>8rnBTFw+vbX-rFC`!omBrbemizMj*AE+IY+)N87 z_W(A28n^~SU%ZNe^2z)7pnwGq%f-V`Jpn;ZbkasdEa0*C+x0fKzO{Ytue<GtinWae ziL%3vFH`NrhSgwZyY$@?4n^$g36OPyZWD`;ns|Q%e7l(;3NHFOxXPe9Wl5Q;u`iG` z%1dY~Tyw|U1vGsPm^8JNZLUs5IwJ+s!^B$aymhla9|ZS);R$mY>R|gIPXFa|5pT!m ziH(9x4=EPpH6S1QD~**cEH~v3tIPAk0Bj5~R!l2OcuKT}+v`p0>4nP0M3|^uw#bEG zZFAqZIiNNH=EUdF>`$VzS6ia+rTNd256y4##a^xuu}i(S_@qaU7ZHD$e)>c%9{z0$ zZPR=B=uf+W(r+8l-vvVVN7GpM9mJe2Y?v<V9(9~KrOhbRxpLEn{RHdK!h{5^ESekK z9cPDMC;n%XABHOujcLn;bggn)#5^4Tm*hO-JmYWHf427jCoTJ{?Ee{Jw;{p8+|rG0 zCb5owC+Y7;oEY+V7H8^8?bLf-gfRY+{Nedm@-J!p_b3C!olEZcnP1N?N>L<8VVk{o zSSayu!|`^kN)b#1k?}X<yIZfY!NonHoBa?ei?HXu8SUM>OxZ4bQ06VAD-hW+#l=jh zP0>ZZhtM6C2`tzYnsmX3nXf_Tx&=oi72P|`vpeRm)Q~ZD&Ga}XN(i*S1}p@sMHDwS zMD|02Rc8jN7nvj5SB60m@nd*n{eM)@kdpSziS1klEuI*^8cAua9qm?g7YCO(g|_(s z&#iRuDHbyCC#7g(+$Q1EbmhIN$nP2{ANI95)2HcCqe8R1*Tfbe9xrVoRih)tsd14# zhOGh>?te91hg+BP1-tbeKjy-M;to10Sl(5YpO(^a4U;NzricN>@ikc-%7cMnXxxjT zFbTVC-fI8{_nnIR4TqgCtX8wtUY{qtkCpPhJ-dJ42=;NNtdJ0G<(fg=8CY4~)Sa7N zJWC0ecwD+DK7jo3;Z!+IK~I4`{l>WfpGUxE6L<2vl(~D}5so>MzO)efx<@VY&t78^ z5UF!1c4_6*%ZduNOT7I03L1hG76ao6M9Kt{E<zUN5#ACjzLK^dp1hM^Kqm!-T{TQx z171Hsy+7P*r|V4{gg1dwilVQo#6^x(g#{i-a%aX&57m)$RW=E}9s)jGNu=}_oNKRW zxH)Ox(#EDL&Cl|{cRlj%Zosgu1!(a@YUC&(1(}8kK6$Q>o}^LBalWycDEiRghI%FH zNev8e_iHR)MUMU2p$<W3<bnyDd*3r5hg85;2QGY-mW57<C^Aqn#*=A&d=t1!DsQE& zJkIDe9aEKTEoD(v;pSW~72rB*qg(OJ2^uyPdkv^EYT`Mp0%*K>-7;B>ocvZ5i`M6o zyUPF_Id&4?C`cz&{K(Kml4e!_Kxvy$=QO38Pm%|#A`jROAV<y}AwJGjvHgmw>0dJ> zWA0B_%tDsOtl7<)=R2x~U)txEUfmH9d{bS~)FRAd@dB<w>#%{Qaa?R?>E$4O6Rd7Y zr)A>u=#7bnnLzu8Q-<POxO*Ec&onFHJ%zWA!aM?<#p&jZO!~<>ku%|6zx!8KmsD}U zfC+7rN|`d%*MO1R*n_CwbKy$WGl-pI$k6EFPf<<Ulyx(UqW)}JueZcjonQ8AG~;Kq z-}YKp*m?A(7#(ctJ<57Cr%umH6K^9F^-zSg?vaf?$nJ?;uJ)E(=E`OkXv({9DiFLI zEv)?OCgE1#^h+PAutwW<gRMy$@Q?hH;ogPD^J{?BR@iKXnd!s8WIx#aQ}l!~`k-jO zT<yv&B^KFs`Yn4fA+(dD_0nyAyw|Qq9rR)=+-1>>hTKwrpvF5-PeNs&qsr!DQNKSz zHUOM=3oNrPF3kGtgByQwJpT@=!l1lx3O|bKeAxwBu(b?dSTIu~qk`!>-=%MG;4gT< zhN7*@>v1UE5DYH<G(VzaLt|1WPO7se|6o+r2tK7G&wEuxEN&p-2NwfC+!%<-k3E^S zk`Rw=2*MpVIyG>@%)_g;Vk~&l8BCQfn>g217j;I2)?@Hp3*9zi<5ff#V(;nBAed)0 zcsWL#s$a#}`WBq$V6a<XS4%dfCc$j{OVzTyZQ&{CgyPAAZ81dGT{=?F+?&<YOblU! zK#~n&Xl=<9?$yDwMyMqsxM%{E)w&e))@lbcKanm6f)jwRWRxZ}j@8cm!;S)EurYC1 z$+f=ZvFl_V6>adwe1C4ol`7`Xe(NYCQj^W(=kY?rfvmnIv*GCYSL=d#8i_OV<OZkI znrem7FN9`vcisaiY*vCwW5$Q!uX#LaxZ%x{@(GQoV(##-u&*AuE(mWu<_(Ah>o2%4 zOJKfvPOLy036(>Pafjec&s`a}vSD}NYwTPNmRS@(W!zA~n6iF@4_FD-jy0v%_*@Ph zCYmjLuUCixGS?EIT*=zI3+JrGt2%(OR5-a#V>X((#JV=m9=O&RBZC}jxXq6kA_d3% zrYr$R((HqQwck$T2IRO??>Dyp#PN(lIB(LZs4yE8!l})ot>#wK%o}p11+d|NQw3@e zbz;NfwwAZ#HyMvmpWejSU7B^lZ#dtS>O+!=JC@zEnIKn>4^PbGc*P^2a_s2!8gzT2 zv&&Um>A7Bqr16#o6rq+Poat6Wk}%ktvhjZP!a(Rng%tN%{QkG@rMKILHtyv-Eyi{| zjSLzAHj(7j<Ki?B=zbs-zmH2i`bQo-Lni!)K67z)LCOtEClv0^^kFi(y(uL6$<G61 zN=$pGX)N)mpil?(o4y%`Nq7yXr_y2nm7`J~c3HXxkQ0p8Jda34VP-#tF<Mu2gbX!w z<XjeKn?=Cm)`a`!{8zA<D1M(D|DLdzPS!2Xvsh@zL#9Hw`d-WDjTM;>aNX~@WpZ$m z(3yo9820*2e|`TYhyNq=0F(cdEA2>b{_~|voTuN!v#=!9%Zacg->hkPd1$~}A0Ahh zF?fMHkop=h##pwYQqbO;sSr2}6uEOk+khJTEXU`=l|m`G7wijV;dUSSb&^;oA&A1e zpofp1Hl)02PnI7=bL*ug9WzI0(&`S~Ly?>0B;0VX!AtSlEdkqMgF!!UY2iU4U?fUJ z&B^lJDNd-MoNGXK{7u|4{=UdF)2<;|&G@z(%P`$L#`j&`<fAy_D3|Q`T4*Sjrv=3Z z2eI%979}d7$rIt_g35|qX5{*&v>;+@{gk+nN7bB)L(G}&+4`QHo|7Q6e@#-QGzgXu z=9fg#8-<?E^x_~;&(q{dmPT-LCM(`iq@NnDQGN`S%-D{FtuzTYqnyK~2pwM)8nsWB zz3)c|mxMB3DFa$*3~gQ*!x2qR<^2~HX)zE{(+_m+QcjWjtV)T$rhj+f7egP*a0ash zUrXRLjKzi82iEE`Y5;=)`s#|MJR4pB&ggg0!9F%m26{TmDHJr=+h9wsJ$v{r=t){( zEk8{zxGnL~)^U=i?)>5nv)S>P_U@L5^6|U(rE-FTh;vK}y)fNaL(aOhjrQ#kc$JM} zVoE>29+^WSSST<hE4I0o1<|?V!~s>*msy!qd5q^CMZx8p4lF#x_zA_v8wfr%R3BFt zS2XflFrxr|SIJ%J(dhYVww?A)q_iZcqoD3bO}u!Z^?==%ftLkS!5-P?j$a_Yv){8> zniCoaAGN=!ktoP822-TIly`;ji2d~2Tx>!}b|5o<b`>%+&mDux4r-no%ZY6KB=&!M zHP?ob?1+j+)W_jWGgU`E3v{b|DIMqg^-zxBIr+eiml?@g;#u+;;}!hHq-0N<TAK1E z;Ax!R6+XBzOrZ)w^3YLkhm@fh%G2uKZ@LPHv%Yx#Nx1mU^yp2FP!qV+kFKp07G~Qm z4PuF517`9J(G@r1IN96h;_wThw{3NKy^?0BIKx%weuIwYkXN-uN<!RSS!&;g1|d{s zWAsg(b&<W2S(0=#`?ZfB77rih*=WfG`>#OuCiuR7DUBQgm7%$ly{nH?AdU=@G`NFf z)heJhw3kKfh47j=T?6qA!a!3Pd%v2SV3)@Sws)xv)EB`-x&ilBIoNfj<PypJ6&+0> zjR5DH>N=RLg6@vGeRY0{{@WQAG0^_e`6uit8g7D>aldlD662q03=}_Msq=+`b2bt> zm#ZsB7OcHD=Iaq@JHj!P;x}Y(A2K5SP1Gqj#&eQpw_4sboJzSuf}|UUtX0&gA+Bw= zXKZfbnTcDO7%xsqTF?}~ODPN_N}|x`I!X<k+K5d*;%ylA8&Un*fhg`yAkgh-#c4U5 zH-j|oR1HD5VWg}QDd{SV0))9GiO$Ty_V0_X1QqA^-zK!Nu6HOwSy2rC_m5FeoA2++ zUH+oKB=A2|0y${k)hkP^;>wG)&CF_Uyq^9g{Rr_F{Uw3_krEgyoBF)7C*`(sdJW(! z>PRUx_`ygVmcS7z2f1hr-BJt;6PCsZRhs@6k;#@qZxDJ22>#{v@=waee&@R7x??X_ zhK9>f!)t&T>(SVG&e`Tg`)46ALt8VU6Rti=n&j<pYv}#<2o=cA{>uYuPQ9QUu6hJs zU4rk&eoJRn(n3->&0T~PZnCoOR~@a0=_6IZvHu1BsX_`A8@p3vn93gOQjXv;`y*WJ z--5;dt6+7|PciT>|BCZ($6jky@P7KHG$Eq;M_Lhni5JNTG}n3jA7rQ0EF4Kop#wAc zU~P*kSj!xOci(9{`v?`>3ocs5zSSb^TPO_~F6~AnRRbCF^BwN=`*Hy_u)y1mcYCHV zd&J2E9hwHX5syB@+eNp`9A`g#Zu;67p4lnVWGKKus+;)IWKK<f7@rq;X=p#9cMafP zn^}z5f1FUYhtZK`Cvj4o!W{Z(zE?v@0YAHDEA`o!G2~HS<R?<828-H<HRZihc3w2R z%ron}yERR<0X!n$PQ$Fp+kbj*wiK@C-V~!9!vM~caZKDhO~qjl`po-(vG?9lQ7zlP zaFa7g&N)MqQzOtwj*5unoU_toBs7w9lqiCt1SQjgfGD|}*r-Sb2~AKyBnT23d`r*X z`<{Exx%a;Jz46}n{y3w?=uxYBtqQYN&000XZ>~UI5VUgP9s85y$!$2H5~dAYZ3s9* zspt|cddsr+V?K{3xiW&DfjsQPh9MdvYQ9OzQLQC*P~9FflnCc=EN<&`de)^S|FxoJ zHizpsIY%II-zihf;QIsK(d5sJW*7D3#(9chULN9g7}Ai7NAHM47a|#n=-yQzluHS2 zdeG9V9s3jb;3yX=*4YZhLH)YcKf|_VLvOiH0nigF0N#M=g283^*d7oZ?fr`0WwYvO z+jwQ9aUqf<7cgrBY*WF%UUK`9^n;6sn7b@Z@y*&NpH4mn8ZqvS11@{b+EBE8cAJ16 zN~mEXO#>Uej+VX=rjl`Klp}K-&Y(w>@)1vsApIwZa-3r@-Ys{h>*(owi2F|v_nF@4 z`sz-oMdzi^YU5328{AYr%+543=gu~tb537Uy~m><^m>e7e0OwfnqF9`v+obe(K0Vs zLCF+g!c{H~m4IGSXBYLZ2W;&^2w+V)RI)EAr?&Y?+d>leRg8dl#r=naRLS+>H<{pp zoex^acc>C)?RdXgiTbyZiKPv7Hm`9QeC3LD)#&@eq$J+XXaE4&RDRw|b5|A_XF6B9 z++;UDfgh-R*f=dyE*%LGJ{$+J@&_bypc$<bF7n>Y(oCiVZ}MGFxOfB)=zjaIG8_B2 zRVnS@?6WY;#1Acq+{G`BQaQFkNsi=0e=rX$zQT49Vfvq)e>;t<uV!h+11rGjS=&k) zTzorlB`E`?unm{lm#ap@<9o6Ds{nQe;7hkOIs_QrBmoZEMhmEMiFM>@XoFB$CcS{k zX(B<X52J$kM&=u50@k$Btz8`II?mF4HCDb=OuhvsJA96}45r@1%;(P$OfZIj->K%2 z$=g!W`9|pb(7n)zEBjGu#bn9_rIte;zAGs=i8f#6gODm0-ynqgRg<?w=9NG0aiRN_ z&r@Q_8*pn1892F1Klv+m(fVBMw`U3vW$T%}dlWMK;#w+05JRxmM~=uU>h*)0S1nxK zWmlpH4|;f>KJb5D2IJhL0^iz)8s8e7Q7Jjkv?QSmiFo=@%?;06)Hlo*R${0h`uR@s z)26gR{*4HsAq&S4?8h1dN&V=Ifc~BG6a&#uVb<O#J)BO}q8?4zo&rumOz%N<ZC~Sh z*tlrqV!-M66(z|WxcCN*{e}?tT4!s=Tr|sPh`DIP<D?D7zEiPCZq%r)Js$`Nk@fmi zrTPb>E1L?D0{*>{+Y3sMZkiIw%Cec{Zp58#78ESqTySC*{RvwCtjfVJxC9@fyJY~J zI`1fXl2a8O!{_D7KwS`#b@=mF8}RR$>opBktW`M;<teOAPgCB4)GNkHW;_(++|X?& zYC|NIxi(rs3pvSRK^_x1270d&>OLB0U5UBkGLwL_oz_qji)V4eh9T>^GsQbv12*G> zd;(@(O1bBzd2x+CmL*a}sge;nQD*Qs&P*BriE+KMDyP>-Vez^>x0r(|AF*OOEJSvO z@!gXs6S$n<ARzMk+ZR+<0qf}%{~BFkcEj=Yt~@JfCSCifXgjdla0#!~E2gjaD@JF= zhlqF8QpXTs;ltU0B?KF|7Z9LbRXf>x4n4oTp?Ef!veSIgJ(HI&Qz~QmW%)ZT=K{Td z*T?xo)ia%g4^g$GYxcE;(Gfwi=_S>~F&m9fG%;ygq_!n3!QBtR<=1ZRG8H|JSenDF z)IC{T8&TZ6%kd(LFGr7kU67Rn!YlAGF_)Vtm`~|JHrr3ocSU?Z8e(~$Q$8#pb|+S4 z`9=6ad9I-=t5I4x+_=PjCouQI<1yMD3toyx<q-*&UPgdpfzDrB?dagApP(<(-_IA} z0F-XwhWq=a<=cNF+8U;;HmSbLRL=Z>RxS35>>af`w*!W#_QR@sH>E?y6#$dMFPy_T z*gzW!(adH{#aePR`=AldV@tQKMx4r&`tl9Ql|uE$FCRCIR1&LiuL%|H90s6lXw}DJ zyTdphKXk{T2PF)+`pCBQMzeBks5JQGe-CELFd%yvTvo{h)l(H!?WIB{>-|_dn6O#4 zH`ecHh~{C=-coZ!$_p;oXw}SbU;e}Nt*0ovGlwrJJ-SRkk@mq{G~}pq8ot7k{Ea7I z^9Z!rlO_gl((z{tGaq~5&x(lLm&=Oy_HV4C{14VKruQFM2WzGcutPX=WMkG+p%#H* zC#%8%39qR#bPqpc`$R1hH@HcQiXtq$5hV)03x8;dvL>q5>(sE6qLA386J$V{p~Ed( z0p7lulf``KuV{j!mcM{BAWS81YLUsuUv3S6B}Vw;oCMJ@vfrU5f8E%%@(WP|3HwrJ z_zOitvMFs7TKIjup&T%3I&)`22YksiJUatpAmf$3wk9Q+U#BK-)aDREQmWK$^C$KJ zph90toE66_g}0GHWJPYKvU@b(P1a(o*mwb}h6Gp%+y(>rel+qTvWltqca_UpCQn|_ z^sNBc8Q;-B?8FI9D#J5(Rp93yR&p8u)KFbZLL>lCl5O9!m&SpW{DWrmon;iYJ4L?o zhRr?QZyOknb|iI1Uve%4aOe4Z?#qQW6NXReV4K`OXbWEa5LeYde+{|sNFO1Q5*o4_ z_OdG1YQOy=N=!=4L69ff$tQH05yiXF{LXT~f=alKO1{%=4c<aEt!Z<3Zl5V`G9;sB zZx5E-4@aA~e#zaB{VXoDXD_{uc*g`*k1UsTdhta}iXc<eZ>6>BE1wXrd|_(<)L0I$ zXWKvg_@jBekAmok1SHQiHJNm(xJ|Nc6I#<lcg2d9QQ>h*eC(37pVf1b!PaVH^f0L! zarE~4otj6?2@gvlT<Y--C-p+MZs($&-lCq;D)Dbq-ud#hl`+_aDv|iqRn*o#8$4z> z6IFYevI;ogEbs8I5sXr|;P(uRjm6gCyV=cXp|(eTg*21(`_yC&@V=x)KGSqcNYYy- zoRGggeM>(+fRoSf%9S1s8+fybe=#ScWE@3T)U#eR>9BXlyvOyB<3O+BIsLg|8$izt zJ~_#kK7fxHSG@+W;&c)I``R_eE2WO}!2B<%p{3YnL604I<yTa0Hod33ErCYW40dLa z6NLxkB+cpUpR*pp^r2uy@X<!6WIN=kTz82oHk*VzyUnH8zU)i6>3^0AOE(Y`nl=CP z3EZbTr7k#M;@Cy3>yp;T_W=t8E~2TE7LyjEsrz>cez{f(ft7LoJC-%X+G)4&eEtjX zTMO7F*3})_j=t%ZPeRUh6Z(N<^q#n)Vdu?40)c{Pnh_D=Wv)-xO9BKJq(2~%{ck;f zY4bWSR_aL7e2HX0Q9!dPw`}%y!FAIsoF2g-CU$XxgzgjOq!s)x>n(LzT`vPP<YyF; zBLmD+?1b~}4D<rB)9gLu^D0*}c_J$~NS>Lw-0*e6QNEW#z2l2>395_XNv~X=>=|wc zsOoTy3DUJ93%(<=t2pqrhA)25^IBU~G%h7+A?XjD<PNrIDUNL(oQA67Y>B}bhw6Fy zqARMI6a7QFvC6lIrJ^)x3AATw2k&E}N(J;anOC#aGHz(nzI`qE$$^Y3L7qvHpp1h~ z&@5m0``4P19uP6}E7Co2;m3rqB2!xvA5l}6z>Vonb<y&A%xOuxZJEuckUtlSPMUm@ z8b8q7ST!RXU(&|OoSJCwDVO=0n&fTY<TW*{FdL~y&+EFn@2x?B%6@(Wu^`L+6}%u% zr?MM!L!(zf_aFL!%&)NBq8Ox%m2-?O{(@oK7swx`CKE%x-TeS*zv4!09r|pobNYa{ zqxIwZ%ejsk>E=M?jDDvII!D!RKu!5~CoOT+Ed&L?0RdQNsb5Sj<eYWo;L-TO)-0$7 zFyW(8eriOwubN9Dx-WZd#%D>lD)<wG6Z`i^nzmnnU_Jn_7p+Oag&cx&daUjzNcShG z-|w%60Ejx{$KxmEf|ysTzmGx*+Gkf4*}!c8w%r%t4EV3~FADs>NC8>T#S8X)4c4c3 z50cLdFSXe=E*2-m{+0ekf&V8dAgIUt_Qx+7+D{PEl4x0`A%G>{;V?0jY4$zEmZw0s z;)8JDKV)2ZV3{^Y?zWcGW<isWg8r+_4GuTVv}!xm&i*(J31Ga9nOg^ZTzR@K8m%Uo zZ@I)UUect}M#_jT{7^dk36fUr%AA$kz5BhWEnG%G6?U9^A(UqUU2$UaI%xTBZjwyz zc>nO;^fV{<PKqUO2uiApq7QMX!<N%Uo_Xq<VvbRCKV(96LDPWH>6?@m2|fsE$KD5n z)=CJvHuusfkJWse^(HI_3IWZ$)UX1=iTgB;QNohVh`8TxnDygKP;pBMw4j4oKEy~W zw8X>3(!vivj~6hFAkv&H1b_hQef8RPUEpqZd}<>FY&z$<<7FTm&WUheEcl`7srn(= z?^2)qZcWX&^jdd@ZMyU2XqP?z@3_m)xjH%=`Z>|}Yvdhp)_pKKlj$()U~cWbdI?Y~ zTkvkH7?PA*`^F5RV6wlI<LCsDsZ*e)zR<P&FbX!kcph9k+0LMngqUyOOm3@1%hJz; ztDSMxQp(Z;U}>nZ7I4utr%Cf+UL9PaU;X^WV^T5$@jF6|nuLyOrZb!c4kn(yIPOKt z65k&ZFtT?Pvl*hA_TP*~u=($X?(?}4>-ukTe`h2QybgO1{CMDHwkF>Y?8?Ocd7%sk zpDZ3ucGClXg7zjS3vy7mOTR0DMc8RD!Rk@s{g5<zAn1av3T*3n29&7&_Vs7ZV<1%7 zT|u@O5}&SSZ8dY2@Pi)1@>W8XIPR@l{VOrcxNY0a2vFoLC0kRZ?O?Spc?=~d>dh9~ zsg|_->We*}5%lvqF-5`0^7LkMIr1{*Oqf9Wm1#?>i^>Ep#3bNz5VbMQ>?a>_XZQI- zieHuOgMw_F&gu_J1E3$f%y6js!lZatLti{Dgd=K*-5$SOlZ2T#(8l}qq|t=!3RJg0 zZNt?Gc)Dv?LgnAE8j&!}fEIfsR$(&N_ZTzHhqDxqmB?)-9|sP1<CT5@(4x0>zoJa} zd{Uo?dNHr#YG*>&dW_8Wjrxarc`p?h3Ipyh(<e^N&S`qBEO>}UJTS&4=?g<(anp}` z!KX8j*!>%7Hjyxb$QPF?SAR8!B)=h+cRkOhE$Q1&khf`&Y5KF-INFm;p8ER}xxFVF zzT+9U!V2h$UpDIz<y!gEgw9B@TB3G+8#nRXkqshG=X_l$-XQoxarbt0ElzltmkT|g zCBRP!Rfl^H@CH2lU&IW5-xV{oy?uP!j%xqFD8Wsx0nSlXFO&I+;aV8xQ@6dt4H<4( zerw>|34DXaLNB2=#BQn#^s8n2v0a;E<1^lW_o&aU1KqAV_bkN%f#EyFv}0mdS&CVx zAroR>%i)YcVyUHrOT3L!dTiORk-Don=Ao$m&)eg;#~M)p?1LUW;P<L!q;v!#HTs^| z#}RTW%oc2~J^cxSIz4SG%^#+9EJp1dUtX{Dk7Aq4c5cMqF5iN%i}tTDY%Zn;*t!lp zbLAvQyv|HJR2p4Oq;`<J_cqc250d3mE|_bP?P=H>c5(atB<H7dou*(2=MUR6xZ;~2 zB(d*>ZbHCWXvI3VV}rF9pA<dk4M!A>JkkO;JTU7jy`+Hm_7~iQy|?0G>($PbWw7BM z^M#>rFO-kIE_8aBgQ*)zEEWzJ9S-!@8GCy4f>KXW?m2zlUYi&1=BsBigfO>$Dh{C| zgJGY+mIRtG;#!HEk3IbT3Lo4UOczNM+3wi=aHfm69p<pw89k3%!GtzC`?8%<a+@JG zol_cdl~<ZAcxl$LMq(#BFVrO!<&e=)PFC3*T34&%fhxd@LKC~hTTUAETCx*|<X3KF z{sbMEuxEhbZ2_qVQpbU?(o-&vb0s`QQEtJnL^*SKjv%gCX1Vd%Pvla!sg-{OzK)uN zb39!!G?x*HGk!6^fKd+J{}#&2RlDjoCoYHHC4Up`d^aZPQ-~Vf0;bT)bQVbw{?-0& z_oyP);2d`{vUs+{LExIs8_PL={YutRoRq!?u=}o?C6&XEvvKO<%2qQdZzsTF5%%3o zZV(A@TT2U<#%Y{X&ycSrC!0`{7_tyDa1Q7&WH^VoG9+G#2qGT&r^4=(65BjZocFtD z&3qdFT-odGi}Hs1{=9V#%FemEj~bzbU6<3Cm17@eyjwG~SIfTQuBE;&G?F3|rPLdU zFUU$Cb{pLP;D3!&B4Iq$2v{-ZOrYqK2#$GF!n&WHlK5wSfrb)hL)AI@$x<=08kGDU z`##V43{zJ@`p3jxXzF`LJh=TzMu;bS;&+jzY#VE6BYcT-qXc<73SRgc(@&5n(IERK zTYEK4$J#FEi_VxYknEd@eVGDxl!nR%H$<9;)9zGINimxM9^&Wm=7UslD)Bx+W~l-6 z?Iq&NOQ;dz+pYzpz~yo)po^NvHD<g~vGO2Z(-Sz!L@*%?1k5##gN#K<*BNf^Eq|T2 z6s=rl{Lqo|a`>&d>=C2s<{Zpvy^XH=q>7S!M(FNgm>x`a3Fy?buJ$!-#ICNGF#Qtt z?%?!K5bJ?lUt7f^iflqQ=Xq|IK{U4tUvOB)@;E}2Ew=z?$cCPZIyKWd2Z+S8Uvcbw zI^x=A*wFk`HG|ct`&o5U3i88rj&zjWya)8%CYy*)w<=o`Gxm14=UX(#7e$#*mqZt{ zQ4dc}Y*xpPY+6e;tfpWbI#4m*_AxW)cuGng)yZCc_=y}Kr<CU8f0|^2$e1uml$|P3 zfQ*@Dz)-3-I94=}&TbO-_Da50KmCm`H;=y22+RRUobgO6X7!btCb$JfV2iA&<;oYo zWv_qPnCEFRa@_5}Xc}}B^oeFlm;DG26iI*O<v<q|aPX@yZCl!o2I52a(Z4#j@ESSi zbG3y0cmT$cNmnPA9`jTx{8AABS-D&cvoVYMz#q-B@4Za<fog@&Zgc1L(NlALNk>Jf z44~s-5vV*du|F=jKn@UHG)k;!oh|DBwqTFj+suKzn>9AFr|_kZPCr*^!7ncN7_M2N ze<}Zt%}DH}tC4iM^bL)EwRIW_Cn?_P<X#^FyyTxC2djqW!+`_?Zr4_fMfuvx9OqJt zaNnOGb~$_4JH<404vNmBPNS3|Q~J9XjYW~gaF|NK-Q9<#$H9JTOPejKS6T)hj<>F> zE-m;50AVCv(*qhIpD%gQR{~ySk&-37(@=|bC|Le>ZohXf-$9W@e^YmX@<s8KD2?KJ zV(a2Q!gP_(rY>g2^gv(#-qi?{0)R18lgdHygK3Pd(a+<W%bLx84e3hQ0~5?wq6~RA zYB(cgyo#(EE#Mk*_3{0*8eBxIDWeqJEw?kNeiP1ex&Ff5qtT&M=O#4FojoCXkSq1_ zTINAxL^@T<0n18YkC-4$4HR-xW^e+*vfq|q!$1TEjOS9$#7%NU(kY=-UNR?5d3>;m zEpla#etFpHiO!Gx1K5boZ5vYWuaIwSU1C$}2dQ3u)sC2>h`8m-l?S{7xBQIvlwfwA zJxV)gon|F|H_lb->01N|IPqRFADIQcD)A?csf#bKtu7WcEiiy1xvQZK%3k@EADN(1 z7qjpHoXxZ)VwH`R@Uh<FVPvqI;#=wmw+;6)0Yt>@veakcO=(IS<Y_6l@f~8L&|k46 zg4qXNLtc*0Do%gHn+KHaoV~_uml+x5X4-%l_@h6QuS6TgBzCk!Hnnq)h0p&m0|3RR znE^m|8*Cfe4~Q%ctv^MSY;Jm&EZK9$0uXGIBUHgs`IvR*HMdC1-*D6izaieSR+|dY zy5IQc>j4YjjQEB)M$Zrz0s9e|@T#(b`hbA67IgUG*0)m{V8=cr87z^*3E~{g{DwJ( z{n|SFxeqtwr7|}VKtU+*V%$<vT_wNOA$Y2QPyQ3M-DvvHQ?mA*NZ@%j_&fXWj28s| zZ7z&*>FCx-kxb_03WaxBnfCH6#+&gUxr0b-)&G_u{=1C%@4tYOUm5<OKmPi=%pXtv zRq{tYd4E>;EA#uQygwiR$C5v4{;P?9-soTT{E_*q&wsV`SINK2{L%T}PyM?l{^~RT zpJV^4<p0bl{u&qK&A*87@4EVrQ}B-^|2P-_aSHw#&VL-mueScT=Hf3J{$0(#EBwb% z{PO|+b@Tu6QT)}_-*ft#@(|DY3%EC{4DZ~6>m_6_6KjC9&HRkL<BT{rR;31@En1&5 z{A1z*3{HYJtORVs3hZ3VU8jFv+(^;JOfCt=7657bkKgIPa(^rPTY1+bqE*asc@*zY zP>;Rs^<E%~#rAgIKcq*J4L1KVRSsf>F?XbrnfK1y?Apf<BcqILYTZXJWUxS797fI- z+I>#!XRZgyMdb1iDyF<gyH30DVU^cpT&pp>x}V)Y!{~h3?|5&>zrNIZxNnQ?`UxWE z<PTB|hJ=@2(kNQoEWr=AKTtY2h_L^G*h9*coH-kg7>+<j0=|@OV9u&8c7B2+;RC3z znpnVQ;%e~*%eegwwGiUd?#%J3`ba1)iDGUuv1(k((TJ2XO{UCBo(}7Jb~XyD64;ek z|3I$l#wb+6{iO-Wh0@ve3qv#Wb!0#xvQ+z2=9$&t#L7vg3eA*;D4+^E*PlB8r^iVp zbExT+gmL#<7K5)3azBZyes~>Q{WP#yT7GUa@0NF;=qf!d@y!@Z{mbF=4lM1Us+H=B z`9+=gPZ00*lZI0f;Xy<J#1p1NBBMngB;cc7YQce$+I7BEy<~!3L*(z9943rN<Qi+{ zvh^u2zI?;z6dEOt?d)Q_z+y$4zOa_1=ZfXjkl!0f?0CkMDHp4&DZvru7?Ed8WyPI4 zBg^mri+4DSLmX>9!qN->G=4~gHM{(1)DIt*W80~VJ9%*1q@&q+;{-*Z?X{M-)?@fy zBTyz&D|WyIMxpVL8IxluL!(Ol;v83Wb94{(o`mm*<(Qu}d9zT`r1_SE;3m}4cvI28 z3JtRuHxd*rL)97ubS^aSYzSYdqy5NKlouYI#gU*x>VfSECDG9HsmB!QX;ixAm1?K( z%>nks%b_8Bez-<`jLYo(`pX5coMz8m$EUnW@`I%M@9$&wt*&0yI-OjK&F(#8c!9_m z3JrRc$lO|$@3t3KlPV(8eB%u!sEFq!RP466Nct<TVL&UlqYr0^R5qsP`;pgMgyMTS zPJp1!=Ze|Yh_pHV8atph81!z04ZA0W-xeRUpR$ECv$VCO*y()6Duh{8`>3ZEYMMoB zd~mI{AJvzX&p{c7>-!Zl&Cyt*3kix0YFP;rcsGn9bYbZ9AHAl#S61-JJlRio!u@O$ zqr<y`$^S5*Z^^e9^X1#jPf(bWXwMdc8O6|Y^b?frhBe1}iC*-7Mwz#UQWrfZAoRq! zGPK-87ye>&u5bS*Xs_ph=%O0lOE#~D@qx|KO4+!0R-U{*IKbNfINYnfTfJ*X)?=yg zE>QU!M`)$%vPz9)Wo#A=YAypDV1Df`xKx;Dtaj})AC4vU4|+vlFexY$Bs)k5>=GW= zSj*<&E&gI(_9#G9w9_mvi(s8HdEc~yKJF)|^IIlMEoFC6@%264SZ6-G{b7AfU;ZtU z^lWNbA9s$LF%FXPLDj#pgUfr~MKx|{nXh!dxr=#Yqf-G9EidC|5H5@*u!GSd4YZ0( zNrb02rcp6#$lF><1Id-o)rMQDlxGJ^<&r6YvTZ6FMp%r$s0>hPNguzE^FMaG_f5yK zDA>Pjd8YE($(p<Z6l@f(w72eBiw?*uBSZ=Ir?}1UbEx8pJ>iH=x%%Y$#ZyR<^ZSDm z*Ah(&fkGigTlO1T9k`^sr0<=cmefEcA#$Bb0liiI!S<vUs5h(i6$1s#^*~HEjmvS7 zjh>yCK|eUJ)<8;1d90HwppV0)#Ja1cj<MGdj0Q$&>Zhc2R;DD`2S%e=&ko$zA`Dv% zT)pX4S)dyvZmdQ76X0~ur~96o(EJZ6URzTz$vO(?{T&p|I@35oIMa311M&=Y9+#5g zl;Vo$jjs5~8@AQ!h{AWQ%&lhatIMRY@eJKZZUkC2VN3^3Jlwg;Wtq^uR}1Fu97SlT z9OpbEDM<x~$3`mKFp3E&9m3s#v)`D?p&hp8M)VUjh`1EJlpF)oG+PwzD++b2m6GTb z>$*Oz^lT5~TU`91LcoXtd>CTasLp|dU9#$&Q$z-~v+Nh25PrjsH`mD+)ArqC4Aq<S zk!c$?*I%DiIl?#1n?6(_Rzz5ba0|ir;kD^E43XE+akP(am+IBK??CAp+a4WeJb}xN z<02DZi70#fN&BWua~CdH@L~sR@uO)bK&Iri;z$uVt*>#Q)%M<{@n1YXQ{f~uqMPFy zzI>>77~7OoE7PTsVMJ-6U7=m-1m_5%)A8ex+|0>6N3t+AIfw4K#RKZJ28Kqe=#u;w zIFA$5+r@5UuG2!9k<v|R&Sw(aWi}0l5h{|1H21TUSD4Rlr1p@%FV37fCoo?!b29pg zdnEDh*<5#k3SOA=AUL|Kn^m#t3aedfDVE&X%{t)bG2Zn8{OlxYC=@uC1G~!gBnnV8 z#YF#9sX(2N_n|!qgta{lgG!vAo@mK7z8+Q$R0)5wWm!@5=@wjpb5ix2(rN6axT=@n zsw$Q~mm{=qAKUP&qLDHv^{Q%W*QGt;j*345(0{6qa_(FIu|L<?ZEQ}nGM8;{4E)D5 zgG#k}O<|i*_tiF`zR%pTrg3t{Ye&wd<P47Zg_XX!l6X(TOyc;Dbmo1L`p?p2s`wGA zQnm1pMGBncfsjMMR!hcV;!gG?{$1~9$3V#rCR=jx1V)Yjs=$(n3F+U-ZFi-C*gQ_O zmwttGFFsWLUj_f7$N%52gXYX0*0t*;-XYTk;u7F<0IJ-jsu$6Q6t?kN;cNtxLjaMy zQ^BdkIUt0j<UT*SsOBt09enYDZ>h72gInLi?6CzGC~PAs=)R`q2MQYxldLPfF_K`( z%^n-S++ofkJ27Xk3fT#Pr-78+_fxrD)s;i232+*sjiRL|ngt!+Yhl(iZht+=XImM0 zaSw*`AYe#3?Bv+7;0lU$EjzpUvt&;W&XW@yerNfRngq--?N!L;<Xc;jMyBM^gDll1 zc2TWv)50(<*=lx8n>tqfYx|q|MAbSai6`oF6N}<b{qL^h*Qc19mkhRcFbO=mywcja zsnOo{3p5yHMjIQmGuJ;@o0_3K&6#w(Atdln(Z_BM{=gTo;*!3q2xBvom572;qxc%U zd0l<u3WF^MpG6d=XJlyW6)sMQ26I`0cAS(qsQHujp9oAf`^++QFHB3#dOrcp&KB{E zuqTGP=^w6sAC1FxXmhSQQO7|b(2R0p!PfcH9A9KuT~l<+^7XC|j&Zo8jCwfMzX*p? zG$`(RTZ3hQAcG{4ojY1BdNzSKcXOV!avQ}IDIM}1s*K@JuNV4Y&`Mar+Gh{ih9VI7 z4qy8!+0^yWF#JBCSm4C0J3t`1&DT9Eb|c@a*pmVX^W9y9=YJY?ja@^4Fd>|&ZO>#> z-YLPdEI|trPf_9okCQY~!g4p%_i46%)uKbFlBf8Muuj0cL4wjAd-E(#2|@`PX0o*A z*1D<3s`VQ;NHN){+9<qfkd&t||=m><1d*TS(O*z|0LP#qS$uypuz{$vx{LR@WHV zo=VdPP*d36CY)z(ZR>EJVOj(K@HIH0H!11rn-BoVwr~d^f9obD<?xVUA;MCh@W%5* z-h|amkEUU?G~X$WLGi|PUV`>8W{CqSml?2!Y;Nt<QK{{}wPC20_AdKtA-Ap~wO-P* zNZ9_#X%<P$N_*)Qibq8e;@*YWmX#q}N0P6-wK*LqzJU_B7D)TbLI+XPPO!y~=s=(T z%+k*H7@u4%JDKN_c6T+RMTNOymmylY+lBlI7WVlDI$~iilx&Ds6s2aZIHZD#{lH)V z13xzPWPsf7ZUE%|MR{xdUlSs5a!m?fNi4>3^Zq5Rq<ZPhLNC6M4~Di|nD4b%42Wge zT2b&si+n=0SGfOIIUw}gyTC?$q#AWTb;$cDqWE6s8;@nzgP))_z}(rb1qu7Su)m1& z18ve$AHweD$|^Z;qsnwbNg=bGelTLMJM%2i(JDbqn>+8qz^l2+^~ym8PB3`Pu>DyC z`b4fiym)H9z2yjFirT}!`rN^J@HOQNlg^}?Mq;k<6i0r_U1`D)R$B3VX9R^Oe!Q2O zg!9Y~Dd4?>Ux=hPMQHs5>5~~QM;~UlZKGr$6GJ7l8V5Dy5sXDh-*hyc%s3u)WzDQV z>4cj}I78%vuoa<?%E(sexz)%j%UsRVjaRW$FJi#{yolnF8WP_p{ZD&`!fa+jf3)6c zNk>!4lMU9+GrqQfQ@O+s%d7=bjk9Clv<B>zU)a!HAB(-yJVl2@6lh_b&lUgxlf}Ji z-|LaK{j*nfMlTg*3#K;vyup6{gwjsi?q+EM(nU-Q>6p$zfjDb*ZcH=XK`n(0MGqNp zm`rmr3hg7BA7)vw>fP~Ik|7dj;#y<g(YmS8uwy{p7RPWILPMZAZfP#hpCV>+)6($J z16TYGG;oY`=pgT|leOJY+e*dTK@T?b4PCQV{8UR5HiiIQd(H-)JIbDS5(Y9#4oTdY zRg5J^ZZ2aw25PjK6Cy;$#HC~7OJa{=8JQ((v-y~Ly1&eQ-Z;g<?s;clHd_&z$D@+P zNmr{H>sq24qH_m{*ut)uaTuF2?3A{;6R11-O)_Xjx2osuRf7u+Ss)EQl&(dMh>Wp9 zoL5CJ83>v5H1afJ8?6tRuJgYyqn2BLpuFG8q2&;0=Aywlgq%U|Ot{?9aU}niZ;_lY ze8|U^F!RJEhPpZ;<F(7PbSXpCh@JGAH^Cq>dFW<ZuJVV3ut@KD+9$`0x22YA3Ik+Z z#ab1M4dlBghWm*bhF6#SC9h5}7(-Hn<&|VumSXRw_OFa*$nRX;1;okXvmB;-*HsFs z8J)wN*`LjQ<#CBfQ;^<W{w%hh!EwC=<<0hfqx;(m5?#TUT+!d$<DtnGg5P11rnoQp za9f5zwN`=qdoc?_26g$hxfjEkaSy2iOA{5UO2zF~;EAAFW|lH_mc8vxEo|nVKiZgJ zd87NPh4L38{(ghKHp!Iz8ZDaMIRj#Cp9SZm?Dwigj|k`Oz3<npT}OLwt>rW(RaSNT zEv`;JP3aTSOVCdwVxJPT;Cf%MSLa*Ra;6oM*ioo3lIu>Jj#nsch}_Sy(EzYsu2Naa zBuS)O+&#JFG=iI#ozh>A*>HkieB$iNoV$OT1{Vn@uJD-Yt6hQB@@u%#xn#>bLWKrO z0ZVS~pCB0EEE4Klh$}BDXste_X(Q&E=l8C8M1BuBIC2VVBI0TT!bsO332$yYHUVlm zHpRDPa*DCC?;KK%d4oPSjkuXPSMjNl_uxO!jHd=4MEHykt$iCa&FbsFR_TPS>|lQL zG9Zn<-3QM;tD7RjqlsG!mFOSRm&&F_EY2L?dr)UIv@xQJEO$I)cE|=ZI;8EaK2DOE zrz@ZcBpx66b*ez$3?-9^bbazsXH)t`?!H~1i%YmTl(|iWbVMq?rR2G&ZkowJsjirx zTz{1g2{!ar;cZGpe~1K>;US8bx2?NwW(1E+u$`)Tjo&|zaGY#q2_$P7qZ;ohl@dBJ zq)0vF%uNABE8dX|J)D7^l6(`iC3$$VLnqihyv=<mS2*q~FKL^}0jav7)lv}AIy_V> z3=TpEWoyuAvnhmUhDWKHd|niYL#<~z@7bo4G&pM7&h$9A$P5Gr5*5xqX@=s))ukxb zKKEfJPh7A}3FMY0$a58Qw`-=Y^NBBk^-;EMsl}8sK8%KmUk!47kH?4aHZVzrv|}&Y zqmv7SjYd#aFo8{GkoX5~)>LjItXUc&k5(L<Yir{|B|(h6t@;)){AY8yy4FcNBB|u& zMad;mp6nbp^m=}T5i;Zc4jUz>%O@1PPJChPcWkt0(3+<C8k({z%yQ`-kI`Zwz0HHV zeTB3SJ#R?r5R2Jn?OnU(21V9N4#m7)A+JxcSohqx`KX9E61GQ9|3LZ{Cy3y!<?~tx zN_D1dt+yQ<639`mncjPz--9`x8IgzOdpx}>7zk0x(%7p}<zkq9paWZ83*$}M=P<ML zeg4sXQ+oB~bhL}60s?6*uQw1`ijUY80*CIoIaHHnBj^n4#?qzA)A|NvKr^yQZ00PZ zyAm=Z$v~J~5sWl-V@{JZYE^+q$4S$r#Bd+0DWFCYm$WXCo+shuT<^+*q<Q*aSK07l zX!GUHytYq%g|=-npH^@LQ65|4^vwNeKG4CLN?MR~2*+4B&gg6+Z5QvDqn=~Eb6u@P z;J!Ecr>h*q{q9b$m@~_9u%V3lC+GqDXQ2egatv2`cI91(lvX{QA8D}r+;4kZ`6CFb zZE0G_wKp?wL8?K-cJ--HPY$k((^kkU2`UCTf@m<&ye0lkHA>0230+zpdGw$j9@~{z zVCsT0nwm(udqMWZV6V;EINlwf=;Bst0<IIjDq{KG2=WRrINsIn42$C^S7Ggy0<w?y zO=4;&?)*}_Rb+OP2maR<d^~=hd6BesL$)m+5T^hdpLH#8w(bybzNJ9+f!@IxRt3JV z$)E;FrG>9LXYcC{F@u}0^HvmGDklOen#WPjoUQN$_z8?^3H4P2ZOx0w^b-!hZ?HgW zw|wgdZb2K}o9>ET0*U{&FyBZJF!=A#`d9iF1^zElKogu9ID>?HNG#>9$Ege6v1NNg zOQyVbtB+5-&*gOGO7eVxj*w>W=vytYwEB*`(X2D``1jwACRhR5{rPj_C~TR~yTP-C z6B;S%fn*tbGJA2?Fjn`zkr1@3H1rh|pIj5>WH{YBJyK++J-c_XcrGG*@ha6~R$Y(g zfo8wKB`wLx*Nf_|D5HF-ib7SP@^nnJ*=G`payOEItjMklXect@0b8D;kbz_Um`^*o zkRPoE_#S`1NXm?nejLVVLh4TA(_+5@Da%-zOZ~BSYRQ+qIhkVsZa>Nn>+0(}CC|}4 z+#2G~w>cZ^Tv}N<zbd^g_~h!d-tr6@w-kxJLL=1OuUh8^@Z{boCAb$r2kebM2L|S$ zR`UP6PF!eNFhra?p0**ZE+F9g?eEE=t63W1E;URoiI9L_;!SfBHhnwVzYMq9bbsIe z%R5LFF=CtMtk`F>bLM;r`?F%9cW;i`_xUU_sWc9{c4wO_&r)T0W;07X>;OXMfcFQI zCHagZ1F*UbZdwS=_7q`(e8^LGx;2TwI-eL?Y86Xz;>Wt7>r_@Z^G&ad{{*F5<^=}S zY{tL@15G~8YWd0a3G`Nz6&NGk9FG7=`E4q;j>be<atl`irN@FR$hIbm9{w4Bp`AIl zFrm3aP<D2KN?2@~qKOVtq9QxH@ob`|vR}ab=Da0Bnm7nHdFUygnRMma`Y`N!@MKf7 zM(D*|J_g6HI4y-mJE;#|oOvs$iWeOvPV3H$a>OiGKh7s(vDWV*FWTcsSg1|}t_<|Y z$qUag&ZNBd>|r^HifOFrcJyqwx-XT2dpNB7>V`^G7Q;zJy{6<fa6x?=ANbSRTb%t4 zL66&-VnefF;X^1G`3o|^nIxX|O=$yi90J&c`9mDz07;#s9wWv}zdz{;b{di_HP)d; zf*$Rq^Q|gLY0$+cm{gr&81&)}QXr+0_}}6@1*vCKn4YmoKT_TGf}1wj^lqR<PoJjd zZ2Fe52rtZ^r?tQ{4WRsKhpgd3-_|q4eILzMieWYO8m3gsS6s4XkL&UZ`<juP#T*U^ zxLnhW+Sam$d3&qt56<4ItxLt<7-w!@+Ts#dOT(nV21aYsW3FaDSqm5hj2PFi52o?4 zbWjsCy@3wm5Q-)~Fi7a|t^hxuPrKef#Jl9}WZqRfD;ks3u=@Q9@v4AoEH$@Q$;}du zD!iA^N0%!A3_`&NoWw7>cLV|;!i#|4V$)Wh{juq;30lZ6)W>i6L*<)wJYAA!i9LE* zcc6}fCQHQTOfJUz-ii-gO)0K>uq`lHMxGJpjq|h!beA9!73<cn-CJxKYisH&5Il0{ z#Q4Cm%Yd)Narwn5)J$b(yoN7dPiE`*Z#heut)HMrnc*^9s1d%Rqi~L6_g@RG2x)&_ zTsG-F&HWPdwWCx?w5Ht`%w$Hgwh+40Yut*>ArocEm9!Vc1oN-OHr#pS7w+z7lbCWp z#!sd8`-curpN2IXtCk6fx8-xU$&^ulD`zDAE1QHLiyN`jSm9mn2FfWC+ID{Go}~FZ z8iS8t;ZtMQ6eO*6$;zRtG}T+%#e&=~ieLKOx%+LUDeh)0W;zOeyCJguHf^)2Pvt92 z-lE=GdlLrPn5@;X#^u(0b;LV$Uk{gM4kOOR6VuVuXrsZ%F5aMu_xrNt=>l*m-5{qN z({Z)H)QWM)n^WJ_BEX)C?>2dVM3$MgEo*V9KIk^OPUw@CDZR_G$-5;jTN1TG+jTas zD`Ms>9o5xvht!zQNq5-oxTT42<LeAp)JqnEHEN=rs5qqCO*_r<E#3p}&42PetT)HW zr|D*YK>_nI)f4C+<X7!qQDyIHVf;39(92ExN<8Cca(wAs6E(2n9lpO~KyS7@_!GtY z%R0Pmb}$s-oUEPpmsEe&{2-K_|86BQrS58fT@5GY$Y5CPjc?KchnZy0>c02j46#|{ zwKzM@hEYj+F0S2x2lXvZ5uR+Y!OZa6a^O9GwcjtgNjogG8rq%vmI0Eo&_{P=Q0Q3) zyp-D>@_Vu2KiX^RH``!(oS>#9JaM_nInD8=8yq@@@Pha3|2c@JZ*Gwmr+m542JcU! zr*a2Ff>mYc={H43&TBb_XKxz9W!9#Dy;bntwt;lNy*a|5INS^q3?r7~&&9p!_lw2H zr@8rHRMe(#27P1?BC`FT%1mi;G7V3#{44#70{^!t5F;;d=+60)X#djct%AEZ-X=p| z%Dg%0K~nwdRIB>SCz~rFej4EMOYgVaU3(PHOWS}1{ytI~Si||kjv;Yf;?B9`{Y95< zfCn$rFOTEZpP<ti2|x@Hd-4+`W*Xw1=%zfkKdVjDDb6V%_4z~R7f7ey=4t(T{RP%% z<P*|~(DdW5pOkI$^KW!1Q!sDTNa3CbK`b;T4gYZ|l3L8ONt3T3gyF3-UzCq9c>9S< zg+B{#rtFR6$4vMg`nU;Gy(&+cs2#=%^~YH|x@Y*AQNH(S`Dyq1Y27*6Mr9P3(NTE& z=l+^KeqHG{+N>j4q~4-zN<5qvL4oOx&hO^w>1cYK4P31gAi(E=s027^xEBY*NDd}N z?AUFPI9_+P#^elO3J3=18kI6^CBt;#z2z?!615%JGQt&i0v=L(fekrjGD0|8aVger z-pqAYrs<eYouyLD>1INMn^1Sfh0_IC1|iEhBe6yh4?zFx*2<Za(}>%oD0q-v!%JH3 z2U&F3pjKYL|CKG1fP|C1I;n4?$HDDkR%ez|I4AzN+g)W}p=+;B7&TnDq*xWOZy1*@ zs#P-&?yGO>g9nM1$8?Z&P0j;eP0nr$BZFcA-kyp~zozRg_Z%!VK1SNTWi>O#Y~Z|7 z4jpba9Ns?Y*=Mylb)P&4HGL>E;@GFgDV#llgR06cjPj#*Pg|`@0T-Joy2g3k65vfV z{L-FXff9?L{&bz&#;T-fmxl;vGE;*0YG=yaXQ$PTVKK4yOr_li5kCN20K@9Tu_FX> zTKV;S%2zDp_HJ6AZLZjkLB9JiafMR?BXeX004awwj-%+SVI?;iHX>69iaR9f-(rGP z<miwi`sXXC5;U@3xEH>a3n8J&zxEw#f2FNxY3R=5V0e8Lu7RlF{kjc!-5b+9NXb>C zg$GGViuH*b#(#Le_*fnrqw;AWHB+(fbv-(a*JfmdO(``)>Op?rxCV@b!IJdNDbj8S zBNh<#1C@0di!7i_;lb<R(6@Gc<e}nf#Ok6&Kg4zW*s=AURY$71+?2awqceCJ8TM2{ zj0~4+6F^cd|D{_32;Zl?r;4T_<tuQUKq>Fbea$>Y18?&=$LCMeFQM0O8+loic{lhC zHVuS(jhHZL_=**W2F0!{q%=O!a!qgG@l6$NL=0la-Uo{^)D7_ERo5F?MCCIFg*}wd zB=<W2RgvQO0<H^+S?UnRBOY^o4x<OcZhf&Q!FraZA<mGH-u#2sX2w&Cacg<!FJw^+ z-rTszsY|>XM^YZ&A{9xwnV8uo<2<XHhUJv5c>o2%N$=KmkI9f)I>l???UhBlt*tNh z%tAqU4Xe5r%ZKkG{Fhf|uAQzj0>}Zy6C#A}lXG?xGaH`v^a$Q^fhN=WmpDF;2jd30 zC8^odC#Aj?n-B1=<|tYYrZ*rQ68rT0w%XT6D%RvMgogB{eQUY>_XE@)%8iuY?QML~ zv@cG{oBci)^zOPnEM;3*kM$&@5t1}!s#QCw?NIm=l(f~~e=wzR@eP%Cly!%kr30%V zj%NAfD(X1k8lbxV`7NO7qrzOyE(I-};kg$T_F2#Jp8AB(?5Jdhf7$^6GlqW$h{>_! z4=E`-_-+s9Yymi#kx^n*-^9w7z3(UYB2=IpsS^NK>iBly4A`by99@((TsCc=&%kMa z-3-{En<IC=Iz+6_z`U(i?2PFb>^=;dJy6DqZxOo|{R9zROv9I1P+ilgV;>^sJJP2j zhYT>p6PC}~9n|%4-oG*rZ4&|Ctd_9&Q<pcy)9P~X(gS&or`&8#P``3FaNZW}11Hf< z=F0#S4`i0FOw=iFG+-V(JphhUQeFG}S4T|kdfTGf#UL9xcyAflcHos{2Tw6lnPst; z+i&H1LvGM%c~QNx$miU}xY-@cTxo5sbiSYPjb0k?zqTBZuorjkncOfRfBf{C5F@hJ zwN{=<qiA<EWYi^NES<i>M{3lZrySb-UYdFmIX(8QQAo_kX-=`50e?2GVdY_cD@jl1 zosT%u#;WAx+OX|JDkWHfqVw4b%#Zi#CxMYLr*l@}jj<s9JU|cX<7HGA&SK7nkr3BL zdv-?6;4G-|?9V$PdnDoHHVz8;XI>AJACW9CjX8^zv^Ub^j1ICwj_DX$-mN-$Zy7a* z7xQ7gHVAK=iq!JeLvf2n)RMfF4XC=UM3unfLRm0__9EUr_OL{wLPFI{YxBOgtS$6a z;b%<sQh{7(o}1C&(|u59aP-+Zv%g0V9n3P?By_!7awDv}9MPESQMYQ2j;J+qF8m?2 z^|o<D*q->+ZdXbhwU1go_{U%mVn6~$=yuKYkuzU*azNiuf8V)F6I9qG`Nx5LYiUO% zhoU+AqlZp~G@jyy`7H_L`=liySg-qOht3=tv5zm=<n_0*WSm`uk}KYCOw;YV18V1s zvEoimQ@Z1~<MadYSC%v)>@)4F{V1M<gki7g8N{Vw;=a`RO*rQ<=;nC^N4Eo^m$-s= zDu<|PDw%wT^|_AKELvv(5X>)eDEMl`h$MvYy?X2#|M(#4OM1YkspjInqB+0TS9vXa zC|gJSu^Ylw>3E8U8O2>0V}g>{Wsz~_0V7&V$rAr<rjNN}suYhV0%S;CCf`XPSn91l z=r;<YfZwPNJ7u0+n=<R8Vvsf#zBAar$)Z!bUiKxAb066nIuB<&huIEfZpZfm0e>+? zi5N(DQ*kQG(DO%TzMpldti-K*U2^3coFXPvnY~Yx4pS{7Z@g-hOn#Qrp~vFqdsp&u zS&Z~H#;<*mLi6xC>TY>nuD%3`GwO*@QQHyr*5;YGeOj}K$D=*WonS?#HWYUoG~DT7 zhOE?qhNG-nBiMLJTa}f^*i&LNH4%`uSoBD+XJc+I<x-JKzAAK)D9^?iAJ90gRM2ww zXL213Do{7Rmx_1WOl`4=s&m`}zSPfJw-rMeFsI|hQO*!RPdmdZ!5u4YsrcTatf6R3 zhOB<yxob-by-_&c-ovvz<2`;A9Ph#;k7F`%ASgGTZ+XW8t3Wy4&$%<A)wh^tpS<O` z@*z(s?=^EqSelzjT$KcUi_O^B81}NngxNQQCwo}5#=@I}Om%JW&*ked#Fsu3=szZl zKFDhbhm|M*OsDNz8tt(1dn0PC8<sTLs=LLTQey$?>!vOa$>2NUhc5fYBlBkSOdnW1 zeI|NqIhocbCz8Oy3=5eH4{f(gwMQ2jU7EZWjEAg})`O5+js*qvE$>+g*PN7@@L#sK z4`gs9Tv4Rg&HF|rFB7kP5(=lt0lzs#Rhj`F3M#2JK3rn2P8%ZAa&c@Uz@`^?UmJM9 zx@we_Xe)%Xh?0SREEn7^<LvDVRhv0RiyQTMrg^$B1%zj$v2zR`TI^wppc$7K3loF- zW(MT=W5JiAqy254jiSdJy+rKc?z{QY*_rVwZS-*?%2QK8I?_5+I`@WWhFL=Vqb*3D z5EImB)*+~5gU4R*gxTtZ@EaoTWsZod2NqHm@9MX24#WA09jj7aD48{9c=cbZqd0Hg z%BV+v&o!VrQOe?$7V~_j<toAdtk8lW=fwughq0oU$4qri(VYeIBtpr#VM6$1`0@c) z0l?wHpd^OdxXoVkB-@5b)d9m^D-i>PKNP<OERL*gry5!AH<TEUxKzkIxYekK@0qXu zBT?kl$%`r(+0Bj7&RMqsIQ`_EZw}?ILdi+R;ar-SrfK}zfQgmKSOBQG@lxQA4G6Y$ zs!c5;_4(5*S*!Zjtk*8${~;6KhM+hN9r$F;`epWS|C98icka2Lrsrr!E*{qYO<u1D z&Urm-wEotTGoc0WnR8K1&YVjwS=HHOZ)Ws~pXUx9v~4yAGW>sLewY0Ei$8eC_K$mj z41+!|<hwP;KSBHZCt!WfQ~wz>;J@8$_up4Fcl4it2=e{Yj{K*$|9|gw!#{24-v;qt z)tn=i`M>e>|H8A=b^i-Dqw4<Mn1&es`<eQ$2Km3#@}D<<7hNivPrH0)-z7K#GRa!# zP>kjwKKRiM?stb|_*LC+3x6AmTavK;eiY}5PQhCoH(tg5fOut!zQs%SKP5Q%#4vvM zN_VnevG@23Xf{mKJLPNc{bkBmR`tgX(Ts7{<s|JTiYVvDq0!^Xs(nxXl(zH=I^4B* zNE=I>W<<uW63iV#>`LeFZ!}K)=>8igpBv;nQp(`KqnQL^?gz$0L#iw9{*;~rB5P>d zZ{H{&?A~^wBKmv@`pXZBGT>2}xw9fN(r;67_9)~e@E^ofmx6zG`hi~+5G_vtH<Wke z69hqBvMP;JO1QFniX!!AE@*ZTj8T4rNtI$o^KvmS-{JUn!QY1-ERyNk#QC%LJ!CF* z-vd`1vv!lyBl0YLcu-)+{4Y_V+&+1w86{w8_V-c^ISpcQ7VBx!hZ2_r=_8+}R_)l~ z47|gyFs-ut8r%*r?_8AUm4|i?{4P#vE4dr_eUTOX@n()a!SrtCE)g_Zma+K4%|m_P zEGhZTI^8}z)6TJpfS&0zwY{u{R=V}O_fiUmC}~Fozs#4Da5kvH9Ou^s#>{+}nHr<h zQq8oI9u`>`&~XM=^)JN^H$2C@?04DU`g-#HxOejXtkwF3fxePRE#j5AmaFe(wwMQa z%MbN{itUxM#}LbS`n+lXY;tX7Q%m*^<wVBZr1q>HVa$i_JKe3ycB^f7Mvnrg7@Ae? z&%s8l+8#>LPr6%<6>1<b!IRlePF{UO$2_F%MJM?qAdSD1BIZ*o;kldf_&HK15A3+P zwUY4!l*sx->?Ow#qMiDG%{b&u+UQh|i%~s`yy~9m6klx5a4}=H@~OAm+SkfYbOQdb zuO6<{bbtIXQp!2l{D?0Tt$h0GsABjH(z^d-seuFP7y4*O>V~n&%6xlMTvH34^rfZX zYUe%AD7KPbr*ce|jypJaFXcIZQH#&&M;If_)mV@{4d<b_T=HOmKQi8aFw?#Jxfc(H zj=6d507);zYetc>;n&DwJaxMb6EIDsao1)zM`Q<ZRY{3&zE91U*=<`0!5-!!PwDt{ zz~y^}ZC)gmJh53lDvl<pJv;VPETx{+?O^Hs*U?(|XNNnYCBwKbFEF+iZFRM|YR;(s z=PxNa1db6|Q|k*E3aD@w;GBZSjryCGXB{}<oMFUA5Zfj0kjon~CGdJ_z{Rf}8IXw; zP_&iD85H`GSn}M3L)?sSHIt%ceIfrtU!GRfRtYWbS9G1!yEUP93;$@LDf5!NX`E!d z#C17Ib7cZ&NL<brf;Sxluls^2+P|8Zn@9N8!<_gnw!G_J@|udE4e01k>KohE#2~u& zsXH?aVWShG99rBTyUjM2Bd5rp*WpP2V168Fc*K_eB$huczcYhJ?Rd{ik<RhgRY?Yq z_r48<Z!BoVC*Od>h`gntzP@rzv7W<kvuQ1B#P00ub3Kfm{7C=B=6o!I{gyxBH03oH z&LN#hpS;PBAqS=oNp|)Ej36|-i;N!r`!P<z#@d#_MBrolFM0HZLBwh5m7k#Tm_JDM zZwfI{Sb;l5Kc+KeC6mokHyFl@a~;p`N5sh;+Y$wQ%KfF~{ecIG0PH^9I|ZtcOQi|O zY2&o}S;X6-??<PRGT2UM#mll0q)gct>{l7j#dFI<9x94iB<v!}2tXX+?#mjqltH9n zXS};soBrelQ{7X|>d*LeP9O<Qna88@@|1(I0z?r<jdHbNw`h2=Y#J8R=WeX5L@sK% zcwPH8Y>vs0WAxIOIH6|+GL9S@F;+0-5Toq>VDBxU;(C_7(ZMAIhd>DK8a%*cu;6Zk zJHg$C1VXUj?h@SH8Qcl(I%o)xU;_kCu)ImmIp00!z3;Ad-(C09^<V78?5W+mySlon zr}ysqRmrYE6U*!s%{1A`Eb;IYBqEbmMIN!0>ajY0(K)ur3VPGoL$kU3qnozQEP0`2 z=gr`Ahtq%`y;flE@7Y5Lzs{`)`9cR*>cP>f3fmB?(lJp+dCZg!@7bctw_p!#NY`7! z*}%yP99OWGAY|h$zIPDYk8YZ<j(LiR!R6e8C_&_5M5d@I2h{WMmqd8%`PoTkMO)Wr z!|B?ulk1oH*&1;DTXU<*MP_}GV5bHVU(S>|fMnx34^0;-r1(=WQ5MML7%3iGszV#P zkoX=D*angdD5<(COYrHVUbMH*aVz^}Il|cOA2rZ(KQb7q;-pKEpy+$P&QVwW^kpT} zF~&%LP2Ll}7S~;-H=7?~D1A_I(-)d7mnZkoV}n1x4DJ7j&s@!`&Rn;x4PN+8DK<D@ zw%oU0;@ls-)NkoV)1d5X2y%eMwS5`uc;oT?d&N(eyG^^q@VcvSrt)W2sLI<{vGo~E ztzQg-@Pf;$E88YD^;sbuDtm{D$TT!>2eajvf<itkqgW0}RUad}|FAqac|`IFYkoNh z?H!BEQ)7V<#(14YN=rdn!sCJ!<}feUgU{~G_zq{l=dN7|GH35!Slc=*OV?KMHb%wh zKGWFyvLa=@lxqAcl!c2CVpGM$rNCd{x`N5nP%2pUy|%1eIk3eC3wNuyhnN{BggEe< z1O1wsvWid)gZd6j8b)k-A_X&H@goJzD)yH1SJ3>rQja&!V@`#wBi@eJZ>J<%K;81b zq|V7KlbJke#lguEBi$h-6NEOo;aEILc{A|LbdIgyC9}XdME@A{%xyzkmYF6-sD@)Z z_JQ#qn-v^NM*(5<uT?N5Uj%T(;@Z&7e;>%<dw0qQMW>0b6QUX3K&^i%oExdxPxx-) z7a#(Apog0N6L>(<h#hTvk&cR$ko#C)=?Fa#2jO_zVno05r5a+|i9ije`~p<YDaKgK zjX&nEpFda5w7<OhG$Ll)X!!0?pQ8Q2PuJvFblPuQUxP9-!_Z(akW=8xIsB*J^;3qx z3=J-0P-QcQIG2nR2{1#V%j%+%RziO-`ze~#+(_Sv9y6hj3i?LME3$)XD(>ZS?D72c zh{LVmkmN6G)4u?=ZmRxoE;k|e5idliMhwfS8D5Iq=(0O-nLUHO+H?#*X?eX?^H4<j zuE~%k?bMQ+4;Q#6bU8o!PN?H7R$_!PGEkXIMfByV-^@=zo}RkQwTVpa;U7POuXOeJ zZbKjU6}vBw2x}I634W3-Bd9|fLweTk_q0H0!8Zmc>L*=7PZ`ZF6m>JV-{Lp+dXdRw z%#gwA?sYA%S{~MZPsU7!W(9ri+xTx?kA5iUFM9}R2^em&&<Jgvj~1tjrVXv|M#oIC z*>ewBc5JP~q7bj30&zwKmi?Hws=a8r;cjjwkw3Ql_)5>aCNR2GSq-5*iWJ&${6lff zsMQW!KA-o$Vlu@OCraklal3{;C95A-q<YOcr?<e9Y5s;eP-h7A91*j@wSvO%(~mkX zpO+7Ce*1*hIStphVY>}Vt8Yw)7$*-zpL5)u*{<5~3+<duym-1@ugaid;;L{rG$9uq zjG>1|iV}AW4;_yxVM!Aakdg#5n5*ewnX;;y-HBjszP%=jfB8X`<IK(6$`a#QKnOxH zXvh<Tzpgrduiv$%KIET;B4A2<I2n2r6D|+W?|XGy@eWh$V*|Y9l@n@G)AeZ7dRcaq z_)k@_h(?vpre54B{9~`z&{}A!8sQ>{`2F)GMWAGs#1N}KKLll0wDlqK52XIig6hZG zQvKjr-?&*W*T!c-hZ;M&UA|c~?b73tV%Bq6S8M%u4m~wrg?(Y#>4DcgSZ*Ta-Idi* z@4ju^w2ca%t(hzf){DSW`1VS=>Y18JcF@M23g|A>uev#HlGWgrB)q2CK+^6=gg&zG zFWG4Y2um<j8;;mNstyfBvJj~K^myEn!pxnC9{Xk(z=Ub|J4;%I=qnQ4;7I<vh!i=- z=p@5P0ha{+$*-r}e8^8@ZtOzG=XKaZ0V<S^0+V(yA6MmJY6B$mF*&Tk<xkVQi)l1_ z$ku&byR_QNA4;p;Rg~toBChPrtrAhrc_fq9$+-9)3tx^J%cf%%rK5}*lN6=Ht$71+ z6j?l>pBA&{%pRVjKN%JephlIIQ-@|2w@uWHkA6;`u+|dr>C*f8`h1$VKwv0d|Fv}N zorQWF@7<^2h-=u<aN0UlBO`K$Xv{Y<?DaQE)0iFVf#vH4P9n#%6?wb)jznHPt&D~V zw4|6Bj8!t<$k@b}9fW+(c6ANLEUkkS{5Z?wgo57U#mIk65OLBI0KeXB79$v;(KFyD zg?wEdLk&IynvO=a(2$)xX&TP9BCqFT+AxlHlX8=%<_I(k4VgXIi+l_FN&j_vlmma+ z_)L#Wn()c@7R3tuL%MM$$x)hgj^}VV&4;&|RNsKOmcd_x;|g%~AbGNb{S}Y(4Zrn> z^d_YW`{D?&Wo&o{aVu$GErj-mL_H{`!sgS`eN(pf!EV?qdxMjXC-x5JIsKn2KN?Va z_??RX{TbsIV1bUMRQF2yu0@{aT|2k+Z(P<dz|MxcYItq;gV66ORLwPNYCpSltep2C zs;z+QKXfv(jTZuBHz0*_I_Sfi>g>%IKUGEk_4O}l{AZK_g(93M^ZhgepYhu{^q&z> z#g*@bsD(YXqIrT?%5zwW`ok)6Smsn?cf^jx?u7o~5ITnMm7?U*7?%0+Y~W<4`(G{< zSA8TBH|DHhdR>_G|GrjTpG3}=N%d}U;v2#w{^h>E`ItWWe0g7bGR7PZbJst)mc5m| zAF5IM>+dfK{Lhg<aozDlqW3G5)my7}&Z!C)`A3bCNBHehTr+>2{3V3{do>|b>iD7i z9ua=&*8o5rAApREgaSZE!$LztLq`W-ARz-#2v7;*iD-G$6Y|jTB{cGhY3O)0&0Op1 zxy7~2{ptB6T>{Y6Ox<P}+yfhW`$+g-fh}_T;}Qi5X6Jsb05Fk|09ayxhxB`j@;bR; zR!staueqGYs>GKM2UyItnB0DLQE(p;8Tn+;>nQ&Nt)IUDvOx@)0J_DMtdF0I21ik+ zS4&OaHA~?X<obvN8iZDDSt#i~vb*K=^8ljEHF2&W{4qQ|<SKuxc7`@zbw4=Y73U!K zBu~U<cIQi8yaCd03hh_#VjW&ME1Z<<WgLGb7kv;MSa+-nSObovMuK+hCnIVt%WF>5 zUERd+2gZ5h+bS?DD$7=8N<D_%I>oUniY~Qrw#M27sQpouB9WaH`Y*z5Zo@O$CawSw zQ0G&WHEs!>Pbv}u%SIt9E35{D$I(Ns80hR8-%e*?$0m-tyf;)2gZrKgFZ#ssyVSih zur|nLTg(&2#Q~56%henwBd-fjoySZwS0W+Ldzo|{XV<gCr!pG<jRW7u<*tcyCNpnj zq$F4D4qFc~9}fNLNXqObkr=MRs*I}-Sl-8H#=S6Y9hjfJi5YxhCzws_PwTQ!e6HdZ zs(#!f&kVr)npyp=RCJ)yk0&ETQ$40S<bF4VnHTD-?8}N9BW@~McG+4YYhacMsk_z| zK>qv-AXpUilYkQlJ=SkNQN%doC!<+k{RQxtQ=hT9xN#7~M2p$-Q8mp%gW|bsAoilQ zAPus%eGQNTpDMt{Ze=zijG9sl(C2!^4i%A5OM@{FZ$;g<5#_EY5%5{>h%yRKmyTVh zqAh~D(3;^fjLTJkzpJ1wdL_Cfm<H2Oz_w#9>&v`PEunl5vamIKYdKyWJN39#anig+ zMPB#YFX7`=IhrO4uL|PG@XF1f)DK}t0OfhVpG0*z?3K%#KLQ-(pN)&ngopY%y#U+5 zJyQg{MOJNBFS82NxG)}fT@Sw;BQKZUxFqV{^BMNbk9CUad8r7*P3UlYZ+c_OsPJyw zeR{vr&R*3N=Az_A1x1a0<D+#y2$^$q3jOJDkn?HzC+64eA?6ww$lte*hZVe8vfd%f zTrjVvf#=C?4v13r(dYq2-Fi>4(L1*Fu~v1?eos)f<r%{k?9{t9X;hfLcv|Oav%Pnp zOEgnB9i{7mIU4o;Y$rUIWkI)^Y*ja_KtCt1<P`E=63C}#272EMC;IW^-d1$9W)7EA z84U@~)rFYsQ+hZ<VuE~>T!F@L`ZeZbbd5+y7qR18`gpyX;zplk1`fCCLK0IK391>9 zBS(RVUjQE_tsLF{g#t;j6UVEwndS8nj&V16(K-GhO~tt3PNs>_AeKGtL+AIgz*=SH zXH_a8tFqn4L#&n#<hqbR8ge_2>)4h$J>};XO9)S2JFFfCYBQo4$Ym**LfHmz?fr_s zlQjL%qxn`!RD8-Q+<n^yk-~}v(<jnDcaURTo*^?q$z1wriquq#xD9WTfqlR)fY<V~ zhzVbTf{hVci)2rl3Y0+1tMDaz+e)3=W!^$WAgHlv1w`2WU5D8xGa5k!4-3SkpsGNt zAjc*lQ*XQOLn2ajPv`9$23h0-C*SSW&_i_1v$lFU@8LB+5<Xd7@tCxE?X8}gdtz>q zCwp+__4lR0@Hu2kS=-8+3hO!;TX|H1(!NS{r`U>_@&w*2o{_&a4d}?t_t0#Oj<kLW zv!Ekw-RWY!`+a|#-xKQ{=6ARHyQj?$4Whlws|z>Uten!3??t~3i{^cBOr|~O!xL{g zp}H1N8=|wV5bX4+-`=Bx005~=U8`V#ev04IzmKZd)TYU0;VoOY(gU9SP2$3x**)^J zM~+=BCHdaogg)t5qD6H5B~36d3f_(G;*)~%9t__%<{-%q&1P5kM$0@+%ja&;x%lkx zlJDKOQx!iRGd~OmY(z(@iT14*Yie-fs%Q7MMq;@^)7iZmvFBAcLl155s1h%kD}MCf zpbC+$`nsx0U0g6+^Ah?hNQbK0*COC+dA-fb@jvoX%Wbm=_9yJDs<3_mTIJ=H8KVNi zt1xtdp|A6A4oMm!<Na?Qt+EwpbnZC3*S4*t_V&MT(gn={C5A54R7QLBYfywJr>GS> zZ$^qYGfPwU6F&R+DLcH<jwncawX(Zm^TJ{emVHAt!&RzZPzt=zE?m%@^Eq)=G{sm~ zCoWFNjEMVLmmN2!X+4?=uU~i-g{R#X@yI|Ad6k5Z(ui8mot<@<rj;hVqS${v7kvqf zQ_;@8VrB0YYhSpYox^;D!;lS5rMm!euye8cbJ$Bz1=YvrSoMV^RqPMurh>e}T%hmk z$^u}*AU1Caa2ch5$Tu|2TM1k0a7qQ{LjI+eg}ha8`7V;a_bWx^95(m*RWL3$NI#?W zRe|SY`w!$B^*6_r3%Ym)7{(*}kJ&$;DYNXQEIg0XT&S5-+XcsQHmSweDsqpN*|U3| zJdTs%U$8YaFj@yUZ&Y#3fx;IfxL$m3<*klsCw+*bcIC~@(W6&v$*8&&F3Wv#qdL7o zOg>{^GdX$yT=MET5?~3)zOG*-V;NgqFPs3sDBrJDR(Xcfa??p$WdHE0*f>nT=uB|O zG5x8LoZ8Vb?-hAfArPlC*|?(pG-aCIZSY>gwbsn{e8sB#<FqY+Q!^BBV*6jgbsDU` zWcZkV1#is)Y?Nc|e&G~-7cHRmM71zvHRy*nGQS6OQ&qig8(vB@y&|LYc%@2UG;H06 zZJufPa@j?)DI(_b)d`=U%*M@w`;VP_yjwesh4KZfsvcVZBm5=B=el-a@N|wv<wXU^ z_yAm+!$&RxDaliq-p!ZfR(!v$px>llxzK{jO_~36-}3OWLU|hz+%r4bx?)`cO7zWw zS!Mo$RsY$AoD7!p-pwtg#3Xq*b#v3qkOeK<TcX*FK@*R)o%g%;1u=t?T4&5f0#RN2 zt-}ak<XfE1C}L&d1v{5Vqmv)Ox|97Zl9%9xRtYw7Tj?z7&c^K=?d&DvOARS9I_=5z zQ7qo(S8F{%NDQ~AMRTHO@#ykNx)HvWg?MVN27=^C5UHjLZ6vaowXh;pS27;*R}ey; zwCLJrq(fR|Yu9Xv1o7=@rZ;7;Y`T#~qx%mOIIvDggubydTmg73NqI~vkrTtBCe{j= zwD)|{2ne9o6m<(Mb($M&;+M8Z%O{RP-)JlaJwwRRZAY;C_ZG9VjQWr<kI=P`e=`P^ zIX0CD8(;5vJ(`8*jtnwlL#-rchYixRihifFJ+izGBm{W^v%hMXC)2}ZaH`hZlL##x zqW|>f3W=o-3BFe79Ul=hi=h@a?&Cj>Aw0+khzXxuB~^n*dgiFh1JEzkEdo}+@)2Iv zWJ88enxNa>1aYl|oeM=A1J7bQ0@y!U4ergq{^GvCTE}<7O4SL9=!6$y>5E*bxbzUP zK&0EIN(=o_yi4nPj@Sx&B$7q9VS<_Int2GuBNVB6(3SE(S;5idm{?IELHt+sKD}5} z<s2?Rg)$liwH0U_S?QWc>O5i{i6tF|XJ$!9&vT5zo66Fy7np#t<turTgfS!=Q|UCI zfsl#q5!MN@(B+K9^A6&8g0x$4a=zmF2JN$Pz8E^b7j9AM28dRrWY~ZzA|K{fLvBjU z4g+^dwe`;U8e@CB;~Kn>64^XJ;|Pg-L}5k|O48Nbz?MUdg69dCL7K7M|1d&=GWU`! zsueywAhUd8QL&);wX3xE@Q#ry9U(|5^Mb~JI2wlR9!8qjk|fUuNgtg223`BwU<nj- z0HC!8<@Aq`i$<R>nidB9NY`vV26GZ5ht`GQNRIme$ay14rp%LR(hX85%aMjJ>A8G( zd06UBSDWO2H#~|+P*cW3_QI8n+vv>y$KL5eH0(G1rUFk-meCK1%{j5UZh9LeSLxjV zA~*7+RWc+(&4%$R$!M<0(D6K45g#UmLXOqsliOanBjd=h01YT5|EQsPoU9FxBGo1z zOC9v;NW&E!Axo`epJYWTOEb7x5J7sZDGHO;o@z&tX@(crp4eA_=2=dcR#+!;CJO+P zRut<(&TV8`Uq2O}N$>+RIPJG)bERJ=)l@@GfpVzZ^HHtWAxzneCU0oza9g5ETB4*J zgPQ6V4m5QCQ8bKKDSrT?wjMET0f_<W(oqGC!3^H}b*IN=-1xG!qw3^)Xc47oF`ts! zx7Rg(Gt67!zE-XzBXevPbU@CeZjN$fNxx9sY{l1ZHpES+YDySMK4cfn5N_~fQqbRh zplte@o95?$<A-gCNOAUp>f5A%gSpj)4VWu&!XMF-)hr^(4{iUgvl^F)C#)uF4C#NA zj>fz33VscJ=1yD(^2b3ir*jA>+&)ciXh!IiW}fJvMt3G^;%{r>C={3Hjl`$w8<j23 zpJ%ZW-KX;w>;!=gd!I4Qe(^3M6{0NCO2edYB-i}<P`cuch+9&OTAh}aQew8&)sHUk z1|T3uOd@=$<|Q3k0T1F=RVq?P`)e+)T;89_);<J<UkuLM^DVWPg-7b<ucG+?Zt`MK z#aV_MbB|XO=(Lii*Qu~~87(C^8939nhr{(fuDA}LAwDjv57sb~p&dL}-R&quGZT&~ z+*oS<)C0&&A4}$Us#rnPSpvC%3Z@)4rHH4q@AP!sB*qBmeTx=F3~A}TJ#L^DifDBm zJ_^v|1s!z@J~KFD428Obs7*U!o$A_+QBFX_b1g=gs=U9*tHDup7CD}<KzS11zh$)z zM|-zWeZ5slVTSk%tXh$W(tRdoY4=tUdXk|A)rz_lR>SHUuN102>s2*#E`V}68<oN+ ze7O0DpL(dQO5CXkAv5}-pB$eqHJ^qJ$NcnUd$KQGg^X_$vC~e#4u+1iZ`rgd>RPP| z?pE8}a4NIuHxKd!q#HR_S=05oW*2~{1_vJwX4|=aRYXKs(d)vbBc-LUjsW;L3Mmn5 zr5dekq}urF!LA!}Q{{y$Y62esx)VqhdU}Vo(XG@08C(gA<j{%M!wk_#O@)-I)2K}= zTW?>Z4-rEy7!DWjZR%8KS^a5;s~6SYZ<-x+1<LO8?Nu4r?p%JlL7z%`>vZ>JG}yzW zmz&X(kwky2!FjRwkO_S8Tzrw`fHQm#TB1@e7!yk~nv!L$eH!b;$D!^C+knJE*iz?d zWh_?sjtJNt-<T8mLC~2CGFH}13G)DAVW{2}8#codYvSVyt4ixC5uJhToR1BXHF&~} z<fXOi;j5Rm-XqDrkER78L?X?-Im_nCqYDa#dE>Q<23N&T2Bh|nDyj#`+4AWq8h7G) zyi7;?4>%b$#bTC?oT`^)9tFmT43JmXa#)`9h40Osz4k3{=WD?-kv?mF<o5k-@{+zr zMP{{+j0>Ye3RMN<>IvE5r54pKS=HM+$ml_R#aXwuuT&ZI;c+0Hj&bU9W8}+tpaiPo zlahVNuFZ8F08;n_PT9hcmYgN*)QD2aq1Lqa@hYZgj*_71m36&skj*^Tg4E;jxpx_} zS(Le7>fN7VSI=c_1FjO73n*)*u2LO8^XEB~ksr9_5;a=UcvknV`odYF^^?rCP!aQT zEs`&1Hyd8XOpR4pjPd3RWfrm;0bw;<7he;deC64;C8b3+?4Fx)6*?rv($;xZSqo+L zmF`!x{z)E!7vXcv**N6NYE|Ks{iQ##7CqWhigq=H_6^@YI3AQysLiu2j`KA-q7~T; zEVb(5sLab66HhhEuOq^BGIx61`iN=WVk9paXSQpgZ!|20=W_;+tu_nu$xk0#+@>3l z4I8&=Kua`WsH2BghjxZIB&N)*)(1pK6z8GH1K6tT>3etT`mu#XG!ri*Dk=j^Pf(AN zX(a<HX^`i{?H1>IE(#sbct7pm7`3i|;IC34YeQt0z8?pXE1DKh$c~vrF0c;+pwIB# za40Rkfz05QZ$I?4vp|t;Lv)A_`?h9e-?F<DpNSi#TfO7u8*{B>ust&Nu8;LT5kC7t zV$JY>kKw}oCU5`BiKtEP@fi{{x0IuSO5pw&9qv{E6IgTq$R${E+sXR-{?D`?T_iw! z_OdDRjX~jP5SwQCg6Xl@3C`$D|Dr-153VwV_l*k3Wc@&`8m|MPU{W2s4@d7))6(qt zlXD8-jCl7-|7?-w>@jE7-^XsEZe4HY7Brw0YA_8;MMvE3FA{N90hc;ZY37xJ??i}j zPgZr9z&IA7gGCOB9~jB=ZPG6Jx!s!t;`?^EJwD5H*5ro+7n*Y=;OiGCEF^Z<A8Oyz zOx057S+aQa@<IRu6Idnsl_Z&$)?yx2ByFJM9ficNh{>$FBNi-iq@mq$`c0|2oxd8> zQwtuZlB)7zu^RZoZ;r6-LACw1!}I9QJXjfAK7jXzfUs$Bu`ziB!p?tLU7@FMIXr@m zz85~HZmo&59>hla6mA~jd-j8X&AVpQlZ#tvmQs>-LLlZE5W`%M?lEDChHZhV`Zj{( zS?CH7iN(^Bj<vteFx86EU3Si1fL8A#d5>8<Kcj?UQM>CBP%F-F)?2tqq?oKUrZW-Y zN@rO|MmbE3nO8pD?uc<J^b*U+k9qxmQRM1@hn!%9t4Q*mgWSj_!Ue9w2#aaepwuq% z0yZ;gN3By`xbR%N(P^(7)Hj`EN54?prq)6l9!}0%WO*16t0e$Eb;=tQEk%isM@RSm zU^eaGH3+Kf%@a`d2VmGK98{NccWY~vm6ioA#|}A^J-$*auj~hEu_a;(3MOKpPzFoY z6fUmF6?dD<klKm7TxhSgSkJ&sRd6F$m-&pJ?BUsvP?mXwvHT!zZOUl!pdH{;{tHkn z8NXtxzYji8zW2jXF0~u2ap|Ahvb&djrme0X3;CKHY1cXy)Pm!bg5D0f9%6FzArWkQ zjUrf(v=SbtwB#_q=sJU!|4uJJRDu1d!RcLb?p&#kRp~B<ZN{oiB?RX1xCh-XCO2eA z$!{p8)J4S5jfZ_QYuV)|<@7x#%5smci$GKR`^Tcy35@{X`v%f)xkbE4!P>V=c1#k& z0Dq7QQDJ8i&vlrgLZ2o$V9W^vGM9<jo6s;52x`$3T_m`~P;4x9*sg)vkstda@&@^S zdSaX7B&MNqC?*jFm|xlS-62}oCGn>GvEPj2crwsgh28&F=)h_JBzBg01#hIdEMPT~ zU1xO(#Ayj&Mb7t1y={wHBC-|o)`HXH(@<bmLe~ejkIyc-aW0~yNg@wlKW-sl(<xf3 z@7m<XsRb^CzVq#0sJ1_>^TPkY@+Ag`BpPyBi(?J7OQUS5Z}RPQpIuZ#j$>nf>(^d7 zp(<Tbn9%u#fvC+}a$P_Hi))f%nEY+~e$Ek|{r&eZ-r`k1#I%kU?6R*zUoZufi}|1+ z@*0Yc?5-}~6pL_nzJ<eezj_Q&VDpwzM>Q8&I`G{NaHv}>MOBN#QOUR^dNYnPGA2c6 zFH|GBnMb63p^j5YH?2Z<i~&?@ZGNRgDRkKT82h?pRE))=3C&1TP~Xm+a*O=crR>R1 zF*-`FwFPVeKgPVZwfn_7B&TX~{Pt5Kjx_Z1eLH=Ms}ol1lx<Y>qD;%|BF=n}*b0@w zHHyM4eLVnlZ{;SX7|J>L0JyC^S-u|$#zU#xZQKKja$Pv^d>Wx!AN1pxfV8}H?6Ovv z?pc9Wuj(5^j$56(dtH0!p}k$o=rnJjqXq!<gC;DZG32n>h2FtbJK~BEwC_^p;MhJq zO!%!UPG)w1<V%dy^4y1qRp%t}i{i`^nwVVP<qy6Rvqx+cLK%VAqS<};T}P3PljlG2 zG#(MKFxHA6&^)_|xM+P?B71y&HStOyR&UurbSoES>EISgbXiQuRWFyG>S#IRqj4mK zn`7<c)+<$ormN;z{@b{(7y3Rr0kOj}Q>u~OOCT#>eXu=Me(}w|j21IRQYpH5ZWGC) zI3-i)fmZ#_?Pj=Id3mOwB1$40*~{+^>%>TOV`@RPch_!XqF-4vW2HmD?$)}<p+;C; z0ywt29A{B8>M?bxx}NEV1FkToed5BH7AC&`I82OCA~`^!Hao4hN5fiQo7eUDn_bq$ zRe4;QDL_@B9aM;yXzj(!r@ypdeoTw0-v5k@{pr!RDcO`mzdqMZ>yU*Narvl>$y@lA zg{RXn3_hBv+VJ+y^K*LkkGs&ax=cO2EU>LTCdP)<Qk|wfBK*6ZuyScS>Jaib;5^X= zqj_P4&=|6Aygxeg$`oX3*7{WYp#Z3z`v#m*BGB~4ZsBT5VcFO%KhP_6s)1%gzDBbI zJ0<{{*l6ypz0L@(cAMzP#%U(iS1bdS(9!8gt59aP&;;l7mwfY;<51Z9+mH-umd<`r zAUck2aAY-l4UpqArC1r<aP{BGQSUE6*Sro&kLn7SjQz&*ol9GCs56YW$lGX){TKx> zgnLmB`|+R~c(4-JsRSHBCzw5valwTo9RAj{EIw=7vmLU}Ohr$G*9!Z(Iree;eoU@C zZcsbaMdftZJaO((x%D$V$?1=sw-Vt>f3dqhWoXX-NoGB&V!XSk$yx0r^K0#LC`vB* zcaBAYi<YTr8oWn@G?m^Gj@o_W1{r}#!{{UiCq|{|Bg3dj2eq8bT<PCf@`F(uLNvM7 zmA5UOK5s9_@1{jg9}g+FSUA6@N9KpJI1j|}d<9nABm3csNlrD1B@AI7pVa2O5fx9a z0;_rL)B?kT6*I1;RU4Uz;{`aivp8^eM1pCkdPseOF4C_WwCv~i`wDU$3y;XMQ<~+$ z_L&XN%t2VfppwSEAd~J2A$ZTgeA^<@BLg8I?7oj11?=hXyTfx3)`@%Pu^J+Hy=A=k zff+IDIZ%~d)mE5D!oAOsMgRmnY9u6D!%X&Vlo~u{y2H#~CJv9z)b&Oh3zs~!HSI6t zc(GKi4gXGhI4ttbIomDwjqLwm1P+LGG1p3q^wjxslZHdYp;^`$#7!NuEfy+P#QeSL zCI#PUIa*LzH~%K&CUyn)GTo77@~SSmg$`t|%Xt1kRf!Vi`#tcoPD9rECsH}I>H3wY ztAL<hOwYI+;VproSzn!6|H*)PWg)&qFRG&P5U6seZfC-AFR1QS94f>LR5`>jA)QRL zS{L!nj-xSV0<OYXV{kjHki%Nu_UYJ~L6)t*wyc-Pz$foWV<+fv!SFI>z?wnvNa6Eg zejQRbK4Yvw%%Fx=>?OhSdW<5^2%o0o+auV3m5F5(@KK#J_zFAiYa9=@>IM_^ENyVk zY@jZF$byw741T=+yJ_X7pcR5Jbi3n+dGo2__h}DKKYasJgatx?^0xzZhpw<uh4_bj zVQY(oft^Hwo9NDUdfC@5ZsaPMDSYja215Be`Bc~f^Md3+`2(^YM``wYln$S|Wg*1b z9G1GQ4k{w6ev=XDIAnFj8LL@e3ukkY>Kc<HLxUm0E*>smnBs~Pgqyp`3o|d2L+jS6 z#Zx+?Pk^MN?&_9OS8(&zj7U!U1|QPDGaX*pI=61k;C)g*i;e{0jIqj}{BX6@0^icV z?BZ!9E8CG&BuY@#V;F<i()5LzugbcNFK)083Z4iJbPZOC=JOF&{J<)M*7`^a8=m6I zAMq|#-S04}(%Dtl`J|6f<x61D#N;!zT}g6FxJjgRI!8Ilu)W3q-Sb6x-dhe#?mQTD zW{ppvIpQ?BeUj&SU4?3C)bEa)Sbmgw;zQbV+wi>3-mf|!O#4oXlBDok`<Zo7su}_; z8UDms?k7qM1gpAJ4T5Aw7WIcwJ{?cn<BB+@;`NkgZ6`t&8?xntvXoIJsLGa;*@wb( zhX3f6JTpTM_)1&VR)#&BF=~<MH%p(>YvxG?d1k4N+trB30J_r&@*~WZ>E$h25@;xK zh16|!j+Io?QQ~|$URMRAzI+!$=U!uQ{m+Lq<|N$&2MdPD*$X-}-c6+7KVzo%ewWO> zv%bIOrl!7g`*B^wj_;2Tfw&TcOLeEwlb>Rl?46}3BcA!wH}D8EWF|hZvvY!q53t@z zH66aQaO2S&j?zm@kQZji(XP1Fx227C3=FlK07H>r<lzL%&mg>+1Om;_KJ2ek>QplV zq!*uUJ5Jz34)gkmtXn+;JX4>sI8@|8uM_{gu!zz+qeX0ADb24M`#^ZeQ<p7p`{4Te zm)#v7$})xo^4_;Ui)+=O57BN(HWO%WdTm<fCXu>qrXIZUsTLSwRei9uu0!+RYz^EL z^VJQt3GVzBR(GDdtcTFany&(akp{p_9vt@#vyne)U|tf>>FTt#+E2MGx;A7DIkH0N zWQ}4Ip7^Q)q|B*<%<cGV+C9QX|3$@9M1<g$3{+B!8+y1}sluAqvepn`jv<CI<7UdJ z4`n+th^;Mi6?x_r%PWyZ?uc<Y^=p)60l_7N$Ym_Abo*=DNmD_N8&O(+L`4}+5K$|P z`iwvzwJi`6XD2G$GewZ66;?NNbJL{5Xx#)JCfu!RpNT+B4$vMT3J;xrfw~g`k(gY} zc#N-p;anc-N9u<0aA$e2FGQ@vSO1?ajLGh}%6GvHb$-PjvUXtjCH5^<#cwVPgT4xQ z>2{9qgxfDZoDr6c+B<W#uB=YV_!Jk<*PXX63|md<jZjroHu?8(eF~#KJXqW)i$cQ{ zN7y~<u;f4~Xj2jHA@M=mTr#$WyrQk?8o}j|*L7OT%k(m62f~W^p4SgvJu%-XVe8o; z5u&qq_PEv?!C0u7cSNW!KST$EHlP=ygWMjr+mxBYO#L<$wy)dA&O<A^hWEPbQ`w{* z3Vzj(@KW{CC&w_n*_$~7pOUsoIiA0Zs<}l26K$lINYl0jqHB0eeMp%F+i7@~_yeI! zs~a+G?~2P0#o@R+vEbkH>L=Bt#SI6;Bd7TK*5epGSb}b5f@&kelpK%upXv^8?(imH zA{MIut&ZpQ#Rz?=oL_YUqSVnSQX(`tp(I`)753Xcb%(d>l9FGBS9T2`dPG%`-8}e$ zp5$eiJi|`niqfKyzEAlMmIW|-(Ht>-P}-A;kL$ABHY_9Rq(_U7$n<(GLmMz`>fM`B zku`VFAk658Y}KwdEQ9@#EQr&4?N3W&Da^k&auM4P`GMwCbT0@f!lDOW4ajWKyArg7 zy$M^BazYUC{*Yz1X#YlDlY04wOc54}DE+%E{wbpL@3MbY@s}(R%JRRPUYv&$tfn1} zL%spsDO+RKhMX*#dHy2&C6E8x)BzF2lUu{`y}8ae#=rjkC4;~8;D3x6Sl^30_-O<r zibllrh!xdKQLnH}ZHaoF{Q@X<`%ONWtS+u8tOl_=;Z(KoLbtTn$PHX99eb0T389;# zf2SumqyL>g@Vn68=#0M${h_=5{bmF`{O>m-=>Pdj34gQk=XOR%M1x_7^Kb)1BY#@_ z!`44FBTauw%|r1I!heYAf2$wSXKsR9DdzA0q5J-aboM`9=^qLF8Gt|HL9Ax0T7D1H zpE3K}82rmX@sRnIjLV4a{~4Wsx$>VJ!hbOE_eTGW5Dg;Q*aIRg>|J-$5#PPRipBrF zD;GCl)J@6ojX&4Bg8!dPnyvw(4mB6WUh^G?x&Dy-KWRZm#@*lO9in@MIrv|=e0Vu^ z;cSyt@IZI_;C1$HN&i4I@CduU1!&}hGYST)jBUURYQ-gfb`3B;;9QaLt@L^2Z1~3B zK6jz=`=V+?zW@jLwceNF-AP~HoqYXSxi|hPsix7_MlU3Fui?cTvH{GD2o?)nxPc&+ zBx9Q=M`gFm`uY3uyP-O18%&t^{h0Q}k(#D03g|v}sM156s3Shk58&tIvZS9Jw5Gdd z-$d&D3LEmwq4(#NzNdFCd3+cQeJv-)wz{zr1_!!e5`jHey&gqp1%$Tyi&<EXuITsE zNCJdWFL$U{5J^0)Kb(j{EoIjeIy)7VI5e8s9zh<)z-Qjg=G}SSerYMrdycQyqpWQ& z?L@G(j<i|3-|i@StAqt~JFV@YoIlL{0;r}b*d`u!`>oNF=00N;djVhi1`58!Eb1o+ zNXDqx?abnS=QzB2dG#=*eORF(sl^kt{<JHiUII1ibN8}Kd*P}=8Ir25N%pGpBHH@; zhE;>QQ>&g=frX6*-|@rXm^xwL=AyXp8b%{|CVPF<{m}jRC3a(PWC#P#N_$%;M88B? zzaEtaS<Y!KX#JdeXT^;-W~?>myPmWB3^&DTvoJXVKVT)c^}Ku6@A<^F$;DK&-_*jD z>J8q+E#JB5gmwM_G2ex)86d$2i6$JJvR~KMsNRyW9_ZJwj++(&J28gk%?1uOIy)O) zAeF}q)E8oGB~i)@T9#L}PBQ0BM)yoW9D`7wkr!64#|%};$ba@{if1iQ)d<qK;$hh4 zyU!M|P2*O?MnrxiY-(b!Jle>;B*e^)tjHDgFro$QT)hrtlF3|}+y3dhyw~Q9){t-A za|CB53woHa69~Y2gUAs03t-(l9Ti;P*01nt79bF*MTo>?JENaGQVZ$YQZ<|{&MvIr zO1_m$-)mFJa@b4%4)nnqWVD+%GH8(@2W(!d%FI(#3bdf$Sh56!JflH5RIvZ4++yWe z;ML*1MNm%Rtr@hwl(q^^LtgK>wZ0WFu2F2b)xoCx7Fsa3Awp5sm5baC!Dkd#_pEpi z=-GQ{z{;Py;I}2mj#xtLMNQvRK$98MEbIYh@hV*iC~N9Afoeh+;Tcb}I~8XdegXPS z)-%|GQ<i1#E1Cwa^A0*9dYe82&Vv%!N#@F5Kh`B9H$!*`<#{aGIjVZFXle3;bL-~? z!Hs6~(J(rVz$!~KVr>9gXJ!xrNUQA27~wD0!fQ5|-PU7vUCRmet1q)I06bik2W3yL zDRb{}YFcHk1Qm+QED{z9?8V3TNBN&i%NMq|v|~)aYWZTFXPd{aR6NZWJAf1f!je=Y zxDo7O44mLJ-Oo5V`UM#5(Q8Jxv7ZBr*RIY$V8m0BY93|Il2?w#8-0*1t(u~)j~pZ| zYs5#wMAJ!6H%^V9U)(#VAVAdFS&x-bbb@)_f*h}KHGan8J0B6TYSbB8BcWwzZP}$r z_%|DJHi;C+F@D9e`2#uFGoN)+tUP7T!4!iTATIt9Z@^n}673#>)#e220{htmd!ym~ zK&wpSz4358KtL1JO=$+4Hy`{kIG{0*^NG}3unN+e)fKc|VQ+!LHx1nbG2tyc$lw$5 zEh6=1bUM4|d8~!@3V3hqi0`M0Vq%gXpzdrh-F0VPf4GjVX`7n1F3_0Or8p9rR6_H( ziGgZSrVT=-uH1%Z<4}O$#dk60sQIU@ah^C)msopfzL?Y-I=VKoXCk#@23HB|{!>?P z7K%-KIas6K;)oll8cQZ%-Ok4$f{gDLV6?qPcDL{;1uFIJ^LxSyar?et{y=QOsa9E- z=6LwXhd%Y?qe}gmW0rmM5Fp~5m>4R6Pv(1XI^k4x=$dT0ANZ0;y`ounn=N<_8?@VZ zH`VwHFt=p&Ntn4~8^#3fWCWO2i@@BNiw?fW-b~3Y*sh`XaI2>O%(3d`lWXpNrCUW& zOBlpttMO62$1&GuRW3VHWI{R1Y1JKSGnuj}4z09k-15d<S8k!?j5ZMhxy!LYXGsoG zC>{9tSxZ}&xD1{pNF-yI*Cj)Js%CL+Iw_Q!+stI9TTsZEY`pC`>L&PE)&S!d^0RjA z<W<mZK9!iJm7RoKC^1U--pU>jOS0vR28ZB@x6S&TEjen5EyAU*t(jJ!ep@WAHw+3* z`$E!AagrTqhhYiP^4~_}+SDp~95~pYOcA<}!4^0V$>@xY@=Pz0P?n09BUcYd1W_0n z#APhIX1j1(+S*iLKPnZS1CeXk9(2l^BXMMf(i4zqY7ukI1hm(V;%jO@UIm~A!5O4K z0nxp~D7rSyL!f<-Ko^k^rHk?>x7gPC+HL$d0rpQ&1OwpzurKaMKEmi=ee<q_TXle2 zSj&0#hrEkR{FE-#DwR|n7Z3rtnglsvVHNUHusE@2ZiYUXqt;o?AN|mHc~76CYxLY= zlf^I!Yww!nfLvwg5ZzV>GQ`x3G&IkkDye4g^9iyVJb4X*!HHCMrS_m1c2slmjjC6& z`O~71RZCjefE5`=R!c0+Bw30c413(=e`iVwvPv}VjQ9QQp?ak%^7#IV@(hlb(;$#3 z%+3QcvtY3K#c;xP#!hr_auNqqd;G#FlomP!<AOH0Ui+TB$bolyN8|R+w$XTHaM*gv z*Dm;4>=|66r2mt#+D;Jfw+R?WyC#`pAtb<p)F+Dcyx#k1qMW;YQ;+#%*LOObLyxwd zz4dlmiWgtrW{6byB`q3g@ywEt>`Y0{*=dz>xkp{b@)5{<)bo8?LoM4#g>%7_y$Ubo z%S6L&kk>6f|5yPNtS30W-W;7_UqS^V_Lc%xtYWH@*+yXHl>=AEen_CF5BwRfZ&4#= z{6V443{x^oMGHl5fIuoJH+q5G4jdGvqH1`-C;+xGQ}pNCL5F!O3;G9^ugA7Hqm|^d z7AR?bXm*nOjuWnLkDGN`EDN_3?xiic6}ka_mwp0P8+1MK^llOv=mhNBZDg6CF4+?n zQr)<q4_C9TK`>}PQojYf@2#6%3C}(nBAVgf03$(M_(m|8ge2a68ZOtd5;<ee+iTP& z)`eH(aJ%DU3kVi#B0Bn(e9xPMD<BiDM&b@9%Z@1C?XIx}umvBZl1pke2PCTjX#8c> zvcu<A9fJ;zz-sxni-Cn0QUKfrs5jCj#MGn4Qjh#<^Gk8O$B6}7r?^F<H7eF#Gzbdo z{752>>@8$h-5Fl(pBESn1E@+xlNQJ6L2`{?<Y6kc$9t1_UfLkz*y3+B437)AZifNs zdn*@hZBJO#@Gg1*s;@rRT!g$2jA+iUyr7x3+rvG)fF#yh*|4I>%gd-jmrd*^7{Rus zm@--Kiy>1|nledcSWav4o8*L(i3-?&`;Qej?$aJ%Rhhv8e|eNM-XO0LCl9Auksy4a zRd_`aPirLWkx<H31iL_y{k&)}!|SO=>O$GBHj`34briD`hoA)k?>@|7+PQ|_=kx33 z)EiD7ESW5ah$-tI3lqn3FD{=*9L#X5l)<`KlMdQ-#oYqGdz{WTBkv>n6SF8>3n%r! zk`C(hE9-B*852gz1+x2UF>^6>l&;eedlpCZ%|x?u3p{3E#f3Ke9A%rvjCAjCK7&{L zfu1}^sg$5ti%yId{)_$cCQ1Wb`5jDoh6JTs6GRLZ3cC$rbkVaZ7021Ate-c!86h1W zLZr?10P&2rkFv8D1(cn#La|vw6+2(=&IJVC#l!biI|JRsGy0W1nHE}ni{0m~3)z|_ zbF-!{Pr2EI*u%c)k1pAWt|{UdB@=Y|Mhul^GZoh)fI3;PYgOb3ni&OjKXwM!$`9OH zWtq2=_WrQu{>n;;2*RbZTyF4q)y?0hAEX|UXG-org0f;=Vn1&aMyZq4gSqEa-l4z0 zLqo}_kD-0%TM&<HJn9Gm?ZjE1w$+RvqHDVroa<e++3>RR3lka0$~xLndo&k{SXaW< zSJ7w0Ld42_E+0a&Al^U?Y(%PSjMs<dRmVAJxv)fSo8pOArS0oj^NF*Ub|5lzMSZth zGn2%~Bw^!0R7ZD_s*B`bfHaB{SnTxq57(QLWdq<P_0Q?8kB^i2eA;6qGDhFOvRnuH zz?fZ;MQ`?sSFUd-8WY2R0oG&>qeGPiluBAcZ2(R8RHYp|&%-7Zmn;Iw0}g32r{wf6 zh5A|Hd}?JCvm^)3J7{m{?8=+9<{Q@VFKJ+qu}}K`@-?42l)=)=f^<4uBzBSQ#lEfY z6YOQa<4Goo@@)~#SyegtHO?h|NVSDu1l7Yyu0xJ4U##uDuc&d2zNW(+F#d8bmU^E3 zJ^S?XTJHvDVUgV$d1hs_kK2yFT13^unrPN@CKtP?)<rxcNI^jMR@LL1w@iB@{i?OW zmPnOIbbz6+#vw?!S%KGUci-GTJ+(3tkv*LWwN^~#s~4UVQ)01Td2CGsS+;+HvO5Od z*X8yRskwy$k9h;5W`8_6pK<j{bpPC-nfUg{V#_zIT}u{o(ZK<|qVVY@qxt2F6S8$D zE$=YzHOlh)u!rv{d@#6PdW<~tH{X(nY$#%zjJ}ZoQ&}Gm4!_Ptn!W{MUJ)Q3kKRqy zt4=eo#4a+mXu9F(f7tRiI_~P@6Yn)dNv|x=K)!$8AGG{@U(Z?f$ajnQa%@`2sFKPM z>fw-==5tTOj9C980vOF-JS`llYVQS>l<0Ab`d99H(I_I*uN)ZO@}e&2G}+TahG3p4 zx_gMSai-zr6$MokPRljEobaz@L+UgWU{dvFl#ZV`Q%w%<coz)PS4;0VO~*)#`+B(H z4Ar<y<<&8bj_syB4LBI<i3egUHj%7ifm^ynU!VAs{Q`U-3V2Q$7;qj%kYkqO&{nSi zMLHtmn*lGw_bVvP?Qg(!qZ#sJ42KOfD{(r%0GL2pW)%m!UjXdWTJq|W9q$lQ;Ulxp zP$7OBPD=Wi-j=BEs7w2Ea(f|57BFH+`0^ain-t$HlVWd$&9FQzFC;E|PF7Qn&u-*@ zlrk9Imx?t1vyI`Dk`}+r67h7W^tH9!HW6Ixis9h}_~%PR(pLWW_PA^f3dum9_L7o5 z8_Eg)<3nlC8)Wadm2)$)#zmu1M`G%4vtxcLZ`a>iuo`EwNRxpzBy3%)BedJrdnVU+ zUHRrb4}70N66Yv~96SUy!n+1;rMPjE5q8iWF8pYVdnb#Pd63!j91-PsRdliYE*^>1 zsH~f6zmhfMKvcC9(=eO2?z%eRCa4*Jbw~HUI0x}mYDW3IAbmdZt}NU_$6jBL3{nb5 z3Eu}6ZMDy*sCWf3Ri`c(=*(0%EbD@-grpaNs7?|@MzSM~UzYJw^aV#fcd#QpU(>;N z!uPQU!;xt6R)$W8vs0VpOJ&W9HC&9lt*k1P-H6$BDQgy%VIXbdCOrC<aYi}OV8u&W zxCC8A{4n*Xy8zgs4&XSu)KtM-B8)*!mQmhD5tzap6?PkvF^}^Gp!x-o7y+K)ll&0y zyh?zi?B@B=D=s|W52Og0=z;msZcIWk>P_Ydyiu&XB;%BB@$Ri^au+pWK7;Nc!QNq7 z_E%YV6B>CX5F)C*sq)LB$|<R%tAG(?y9#@_8iD38&V;hojjWHe)d}b7m+W{W?NW7D z-x3g&W|`$^s!<CI^JnGOlwA7-fTx&vLRLCxb4pH|Uk(cmcTp@xYJJ*~lInOp?VW0E zy`6FX%~+7*)tB)l154$oGPsa%*40Buj*Xbyr4UV&)-JUAzV?rUNy2;U<=7vQCqF-r zoY!>jft}&k30Ol~Vs52y^);qor?&VH4RjXn*}X6ToSF|lHNi|(aKNxVFaPty7JYrE z0s6RC5EfEerg!*|S81l#yFsDj%YBZY7V~-Q?Jp#MJGvO)<2lGW3c1d*L6S3c3gik& zKd-o+r$t?D-c67!2=wDw=Dg_z6>Hj?cuLr@N3oJ0UGl81^Dk}$NK|QVV5}}OTD7rh zG|`?j?;_~gHAYT1YN~Q&m$B+Yjmms81r->NS6mMns0|3;pC2%!$#L)8{Q`Ww+wEZP zcyC5OuL6?VZl6~XbH2*Cc{lib<|z&0uy$V=cT=6X<v9;Wbcgv{f+d8)(d`wE<CUZf zNJ+Ic@tiEvyP=t0=xAV0PeU&Y{_uY8yirGM37Kk4^fb^%wJZ#y(RyA5*!7l~S|A44 z>8X3DFN$m-Y!-&OUu_MzMFL6k^d1p5`?4?>YTXQ#Zm%$<@6F5wg&Ya}92W=WQtJX= zJcb<&%os>Rb_>0ZL0xm_xT<C0D78cf=Hi!xs-JH)e3it-_+S#@=BPEc>jz@oiHGGg zzS>S4;>#;a41E$mqg2G~uPpxd2J2zzPC@pL{DBVe3m^}tnQ}Hc0TngBA6s7?x?_dq zA_Ct6{MHaZk7|EknH<F|o?MYTz8kYYRs6T(n}G@M%FmRgacGxi(>Z5N`tJh&dEzI| zn*XT>2gb23H-_n@5AdmB&VlQn*8lx3{By_uJLj@%KB4eIwX1N%>|CP-?I!-0<G(~c z{|;~OSsniu9d3RlhGZsu2jnI^T&kA`DN9>_j{l%K+-a=*Cyt+??q0VTce20Vqdug* z|NS05XZGatd3WlK(eHP&|JdW%_xe3Y-A2DDBv^5gV<tyg61UId9Z1Y>T{TGFvON&| z(2T1_`pvd#?=))_S2(#MPiM3i6{4_!&t|3t05YZQ8ed9E{l<qP%L@S{{6+;65rGZ1 zhOGDy&`Z1cApX>&>o&om(%*q7Y>zg4o|ug!wF$$uHE`ziBR7T-FkCJKtkgl8W2hD> zk$*AuTJqT_tV?bMX;OBb|El7JDT@RGhkMkILtfOn)TtIv90-)Syb)dHLfNl{ixFSg zC(W~10y3kbZs%m|l?Qa8o+0PFfs(a10yWlZ$Nqt!5ba5yBtmoE->6K<i8XYkDg;)M z4p|<KtZ9ydfYg@9_sk`r0A#$dq@(g;^~-3y%WAvZ8^6)w;$p`yr7K7L4Ht`mtnz*& zm$gMeRyF@Xc7xE>a+{cGpP*iODJ&z<!GDmcf;0#OGiv@PO_-h>RU5}|fbpfend%!> zI+S!pMBg$8ES<KveYHvymhcT(*1T8L%~=t!Mm#Vn@ijCPfynH+Do;d0r)LFi6Off2 z(RgBVk<MdDqm;EZ5SJa(6RFxF>KZCfeSUl-9M*e3%WbKGK!S#0F~b<S{BK94_DMTG z92=jqSXZ~7Hif(hb{Z+%1BheC2O<!euuVuZ0(8xr`p&0Z36%iOTZlX0WC~y|9n}KP z@->NbKq@tUgGYbkZ0AAX=GmK0qwWu72n;zgqaZ3MN-N+Xe<J&8F03#SPWbT;pmRXR z>R3IIwN|W6Yj;8VBj~6Efi7k}L1R!zEPR1)g5tI4eC~|Uud!P@!}$`lo&$`953{+$ zj~BWu`9~13Lrz5Vk~tA^OOw6Ft0v^<cTi%FL^^U0T3!6U>9$s(RrYrvE9H@J2uXJ4 zenN6A%R#AqhHpBGs$;f+Jb^91hM_lPvL-T6VL8?)boHe(#KMi+Ec?4VvPV1CAnxa? zurLQSu!~3l3REM9>3O3M>?8t1u|<gLdyccoK{CDm=GTv~e6=cbn%5YxsS8W_3l~hv z5Bx~cs&%5<M|?A1JU*SSykI#wiXb+876;laR*SY^v9=0(obr*=;XN}pBT4i?#^^03 zz9kwG%qt*0Po_xxQ0VYBR5#hfi)(s&HRKBM{K<ZUdMnqIEBPp)m1{tuZ`F$Al;7vb z?4!e=_qW7?d5xlqcNRkA;Rg2PVQvUSB|naX^D&&g0o}IE5&SnG<g`^J@nupE{*I0X zi<k@F4~v@*<%M%vpTL4w0YuKK&2R2xq^d-8DoG*aKnWotNzbQa;cQyIdIi4#4I=nn zG-}M|80rY{*5YsQR&DoY<cCfa7{+?$8LGlzb>{Phq@=|f@CUqnDXD#U1qIC7&YzC9 zT{T4;rN!$1%LKcL#3zbxK}B<M5=b%|GEzpRy2*ySC~YjS=W<Q)-iBrUL6bsl(@PJm zOa1>J_TB@ksjgiY4P6jHItWOU4$}J<nlypXd+#Mw5yEF8grXFsSLsNH(0h?42#C^q zs3J-SOA@4dmf!dP`~LgharPZ&oO|}(V_e5zWX)tQ)>?V<&b8)z-{*PW4$qy>+Qg!9 zc}48TUL5}5jjx8bNm2<K_m8M(?J|7sgvw&gYIm%QN!ITwiwVMy2q`MMs%Bgx3VcH= zB&KS<`7e^TRaYxVV7b!}?`Ru|iNa*>Ak;9<#>$4_P3)uU@MvZqf?k>f-d9Kt7QdNV zL0MK6GsiQ50cQ|Cf>8Smw5p})5!(z^7LsLuqvADxz2h$v>08d#@65#<+(|<6RgBpp z(!-8PSe!g=U0Pq76DX)nZR=t4TOj}u3w|#Sp)%-iRO5CN1isL(+R5o9B7Bj)U@L2n z;&++n$6qbR%YcjRzBFH1AulwqTB91?BtK?LjwVkRq#P9J$M{wYhB^gVqZF3E9AY_h zvRh1qB-*&DM+F<lxESner-{|9&|OrW5rb>l<{Y#qN9_6<ZExQ>l&#hG#u-%l+It+3 z5HhA0@eibkTgL3C1EKJU2DkGeCyoY_78qXSNlf?~205~j&(5(s^QQpgb9tWOYYY+n z%a$aVD?&|szRKF|7h~Cx{@p#g+c-VsSnsdI&SBK0aP%%^usBx!W;eS9nP=)AFLEse zc>;a>z9=szVI^vuGa*^?e)s|Z>{NY%uo044t+g>dw{~sX8NbEkZSs1AuB?W-Dx$H; zLS2_+ay7nbI`QG61{5nxVVL=aqlrnq!_4kuvXFi%$!dWo>r}XuugH()bAXU-axPuq zZof~{)7~esXsdX-%Qbm)cHa5*2jt<NCBatxSxMzyflG3qKhuLn?KV5Lx#$3`O0l*( zG5+z&s)#13CnkL%Hx`${d?(;1Zq-2$)oq867dW=wg}(;c{a+lf9wja*A&M1CtJbxS zT^&BqO+nrVzo=NA(y39EdeiL6(o}Y^BVM-PwAnzbs{4Wq5h@CRL@OBjH#zG;+u!7@ z@4p6`Nh3fKvTO(8B`{T@?JtQ5ub7aAImB&9Geo_ZNKiFCeXD<P+Xin)Z*A~IMT=uE zu@GlXi*3}NgQ)AL7XA6TI0sT3F(Mi>rm0@_4<eXX^~`)>%E5<M;rS_Gu(!4xA+u7B zTprw^{6Ro@1dsgP^j7C4CY%NcYJm46(ZzHp*tv8?LE-D&UDcQS-VW9xQoHYR<=ah7 zqPYUDUMjxj1yrSuu(I^jL$A&)<YZ%7%(a~7`?iMOz~icD*1A(oy=JX<mZm{sU`}+o z>D!T^_wNHk1h&D+qr2nMbPk1~;%mw2^%KW88`O)7`a!V?>HRQ+hi&zE*LLmeX^w>q zt*!0W8m~=w#MIpPMah7~Si}nNUV&(SxL#_6bX-Cd`$8dP@$Om=bKUIDwQr_3MW(KY zQ^+ufedZBtvrKbP8Ml_$6X5gf52vC>*A4`UGKya=fJc1lP#(J2AudR>&*JE-cb(Ss zSc=ne>l;~XN?gDppT;kkR_*@;@k{I($cz0*SU2~-lxV-oI{G6d>b$`5%GFs4cI(8s zbXUGX>aZ$s+#=5B4nTHE`Cy0A1%b|$8MCvOjdoPc@>WZR(S9vBw$Ek~=8knRdAn2; z%`~qOep)bCMdqB_X|yKbbcI+(^Tre!k8ABM4>*LWfBCRq77+02`3t?!)^f%kK*Q^c zq|B;p@sb-Q;ecNqo0ZMpLsxB4bW}8(APnS|2j^{@7>B+Kxd2oUtv_P_Ml)}X*^c(~ zv219%I|J*Y5OYgQa2G)I$dItmQi#3tU8?Ql)x*6zqH=^mH`O}dT|2n@rs4gp74+mf z>nojuIv`jtn9l)7;QqCrkn67_ix0#8LX2D0WGQ&dv1-88tVSuO+NJ*x(=NlW0Jqba z2h`P*$WkpW;+j~pLh=|o+7CZ21SQ1$0@d61F&-o+0GyPB@$HruTUkNzR+lD1+KGKS z2i5;T+G_#?l-Qv3RJ7r<G4%}RCIk&@a<nslKaKgrUtn^q4Yq-io3V2E3}QRdJ-T&m zumNB>WIbH$b6{{9X4@AApyWm>-?HDmtA(|GPtM=1Xc2mR6coU?4G?}OobkeJpR*vV z=T>3?ItN!%13(@S-xorQb}hD&tY!s0OT^AugssOUj0`lSZN#GfVzFqtIxd=Q{FBmx zT{t}2B?mvWe8}5rljK%3>~i+>MN03JmV?L64^xIy?=}^U!@<LTw`<h9Z?RPQDwv#v zO9jg#s<#r&I=^(k9-z37^%5bC^I3Zk8x$9dHEG~L;z>!*caIK|RyNl}-<8Rg`M53| z==bP8$*9%Q)pu&$`89@ixhLCl?>i10M6WkECt@=#pd_5#!yZacItM94`z>leoNU@) z+u+nZjaNzJ#A^YB&Rufj@b6O6Jp<`0TZiCHE8JiF1i&9g^7lIMf#k$AKq_+GdoeV* zMH&)sl>0<TJ93S%6JXy|(Q|8VaL>yZ{tfLXpD!ymc2ySOt<QgTFXK)M;w{$J*{r}+ z2M}ha-lt>R=W`+m<@}rTv8BNs`xd~|OZ{aenE5Y?jOJfUa$UbvXc{11mKsH4CuM%f zLC0&XkRf}_D`6YD_C7FruDaWpk&Go=q<)q{m0scDdhA1t@)pm>w#4sVzg7pAcQ1c} z6i$()>%X2Jm@Z&VQ8hpeLr`Kmu#1kG6TY<{7X(lP{Qvy>-TvDYzwPkb4*&o30Xl{+ zH&cLwoS-oOk0<4u)CDoxp&Y-PzwPkf+zH<Q!%g37KOQXq-+R&LH2%!3=w$SWI&~y1 zU#;XDH*YfkAF=nhwExlbSNH$R%U4qUL2jj+X{WJ&Z!c7h|M}7X_f3F4r%KKy`+?Ti z`Ggd66UKLyu^2<58!2}ZJ$|I}_9`=^FmibON`C@~ApQi200G4UU@mZFuW+iQ1cVVU zdV;@&BBvbgjLH238If#D{si3`QyOa0|5`nB;q`y$9rc*fAaDkunF}4s?ZGC!$A4}9 z@xf0J(ETqLK>aKFCiWc&hQ8ZI@@`+!^U27LDDFf9QZ4}SZf#C9g!>L#)<3?{PE$RI z<h<?l@$BP?-fzGx==5S$DpNczDe?~KPL27QnQl$;LW{*s%}w%>TYTf+lPIT{WZ62{ z5n8;2;j`=m^9OMX{w5n2XDTyhdU_i0E-ki(YOYQ{kf?86et7NUL&ESyafAc@Xl`-X z!w4lG1HBj2?G6Y9mD7sbtEKf?b}xVQN7sysp3iQ);a-ZUIOZ{<UCc>~B3F6<nP1ey zlV!bk=S7ZBbzE40{E+6sF7Y#oS6le7xLisj;*Rgl)FcjX4<qSKKCuwwQhiU7n#e0m zQXtm%W^63y+hEy9T&xrt1d(|1n2cQQle3`<X%&3TM)s9jRVIm-ySUn#8rgSPTTw2s zpP*EzC7@7uXN-HU?$ypHkn4OfZ5Q~lb;{cND};MnPr-+-L7(BMd;d)H{XgAe?209{ zvTpT6%9BqG6BU1d^m5=2NlYwC#|~}<zN!qe@)1apw{~mHbIVffGDj1l(|H$K&IvII z1!mYw=t5=bJHx56&*mh&ZKzRE;$@?H{iX+ljv+_1wNr6N`B~FE6>-m86<UOpmCHH8 zagkuL5{Mxa?I8Y}BRO(PN2==<2XrQ|6g^OW#`F{-ytP>R@(<deeKVSAc_`+Cii~7W zw?<YBD<?uiSX;6$d0MGC;e%A*Uh_~FZFlH^Qd}1{D_~yT^+a^S1@n|{F}<mVtGbn^ zsD|eS7PW*{>*?0ZTy_n8TcP7Q>%(ZEqN?HV`p#(1?lX*uW*UjRb<BrBTspXDXgBZp z&%c_VsWu^OEH{Rz(pBQXfCj7u^;WfUvun7*b5%juYRW(*j64gv=vn{L^?=*0wh)S- zDO9p;%q#NRsb8&DTI5}TEJ>K^6+p~#1+5)%8RBQyTW0Kmu?O#6P<qifyvBUw-&9kN z=0Wz9?V0Xi1rol4MM{0Nn548vt?jj$^e>n4lV^52L)4?vd|MrK(fvbSfd>!3T;)@l ztXh|D;+CcbMzaSJ)~ZuJoC^)#h#rB$rP850c5VEk6_L_b>!$7{&1Vs;W_|L{2pDZW zm)ac8-fWjjVr(wcVS|MAW4?LNO}GxE7@=6|8{nv^gD16^7oTWe5^6eaewlp2TM{_8 z`#QqcGXx$laZ_Fm=MJd6w$Jf=bT~i-z$EA9DhRZPLqbxgt$e_l>&|nA`%c$&N%o)z zc0;$nWDnHzpfij5PF}?6>+JH+wi9_ilW`7c%#E`9x;H;lqzS5MY6S=H7Br$i7uDR& ziZZP}<b(>$?WVbA_e^q+-0G4hTV4jf>#V)~LM3lWGiJ{=fbY=5R2X4OfU9L|C@%@b z7**q2A%|J-&UEy(aAQ52d)^7*#%$%g#epnyGiiteX7%>acZnIg$5s2R!DdRG0*wPz z^UR|5Ykl89`ntP{ra1A`Z%H5UDPCn93}VW%pW8R~EYc-^^J-8;K|=HRq@um7D@ZF* zre(NJgv8z~ce-6aEG!_(s;c?;_052DVm)q@-RSd7$7C>X(|u#n)|X4Zg!7X>LBccq zN>?l|&%Rshl}j$3@5vGH4FE12BBNhXKOH~+o;1focGRLf4h$SAP?qRMo=a>HJWr-| z^fJ}@Uc6fta6kX@iE<$u9VAyaylyzcq`~;_UEy9_>GQ?c(7mb24O(efl51rsFe(Hf z5DpPujz(#`tg1S5*A~CK-P&O+EEBrBY$n~!gG)Z%rkQgW>c|THMt!rg8pWeGzDq61 zSExG2OmlVKhJt0`+C4A^r(;a<$v-6Q_7b23f4J)0pgrbFcVmzTVdt1WWVld&)<WmG z_aI#at=1r1nm|x8^zi|p>`5RwH-iv?3RUM=YzQq(-sP%fCp+4!TCKXr;-X2ROu}`X zQTzHFhCn=!3S>R*Dg^)@IGvQq_A}4L012UMF#5OWWwqJ1Jyo|G9SEt?9T#6))OE|? zb63%)MwB;CwEYCFDz03WVXf_!?~lkaD^FNvavwYSj$(<j&u%PEXbN&pF2itJS=D8k zzJua}tjyuf2o-jG@)m8I#p{REbE>gjJbWWeZeSI)`59LfIxnSZI^rI|TpMc#Ah+D| zv9$wg?v}rDE2pKA(q+ylc(J&M&Bg^{D(?V9K9#%$u)T9Z2TEI}c-S@&<*RWG*!Chy zGVKPq`evhx&qR0o3v70a3z72DwXIEVc5iZf<Yc<w(!Ilm{?{UBFVbyjU21f7{FT$C zGCKMU74-`qJ}%+L-Z;u&2_lfpwxTX+sOh5{4Pe+;VBw239f=g4Y`7CZf+`+U(ed-? zwc?iYWxDSCp_HfVISB7SApws#5K(RPuKsf%k{1O#Xl34+*uH$&{S#zgNwrUI?i-rS zNtUSNQDey1<SXV;k(`tvx4K1MQv8t}7sa|Ux?fwybkECYh1-<Bf*|EmkFrZ1oE8!? z7P*v_kg{;CLzYRxU8i1VQjSrKzubSs+9qm)fFEt)%E*EWB{sJ;Rhsp(_TAM!Xo#qZ z3FgtA_S7%YJ8a!RtYMa?7usMm$(S&|oQvL)e|!3_e;D4w1{pyK`l@xW{3f|u4X9#u z80tT@O+YTn)l6FEik;ahdS0tMLD@QAXAG8ls@vw8qm9GA2HtqjEL@`C;Cv^#;LXh0 zpz5wIe>-JRS~ccFv85OB;?<86mHrIHQj}f!YFCgh8P*N%KULil>5Y7hDBO5AhQm0N zmOdxe`V=Je6SPz>i&lOsaak#X>RS^_;mTxmXuUnps5M+{t8_o{vl}PNv*Xu4l3xm% z&dqv%@q2<XGkCv$QpqUs<6W<1!Ry}7Tp7+44^j_68>G8tQ*&1N3H9P^AiP1$_NZWI z8#*DnA|0pK<;f~cut|_CUx$fI(;sL=()<KfK^{#_!DJST6`oVSaX(k}wiZOsrLk)e z$Lnij0?cl-dbOO^v$?ugylAh=zEOFC>DB!h6L9qA#Yrl78L3k6rgtw6E_VMhQcO0Q zvui{@yzJG^P8aimVcwfqr>4u7(!%M7(9xS5#Hk@sjo`82n@BWu6EI@%sky5~tYxCd z^^R7C&Dx3^0%%2CeHimHY3)0VTwBaI0Y%cI=St|rbG`m2XP?x%>q@1r3AS`;4GeJz zl}J!r#?*fzA_R2mrF=*kn3*5gO=XxWk@JcK6o(&boK1#6q(6Pp$Hh)xB~?P6U=Z-u z*t%QYW+@nj7&&$kONnVn@m!6g^wKQPtG(usG(|mzIh<IcMrUX$8$t}oiG?x@#_t^= zr<9@_<?c#JgAfs|Ae#N|I}Kl6<h+sOqB~|r!(Db;U_?Yh#{>j;4N{PbQKYM<lZpkN z=G=6(LjMEO9n?#0k&D$b8;ay{ZSly2S6HU>8M3!z3Zyo8;%K)D>hgN}J+YA>_W{aN zLg(liMc3$(+exzEWqW*tS>pU;enNI?G23_YR8p7HTr>TEr~bU<38~79lGA$bCDvxq z`i_s|h`>w<re^_oB<p-lhm^Zw*G*p)e{3c;1cN8{h3e5%UBLx`EKHtlhPHS2wvJY$ zH>em>GP|La4F(&kR<q4M&S?KPT(=X8+__#2q(eSEW<Tp(*M+-W`cs}mC>98gWk<f} z>D~2_;(e?2b>j0Sen|AyaNhh?<Uf8Vmc?0o>nrGN7S?Lk?1J>kGX^~tk){WCRQ2+p zdnEOKX72$|RiZ-8C9#;oUB2Fca)W4L=sauU_bNBIV{^FRs1XhO*2h51#Axt>V}*Qv z*^p|?C%83SX1FU;jB(CYqg)VOnDh{=GzHCye-;;-#2b}hZ&czJ5bV3RCx=B++3(RD zq`(44|IAO9lIO$kE_s@Lls`I}c83Kwp%W;Xbi?%aD{_e8toi(XE=F0Z7-2^v%?FQ; z3#J|K@RJp{<55^wJXWmJ4YajaEyl!Tr-nd3l52<t$7rp+VN49{c(OS*`tg+$UQ%J= z#h*NKyE;d_%UPHE)@I1B4p}%)MW7tVqXHjb5S{h(e^7Y(UI|nV((4MYczX!e2mvS_ zTYn`{3Ve~q@E7qoZ@&Q{$9@x){EYxz%s%Gj$<gA&ET=_$=}o*tWvwS4n4t+99CuIx z5s1iGT=6$g9NSs!1JvEod5Sqa4RXxXN_n+6m;aIIaS=K~f-gT~>5<b1>o(p<#+J>A zlEG~y4a7%aGA!?-dRKHc)y!{dn=T0s3=q!H3V;0%Sy%}_UcahVqaagQgwhaC(Wn;` zuE__>c+2TUAFokf5<I)K5GB%dC+lj)u(Gs&)z~t>_fOYy)%$PP!{(}F$$^5op8O1f zqgJKPQMWfN4y}8#Wa#d&)w<4eHrlomv)_JO4dGg~!*zE*eGlv^d6vzp_|jj?8yD9s z0A=VIE1`;T@6esM%JEU~T7eOf)K^1VrFN92zRVolLY|f*t~vl9SlwJa7W}?91|M4U z%B0SpUXJTeMw-hqly+=<x*ys&DjR)wj;AaQRuiQaT9zS2*GaEHG4pf}-wKz_q^iJ@ zD_elvDHtrVsi?H?Bc-`4LEX1?ASw@?rhL>-W2;eau2Ow$X45e~?OuAN69nz3U||W5 zqmm-6n8YtGA-LNv$HZgrt}U-$-hOoUb?F5zLyi}yipIOkCh?DDsPt9r?W8JLlgsw0 zN`CU3<wc2-eIL(@sp11Cjq9YLtLmpasa~v0mRd7*(I{i95T2hP1M;3j)3YQMcS53( zVgDGtglR2*i6-&$mhAW^oU*(u75KckTPv6@O{0{DOH#pWn|)ptk*!U~K@|t-JWUz` zCP6M2kz*m)8z085#W5%{6*72K-ZR&9AZ$OWck4Ne`ttdS#`Oa7>QX75!BzD7W7WMU z(S~T#DDwF|rq#BdTw=WC0ipf!2QAX|JKtOFr{_Bzo*cUFuY~M|N|~*92%=Y=`DHj4 zF6Rm#EG??dE;}~gPBqxmn>xY@`OGa<woINxIjMCOS4{4AdHObLc2O7}!Hm~P6EILd zM(Z@#7xEIXAn6Es1ZqNa6JLzB)vN7FBQcLBzqXoRrTucqKHj$NNE_E?F{<vDx|Ll6 z%B$}!@pXM|9^h*@8ZMg7%xK*lL=?IKj<D>7sLL8RSFEhI6Witmy*09v7UlA@4mwL~ z@vx9(ZFd!vg7sAG_qR4)Gq@%PcCw!?GHlMPZdXX`78$DAe{Pmzv2`=qdh3)2rOfLs zvdf&MrF{e$l{4V1I&$(a2DvX1R`+CJuY26qfF1=f!>3xF5qt>q#8j~=FXy4^!}A(W zOkIyg7P;87{O*T_nfO3T9E$49bQhrf?S<<GB)lI))1b#TMyBB=%CGHv#=t~A%oaWh zCOSCFiejI8UaZ4jq&w$9c5!mMuWMCVg0gnZZ6UZSiKQz--d(EsNn)tktGYk==Xn}0 zg(o7R0?DZ#Ja^FQx7^6b=fVKMa7c;H0VX6I1VurL-)cSE)+y_!SMu_)EuKSa@zv3X z(AxxXUkZDbUDKPl>mFXq{AlWPp3+@2FP>ktuTg&CK!cV}dLUJcW=l;H4sr^XX~J_H z1>?l?zr5GVJeG&YwC&WR_11ncSe8{KwH9-Lumz7HK4|ZamTONn@pNmV3iPTgtXtYN zehDY8s5Or9)Ry+Ukc@mNb)CwQw%d<*lz>@Re!Wus{w8^Fm*JlSHhtgj<J-3xKH_Oc z55r7!;PRaew#zy}1+S%{@<a8~lyf4v?>eo*OG(k@)p94Lt-CGq{)JX~3DpF_jHD&W z(`XeML*ML60YWna_!qGi*ZCV53;JOVp6wt`z-u!9@|u-0#Zj*S%X&Te7=X8w-Az{$ zC+^;i*G`h3{K~tnl$OYwm_+fQq{;xFQ^t$8?T<0rGp`pEDfQRherc{QdzOe<QSQsc zL{yRWPPq<0vu{2BKE*Sy(AbVuT$P$_wD7m^=gvWuEKIUc&Dq;@g`UH8dLr+NisHTR z^)0%<+;2%Zs9xcl<BZs#iF1MYB)+uD?M|rH?jmOFGjKktdbc`Nuc0D-dE!}V+5)Rb ztKuoRW_Y#)#s$VGAo1~@9wPeb?FQCzp57`ku)u#17hBVS5j4(hn2R-c7+@qL51F&9 z2-fIlB7FDGzN}Qe*y~0KJM}wB^r$&2C&e0G_JgXP@m0v&R{4enX=sqCeaAj}fM9ow z8Y+2|qqjw2aNftX%X&{-5mWBvz(!tD8y82oFN<!sU3TEovIu+}gd2FGll<ZY<kqvX z1&HAijPW#X&z3$LWnl?T7H)$4X~0a-HZn@!@Tt!AOvB!lVfw`$YmbIPTqS8c%c6d( z^-quo{n1k7v6~`#D%Lq7B)QG(I9-<0I;Uy~+t0X%g$fs8bVUIW>*SCtd)TwSPha{n zo^)_$43Y&DHgJ^U>|xiGRYtzu^xf47e5R1o3H62yKQzH3_(N?;FE=3$0%^9nNo+uQ zNzScpf&Y?3mZVjJ)8bQGxUd%=<Kh?^-ixQ$|7m{8BS1)HaWE7#xLj7=w3I3W7pe5u zBHSK%$KrCcH0|^2kjC|MO`W_K;GEKqZei|Jk|yE3Hkk!qOHp|A^fRk+W^a6G_4T~f zYb0#ZE;HQxhRn2lwu>hX>mrTM{bedhct=J@Clg|_a37*=V0F%}EcmWR%L~E}`N4V5 zL^=It>_pdAAdpPFd4Bff&xDhv-@J&YER<ovH+fn&4clt|1i#WAQ4cy(TrG66+crAr zLJ7c5W5$Y`$;CN0ZsX;kvqyM_fpYVq$2tC07!Zkb8*D19zk7H0*%2M<PH7r>qIAJM z9d+zek=0k!Lr{SZjWm2O{|(k5D}kD(hPSViR{xx+2cl7Sl^_Kuh0+~4G2$GZN=6je z>DBE*UCgF^&eL>2+5DK7y@43&*=?>X?&bfH<2|O^WLaB5fF7?=1C})XL2ptWCWaQv zP3ZXw=E<HYf|)S7KLN_!w8HqZ#^-n|^aCn)O{*Hu4`#Zm90sxj%Yk_2qwP}YjIC8} zl&g^pf>9FlRJgHCnQ0-UMk?@z%KEeC@!QgfCUdP>>K_&DYXMisD05Z2q16@!y!S?? z_bC+SqR26;Cd?pd{Lw#NM35Vt%=TB$MhQ{ybVzn)cd0m3m*6ga=du%W=b}0fB0CCX zL9tE?c7^!0KSAa|wT0cPBZaRJ#N<=qLnrQ*wRBFG`Tp=jLVaEHvid@L5&_Z+)0k%> zbNKQQ<p2$mWF9XlCbW>ev+MNcA(-Ra{wmCmP@4Dvn^mpNm_uyybkDb5MZ!diwrsUE z?q)z?{=~m71Al^gRJ+ZbODfMPcwb7U*$fbmuaA&ABD{Ux52KNflt1T~zD|uhOeY)5 z35}5>fIj^R3Yld&5R7=ROe`bji}W-=PjrRC&sBh;Y95W_FW8wW0fpTHw4rOBl4ksi zy`_R><iE@#rrez?l#bTM7Qe*(b0PW@q#o8{Il|TAR$F(W={+~~k;Ysz4q|&-Oe*lt z!GC+JD2FN@;;Bt!%<lZd3A*z&_P^k*!)wc!{-#AG%A8+8?T&v5(*sc8)5piZApJm6 z|F7uwUx46G-@7bT*nS{O*9MLB$7R`vcM8yyF0)e~v$OwrXsnq4_4qmlxh+>&JS-*o z=jXCSmjA4-vcJx?30#J;vF0=2G9ZxK{FTLTfXgT=E1;d70lFR=8|y!VdIDXF{FUWE z*N=bg`Y*ir|4c*uKG%Phi~hF!f0pG<?Ud4v!k&Fk(f2~0y<KWPFLW8t91UDEF8h`z zleYV+9P&xtkALQoUe50ie;eetGyEqH1fya5(<mf=1f?Tu^fvhct9@+r9bk5m7bo8P zfbHLb1wIkSKfC=}yY{gfgkh)vo6QxzvZD`rBQWZ(!pNTZZT}y^oMSL?VI5M#q5pPg znEKg#k6DB8%QJ^Ja8CWX3+2n&7Eh?TK$(#(KU4h{Ipq&1t`efj5qbded9xZ(G0{9` zoLL!V7~?8RIA3@*-HVugnioS>C4OJApBbWO9<1ry`n6B7+OMHr0?gA2l~*^1w4<5P zZuM5e*He$SHm$r_8GQzw+qUfjgqEic&%Z98TaV@JujX|jKX}1~!S=S>B{}7+S?rNp z5`sLRynPIFuc)+>(bxL1Ci7O?WY5HP+qCJc;uCTf+X--zsjAX|Tukx)yzr$!%7cSU zW|@Uv1=z*ls&g)oS^CVgeDg!*<;Q<u5Ka=(x?Pf(1LD596%apJwc3)D5(vp(i7o#L zYF09hxyF<&-ctCEb@V|$)_5xH3|`j~_Vz7aMC_66UQ2{!LPE=t_&cKJxEB4pQoG>_ z%7>ml=}@`=f^Cu))i<;P@cPM_sm}|H^wyGC?p}QmX<W8Q!FM6Dca+Uwm{}{Sb<HFU zWUSQFX`TbaZ<Z`7=x=aYWlnbtARK%!rX8XW7MfqQZW$<=evn%xD$0ul^ZFkDa6ia~ z`kcb9O8SS6c#7W4W1O!Q;trYJf0YObL0ttz`br+PRGhp=U+bQt)4=Cb*`t5lgusM; zUQM$7)|-~>dyG2SB)+!FoHq<cd?mIUMH#-$SoYb%fAjDu@Ka3NV(;VFOzS$Q(kfkB z-EwmT9tEpwwRg3x)ChHUO_35^HW@XW>My(l-9KVVgxjbrZa2ha3Dh{{l{2Ba+brEa zE&)vEuuZYX8s)1A^h2TGSqpJPN_Xn*1|nT-(8f!{Mc1-!Zkq<`Wr10NPxk;zL4qb9 zJYelOam6h>QZO1wsh&Ad`rt-j_$oIzGIBc(BGp1xV;1aS0xA<fE+umL$X?)GYHX<E z?2p3&HShx4&@s&?<nD4};jLrRC|O2UwM5gr+u6yPo<6&tdzx<t*syWL<84i+;9Z}g zK3GeZEU_G1c)up`h4^x-cvxEH+dHr<XN+>#&Wd{P76SO;Pfmi=+qT{rK)?B~^$Ry1 zLc?URhbxpe<nmT+(t57rH_fL?J<));I-3-}U2Aw}U^CzT-p~d+PpdgE32Vf4I25aw z{TSvLAirr7^m+Ei5lqLs@thcTrz1ZZJJp@CfT9>0CP8_~4$}L8jz#jDt`7f+>o^}a zcjE0NpQX2+fhzc`wWgZ)+`nyX0Jl0j2+DrP#M}~MKQwhVcybpTG%dK%7^j^VLEd3k zt&*-ubTLSBt=9evTI~S65=HZ)3P^~acwKUaBmudK@B%+zSr_sI$U(#_4u%4Ru&AE5 zWpVZ96i<@yhBwtF5BJ{ru!qrx@*v69E8Wq(+k03109fg)tNM}{NehJa0qS^@;_!PE z9{9$z^(^FR!z(Aa09x`xzos1j-hSb{YL;;}im4&mfRQPG`RwB1LB6k~=W*MPNE=}) zn8NUEq`p-<jQ7<~P!W>GJypM|n^|T9U!5njQnjs~ingM)iwW<DG;T~}R8Ye=rT60D zq{s~D!Bm4=T1)Vv1;%|Je^mMA?WA@xa7Te75FEb{=m>VGQv5E!0B|V}TxsPIsu5*( z8I+dIMRso2Ga6|qfTK9fH3a(3uVInbt1cmX`)v<%DW=I{o>n_QC1?}Vwx1-3dZzwt zOB6WbI;ev!BFx=khH}<@`6p;E^|1FR$nrwzstA^<_?lqq!1X7{LQG!+Pw}-fPf#+_ zKGtDRdnI2?DZcBwM5RV;%Hu+XTj`7LroIU@iZe|#hi4baqvL<B`d(p!2~Y0jJ|0}3 zT*>emmuP5;E!vR>ePrdiIQ|Jz*_+`h*FP}BL2kgU3OH~d@38fe8m*UyqS1h+mV}a5 zT&OaszOFZ<#Bcd<96@foN>_FMFz!%p5LLWJ>ob1TAFDBu%4fUW)I~s@@VuzbeSWoo zgYU2jdB5v;!i}3%<i6c|-{nLuzV&a}IN#MaKSS!$#x4-WlaGxaGrC<MzV?1OUa&H9 zKyq=zWJ#dpL_fXMYq5*m$5MmQu|6(VJ*Jn(F~f*Bm=srcde+RUq~jTKdH21m>UsH` z`TeHgsqvK~Lbc^-D|_FEak-nGXNs{VKI>fy*1^7n)zc$Ypd0NG<#OYM7*qM@3=QK- zoa8moqTWiQv*y^Um+&+hk1eK>I-PqV4*6@KG}uyC$?C~=6LoDW*?{k1cjHrd%U#Po z-d7W9Gg`dT4q-OIE~I7So5RKH$K<fhyK5QqAsyo~ETi&bWssaU-_=>-$E87Do=X@e z)7*-0q6dhiQd67*RTwBn_~li%510l*-@YGOH-g8EP=qV5CT8tqLuc!+erzOfakJ77 zF2^r7Z7F>)q44rP6a~%S2Gj!>3FeGCp|lCTUs6PM&#<k?+h1HAuYcT0Y<He3T<t^| zm+gj5o_B><2n<j}H$1^eNv-vLexG;=%J}^4O)NNC@ip(uN*_(M3+$^H#-EPFDV%So zb(V&?4MvT4QVbT(IfJa`<-ZS^(aoH4TrtRn;8$6N6A7HFp2913&S;mhZSEub8uMoX z#Zn5s`zPU?o-{ftdk#HQ{MHpsH7J0XmR(iX+E;>qaqXqe+Wb?ngUdF})Z9X-hA#;( zzK7tP_kr7RzDnBN0$ruPo+V9J;Dqa;2(hc9f8KOXmFGGO@q%l$@OcXQoIEdxrS2!A zpD&!(*36MOVMSTS?ky$s=^Fr4A;o_J`+o5iGRI}j87Ce@5+Zf-N*qZhO#KyPATmR4 zIUgk;U$e@705uTZJbNT0*O{{Y;>Lb={5HvNXZSq~{%3avz2dLjFDHJ2syo9MF2&B* zXBgS)CzqQ~;(K!|_a9u*Gb%NrB<Fxh>i{nfZtZR0ug%XTp;AH6TdV}^*B06T%rtGI zl97E(Vv)p?0F_k^|GsDu#AcP@CQC+qU*ewcnm)l?NyE(A0ZW$7{N;Nw0WX$wS~rga z6I`1I3%q$gP|36TaQjTSjw7@wztqxIn$4e@GS{fOB;r~>;p2@PaMO_qq^J0IZTFp` za3&gCGq^bIr4VwSPTSx^^&=F@xUI#!;+<JzZ2Qrs7oQGp`{g0m*X(D_OHNfRTMai+ zf^o%lj@g~mDdF+)v&11OqX(5kaJ#<VxVf1Mx(JIq^MQdpaP97^%F5CnW99QRp~|!A zy%vfQmPWRs;^X|38L5x06<yvM1J_D{<rM%d_NpiwI?!9hGuzj+8_KRS`|H4jon1S) zPI!S&tfv5S%B|3%XP<N9tKhY*a1Wr2+pZ~@zxShxI%A`_2E9pkkcf2`OlZL{C`Nvt zRfFHm=pF(3TES{jO1E`S?kruk+>)Jq>mX^+2wY#t4e3%UZbQ)yH@Ha`AU}9$CV-^c z+n+snLjc&s$=btAm)xO`)&_e#T;Jv$8qsO^un`m_Zzkt^0sBTSi+LJ9uZ<&rcLUR+ ztM@fmC7T~1f9E9TF`fWjMLj3qiHiMB(~M+L7(9*Yth5_u8QlSo9ltNWJ>p<_Ul!Ru z=H$7QL`<ZzqS@9A2?;*F<6{`{$HdrvJ?c?;)pI7Aeep_m=U1<lTl(q~K4ysKWe7&I zZtzPqdEK^P+(zuBJ~&=k6pOtU!w@%+Aw^#BhS0gGNH}Kue5~My&P0_bVeH9O7EbBh zieIYRm6^4Wn!>$I+Rmc07`FArnf?`3N9;Hv!TpEf$R@S+$_^e*AQz8RS~!dtTuxXG z9O<s+qiBJyn2&R~_)`&7#i|1z<=Uo~UUqqH>mBlA?qDjg*fjU^h`5q#T5cUtAC@Ef zoevuj<m`*vLdpbl7^q&S7q~hkDu`mxK1j{2>a0uH0KVBB>2~fH3d)Q3O1>(eCB3tO z2l5H3Qa433G~(>%LvaP0*EGZQhSrMv2vz6h`tU`OS~eXGmlNj8$i0FoKU2%A@d+4Q zvwSg_+ac<kMVG;imb!q%+%A-3>)<hs4aRpLI&7Xy%(0Vm{!YJ@U~((1p8POlsdAQ% z;~wIVCtdEk(RH43PJQPbueo>LBf>n+_Z?oyay2O9-UVAj94y+oNIa-lFIg3=E8^I& zz={Gb@3SnOKem){V2*<3m27PvWgK>{9N5t0SGF5hC|}3RRhRE(o{N&^(N+uz3zu3D z(^yM)z<s50@Fucvzb0<jrO>~}3H2!&8p43$^2t>@twK4uyUyfcZHA0W`@(M)+?_UZ zvG5jQdx+<O880ElhFj73*M<5hU{Nu8CM;!d$n(kM>SzjYer<qEShwmMAp~vxO^+Cs zD$-`?K;r5`{YT$3hLV6~O$XMg2GxkwClLenH+f4%@QCTCEckx#R4v;ytg%pqf1nyK zFg6(0D&E(z+CSR!(r@ID=Ax}Q;;I8tO6)cH#3n=wyjT1_OOB~6=|T!RP<+7f6uqM| zwMLNN+{pjJeONljdFYv{EQbK^RxF{KI1+}OikIRDz=Bmk{W>i<-hS5nuyvK3<^;mF zThVO-Ir<i(K=?)qg!27%y6?C1vG>gRq_<27@z(~Jb1m|Vmv4*~L<)qGSN{0j{B4Kd zPVnDjFi=HrDtR71{t2q+8UMaYF^41C%jo5?y2$eS=34jmck{O$emlW`kHO%Ktg|s- z4XtN=5_~nWc6v2E_!FcJesc5A%Ytq|@3Y|h)l<~pMQ;8o3iEdvp8o?)r{o`rIo4lX z^*@N0f5|fbp<8*uV{%0!fFw;<dNNw@+Eu^*??!0w`f2DyFQ6l=wEf+~ysXUC$%cP4 zY^{o6D+gH2NJPMJk5^4K%C(n^K}T1UXP7p-4VM}%oA5Q&QFPbM56S&zB<+#sL(zsl zf_d}Y-lJmk0cx{k0da3eR%g3k+udEHjV53smzY;_E$;dDVnv{)fa!Rd7RApI4rGRa z7^^HunriSrtb#YZ_rF*lPci98VoxR+8|KXg4juWQ)Yx;tyNp-(o9Vc8zODq6%TUU> zfUKYD>|HS_eRr#!on7uFKslg4xtCQpnM6`H?E9A=tBB1I?<2n)9Ik_<T;b(x_Ym_h z6IYT4q)1h%6)0FB4`w`HxGHn#tv|{tFB$u!K-<~w4XZWs3ik4@oJPw~7QWmrk@pEf zzqc-@C@I?riGb@)P8^u4k%g?Z2Dnx41%}}-u_yI>5k!NnmW>SqA{QdUeDkvqB6`!e zyJ*>736W)@k`6*E3?w??zWvqSj`G@*Ke#Y+>z4y~5y-UIU5(NS-v#X{%C5}()JAke zXB5iM>K&X_Sd(JIr3rxoOCDBL2PLF*Jt8Btu{QScenfS`W<=jOeC?USedjRV(s;eK z{ZbD~|GN}!b)RnO)hr$2bzS2E7DE*$#-^>lLz9dyW6054bM<>Hiy34Q&MW!Z^<FmQ zy!WjN2z|4=07YAWvEHNn7dzg_py`$ge-SCSOJ1|X#XBSi><Lp~ju}s(-RrB}daLiE z@-tg@<()lyasVSu7zo~NJaLLHZQsHcI=u%>ZVSnaEUB$okEj=)fu+o}*u>HK1(lan zS6WiPLyvWtl1<zP;{@_L0vlKo-Hhj)i^LVE^Lo|vb-^YLZ#eP<|7c#o+`2h2m87A~ zF|?_RDYkoiMa<E!cw|D(RI?joZq^O94&SNQ#U$!ibeVeg)a=0}uKdnz^uC`X{X@SV z2t2;DTcCM$wS4sb7Z$zO{nz7n`{K%zIiae5v&Jbsh}%-%kWi(iN5_2FK>{o~1I76q zj(^VSvM(9#XhlBy3F?o&3S3Qk*QEG)Doz)(N}O6U(Vd=ssju$DMP?eK(pybVp5kg& zW6MX+EE81E_W0`NRfB@kkE+lP_2bz~1`X@mYT8mxnMGR$2K7Y4j})sh1)Sjgqoa<z zs2q83M0<ABOXK^tnHG5sSa>{i<$22ZaLM_|;Luc!-)xfD4Cvz#B>|zA4^-tuy6+9i z=#75G=IMQUEFrm{@6?Kwa5#jorW?jOFt;@GXk*j;<*CTz(Q5lqBp|!|8iyz^UhWiQ z#&oJl>|^+2OXpdg)>gUje}b&vP-ADMtBIr+>K#9~Sypy0u+#f0+x1f|XnPjUvdN)+ zERUf`<pNi~-2&?^{<bGsBSA|A4?PAa^e1;Ey4Iud)^%$(cwpDPM3M2GPtKX0sas05 zBim_jNG6~inAF2%UTVk<=xbT)P(E08JK8qek0h_O_#^8AAbnK-1m#?vT|Hb=lCwQ? z4#SgWfk?gTy>!d(8&^$eJ5<_dOcP*wh?e-?-G4s(?JBe`1SxmSwj8pa`4^%2--fxp zPI()vFf!VaW~yTrF;Q;xEu&nk24El@Igv<~PBfoC@XU{Ctbs)CKB;Q{^n{><mzANZ z_+SZ4>DpN}Jh^V_6ZsP)mJO6kaa4szYe=`cg&)yz7ING}5gy!O+UeSvxhv0M#49Au z4HovZteIqCp{7uqT-Iy1OE_udOsN8Y;(<#pJ0Vm_j6!x_%EMW;6+}s&f?q0QO@wwT zb<1Df8Y_cy?01|S3TXE$J)-W({KRCPgos|f5CfAP)}5?1TV&39BJgC0RC1)xOD0qv z*W&`4Eeja&%F;Y(cC)Lvh@d8ia_P*08LgYeEzE0{JMOoND6Umfd)!-i#3AOyhbLc8 zz_bI9X~xVi-4cs#ISKC)wd9rR`{Lz47jX*aT+BLV%D$(Oih^y>CgnZD$C2t4+MAm2 zyIpURQf3CBULFL3i{Q71=Ez~Qajv#EtQ6GKUdnNYA3oag66$8Cpw;{ko2|3g(-%fA zqVbZ2sSLq~xDk%(chKr*lu+@JSDQ|QPd6LcY*&Mv<P!_=tw2KfMC_Yz?(wo-cu7;F zfRv}8PrvoPLU5MeOP|s`AsasX!l!zox@9La;&eL^`R~sMA>afN0_Q@a6whi~aJ(no zJf33@_jA*5Q5Mj;I{p}qeYs(ScG!~LXJQ}?+i+QnU;F6JC}eJ}y`CWIa9nK?ET53n zG7t86dI5kM0Kb~}^Wu%rfj<bBW#vfQ1nNs7JXgQSnZvz3ov62ee{t;pc!6Orh=a^D z?g<6Bh_eX4-IS4FC$`L1z4qMHx?04JCsy)gceZtlk%U0JC(Uz)v*)VFy;z_E<C?q= zx=A?uY`2(ud98nNMxaic&fb?XOe?nYH7Nl*EL1`TlKom=%ihmqa;C$Jq{zm{_3ckk zHnQm~;HY1D6!*iGZho(1sX_T{H3EL?d7>I)F5XYj%WN{tGTw+T>k8g?Waf7)V*eEQ z4l8AOid`p{uZ=2gy_y@be&XqkMP#{ghZAi#kEeSrxa!<OgI7;~VPG!{kP}zP2^@Yw zN_x<~aTi4Z(u4o>?qsjYai7n+^k|(Lqg|HHZ53*)_WifDFPquy>bd#uU!N+5<>pUG z0To<!7NlNQw)lT6Qn`Yk|8;VJcuEWv-Z@EbdbB)9cqw&}&A-Wib*dzXyM9`bcSM<k zD+;dLr3rdlsiYAZpVCwk$Q<t(Uw8L`b_k8tPf&tqsHW>EY{_mV_g+TLXzF?_ZW}8J zGdm_Bw)yZpC~26tV%QCQ@Q?%-$WMCGOtgAPu8hOtNQ>xLZd?lFeKrw9bXK#;oFbLX zdwO$^mBeBIl(eP?m5GOTm?hYQSv@lEGVJ8qQi;rzlFZRXkNdB=&l>RPpE$kvAY>?H zOoCxJuG<EG{H|1hVZxOO$Wx-anjx%0&9&S668ieN-d%uyQ2zQN#j|<p(31Lt_04Rs z{wS*+BlgB(-+^bjdyQgoxkomFD1)3?C@rwlIzWrHFsroVSU~moz!H*yc~ZY~RzG;f z>4CMyZ{6q##Z>N>d+dd-d~=d*OwG7+qo<@npswa5>^jvC8VV*Y_RCFAA%?1rv;*<l zM2OaFk+CcLiMiwIlf*G*Ox>)?{!$jSTe=nl+KTm112wUE5-jr2=tX*o{{%hX{(s#0 zuxfku_S2U0<xOW~Ckx;6zn&Ht-oJ4|OsKE@RGM|r*K+s4re)1;{#KuX%6|XtiA6-@ zN#duAOFLk60FT0dZ?Or_ys*dX9wQf_u0Bz+#tAbkoZ|VLVuB9k4KcFW2wP20lRL@* zdSX;*CseW4eBdV$cxg)+XT_fT7o2pCXhw$^Zh8hT4%OTjPc2{(qH0CM1kF_$!+<cX z(Aw(r=B?3!l5uGth4%DDna;jQzQ)%IFn;d`v?z*6jcYNc(e-g`7Fc}!Y8AqpY7Ls2 zmt{Xea4Vr*D7_20v-qU?k-3|KSiu=QikwM|Gz5%?+UFv<u{V1wFrBp|Ji{#;72kaK zbL|wGq*{e~A`_G6v(V-@)=Y&+UrKoIJ}c_*7Mo}wizNuZaye&YTK{WOaK%{&?~Wrs zzHAGX{d-cd{@0xT6yRFR^aN-5qXL>3xMZ*M_gYsCDF<@vZ>6ebLz~T?Lk%1zMxOz+ zi{oi6eU-~kg&}!-s<B1Ig)eFTWdHIawxLCSkEmcGg-Q2{NXdG9?<eS6S$0<teeIyg zVj;-NvbY*5>|N>3C^)y`+N`9Hf^<{y?#Z9`L4+xTT6`N0PVi)@bHSx5C(kT$zA7zM z1$LUU8J&|P5ox7YEqgUugdDbKTX}bGoFYh^gr*G8V@5?J_3lur9;3<%1hoHXSG)v5 zk%!wZ@k%W4c<WiN9fS?^@*PNy+T(<?1d(4i0AL-(Li3CK+IB|?bFv)7@K^v86_1+3 z9y{it07V$w8}9`lC}{Y*_Dp$egKMkkTk%qeS$<!Fc|$nYRb%sRfp!5T3RYn_%afg4 zGg~|0XxG=+d@KA>O_rv|e)__UV!C1u`Jq8^1w@L=y3#i4b$7U{hZO#IYw<Xjpw~pP z#WvIuOfc(m^T%~<Vl!o(L*@z^q7srQSSya5p50qnD_g40xZDV9Q4$m;jv!6vnA>~H zz35KHt=0KtCg~`WdBJmeZ?+rmbo$sO{AANkN<OoW!Y19JceMR>RmKp+eDcOp7a1Oa zd1})LUP#9!Q@2VPc-KUHBqUIZ1Fo+pT~lj7!GtfpaJFWZSv+A%DUvNIuh=^ItEOJ| zK9kKMW8eGf8uapFm_>L49@ny@mtDDD*It9xKFB4Z$Y~ngxLv*)|9z^PxaMK!TED|H z%V6>_f35szZOKA%lVy!ZgUSLeM771JCb?}Ih~~)tLwhyzeSuu2In%U6kX)KkHk@Lt z1h&aDIB)u@yq<;N%B6LlRi*6Od7MRq)0^k?LccbV4G;cq{Nw%Kn_;p)HeQRkS06gg zGB3JOZaDRS<~)u0`@cXMH{4ej75)C@MmT<YxPRImS$$Rqudy4lEG)OYf5;B{^FX}G zbbPxEMdZ)vE6=KTvw-@A%!28;LGWy`3&1(~L~HeQ>OR3MvC*vOl4sYar$074gAwKD zRVCY6Jm?OlJshHR%pMgcb$HDc<!YO1ss4s2=M9WRFsaEh#Pg^$t~gu@CcjWwebn-n zOa>p}R+Tg9smxPOfw$&X^?W@0QaEEafhkOFpHLsyv~^~pU#<=dv%eI-=2=s;k<sCk zK_Wo0wp3m8rDdtB$o~hB83PhZ-GcREHs(^ztfoGOJCP9^kw+5{KuY7#)N(DVPXVDp zYBQm=UNg59m=XA9zwcXq{Ha~}q4nBNP}Zk+>J-<cOvI896DX5xAH5eqF~uYQYMxRl zs|CjvlwVPV7jy=?14$5OC#ErI>rU+1XV`m}JO)>05yUt70FUdqH7L?SfN%bldTUps zBGv9g7i-9$nOrUZ_Z{B-hz$rVHo0HtznakVN+)HkQ~gFmq{CPU=V;&us}%pwUb{tS zLT;P`aR964RCu=MteTf>W_sAT(zj|lb2Ra^tVZ%IPfX#~YmkF`2|zn{C2SxE@e&f* z{REk&@3v^4r{E48S9CG)R?p*IsjKwdo8Ki_q3hKVQJad1cHASavXEyM`0HVroD9=R z;V*6slT_%WmY&+d!2>Wrs#X(<36nJ=tbC1S3JB~KoX~9d9S-F!;V-%b+cMXb2+f;6 zG_Tz6X99P~9%Y{eo=iE5(X+VU8FPQ@TY56*C~KCV;iFf2hSIhdQ2Lyoc6zr3UQOS# zPMSS8w`X|L{cc_^lHYb@><0l@vEYs@n7VhGVD&ny2;FqAVWfLARkD;hzuVfGe>8Vd zh_)#%WDuvXGi3_<P_4->p0!Xuy)adbSf3R67w=uK?Q#Bm>Ad_sgwE_Kt9FL*IEdi# z+ai2Xyx^6->f~8s^MvOnReKyrftJ$YD*OsSn&3iDe$9inDSH3ZF~5YDKEKNIM^+wQ zr2r|BceoHBFtBLBwyRl>ug}(W(u17!<0AfqquWncA~v~TG6rHSKq%#R^S2#-JHda4 z!C;N7GjSMSw@Bzy0D?B5{V~7OBfrxlztbcCJ<=opSHAMa0g~oiAAlYZ0FaKOMosEo zF~RTu(F@IcweM7a4C;&h#|@=!xLqEXRd_ntk)n6gWyQ=7hM%A_eO$tGVI@;}v4w#w zyJd#@b4J7{vdA%sf;RXC5_v}@ip?VQ`-Q^r(u`GQ7t@g2%NLU)ZynBftBI*#a2<V1 z_%XpIkbNz%WURbU8Gf%yi(?65%a1z<c_xnZv=(J8!AC+%6aAThGBwe2#%ZiIk+J3V zCaW2A9Qqrs-VAH~!xJ^R8@YUUHsG^B`4_eZBa2)R@%?mpYH<R5u*ss=Nkr~L$;@uL z?GThTtxa(99$|wlC@4jDdi5SvlCbKNMC@e|J-E+(`&V%u?L3L44y}pW9C;<A=kmnZ zw7spgvumQYKx@b}@;%b`c;a#Z=YCS~VGT~7`k<M2RE4=w-_HdjEWHA~{w+%JOn<{3 zTXK$2GU0uxja~q4)LZVz%aaL7v3!uBO@!PkcMzVAGFZdoL-@GaaFXYjNKD}t?0eD0 z;4SUj%hnAy=_RIu2?_4RDgGg$iz_9N2FgTUOOt9%(lR~lOBY|MtABZTV-<XJe$RWl z;K05D<ARHn)IE!I%~-Y~_kO3ZVKbMUq{qPZia^k%L66D8A#z0}Kdz(7@$U~MrAwuH zhGC58)fb8=)2Gqr@)K?kzcQ%@rOdlKJ;i$FzlSBy%1LPL<ewN*sGS?1@jM-+N>0IJ zKOq3}O6(D$Dm1F+S|cl}r()C@HD7Z@vjrs_Ux!C#mALBvd9&|NS7GN9zHDCRMZSJ= zaU|*enyg@u)<L$63ph^8;IW$a?N)Hsfl_$3dy}6ht1_}O8&)T&Na?YqAA;0M^P5?K zV#=4+BPE{&MkOBlC{DENYd)Dds17`3g^IP|hosZ!;i#4q`hTQKCR83e+{638J69T9 z6o;u*U?7mtJF%c`Fg;PL><rB;+PUod-sX*w>oP$5+m-FP+QU7r@8nwDCoFm{4qhsO zHy`eTnwt<Ne@rdGR=KTX4w!g6g-Uap{yZFhfVH)4^O6pvlO2t8ces8i0Wq~sSvgSd zskxC+C@V6HdI!0_VE3SxV<DZ#b8TO1e2z8p)fhpky%6dySv!-T?`!ujz31;Su6ayM z%vlCs2AQnQos3cBaiVG%?bXsZ>$r#wZ$j5^Jxe>AZyhQzW7AY=4j}`Q3al;4yM{3i zpBNqVHE!G<42=(t7S46q(%0;$z$wrvKX!pIPg~dL(kTJhMYZFylm6QS32%40r15fz zjn-~HB(Wh(@dxF{_WHf~kk+f`z4OM!u?^--3>V+T{tx!vGpwnuTN@1>qzZx{1Q4Y6 z-ri88caYwjq4yFrJVB}yX;P*4-g}cKRjPyzQWTYvf(j%`^NY{(ynF9=@AIAWoge2q zKlZ-Jl}yH3nVD;@vF4a_j4|(<hK(IS#)P{Ru(S)iEQ(GQTvtu>9RIs(_O$I09`j_q z$>Nb@zitw0y9k3JD_;tR(Vm$LDYI4+tf+2zLHLt$4-c%L*A=wz@4>{jT5{2LAl5JC z>$7Hf-(E^K>$1*m$9?6jS!nqM__3sem1R;0Bl&1(RFo3%D5+gQV1HO|F(1ZS318jq zAR&Lbu98RKQ0}F3Q*=E{m--|FMBCwUYJs^N*?|=HI6Phi)liY2^M7BbQ$BJSBn|nj zou|?3#V$vrL3X8g=9M=!#g#?I=I_GqiBf&8!N`u|QFWO6c{S&?+D*h~9V$8njLDE{ zcC4U1AM)RezJofMG_74RbYhPHGoLK2eyMst>OrcvWV`e7J(P#J>lXlSZwem^2C?e8 z&^TUUTfH7bxJXHA9**-3Eb2l&=(U|>*6#^x%mznt$iR`usH`^DFNFF+qwv^>Fskc; zL8gi!Ba9q=$AjCerjXl`7RdpfHwG$!^oA=RIVIQ}nZ%fEdY@BhKyV~blH;f)Q_82V zcGX^gEVTRWJd1mJbRmhM>)~a3%pZoOV7h^u!0KY>Z`Rl$ZUM!^LkMjQCcLIJ@sl{~ zgvlm{Rr!k2>L2u{whb%E2C-AjeQmu+IbfOMOp|GYQlF@HPX1EKl*p<EGFrf-Hgvt> z=04%7)Y-AHb)jw80U*A_xOvHs47r=UsO_K`SNiPL7mCF?>vJm%YrJY^U0mg}TVE;A zI5azH&vhf=;}X1fw|)U4;qr=(urG~Erkha7F?KQ(2j0@%MnT1Iy2=Z66JQNIJh@vE z1!N~1#{f$RJI{_&Pe;wMD&}_Na+pd4>Tbr@NfY&1O^rL0ZINDCP4lTcj#@7avS72d z2VF!*>c<tS1KOgIJ}Gy^m^Q^;skZD|$r7+P==B~6Dm`g#(XgmH*y`YACX41hl%e{{ znCm0CT7E>gX&CBs9MxW1D}y$eZN64hflIk-z%HS0#iG+<7rzo>*Ul0==<VDvFCy0> zML1qa9$SgZf7iR@=h-kO@~Ua8ge{yXS&2{kYOtxL><qqx#$0s1KUM;`VWD$;pPkQ5 z0zIC1OFAHRuDWNsC#g)~Q^nuQ>k`7Q^2<6e1h0V`bQV6HOGn}Y8s4$M2g_3A?_K~i zaO9z+F!j5ULqpW<D_(<h=7n?t^D9)Mgt(1fQ2Aso0qZ(Xmc8z$cmqdZ8C$OoUqerC z%sExBz3tiR&{J#8M-z>Q%Y(y__-BvDiHHjuIB$^cqzLor(e=-&wASo4Z0b+^L7%1< zf-Ek$J|mWb`LwVMp892}S|tti1n$z*5Q^2$*p#moVzeXLl4nhqDws6Dth$Vl`KQ#5 zipP>hbNbeCMzB4UFhgm{dYq$Or54r^59+fcde8lNy%8DxstV{a<XqRQR9;yh$bR_d zvWF>}cqg*>8<pA$h#nqqFkd!18Vopw`d41*Jl$d|y_w2s4fAiC&z`0cw+z$iu3Mv5 zAbw1Uavq3DxZ=fyzs`kiH;0Qq)v7#iuNeI1pmv8cavqPEV)exL+s<9WgqkIfW3!o@ zi?JVCWAs2D`rt|ga@V0FoC6m33o!A*Xw|_&=idCAlap|K&yLMRtH4;r7Qb8Px{yPA zgtz2gSbofM@ypH-I&+e%rH-vCmQ_d7Ky|Hk5_jYDC7+3wl61gMc9f`c@iov-b8jk} zX9_)3b_Yq|E(-953!l7x&Uy9b#&6*ZL)GRT{tX<^$%G0WeBwen{XFhs7<R<ZP-(G# zN!<~F^X}?cX$!P4{Q@k?CtmTYUAo}_F69;T4Rm-c%<p>Rc1>;NyALlcTne~-gM<g6 zp54f1T7W<E>%2&c;iA&3YOPt?h?qIyqwAEqANNrZ7Y5Sr^6{?SI*%`Gu5InzkPNXq zqO>mWw^RoFV{yfNNQZTLvyJ)@#hkoiv!&7JUw{IJJ+kV$0khyX%PCPH1UMvt+`{Hm z*6S;I$qW+8JFxteNs+<@n)<*FKO^J#SNo}lbM^hyYdh`d$8f~DidpkUz3h=v53fyH zgh7i#72IJn7Zf*lbjL-!7%Ef$5yd^EC%Nf*L=4x^!MOR;fhc9x+D~*2{3<#hB9vZn z#7jIY5AI%^AZ5X$vg%mPP-w*6+oCJGi9%7Xun|{cD727sz0OyYpPE90!g<r$yQ$^o zCqtCY%I|2;CCDOXncX(kvyZ|JIAPh{?U|H`!-fHjM8a_tQeLE_l6$_OM1wtwv({>@ zJK#WNBL%HEzNIzXrh#O|Wn4yg^_ixr#)ER1mHYjsbAE<FJvavX<|v#Ke*^~#Iu@Ed z0o8P+^B9r+2ZX74aN7%jPjdVfs|(q(^Na~It#;9O>^AeHsZZ`v0iEMEQdZ#dPb3tl z6ELRw+Bifz{ty<n()I9fAR*V0jn--XE%NmK6dTsr(OBJxpsUm~YYL!2-JDrFE?!u@ zxKOowHH>0uDIO_a<*K*du<Ly85}6@Vd$@9;84?!M1IC6dd=Mxer(PXw-gm!t4$FZK z@O(E;JZ<mAIf4mqOC4Bv23KL{1Dp(|j#+ZnEA}gzcHZ$+;Px*I=T+Io^q-TR(?$tS z_I#=>dP)DKrE)nq5h2X5sF8kwjV>6nKSF!{0;u)UZb7*l#3rs>J^M^opvvOOJ-iI# z(I6@e=RgpMBXK%EH1ah)Y6Q*UNt9Rb8O-`k8q-UMlwxaG_#k*ScBy`iFJG;zYGKno zs8v*GnAW&`-^B&ZDR+wy>w&wk9@~b8R#z4`UHW#~O{D?OO0RI_!hM%s)XwICx9_f9 ziT-}BE$h77E9ygC(2N2go?igBrmr5g6I55%0BedfA(z`by;euzsq{z%ZGKI6oG~`k zIrclth`=ZJr+&(Z{%ek4>aoHFV;mW!p)$^fLU$rH%_pS-^?KK|ygO-U@|!6t_*|r1 zJlBk*_7&Pj@Q7hm`M4)^&ZyorMh;ljO+ZMG)mtSO>L%G1X>X-5Y<8_t2p3XHYChLB zZ}s7gU2sOXB+a=Q2-ZKH8gV!!`8lMNTT{NcImQ?eYd1L)e3plhvPdF)sG!Uqf*-)_ zo7>##4H}6`I7;j^zc;;FV<C$M&`C+Ig;!UHX!<j~C`IPgWn+62mu*RuEL!wKpl)3g z?7g={mGfc-1OgeBkpVlRh6|5YO79P2EgcsOmJD^HozK}gRIHx7#+TP5@dp5}GNeog zR`Rf`P2^29n1s4Yzp#8C_2Hnx!YI#L`PhE$lKm&lTb-_T88tR-o>b(K1O4WnwKh9n z1dRPz4%{4z(ti@y>vw}=yPlIT^HdA1A&T!4nHNSYekGjq^zd7{-MSrtL~=?j-LVUM zH0P3IMx~R6|K}tlBxiZxtqbq>qKuVafNQtEKk`uO3Fv{O(I^=7g)wX;kYo<R9$H*% zt)%HZILTx_f)o>3wCnKG$&CCO#hqKfc%Nwd(&kG6qqdSLj%j(0f5W68Zk@4#L8`pb zf(r7Z%-g8+c37qc=ht%<#_%v49rC3s=jzyvVih~<VsQbo8Z8^g^QDy?Lj7utt^c4^ z_T*eaWG~<pm=8Qq5={#mb2fY`hfDl;mVf$l)94LW2!1jlk?MBx%yk!j*OPAK7r_5g zWAXa_vzn8b(oecKbRs|WhCbi|u`x6MyE5*njhPvw6aJys|3UoZ|ES2){hpY|2#Cu- zd4FF!E7$6i&H{(|Q`+{atRl6V?_6##1^$unFT#d@7pDH(ng0|T|NGZj)&42`uV3f? z_d3ge|ImLv^S=sB|85fQOwIqhCM|IMhco}#_<w2VfBpLZZ<qOJC;!W}|A)r^*LMEz z&itRt{CBPUzf{_PQN@2zhCjRR|0AVM{g0~nAMWNe2xh*5rT9qnB?%@`qWDQT0^@T{ zem~xs@%i6xU{~}1_;S8|sz#&!g3z)>g+Y);JxY+R3$2uc9&+7%*Sy9VKS4*qO-B~< z#!2)QEbjErPd#o%+)F;y9j!RHM2)r^9KE#P|M~leE+7BSNqY4-;C!ux^#qIXk(QR& z266g#%D;O23=Y*nYhH6VBCQ8o{7yA{Zk|avmlfO%ip;HB3fw)*XC3mo&%-9O<B&%t z-u2P^N?GOlr02$=?>awxOQYGPfSKGeQnD5Xfin$eGO~8QM@em(xHBDo54uxdI!gTr zjl(`rc$-K5kE*BzzG~M;hL)3U9&FP_)3#|PmjQepx&SV4&TAcO^U&LAT$Fr%+mN%a z^t%DW$4sww&5~^#KY^(z9+=vNzTCVEdXlr@1ELXj*u5^2Q6OSV$d@+*6vp`@erD!u zZH57|e0IhfE)B0q>T%c&xtd^sb0jFrT2RfIAl3UdP~GSHEhfG~ynrT5<!9mK>Cc#G zI3)FFOzWj)$DDveWm|z&WP#z0-4-Cs6#K{g`OhI6h=iaoIC&P~7zUmg*h8_qH5fLe znBH*M5AV7XIYLDK2!)D@+H_-x5(W!V#amdm8LUIQU$OK1q+b8>Mv(a}V+-B}`Q0y` z-uD&@JNN56kzTKw^?EK!FmpbQRZiFSX@Tul?(mp7zv%S$4|RwYv{9TZ-Qn;77m$XW zb-mz%)A4(^Wmo3#ujQ=GAHA-PMv=wtI2YoC#E!e6N6aq(#BI=p2_yRI*(l;nUp`qs z@nMuG<K=>+Kt*4EY^Zs$Ih6K98>%+6EOoc3vnWw9b)f06v7Fhh?0D5HB<n1$5~%_L z+A&zw;q|}6&=W)Hues`%t<^nR`pQH)B0)4aDa%X#y0z;@qJHiqYh`w3U3QDcCf8P# z&8kQITZdeZ9~VKlD|%3^7ooPV&w!zI#Es2?1QH9HiUWuMvwQxPBYsaJL4cj)RSyy^ z(uUQp2WNIWX=~5U-05?a6=u))&V1`$MBUjmlFvQtyZ5E-jg;o)_%Sz>K%?ty&Ek86 zV$t51Ur`(!L9V!mrO3LBSz6Npa)_BSGCi1<hn}rl*Md^MK=~V4yA8Gbs;XPx%<*sb z1twqp02B~_$TiY8CFep!EWTe{->q6s)*lYeZn7c<WxUJs6xy*~^#<hkVFXLWg&=lj zBrOH!g1Gp+jmi^3kH)IO#+_lkGrN1`K3OO)1+U3|5K+al)nY0N$!7RP%z}YM6a{=} zkD(dEpA<917GIE7$CD!bPPs4y>62*Mb~7z8C#29ZtVx!$XY9~doqHG>jrvpPirtlr z&OHs@iQ)l1N*{PVH&l|?amYU@c6iOR+BiymR%~KhqjGskaf8rpYvD*qps_R!^Cvt5 z>6Qj{vuX0TJO=469(41|kdkOOh6(7U1~{jrBVx&4&c5TSs6sTrDzecC4&!%Lbpdu$ zq;ERlChs2Mw}9We=X*)g*1xBoe-NYmkRW-nEnn3|Zqu+0y!+IanDa4gIz`#{D@73e zp1eU$sF9M)U(fd+SA&JW0I!>W0gQzmUZQpvFJ%@=A3h6pn3KvfAH`o6uk)<+V7_=m z5f6iSH{j2P4P(gamKH0G#B&iI&T;_Y%*NXB4ad-maPt_~%8!^<m7VMApGkd#F14f5 z{@~ixu+NEsaV?WZp{yI8L5z-OTS5ll#K6H(#EO}DrCDC7({OnEODQv(#ua<PRxjMt zeQl{~#lqvKftI-hT-B;Z-&LqZ@uV{4ZDZMhYf4k%CQ8AzQiQJoC{S&EA_0%qZh~8H zJiL@CEk=>=)^$!u)?6;RgBlUbYvygqDt);61Efl?IS%fu=th;mzE7LS+6c(`GmB4K z`F2JjTjYw;esXtL9@PXw&?j`)mEkX!E3Ki(UHHLH9u7+`{Rk_eh{p%w?Hh2=i~Z($ zT{y!cr0Ya6xz0$RHz3sK8YXi5tn#^Bwo$ze62uuJHv!)CO>E?-cO9lO;r67>_v4sm zx`=d=$^@!!LaGw$eLiI{;;RQlER_4Cw%!}3xH;r$m{WnYD=hbfH$$x+tyK0f%k&W2 zs4Q)STQK0S2Z6XR1m2)aC(Z4lnz}V5@JCrwZbBrF)*DCiPy+AHqN9E|b$@}CUJEeR zm*ZC%tKj_6`m(~2lO9nW4VW0<&==jT5IJ)?AN#agXzIXSuhLP{Ey*mH%ZbY3A>tSi z;yXEuRw|yoRJn+2MhziOL7#tCHz>l~8d}aRqfnd*kH`>?qb(W;FV)s71HAw+RU}i| z7igHg@4Li<imUrhTHT%V21_d$g67q_&xxp19(<ZHMo?kJOkNJmo~6MZti4--Ez~>Q zRom*BEun!M4>kKiJa!zzl%3tHgk<iIo634HsgrBF2<HX`Qd!Y-Ll5x@qfrvVq>Bch z-1+wf0jFW9pD&v?x{*v>2MR$eMOS}(83C5BkM@j7nMBySaiz`?e8IUm!xs#U4o`D< z6xtDV?=JHqV+W&dFI+9Dez&8i9wO?N=x)BwgIga)>c>tAtKmk0jx2>zW5=K@o>lg9 z$VFU@%AG&H0e(h*k>If1*x{)VDoX2eE3X@fDE9lA{n^eym1>a%hxqHV37+K>>ZyVz z{2aiU7hGnNbg1BvvB<JMGXC;~%<PFn-e<l3Dc#pGfs+^<CP~M?+4GB=1)SM!NAd8i zp>PX;(7)`+q3Lu?O(0k`gP$eW=+kr@x2c?X>Dw$Sz28ED_J(Oq?niRsFW+XS=v4%Q zIWzcJa<x9;gdEMgrz#P{?-(g436ve(DTs+9hJSw$5R;((?ys}L_s>MOVKr(lv;W6` z%L+J9eZHY-zwh~1xHQTCDg93${P)#^_UNt4=DueTtl?R}`)46oL*zv!%oP+xjRWzz z&gpwrp0fY@xZ6Yig3pn1+#c_cf%M-4#V$pHuQqqqdWsU$wunhOa!r<e7^O{Zp76s; zUZr|;##d$e^pbCmO|!nJW!`MN9OZe!^JU59BPxQ^*~3paP;`ESt>9vQSQ%oD-^wHB zXP<`<++H?r5u3`hS>)5p4*kxkBnBCLw>|~ZFh8-oRY4>Ra&<rFcvI~pv`j4u&W(!1 z=4J$z$Vi7-UL1DK?z@gA>9dwTEOm7aFOe(WK2cDjHpyCgmyhJ^z(qH8CFifrw%~UW z7++#BosQDvv1fb}go{=xL7hTJ<RL|~(TbhEroRByb=9q{1?)Idz-@LWftF8XHk>Id zoWvf&^q1pQTn4D54;lvC=}Yz!J@?0cM<4GDOi`V&)95MJbUB&obB%ydakO25#9BrM zfIQu{eST@yo}?57v*)Do<;G<wcG%<dQa6`~lE=B_y;12@G-J-6_IQDh#~k-?7%Fmk zVe*f}={&Z_;9D=KXpl;}Uo+d#t>R5$X?lyjwbagh?8+)6giMv4OFL!{)D_y3!f-Ki zVFO~LBpmF@D8!d>p;_0f8CuH0M?pm@p&j6lC(v?0%!#`Krzr01HN&T-FZpkwlV4wI zldM(tWZO;Svv!`~vdM!em@4|qCs3DEVv=24;olw+o`JgsxJlm0vR|si-)V2<2gMY< zt?bCLn~4Fryw)k|LOUgx9Wtb!)AUfe=4~z);2$f`mLfU3Ju~>BTfNVzn^nP6sYMlB z2HeG^ff`=u;jH&r!Fp34psy0DI_YHJPbvTGvs1PIZ2U_4?t}e7j}YQ9U};~QM%ZU> zG%kk#%wSRcRO@^hy**7Pp`+fp*elaSn$_Nl;eDGICb00j0(#V1FU{XycHk~y7zQuQ zrhjldDdVL8#rbL_bqAefSL5%Ccw~velk8d@Kvt0Hr}RezCK|k-7HP|3qV6abJJrz6 z)6D{Xj3F~wA9f=plg-oZQx>;ynxgH}1lDO#z-{Svcms~%wgT8h7M-Gr3ICD|-od%E z=g-OvR?)|assvHg?h@Mm%{%J>r;<6rPv%i^Y+}sd3ug@FWCyQAO=qkM8s8)&soHCk zagXuxIGEb%G6`;LvO}tss7n_CKybUGxu_TkLB`A#LfyXdr`rkYICtq0<jm&T=x%~; zd4ZFa7LSB>Alj##7uVR(1{v2636-5|1Ew$UL{VExEM_iyF6B^w>|a#1<w5*MSE{;( zL3I`5{G%PWqqx&Qt0sv(B(YtxvZjl$(n^FnWZgO~YOIJSRjyIy0hO;+w+$=k)QbPU z+EHAzIbEk<10@>`ki$0yzd~(ROmDD2>M5Aivt4laG{IzbdzMr@t|eu=B=^tqIUI8v zX{1++@clx_RNWe#P80h;3<!TAu;BWc6L(^2h;|;Vd(D|hP;{D%wQpmqS3|FC`Ym#& z0!K(ViFF9RnF}Sts3fCp*iw-LOQ*`bp3OCwkX&sYMMFmt-@82RH2BXur><<8OxjY@ zl`L(!wazb$)8B}{ZI_jRj~DRq53qUUsfHAa`7^>O<~WRNmT*jTuA+=OxhVFvhmpl& zbHF%@@6qWh+uf^V&bUn~8KgVPZQnur>!9$LQZ^Zx8@WexW`(rLr4oE$(d*JlFb49C z3`r^Dz*YO|2A4K-yWlCE=GQlG%Uh0L@HMj^G@O6L0rjYmblgT9FC(B^177Et{2G$n z>KQP3o5&88-X%2h+nl2Jk&3H20)<)VP^`CNW}Gfyykt7IXr1&(6j`Pv-Cc*IEP?o{ zVLvIWO^VNGLWnx3z>{Tda|3KY9=?i5gjyJ5qlJaDH}8}pnMCm!CjWpPONclp`>Q&% zd&ourIwbIZM8Hp%{;2o;1@PtZ@_3hfuBaD;xHJ|Pu=bR`HR&o5FP2~Dt6V&mfKffu zHMl?lnXob}A*wmvkADF^((YTEY5*`rr*{NA`5vCa`(Q#L9I-WBa<rS<o2Br3*WXw+ zo-EUAgukXG9B8<u%`|DOSeko8DICK=+3CiTkTf9Gej6pnVeN&V8EDa&@ajmY#8-St z-^{d!96)j2s@P8%)-gRh+A+(Vy>Au%ZH;9;6Mn0nB{HE#FeT80fEFu77|>GGKq!H7 zI8E^qQ5GESh@?WOBl8C;bl*2ZHF!aAyu7$pl_?6>-r&4Q51+~UCxyVyS`ZMiYV%ET zK(*2Jj0o=-;c-GerCYF^=f*!cA|);Fi{$xoJ%D3w{B+IXXa~M##nFb`o{Or3n!2J0 zq4Qh5%iba=e7V3(+J-QHSE4!p2Bl85md&zg=WGQ3=vojz=xwj26Cy94$cn%bWXaD? zSm~(&p4i-pdmyPZlQ@qH$^lQ|!Jb()fnFv(wK?)6t)YN0*Q)VmfDg%+8ty#Sagx`X zM=x=lRp%nMkeb$C05T*YM)Po^?)SY<hKoM>sR-w(>S#6*+cm#wtX?N<>TmUsN?9(- zTI%|!>ao&(6J@!Q)iurx?TgmePZ-i_SO-<X6uW|oJpj2!jePYL3U#|H-Tk*SSKzd< zVPeNMR<7SVshuR?ePFI(ANlS#gpBx0kq8~E$FWp(0HI40r0Y}xYQ7+9Y4*y8!L3nw z!5lnJTYsxDd{)p%-oz{h_Gu=O%Rn(6>F2=>Z1U8c!d6vYIAo%Bi(czmH876St*x*O zT+5k;A~y8~8ki>}QW|FT&5Y{k&3PFdG#psrVoK3|7GM2-;wVvT;1+hOhYXwACpk+# z*Gx8f?VFlTNj}g9{DA{mS%AK(JbF8dSb`p^m}yn)t7b-_%xFK~Z1=q4kSM0PBiH(@ z6Q8md;iQlUE7#Y*$1kqa4{Z4Usc&gOzjl3CA9^H3?%}Mx^_ppM!#ZPerw}~&@wa*u zWp?eayjHdA6aeNlTPX!7_Se9T<_+}@yyWuo&KZPe2lzEMPh4<Z9_~zHGXoY)tDx2{ z5JoN(IAGk}C(j$SsiAV-DY-gEvTU`I+QZaTZ~ADA|1hZgMi#BqcUg_G)>$iKFa9#N zSYoE%&z(%#-U{2O)R3lC4RymP9{uc#skf?}jzD!oGtyM@-h7yVypTB+(dmRf+9D_{ zeOGYK`b{bp7rz-6+}+qc^$aq<K0G?l91DW~0)&AJEA-83qFc>cxT{X<Wax%|Dzp=8 zYWMsCd_W}P3m^g1p>+Z+>Rk9qpG#*H=uQPlA^iJaGjo>gRw0;ZhPA<!t-*z_2{mmk z23jTwwFAwt0lLf97oaYRj7?p}#CjcoKd6dWvK}0jl#!4&5KrBz*)(G9dB<tNxer4p zwPzGv!?l5<h|czIHq8$$c8N~YTdOI>;{<PO;t1{yJ<gfcZ49xF472j3o-3`y@9;R= z#bkI1MK6=8jb>-H1r@8pO2U&z_X&88m<qGj8TY&K?|W`<@k0~LGwmJ1{ln-$70Nni z{ShFw1dZ}a691ZgcXwtPb3_c&h&yxTPfhKOl_ceL9W$yADXl`9%bxSLeDh;y#n;Hj z5m{93y5Ek%w}Rny^Tr6LC<q?!>)o_%HfJ=A)w>wLIpxMyJR1xhE8o|b+C}mU(1xRl zS-~FE8P`yNcE3gL(t$&2tk-(T?2e!%7KdL|KYGMU@y7xn#ji&j4lfKc6fESv+&yeR zlezYW-88K@YF_C0$;1LmCRRBFh^)=DI5){er5AO0;EZxKipPBGKUsJCO#GKQh`0wQ zv!q}&?6pYNKIAXJXXEVYOSRezL+z>UO+EQW>{{1*UiNUBO|MA@Er48{sh{a6Wl59P zNSraeGp1V$z$p4xb?eNPx--S0#OC((Uc7sdz4-z~bgLsHzQ=~0jX;R9uTqk({JpIJ zF9q%MLPLXW;x_<`!-Dt_2j1`&QaoqBhm}m>`@|*IHm%<}$n4K-Kj}>0Hxkt#<J>~b zFLyHT_pl6avH8kSu$B<k78`oZTOb5<P(q<**;ZSrc6!SSzC;S9(@j93$0Uwqu32}N zwpSt7VDWz4oqqcn&<g}ggF*>zQQQ0ovEIXPLnD2Oxb=#O3HViU$wXw4NluKZcCanE zyF;fLB&1ilPI3JPQcIFxUpAnv2Ykh^hYG!=v^-{J?FHBiGi;Q(Ph=OiJS`j+uRuF2 zT`Rgy^Ep+6IEbpox|2|)gXs80zn}XFvByd1gQD1oja)5K?P(G7J6N3%icbY-q;gn* zL?;Tugm%d_L-<I=P})-|M`UU$s6w(pmf|mFGJ4?3>(=HqObNFJqL=%-SX+0v<ezs8 zex!Cj=$J)@K5)aij2?SW``KvEtPaGCk#_8v4h-vvFr+gfY<*l4%^1e-Yg*lEhfF$Z ze2Cs4@S*1~93|l}b20VaX(%ii^;2Cb{IQM2Y0Y>cH>4?OR%r401yO$hcDh-2ML9gR z^_#%qVJ*J-P_X>ylBt(>9VUo!%n^O0%;F4mk~Z~{Gee5*goU1!P>Bij`qfIGG!u%_ z>G9Wf4r7Z?+(Vvp)XUwHe-*0gR80V6#~bv4yx?OtpS~_LSzOdQ=0S*^h#n^&4><A) zWKfk?dWl1o@%P4htg7wmyfC;a8L!B4SkhA8dK|}b#M>)pOTNZ#-}a8&YH)~m;|gBS zjhNt}F*dusquAP(Qcy=Kuv*2gB4TH8$M6qo_=*d|)bU7UpN){YLnyxK=i4vLk2WRv zJ45OD=QbzV(|0=B%iMnV!E~eDXPtIPE9T(uK@sa0e6#PQ35-!qf95)Fr^T<?5<gy; zq7ACP{_KiQ#^*6&G`=}@ZmOW?TvrR6pL|fXbYqWY+lDP&cK^MWbZ<-w7*3JBJ&7;7 zr^!OPAIaj+nL_ygD54M@{crL@{tk{k-j!|}X0jqb#_jY>T{pKR5V#N1jnW9Xe8qFY z`=`6@@vhVx*Z0{xjQDo&RYP}YwHtJ4Z<TaAimk;zx0@?r0+18jnX$>3#)A!^oD=IT zcE6s_n=kRCr!Ne3rtxl_ktQZKJTrX1`)4RlY9rpS(w13ukE00g*e<x?+=GbPNv)JU z*-l-Tb7nrWAb$7bR&~cK!5L}GCi%VY@*@KUtP7SuIkPd*+wiFhg65WF$PQ5l{V2l? zj%n@t^%`>PORvce6=yr!>x);Y`GBH^n~~|FuK~dPZ;Dk4K?QF0SdjBk-i&%YQoeG= zlQXSL#3kk1H62#wPe&-uvG-TY;Gsd`zhiWNEKiZpz82Jr@CQFJz9jtXpGbi>sn~lG zF5Lu5J$yVp6vHYw+sy~SuqbO^4lM|Oxf%+&l>XU8IM*v^AWAq?*)02jRyl=E`n*+k z7~fOg`ZP*~hpnZB+vlxwKm?B6@F{{loe<Z3jkxZkGls7f(2~hsAB8Hkm;pbXlN}-? ztVSO<)Mj6QkY+9KnNEh(5Z1C|l2YDQZ+35(l*rzH_Y%YkCE{fEf5Fe^ECbglN?Kf7 zbT1m0TE$zaUvzBjycYiqZ3VTfp^TBv52I%*>pR2D2Evo1@ieYM-WtH9GvZ=Z2kjN` zledZ|9+`O?@8qLYri=YdD;i}E%Ku1`=8k;pIUe2M;*lw3prHXP^I&?%;x~owu~|K# zthgv?4hSAOtB_@WHOFb1<WI)_35SbNlyYQRyJ^`(Du!>rTJ%!Wk;B7&xSFUR@WrF3 z%6AsSHk?ov+VoM~n-nny?{w;Cu8Br0DpYP9PH{GS!#h1E@%rMqA88a#@Tb0vQmZHg z=`l=By~&Uie(QW!V`_v>)ft{EXn+R@3y_SOGx6%G1^DL4G?EQ_<49t|yeItIwa!ar zDVNn2J3G+=J@i0l_o)W_z%hzQrHd{io*s4bszs`VJE18{Vtrln)K0ALoIe)&*a?#i z+&uX^4w?7)PvwN_5t(eg`kZUiG<5CA4}4fx1b^oEpAYriiZiOK?kL_FN~k|4tLy40 z;U2Dt+$b1%;am5-{Y2rQ*W!>4>3+59*;vcFwHW(A<%Qp36mH{sw^H4Kza*8iE6?Wr zVOiRPs=SV=sm{W-3Tpi@q6iv?6F)l)Fi)?_vasFQrP-G$p?G-hXYTv&*rxVM8)l~o zJ!dTKvF(g?osEu=Pn@sinE4^uRscy@IJbinS@|^ncKRg?RSQ!>j*=$a#dkm9O24?E zwO$t?;-nfiAs4#jx#9^y$jWASx^CrK){YFn&6avzXdNRM2!r56c2=2tD8iY0qXxD3 z5-e%rJl_lzcZTM`vx#V#h=Beh-B<8F1^iNws(Xs@d_&c@O#)|Y%yORZ%g_RpN7Frx zwy()GTRkPkD8MRt9q3-(`kg1Jmh!@OE1wX7wo3PLQ$cKe;SgW@={YPszW8*qcSvMA zd~VPy3$*u9LF{tgh5mOz<|D4d4WG!S%!Z%78vk9G`|)>AANC7%CHJ$oC+`D3l-<fM zsn-cBbt@BudGZ4FW1P7Qmp+X^)sGSEQIG{yYcy^@D?p3&svfLWO52Jw2HkDMzex7W zG0Bq9h4JI<!f_F+q}6C2jqaJ+>D-FJw7*2jZHPm=vgvslGELR0rK)MK^JU~_oxGGl z5&`yNfXSz?P@a$?Ibuo2Lz3b67zdwDSi4lRbSpnxeoDNW!6SD@Y+|XW=xs^cP4s2G zfGoSdh)UVgwHl~mTHe#QVa+o%p>#0rz3z#l1xxPXwT%})Lb#z{JCD)~+V8zPuuhMV zlX$qcWIShRHTqz&P%)YLDMjEs99J{S%}sVwB}=YtYdrFzD?$uWJDwNDlshk7FkP?_ zGW`K3<4!=A$OZHIs}!X|1z-bAQ=k}HdlT1S5@`rb`1LiDdcRbrm9>buY4?Dn2y`RB zi&&YN;w<c)$fOR2C7nCx^F1L=n-UZ;RIuD$6tn%D{h8q6vET~+!@k=ce0d;!^L%o- z&PYN=|8v=pUjS_=U5&DD{g%zlY96`kq)QTS@l_|;q6zMi`fGT->`d%SGfjD?*4fZH z*e>=~X_4fwVfLB!_T2AO3;k0Qb{4fa7deDU`xvq`Dh{XL_DA^|r41T>JO=jt!l?A_ z7vS%qd5x43H^2h$ZH1a;xeOmqY+j1{%jnXM^EA}XD>;6^`^y}Wd(D%XY>0IY&Yn}k z$6B=!yg{iui~1cNBM&ve`6x#`S%UTpHniWLxd(Z;=NxBsb~5lx7n-tt1yCH6rE8wG zC>{)zRaPG&+D|*8&JCO3`f(7>z6pf<9t*-M-21q;VPPu5N^FPG|J2~$iYw=WEtp`( z#v^wVuA~1Jyc%Qu>e3$0gY8c?J3d+$obY#T@Z<+Lzq@ttZ;d!o_+3lbEhdNDte?66 zFW(Z7Cu0AGMer{W1pfpm`0pnK#o@evSBvK3u<9^WR8g`PiPxv|5krl!$lkBel5()S zRjXS|_!e#<+;gXZqJU!WSx@AH0)YJ6EP0urT9c8VD_w8=nMp{lpLvpTa|(ot;?fLd z!&1?Mxb=9)5~t@}suzZc4ld9LkB-C9hfqM+{KXb#K<uH4hSqDBzWX@x1uq=60svCI z_+`r{d`q)mH0smLBF0D3jU8VbJZW38<|+}5BH1L(Lb@p*i&L52&^B;aUzWc-tBP%j z+j(U8LGttMi^wSuY?4mvRx*b#=PhyV%uc_g2v|9q!$a5NB>m3QY3pvBHl^hy*5fm2 z-|v@?%p`1}p@!q4y~jAjL0RA@Hv60qE?wfCfftfn{H8mhqLc|$Zf3GVY4vY2@6Av& zJCS_F)m6E%uEP4Zn!mxHk!Ez-W2UZvVaiA@&nJgGEotwZcHp_uDm@CMOg)xc#oOS| z%$}kKM>mZNHufqH=W&zShdxd^hn{`75YQk46Zl{0RSNWa8Mi6`@`AuH_Gb1Zw1kfN zkQY8PTMBo<V3J+eDiwqK6x>`_AUM%K`kP!~*LrOc@)iEkSv)bxpql=L569!`*Aq~o z;BI(tEdmLe4)<*^sjf&Ky)rOt(HCFN5h$9a6%~6WQMF|16L8|P0iw-w)4`f~QW2;m zN>14??xsFI)A7LIDA+SPTy_c#ZC?JMaRkb<KK~9f!_(d0N|%8=ewKgz+d+J_tvguP zZ>U`*5<B^Xj`X5I$TTBej|~GQ(e;CnIL2LyLQIv?!ngX@4vG6dE3?k$PMpr-@|x`g zc^@hn9C#dHTXbmw1RWWYPWguA&Zs2Ix9Hp+k50Sz?K*S&BWt51{B-$Qxz@9Tpa7+) z=9Qpej|y*L=<~bc6M<6O>M44?@a7DG586!bx^{4JG^oN*cQB=MDXON%Qf5bs!z-ok zg0Z%x^pQEOb;+$So@oCAL8iAX(D@ujMub-IHSs9iN1y=umOoF^XDDW6Q}q))#lyWz zF_5UFHBX?InQeb=1ME>#No?;3vE^I%=15`z3%*PH88nO3@>AqX;7eaYZ~g#5w?mZK z!$}?{llae+7wLlFWATaL8iD&R1x#M-UfQy<^Y^SLD&NVH6*Vo`C6#OzD!)V(gB^}i zjBiXjL{ZEwT+Plx%n`WLU5I3wlphcXxBKa6Y){gmVlE#&%|0_bi(i$+s+E`>UhqPA zfWEMOVmuyvKDPLu#g4n_GtwkAzRyCy_k-Pm4J}EXuYj!>@@}Vrl?T&tZ`XuE#vX4) zDo~!_5Zce9-2{&RfcK1SMQw$NKbyPx9We~|S+EH$rx(8z<ZS7uO9(0ncz$b)_$uHs z{A70?2jqmkEg30ASt-?DE87#+ZqVV;u}^Qx#ofYhIwFV6%#^oIWZ+S#E=yiBilkq` zL=nOh=W`Q=mDExi@FW|%j;&krpKDmqX7qLfg|E&H)$#=z0VYEf6ibcwJc$Jw3^mWL z0pk!(A8-A89%pCQ>Ok*jbfCLl<eB909h77G5=-{)q}%=E&UgKiW*XQp$>|VhuxvYL zDc_I7cqWp5%1qn6*e}q3>|_=!PjBfh-lDA+e<jBZejr6P>j2UePq*GueIc<dCdp}1 zP1!37X<N_?mXfo3<-JcxYwbZ?u7&FN^`CZ)_c(;i#T3qdkD^LW;8Akmk<eLRHd-Nk zFWyV1-&Z|Pr3U}wAyjb&#qd~uqXWQG)_CuEv*(bGC@CZHBV8N+7OSGt1nr=@dPnws z?}>{7*@Y)X@!*xdUw|iFA-*SLvcZniVexXbv!1#54u%1&8(LlYCScrBuP9YgYM;Rp zm5zrY`vq9;wa8Fxq))sKPxVoG;4_Nc0+Bm4#g4mFB59M1ewygAe5P)LN-n`>qFuTm z(c5=K*>RY5V2Q=&h5FMf5bv0UU`H7l8#Y&1+uVgG@t0??y|+9B-z3@+@sx0>6am+3 z+e-bRY(MbV2zqF_R-dFI*Xs$=G>vb+5JT}a6mKd>gtp=k++;3)57gJcM|aJ?!a#fc z>&+b}u=bL}<p{{2q3xl(^aIL;=oLl7whqDd_I2DSdp(@A&Lqn;e7!iO6wFYiq49a* zY0BcJf~GqPSPH?#c9^)yjVC?(Q2$^=0n0leQEQ;-UNPKpxyu9h>j4ISr4`pl1mT2N z$M4H9ErgLjinq)WFJJcDE<RQ2xj~?d-%BM_HFmmAc3wvqY6-XNP_Z-{YfXsVThIco zhBk%|?jvA@Qjsz)va{V4hu(Zc%(zL*rB%cisGQ}};i*sdkk8Nzz#vztqa3;8Ar?W# zwFV5#uzNKHEJ^vQ*6bxuV&4*2{WS}aSBy5;3)R2742sOm_@N`sS%A+dO&u_{g#V&K ze=aThL9TY=)D)6EwI`u!F8or|=xJu&F4G7GR}1`0TitNnBQ4+g60lBZ6dv;kr(&Pr z*IeBQ1#J@qL0PSSWAW!=BVbm_Co7FlCQ+Ya?e(f%PwIxFs4o(#wkx384+SS|Hr9i9 z$t>CF1`Pf7z<71+X`wa9Ou|N^UW#F9!b+R6?wTCqvm7)x2iFHvdV^sx$<K=oha-fL zX)!ByUvmmP(2vZ!Tjwdt1mCzl{Ij?*J~PQJ*X9?h1BUJqw>qU>C<7ykcJ1yj`tWOq z*bkjc=-uIS%JvsGH(Iq+P{z2to|ERsW<}$TRjhZ?Q%6ahRplJ=&NyWy-mvTFXS>MK z=}AlHe%+vw;FGr0mZj6ZeuV-%u7C8vR$a%S35Y!ut2_GkZfIzxwb*g=V&=dVnKVlg z3%4#4YZI$+u-1bt*7tM*J5#aikEu$3%rOl!ZS{r*@KYW3vbWeisY>!bB+<^-#O5mg zjHXI4N`1|uM*x0^Sa_|s@G#!Ho%MJ@)jTuH$?iO|_t~q3MzdJzi$CTb!eb<)lGpK* zrd9L2O^?=L+)4p)_>&i!y_!}<F?G|bXBxxemvP3TFD<nD6?am*ptM!xPwOj<bEb~B z$@r7cw6TVkh0s*Z>j!?m3uZ1QwnaN_IG&WNxj!QeSW4BwCY+J0{%z!FVqoSBbwL@g zl#mwz@U890_4_vq3jA!pXBumV${{w3ROL@EZqCkVU|OLj;is!R*b~R>2LK!;i3fpn zzQ*jQKW$uZ@MhDP?}~tMa3ik<o;J{xWqmWKx2Jf-?6|j!JGrIzn9+8IX=?49K`y(` zRC4;qBMocXwcw=wR1Z4%s)vA`e5TsNk-?vhKKjdICNB3MnX_~%)6cHhUd~%eq*Gr& z(eQouN$Z*51H;9lG(Ow?wex(94{q+<o<d8{-0ghqM?nvy!c%t>x3<N$+?SNhq5W!| z>!A$XbR8ZAA3YmK)1^u7E2GCC1fS{8@nIhnGR`J>=jt|kAQ3owXQn35b8tIRs;{j} z9J9}DIiIzd`93Il_+qf{2zu@9@9R<9DNy$&K7L$zOA1l3L^O^`BP+`6wk$W$-l-sz z1-)!_=I{|efbMD`RcW2ZrxOXn%86}HY>ehZY5m`@*o&5=yyI#*+o%rwkicO%^9$g! zktHjeqsV3uJ7K^$<m>iLIy}6JKYTx4Tkh#*pT<9!YFaORE=QbIl1whc6sSOLYfOvx zWnE4fpN)}m!!+Tm<}7#Nq9oU9&FnjOjcYi$zHKRPm$i_zyj(d|O0YsP;O&XY+rhBU ze8MP@J3$==yXmpN0Cp|Gd0T#D;ib>D9$XuPvPvY5|H$xrvr|vHB(1rETyQ7(r;3n( zea~gH`-?DgDZ{MqX(dh-QX8i?Y>3U#9Ez9T&hy)!ZZQ7SDkMD#<z~x3zQzWJn-(k= zxkg@OVjb&S?V4Lzq6X-<+NzZ`rQQd@XIg{DG#rXZ{6Ed<3=3=dMg(_OYlx7g{&lWh z+iz<sqFpR#sQSXQ5nww6r{uMkJWH~$EK0fe($LJ8nSu~rRg8mOH0LQ}imfA>tep7H zopyxSB!07XaSf5-RtSW_oD3L4YjgbScB?c<*C#s+HJi%P#!5-N$ja~e@JnC!z7@J7 zjc0CxTgmc#!nPB@Ne=3uQVq*A)2lDUvLqG{^i&kSUt(RMg1fjdyElVRQM^-atG|%+ z0r8_y<_r4_Ma#@=`3fUu*{y`~dYf{Q=j9MVVyL9MyVRY!_VdC#TY*xl@BRi_NTAVe zhn0p<-t$9BEIC=@C~6DDuxyX<^P<eJ%5<n2LR1BS?(kJz<Z7@r2T?qp)&)MQp)By( z;*$=}lzKwKI9p?*U*9#o&;?~Qvr7#9F!2$r>vK1`Yk50~r<^z!Z3~L+X40P75j>Lk zoKWfQUZ*C|k3i*lm-eKSQ#Ecs$ur)kQ(Zz5Q95Bz{%$4jmkgj%NB!KHdFWb%DP?kG zrN)Srk{XK}hwvge=?D6~TbYG1nD@3fWyhY{X6#$Dd4IBF+U-0P_iYuzvjnkTY9}Q7 z`E3x5!0I|RCN}bxo}BB0j2%53@aQ|>k4+HNA=4CZ?&(AzPf4q4*B66K$0F|3PlXIi z-4I*?@a&nW{GQ?<x&b>eel4O6qENIuK_4&tA=fs6GYxRNFu&y<LOd+Auh`g4Yxj%a zKW#d;{9N<<?W>q)_t~cYb3qDXI@#@J?%FjIu+I32^yZ;bTIwgxo0au&656$IjDgQw zk&^={hA3dXaV+5h+n<$on8QbhvvZyHbPe$>pU~pUOdfl>)W6G1g8v|M%4Q|(n4!kE z2FFDTDn7y;E+TB1NWLfOzF4mDKOcW}K`G|1wAwskyh*Du^3<O3V_?NO9)2b^^HcaR z1wl%C{9S^73bSy+XPU6dzdZ8mHS)IEpf|t$G!MeK&2ZF>NTmQ#^bsk5szu4kxkUO? zYtC;s4eQ%1pRMjN>i2pIeGdTy4b+Dx|MaJ1ICtAUzEl_+_VTB{fAdaGcpx_Bg7<Cg z!!R2Rm44!ONCxtR4zF?8G$uImZ3t43XHi3spKfz^arbX$5nS!TE3G8M{Y!k6m<;S2 zHRoq+|Ezte0{y4Up8F=F|L+(AYFHK_oA0lXL_p9{RKg7({9cf{?(?TG0Lw^B;sH|D zuY`S;WBY0*EZ|!iSiyHi{d52C*n#x8`jPg7nb^+gD9yHzm#(%{aCVNiLS^jDo4<~z zcODR?K4#*W?EzLOtAnADC%EY>Bps0V7>35hNUU#tbD?LpWNqa&Hi11t(}jM>HEvo= zDaXzUxmn|IXM)QKqT}NSgi-mnN-I|!L`U@u+_*HzG5ll=s5m2SfaKw^P6X|^OSUYH zIZcbLK$MDvL4=eOHpi~V!~D%Czsi)KeW8w>g;wKhz}=H9AL?^PnrSd+xk<E3i`l1X z2(x1OV|t}yF5U0>cLS6687IQPs^Lju{er~O7uVFdjU3RliE*YpdbmSXi%@*ASxj|c z^(y4P>9g9*4-UtDY12<KqY};w<IQMG7kl6I(M;==fc%`4L#Y;dfwyIMl2~+PkW8)* z_*2JnwGI=8gB{-(!+CTUF-hpm+8UQ2&bTeU?H2HQTHR2Bc%>9w^5MvHF!uxj&pO}| zm#iIM;HN?LkLq6l^OZ+okthkABfqARCT#a0^`CA*?iJq-o(?_YZoEfgRNIR)NI8h& z>UDI6XSX%o-&&HS+8rEtNoAMXIrJWK+hZk@5{=#xX<dUD9PluqKtXWp0VU09`;<OY zpUFSE5cYY~QrX<_H<mxC?d2?y>n9Hud?VSh`$aE(@W?O>0DbkY$Df`DYJeL$|9I)m z&H^rHXcz8J^(EG9T2*V;V|r8YxaRhYzGEHyu$VQ^;1&71H^T%2mj*}m%g2Isdn*IA zNmR&TYV||NmAu}b!Q7J)iy!jm7iX*QE2QU>yY{B(L2UIvP9?9qxb4gi)pc9DL65|( z+Mr3Ro}D}u77d%l=E3JCKKa=f)m2o@i&2Z2POFW;%&wYxQLJ8TQD%*}uiU66zt8GR zFTvKlm<rkVL7nB9L3Lz*O@LIY-V?Cwr8)NUE~h~~`%M@06{{CNjCADyojrw0?Z0MQ z8O_8NrLB6Zp9AZiLj(*vCpqc5t9goA|IM>ICmU0|!Sc}XGUvL8jYs5lwIS;3oM>5< zl1Aee4mzdbOdmQ~>Yt6?1e2*tR&CZ9jMM4lCF53$rl*T9%D4KTQ1^$X6~#51UWAaF zWKSC9nbo|T4Xmz-UI!FK5Z8<P0F~DKDBzS*>dN%bcMl}5@2XVO!+bVIP?<hI1;mbI z+#uQ*=;7gwwstcFd6MZ;*0TZkMJ=?`Egm&2ar!pUMP;bkXJ{q&I~Sybfz3rZq3sZ) zvq|@-%OF?e$)<FweX-lypfju+#5KQSJpZUWTwbnB-#$6tUqhDPtsDXOc!74L`r;x< ze|*-k6_wFZTa>ELo%19VfEHF;;yRaZe0dx`VFF^wlV|xd3mmV?lCoAvv96Xy6s70` z8Kk{OeMNW|w4ZcWZhubD_yx#XT10Or<FJVvg(d})a1Q!peJ<%1>9nmE`tqKV-APuu z3+fgXHhm3$pq=lJmJ^%2R}1W`R_;seDk=k&`~nn#{&bl8;Ih7~uW97SdQc1DN(=LU z#U613*`FIbWagM2>^;P-B1vSU+kX#as}BQu4K$I&+Ojms>+^W?>_`+(4OwSefv?HS zn{$)XI5Yt!8gt&Q-tT(_>_so2JNkT??4~s|pUkp#R*oC^H>uouMsT`}Yd`F--#^vD zgQj)6f@eH4&f-xtw5!|E365UUCyoktF+|Gt6+#=iftwZA913cLo!yQfE$_|suTzcx z0)#BumAJ1*95WL1Kx@4OeaDS+VXl|jb2>pSWI8BAO>V3+y;{BRw@k;tDv!GG3_WH& zsQm=Uv4F8NHYl=d_|)JPDI-kmtP)_h(nCy?1Ns=OY2dvPRro~I@sHB|#<>jmBgH;k z{v-+E?I;e3eikC*bZ~-QvvZyC<`2aseu`_Mq_H#r0jTPcytFJ;jQDimUt?C9Ku~PR z{mf|<wTt;N{sbd)E+(z}kxann9ED=ATnaK0S;XzT<x5Qn#xyZuRhYTsI|DLXf|vZB zNRy}rQMJl@)6>YnlB{$7tD=5<vG)=gSoKGFk9S=yDaf=TxIyd=?2Bo#7Rqy7dgF@V zM#H=;Ps4uF@x|N3MuTD?51fhVvWz(7;lTr50Q8uOkDu|eo6tri-@|zE4=iGqbzV!{ z2r@@ej(SU)K{E1XE}iLYLhlwvZX+C0YtN|8f=-|2!|EMM$>WDjR`etOTwo;RO%00M zD7gi^!XiOR2W{FPh@zHzC_GNs8_?b4Qqjz`87M#DXpp!)5XTitk#sdJa96Q%)bfrm zrwHN(l^}$TWg0sJ2~;%0mAF0QF|g`=7Aw2PytV-3dt82PCwmKC0sfW&m*p}V%sc6O zYgpblr)&b+?M7QEpSRpD{9!w{+OSGNHAxtB7@?$>yhAD;Lq9N9b#Tkt{L!*cLv;t! zL*Wlun*I&oFcE3*&1*~X7~jmaTkDJz`o)_EzN1A8cJu>TWxxCM7*teuZvs>7c%`>o z*>w-AI6nq@2bS?`zfnhseyKxR*W>h(qLxTi-x}>oO0J`0NgOr;#EqU_el_0y`IX%L zgr(-)O!{b=j%IMpd=rH_@iey7oPspI>_tHxaP&daB`2kMA;O${aQVUGD3EDqwv2Pl zY_ELS3)d_;UP7iYTaFt+r<+MtEr;=`%;;`4^4|N(S%BtqpuuMeL$fTK3hq=?7z>7$ z&^qca*_pS6oOsOU3i+KApi?EDC*yk=%4zB+g}0Y-aC#c_BPXdFbC#Lf^eWLTa)hKN zKJjofmZCwNG`{9VjelJ^fcks>-_sutAeXO=-|PE$jR1ZP{Jp@TClYlt;qkVgZiZ9R zyM?-UXd+gV{{4u5X;8)uqGxqJmNC_{*u1PzxPu2%v(KQk2R7%Le2{~=-n#@R3CME= zk_<4mlWzxxJy*lwbEJzU9AjP`xJ~sd(Yt?ceX8gR>nR@l$4=5f*MTSX*o?<A)QogD zL?D9e><A_plrLn9o3~_+x2$hxi@j(5D)x$VXJqQiT1;y7*lS^cF{bT{^vhkwy!v3N zgPkPh?nm2Vw_laX$1Hrrp?|@&yPA7fDRU6bB90iOmEH3dB`f)^8*T@KdU!synwNdw z!YR{EQS&}6RdaeI8N*p(MQTtTIcvTE$G7$hys(?YEl+tpIkZW^B-<5lh&cNM^FZm% zjFqbCGe+rM*nzIYUN37GKjP6|>hPp<YDJ)m#E&NmlGz&U`R{aXnkslsc<NyO*;(Ia zfPHq`!vCwi_W+Bs*A|6`qJoGtL3*#!rGqd^FAlvIK|o>X9jPNt=}1?4@4ZSFqzKZ7 zUZwXww1FA^(fxh9-S3?LoPGDc=iYm6R-R-fdEdM%nLL@SWUZCw+f#`)M<H7(^0O8% z*32;_wmxg0^Kp4bVkcCMHM%;Xb?bIBp2vQIdVes>;`n?Aqj=p=IW3PPWEXP-*;*=) z^-h?CSnRouXdv9Wy2du?L4$IQ>XNJ|;zA*}Y7@`$-aEsqSVJw(EA+ZymPI(NSldOU zgvbnk*_$%`Y0+!9D?CFH7SOZDJtR7wp<kY$i5ai1-2f<u6ycIBAiFl12e!`vPxVI4 zGGt75YGRmz^mkIp-ZwRbyV-Zf@=vt5BHXnY@wB?Y&8Fk$8GW}Y-oF_#9M>{pO`q9{ zb8+jN=eV=Q?tgE)Nz+$F8g=JDWJm32rmo8KajMR<=%C1sP+0HCThC17_%>bd9y?V+ z4wSA0OQ9kl#$>*5WSb=5LgX$T^1F;=K9Zg(AC$l6WxHJx_2ukKgwy`ko=gWy^wp(t zNp~xL67OY?-fbPzInQ3-mc=(bkXKnbdsp*;B3_hDG%b;@0vW(xdG6Hskye7hfQw8Z zN}#-s7Z?&Ld7aQ&ay8OR1G7=7OYdyn!Y|yZ7gJS2jW{)|Ev{S#hWM(wdnMw5a-6Ti z^*&xHpmfK6U#fppI3<Lbykr?eWx7>r-=PigXYwBmj46|YiX1$Sj9Q&>RGFA>qMnu& z#nFR<rsq?xn82ouHdS@IuTTpP*`<)za)ZvhD8(F<u^?C|Tq3r<ARJ}?Jw35?Z}zCV z<kP0;-k8=T6qc*-L`70ZId9^gJ<0wP6D3d42PwPT7DLTGZm?P$;_>v-?#0)ryGB|A z=bOcRyi*2nJ;k~9`h%StEqBH@r|a*|t$>rrVV<DbPxz}1NusBoa<=mnDJDZQ<1!>~ z@fm!Sn`1m1mraW}sMyoK<k!d!@ZS$%%F3x4*xfn30(|+YzsWbUQ&e_#D?no8k__3u zRs32K<2{+ik0j}_EqnNBWhV@z3EnTrDiXwEsSW8d%;kp8eXdK~1#cGBSik8ixxXx( zopY(20zIwU8>$1p%UAMTDnePuX{IF8Tht1BtpE?j1M{{UiLM=;MeJll`o_2rQ_~@G zO05ay6m=_)<LioJZEJbIycEX<2?&dQ@#ahKAq>CH>++3t6WqJXi>0BJF|>zYz5YNl zzTc6!Evamg=>oInP$xg-^{Zxau<OB{xd+32u)PSJ*&oDC;w{Ge9QS$}_Hl!6m<{T} zTvMONnE!QqG}p8xIYrRjhV*hqnp9fK&L`Ms>S<N=-Y)G~fH;9pU#mLDCgh93o^!DO zEOE%x{q}HMfZ|b`s@-(j*?f3kkoIj%I<fbvoiHlw5*AKJn@`zDWI}oN;&l9M%Cg$& zDf)h_djfMT4SgZe>l;9Ml_!qM>r7?qYIoh^sIdCmMlA+{XQrOF!%i&$Tka-g>J|6e zrtjxY<!=w2IaTME*3-Le04`oh)>ts9QU+n3V&^Cc?LS(pj97d;S=J?TFaP#qdui+z z9WttQUQrMy?LGenXYoL4mJD!%>iuxO)$*_G`a7j=llo_@X~FrruyCfJx{qN-u4R2i z%AI<fp{@z)pOr|L!P?nMMDcdnbAW*C;TE(>@iLwH^cS;aL-0>_Gmm7{^j+Czcw@Is zOYWmIw3Ke8V({t!4fhXtdn*@n$Ek8$uUd-)y<^IveyxXJtuG|HC(yI|=NeH|#tli1 z=hXYIm;w`cm}5~he<AyH+s<y1JrZ(x18Dkg(NyMnzezyA6^39_S0NgXA1SE)O3~F6 zMM}6I88j&A`f#Wj(wFupuK5NKBtS9|bsA4u0E`5Jed0+-nMey65Oj<v>4=4-F#TM3 zZ6cGb*!xT8pIWnCcRwjQvMDpMb><4k<rBs&tEVVxg#7<y?Mi&hVhyDa{(r%LZ68E_ z{X4zQ@&Z^6TEKMLWkEhiQ@urz72EByQ5Cgorc*RM+Cp&)n##ZEcrM;*$rDuMRhL7l zUm+;ne+lS{v0EK_;Tcv{gs=LgRi{sT<->o|gfMfp*kRmOJJp#2zS>XUTtS_i&HY(p z^h`LAV16D&i-|uL?f)h|VC;XEl7FuTHlE1n#z^sib5rSx@6T(#-$VI|pW$!#pK^XB zQ91w5|KHRD6gPlj=uIbpg#dto20+6^N5e$LKOGtYAvyp9pUB|>tqIT5w;wQ7Gb(Oo z09a_~Xef__GkokRXiO4ampvT}-W8ZFZO`u8Fo5n-^VKa<tk_4OjJWy?eVQ6~*cq4e z82q*?66xAx7V}2fx!-|Cy^M=%(=Q02C;dO|I{W|RI{&JsXH-4K?@Ow;vh4PMcL#Mo z0;Rr_nPnE|+)Y=lz~U>3fiuXn0SxHT#n5vLalQa(Dy*ADc){DVCsOwI6AK!Dfb%0| zd3p1|Tt>dx%vqor@-4Cfj`w-}UGNfjeoySIw{&Y}-t9M7EJ@c7pCo>rHHxxzOuK*3 zCRGQy2T_IKLsWeiSI&m=YDX?^05mJtkf<Xhu;-8P6laO5p^|DCdDFkdRktDJ9sQt3 z)M-a$(OU=9MO$y}Es6)r>fGBdD-Qi4qkH@B^{1tIzF<4$5<voa`%^=ESGEs{zNi$P zOt2uasen4C7b2rbfA1IE55u~akKQ!D;3ijKjQIz>?}sa(Dh-sniaH-ysP)r<>Sk^K zF<*bRkX}*+3IAb@<(%IiFqn=<|Cq0foD84mF)xl>;Z|nTvF_9~Z3NZ47Al;duTnrV z!4T$nd9%B-wrwUbg~19@>uw&8@B?9hG-Z#5$ZFOd(H1|Y!ohrjEyLaI>i~D3W7)F( zt<>sb(Gkr3!P?TDVWo51aV?Gf&B{)Q*$9j1m#uQr_I1AIGk}}?iQyJ@u*TSzB}~^h zjj8YPu(qAOCBg>>%ewckKE%kQvrsmXA5%f=TwF`-4aLMJ25ZavNB3ipbv%3@@V`-z z5l{@Nyyqj}BWhE@#nqZ+nvdD<QQx#03_-H3t}whc6VGrm2@=5|U9}b_eEgU<v$AZ4 zA!#*Sxw>T2A=UiEWQ~$C<>cw%k57<vEu+cX`@5SIO{JCu#nsi-Szc7sxgM;$yPG@V zvDHnYOtD&SHvnqNpTDB#N6!@G$1CoiKTAHayBswk00{u-=x7*dw=vQ0+(EzdYeqmP zP$#70Rl}fv_R`c5pZ2kXUnUU)-&2$5_6IzYZ$D&IsyazI`^RKeRQ)zlU;t4U8NP^I zuS4EfS1O;OhN`@ROR%4uh=B+YG&(L|qr60;(;EPWPtM9xcGQ<Wh(`X_Xi0f)U&<mB zA%``jyjUWUr0$5a@;_rUG;P&Zh>){&ob0ac72=vn_wZqC)10&Ox*Fj$N}fNdUiCDY zg}@ttI@5V)lWmnVzD>qZ<+e=jJ^YBh`fG|aySq!?9#N9+TyGMA7K>_SH0=?SwRi<R zUDp&xG{ylmYHb1AzyM$1!GZBD=Fvl<HfHylOXK!OZMB{TwY!3+N|!GDU6t(}lhJq+ zR_kX>zL0F8AbzeLA9<^UvSd7%0gNPVXdoW0*&Ng&0Bgl;Vr{b~$<HQwqao?-lV^PE z&`3gBzwEBNTNg6HsVnCH!M~&jBAi+kLr<=Zyu4GVu6)W4xFNAkH1<`!PT$Of|2<d@ z{t3UHXca5}_0FI&itl%u{My`tRNnPz+ewaR4#~A8DlQEfAK@>}{2nM4W9`XUG$PPP zz5SU|-ACbjppwsLk!D-s7rn8?S!!!Uo$<K_u`x9v68JEy6Xy8IL(b4rUKsfy&9i(d zsZBoQ-SU^H6ch9Z94}-3+UsC;X#sV!7mJ(3;{4Ik;>OC=K;rq8w};ThvE#8_<W)k! z_#*v5Z9ZiE*^48%M@v_6)nZ`Oto^s9NuBl02!zs^3#%n4f1z43zE_O+EM}};IV_y2 zjJ35-EcbJ6nP?);G2yH_B3UB+N;MHY-88HCz!9EEk$hIJ?oPt#kdUj%Lh2*t%AH6) zzRQBmcmwD%wF1?;_8lQ_O=mS&_@r<NiIvYC0Qqe`z+^vp7NE8@d?b2?o!s}&IHln& z1B;YY``!}b=X;00b^DL^S|<Y6+$tLfK>PO|Ue~Eph=lOeu!6?u?XEE+nSaX@*Z<b% zt&{GFZN2kRGkcT0lAXF?1g0D^!IdQRe?nChw!~R-U}>?Vp1;uORS#;p=)cYTtKxqX zjsBZj|LOz(b!f;4<SbgGRVgmp+o<j3b|^^WNFtRBN@<=bG&~w#e;t(D3le=`-&&qO z(|SDrXj{fD)^p-q+O@rbUE$z|m722SIOJ_pse)*zOl_M#u`GMgP=jOYS*T9Wm5uS{ z-0X|5-uE>|&lnq?$7nD2F82z6AM5BFMQ*3YPjCBJg#{$Ht#X|T)o}Z3c^diTAyjNH zXlj(UOCv|zK1`hF?~9xnZ9$efd$MbrR=T3DWRquAFdTPXK#UDSdol3xb|{yVp^EHm ztWlurNdaU!x9uVdWvh-6PN~(SqAz=}XP6aJ(6~H2YkPw1&}^1JmE3NfvWwg~m-B&S zJeQBAmkuFhl#j*_q{EW@7Y0EHl&~j%t(H&8;`&iJylk=i3Q?W#JmGnwwo)-u>@OIP z+3s~UZ>$VABkkt>R|bfyZJ&p;k05JVq6Y50iZ52x;}=<>GvGt91^T?jx8*Ob=G4^_ zD~a8`m@cD1Cz@@K$*+TV3`5s^F}-&{AzE)T#o92rk%Ds8tysky@0iCOrCnuQ848)a zqcnUiJP=6*lb<-Rd+o&92=cvfjWO(|rKH@~dAG-x#aiCGi6g?YN+9usjEcK%Y29ar zWnu0}4WZVsy?C)J;XgGTSnK7xUwZn`<NNn0Ud|U<m(eW;Ur%VWxvV~v!g4P^OpNbI zdvlC?Be6!WAp{~Cv<toC1P#vmHc?^|$@H)jMG~ph?Gm-+YZ<SQv)H<`D)P*M$D&)V z0&YV`#4;BLhxuJ0XW#AdHra$7=Bt|?uDm|-F_pclKhx^*YdT?S;L3?+w~1f;w!DWc z#&|Fj!o4PqvW0*ygOD^<M0&;8_0)futwc3Pa6BnzS~~f8d^ue!NO?frewPAq`g0s{ zSI+samY!~Nog^lr>o*slFnBG#Uw?+Wu7+L^u73T^+UhJz;&$=IA%7c9=RC=|SVyH^ z)5BFq*=46ZnIXk0A?k?7+)4|nNNMxT0lQ}hEgILsW!$j^>6Y;=qjZV}$8s794`-Qv zxa$~P6e?BECK2WAY>TCle3}n9W~enzpX#B$ebAq<+885U+Qj63{Bum5kuLAL`!a?+ zTJ$%tZ)Y|hlWQle>CqH%5`-R6HV7yp3C%yTIqA9XA&a8jeXv?o+6mNSHeL!a%V~)% ze{)YoSu*M<6#5~%s942$GCb<@qQhyiL+r!&;25V$QZd8eskR)d(}Q}lCCAsa<uttq zPp+P<d>N12Kc}iw-1WLl5byQXR4Na`Jr?hUNa~o?T^Gd9$B<{~n7wMc0X&Ll9C$%r zxHlY{H2WpI@q+vnt^|wEo>!Qb74eV-EPA7(BuawZMnw{~%Q#v*1?6r}^zGQc66AEu zv{Jk7Qz}TF3xjT$<}9YK$|z_Z%j#QqjS#EAqm|=B&)R|}D;uZA^Yc25AD*hFBexl< zb$+lERnfQIe&*<IjHC8I$M|tpqS3c{iGnB(E;VAfbh$ZW^5INSz7D$DjxUoGa+&jc zk+z()8{N9lbh)GOBF)(TWctz7qT`Ht2;s&O)3V}zuhH~^@(YZyDQJ!2ZhXEsVUutx zK@lhdSNodKm$5O%wGH#*+P6g@nW%d^ixksXG|P9!OS41<Fjx8=O@k_x1cjn1kX9mT zPsSnxhgW3rmqc}~7t~)Noj4hdf8+CKe2^BCd#F8M{#w+0vL~^)R{UqS`sYIW769XK z*=in>516!1-)7uW{S#Y_@sq8-h8YW#2UpzoC^K=cxk#rnq;>KbKZF}f;e>@aa^rNM znCi|Gs)qR%+oPj8B)#~jA-gJJk;$Pk4AhyU<$X%$@=ueU#bGF?H>7{9_lvvwrw1Cx zzFa^uns=#xsrd~M*V?#ia}sar&L;+UGYdI0lr^K&kqJ=573=PPH?p()KJCV2S#@;C zpwLI*)69?|oye#=yBPf`k%0P6xo}6nekYA5w2>COFIqjjql9{9zX+^Uzc*lbEA(|G zyZwsScT}PWDBEV|de!)Z=3VXhCd^ZuI!Z2k<ZqGijrS`IN70DD=fCX>{F9>_z_wH= z)fKnckjaAkk#_IuN~-q`8QIWf#aV3Y7ull1h@I+bW5NTJvNu+5?2_xDU)Pb|HpVp} zmD&4p)E#5v&Pby4l55QQpY9)JdQq(M4FJs-lUWnhx}hHNbTUhbUhm-ah6TTzn6QX@ zc9~f3NOfbA2NeXDQm*ViE&6>~`qzx;^z^g<05bQ?+g$Fevjp?&*RTFz9-dKd++wq> zc;R++^$a54WBokBji~%p1l8$*VG-s@ar^zohVg#H0%WV+FUq*&6pk<(ta9LS+zF1J z6zRWb#(2MSGQ~o8XufCL2-Oke27hM%#m>CM(}panr*|p-ocA9=ARUx)7vd>q+WYSX zN>Uvh(3Thm931CGyFX(IA4M@lQ4ZZ{PwMZN?n%Y|^odNwFXU55JeIk+1w#M^1FgBw z^3TnTYwO(|=|+}2vIpe5KgNx;bSEUJMMORZq6ecrr<6|l@{ML(9C!0Dm4?Ja6GwDJ zY?7Phb!~Qba|-3fw<kmF1|>V9y+6o?*Rh}!<mBt}Yko=xTOUJKrJwc^;8({m)0&u= z<6$tAdaj}ni(oXrU@|l`KK$0jpY6K==%g>7pk@q-Uwk(v0OJ-W)~(<9ZZ!fF-~AHB zcjG@+cW@-4^~+@7ku>=bUD?j3>hw0_!BZ(yXB69g_>1kvKtr+JNO5W(;WIGkI`f@3 z$a~|Mu1tT+j5#0I7^_AGzJuI&4>vMg`*a>N82>Go)dE6y@TyBmXW2st*x4<Ni0$|~ za@dNMy98a0+TuB)Y7KN0s9JITQq2@};oz|m)EYyR4Lz`M^a)QBnw#-lVDiDy&^2`W zd?^u#D74s#_Ig-(x21Tdr5Ne6<%Eb%j(Oql+4$xOTy&_4x7$aze5!mZkj^`McqRt! zCU`oOE+hL<A?9#xsh*Mx4^Kj{%;```9Py!gX{krtiJJjJu(Xrb%2R{5bH>guC+EL! zkmNfr7ZKD->C^KiF@PjdcudaV3g{OmK~3pANuS_=)Od9E6Sz&Y*~xl_J8K1Ji6J<` zGYpmyS%Sg;t)d{yh)n%|q}`c5{cZ6JZO-n;O%~@u5T=;_NF~;@)mO=FF$1W*Uz_t6 z1L<?~C~2~FwrG3o=)uQw!o4Ji9~0?2^}Wo)mZH6RZKrakiNBM~9y>;b-F7}@=$3CK z!y(~|VSoLtOt%(Hzrc4DRxGx}C6mvapm5C*vqm)A*DI?_=^?#HV76#?Zv%KAB<iKd z6ux4r@G4Jb$!yk6K`5MXkmp#TuCk}TADQ+W1vW$Uk<^Y-$K`^ZX(H=&)agX_+K`}% z>$a&kOIMear~GXexAQ4wO7N)3N6#!zKxUK7Pvq(|CK97`E+gPTAL?`XM;OR#Z2ZV^ z+jgmx`}O-g$I(mjIK<v&4|#P|!KqB`l`uJ&@kr&ISa^_Z75bi~^$ifj(FTfg;<nxG zd55fz_9;oz`DEL$7CL*m8hhCM<cSj-B1^?5umW{Q$h(1NAnfB6)meLx1kV-4k*n45 zk8v6t*Lr%0WrJrqhErlw4;e|b6(UUN%p)B-{j-zjf>IDDV;D|C2qo~Nt3ht|gUjDa zVnz~HZ6czp1ZBTXQ!tqS86}Rc)T2NJGPb+Zh=IkvJ=D*0T{eyAPyIj1-2l#_x8&lV zIN2P3hKclbV?w>jlY367b5a~c%)Zz6wXsiEewG1ynK9N3;n*B)gPp9nX+B=}cJ0sd zq%D+q#HE+Rgd*v}oo@gX#O2CB0xs$7LOYhP^cR*<oq;WClossh-OiPtwsu5#1s;gk z8GOfd4llXRLvROOq^<bwyVEX-vyb1EVE%q~tNd#>5R<!NQ0QCik$@cMq3x1Tw?uxl zgjq?{tda`3%-N3pwD=-IV?o_(y<YHAJK3wHGvVPiw)$H3i{TR=p(oN+ON_1Q96}** z$U_AB4Iu9bh_`c%uG=k-;x^?W?Aj7~?#RjUyFrqfss);li0=j&bG3}yuO;YQStjHp z2tQtdG0r(gk`<A+sBmW-$DC3NQK!CtNPNn86mGY;s)Q510Vf)n=EU<`7CvQ~a5b?P zftl&{6w}-QI0zR>S7Uo9GjmP`6~M7s`UY=)=&NrYm&fWQcrw&WyKU+!4TH=apExmA zgolKfW#TBOKQp5UBPChv?|%NnI88p9AsmNvZuT}q_(ugu%|IoJENuy8*=TaP_bE1S zd<b$-s5JOj^k?#aM*@Gg<@dyI2!4Sk-Je?dN2UMc^Z%+GT}av2jmdz=J=>lL=Z+$p zXt~KJFrn;br1VjpID{G0_r&6{bVWI*F(!=7%sZwh`F4uqMKgI~{*Pnft{P?D`5qC* z73#-p{@%95+Sr_iuZA!$W<@J6&Eu+5Jb~*^Yy_61u<iXly=CguxU0YWzDq~*rTKUY za;WP#6Kwc0`S#o!C9~i4CM7rM0?#mknm2VIr|5aYlc{T<*BNBB&pTSTCzFyZ*o^cB za6<oWiNiq-+ta6u=^b;-qA5F#VKiijkvH6PHEJW4dcQO21h`iDAch2S%vwSRhHf&Z ziGz3*!?V}~woVz|l}F13D7NRZ`JST;!07=)VlO`ZaS+*KRynonCPwuKNWW)lb)DPb z^sJbL&EBWeKYHZfdHY{hbOVUxy;MJlZUKgHwI~RF9$e{Yj)6wQKW6jW6LC9Q5t;U) zxO+2PiprcL>6*14Zy@SQPb}>F!F^{;-P2R{NoS_GG2adFly`fAVh1L~KZnD~SC*d4 zn=B|*9;8QyO6n32GCKO1(Krh;rAtazr-ryFWk$VBS=Id#crs1ZY32v7q*zt*dzs0A zL){q|7*2|Wv?>Nk{(0OYDF}7DV)S*2HxoX#3Xwaah%j4d2R`bXv$cED#jUQZlS0@- zVkN#<Fy?le&<Q(gmCJQZ)kP6Ei0xSC?EfY{Ph8}55F4B*OW&H#61%E`-pyN45xjyv zn~gpdb<R+?&_MX(N7P1)@Ry224~B4);508(DBsa@rP;49oBnK_0yQ^4)YZy0G%boL zsAXCOsZ+M7=^D>N9CwN_Kc9~KmD;23;#>hYuQ>BwtA+c>t;2J~3BSP_d}R$Xb1RvO zBPuVWIJw#$D{~9~h;y|VF^?TOZD+3Pi8$Kr_RSk|RxbX^*wE7yU5;pAYJ77_4owe? zz1AY~UP*sV`JTmyEY`J>G4pw1d@C9AwID)wR%w!(VLU&&L0kOZ5P~r#!UD7QyOR(0 zoAkG1l|yGwrgzQ}wiOj4sE+Tc;vSCV^%w5OV^=#Ri3^+{qcn*m?_qQdr(8(@hssKy z)H7N}5a`Xuu&Vt~in7tx7NM`=-jxlGHl%0wlk?+fI^$UFXeaKVPjirY@}o0nSILi* zq+`%WeuQ#kOzGV3uZFw(aeaA$5>3ZBYJJX0fCfOZ^C*WpC`bEwRE`E9P(!WG@t+;h zIv)B(XY#0;I6Qq@`5|NE_v3OPKC+q#Ru<2m>r$vuQx-pw4>q#Sbt#KSu+QfErY?!~ ze=TFN?3d-)nxPVtHRYp$3XLMj5=Rj#N-*QhL@r}^v~i2huFEp|?o*=>kddOp7o%XD zO19!sQF=Q?<^KG8IaXN=3IsxQ<xd;$E~r1$c<ELgPap(*d-nc0TnvsU%UmrETCdy* zS<Hp?Gw>QYZ%*nycj?^2PWu=o1(6bH2)P053hhKm;ci&E?uk7=oye>n+xj^0a%91x z`0j|;cwMPUuB~sqrw_dtSTA+t$Bx~@q8~H$m9_)j<2i31Xv}lf<$*&3v`S!))~p>d zp55ZFf38S@v+2H<Lo5RiS_E6+zHRp$Bdncjd{%zvBdHx}0eYbI{8rE-!?%-qwM!(D z#gYQ-av1yTw;Q?CvZs4s7wA}IFJJC)7PT<v&f-1PbaBT5_}^x0T(`8+rp-2^>M%V8 zmu6&}E|^9XdxQ$+_N!Ty)D^+P06AhHrMeT$2ORF$=P3K5&52h7knP9BmIiW4u+J`g znQXOXtCiD9(@oM9rOFBB{$f0G<_YErVvl>2kl7_*cd88ss?5})V14|B1+#Kq%3$;# zE!%qo?UFY3GfxC0lJ@vhCxQ^ximNZ(hNo|(JCk$*?iZD@EV>?`IT${)vooIA${$09 zZTg6>i<6$NpcEQ}v$O86KATIy%-RP`J;Zkp)ryP*XR>ypZ_;g35-F6-6WgFwZ~;&} zU;=IFt?G{d&cN648+4=MZWYoYvL|Lw%#Xs4V!Qt)8GiT|C^`HO!92zs%$8ysQe4Yj zou6@C4oC6azBt3aItWN^-P3c6SeAbe;#uNQ@aqXtq~0cw9oaVeO#>-dv84k&d=YTm zwliXxko<i??~}zd+Hlo`*Lpg)r(be3Hkh~UB`67m$qe?sG9(BklHx!Wsmfw~=M#(h z6sDfYZOQO}DS56cmyaVsYp%+W!2h*|I7bARI$ZD5Jm#xJ9S(mU-N#?W8`X8cDQ}E8 zKeH83wlfTtE!xa^`&qVQwuVuYB(Lm{y-RxH>+V-h4PH*m5pTnaXE;8r_v_0Sq;J)X zJ3D=HFnv|zzivfBc&JWYl&E18@kpNo=)Y5%F`w)oH&IYQOi-*p!1FnX>DifvGpIgz ze!7rl!j^x3oJil_5;wO7>XWg3_Zy$&=Zc~%CVn`}pIQtxqjD)s_b6W%jf{1-8~$w6 zy^rx=rCCTnb+pNvt#Pke?&Q&dhsuH&Uo*qyyPcA0mv>igN%3gV1!m;YI9#gku!*7J z5d~e#7Z)f`6T|0zfya|h?mn4WULeTh^j@k(aQU*mz9Lvq(PiV!ysRN8R=;So05{^5 z<rYqqMhtb$H2Ns{xS~-}D|3cwhBoSYtVe@Qiu3QbCw*SNO1kxcbRO;CexlbiC=OfW zqfGsp2e|V>j<~x}DuZ}3)~wUdeB^_BhGiT%+ClRKB&_^ibGM54Rb8;|O+?dq+T`Ws z@|!-jeN}TPJ8$zyNA!H2kZN~od#ZIcH<h$rvtU1t&Gnq7-D)<sD4EqL?&(fTL6m39 z_t$A(`_>Zm^vQb)@LIm;-!93uY+()}v0Pt#%{ZU&km`P@M^l0&2_O2mBzq1^^__*> znDGpyg$K0rMn)gwvNzM)J@NWblEar7G_@t18PnS}c_sPNNc`Yz_@k%0o*#%Hy7rsb z4>PXuP{X$Vt)a5v8jQ<uZSddleHB|5+|Mp)PLX9lU&6jb#pP1qOr9aXbPS2x-uEuZ z4*7mqeECaKh3)U*xx{gr`bWeX?^U1Kd0fu{ThxL^-#-iffP%jx=>Lo)F9D$K+6sDJ zgv8h*--Pu%hjqFEZ4bm?7IyiYV#w*VsQj8CNsII3#H)l@6%ed7adhoFqGJutW!T_^ z;%ZG>^j$`&Bj`q3<T8<oZ8F~zN8yI8iQKs;WDWN7k<*kd^<2fB7e(=-sI@~aLeQnh z(B(ByiONyTW$${s0<d4A_|&NVA>G|%exa}e{eZgZ&vdeweJjn0Iz?gYYEuE`iwhcM zoT`wbcJp8p3b2YM@qvIQ+e5h;rZ4(Q=y$<9IBri%%}y}M&kG{AZ(-$1sSVLI=$ukR zRK#_q#%HLEkvy@045vK0XNLF@`-$r4^i(AUJZSsTX!-*)E(!jR@m*ByG@K8sY9n>- zS3MH@LUF6icwhE|o5myPxG_{0R=GITT+5vDjX89nr+GYgU!VY^UWRdz*7hOTCvSxQ zE$&2x^muMDdi8BuOLvO%e!60j*&1;?aGO;!A~^2CuD~n$A%*dC*F8L0(UmgK*0gzE zF^If5BZvH+zAfZ}&gcFG_3p8%+dH2dKyhRuoTrWN^_`KnWwT4MEm0s!UZJeJP*|^H zki?-nD1~Fm0tc1oZoL6O<NtD$@$X@bG|;K@Q%95~aB(|hgB>6HqDiGhcs=qK{7&g< z+vI0)8yKF!j&Bp<$_(yBjf}U+TCblkX*Z~9xj$5t0-JCzT+9_}HWjB)YRGwIzbBEJ z53MPj64kDz9?j$bm>L<5o5%ldWG*$k4(b`7O_fR3mO1tQP5;(?gqSVg{lgi886R3O zmU6!+1*|Mxo<b5|aFpV!8>W!UwwLlrE429l+FX7mkqUQ598Dv{qaaW>NWLJjaDyc! z&C_G+XXJ#6@=?NmPJGcR;j0!5B4pnNW&gV+AYXycRoSfNAaCjsruC{*!Anu_p;^)g zPhXYdpDBgxU|9QPstUG=Dh^jPF&edKNPU#7N-ZNVXcV}e0c~vR!&MWN3<68>^jT#q zCErqFSMR>JSIlMfI;-q!>b6MX(;e>8V*bb?PRqU!HLg$kVNlstm$1Sr*Wyt-*$Npl zyN|;qeeb7LZ^`Hao#9rS=$T_xn8g$ZuLh){wsnTMTRJYmX!e#dxCZe#E=iSC$={QT z+zHonytuc}>_Psqip)vF#IIWNie+<|P?k=cpj$*5mC{e|uko;M<(t(QG*sA5*<ntl zUcE-$=%cC~FZe2=W;o34P6RXR?jkwYCS)Gr**N}Sw3b#qyz3jLfp#(69yJ<fJ%`Hv zY9xGj=IpP3JoiV@wB4(Qgmr^Ye;C<J7;yI2{khQQFX;dH_@65Ox2yZ3kN+V>bKn0& zk<GtB@$cn-OTr&N{Tso*zRhC*)Gy)KYvxyW0m?QYOfj;im6&2}HfOqnUi8#he)o9P z#AUeMRd!fgi$#Lh@X9~+84-xf8hnSxRq*&JV0X8`7w*XJqU}oW&X1wstfL*;a$b~( z*C!NUJvlmhUI_AOZ>7JZ<p9OM$I%LZnvnPkw4W_cms|hInlAg<EGR=(MoscvBR(ss zDPhvPI&RJ8MzpMVVQ=lQB!h^I9dP(59@wX^t#9lOG_qqmYl|ns{2q0Gv7yQ;Z7gwX zS5+h|V7nt}AEuss*H0`VzLI1-0XA~0%fFV5wIGx03_OEHFk3mp#i8p)tQ*SJ<X8W) zp|C~31**;UKq6Q*W`z9yiTonAlh*1Zb}jruMKN+^XH$0eZNs`-$+QIKjk{SzI-A)h ztRZH*ZrB+D0hb;PNK!7SdJ(-HBq0DY@)irDep3s=D+K(yu;nSIdRMm;YF0|zwgaFd z8EY_~<>!wWxLcdKM@~4W=+NL?Oj53^I}?a=XRZ=kIU^)5k;^6XyTcn{!wjC?g2cx$ z!vF^KTl@n>4YH@BYjHdJ894fu4!CidIXNUac1dIIdA(y+8Ce;O^P!(WI-*bCdut^+ z;O?olS;tj{%D7Uzo6qIY?qG8uk!={IgG!>cvsQ(e29cEo6DaZGenc}l51XPRXT4K{ z9<SwsipE;TfU<cB@Oq0&-i9kayHIz+-eQW1HhIF5vD@u4T(d<zyPD*IMR%VKr(PKC z{?@<Sp$vrrnuWz~hT|<<)(g>EHgA>O=&6!qh}A8n+nT3`&j`$QUgF|@$^sX)R%&gI zYu+-Pqwalr>+z10(MZlS5+c^FT@srSv3H41jbDv68>;ZhQxvVqO$uKs@}s12qdWN@ zK&{YoZJUHL_16JdgF)70iBAETO<8a6Kv9Ik<4jP{&gQT73p6nEu%8o#QztP|vF=D` z!>n^XAE}Kts<FnoW~s5pPlQNkk4R_dq7vI>wcCYqS*VOs!Vu}Q8bv0;#u0X?bT(AI zak40vFcOtRWf`Z)<jESRxFcN-B8&nl?x?qQ0S|R=0JsA_L>5F+grN_Fl3ny9MiU5& zYWwSk?R~gtN7!W6)%WC?j^(C?1p@?X_!}4Qqi4;|Q!P~pjbCpG@?tJrb-v>2v*Z{} zo>*+<QpdXU=2fte%RvqmKT*C9Q<&v@odz!EJXOTUw~@hB`&l}uwUCOD<s@y_aMHe- z2J#XO-MTdh<Qk@E!~9{dk-m19#u9Kx?hS?+iv1UO=xkBrHeRa=KuwRB_NrGb&J)F^ zMYqTsHKaZhlh|Ep&*z1^;ll@TPwz6AHreXSnUky_#DP7`I9O~{@8%c5jTM3~Dz?7` z)-x(pkl;E4)Fl(o3ni_qW<6$RjU^TiKNJX1ou@2(Z#@+dauYu<_^fBWU1taq4dA$& z=s7+IZ5Hw!xRS+gRD=1AC{ZnQ8L5~yX`<JgPAk=_BZ7_4F=Un{PSg)KDrGOZbZtnu zb$MRLYTCF_O}MG5wLQ~(<ab6_3@w;=xgRP!mU!pZ1LCH+g|ge>xGjd20xww?y<YB# zj%W*EqnWtRtTBNBXqp;W5AwI*$}dXyW`zBj4rg&oMrx-+WK4(;N+!~x3I_O}yg&{^ z6)6N+7LEPE0kTj-s`}D)U6QfIummDkjXl9+jn;);P^l{fsH0U@z9l4^ac9(uGr+8J z1`wQNYtof4lgqCoT{5nf%EDCyS2ogu`P-)TjdBfew2%)lh4Ek-J4`<y8DkyAQ8c9J zmTQ*m(aU5j%GN&?6#HT@?~bor8lUr2bEKWT#<)Vx)<A1qdJN#Gp)N+RHkZ<JutQwD z-x9GQ2*hvPe?coS*Ail6ri{)=af=F|4c?=Q6BiO1X7bD8;>1=CEV*6v9lxdo@C-Z` z`F$5nKx;eh>ZuVTe%PHah(U5ZD{AE`r29%)XvVP>8gZ6lU$f$qPq8Pw2>z8R&?qq) zuE@*UnN9dFjd=d4-}tA}iurd<C%EhKbKR&Ysv)Ee@8mY{xjzJ3?}43(BMh1zwQ&8G zxB-BsktuU$Hvs)M)Rrh0N_Xg&>JSFz@7hCXzqUk=o<-x+I%e{iIQX?cRsE?TF!H;I z0vc*hl+XO4?Lpha<+x+xuoD%gOB8x-ykrcdmUx0^*6w#*I=w0@O?T}<6BR}On1MMz zYRTgW`@|nVUHu}RCtZ>b`vySBy*Kl2bUvPQT3fM7Fj{>+UeA|E#k3^eyr3{7zXC>B zQ~INr{#>_&HOUJ&CE@D`djqE#k4ijjlL_1G8AT?Tt$718z0FZG#mbJcPVCUg#*VS% z?50$cj{iX*6*T`;RbRpN;CxuiwW9n}#<Wb`5dNzys^rG)!{B_$7T*=^=8WBCED*6^ z!Vz(SPx8{|iJbDnCy^~o%$LrJ{JlDBoR(Tc<2L-#dj=CkE}-(Jy!eTC5gSR22Lmcs z^pOF*J}LK#w2dI|2O<RHsh5~#Y#1!V6s)a|WV@5)6*!{{O&jP<Wqax9J2gY)Goo2z zJ`z4qU}TI5VU)4_Fsq=>Mjxn4D5wBg-U4pzV-h=hs}^74YS@eQQYar_Q-B53N{+E{ z3G;gZAOVf%&nvT|v6K0k1!J`!1oMo|6KxiAH-L>VH-N1~Mq@VyP0oB<vX_0=S7G`u z6pQ(TWC-&vp0LA>sPQ=KH-|yy)1b&GBCG2Vm5sZn8UvJ0e2?d|Cd$Ci4>`dek4m6! zYCYG|qYzw{#^+%1(O2gx(%N0p?`EXCW7RTSHJxoG_zA;6!Nrc+C^<Vd(KFl}l1;<% z4nhhr5up;wxV1KCZo@QH^#5gkmMR+M{}YWu{XobF(9yL~w(QO(B>ful(3cMmL~Uh9 zEm?d9Q;p33k^facs%Ua(8JLNL99?s)+avgJ%N2ZqWC$9RmGGX9%kZdW{6KR$ETlz0 zOD7%HH(6P^Bhq-5&WmtVE*X|2@S{rbH_6BNmdPEYJAFAXZ4R$qmd$J50Hhslbo6m( zHS0KS3G9TxT#qbkM`<fxknTSVX(YHH0{gu$y>Q(G*$EgRNKAfwTsC-FG-XgZ#}+xN z2yE5<5Y$$&aIm89P)y;*LT<$`pj5C-oin!ZRZ2E=nSZVBEX;Ati7>C@b(p5*1vNZO z{RA^R-}FhjOb#!d0CUdS@ZigD-y&z`vG=R&GC@R2MdaX`G3!mdZiv+N4Pa%-{<IQr zs3)MOCo0^V0eG){WrIfUormcYGSb#?gvgVyl{<cE-~b@CPR}xLBc9|Kc~zdWbWFgg zfYXd>QgV=?2bUC>J9E6lsd2Q1brup*YEC7h^exvda_jA$x)yD+wLX8l!n+B)F9);G zs@#_KBE=d)*Lb($FQtz_+PK>Sc1U>0^ni8|V?33lXc3F)tN=-LReScWY-U1s8N7FF zjuX+AACqQkWy4TstS?&@zgEy&<@Qmk7D$h&gxeHu$!d+a<<`h{iTK(#+$POhN^)hi z?UH6nnC$Z)r_%e5D^IB%?(*YIjZ+_MhLya3()XL5{H$cN$!Asf!rp=m^|66Y1=-Q` zn3thcLXRV}y9n}BT##?CEnpCo4HcRy+L2<7Z9nb7@@Xt6OZte7PZ0#7e*YLgKDl%; z^lN<K2+w``CUS>%l``Oi)BR_ELDjyA$kDD*`in@Q1`!_WN|C7LgWr1nqUlH?aJw>o zEZay?;Ag;ZIjR1)_6&pm6GjeyRe=irz$7B7T36P8azLm*3prJQm>{}*AC5$w<K2l0 z^gsw8r=x;S%@D^#h-Dw5Wg<kM579bgZUA9%1W|zC3}xY`qjFJzpZ*hr%!*y)vMC)Y zs$Y-B<+Ay*DP8j;`A*V<;7Eus*MLx9VA0TX!zzuL<eW=huEZ+liK|Gfz!~>WLVp&H z5yKw^B~Y*YN-(&2{91c8a0O(^0E1B*w&x0n^3NtllVh;U74sHiXj(H^zP~6qCWSEt zQkRJvjg+q$dYi!<kK1If%ddH2we%(?h_Tois|Ic}Dai_g@7t5M=cN&GjcR&X31(}2 zHIsZ?l^^cZi0vs`7q0l&_P{Vu;D=qrgJmP%;%mN@ZDSk(#lXRo*z9RwWgcRNn;{~y zF^}!5siG2hYL_fRs!xEF$wxo1J2bz@Q|68v$B%$h6$bkSaxLu3+1<_*qm6D~f;GI& zp+OZI(o18N^za)1Ruju=Y)FWF2=_I%8`HUi?B0WTYwO{$kMng(7agz)Fv`GQoZCAf z41&RZiFpPoL|wQ(@IX!Gf3;UlhAj+j&(HhDHzL@OHvk~GbaJaDeKe*wCz*BKHwfP6 z>ks!vhVmVD9c`=(eZ4q=d62e7F-y>lY%E;^-@`VR5O`aMZ=QHxAl}v+=bb_F>W#mK zxx!Nz-fyl@G6Xsd5_Aa5VJ#7ugkkE^x07I1$oO;ocT4oZ*GmgKCx0kHNb|G`prBVc zNWRN%3*9byt=X%5OvLT;y16%1sN?5RsPOkbQ^!543#u4G-<M@MwF+@$<w1v*Z1RDf zx!NjdiiO(M`}QO&jl#oYwc3Ooqe<AH9tt&68Pnm^FkG3eBpsb`4(Xho7sTX9r4lQF zG1V|70YUm!5PuRwnE+!rE23avdTIuSlDEs{12gLjcdtelgbG{I7tu%J!sF72@X0z> zEg3uoT}Kqi=};mY$yU?(xLD2kXM%-gdt;|1lTYoMq8hTsvkNCx6EbZOftDVw!LNO( zq^zvOz0;)2@!Zaj$0*{WdQ!-P?HcDNl3Max%PQF&%Z&JyY>7y+%~AW%4H5XshqZ(X zjB&=@?9SNI@ois~TwLX(O<vGbig0X42LJK}4mSXTFT!^KKPWNYI^0M53yS$SslO_C z@UtND_YA+kfA9B#zpd@RAa@GK9%@jYDqSDO9M*1ytgpT(Y12!11a)zYuCJPzc-N}9 z-Csk?KeIodp)#(|ko4?ph*%{56(NxtNdQQ|`uztBZ@RhR7rq<>W##uY-3VBduQ|K$ z3tE&d!QhF-h*G9gpJH>CeC0?H3<WoO69#eiz5?Y(!b5i>YFJWP7_&;UJ;w}jGi|j% z_Ql$wRY`1-wZ4>uZhf2rMC?sTx8rIhL6ge&K12p5RZDu&wstppHhevYtoSC)dw1C& z?x3VKpMJ6e*+9dGIU^xvRt%am5%~r2xCEuw0%lgw+Qwx4YBxfwZ15GuD~J7E`51b0 z`7!CG_KKpyNuQ8t&dl;?K9K$DF_SpMv6!=TP1bZ#lYS7_M2Pi^;OB%30+`Q)ldS4i z1zxyHX%perF)cLf1~skDoAPebg)DBh^C;JYK8Ax<U8@p`&TS{?IqHoQ27F5Gju-cD z0Nn_o%IWHAi`Rn#smWr3ZZ@FVg#o=w-O0Av)MSx`LHFv^-3_n*B+_l?q^PLq%Lycj zdEN8(@2+3{%1QsbY9ar~hyF40{!8CVL-E0=HJy|*^vfx0J$W1KQLl%Rt4VF-PPCLE zQ(5_@LveeH@Utm?O8LTA$Cmf^*v&vszN+Zk2Ph>NGT0xwD5}ojYeEUMC|{2~fA0p% zgHBixSour3@oEuTSSjLs9SeJ1Pae8OX<~H&(-t77I40~5U-hsQql~jMFS6fjP;ezu zzP~vPBeIbz)@s#Lhye*O&O>kolazT=O6vxN&WP`4zb>9HXW);Sj9u{HFRd!KoE%<M zh?@KE3b(gFmI<5%WpS2JjB31|iK3T`m7lDvoM^6Z1u<IIQK(a@(5o>W&#;iw4v5R7 z7Nto>SW8*k1?rbdXMCN`n3=UD$FBS_H1s(kDY*uLr}^T6yn@g|C3jC8f?!Gcc}Oi= zeh_BdnB(!c)el+thg8sgz4S!+Q`sU*^O@FJcA3VcrVL~bSAL=%#YElE;{K~fgfePE z`s;b`fAhag>3`+_IqFW4WR@b<O95U{?N57O5b@Xr$685llRP4|#58mGp1C?aT3w)g zVbcn0@$OQlVg;jjHMZ;#xxRN8>_88H%#{kJb)B(pOV)zP6Duj+^grsHZpI}9)w!;y zm5TdMM#$4M`;WXaPnY^)Jws}(pB<@44|;hm&aIs+JN${<(`KiQS}-#|Z>ABP*}1Jy zV=V;3kABr=X7;+)05_y?<9lyL@&k!w-DrJ&+oW;PcdKKIQ*Ssq=Vt`p^>t^zY-D20 zPi~9V=IpK3sF*jci&^yCtYvV7bjb<Jc4t{T$M3eT_m#FlpPfruQJzpfWS#D|Gbv@X zs2*nrDPgzvB-;yLA>O;`wcvI4Jp6W4%U|aqA(-VRM+BEvjDEm;_^z}!*IV2hPw%*R zDnRCu)D@MjvOq;rl|Hb6sf8lck=W7d#nhVMK<(2M5PA77$MJ)uj@uOetb%f(1wj@C z6TQ@0sb1c^Y%@c%)B{8jhImV0vKD1r3y>cD48?;v3Y%9CWda%G!J}!k2(4UBRuS9G z$Fpy=qWguci-&(~%b?b*)$bW0(WWz&VXR&X#f0<NF=`P^D^iNUw~}$zNk`|@@$$3v z7NtOriCZeSFDgN_sT7Xcvt0LhnQX6wlIm9=pG)`neNi{tjSvp)PLm7H@)JhN*89qK zLRE}bEEQ!6S+v}jGO5EH3%`~M3uMa>c<6U76%xt5%cAtK4H3J&L{~>q;&oVcSL%nP z?E50kM@-YJX$S3Ef(n;en1+dJ7z*OrM#R$2`%|rq+SfUfvbH5qNzO6Xi&yJu;-s+_ zf%CgUMtql)i<qQi*Htia4;%9!3Y{bAAf0HdXK*hHt7*U(Q%Ip`?W?ZhcliGF@;2a_ zqAC4`wYqOPNh~^Zwon=*-u*P(8^G&F^omVaKD&c|#X3IwMof}b^&fW4@&AimNMjpl v7a7k3Zv7tJ?}Gzb>S{y?Rm1BX7jx~}-jnR0SOeI^4FI*AzX6c9-Aw;~m|pQd literal 66585 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�R7DZXs5=F5$?UHrd?(B9ayT@v>(^4=$AA`O7pg2an>yhE#->W} zVO=gSciF6D?DYgQ>#`cNfplFqOZ7K5?I$}s`q6+A3W|#qW+rNi;xbU&N|D_~Nf|y1 z${y;R<~v#YHR3riRi;{LQ_{YEZLD&Ik56{4_GlB7ZYIKwerCtP@_XsGVruHim>8SI z*^|KHwy4QOT~otnvnmkmwZZ~X5UT;-@lCsa!Zm^P3&o6ri7N7TJLG6MT_beIzN~L+ zCAXHBPXo-*JjlWviy;!Cy-uCIo?Cpeqnsjd6388tOM@6%2B!c*M$n8orQ3ss!@Gk_ z)BXlzq1){tOb?S!4jhBS`;BjpCqgV|(|_i=T{?Q&Ue(mjY2GI~dT#!N2Vu__-wm>O zUaL6FTM3$mb#=TIJ-0$ML?WXr@RtZBb+9n=?YC4+Z*d*TAQ?7-*tjY>WA_?XA&+iV zySx)EnNw;NVTka^i$JqCBJcrR-Bsuc>2^Sg8Byf+S2O<61#1zP8{#;fAtLtmI!8P4 zZ@;=|U2>?}W~>JJ{^DC!BAHnY5dl?|s#@w)O)mqiVkp8pglX~po9QmcycBm5W}_dB z15fsN2eB$g9X=k|DVa;bsVa3adnY54AU#c;GB4ZL=P6$jFbs?V4>2Ck`Xs9xE0k{- z<F(JuD~5k5@w<>t5w}Wqq2vm=l<$Rlkt?4y7fInuMccr}m?NGHB+!DgVUppDU=MqB z>8$TU3NEX4WT~`PjrJB|QjJ?h+MN`Z<Wmcpg}{y8XqnmNPVc$&EQ%;;(7;?h<y9{n z*MpkN<50c9!$))9me0N>5cH9!a7&ZeqS_ZUGp^En+hsodgIPA;jMdy4uX@yrS#IDL ze-CCy#BJG6ZPETwsGWIxv43bvV;SW*!iC<BKbjL4$V;!plTuO#8cn>S&W<o;`p9Ie zmcW<RBy9lXUnf*=5>a^Ep=Sj*$^Sa4^N{b8sRe!U)WM0%T=BJXK(TckfVMaj7$mP~ zItLGsdG$qQ_POdVMl!h;ykK2rE>_{W@o0R7?1x1WLo1U&9+iBt_vvK1WUXfi2=;UF z2*9xr(?A6tE3{P0LY;Dx_FU&KxvE3K)AW;_P+sh9TFU%wwjVPr`^j_oVv{T?*Uh^b zut(Z@8gL~(o`N}IJ{3b=b@spxJ4j+<-KvDXM5!WGHN}jo1R*94yW#W*sQKd07enQ| z=@qklHQ+1)dWx{)=jS}2RT|}yCo(X0Gt2nshOCE5R`!CY-kTl>A-CQ|d^3)opw*?C zqUIz4rU*KFrGhmbk6FG32G>NiF=>ZWKh1ank|*KdN@bUQYLvwb|8U*yU5wr*Lf;wT zv6;25#yHDI!AiYnLL&tFa9K50^y5~6+M3rVuoYr~O>N&8eFEa4zMPgQnENISV}IfD z>QVWu@FecRi;pu3;HVtRZ%GukUyi$0vpa9XG+2(CX&LtCy9`@ZgMYXoCszE-c5i*Q zdedbG#@ivr--6IVxwu_!zGhfQM510bwts-+=gb*Nsh1_BMCYVv>?3POcqsA`vo*O? zzuZmOE-G;_<0RQ!)|l3&N*ocEKqvNg+YlRl6~8jEOXuaLgfxX!a1MyT>LI2MM%Mbu zCO26V_mdK@J+ca;EqtY6e0_z(z<f~MwV8F$*(-Zr*kYGlwH8v6XTNVFic0H^&^Y`- ztW2oYpkEd9)fGP=GQ!MW&C@qlxLi~*F+Zx`B(`o%A0Qzmqew)%u5YS{#)kS8VV?bJ z2)N9w_D5q&tWvC8Ki5VxJ`?Ht!H}ApMU4G1=P#u?Rg@QE>p#P;Bo-bipgh-!!8u!4 z*SuAIBh6Fj8Q)NnmRk4Y=&Er{sY*dcX#wWucHln@=$51@Dw5UZ>uD*+mOR!0`MtDg z-mYtO-|y9#B)i;#r~TRxp58OHN#vK7ml18(5t%l;#9OXtp{x3`;$K0^xDlfm6r2^~ z6hA<>eKP9c{MlkN5<PbU5I|Bp+x~s>(R?2xHiJW={*zJ_5ZUFsiSm<cjG+kAR8r5g z_4%Vu&RQ>dvMH$#4mLR+1w^ypJMY@&Z}-U1ps=JsOXY>>zFd^L)=fX1JV?p_MresJ zN52CxUJ01ckF6YjI$zJIp6OzOu*(IKgYD#`=N`RANwp$(%bx_Cd^-@=i7j~_VsT}< zN$F7ERTQPhJ`9=*tn4(iL*`Bhyh`%c0!7h{u{35;kM=$8oh6bHJDYMY{Whl%n-!(l za(;4rN5o^pIUP~cOchwd`lgLIWX0Wt5S1trN_C3UZVMC#Mb-MQCyErXZJz~dm;FHO z$+T|l1YqK(7{{m(zp@u^^Fh7AWJ3<m0W!auG6l{#vJhqoUF=vvuIN)Yo+=ted6#HF zAT(xzb4GS9E=5c3hqG57^i4B*1Yezrh7ZzSkeKSXXY|Y>xJX+zsw04?_Ubi<7_xL= z(8aQ)<UE7g6QUM__+IrugMz-*^#Gi(1^K!caYKzsopg+q;`I-+e!Yb5MnTD@PL$#k zC#DXy=EbXkJPma4a&Vc@O=yVwp5P&AtX&s8AKLC7-oSKh2<X*BvRGjN>b{ZlmkPbg z3H8AtA<QSYBsa7Q!VbMS$Ek11RMFqOgm<=MU3Q^Dq3tP}pq|L*qUF)mPIf&)YX{_{ z6U^m5)oCg%O_GH*7KuQeil8i=PW!C@&4b#g!}lIHY+Yg4(}DHbe02Mfsniezqi_gB zC{5%#9nGS>X1c2h0<khdOY4A7SHs&xmJxwXSLOqy@Sd?*ox5xTvE+|@rc)I{i@vuD zH`meUrIhy6iAwdk`SfHfHUk^viB0W%?5=;Wg1Cf1Xy`}%n2zfc<A)6W`4iWAV5o?B z*daleAjwwq{wqsd{`$d6hPuJ%uTy%xN+1KS<4rfNl9%!!eQe2_nu5q&x^_Lxgx|?R z58r4~8hj(veS2&xrz4{Q&sATufGfT(3~GZ~i0&`1i<V978{8I`eE-<AKQW4gPToJz z%z!1Qh5YOTW_dlu{kEn!zO@zhtR>4#Zc#-~8ZgdfdG~QZA-J-z{IkY(ThsoSz0b&X zz}>F?-LmlDxnQ~MN}OxEBxoKUHT1x3<j}!+5&sl0C82^3+74D)rZ^|i61nxT@p!qm z!jj9oTvC55Su}LlJ98IX{v!ORHpOL93+%0xySM{5opF>7I&IX#T>Q)gqu4k)?F{l> zePoo+D_hS)oa;y&FZYUbw8@Vb;p;jmu6IxoX=QN<C0j{Wn#VL#v^irbu1RH<|AGIs zs}NgX?{%g4`WH>L#x?rRq$4tQleUv>=1KW8J0GY|S-qb-wfC7<-BV{S|EsSvvc<J! z38vqO-o-vEQ5ZHTNNyStYAch`$}+Gr315+!ov2Ru<m;ZTZet|#5y}8wai^Ye;7N2l z0gR_KYk|I+^m1#X;vyC+MG7Fv5ZQr&yWp;qXC^7>X?JaLUrOqdy-S{+a`_n&wiK3> z675!AHo@PUr)d?9!mb)7CR&sxK?d#=<D;Yah?t?NBk3PTNBzAwSs?t*H)*g!6FP=% z)QiF6$Zl#7{iZRZYmH>*fhPenRZMocuKDt>RYGKB;!1m3i%uY<y&o$a(Q_m9O-!oI zn*b+Qs53(l4MA{)!Z_oz+i0Dvx=oj64bHYExz5oEqG}34O&9&)gfp@9#<I++uws;9 z`b>kBhVw;KfXVgi?O8EfJeHY55I_E5yxJ}XBG%}rWJ^Wf^>nVK3HCevvoeNHdh0Sm z0&LtmFVt;PZ74i+H8Yw<9h+o&*$x?9b0g!JdSyQ8K?MtPf%6RDWp$6170}HkaI#&r zdr=`raf~nAqiLGeIo}DW8m4w;Vr8?IGIvn^*}Aj#I~KEk!V9LG5IYZ(7t@duon4#b zS>}%iEoA2OYLlyUE**3!x-QOl4D-y*luJzZ{IU5`zJ={4L?dpqGNU(X(p9-nWVm|T zZGcw&SKfi|ifd&|cITT4U*+-X>fLk@qR`4)*)k|-r)S;WVl<IY^V*nH^E$gp8TDP_ zxb8D-R<_5q#km2quZ63RX4>_e09S~&i}091IA+qGxzJXV!w!%)2`1*dSU5ctTVDCn z<LO$z$Okeb#Pg<e9N*pQNFC=M@@B`1EqH(+<xID!9fu%B!<W1}f|^-(4+D{Qn_dtN zor^BEedyZ>JgpUXBS`HwrUEaov3D*~WW$s;rOM~Jn)3&EL_h{#J~Ffi&CC;hDfv<I zVKZoWj(ZMZ(Jou)w)<`%GrK-Nzh_+4oZ8oY(_|=H$3xf3a&3iksB8B&lkG$-fXlrA zES~IFLAJS3eNCHSwi2&Fkb5dEv{MUpZds5G{=ijJK+x0-(~<7RNgi~mf_P_nXJx8? z(EOp(boza#<L6`02ThF9hK>SZL%(Drqw-(7`K{_Z7$u}AjSGtpFDk7cDR3Qw>QUn^ z2j04@y~U}ggHjO%hSR5>bMOML5o-$3^n7AztSLa%Fcpz28z<-aZJ^GmGhXn!%8lyZ z_{&rrx6KL9oU!-SJYFB)o9Xu39&+zFM3gT!t*9Eo1}jVKTSCO+f8Y>VGW`wV1^wOW zcwdd3@%}osIoN`$K?k&FZ2Wzt3TEPU6LDctgJw_9uYcbd=rNwLb&KjN<oP;)`Zu=_ z5mqD^s{bi-AjIwTZX`3+le403<{$iQD*%Bm*5LfJ(GM=~u<L5SKt#Uzb!7xPxW^A> z6B0r|OX+_w$kxSCK<IOU*=?x4M<N>s$LU%x!QYe1Ku)lu^!|0KT{k;BJBi(Z`uci{ z6RAVb+zJ8DJF>q;?g4&*Xc1M$R#x|>v>a7~adC05vD7<6T(94kd@$|&Pu&nL@6Vxs z9UT7=Yei_S{|3W;SMhJ2|4Zio*FfNZqlP_Se0+QmyK|v`XrB*i9{loWTwI5G{a_^x zzWZCbY4)D~_&C-L{5fjQ`CB$u_>{fw`+tsz{$CN<{~*2pfmr|Lb+kUyb9TNO$&^5V ziMkd7qS{h)gaO^FBtPs-O-&6942<XA`lM3{|HB;KLve9+<>TdjZhcqAIp5;Bv~Ck# z0$ZiHhpmPRS$5GT_c$)OON_Q}z0S?eHSvv(jxGjvxClv&D23;}{}%}6d(M8jVCiUN zWTc>gYZBDVl-AIYSdkV~Gb>B+{5cozV6H-{B~U3nDjoynpAbJ~&+L$AZVhgKgP7Xh z-K#G~L`bOd(JOLm4<eHSgXANdXLshgn+E=K6)8|y9_8-R;ic7x2vX{h#Ha|u^^v*| z(KY@BqWAE@!W@8C4DTc)x@%C_lcj1E-<g@28Aw?z7<~knPt;qv#Q$;t{QayQB1$MT zQ;X)xnM8|$?23wtWeTC5mxp%?tKFefHk5w~HfI4NI_w9&a|mS1vTpv?Tu-!H(5z`Z zX<5-~cYU%gp4;)`Py!Ih0*2bvSG&F-nF5>Wg%>Xj4gYQqu5zHFk6&MXwY&*_#x1FZ zg@aS_5kWE4a0d_(6N75M&fAL{8fMcQ85?Z{oNos#H=MWJ^7)U|G-J6oTin|&ywzQR z-`~YsJ~=P!|JEX1+stw}2ijf;J8$_pI2XIgISSxdu(PePR4mU!C)@`fS-y%lD#pf+ zWkQCZFavXIS+^}Ljo*KYZ7i)Fnm^L~b>9d!(xXR@#Kpyz+)jf}Hmy8PpIy(Jg2NlC zoT$Ngja^0(7*HcadNv#HZnEo(Pmk_%^p1mfFqARtbtmojvA}J02oaOJgJG$}rn@yg z8YWWT4}1!swfzRNIL$aWA~a*M)&Y(HblD$yD?}eP#w(@hP4&v&mPc;`sUg!NgW~W2 ztqD|xipQyg19>#KPBzk=?E?crN&bFWalNhN$}EluLV2W(9+7e2-KuzsEHGL9CGwVF zW0L+5Dk;VZGq$Oz9{ak%d8K5jfcFBChRsPmNz(730I|&{DRi^0dq=G~b$={$CxIuL z;dPhQQ#2|v0*IFp$@f=4KCc}d9DK#Zo*SkKGAQ)#m2qYqBPfml`CQuI-Nrk%S0C;D zNYC&RjhQSidyxjL38#os#P6tCLTvU96VH5tW@zq9IZ0Mc`KZgJ;2YI<kY0+Uags!X zdS9VU0lcf&Rt3bu#jzOz@8V6Cnq~T4_lUfWUd)akk89-98Nq`5PywuqeeP4wvbSP1 z{^@X?=F*aZlJf+qIL5#xhEK}<NnKJ25QW9e&Zl-+vBJ7tNSXz+sc&pfZv2}nVFCl& z8_ZvC5aHf4EQ>54e!t&xTf1`=ka~Z!xre8t8invs67nyGOGz2R)bXB^T=W(I*>i>V zSlLvT-}fU0#^<d$d|z*ihdIS|8SpA?t{jK+#VQc4;US|cO!utw3y#>Y45xe3mW(_# za=QuH9)6)hEu-gA=VKuwVUdOCiB<*+7ml3f%`2Bnq%4)wHPDPNmZM%WL(@-Pfz@Dq zJdQ;fDeac{pf%AiJ|r}0OhsUfhWb37R(tXA%bB0(yaQQy!yF6IRkiG&5A|I&kVXj~ z!-x7K3fE|Eu=>9YnLpN0!m(GV5T|esz>RiM7pvI_jB|SL%WszL4K(@)b>7x+;qW%k zDB~$Zh{^mkV)~AZ#K?K@Iy%MYONr#t{tP+q9Kq1&1><LmU(;rp68J?9&3FctxYjUE z{Z@d}yRRiq(d6vA0Z!^vU>#{f=Z)3lV<NUzzUQGsxYMxVwQ5PX#TVa!m;pFM{>yS> zM+mCLOXm_aayvygfhVE3x*r;dz|R(~5km;1rNoabMX+-c^cu%#+Jp}-3??N+VM#Qg zl#~7FXd|19-An9b)Wf(qMfq&^OTV+ZJ5p^yq{<W1ViB)Q&a@xxqXL;TU+^u^^5hUw zZ}mc=eH#%Pr^UHI)jLq6_gXWjBt0R$vRCSeYzWkgqTw*ifBQ;w&kYBe$gTp`h7hmV z;~HZsSntf9d^_5W`FmoWPAg%>2h__TSUqVJO<dPmVx303`V{Fv_N*{9kinZ6&mTN> z%z39`-?c*6)ZU*e-ONXtiGT)V^fU85n7atFyF~yo6Rk=D;a|q>u^p45$dt%BB07yp zv}b<bab-!ESXce`wgLG5W3aGUpdmP%b{C`Oh8MBl)IVw|WT$=63(ZJNkI$jG;LHPg zRFXWX#vZI-U5J+*0XWB^u9Gn$B2(-mI9%TEpj7$TQSKiZ)R;A(P^z#3V8DUXBX5XT z%m?I;?0ugR^C=c}csz++bqZaWTEM~YaqE4gosWiNc;N5VxXkR9%9bw{d>AKQrKbqU zP5~4Yy_9E1{&chAtO-zT%mC(G?{6n;rmgly!86|MI4w43MD7iH6Bl<&nyn>!rZ7ot z1?*=457eI%v3M6WTBqln=-e)hAe;~7=g}D%2ka`Vg$HnmL}7dTm6(ymG;HK-qAE|| z0nC+oZ65;)vaV1qfvD5?7By*UoMEcuuLaV7c*BL0w{p}5I3f+|Sgg^7dynIU3A9Vw zE)cYxwWJOt6+T)mP4q4*lO_@@78da3KzlnS@YC~Da=qQwRJPEfzSf{dousbtSR%Q! zx~#fhzCA4PLld9#0TGn8qacv4RD8h5TyU|%=6Vu()q%=lY_!L3C!8KRkims_9|OZU zl!|yJjZZf`^9b=wDgrPrcsBXsbRta>SB^(sFw<h}jfuS9;}d)hNKQ<AzGLg?;D94n zo*A{CH0Ac;$A^;@g}II*gyC&Y0LGJRHjFu)!*u792hHcJ&Mv3(J=8lH4b_TUi|)>` zJWk2&wTx_(oEaZxDl%PP$S>(by3neU(lgC%f;cQ|dfQklaojVLL>iesu_ZAlUAD1l z7Kwj;%$1}VBh2zt<1}&s+XlrMyNE1;S9&py->}3eLT6)?+B%orkXsb|$+s9s=+mYq z3b+mA{|YF5#eV*aX7wNp;hdpW%Ooa#uv-%w6VnsHbxnBvqC>Dsbb}Dltp~apQZMDD z-wm>D=J_eviQAc+WtHX1YbEaK+osySmTq`M&7(X_3?{9Ro|GI@d~Fso41hK555DUj z2M@z;o{F2Gmrco#Ob<SjWFBjKwy+Hd1^2L(`}oK)Q~nxHa_xO8La5dSDhcD^t{-FB zsSLai+<aVou?!{v^_2O3?&9t$(y|1h#`;M5<L>-CvI$1^p#kpitZd_z-e-GfxU1jo z_l}TNXvdal5F@;r)j;Mk{PE7;mW+PgTq`1`r`#2|QG@YaOw~wk7&gg8I{BZ8O3(qE zs-lv9*bHZelH@O6*8DZa5nG?rtca=m;frSwL*F8({<DaN5=lKv%Y%V<4iRyLJJeMG z6GAZMSMd)Jt*JaN96|SMS&YS-ePN3cZ{M|2WAFjG(i=%jKSqqu#rYM#^G{xTaCtV@ zHS-ui`{7?Zdzu8QuNT-`1SG1V{?{f$NZ3pQPESv@FA<{e<|YS;kdOZurJs|tfX@Y7 z&Rp!eZq!ADN)z?IwDt6$?X$KFrco)i{Yy4*;BRVbLXZdd?nXvNrqY00)#BR6S1VnZ zeSV9#rgjMkU$ZLFSNJnf_M*#3F=T-Mf7y_$>8WlsCL@cBcN3EwRncEX(h-hD%d!Yt zHC51^x5^@|T`{~yLFT`V|9=-2|Jb3w))D`#B>ugv2mdRb`oCBaP<_YUfZtCF!MX~Z zxrI`ZYR~cMvDTH{bWq^^5~lv0Ahy5G`4iOP*WX{?{_Fey|JUg~>!k&F*M!-B#AFb< zGQ)sp!~mKf&%zNrf`2q-5Qq67Ai9hdIjO*T`z{0Pv+%=X*tjygjfX?eB~0o4N>_^U zwan_5?ohYP$kW~)Vif{aTG2MmGt5Mi4chPCGOinLvERK3>bB5!Sl1dk1zRF9_(=!_ zUTCo+RFv$xxQ@K>GxVRqg_#6w7I%*18sk#;9Ts<pxR%CO6Mx7@kVFa($!)IMO9c|Q zjU@iiW;_dNX60hecF+3hoT)i5iWBNp8L6@t_UV}Jd;#iwf4p|H=ftwkZWh<&zOLCY zK3Mr4UU-^Kt}N4DjG<=W_+H-?<8$JVL6+&j_nYdk%#xCGSF!t^s{1ChI9zL*|145D z#JnD#N7}P<*m6G(;NrDsY$`o(gvbWp-Os_Bm+HzHo327Pz6?1N)H$QEDu^iJAvMpi zAP>}dcY+_zB0tUx2_B%C_6qi2-Wz_3C4gD?*&)`bSftxw#yZx}qEay>Vt!-VLTQ>= zT2h5?C!6TWm*;PJHg)dmUa=HvT${{no_*2IkX&^AA@Hi@aM89W$aiy}b#b`ax%O6o z!$4hKeFI?B3cTwsy~}NU_u>@8nQ!kR<tV`a)RzT9Q%CZA#|rsJisVrAvcvh)Ye8q1 z7wsOJf-@9C%Zp7n-d{zep9eR%(oQ{=rN}`+3iTpbiG*2HblCPjTkqjp0hEJUJoeUj zH-zp^cI^ZVF5!9pU<#)N;vaiz;mQ0o({ns$MVkkUA$`4k&Tmc}a#v;?j6xC!tpL{1 zJ70YSfki!+Vw_J5-RD#sV7iyUdayI&RT+{IGg%^^c03?kplG;>Tn$UL+6<a0T^cA* zHwm#gOy09sBARQ6c2nNgpIIn$DGD%>FAy8ItTvucb|!#%;PB$r(#-^ZJz6+W@U<gE zuvbnoHUJVs?$>*jz|tklm|~EV&<$GFik(dc!x4s)`A@f<PO$6U36re!L$p>-4Ake( z?vA=<hkZ;6cs8W<^f|?YqiGtC>(5QUf3U)R9?VBOE@t<w$uaEg96!h%6KidOV3wls zSbsk`P=;s+wbHaH!_AAQ(tG}t+>vzLgLY{9dxKOV)sigXF30%r!JI6?56DXJ{LFB6 zJjvkA-pT3cgK1YC4ZIA1zrpIPe7b*rqyFJU<l6Khrraw5C5__)sqF#Bj}_`Ec%hN= z2A=Y5@2+U1gVch=eW<HpUq>~}W3`T%vA5TD6yKO`XvhjDos@^qRVK#|ltaRK%Z69j zAjAQAVelIbL-92S6J?<sYZA}zD!9r73WRd}sR>-@fq?os5w?tRIn{=<K7GbrTYgXW zNU!iin299+l@|2N-u^H?bJ03YXHh~Xp&Tnz-_Q`!*0?gA*A*WYAl-<R!pqW3n{{_F zf$2uq?0P&1bh}tJSRVE<&*SXDaXC=^(e{MErhy9RD3@~1vi_p-Lg_{52Q#EQX?4-j zF71T)M_lJby?~mNK|WL-tSaR`-~*{f*t;!a-*v#*JkvSr-MPO8H%w3@EH1ky=0@%H z*VXFeR+@*H27W~6sAH@dfae3A1P<6Os!URY@u<je4zC<mj;!#r;LHbCuSh~{s=hAt zvqVt7^M5kn@H$Ew$o~0_JQ#>0W@?_0wWc82YZ#Z9ph!|k8fY^>yKzXXgasp!0DL>t z1w0V&2l{08HE>&TO=;m|H7B-n^_K?LJ9RZq`LHu&1#9LtG2H`_PfhtyJ1-*|hsig0 z{qiJZ7sve=l7G^@v@sbjNXT>Aj^@R1XqBC+EAAu<sCE2QwjZ`nAnS*ahK{w)$EZ0v zKPA=`Eit#303^P*>+0)k^m6W62E=uE(ub?>o?hlPBgN3KTsd7k9xeoyf*z<@1(I|h ziaWohFAbyFiP&84%zwj?oH|*c_!3W`DWu%L7nAPg@hYM9^=0o7n+>{{O(*Zs5-7V7 zi9Ix(RdoF0KtJ$~wL$t7W|!FYmj{6zu}l1(^%wjn5BLvTVrcqhoROmg-8f!Ff2{6J zWwG&rM>}=ll<c6v;!>E(ZxH|kWpQxSDTWUHY|1x2$B3I+F90m(;ZE=Bp0cb1CE6qL zuuI(due|M$$ZZ)T9~#2%4BZ(b&BO9uJ$f3tMM{?u)M){YREKnGm(t&~HSO*q$j;Yr z1N^+ki%c3t+`+1=0EB~vbcRUMQKDn7wAY>kUT{O7yfnE?>|I9JV~w7Lcv2<9%Z%P4 zKV?p(^U*}o+La{Ndxq1SeZPk9pQtS1@#EE4#0ecrS2P-$n(-jk(l_Df0lG~JyMSYJ zfwj?AEDG7t4_d0JPRKU?`_<hgEM@1*0dl$C9_`$Sz^x9IB-7oqj|E9<^@3MilR&N_ z91aS;Rqwv&=%1YIf_kdu>2M2_&qeS8&<p7~^jLl<&@BTL@CjkQUqSq#6{HsxBo{{; z8P!;C^V@+d*B;@#r9S}*8ykR*{6?yHFD4B<z|yAlo2W)4-Xt=hFNr*Y59bqrcuXrA zZX80Tl9#D_8x7piAee5RllXC~IVIp*Lz>3o5q`Rb7IlVx0c{wnea~(Nf6a05yCH&~ z%(}!3kmH?xDxDuegw6EKhVJWloUTnG<W)X21rQg2y5(3_n{l!OJXiEIU^}Fbv#sw> z3zM1v-Rv~wmr7QAe%=C0P$oW_xzH&BxzXn!CJ(nbwLO78#R!TF*yBN(R|8r_JqGy1 zm6##9=xspj@8L9t%erwigpDhKw6F1C6-n_?Qx-$fsGKYwRFcPoS#cb}OaZ+=9wU1Y zthPJl`$8ltRn&hn8>Q_1D1l`Wx+xjLZ&&FX^@ZfY1d-h=Ih(>=h7THC4I4%D#I^7m zxDjhW^4`Yby=Vq>L3zBkoA~_fH&--KjVsPksMNvY6Wo?cqmp_g>Bh)kYMScE4CNu| zWR_~z%^G|zmnXaR&RwzHin?rv_DcA3=-k?YKa!M*$qqJ;)m~<JIly@j6*wOSSxT3F zj8=;p-H1plMre|+XLFx(K5~tp0*M*o*CUr}HtI7=7$&|q{4><CUKg4kdS6eto(R&t z&3n+PmqWC1RkN(?#?X=>K|XLKcO+1`)RJgbL$B58d85x%+y421WJ+ENZ7>YH5gge) z^SDUz!Q-zp!qRiFln81!FLK!WL$@Ku8$M5WQ)<ZZT3I7iB6<vv-~Dc7_px!n8fuSI z`bs=nPD|euUB7*X=F#=ZuBQE*hut25q+onIFapQZdu&Z5HZI~_c2yYFYkIBlafl~2 ziM}$y*J*Y{#%3spdEcF<+RBF}>O0McV~pJ1+>-zitRDOFh&fF4&Iat{+R)8aKz2tl z6$h1oxm-CCmm$fi-!8zng*itIIV2&&dPyoW^ZBMjf7?1OqRB4$Zuh0!H)?5pET5Di zQ3{|b0K0G~OD%tkZwPEYtIXty1gYAqmZSf+IR=1&-wr{rE_$}43)_%e!>iu$pS?bZ z=?T*i;Ezxoqn3;vfywQ9?xG@!`ji1*&BesI_x7|&N1Ipj>3>SNY1+TsZ*bCg!TKnW zD%9KDNkCJt>tV}}rly*ivQ>x@I{a9U#N)J2(>2K*K;P)(h-Q1Q&@ALzwv9Ug)X<b+ z4y!fNlyciJe%3#Mn9u!36IG185YVx6S9d)mTrqHr77*Q18%*DGv=K9Z8BNJ#S^+QT z2mI7t4Lgf=ZKA(2ICM+s2(?w8q$lo~!B4Dg;=jbWgq}`6{$)}GgmU6y{GR`KoRAR* z{-)D_%Op@zI(zA_hVv&OW=b#T|77`PjQpzK-}GyEdJp;4C;z5jnNKkg&+t$Bl{pSn zR`EBnmpb7(ceQEu`~urT3&03*!`~?;R449NNqYaLKbJ+QWc*2gFRSr4#ev)i8}&Ws zz(njemkM}GsmcvP`;7Mo$E7W>4>|tHwHx=&F!<)Zou&R&UGdSL<<v!#C&s*R!@_Au z`WQrItmu<9BMzFt+|Klir3nV7f;r2?9Fy~?gA>;r&WjG`Os{osJkNO!*AEwuepTQ! zAd=PU+2>oXwu$`_#4x%rwgSkVJ}|hAO<lU53HFQ<zB)L%8WL=|?_VEu>R3Fy-w-qx zZn{vrZ)mz?P6BEwsgbEn&6=7oJD4WqoZs?{6wN)v5BDy#EKN7zbd~>z#~Tv^uqFE% zf_{&Sqw#U99+LZ^+BCrunPGFXC-wAQmlXbsE#*Of5!$`2gzY^=ENQQry0<FlHFEQg z=EeznJY}9!!=~h$qR%>7Cpn8Jh{;&CK34}Xwm1nKiOpT~K6DD!kbgi70gv$>kOj?E z|D2zUhe+$yqGS$KK4wH9H9)~PkaFBKkE-MwB*l9>r>^|khL#rXGz_@wk!~Llac4^{ zv-3+=xl2nA9FF;~I_}m|A&4Uj(MLB5u5+F)m)8o3b9^gF@P<f=kszTa+m^XrjjM%? zU7_2tI}aO%o81E%^CSaaFS*w8$lFwQxw@s>7M@}{_b}I#T`1&<P#<}r`XddZ>oU&8 zrznE{n<3pKNh?O706w_WJC?L!;Rk_aOs)KupEtuU#HMp6Tu)!1?MXgyatDvWODKlX z!_BvnAE>LGfYI|E@5X6F-bfhuZT2T_4`X#weE<((t~96l>;04pp(>KVIagUiZu_Fo zJt9`p&)``wLj8Khc{C;CVefRSf(tGL)4)L^&H0T%%2?o0UIbz}m@%%@_vz&n^#Ue6 zf9C__G3Tx~4p}~pNR8-tPq1d8i==+K@3|k5d|UQ<1aAc)C!>A&@;=oF8u3lKj>SIr z$jE^aAGjuob30%?gxBvw)5*H-lJWN5X+5p{Aw&~Oj<$m{=W+zHc`$-b6=3*Ci;NQO z3k1`hI7UqMcqgX^W4-?i3Q?$7AuE^LRS(G&vZc*jYXZv1f>$`k@3x8S3wn~Hix=nY z2tPlmaOG`W8JJ~?7C1eHZxpt?_iT27RSu<M<OxC>$e8rqJnpB4{IT{t%sRC_F0MG{ zEe`jG#+WWWom16uFSzd;s><&dnvJPukbt<TT{Pc>R&vPm{mm3=J$YBw(&k3T{Fem3 zkko#VtZc*1!o#y9i1^v~c6Oxfb_IR#^G8`jHiM+ibG<-!w4<>2?;*l!i~<jPy*|y_ z4W9KWWcM#*ZtuUJ567v-{QmB_HKV{`o_87T3=2(kWdo=9>wdYdjk@vF9pT+<qb$y^ z14K=7IB0S=FL}7hIyOG-FatY)NZQXc*`F5pVN_>E336p0rEeb<%{?=$x7SZw)irLS z+DS2+u;aLrAxw?gci7b@Tj*<~8VCxdgf45$e)M~Ce$8ZK)mR<)lII}n2gha~fy(Rf zeW?!^>lY8*cF#W|goWJDpVmAJ-q2~(H=kHHqg0hpUEX=uT^pG#;)^6tY6cFaVo>ER zZ~}{Y)7tw?F(C#d#9;Kc5y`rOPfOmwPI?z$G;K*z3cIa_d!DzXCbYQv&Huza+20Uq zAL>t(<eG=~dx@LB+;xg;yM|kN9$($+-W-IY#x00@BG(-8y+;l;sZCzG-@i@09So$K z*s)4IY{%=!6@uRY8G!LR-^FO^->tB?Yp~X{by9fF-WZB-;Q&8KT8_+q{f6Y0^9;=p z4dDR(6+aF#y61|Yfh<Y-&;@r>Jn^iy3>4aWoaS#m8=S+w>MzyJupx}D|1g&|`O07X zBPkz}8WGiTtC+#oyULp2=Fe%tCuh$eN}VIb8^4ff@ukg%qHRN2eM&!wdI%XZlH?_S zQf1{LaM?%`-TjF%TO87a$>uGd^c5QWFhtt3pi|UoZVx#;^iu)3Z#gI02QKk2kjS#L zV{gY73*o5_<J#>;Dq;YGM1C^aH$2v0fwz{W+LGemEt>3Rq=Q0~XxR*ASJ#|<M)oo0 zt!BNslFJxMDf`2mzeUN39j81l^`pDV^m({GBFXs@b@Z<M(T?rMC-ezvlH2deK2UPz z7_fF>5++mDcbe{7VyYni-lc&%3e%`c{ff|hKziFOsuEEvJ24-mSOs?C1Sws{_U7K> zp``aI_3ct=M(YQ)BU0naqcs3Me~fLUJYs%PYd~13uoKRok8mBuyYFCFPClPjfvZ+6 z>}A*bSDdV0lFxOArQ6q+nw**{S)96b-S2QqyO6paSv*jL4)xS0bQgkAw<b7NUe!U4 zcR^7-RSkEiL-%@OLLnX!y8zGAqrlC>h?JYX*%Ov~BEa2QAPZOMdt#9x(jR*{)*L-l zT&+;(*8#NGVvX(P4~WJ|gI$_NSdH(vUdawKFuq-*?WrVxg98aqp?J&i!lpAy3-Lk< zpY`sY1gZEmueu=hPb$+D+T%%G5oMo0lN)mg9FB?myiUm|GbZ_7`uPy!{x>w`>1Wd! zik+;k4vISphQ8g^^HjKP-LHb5E3f&W7D+c!g~f0VAJIE2UgatBNzWLySXBp+`aRFR z%LU4})qw+g^8Fo3g|=`}9wB8>H)iCJe82?)O~EW@ymsw8lfad)9^95xcGv3UF6K{^ z6$&^R^Bi$sAP2TOs_v^;y;4$7&5aQrd3^Co3%$bLq$glyZr?aTD5zWY&_#@E_~8QS z_qUu7VY2T*dxuX-=|c17CyG}9L_FQdOOGnIm7g$>XE!n<ERC`<)>7C{=Pp6&m*PI- zxqgR31z_Y-ztglul4B&K<AC+MqlMk&+RWv-DNi@z389;_)!kCalSeOdUYrI93BTZc zg0cn>x`)@Uj5iEX<TS2?3el(<5Kc+&d0t*%YSCUHmqb44xLP<mFGLhlTY3+>ICqrL zEPbnyI{dBG65xb9sTgyL@fK%e+9x3Jc>2?mZ~_`*!aivK6cA0pKpj6KeqZz?;EljH z*6bNaFzo?Yaa|Q%mK(kbQ>5h?w?(1ZND+Gg-O6)<a@*v^wZ}U4ALX?^I~&lFeW7~C zxNBWwC+HQbRLL5Ij!~r_RuFxPArq*?$rgjrNEH%bBeDLK{VwqlD*mY}d+Af(F_X<I z{yePG)@^IC?+0n2+d?DgxE;X9l^Fo^rVpZ_$?90wu2K>5#U_EO99ZTrZ5{+`u6$;V zQ?g1o&j`XGs;5>rbEMlW;iN=;Z8zYDi6Zd$ZbXd|=>ySJ`apKiz0!kN3Dtw05KXZP z?HJHk_R=1{f;DKEuV}N{<A<AK<-gv>o6SajU4xg!L6E}(5bw{pqg%~tzF-jA@I5K! zbGk7T_Ra*~QsesfhZ0IqY|hC!jcoU_ds>Zzy3qLtQb?+bH%?{T{wgUrko#Mq2fG?q z2i>>HwPF2dr*pfgrjUo{Gm6vLZX4Y!Kd0xG^q-I4f3LtGPK5X0A#{ncMV~(8nNidy zc@qo^=B+EA!QDD9j%%V^#*YWV;sAPBXwp8%Dyi($33ehB!=g#i3)!cw-zilVrKK*E zZIq@nBgPg7G?#23;hzC}QiFD@v&Ut#`H$B`lZ<f0GEf1r0Xqh|1|F|h&^@^ARVBi( z*;vdT?qIoBbPX)$K7Mok=^?O*7}HVZTE$<IZ6SArnxf(BFp^FZ8>9Ke_NeO@>z7q( zhrD`}HY?%<yeZQi`Id~C#3&b7vKr_jL+n-C_H#aYiagR?&)LG8gE?*;YMs#_;e~U| zCm19oGW>}6jau%h(w}cf4_@S1T!3Y}w_mU1pV0|DSu80G%%Jp|Ek1Z)U7i@#ui}uz zW8E<yclAh1W=o;z3`0(J9q{6~>i-n>l~HkROSia%;0?hwSmPdoyGw9u+}+(JNN|_n z?ygNBNU-4UPS7C1Ew4$=x%b%^-}=!%7^~S$vAb%{syWx@qQ;o4$l+ChvOkj1Qr{xd zKC!%7U4VXDBC1~8yGtjLg1eH0S=8D-^y`XMRmZrWTRU$DAR|dv6SeP(7Pp5d^LCSB zuL-y7M;c_-=-J=42XG!iyw~H?H4GQ}O)@9@So7nSiTb8uKw9}qfAYT9y6pRXs{1^= zwA4uD@4YghI=NrQgm;mWzu)%VPsK&*I1PrbwJ0n0Eo?u|C90UFmb<Qm)HRtAf{%cj z>F{!zD~W+vvk%LbYAjn-!9+EX12?*CcaD5}FGD_1$F4_n5C0mt)Xx0=V2Fqmc$Lj9 zSTiww6<HcFVN2Mr{fiz9gLWeOF_KNa?0fqpCb3J=hnWRsm`sU>#Xd2Iiv^h<rj`Ue zNuU&z#5quz;H=Puf-l3=!lR390rspS&Gv#tu+EV}n!jv~15US$W9j5ij;pEp1p0#f zeOid*ZVE4jfY4I9t`B%Q)_8?-z~3-L)vntTT~Htkriete3?=s>u4<32R%KeplST8> z9Z}$?rt!AbqnA(sIgz!AN7|CQ&y}R;&}IxK_mx(ph?Y<mWg*kAflg*jK$tZet*;lM zivaHpyWaNHtsQU_jHm;YBP$52*&HpZCd&%|6qLZeWKviU@$qm5dR`e<J&f1H?pHmg z*2e79SiLX2>4jnO+?@2}Lxb0^gqUWYk)1LM85=>YOHU(T75#@uQ4oLrE}FW#L3g(? zElcqUiS;2Yp;=8w1dgXJOF6gqI~^KJpe4&!I9a5vh8zKGAI_@6hF8n4TU&KBEmisx zi92FrXZoa3f|i=gEA@ZY<(dRrFf(YTq7N-1u>XEtHC4jCMp}}jS8o`qSE1wB%D<`C zc#9R{v^D&v;6mDlAHM?4hSpk?MP@v4&wok<qsWmr?eQo?49YS4vmdl!oEyo1NzZnU z2MxZD{t)|`m2ur-0?xO<hF{v`3IBv7m4tNqcA}#^nrq&v;U)JNfX*j>q0nwW541c8 ze!e++>oCAI*r=E`D$AgI10EMZ0C|?Njoe|{^Hp<vQVKCyJ_FHvA77M0-u(CNUtd1i z-}RT-{>xZ#|6#T-8(-ER8VnACd=LIvFEsc+oB!Y49yO!Ot8S2!5+#=(E{b=hK&Lrx zz6e&hDaym#E>tf5D*3s+xT?O)AwM$aXWKqpH*LDo;I)0Hh*2)saLu~Tx#Bl)?AuLR zdG?2}Zli#2!~`yK`LnuDN(p@t1pJwg8b|B=gHGt}gCX<|!tciLY8FVz!%0ogpMDNs z)OSR6*~Olr(*!^Y<mz;P0r728ia_>#?&UzI0;0f1)^9l1WaE-v`r9m)tj3*K<NLwX zxOPfy<g8{)`{^o{pcymp(EfBP%?g@N^>A%jL!PzeJ>qZ96^xG}4FU`Hcp))Fev)Y5 zmA3}_#m-Z>6E_>2l+P1Q<~oiOTsB=U+_-N@MJtAkPtw{iGGp_WCsA%nw+ox!wg|t( zY!C1wN&~7V*5Oem=oE8CGR^OS6Xr2p7V+cP8}nJa%PdsiTanD8yRQsTfP1D$np0Xd zh1l1y_wO#xKAnT@H+n&5j8!btHXDF31Q??3q%Xh<9^4G6xBR^8*p98Ip4rnuHE=o# zWop@oKO7%g@y;V_&B^wHvV~Q$kFeABq0=m2bC5bod}wv7y+UxBZolWjLXDxw`s%W% zAJCHeQ;1Hr4L{ad_&LPAA5{)}j~WE^TMbp>T8bd@eBo-E5&8<Pt1K)GZkj?SZ8t(W zk#hJ~FgD84!oWf#^9gOtC<(!b!VOv-9KXYEAgWdwAdp3a119DIkx|e7H4I;kAdOlc zOXU{rxuF>n2=gTHbx8YcZ|+GCsnx1d+cM6lOxL8ToZ(!43}IkfnGJ*L++MUAw{pL7 z|AM-n01uy?{`{rDir`jer19*=6k1vDMH7tS=7RAe%kD0$x!bl!4oTrVNjm%Bb4>%W zQ6#><0Y6RlggQuc4SqVoH1w@2to6yieg3rcnvwr=b<6RTq$<l#s*Z#6mEWx@id-2< z>_TU}$xQidtV7XAe4o)!2R<}}%`jX`dgao`04xL!qKM1AVbF~{2huSji^<_@kS1uZ zvL6c(<KlbjyTh>ER#<)_S2?xrf<;U#r<Bv>CAgJ{qh3*FaGez>1bb^Y`zLLVT@`AC zt%wYS<2e{T$1z>)yJ+WYLU><i3KRDSMCaY`^7LzIxGKui63%c6xDTpt;(x$&Fr7$( zMKC?e$yIbVueFE1UGpHVR;K_)(u1`I)!)oDQZ+)etVxW=;7Nc<(o7TFgFx8FtRakT ztHaf|`30)as&I^PXD))Bj4(2;l_Dnd2UTBkVIq(6GYTT>s@i?P)$zpH1WbHpr|j~~ z-oK=Av6E6`=V^eKg(G&0dQD8?vF=K4gh>MwD1(%`0{?vPVl)_-Yx?kI0xlF|HL|oj z4EfTz!d!ndq@@(C3o#_zRm>OsC>4TrjVGZ@fHR21;o54R<AFA9lFJaDvN50tyOAL& z9X6(fn-ZHaO1%mZQj--T?GA5x=g}W%@1Fm|mAR*X^*cVF1pzOzNiU1HnLIm`yvOH@ zE0oYWddbjmdzV9YEwQ9B51R>zoox(~FjB&`$uOPEK9L>T42Kdg>3qdLj-}?{C;MU^ zwaF0UZ-a8JOgMrZTdbMftEEO0SST~zJ4zRh8-_$t*&!3QMuX&6Ib;mG!dlX|rm%{f zCiK8Zfi0y?i82wy{9Ol6B|{rq7OoOhZfM<Os6zXQFtMn-oLXvFBK;M4I(kXE$1;?q z?mo2y;Wyi6f#qrgxQ<+mwWzg=-3L@YI<9)EPD%95vP?NW@?pGkA@qG9X`lB=c-X4) zWSCZ${7%Ns!)(;6st@^164d8(-h_qW!&uLhdjG~60w4yuY?*WDYj}#>d`s5L2{{Xj zr^WOZbqz4yS`i{O^}6I&uUX6-MYm(hi;T2lYaDdue$wFaeU%aF)+CqkK^%m6P0(tG zMU-@Hl2t4@{uMZ-4i)64eZE3Z5urW6c!9DYwO{xy>_D_LNdqTZ?VZd<vPI@mtME`= z5F31movX7?-)4$8o88g0V%j!fLj%tsr&@~%qXMa<JYye2EZ8Rt+NP03DK2s5kV=C0 z$sa6yB%`$EPJC8pY}kN9_d3`tK{P1%#4(Pg$O)wUhAkO@6MbToiZ%}P8L*nOj&BMh z5Dt@SfKQRH#8t{>(th99cDHn^kJCXXzDpY_2oRQCsl<*gwid@M;#HT9{shtEspo>3 z=-<iUFCUJSI3&h@dqr7@dRdVnM4{Rc@Ej7{3<9}{TN^cbIV~roa5}XJujkLQ7g#RY z5tM%X;`0|cWMz0hFjZoM6%GsCQx(hn?msPES=cqb4_I-M6DpOj;zI*NkBv!^i3S8b zFSvdqixC}vsAV7yCs~%hMwH(^AYP`!5gdFY;(ILINNe~h7?o(~3T~JQTN4WXzzW<m z_@hLLnpX(LgieC_x>smN81n*(c7yvIUmy4@drC9804Gc4gjPnV{$3LyA-z9D?$qHY zB+6T3Jzr2jm=a)$jNj_q@zgM!yl(Yu1`@^yqSVl%qFTx@F~9bd1Tx>bt@3<ucp8}6 zio=c>y+D!d2Nn`vs4H=Bb(VvTnwwO|ru&hEtY4d=0IHC76FukZN=1&sHSjj&{B6O- z3yidmdS8`guu+5wtM0@)8+9<<YD6jqT_buO4Fe~@R@HeK1v7P3U>_82{IXs{n$#@1 z)dE%d2^7tpHM2YG&lX>Lk2@SM3maI<mveuh%E_5gqOk5>{AqQA&a=~6h&9*;-@bn6 zumgYP&%5c&R_izq)-8!J=_pgoyuaE`u)xzmvB(Qh|1laU#TmH~pP<pb4wF?n_W)`n zG!<##_bSUL!4nK=B!#-2>n_rkx~hW?oS{}PK$xUfQ`C(|1aynY`pWpizgatp&Le18 zpEC|2fJqColERq(8EJECU?VOMN0RK6i-@&DF4HywRlT%e1s3sS7|aC#IHbJ28^Kc- zdqj3^G%8<7z2<uR)0=@lm0N&eYNWzu1TLZ6!e)TC4m+YSpP6K1K1I!0U32%Fi9&m< z1|*iuC$dWh(Zs{%Ux6hAkegXxYD@wz<;p;<SK7)?@B5x*Pfehzm0)i7fno#hE1RV_ zGuWni3)@96@r}q-dXKo}n%>>OUGNOH&!Uh}v2ahC6Zh^_wSy`r2)Z9ibJ$RrG5B<2 zce+@&M`naG<o5L|y&n^ig{4sCeL&S1`Y7A}UF>!V9}UdVRkj)_UL~+3T?X02`XL(B z1x@mUj4<iE940w(m+A_Fqw9A(@`doZxnU;KzZH=*&J*#+X@^HPK)&igJ`I(<eLCfM z+i6(gQQO_4%b)i&z1viewFC&zo^Ie9x|=(ahh6L3G0O}e!B!jKP08D>umSJ~R*N<D zNGw|&N@VmWZ3CpEEqyUY8O*$<j>QgE+)6Or3+Pg0biIr}SybRNZ<n%YPeShYi|PEL z0g^tg)lmkrre#if<#0CR*4^wv+_Fh<iX&T0478_GC&8}pm6&g6KC(ZVgk<cIBch4O z`k?wSNk2-_#-rm}R&CA~5gwFmDuhpNh!~bM+2~{N*;a!y>K<-1Wn>C$L1af=W#&so zo3`U#mX;O+b90%|muiE%BI=TkTi07h`E$d&=tCWJ%Z$7-2a2W>T$e7M<vt8a^D<k! zt>d>v@~Y0NS~fuD9LEy6E^X~Y7PkO(1DqRLHEfWMqP|%!IVWRBRr`sLaC1HK!DsyF z7(5cWwtun-gobRpRrqnqUVUy2ru1<=S`eIf-5+0|b5kKC%#Nt*H@402PjN0cRLEF+ z%S&jO)uS<0FAs+VAPf%2zTCcIN)}ZdiQM8LIq)&9V=GuTG;k+0Et98N>A)7e4zJ4I zkMAG(@rD`gYd4~DxUrkM_kAjDxu=Y$D9T;p$3I{g(z2C0sn4o!?X*yDq6`L{i^CM0 zfK!n%jUvjzlCOC1bxu>h>vXNF6TQDXRIald-=#`v_~H|z5yV<WB{b_DJV!!+7R&O| zeg8WTTN6cIsk6=LVjG1Lpyq<A)61dJ)DpNHp+O}g+$R1~F_`s24PH3G9^eHR{9S)$ zV}JR>|A#{SU%Ov6|34$Lf7!+h{a#FK={R9xW{z#XDYAW7u92)|Z8&K?hqPO~WBN#M zzOUT|vko+L=q<lj<VWkY>#)rzo^9xL$y~MD{I=Fs-+$t+z?9NWqdp*T$~?{3MB(t> z*7-Qc_a+9%L$aQN$i-_7`ehad8HQQb$I|+FCiUMeH`?w}{kg(eU(-gx=-fLWe4m9f zOZ>@6l!2K|cCh)DlxRgXI;?l+pMh5X?|9qi*5!i@u3yJ=Im@gr(`9@VGyvH=<6%-9 z!Sp(wyHdtF3YYgA@7aGTx3Sl5g$I_@=O-)>k6iOtn4#*H7+>9~{E6LnU@@6b$k}qi zE&zFCnk(d)=1;5d(I@c~@t_yeFUlX8f814%`Hu2u8VSd?C(*4#Z7K;-n80U7Ti^>| zA8k}#lOF%&#dsTJOY><7z3!vOH>Dtgg)ke1HwdkCme2%6^0(gmy<c`2gF>`&kSats zliRY0y5ogeERMXaF(#N1Z;=nRN1a5D!+`H|EyU^SdoVA8gtYkv(X@_@nJr<OZ~s8? z#tj-#(#X0Z;a_iQ#Ec;aUIh&H^5xd-Liv70amAj^r#Xo<(MltJ)o3#j$<Gk#xbdU1 zJMLx$!X(&xKf5N`z`MMybh``J7af?oRB(ukwY>#?{;n9L%!!Lwr&ouZ=d$~@PI1fp zW5;p3lAF%Y2p3wr*dG4+pfOx3U*R9`t~E)JLji}`wBIO50lVK)ScXJ4=z_R#&UXsn zWPk~S!N9>^#j9~E!o0E*hg)6>OmGR$cwQ7*iI19|ga1^2QIIgqtzXi>1x?ILKNT-0 zfl)uBw*k|z4Z;ufPAMx<46o}Mi*I^ZZ5VU1QN2cY3_fGgi2(UC%@&12w5bk~DO!T- z)D&;n<1}_+PTD<=TN8hpMb3mfFmPH6HE_Tay2?Ew2Xxjef2;(6B2dwZ4{WpxevF-1 z0fPe#ob-70RSMN;E0thHJp(L0XtA0I>FqFauLjpzn`kIdWT&u>?i<kP6*`_DXdi%W z_O-=9n<nxq(U9cWlv?N}4i2?btgn>+nnw7F*`-6PH$Og^-$2uN5?fT8Gx8zFS@mmV zLd1z9VKvEnY_90Q))=Qc#(t7k;tVGID1)qKZT8N=%_TA;MKn+~mu^iUjzHK6DN&Lx zUgW~iP2qkZ0#Qaw&{ztb?J-6ZU^tt005aK#uRDLD<!V-S3M@fdny?<SwQ${+{TdnU zla|a(<>kh_2~Z~uVmR(L92JH<f94Q*jq4=5p{d_g$MK(-Lvkd|2?7@%?)yu=hD~M7 zQ*!Mf9O5c@50-tH@2p;1=a#&}sCF{bBw*o0B_#457A>0a>u>Dy-iF@|8APP0xpZKr zJ3&F;p+vjktekA3&<=!ew6{ID0~rq;BW0&5EqV%IuL7-mNk+fC-lwRyAV3U%O~YrE zhJ*?Ru^Yn7_A8&Eh=h=%K`)gyi;(YZrw|rPl!wW2D35dG5ecx#+g}ZG@U#*usWu{b zeCa+I3^(VhQPNhn5wT2Lm(*nrB8SVXE2ySQTi$QqvT+@uHX#*Po$PgjLog0`1R=lw z@NU=|%Q)Tjs*#qOzhTXZuH`jvZp_JG7QXSMy-<bkWSIn<&r@?PfgeF*2!P}#4FwCF zd!#N|ziS>fZe(^Gq6-B&2{D0Ky2u+?!<u-JAFy}o4i34EB8%AlnzZ>87L?qMgDtk6 zgJ$|F<+*RM-V%kvS{467dItpKii3RCY5Q-Q7n}LN2OoBvQT|kX;@IzlK*Sv7Yq9GO zSbl0BKfNSYNCJ*@o?_a<s<M2=C(MJ8)7lgRq^u2?BPu^b5&J!bY6pk+*{{NG=2M0O zdxkLX0yGDMYyvfsQP_~KK_76+nAH(>3fE$(<{!o}Dq|%1fXngfWa>M^XxJ9M0ZC(6 z;*A$wje{x}CI+jPN^D=(c`r-ndmiXOLo8?G4hx7QieNlh&z??FP7dTy=JL5nnQ+&Q z^)jMT?MWcwOw=f?qUFfrLX92$fR>SW+NT#tK!^&kWPs6SlcHXYI?#-nt(?yvWXGy- zR;ML4&E%-C<?wbp;HVF$ja8RjYM!pzB#7c|7KO}m$lh4b0A%@bRd1CmXue>(^hBp? zqFd__9kM(&NeI}5KPAnJOP2un<MF0_<^x4{8$5*=_NRc~M3HNhF2z`J%S*|ECQ*>g z$16Y6!hr-VkXvEB(M9b8cC`+q%&L$EIO|k(Y}ty<-3pQ1BHZBnN?o<_)bs?bK+3lN zrWqYj-Kj|3<<ZG;^D3rY1>6~W)JwV%GCQ-WxOo@~VG2@(*3ZXZOw$lk-0hw#{uTL+ ztYN4?djF?Tb$lFYsU0+$OnASXTjCt>VnUs7@WFT<KbR*bc;qdJl$!P`=ENg=n*Jiv z0k<ZcF95sr9mp|&=fi~%8?=uU2vZra2w)1%pS*Df=d+m5yWtcFm3-1De3rW=NB>lE zj?w~kdZ8}2o4@GR@JhH3nBc;xOA_uWj+S5M0k5Dex?>1uu!BEl1By@ohPJ`ekiOxq z7CR7D%zY@Od*#)kHXR5<XH1Cq2Fgc7V+9nW!J`FIW`AIMhwe)gP^_s+WPlL!#tn>X zwYT7EOzLeas)A#xh?9iMoU(v2=r)ze{t7R&?bcDoqrb6ENdjKjr(&JGxL7jfCDOZa zZ4!G|>RLeB@An^lhX80FClAs&>((m1_?WPLa<mCe{^xe?Z`%PZUm6u_O2GZNVP95n zR)l$(Yz|R&0d}=xrw6FyF23>#ZE&za9z#hA(_Md64I4U_RAZAgI;T<|hG4H0+K4#s zxJ6|2xfs>95=>jE!K2~<FApuE4gg=Wjjk~Xe4_LJMij0VS-O*P(Z<S&w6<SvEOVm^ z7C~e<_$XWh7(bw32xy0AFgfXqkQlNll9CqWs0laYP*bN3y~xer5E2L&R^m4)r$)NO zPqN0L=B$qdp!T^TB=rbUAX9(ccT+t@frVx%JE86@KyfEbfcR&58StYb!7%xVdW-#T zhI3g~rNL;f@LNOfef2_0-+&m;BCcWqu5GHXqu{x02PK2JcZ_x-Ak7iT@HrHuT1_-z zC9I_oFT0EJZNYgT5iX{D0gd(z^n93G3*C9-qvpoooSZTrlO&YWj)z{*BV1Q6Fe2zv zEHF^jRS^da!@P{kJKYe?lNlwk%<kBzSMDmPq@A}P;lv=5Z$u_TVWpzKpoYq)Hh~3g z{o2MrKmG7m5Wof9#^oTvNf!TUrd8bh8^9uR<RjmN>!T2kQ_|}2-<s>g0^ZWx;q${A zFTzrzOJ6zS$fuC#oWyMK0Cf?|KQwLD=`)YRpx9Q#t4dGVfpop9xHFqL%taM{xLB)e zk=rlWNAM1Ll}s~`WM*KvD;Dxi_O8WbR&l>hQ*=2H;(_fZ8~lLey?X`7o5!n~BRFXv z>_z_Em^;Vv7MEO8%i63>{EOXtJ*=-~Dy(m7YV!;IhoJg3Rai}isnKdF+S0-2Tnx}p zUsfXs12{>4=PDU%M`1ZxEm|E2*@}yU0;yOmxfT2`PWsf-oW?#g?nT0|$0lkZC@GTR z6bM&v6H*W)tJ4xCC%Gqzo?LK?xJH-KM@%@303&SIn+px(*gH^+H=C!!RAM7Ip4_zi zh^~vCLY9-~Lt$VmyeK@$I^hx^v_^kp_n0to`sZ$?(iJ2DnJSZ)qh<Ko^U5+KfLJY_ z0+IS}rz~C%R|aUsUM57Upa7#v^%YZ>BKh;kqwMHyTg#}xBIcl%4*!c{8L=Pe<0CQe zeK(-P+F7FAqX<5lS^wc>LE1h`*_6qjGzUCZ8S<}QGB0Y{bmVg4EpP*;5F77=ZYqB& z{h1)DZ}IWx`uURDUDj+yQ=M0#-@ZGgbTnM}&+SGzdbgZ&y?D|4e#KN5g=4qAmwCd= zB_G!87OW*IppC2FWNnsTa>hfDEe*LHv-ZtC(ezU|%1Rv;Xr^0;`iJ8>?utc3<=W<Z z+J7hq>AM=9vv1A(?p)^sbb-e2k7;pJu)*JS!KB2eI`O%;Ya{^+KO=lRm~!8j4q&6b zK<58}Z1hKDy5rt6D`sbDb-aIH`JYu%`F|+*>LJ>|7i}IyiTHQ@WhwvJ4iS<Gf$AQ% z4leBd*uBne+jkFq7lOQgLrQ6--C~P<qx}kty(^f}^I>meE_$tjdtg?H<*?b_<x!NF zFs6M~@~C7Z+VRI6YlhFteX;xY-0kRGUCyGn%MX{8hi8jhvnKBonP1b2qwixy{Nnx! z3)yOv4q7O8&~F;RTg&q|T}%C>5(NzF1|Vp#(MsENo2&RV?f_fO0>LJCsU6?@KID$5 zjJAxAT|ZC6<#h%*l*QNi*iQL=<*b(K>9}>Yco$S*yNa6|W(;laHy5w+vcG9>LZLJg zSmvWIWYXMR(VVE}fB&jLLW1cq#-N|C9gWm>j%jV*^{3{)!pL-uq{9{|!sgT8X5#&% z!_7I~pt`2rn%I@e_AY$N)2dM@zqKV7NlNCmH{eA$9Kb}j77sjwh=_+y=5r?Z&jv|5 zKR2Ig9a7JuBVn+4YtupWnaw1wjmykj<J<-9g3oqWgb>R!SfD;9nk_ogcz(T)u%)*5 zy-p*m#CT@GSV`2@ug;|@fOltzhC#>scgFqi8sx*<4qX>U$Bz-RwQlA#bk4Nabt(?8 zQby(7@fYSf-LXGo+azn{nKASLcqERdyawk8j~$MS=+tkIj@GOYeGIDXQZ$vP#NdHh zI#C9$QlF8V&3I&NSMPbh1<c^v>qVmQ%<h>5{H~^v@5c3?nQaPv-j_eyi?)#(%Yj~e zi)eeGNh=Rx)~rLz)^#!ekg98wx}dN+g21RPNtyWy>`|~{?(b`c{r5hCOsg8dz}yB~ z>A}ncSL_ABe5H)m!m@o{A-B}Jokh|j>`&>djZvRj*zvL<_57-Np@>?3?PEbqHW9G6 zr6s#ar}3?~^FXJw^2lI9gZL2?CTCnm+<3FYYn9q&^`ZvLXf)G3o2r}YKJeBQV+qwO zTKmde(#-M0q2hkR>_M0I&({;568zU(Ql^YwzlGd5vkhSpt2pXO44i|-_$}uP8;d6< zvM1jPoPZ=l@~=R7wIZ`(;=q;Vgr}vF-Ixy<TvkQGu9SoJTKkEBF~)Zn0<MP2)^y9s z{mXe?gZ0ARW!Nd2d0-|ljj3QAy;`GbJ>o@ormr=hB`ba&vZte(oD2`RCCA&kNN~h( zQ+3$EQ!G|`hdyH7+@T$}(ZR1JKn_JT{}U=mq+ZwDUUL>o`Cb{$X@s1+9KUhW4rfuy z4;Kp2;qO+?al>4PjnNWm#obD(n$y?#6-n!SFqiK~DQt7Z2p95M==-Fdt$1S7Bzb0W z@hm(x8JR`3UHOzp0yURBl%_@sHf;opwe@U3;)+NJ{})^>$J#F|U#<p&`AUH!+hfsd z77ctr1f<!_RvM(!dxNW@YRzcNa8!!=c1iUP;_lJ#JHE%wNWxz^+H_KYR{gO~Wi90( zfv+4-DB5D9davB(GLhX0T*boDh9j%i#ECjs#)3sadG&w730Fg=+i@j@=OeKgB7>M? zRd<t5)`v7xjrn%rxF=6`;jPt{Q8BXG3|*KU+)4kk02^!fQEGlOiaM=2y~FRc1+wkV zeY+TfSFbR!H8m?4Eu!nmRR)^9Ori;62TyV&Ds8NRpHfb-j9VDq*imr_u?PV8Z`xCh za6cAQu6ukNXaA#MhKwSEG<=TKnU?(4J>fTH$&qo-H9D%IWSfe_KNtJ4{xC^`VTQ|i z#X`z}(Ul9wbC5|jOY0d*`75%@e8R$T&TZsit(=)rq(eJHST#^14*7GdW>05RK-dIY z;}_`gvy4xshFaZ+)rzCdiqY^2B6fM=3H?#gQMs~4VVVp`Gt7GB`e4-oTRiB(nCZhH zh^{}Wzg`9?^O2$MDVkjy&!f@p+=w`dx~ijqF&ThlwVYoZgceAyqMc`vpASe6{I&-* zT9HYsMQhE!^nJE;#x8cJImigRBD1_y1yu`2p}^umBKC$^TUphDLmMFi7dOE;uuD9i z%k;GpVEHf}P(o3yAZXutu-<OOz%+-8xAm4<H>YeB=Dv;-YU~ppB?Qap+UT|;`Efb) zZ=q>;{mICGW!^1zlAw%SeSc?vJoel#tAaP4N=dfNsthWX?$9Y5rwqL*Yss`laDnq8 zaNw2qvX{<b8gJl1n{rw;WT>m-#a0vFk6?BZO@P=t>N7|T*<P{Nbu|{qHKj2GBehN| zwiL+R?LRGCACJ=;+EMVC;ZjrY$0f!Z%(u-e#tvz7%Xi@}M8<z;LRcwlqQ;>3!m4>( zq$t1E6<4yljkfl&T)rD?&7e-6Nf=-rNHq~#+09^`AELq0ZtnyZiS>QM*ZyGxpp5+| zOku^tnDyGx8Vr44qhHDwO9AxYe5&S>^T^;y;`oD)6--Md!LzRRNlASZ?J7z5S7pSz zVbCXStR&Ih3+IPcVJJP3h=OZ>MDytyS?_8Bk|Xz%>o1K;eJgkT$ZaFI{e(P~Lh5jj zxpg-03-*G*AZTRz);dg@S*Sv5H_1!8McE-L4%M#+M<bfT9bfR1*NmXgi(g|`Xryd@ zWEl!>cR@^(J2Tr+62N*pYW(dLxKvefdWFuFgsr%_SuDM^JVHJz9n`)n+;&Hw%Ubo? zd2OH%h=mkI#~a11TTffR^%{%CIemDb1)`LWM})s#Yv<wABGqmaO{UM(bk;S4Ksw>) z%2mx`6GB?eb%r{lijQN*2s%e|A9VHe>Wv_}!xjqIdrFKNn|uy*lmND@lh+fmO5LV| z<volQ7#{acl84l#Sg?b(4eTiA{Lq<)<iKqJJaD+&u2S+yDIumTApena4>0YkhP6B# z-(MOglB<w(8G5YR5hja${aLYqoRVO%y#W=cCtBZogSl5f6~TqhP|y2=mzcCg`UTCu zUV}$H@N{{NW=sC!L?|_wKLU$htlm$R%BzZyDqOG{`y`gjSxe0&$ihtvID<kdC|#}~ zo<EY=TIjK9<V?2~t|jNbWuz`*UrxQTuwxUw9E(zVuFgBH8?V7o$o@2Wd@)!0d5Q4z z;t5E$qG)?HpLe^+damSE1c2Umy0bCvU9*L_8Yqx-m!)29L<R_DdN@h8hA>4tRjsNH z(OZcF9c*{h+tbJ(eRBCyd7aZf^C))DDaQMvWxx8z4;De?y@K-j6sqW2cD}}RAamMJ zp;qrgZyR`izkSbiPoq%JL5W^Y)f`2ci5t(niXpb@k2AY|geS<EFV}X(<*Ke9H?r7r zKcC{Hk*?|2hlwZ7`EM~z)5v<h0rpf?_24{5+uWmwG+s{%1jJd3x0&8wuL#hfWhYQ9 ziE8BuY@TZ=pJ;|6|GH`m0(>M9yIO3X@vSz|yE3luvOj9g*J}gidFiNrgR6653wP^H z@I7Etb+eDkvHhnOrD=ef*ZW^-)Brp~%ZQU-d>=C4Eqn|FZ|YY|J`&a{N=3dAb3d8h zWgheYlU*SNY~-eydw!teE)~XeJlhl1LQ^YNo*PmMh2J8;cnc6PF!#=r!(J2qv8cTC z&woVx*HH2oj{a*tfjGmq7CicwgIh{!6o0QzH(1?#3?}`LSw&0nkDczn-j){|=>K4D z;o$<YuKfJHda>@?)|qYR*cHN9S^znDye5tBShvdx)MdA-_iFcq5WVuqePGOyvvG5+ z!)nbH&Gopi(|pky0%l7(GYu{>yTEr{55I55)`;`Y*lj!oYy8c9ZoE#ZjLb&as%-dt zZV!3TtGSr<A;^#S>$ksu5ahFkewgnPdp<Kw(WtzU=p=t;d1M>mUIT*88xh}Ju-{tD ztKdt9^@`v6rFw=x%T;E$t)}lZqrZ3f5?b<0MD6$H)lU_3AK$tsg9Yx>_C##g(6WLd z{S*J>IF!8FqT^CSbIY%~?<$V`Ef_79MxzUIXw1cLT{ba-T^VqRzvf61ygFs-dw`#A zU+x_G2lKx)#n|;~79^L>d@kMH)gJR~9`Zaxx6$Td(h=l{?0H<~v&baYHoqY}64{|T zj$3Spb+HEeTaHWbg>+L;fiUfOzOWMs65YQe>Z;p&Jr8b*_86CLt=rpL%x7HKKPxZx z<$7ZW7qe|IcG5GxcDCt}W~oYa^zQr{vfHhJ2w?%NKT?<(HZoe|`J!me3&0iJ`2_g! zolDsFdftGWrh(AI%yv{q*v+&`%w;RbUeDk4>Aph$_g>Dq##?mg4w6P(Ty1nNm`ly6 z;jj`5iY_E<p8dv&ul#S}n7^@JIn>q#{@z07?)kpSg5j={q0UZIG*F(IW-H!WU&>e| zq%>r#yrtMAa$~>%jvgZF)jL!)?9nDtDBolfR0lAM1LwT(I99VdU2v5Yi@l&A<0iC4 zlVBL;rXa4ZI8W;dLz<>By5oQU!CTuEHBisF+Ns@Fk<ZVpd&2V7ux_L@gT_uO^H^<` z+t(4!Dv2Rx_v{^(R~=Y(I`N+UeXRXVQBz+1eVrX~M9Y2z<5o2Fmn^r23!S;9aJ6(* zurv9;isT2)r)!Lc<y$E}%RdxKI)5V<`jMu=VOM=?RhZ4KJ`uZNxs<td#TkDvBi*7G zTU<mu9p@zn-r}xEO=SGNw^x${HrmqGGH%Ljm0@pNmN~ht)aU)xX=M7HINzMBFq?t@ zGO9z51O>=2G#<7AV2=gJt2R*RYSG7p4(A-Y2Ctb9#c0sURG_*?2>LI)$s9@%|CQ&| zIufI{sB=8D6xm?JInjy!d2`sKhymJWOIMMwG?@vTZk5Six4v(;;X2)i-wMxQJiqS0 zDXft01HV+fmoNAVK-i5@{hn|N$1)^8JL6Rli<~Zd*jQpmKzhav#yadJ2L`4B?a_92 z$sWKlW;8!Ztv*bt&eL7=J2>o|%F$&I0jl~Hj4zgV{6n#o(Katx`CPE{C-u~J(LhsX z&G4e^W=f#n8HsKaNwqNK<m#`}YgZjVC6F~aB9z`aDu&gblW4BC(x@8?Kx;sCzpXg+ zf_VU8;EVAnSNU>%x{KAUxwZeTHU0c6d0nPVY4=j-8f!zu!he$lGZSE<g%@UMIfZsC z?PGreQ`grd;PQ)Y^J-|dy;-O*#;qfOkKCt~j8?^@U#t<W;drC;!kArNwNd0#{|7e) zoM+XN>Q&JY1yQIGi$sU)O{VJ|gA*qao0SfVWQBJt<;DO!g*uvUX|e-Zp}Wu}ibtE| zqGj<tDPv{cdRg?d8qxhn)2)=+dTwdToy4Z_qHuCiLONF^Lk7W}f1n9VO}LbJm(!%% zTTtLWA25vbYr?d5&TJ}fw0NH+CpNpeZrXI`yLcx)YRoM>1B>ulUg6*Lpm<@+O%;n9 z!#I5|t%G&20fR^ffhmUCF2E!dzkr(-ONdDB{lq<jK~06zBGh-*_2U|O#$$zO_&Ax; z3|wg|Jb|*{t)2H2QW-zKOx*5>JSD!8;1K;JC&$nw1-T=~pRwQFtUq0)&JX{}#nHqK z^h-z!QMrgRolq*ajp=~VvIXK^I-e(ggWuo$z*j$YhbbCtjGP9_p;80(0h0!BGfT&S zD8_kb=66ezv(X|G>O^*Ld$lU{TcKoLu|eId_3A}y(0V6a?acIk_MS7BZR+n|3Zm8* zC>o=Rk(}@E({Eb@*J|o$_i;uRr4fG}o-*0u@21Ch&*w-Xb^5392`GT-*7W03srTo1 znLnmMH+}Kr^Hhq9>ulasc`fRXguk5DcRGpccoUfA5W657TRUIdAtq?<(f=V(qw)pt z3b~DsAJ@)(T%3iU21(OnQ-N5OFCqaE8dT}@=sMak9PlWqfyRL3o7fI{s;^*f7me(g z9FhE2ROi?`dhOg{x~V0K13=&yM(uHATO5@8zNfZ+-P6%rs{fPy*M{HcUC(Yzp!n|T zjm;#w9~4N`3QkXD??cc8UDefBnuw%0BWfr4Zbqe>+q4G8l-|}1#)S6d?1Hy0w4p~e zAl78X#-pbaQAt$%ddgV`h$!lUKi;GN66MxA33%15rPJFV0y#!u%@AUP!lP&`ZrZA< zGDvu{hdA7(ljB07AoEF{=}~%+DELpu2x4IU3N$F9@G4^Hd}BonY|D|=*@_-e)em&; zVdbNsY7xTDL1#X?@PaSA+4!cIuZsy+ocbW@)pATD9f>y6X1DQ)&g4|7%v}|);~b-2 zr4+?2VMmygfi@9dy+PzoDv8YxfU%PiEy&mp?qQ=frq2pzb5z47<hiq5(G4CpK%AUa zD@A@s4T{fgN0euPeUl&_4@k;)_7&RQHZ(a_+7S-yRBa?X1lo1B`&mD<ob_HY{|+vG zy0Rbkgm>bi^+u|-dsE?RDZNwN$%RZTCpcYgPXxhtV;gLH<8k)lC-!KCk)dS6hQY_h z(VUsXsNoW0ybz+BRIg4uAhN0GN-_frH@y0hQ1iNzEz7y}7k^&24hQMPc&(!`3OXH8 z#bEG<%fdr1_$h^|*Kh_Gwceg6HBjZSmLF?-8q6{$Gho#y^g{cp97e5}!mm*BgL3$5 z0}-ibf1nr_xW-C+c-tTQFSvr>;qA(r?pOsrsp*b+ySakLvyroFs^LJ)cl*kpEgse+ zf^N5MZ^WuZnCfH(TyVtr(y=sQoVyjb*rtoncDrxU3q(LqJ*Jdv;g*cj(e%)gYS<1o zPF!h~YTx6><z$A=QTRW1$EYjxY|hTC?SJomo^??H>!=D?>vk^cLIHmsKV4sRDULKV z3qD*W@zF|6cU6wWU}ec`-Vcd(;UH~^btJ<+C3>F}Wi1!2#^FXzop~!WKEO9PYoXp$ z8k>LlLT4T7!~oG{(r+9TO1+ceEf-kv^xvA7{m>g}?KtF65u-MlEux5}@F5e^DTa79 zig|{aS^7>j^ggoj%afHq<QX%LWly2hAG|bc91tjQwx?p|V2kRuve3^=p<bB+i2qw( zh<@Avoh-39N-{GUBn`Y=eF|?ha1&XFr`XF2ZMy{$6Te6$XfF?|_noFco!I}rYhgcX zmR0abs!Wy^pC`UwcsKrTIcHYX)X4#1fW&%Zl#6s8xP(4iov5J@u*N~sM;Dqis8Lbx zjqSHl_u__r>7zRGg7f3{{F(-V)z*@`0Mg)L(q#pKwoyC7s#2iYBgGy*Cu1vHo#yYI zMBZuvz5VLiqyJ=T4^q#5^sh@QG{4b`n$D-`nBk28_a$AA(#5zCfN9uLt3LDE-n4(Y zwDm{t*I>lpEkxSCp6wUQwuk@!;rfPv>c4?_dHoKIiPj*>3VpmA_kS*3GX2+*eK+_= zzw#oE`n&!I1w5psJ_vMcS>4^;oxJv|H}!60FfncPb-I17{O>O{Gz2+<_fD`ANO#Yk zzCQb1%+Ghw1inoD{=LeJ8l1+EMA%c4Rx|$Gm*MBo=0k&3>i;f$K~6`!6=<+?sO{n> zm`vz7dP4a~O7Jq-`lA&2^YR_25U4?PeEQSQz5_UNcR~aCLD_$=k>Wf6d=@nEzF&NN To&4_QNGfS@1+i)ogP{KflJ*@8 diff --git a/_images/contributing/docs-github-edit-page.png b/_images/contributing/docs-github-edit-page.png index c34f13f08897a41ee963abb2fcef476dd61fea5b..9ea6c15421a545259715453086a5770e4414e760 100644 GIT binary patch literal 62133 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 NeG<_2PUY|7e*lExxElZf literal 63974 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 asr2F2k>O5&{PADWoU($3e1+`0PyY|qnokY@ diff --git a/_images/contributing/docs-pull-request-change-base.png b/_images/contributing/docs-pull-request-change-base.png index d824e8ef1bc507beaf51bf95fbee20093dc44dff..791901b8ec64b5f5973eabb57b5cde91678b35d4 100644 GIT binary patch literal 17589 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 Rq6+!<bl`vMFoxVu{|^KJr$_(* literal 5849 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 Xmi&>mce6+#0DCDtQCBFJGk^Jin!3@6 diff --git a/_images/controller/error_pages/exceptions-in-dev-environment.png b/_images/controller/error_pages/exceptions-in-dev-environment.png index 74128990e57834dc8a59b93774dff76a944666b6..e1fba2bebf96f529e65439d990e6493233bc56d2 100644 GIT binary patch literal 82684 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 I{A=}p0G%cnivR!s literal 62791 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�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 DL#k5w diff --git a/_images/install/deprecations-in-profiler.png b/_images/install/deprecations-in-profiler.png index a8abcae32b79f772c42075800e2b6feedfb84a99..3d3f9a98a4a4fcd617d024e47cdd2143bd8e7669 100644 GIT binary patch literal 103758 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%0DX@1 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 U!xkd9JEl)7|5fq?`#kqQ0I|AG*Z=?k literal 60991 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 diff --git a/_images/profiler/web-interface.png b/_images/profiler/web-interface.png index 2e6c60618924a9af44f88a61132e12838c59a811..2a1bc8a0650a75de1472c7fd18141711954b67b2 100644 GIT binary patch literal 126397 zcmeFa1zc817cl-HiXtT;9nuZb9ny_}ba#Vvhl+G}cS!Tl4U*E`rF2V4qyI-S*j@GA zeb?Rp_kF+jj^2Cb%*>fHXJ*cvId?A4hw%@u0e3_MgarU#U;qFZC;&c80XzV=Ko{gK z$lJFeVPK(QVG!Z(+<`~LL_!7yOmYky4A4JvA}T_BLMkFY25M>sJ_#O99tm|>S#>)L zyZHD4u)j;-LlXf07DVIiJK$h=fNStz;P7A{S^)GQ2CspGedP7a1rBlj#?5PBw?N2G z*B3mfHP^te-+=fq34jI%mAV6d2b8pU4<IB^YZj<fKk&-^Th@OOq7u+w&5tUAfMX9| z#yo1+w+#NLDyNdSvu0MVhDF|f_Pi$fjoIq2ig;KgO{x1x%DLPWCG%6rq11X&=9@bD z70j^8vf6)ibA7HWsWhneZK|sfTknR|%K&P}1sCS3F-mo~7L#eb{r>U~fFy~O_EZ0x z47vw&(bWm@uL}lPUO7f$g}*k7Fk@zO81B9I*10jeuzEhTSgtpXQyr5Pg=5PaA$>hU z>%|7Wwk{X%avQ7~NBUCN^5T+s6h8}3tLiTk=N8A1r`>(+nCsWyCc#N^3S%>PP9UYM z^a~yw@`&xOp6>4)dR?EqPbVo!gIF6Rz!H3dM&3=tgXaE`1Mv2F^{EDL|AMF<Rs}{q zpu<Zt|4nJeX4EIZJq;#Be$%&&D;MBNvB{=xI<5p4$yOu<=m-I6TMe;&0~LAB?wU9u z3~IHJ+bJarS^7&Z7~Uvdx_!^E*t`y@?%P68WUw*8-LHF0J;0v4T2(d^(!Cj>EM?Qw z*264t-!67rACpxk_8>L8|HMv~c}z2TrZ2oEpJc|&dP-|ZaYDLhTUOH5^7ThPf5inh z>68Vv?P1-OVc+)50C&`!=Ba56M1jiCwXVF0h&i<A7S}^A@c@yjR6IXAIp?nF3wogW zV=?HHA~E*vyk<$pE;)1hI7&sIs+JvNtCjKCfOEBu#*duAzbCpVI}Yz$a~{eF@N6(p zw8(TXF|0L)BBG8Kdr_+Vti7*n$VR$YuAOTY^Lzws=9n*Q%eTBCCc!UQ=`@4{Q+naV z!y5x*jt<!co9KA!10a6$ot0aLx7qvEw&vL)b4useqSgJ-d36sr-kEx_0H)WT6p#AQ z?%bG63uGKuXx1dkGqXL|C2E%Y6@vOi1HAM|0&TkSk{+jVIX7sqz!8sM#sL6!SHg>$ zWA9H*cK?V3Pdb2gHFCdM5A3+P-qWz~^0Xq#lICsW$FzUqy3w}V>Sbu5IjN#x8-<LO z@#`XHv<R~X_{l8CtFW%D;7Nh*D+^yEeiwAmD2(g}t=%#xG-4{PG*(Fe1OM-l1ICl~ zrhj5E{u!EJZwEdu?EoVGy~ul@XFNCP2D-q<cK`rl_fPOYdjof?8MLlDWq}<_8x>bO zn(=+>Cp`3SD2a7<+!{gVJ}Wk@)VXS|6;t(gvv&Q6xJwURpUbS>prvp=#^Q>)<Du*v zM$766BFl7FfqdEM^XCIhh)INzXJNz)Hshv?GLi!&fr<n!q$JhvBXX)=NKTPeIJX(M zzGR*yR!kLpyFTW>F%)6H9x>6Ih9jBaPyi>`D&9c7cA~V_U3S3)#hlSTRJ^r_s7PIG zal(eBHT!r?anOn#JIFhnCXxFel?+(J)G8zEM%@@glrj`HPHsafY(`*WcBBibW>d!~ zCF}<PN_KCWONL&@`i$D_Y;@JB=>yxeS%-=GqG8)5@LbEpXDpi;gKK4@6(i@bg;FQU z!jeP_mixD>-?DDRTfUVY$zfbeV(orauzylvT99PpNEM+{<5rcsf`Pe?{E{+mo%2l9 zm;>KyZa?VZ7HNcKm}uw-c#59%3Rj#HoL{~Kl^>_xRA=D<WMW}`#@U?PV^h+Sy90gQ z|EN?z#BXw^ao0e)g8+$T^1AxunCl><ieXo7KFKv5SifGs+6`6I>y04f|H~Ix`NYDM z&788(MzvpoMQycqhF)F2Pw$1gPFUguQw-xip=Vtn+xc>hs^*L!$Uuy6dmMX#mdNd{ zXJTQFzM(#$H@bZ&J-RQWx$(eSRTd|0KgKU<VyTY2n$s_Uj&D{ar6P`6O^*~d$i0-o zvo2B2#L)J1!z<^^L1{*r(;?tqe4~=l*v620T*!v1!F|P2mN!TGImHFgl{HRz=BOdj zjQ-Fp_xI_FB^iu~eCV_jWdw)-j{BSS8z$BHr!Qt5UF)q<#*YSP<k`1(J0*J)Fym)i zwSB9G_tdQV5<B``X7=5f#C6(oiRB06`TeT*^9RqZrwvJQOim#aB=!X>^jYGz-whg5 zF`)Tz!gY7$ge5zO5c`!s)#GRj?XbxTV`^GxJ)*?TpUy6!HK(^Nkx5FeR((j^T_m>d zvWZud=Nw1QUQ$#MVq6$o7RFC=t&1ff0N7R2GS+2LUX|m!LgbmRGa$xI1W?Up^Q)nx z>Zlr%aL}Al7z;kDQ_xxDJjG?nY0rz_wPRHlS+_cbpN(yB>M_KmxzHCp%8(V>I6U=u zCH7y8K(H!c|Cn93h~<=XX{oa7qt;#})`AK8Yvaak4ilN#1^F!WgWFk!Xpq5x-U<0J zxh-4o8j3o2M&(X#$hfg;L{-z1VLbJF8BnDMxR#N@elYgYbq1xPxtUlh6-t?;*EDWa zr&d=y;<YMh7n)nW(I=m*s$l#9fXH@HMru<RS}Pj)OhKhKUs~tR&4z0eGF17#G3M2$ zA*MztRFx6ZbHFvS*xd)hR%2r~a?xv1$PAgJS8p_97br(EDA{<<Nz!S>7AQj`VMd9O zy)?Zq&)+Vdg=}u4X>jxi#RWUq{NQ?*TQaiPq~(U*C_>-!3@QPEI=Y7aRAtL7XAH<P zyonnI73_{FW|enCKp0xYdyGnhZ;yrvXDV2|sa;pe%}`}qdi<0N@!gUMy%<xChL(#c zSpB6{$WM10`Vp@E7xMo9s|XlE_{L^+HqUwnR8BZm&cnY4M$jsc+)y3?Gk<iW?jiC! z?*D=RtQ>flHoh}(uJ`x6K>iN?SEG1n(p>adrcz;TSDz(R-&-;BzKld5N}C3V{vKU1 z4Au|p`rDjWi}k()fYH+#-EjZaZ2pnn9e<-%t%C8V&1x`_xZq4$28wKZ1tm@LIg!;V znbT_(gn2~~3p&QiTZ+D~UNLOF_a7OevVJ+hGRKF|TET97z9s%Zo7}IAuU)58qnIN) zAh185*1}h>M!Vp16KqTmYht^`$k_MmlaeB5JuGf2<SU95*-%R#znQ7`l}@OUvy|;U zf4m|&izzj&$(&ZOA3Mxu{%YPNaYBW3`h|tCY9a9*o7+nf#OA}I9j#t6Q=+X2)x4gC z)n{Z9b1x!84llwj<fUdKwsnU|A!4RAm~(mtBuF-DeH;JS-2WbP4L(32Pj(94Y;cP| zSKJQ_*xI;bU|L2AtkmQ)SpOoef*GljST#S{SB!4ft}ykT8S$nkOMcu&q*1IItMPAB zVYW-wHi)566?552Tw-1{QXt3|_iS^fiJ8+qK4{xcC?5{*v29lYTr<!ch5~FlQJOPE z<?dHUU%>NL?WR=^q`wS!q%gq{<(fPv0X1nqXF+e%Gok`CtYAn>-7_m}@15#6t&eZ1 z*_#4(SGN<dd7*68a#hASL)GmR4~>%AR%RSX+;uB3d`4hv=ZZCXY+ZNee#D7tr<zzo zM(Tq2-1_#2R((_=>BO<c^sZ$Yu=~({bp2g@j$D@@%LUxYfw#hcFTp>S{51ITCfq?O zcSTkChPOd3ooP@6#)fw8Ar@l7!8LAB3;;mtv9-MgfJ}*dNO5gJsTp8iEsugS!(d`c zI0SQ0_Hr@@iBFN?v`o>a`lWSN8?_SUoy|!JgUFTbP@qE^6bj!0-q`aLtki5CZrS-j zl-T=frH=5EWZ?uRh0}HNzRYSy_Pjs?he;+EYX97f{mVK(Rs0KXxTyW#p+e+o%3bsw z{4Yj<2JLq!UJkDBB>Z9&Z5#b}C_;<XigOo1e*nmI1ZdH=;ZyvF+k@ifeEU&Fg&IiL z;)zOspm!JQf4X@+sTxw;F%pjRDeq~~&1li}7f|^5ZDe8j&EL_ty8ebCK?A~OYE>tP z&riwyBZ2|?Y7&nd`X${#B4AYNHy4K=gf&|Y=SBT25*pfFhHH&X2!cdcganceof=bQ zyJ}I?eZ7w*KVR6^Qwa=75b0B<5>xbqU$6iGG&IFD<=+@c(7*sTa|B@Itoo^pgy!fe zH8soLz5t-eeB%gl%XXGwq^_<ze}i1!ihtj3b7-rAnb68+fj%k58e74!VQmM7T6r-c zKC3UPgy9qlrFl8BD~n0VADA=gG8}4Zb+Q|$eL^Z*Y+9OO3mm9=1-R^an3j+Z(5SpN zZSbxk)r}q7lKlugV)YazdHz$oAh7k&3NgC03&usG>9_#^H2VbS<*wtUL`w_zPZ{7? zO?zYeo=KaQXPL$#1Uy+V9$6=5@vDAZWF{uoTanH}o-rmaSr7EL$e0iOSONk9*$g@P zzgJuk3T^IFDlD%itlx7D3p*U~EO~H`OTNIU&FNp0#X?<UVXt_sl#=3SHkAma_BP&+ zvqX-9;kDuhIJJ{J7IuXS7K)@aR-0GqP~=4vC$hL4pzLi`QIV2E(X2ru05!%w_K60D z4}KUr0D$b+cmdYv6a-6IJ_FO8ZNOm@wtu!gJe;R~d*7Nq_l7gzV}89_bIQOPO)8BZ zP~&XtNr&LjRo%pxQwLIMkh%B`HD5CLLBzL%(rzX&u88Zu%x0XDDer+)?m;aXwc~g+ z{@$%lN>E~%L+6ETMKxmWI-~sxNwZc$v)7Rtl35wDi=h`)`^#rZe#JCpXtO={0gX*P zO`yf-zrMP@s{wyA{=udz-5xFJR=9Pa?zW$`-F=j7zA^O-Tr;nm?wp^7(zaQh9n^G( z=-)K`UH{3LB#W2G9G}car6O@%U>1ExbJ&}htjYE6dmwHdhRm!-ozcTg%h*i%Bg%)T zVV||LK@%gto2arVY;a0OKK0THKFLYfz`&HqVL10P&88633|mnR)zLM!>QS@n23G;x zzhCmW>{{c0-F8OPA@sotUXd9Xa%=kh{=WrM6;DZn`e9laGy2MsLPNXLV?V2mW!t3k zGWH6eziEB=w}ijjBFZ#$u%fZq00yV*{gQ8Fzd+f_MoJ&YGu<9ApU#rL=hYAszSwlY z&p^!y>t*kcL)wYDZ7D9(OdzHTU2oAaF62Le^rNTGKj}o>5+<?fjQ?EGM^1d}k>{lT z#+Crg6ty2Cu`Z^Zq>{^#<s`-`6JTCg%C@!<Zk<;WKW}qk*mp`O{mN?G5qgC+E?omD zdRwj6uDHsiS21K@iKT#8(j#@lteiK_$Vr`y;oha#9_5#Tv^Z3t+1)VoVb&WugT)ok zbrYful`*9uKnqu=@sOBivEF@T6B&VtH^GePJ0*PbF$-XfQiTI=>G|!=$?w`WQ@x`c zWArVR@3wvXQeUxChLH{}X|YMi`JRG}00y<KoSca^-}shDXS2Jpq9rO6_0#Ge?{<^N z{!09_As`(QVVyBUC+hmBR8RdGR&gJB_c`JMy9Qx5LwB|qgnAleNU-q)K3Xu%gqlC2 zEe)cszcyWw$ZV8N#^2El<^Be6{c&nw<04CGjNbBV$v2)+y})9NzF>8Bp2t)3>k(A+ zineE^4z#C0W6&JkV_wWs8r<(A=I>a>&vIJklt}5t^S%@zm~{CtXrfZFR4P`E%o-iE zZKWP6amddzjK-=t=qFYj%$Sflcn*pBkODhKwBpWBTOi&t$!1dw`)_I5wU2TuX1zG2 zdQYa9VV191c=t^$$kc}}XY08=700+9WsKXADWRBJ;7pNdT`zjGb8K*pzj8lxEldR& zN475`)bRsg@J)JCBV!y{!SJh@5gode;bRKd(#qB#nY<l?H55nwB#2De!6@sV2Hw;` z(Lt>O5#=2l)Qqs$aqAoJ9fOMBP%>$m;pI0e=;p0pR9Z7<)CgCmA*=W<x%VC=A1KzZ zvd5YFM_9S_P}<;CWXu@a{0*H1n!#UY>y_sXkx$yCa(Ug-B5(9gk0$ibZ!_4g>4Pv! zS_Runz@nI{D)f}tCbT@<Pq(u6ui!W2Cx`=Y>`}?<;m&I5e6*@Of~wC2uI9o}alWJy z+k_F%4g%2wsK#Xf&Xm<Lj2>Oe#E6VGQ_`$5^!!_(vBSsp`ik8CArNGAc%+L*k1}d2 z9KHU19S}rnM1RAe`8~NG#=#<KGF>4Ye6Y<+)Tsj|j`(9dz}Q`jyX|dVVa)j6cdIye z_^Y^#qCF#WOMBE8JW9J4@bD|KOUveK^dAF2l8QM-TPB*5+L>7&&+Jny83iy-#-|aF z)-cB+(}cH1hpi+L*%FUKC+MlPj9WP4eq{w5ks9$K#n<RR2XvthDtPwfVK5fyzy3ol zmzK~U(7zl3GWNei^Iw!f|IO)VXko8C{=h{`SIgg7M*cwWM+ne{G?YDzix?Y`OboS; z8DtTIg%r_md7`09dU?zVA)K&-Ub|i?tfe~-+7#Lt!xkop4sSTG(=w?qj~c1!Wj;!1 zkfJ6wb8LOQVwBm6RWqw7v}#}Hsz#SpE-Q`!)Qf*$T0BN+8${E_AJu8Ts-{jQ&$w2C z37phr_N$WiMVRUj#C4nA=-dk9)np0FHVvfOoGvIUn3-oz!^dvC!ojZqyHJP7Q3yI; zwZGzgE&9}q-l+!_LZDfF^DH8JDv2|d)A1=CSBoVYGo8y9d*oxSmpbOAc2`Ssmuu!& z8WT>6{hUxB&g4lHUyeH88~J^gc1JH3TGR2N2n+$=J*&W^ZdM<;lOxP2%fRMNiHUgv z3$?i>rv#8WqPN7M9MLsKYf;yZ^cM4G)fn`4EqQeuD^_0s)@T3`v;iv|=PE-;3!6MF zTS1|2c90VpkuERK-0H8Mo1iH`3v`X^R*?#C#o)l~cL$v9xEuq(HeOv3^yM}cDxe}b zt<bQle+_e^shUHXhmBv_!+$onU3P%fad*PTxr(ao1E6bEbt4uycoeTmHQOwxP&?p` zoc|n2_5DE8z5vt+(pN`S9{m&hwCBqyzHG3>q@qV}G_KV5D?nX;gYS^}7gezPAFBuR ziSqdy%l01${s;qVybGr|k)oepwZ{m@F@T_#AwRGZwErENS5Lq9wbUg)V2BIor^lT2 zaD~q{UjGmHkq|nNBK3R}k8#BNk{Tq{%Fe7*3yy9<2*^<h2XJz7pM<@B0Q<@lZ4rOJ za4Lj%<9=Ja7xNLyK>k-@U#fHuZSK#Qv;Bd!+5-dSH!0?x&+E~VkADMhYX3JcX1`YU zJphcrQZbegT)()`iD`~r&0hnI$hOo(s~OGYL6H}diHk829nC$of%$+)D&`LDuM{rT z-gSKRj*cnYh5dRi>Ed`u<C6F?`wo`9T~g7ux5Hs^`L?_XT8H(P2JA<!O0w?nRtD<d zt$f^*gB#{;W?|I~v-!ZrVpN?pquayKe02Mj4OXrWhp7QL9Hw<*;n=wJGRj-;PccKA zBdZF#PrZ)rNi3pWVaWGNQ(tk&rJ1l_334(iF7FK<EmwzzV@ra_Nb=<ye`VyKcDLBQ zMYr2H#=$eCsF$9yzSJjTv*}$(tPzKK2Dw<g#?;0u?8COS-XjUV-b3R!H_z<am-jJL ztRTxquxqz10-RX2<$A+M=`tAn^O~jK)zPb&R9iuow$WfXBVud|ye`aR9RgqO8px#} zde-BoVjRcpkKFb0$p)R7Tue!9gQA0Hta#p%OWYsV@UIg53P9qAb`OwzjeY|z4IW(7 zq3WI7ffrR)btxmjYz09DuedEyB5@+={uCEhh}e8>%5nBH)Uu)N+ToEW8+~am8-2+j zA~*KD>KW>yeC=eMm+cnz!|4`c%~HBHGYYA~f>jNtIvr907==mqXgM_e-#Wgje2S@U z=i>*-X&Wn}n>@MJGlig~9*xgLCtkr&Vnj$Zw=qu`cTGz@1{FfE&Q+00Esg!Dshr`9 zBKeYlczDe?%ozwnrfx0>yE^A(vl?<W-K|_S&n9Sdh$bA=HrE1YZ5s^KI9ROgqCv+_ zT81QxfQDKF|Ck+oj+J>Wv}%=Ue5(!cdkKE<Nh?q$_K6hI_7-V0Osu9Mp^XP7!7YwQ zPgdKeR}Z}s61^yTHH8e1SWSH*_HXG+W*?fo_InxJ?mn@gtsACq-~z8J3dR|wS@=zi zKZLG_bm$pearu1Bc)1?j`MOqM*Pb%X7P-d!ZWmT_8ofDE;7n(c<~`;P^3+P=Tv7lh z205=0c>s=)UnzbDz?p6dgVMfUkoaH0p8%Hw1f#oPL4_r-uzDR9yGEM(H~A6Z^LVO( zw>Pv4e$V=Evi-`)rSRZ}*!wc&f&w!0@~k*xx*I79d4QEF5^hX<@hb`!N{Dgm)eYZ< zHi95-eUbbU6@6k#SC1{|-RC8@*lJ!;DNCykj{gIGEQFP}1CcbzTw((|6zRvI+IP2g zA7{BMZl8Ntizkspud&2Or6T7fs?)QX!^PhD($OI0j`6nPMq&~A7U*s1zqo+{15S?e z$H9qwVdU%ca@~NqXwX}wM_GrVD^IvLpW7WNS9;-fO--rtfnFR`N&nIdKR_iF^m>xy zCZ=msUwN@d!zs%_9W|qx=Cgqn7QYmVm1J<kQpFDd-s7CMf+Gd8r4NApxw2$dPw!0X zqHrJ9NR?WLiebgFrnUaAuBB>)UV*iu_&5Evirnh8NZerB-BX}r;V^qf483W+u0bx6 z`AZw`u-}WVDP(ckP>`%B&fKZ3*jmwvpK4cZWXT<i1*dk)S;av)cqgV@kk$1z8O3eT zl_>w&7{lPc;DhKD;5&b-gf}(@uo~4)#lZl^m@15<fm7qj+%n}z>%Kbb*E`E*L9bWb z9K}NSC9(Vjtl~G8SwvrMoQB1*-X-d0;*VYq42Z)78p<k;)VGtUtrR#NrHfceqU4Y$ zuaL6LAdoDJO6W=_FnSsX23y&D01Wgc@IEXx*-&j`&RK}jh3wZLN&YJ1p94R8%|P7) z&gAxBZk6oJaDlUT;Kfn{Y`gCH*5*dN15R`Pa1M^iF@Wt_Vo#;T*>lbUEI3aQI~+`| zm&4BcT*M|LmJYDlSt}cWYXkbJrd+(oxg46g3@%e1XXi&-j%FVK-h^AsnDJ`c&g`b| zFwSeJ98|Q2>+Hz=Pq?^89oY4`YaS=*t0#}XLb@q1HDJXBvu8TJVxfG>vAl(e@pkRv zVm_)bP3?)+LJi^zr={wlD$U(KV*AH#`s03p$pcv9hU12;vh_0NdUY4K7nUCY>gnf_ zTFpz?OWX9@cAIN=_8Yt$Q~CvU+7_E%6+uZXr^TIeiF@XU<Sa!yj^P~b*xQV=Fjbk? zV5@-qnLaxkO1%zfb8lV`VnF~?6z5jXPnMNuYNE`<XVppftYc2>-=fwE@SFgbTI!^1 z&sb*`_v0Ph_~e=2hGlObM}-}rpbwe$5Pks2DwLFKS-hov|0HLx@20pFHL*dGw-Xx^ zYk@QOpX{@b9tmX~(w^3q<qoai_wK*AeK4#UREFw>jXjjAkl!{C>?yS7hCUln>vdRR zgn22bqDx8@mq}`69W8>4BZ1j!l;i%5*GoH>BM45rd3@)P{eQrZg)kRJqRq`VN7@kC zi?fgxZvs#-dDJx^S!thva`F5&&qz#WVQgYV7lpu_dGdJdI)7;SH!)v&slXOC?T2?y zy$^RdYT?Ymry9QxK-RkWe?R3)p=;(i+CQaoCGQVw`jdI4gN2;!v1e~qJlT5f^mhS7 z`!lpZLuT8=B#!oavNc&?9;-ebLd!Q{eugfG?mlM7f*ed+T2_3Iwa0*t<DPs42O^KW z5lR49R8&F*2^&U%d)8U0LT6&^#o`N7%lp2JQ=;VzY+FR#ExX13`<Nd9w}6btI_h)` z5DR^^cy@VBD$tdE_AxZE+@C7~nN(Me!#^-`iGb7!_WwZ=06~yI<4PJhF$PihlW+Fd zx1>u`fW4i-epKf;F(BP>m-<zkS{ENdM-vW(%|L`rGE6-(3DAfJVhZQFR?od4JQ@Tk zl!@!ngF(zEsLRd@sp|Ig=0z}pnA~58hO+z#V-{qPz`K7b@w?|Wp~c@cOlLu7BA5`M zhicM&|94pdfJ>L7L!i)ZE*$@gvSs^zXkh7LT0RTOhJ*;~(9a@eF>R&<2WKwaSBMe> z3N>Dd{s0t3^3eD}65w~uM`NB~)PdxGm3h#`NxDysLejKw6bk^WUnRb0^IpSv>VoB( zNr}p;V`}PD6KI>7nQ-*_E9J{c4F1-`e$<wF+z0;0!GBsu$Ghcc;XQmPKEgj2oSt&~ z3;oR?`34P-=I4Q+@}o4B1DMz1B)En|8RBC0@l*C2!QJ{D4jWhRUdWy2s9B@kkQj*z z6n#=O7B>wI9~0qI%{<B|@ongQ7HhYqV1OtR@T;@|pfM@%Ee4uHR!HqUV@OM5_LfWM zQVGNg567ly<BQh(Z9f2boR#T`ptuNz%F!T_-sbJA?vHK`IF0MZ;yBc3Rc*MvE~MMJ zLhCB{mj@5Gb+3N3HLQM&Cy0#rEvFsqT6dJ0K2jXlZ)7ihuy8aT*bEfXS5(*UREhO; zy@kKJE&B%mpnB;cA+@UkOS^jZ{s(}Uo~1J#j(#pO7T>j(PkaJRm0p(j=6BP+a}A0V znO^C>&?tUw#2=@ccc^c~{jJ)o5NK2PL#_3@X$2v{C?0d|;nmWg;cwG9TkF&JT%Ym3 zB>-->zDLsaFejfUr|fplFj?-u59U4_F?g=<ofdpT{bl{j<!`*H2p^IT|HE)=Wk(?R zXF;8$J`G>!p9@S5cRR#%p3?ul@C5Vyt-=2g_Ov2FtJQR@Q-$z!{8{{aFaPu5wdoeX znH$Sl@<TXx3~;q^<Hjqp|NQPHdNBw+lJtsU{JWLp(;&j&l`{!2<^rH)A{xFPW1I~B zNC#qggy@d@q;|9hV|B6%C*2M>aR&$;HxT&BKOkhYMKazfhPm-$&d*mQ>8-{u@b8|# zQzHOci(->k2<5C>DT4)N&OH0-g<H2>pfao;LK&&>qG<c*5amxYWqP$zjhh)M*e*a} zPvx_GQ&xb_Uif7e{I(2V1@~{2{dS=N`G)QTsHYNK4e9sS0wkPcmIPjP(&ogOLV}L_ znRw!<&@rh$D`Fh4@t0A~p6N9v?rY<4nck2P9CKJ+1oq{RM^A3TbE?sMC?1z1;s{2d z!QiLuH=CzUYeJ8^Mzfi!DKdGd->=te)YdWHybe0RVG*ZNOY@|3Odo!=0{!tfwgAGI ze{peCHWk{cthHTL&KlV-zUXR%Q-w=_eU@Ah==DSti}-;o24#YQx`pADre9h0f2Jlr zb^o;?rk?#_<by}ZyAPFHADG|0QF{sUIu(C}-&Vg-ds*T8be0Ut{srZH@+S~^r>S7- zYUV5Deg`%v4z9L0RDKo!p)b#szPln75Gafpa<vW6@t^F?-{$!g`(|iLw^DF_%kWzQ zpHw>*qH6lkISy8jn4_JQ%#9u~6o&gM!!Lgo$RYQ9=)r-L`y~$`dH&F}``tnV=xFOG zx%Wr659kQ)r{m0U_3#Ud@E6`8s6P%#O|*PkKMQWRI(}jk{n%RilPLu4!GGIeLOd4u zPiB!Y)yKt9wmf6Hvpqilq}8Hg^3JzD{|x=Pb@5W)F*!;U=CUkQ7{V&7O@;ZJGYx_E z9Qys7m}Mh-y;f-(=l<iyZ1)$~j3dVvsS3M&w8H3zOm-MEqZZG2g^C>L$q7w5p6Nc- zUq4bRA%|!V)H<IyxnCwn3HJIAY=yG?MKxIC1viPM%*)|EVXSm*tLe-fhuppB9W2%` zG<tbfaeNr#m?d*!(@{1F+f>2p<yp`{-rkB_Lw|AE9IJ%a*3iXIR$k0wMt|YsFH97G zbu`QB2C7QG^$HD&r1cZi&U7d}Spu8e65*<c&coImNu<53QKY3qFfES2l8yl%I)(+! zuuNpEn;{7ccg*Q`0|M3j%_bjI54U}({p<5OQ0S`R_!a*V_@tM=VZg!y!t}VqK_C9I z(Uoh6`kPhGJbfx~^WoCM9M1}Gp`OK)v8u?5j^T_Yw3~|W+HcA|i#=iOcFyV;**z&0 z6g=y3|3d4pv|TN0H|0F4yC}D}x+u4)sSxUREd|-mF9Dm=y`YBbG|t|?{><24R{z}K zHd$8>kzCUGvZSx<2Dtd)(f-8h_>UIFb*tk`tB7`oKuaK`2K~XW4wwxb!2~}x-Tqw4 ze>Cs}f(65n%5@;QKTG<`<F6PASBiZfL=ZG36YB^trY0CEkIp2gc9m76Lxu4wQRt2z zrF|c5S`P0&(WXIksLiCLJ@5PsY@G+G38j$FBri>Fyh)1@O)n%V(oh-3{tNZ*8$|Am z0%g@B!R}vjeR+O<6{H=?ZlsXm{RR7niS%3R=UcYlKwyIoWgZpgCvC$uW7e@+TO3f# zCF=}(aU2=6_$mAf!PR3{)|pLMD4|1@%WU(_Q4jscAKEEBGt8LO#IP@Q&^g1RF45kQ z55D6-Q?AqlL|_i6mrJG7JW>yK8eG<N|5DfYt$j3%^)2^zK2Ze>+~C{I81!w;J;$2m z_HE=Kvy)>v_T0a+Tj+>c50UBC7dn5**85uMM*xDLJ;`<+i)b#a^m=o6b<q;lr-<fF zIn0a^FH#%LPE`fVs9zT8(q3a9zsk#{+XkH6YVX1GSaNmHewg?usEC$*flpUFz}tS3 z-`8Qh6><gtHZSooXP;8X>u-g>tab{!*?8YxVgUdIfmaRS-&yzHivI?>`Cw&A+ezsq zS~q<Bue&9b=LcqWecnBMuJ5yMhlx{QG}Y+1TqeLGe7|w?d6phEu^Z!Y0e|L=`HyD9 zpYWCZ+>`S2RN_j4TR(Lt{mj+$CGAhRoJ2pZhTkOg75b%GfI=F6b~OPh>_JHvISxe{ z*J$LP#Rq`hYG-6Sbw@_q+!DI5iE>(k)&Y#6R9A^9to}xxMX^dAbcsyOplJ`^jv2JV zA-0$a25kB}ui}xoS}}h_CMY`gp!V(|Wv>{t+%H`JK+!p#epQ8EasmK<W%>SA>iZBR zesGXQ)`7#6F|wJJF}{9zF3ds10I*c*c?Eho1>Hz%*MmF^HW&)?jrumR(_LEl1w33b z+~Tnl1m0DXofL!)f5KNy7?f^FcW!^F;I~^1mxDy?+T2SgGL)(4KyClwHXZ;>bNwc) zHRwnOZ3Ur4#i601Lh_g5py!|Vvi-(WeTBeP5VWmgD<c{>;AF_|Qk#n!jxV(#ro<BN z5|p+a_-hf-XnT9tB74rt&*XpGXE!3J9`;}Kbt)MVcb#p<n}C}Agam{A^sNSCE$9z! zFps7KY+%)gIt9fSRQm@PMMWv^&U6dTY7d>bUuE~QbI%qw6-N17QwRip9Ef)h@qV_& z;nVtuH#r<HNq2v;2mA5v>}pC<`%k^opY~gXpEiWx*_P932QHGKO`0Hqf!kOvYt2Yq z72OxR@6Wh$u9o{Q{6|+S;>!VF@RE^08-@iF%i69$hd!EWz2Gcy<8n+N>)}|O^69~R z6oFC93&$ohMO&)y$Ip*c9*yRQhzFkKkdX%tuTXjUN=2z?Wj1IcEqT^En;(Dy<A=)W zV%_p%a>c93-|yKG8qb=I7r4whkqf^Dd|ng2!`&~{aDRN8VpAX*s=l;b-`m55+rmm5 zOZ@btd?`3V1|><vdQ(jv$O?UTCfg^e?>vEsjF10tszs0b{mBPFbLOZ~KbGk2m_TdD zla`xW&%#BNtXOt7dnG-!&tb~5=AN01!pw@BX<-Ex4iFvI(O?hB9276C)<<HR3Z^>W z0sLLp?w?!K|G47<D;c#eOxewba+=x8x#G$B29i#0^kA&GB=5R#|JIxQnP>UAFtj9F zb#eWkOvq<`<-_g>`skx(cL1l(PCIC*udj6B7v24yrVyxea!=yNfn6{J?Wda!?jYih zYZm`pxSn`{+R*~}rvfqzU18$&Z8dMi?}Z@v#g?DBpFgHu?oXrzaVtQ_SNG6%z2BX| z*h5IpB?+H9cHp+R&PAJGK2?7VM|Xmw5vxUM+jafhxyVbu&=o2FLm)VXws6X+BIo-1 zICc`}&~-~7H(}4H|E9e_7c6{nYdcy|BdtO+@ixi$#`|w9T+Y^S@qY^X`0ex`Y5$8y zI}H9<`{!@2zmxEbQ6C$R9Yj&f{Rg_28-hQee>nn88yyji?N%AYdrUDc<|FjS;Ka<s zOz2^qZhGWQclJQ%RnESB4Fv%FiwEf#tFr@U3z;6;&&)4ibiN-G0}DG^w(v<<zUKBY z2>XK1MFRh5UR!)+EclyH{>?!<zGA=;cU)HK0rGK!J`Zs@#&Lyko=pD6%)cqDE46+B zFU`>}v48OSvtxDtV6~q~gHDKXo_D}_8m5|S(ubHbXk3qJD+7*!{vLKPP2;!f|3zgh zmZuVC>c!NIe`7UCxM~QXqpP(TJ-*+|8;8vjb+bXg57FuVvdf*trYmps{>9E3!pAgU z$@6219iKF6grqA=)6IvhZKLJT3J6mItpnPy_r6K((l-4T|ED0(XQavBq5Ur^!SB@m zFE&1<f&sP;w_QFzyBmu)%Ki7uT$*3M$Nu^_=<CN4Ig_S7^G;Guj)TyMwzGy?fC=l# z9_Ll(A-L2CagM|tD+;zlVPM*1GKrcam2elQ`fE~z10!JJ=sOi&#hlWnhbgOrm{a7b z0+u>EmmL0!Q%{sZpZNkg`%Ub2SaY?-k%x7l8Cd!1x!=TS+4<PZK}O7Sgm%5<=5+CH z*90qaQLv<%dHhVdoaTb#C0E!&pYGZOTWsamtK-99QJ)>L|046;-|5hQtLM2uzc#=L zdI<+{4RHNB_${z&5FdYc;PY<^Ai^Uc-Mx7Snf4ytLzMe8^bCyL8jo?^@$d<l`1pB~ z35kLQia@_R0QyY=0N5?S2Y|t5@%}bpxrV(}RPO@{zb4G|p_UbU!)RXohb~?V)tO14 zmvhmskZib$!j5S;8L8Uh<_TLc9K+g1&9sfg+L@No9{`N=%)WcN-8`J_gh9X#?M*X< zGmOap!z0g+xo~eWyuiI}VZbBf|6)*OHU>KeI~w%=JI|Z`(V<NXoD1apO%}R~w$;;` zp4!Dz6elZa3lWlsu^CzqU-yew)a_Jncdo^W<g&j-l4CM4Fg~An{l+4~^qry48~8pF zu0)@6jD`^cXVe?4q`Tg(ip1Vx!wQElu+w|rFiPj+fd0g)zi6G$69L-|M(^|Zp!=Ea zSUw2W_762PguD`^Qs+>kpYAmm`8beGJE-~Y^gNH3-!q50dmFKweh!P@c(nX+?nLKf zF=d>L&@z`1GdNkI9D=nQ9@_fHY8sL+eXAbVV@e|Pzj<YI!hC_ZhkiQFRO&A`%cM4{ z94L^gLJxc|v}3+++aMPkN>bqP;Cxf^_00Qh;$H9@MAib=q{A~vh0F$J1(a$~vI~u= zjpO3rTJ0Z_o5t|rK%-adiF=$**pEc=a$b+y(Gd_3)J08I==JAC_CN1~>ScIzn#(!{ zQ#CH=O{v{a@G|MS=7^%=gjJvCCS-9+o$!<97+)?oF7%x>l;epB28^and3~NUP6R|m zBC5gWrp|1J-p+RR`<c06I^9R-4^y)oEVod+>>albWPq_ru#f!^mG3ITa&Tb-RnW5D z+{QAi8b#abf{FD)e_Cst+&P(6+FLX{|Mn%(<8I^O3PMOlU3N0js=EU>qAse8yP8Kj zROuGq(*?EF#?WNYxbtYS6-;O=<oUHyHdC-6*!0H4Kf{g^#Jy#Ql2`Cd5f@&iom}Fy zzM3$fhjb5h0DfM-CkF{tIu8$Nt^MhMxT&r@UI8B)=NzdkMyd1^UPsRBk?~A=>OGui zZgFM%Y^;OwxVu!CFRR{dQ^bjkdJqhkPL8n`o5Hd;i<l%BsR)L?DVHlNq=*w+3uJJC zDG6c)?^-nB!u3QDvGD;CS`fiL5*RJ5!d77+GSJ{+#k3-*^^t-Ja}F+L_Q=1fc|%Ak zz&2ufaUlNmFk#VlS+mu{ab3=%kqMhW!>NlXPPv;tb8y3IWBPF{RVwF#28b{u8*kWa z+7i>n%E^9FN!xrSpJJOsRAI`+z9$t@3C|r>7^99rhw#W&!f|?A_OqVGL80zOkj=(k zkHTYegQ!XO(S~5qIT2zg+Mp_WQ@&{wM=HLlxjKkyCt8=;_ujxyQInFW@?CJGUvx;u z#E_U}r@6p_v7r%fqP$y<@P4XwOii{8FYYeFWDPA@Cc9))@R{UX<Bq3urukxvq>ojg zo+i7!CLnoUYDPU_BmLb{NjlARCg{&|GZYYTq2?w%U@+K1hK!Z3zfgl=nRcS*Q^Y2b zVxCoK2A&Ir`m&4UJn?7L4raffK$%0FKz^F#<zIp=spk=NBVL_jpBD*_`p!JOJ@9>% zWxEe`K^$C8wjY9uw{%PdMr#Y6ILzHA$6?xdL@092sL)>cO9!2TehoXiCM3nKX!4!| zrigEx^^7cX{Z8m~>lk%n%x@Ln6KK}t&`^ZEF4$5~Ql9j*Qq~pyy<?-!(4s_5e3ou? zb^J9(k8EKnQkL5znonCJ4{w~pR5mwQj{3JBIf1u8*o{9dqE#X-FVg0DF7<3`RG}@> zf6IetJ7RAa+u2k5rT5$k;>(7f$rDk-c1<B(iUKJ35o8y?7e<MQG>c@w$32<qO4w;$ zqvISm#yi%`@0c?PJ*)O^VZ>|oBYTPngoIY$o3T(tJ9{CO!lAaQVT#xGo=3gXcf|Px zf>s@Ti~~hD2N~U+w;I+>BCuHTS(&3Hiuba@9jCzkWLPq)Py`r7St4jqQ>RsP&>mtw zi<~mkw!nFGh_RIIG1AIMlpAjmhp6(Zl>KPracZM!8^uX#M{Y5x{<L{&k<4iMy$<{A z^*1#tlCP4``AyA5q)A?<*0qFt#oJ*7^qI=TQt}#`sXk(SAv|B;Ad>H`e>C{2T2QhR zZbi#sq>3Rsp999u8gbaAt?4Q9i_ncNZH3TiEeHvZD#aV^>Uz6}S}%&V@Ha)-6DN&` zD!}|B+xV?Q?(qaz%h}RrTW+7W#yv0Z)$_<4DWN6@DdLk9Bc8$1;R(Fn#OsSX(N82x z{T$TYP+I&djq^}#F)&bk_o6sf3aANLXPh5#7kEK7kUPA{%TCfL%NJFOOi}ArnQCsk z$Ao{aE82dN3l^wMVZ(@wTrmon;G)and(hNLP7{~qEKs#wCDtqE^nOsuS8_DR%OCX9 zGMU)W&Kqz1+zP!z1pRPo;!*nHSenR}<OYx3LVAmJW7Mdp1Z2vFH|?{|<grl&w<l>9 zZf-~3^suGu^fTwhZ(&ksf4n|zOC14HVCH?z>U|1OK_hw3oeVnemo^#ti(IVny<C0^ zROP>xPz!Z{Vd3Svl#dp)eR$KmAdZeyRYK~<v~MExX*IjVvdL(t?t#cFMQEWScCnK( z^+olYQ2x2*q!yzGf^p`$lX&rhY*6jeQ@HKLXcV9}r7E_%oAl^yH_?R7`f!SnA?NzG zb_WI^h#Wcz1#Xn}RT!(SQzZ+94Xh$2_XTKA<64(9B1GFN;R*9^W*a5lmKp8GF+o$2 z7Y#KX<q4NjPa>Lx%z4XecVE@DG&+D2V_SyQ15@~>@DO6z5DND&--N7?BLN{0zh2TH zjmk#5CC3A31GDx}Jo+$1*gD75e&IF|c6eoepDTTNURvs5RTf^U!r4ZyjIqVkkv67G zj3j<Zn-BIZ#$IkfBvFgYq_+Pw5@j^ag!-JA<gGx^I(Hz+YK)(sIQ;~Vh?-%kLp;A0 zB3ZB?FZ=@L4ILhT-f1Z&5qVxhyQzwv_UIw~zGkB`8s_Sd$x&+<mG9Pzw_>i#MR{bg zLFTwIjG;;TBuNO)hY5a5cBkn<&zji7E7|x7`1>sE@_n;w=Lf2twOZf2QKJX_%D}Q@ zlJ5yF0(xrDlA^h;3_*IMpdX8oRO5CDrtdD%^y*{1UJG&FbQT43FKGe^(DI8OfkRRk z@NkQbf_>30)*&~~cmAYJr6i++>IG<d#haA$((*&5ETAyc!|b{(7P|a=q)HXPRjleT z;QIbsA&2(FvW~Zu^X)#INE7!7fmD>OGYQkFQMzw3nQSodNC#^l)R6l}O2_WmzMq*K z%vX;vZ4HnKWVx}T;xdM9S>0=+efB1o>y>ytPXv`%`{;QzN_kl~2Q~pqs78m8m|<kt ziWq6A$#&jWKw5&Vo3Tvy!zF!1XwRNv(E`Fj>%7Z^_k5pBj1~)`%+b*2kEGO<w_RGx zESK}IqZvY%P6@rI9}eNS`Z(R)Al|+c<^qSSLt9SLhUwK<3=u)9R3HpM=84iD*N&mm z)#^Hu!s9FS?q+sX%(S}w#0#(J?5(iF*c|9j-TK<Hamb|TC_bMRe35mrIfrEF^DqLQ zYsn4b1Axi+o#6*S#Fa{*%$SF~Eoz-w;}l3lkw@wYHTUB1>2=3b@Z&exMO*OjeRR|) zCi{4zb1d4iEX-Kmo3>akX_H5n;`oR5?VjmGa!wFF+YMEGPrN`-a_%}o7*sB-ajp~T z=5yRZ@d1ESF08#3s=$Rtm^AN7E6UXlihv5iwF&DVC;gvFL4E;z`(A%hb8M1fe_Us? zFxpWyaCW`jDHm%y&+f<I%UL<dJ&{N4iIN`xuO#}QZSA#7nz0g5H+S0gJ=xf4Cf)@8 z5BWcV{BJP)<%!_-0br?Y+AbH)xDQuUFIc||zsNi}!y}zR5*nr8@Z6H)h-SVcv|eZr zU&w#04F6cXd?A;Balwqfgf|H>M5ojvf9?>)@BQn1v}Wpt;5|CLdS~ecVpNY9d3eap z>N1-AX)&SF0a?%5(@y$lO2JaEB_i6hY@!quQwAm}Z8jky2ztmw&8R0qUkV>P-}Qt* zyO~?7Yt*T4b5w#UX;?N^WJ#SA%-X!UGZ~&OLXaVqo?*!2OOU}T7Va&B7lY)Pn}=;~ zEbu(E3J!fj)u$uW&v0;)n1x7Lma&jgqVyA=0kr#VIzx9dJLrgT0`OR?aG3WX>oV_R z^C%M|VHmc{37JmD2}t#>KC&A$BxF<8YIefLqoc)JOONw05GqVU^^t}Ehrh`wwn8}_ zMr55G#Msq`7AC?IoF)>;wm89Rz%!aEf|XZn2(ggHa8V<HZa5YxUiwZp?G_U@eC~=U zKJy@+h<}0Nt&jO`e`GzAk2FNgmsfTaj;SnzP?%06_<25GIE$jrAWXYk-*LnC?Sb$` z%0X5SV1U}Gj}MS&K2qAaKwiwh0yhrUD0cw;P&qm+vi*6VV{hlW@~DF!$fAJ-4*5kc z6m+0oM=fZeRW2?uuCz)p?XK6wdPbwi(^_mF4%8{Wu;vAp1z?s;_^5{6nQHYb)3z<| zY}6ER<eLZ*=_z>AYm;T!aZn<4+Zj5Bq_S0Oyv(DK#V&x^Dvz~$8&Nk*ha|&=mDFUS zgG`lW+y3buktHypU61ZvqzP|*_#xFrDzFU>w<5xV)76a<Vbq&842q&XAyy3w1<e+3 zjAl!E`ne*<GWE`p9yyu?6KY=d5pI+1qeI+C7aI6CFLQNdlpaYhc%D6~%1_T_9!Ttc z4McterFYmyDei<QFC5nq#_=MokPI!qll)Per2PmB<C*=oLX87iKCr`RK;9gW&E(S{ zYQK>hI0vC6v~%G>17STzXHRB)k4`}E4R?B8F26DjP3*N|M+i59#SBEc96ekSEgh4w z!*|@CQa}|O+7Z$C4p%FwEXm~O<m5*5%I8TX?7pY#Y%flD5y<n5aC2Z)(eaA?pHwpi zORa8dFUrEkudqLGKxC$wM?zg&)n|~$#-<A*8aPHfPs}Ebi63hBBK5Iw>l^>rsfjTO zt2-O}`_Bd6K0}+^M&YBv(Ju^wbu~>+oSaOcEPKtDnM0wb#(A+wSi@QsKcA><Xw*lV zoWrloIPwhO{VajZsT?6nQ<I3hD}W(fmVUK;rq&}%U!EcUk(h{bNvDBPh}=k-85AL+ zF$I}gyH)}WVO|I7ke?NS`}}?{$APy-L&}tc{s%y&-0i+`L<neQ5=teLSFgH*ZVChW zwQ>7k-B>gz8l>V$8nh;$(VNq&MaiBE4lN_<CJJ&DRz~jL8hK=mlqU%+><+<mW`69< zi$_kv+j5;`gB)2lzjDi;XsT;Ca6jN)EuW!qgbL7?ej(<D1wO6Dite5Hio{M4)xvyZ z2pc-GEu;8y!XeFIJjmdX$IA>_ilwueyQ7_xy$mjxETZo+gk#|KkV`Uoy@%sLUBlc5 z-zTZEA*IbhB}y~Vl1nhW7)zupUOD?fOSBQq!cO#Ycxlx<973O1?}5hLnxN^@{LQrp zt;s?5+d{PQ6us%kce=KSx}L+w;H<2piSbrE$33rZ!-}Xsj#e#m(Wx?yLmu$1A{|Fo zq(%k$FTOgSS)$fbm5oIAJy4p-td~sPCZH0Fn~p8uP#hkdSA@Dt#o1CetYKDZ9w`+p z|H`vRRgaVnBLG?2G;MnHL8~5L5MQOZGOw+fjL}F&O%RQb4$XSJD|@@qV<y$v_%z%n zco=tWqQhHT>OBm1VY^fmMpje8TSUESak}y}CzRj8(}-4gp5`JG`Zw(rbV5U<ysXJH zh6_`x)w_69Jetwr_f(;_$}4!W%sY?F*O_d#x<IV8Cw3kyhP36;%t(973b##^TvvYe zOivYmTd$EJmPb#XAkmU#_L79AjTAKrRd)0fli^KX9FC&mwaRztj7#mcF%P?$fu?xa z@FHoE%}1~*I{g{sxUNqm7*tKM^)P};H-MxCT5O>##>O^Wm6P3(3K_YwwyO^3qkC9+ z(LP@OOE$sT7y-1r8^LFN1<wczRP79_f>6K<tTQ5o9qs54(shnx!`5=OThls>=5n`~ zq!OA)k+Urpb*!-J$aOm6ycP`&*Ziv6c8?{>WJDRtspiEZq7<5oE9MZ9YVrzmfLaRO z)MT5<jYe1y;%e2i16Jr%kScq6$byb`hzRL!MPjgR&?poVDiH|joaq-cNX~Lq-jQZ% zlVqd4d?jbyW+m8>O|vE4h0!I!-3Cdprn>61SeAIcttmAmRMf0Vx2;!={XPJOEF%%= zvQoSX*R<t}n}Hh^FQ{Jz?k^7pj4)0Gunz240h9DMUdptw!dAv>E?1hEW?{*bn-%X9 zzZ{*k8Co*CL9f5AC+yUjnNmejL#0f!>tlvw8=+vL%y8r6p~Z`!e6IunhVI@<o9Kg? zYQ0qVw7hv|hD|)N)$S@cRqT2h@%tn6gi@K73xf;A^7%dt%nJ}3##&KWp>-x=Iqhj- ztIWeTSY<wzAWxxAn{wGaA(oCkrD$;!zbYP7Xs*UUeDwq(3}t1RC1IPI!K?U9{fX1v z{9cL2;+2LBh$gjbJBDr3hAIUPbfS>a{vE|7nQKy5tL?lhZJD|?qNFwSjW-`CWJSPd zO;~uv>-KqOCK6Ov(W+)-KB2v~*kSfGP)kmVpk2ifwg`w$5MxX)Sn+~vGzD!;ru3Y@ zCx$kbnkT#HcCptJi?U3g+lZFv0azW>rOo;e6eN*&Bhbc+F*PT1+9`A}baI$!(d{>$ z+lW<d2omPe^CTYVIFnH6rU#0{KubSpFbrxng75Ya<J1eqGi_EZmuL^}gDHI!vV8x* zN4zOri2})j439(Le1vhRAc@?VXG)%|zquDamT;I~FCZoxrY&?0J&v9vqSG({S7b>f zG(9GR2VAU<kxf!*EL@bZ)#xz5_c)KelU(~QV%Q7;C7&J-w3e%mTzpC3wBjDBiQFSR z890$Jyhx1TgeX<)Sd7P$5!%Mm(FVGQ_>56H_a`&u7lM-*agxNb?w_tgiiA5O=or%B z^GZ~;2g}M)wZ6ND7g(Uk>U}r7m9Sz_Bu*0Rey_=`(g6`fD+-FW$pEzM5F_9O!bs0O z+Afe@oebk!6e-9)%_*p{3ak<aJ1%Tc!Ed(}?I|9a5ta2qBgsh)V=z$eyBBBEf@qpQ zl2OXSv+0<%ES!^P+4i7ZB<&e)R$xspA-$RpA_XNGD?RNQhwpX03DP~1#WI~~f`l7d ziH`)5Ww^+UfsvP@uP2F6IC!dg11}28zs@{dKSBDyk|a_{?STw(O-6s_^aBg2_F$oL z1D>%>l06uRHxBok2Qi6al7wC`_zOE`zF5f~q3kp|niq1du1<+cr81cq-j#x{DmqgI zRAvRJHN!FrDW(sL({6xX0i_RAA>`(`on!dB=8cybY~o62Qsk2cS7xXAWmdIMMBQDp zF~_sB30r&r`d&Bl_#`2^ZbAVE<=8?#((#$4lK+X?urMk7G`|4nwC6;kEs_ilGZRHy zt}D97HfigI&mH_nl;Ko-uZ(<Ll%6X`+_Z4Z1(JmlRYR+P0O;-xx#r$dVG;0wiSQWm z&a+tX@pXNX;&$5d^7FHCT25DcSJ9EJ3@HSgsQWl3rnRCV<VN(UQKs*?{9Rc|j&}p> zYXd@|`?PaL9a$<FVIxP1oJreY%?w&ZX*m~#^irX)F*o4wSp-#{hUP{}gy)_|`x)B3 zm}Yq>eIc%6@<c?orJe*&wv@2o+B92q7aAJ8O6QxMg}LM&)JcRT^3_MTN=L{ncF}hu zDfPNo%n|p}*~NrIummzK39}!QB3Js90t089XrmA^fyXcd+@wRn5z`8oC%KP-q4*X0 zetwU)!-3)OcZ-juaR@m&hkRpw$DRn|ky3{|5)GdoH%Y_4&{J<2>*lU1^kJYt@<WR# zG8}<mh=?`TXt$TmFDEBb#^R51)Kf-S*R7Wg?RYe(5~XT%7V!a4rh9w5fd7SdT9rq( zjdS0mq&TL6e_NdkEy<l-?!Xv2?fbcL5yLgu^u~;64wDY6mDQH@I(o|8=nq&Rn<}gH zT0Jp%9vMoJB>2nZWoL#6Zv)L0k)e@&$$*3?(6yc$GuggN`{Z|uL4O<;!_Y1%S8UJ2 z)=FV(V4AtqW-rxifoS{s4S`aB@5(6(B<kK)G{N;QBut5d#V82O%HiD+bwgOb*icK; zvbZu>!RHXm){1Y-&+ZdQ2&@j^@@siSkeOt`DAb6O;k?VO6-g5;t1|WE&x^J&R?hYF z6AeEYLx0S;5kN`BxZlU+w_iJ)P1$bYF~*?sIEz6Bp=TUO*d~S=G&+h|UQ9%gLuu59 z7DZ~+-#I6hs+~i67}OK#^PmduRcjvdJKQ~)>3rtw7y0%`p?IMucV!8mCOxN68I-it z=@9CG^Dy!tf<#!=2#aA2x7`kD!IKH!P`UB{vG>+dZ8lxsXz$)Nym-+T2@(R7;9i^r z4{pU>gBFV1#a)7XkpRKnrMN?};80wPw?L7e+|Toz@4Vkx?>XzN_j~?0>s#--vSwwH zYbN`e?7e62*}vJ-<jIxH=q!gKi_)0UYQu&QLVP0EKi`|a8eClQqKJoEyA4Lt0uJp* zOCyb8Z>s4PtyV1NK$V%c64V!oHHP+D8!Nhev+mP~?~Fa%h%v*vl&1x~N|{GNJQrnU z$+LkK?NRUGi>6_j-g*Vqv=zgkj!)ASmJ#*pOud2hx$4Gdr)o?lEoVZW+R;ZJDl!ri z`vxf#sbB`$IbL`AStq9sBn|XBxx4GD?;OX6?1H`i;L~zy*M>jZ5PfVvaJE;qY|HK* zt)7T{Y+Cl2OrRK2UK`X$(o~_XuPv^p`IBIAR(np6tfd9rprrdQ8<S8|3ld6+y^mdf zIYjE=JWh02Mim<)<y=4$T_DI$S`#lk?P?(i7&?MA4DbLcCQW{{J^<%3OntNs26tsL zxQZB<rm)PiUJdNXhKj7j|Ggv%dvEnRjgtDpL#8*xd;#K><`HKwkRBGx<WOR7%um@{ z&T5-46h@-u{{3A7kvSWsOTfKXRuYxF3muoCnZ`EjyEJ_pjg~&`Q5ST42}*TSd$hm< z$G#H|e{!fy;?9v!a~>DZ5g{#bCY?CbJ9Yo@aNsCgdM>+@p~cbkWtn?;M781&Foks= z``YIFoBrY?nu82^u6?Ae8?2(7v&DmGEHLTKJlTaABp5dRmRXZuIjl5+{Ivo;Dq?@q zR72;@OM~=Zw=5HLu4W|}%W|5}x)*kLXLR~Pne;iT?%5?@`+>~SCDcgBUk4OfgmWAP zwZL(y(K{9}pkM+}8!Si&ecMqR3?`AC&u<Euk$W@l*dLK6yh5r}#%H@*PoF$aqBj)P zjz3PULC|Z!rZ?nX-c?nbBtHW){WICkqnh%tg1wYc(`_=pt>LxJmN+*}J(FRQ*+;^C z_wTj-VvIv)D`tS2VBv!O3Uc|vSHLqPFG^ARc|+Wt&l7-lJL{ARLiTXOfT8o$I)m<L z$Iwl%&JhI31>!Zb@!~W&-S7cgX;y1AQ2TKRDG3#R)ks*EkxC)nC=dH;BBQ5|=$<uh zbMZ;=9YV)ZR0{n<1Ljo9EU6d9XZl0Jz7}*UI21}pro~&xOGpn`z6+h@kcu*kDOYgm zaQDs~Do<fDw8x&yl{jQID2vA3l`C)v)KK)W*HJfgkxS7hpI&)WoQ0E@V8q9LdAa91 ze@3iVjF<(G^F`;f$n*^jMG_XW00u&hl{+>v43Nb~3GdUMs4|R2MERM^sLfa74J;yh zF6&?TUKd(gTDqUlj1HC<)~)9GB-PBci~z4Ei}ZB*q^;xZwnXLZ?T6y-Z!H{Xc2xh# z5jYLQZnFv|ziflV?$o)txy3{Bq`1oRMSgq_Bm!l`lP+OXS?UU=cyiI2ggGD8Fkx#v zr-w9`+IEFcE`KD~KTK`Ou-&m|YAf+NW6&RrJA;&Y|JdDHq~=w2TgM_c<9r=V$V<FI z4@xCgV=5`+L4=c8xGna78_xiDu$#<D#0r7DDYz!Fp?M0Hl18$kV91zZX4n*<9Nx0m zk-aZIVL#*>o!<FS>OdtsS@++?|BuGN|5xxNPcZwBoK=H{knI$fLI-?BF{hR$8|<Ks ziJ^wLDWV|XoA_5X4tQf;EWaO_y1l+J`sj62=cV@G;P2`1>*Mc7I3S_(X8rFf&iHkk z3Ot-A?47FqCnCHRmFcsnktEN*q!aI~@)kaLnIAAP^Y_dbOEQ1ChTHbDJALl)XRjV$ z%^fU}`wEZna4cU8`l+ti2dG)+-i}c0)6GLfil4VXf6z{f_R(T3*=mrs^uf~j8SZ48 z-<QDZ6D4dYnxZ<AQa7M;C><96I*qRBNdIeLO$A$p_RJUHbahPwDxz2Z;#=gzSpIPA zh243A5owzX?o2>YJ>O4KUSL@QtF1Iej94KdJ!5JK<DhNf*iJZlf1lhGHq%H2N1__p zJ5~JG^~QO~AT_XXgWmI&^mBK~m<FmN#SA_Mf$f$QibUzS%>xtETVx-YmGBS*U@)U$ zEWa1<c!JhrHZ)X9r{qsrRQ>)$kZY?aiBLN2@zRgy4;S5?365aSx#K@UEw|-0<M!Up zbNcZS8<lH=x*4-#)LN~R!-LK&7Jq1Iq>A$3WI%A0?4As;ttJ5{UWbP?dLX}yGi)3R zI*#_jN!J7#*Zep`>c=zX&T)wzf1^nv!&7>^GbQa+Zk)RPu?DF-{q?Kfw#S+34o$d* z&}FIa2W5V^fzuQjf8b<pp+ik35Xs9{SCm)ew=)!`B%l9<1%f-D{W@&52Y#T<z#bkM zb$NnsJ<~uoBb0*=5K&DX<Fec{uiCPgA~d{+^u5Zxw!_*C`e_s_9r)xsu-ZWL_6CRB zyQn8(&Rb9y|0(Wg;BdkSe(!-J%UV33&GRX8j&f?C$9qVn&!f4-2|vS^cQ?Z{YO*~1 z?b(0Ywg(MgCCmctM;Q;>Rj$t?HOHt?M8x5yJg3c|GmusuIz(|ug9lM@M2Hu<R|R~+ zGaGfpOxswY(L!xS<^6L=E&5uFN>jvn+i0DaV3uPl^e$fl6E53!x^;<Dr<Xk1Nc_MC zZUTE(nClET#e6SvwL~>ijT(K}889F0z2NRGk!d9EM=6Od3qNrEi|_r^#jUik(W@># z8a2b{j6~{)xh%(NdI!>hkyz@$DsQ$re4a)?qv-WW_#Y$B$|?!z2B_U_;UiAdYu8Yr ztu7lN@W!%2ja@#Lf(yoKp{w1Sz*Ss2;F!&_t4;V8Xnzgy1MU^Ry$DB)0xuPEhP`CK z!#o2=VE3w9?VsDue*;$_p^<eBAR`Ygwx_#&jRyqxyTSfU%PNDX9?Vc%1+Q@$oQMqz zL4%B|4Ef%5p>gVNdbS>_K9-p>$(UgT&KZ-jJ(HNBTQ~R3$?#x7RokCe8h>oa9ZL~r z3ONy|-afOm>b>JgK8&-^D}7-?cp<z)m^0z0ECUF>Hu}}Oo;~WJti*+VT5su&W+4X~ zrr2Q?>!*3IJ<iyuvK+7nlQbTlC+LrOxZNobU!IM?PJTafU5F(rZ0n-}HH?&6>}1JB zJTXis40EIr4;}Ok<mTRh*9wk)tw__!WY+CTm6rKn_5l+f4pUozN%%32@DbAvyS|{M zF3adQ(jAJsL=nh)rNzpfekb@GH8?oZ8+%<{Tq2@OT(&++Pv6GXrWXzEWjR8<=_InG z?Ka!xd>c#H>Cz;^tII&0SS@59e!iB(&~vhw@I1IWPSxH5XJ}ldF^6^36`1u72J6R( z>#^LKF6}toCnJ8H@pP}bpYsp2+JoBX-;ajR&FCXix$@*eAq*Tfm(p8RItUl~`ZyVd zgbah*;$sPcmkt$_wU**<{ifX&p=bIZ!p=yaS=3LwUm{!}&&iNWdc8BZP5dTm%<iQ* z%^lOsQak}5U^yX$rtDLQ1LLT){tl&dYQ;pGRJDF6mM)%sa6P>~1yxvW0`ESX&A^I2 z-&#@UskFe>3HQ0Bz(qlxAR?;CYsQeHDciz&kd59|@Nvrz_^>*x$grkK?%CsW0hNaC z?M_7QjVb`e=frE>`pj2}u)dv%8(sKA{Vm>zvbTp_TlqiqHQNo}CjEUEd^e)SBUM+{ zR4GP+@ak2(RLrt+nZfOAJk5!?3Dq%wH$7Yovk?BxEF^nMKcA>B`iADWZE}8dKPb#i z5pxQS&CJZ6JxhPstD_}<sOGU0Z~iV9+!<F(>@Ub-=Ku5TY~2i(VzI+ZOUkb_?QCwn z&-|x;mI?Uxqbt$4Gr7y*Z${w+B;qnbtPuWrX4&a#b8b4dOjo?J%HEZ#>OMnZMNmE$ z)4-ds+bH?Z1CGpE9KMkyyY78n#^QBFUThBwDJfxV4W?0=({<g$+(h;+FJhZ|Bd9$# z+)a1qzX5kgC{@pButD*%el!nrS=;MZ-ywnB`(uaIe|hmrN0fRgHixXkkJdZE6EwYt zoGW$eGGY%Q>eXt&OACgYVy&!C7R1hYA5{NlhTElo%`3O97|DJB{4It%Y{|deiHSfK zKhVU0o3G~Tdlpoak-a6_5H^3t@g0M=#qno8q0<-Hi5z9E<prqjfVEn^Y7z64te=BB zQLao`5_EP}-+|FS6~c&Jb&gblDAOB)qFqrILtRgOh<XTTytkj(xy)FsTWyMf=|X5x zD&nixSf$Xn@-c5*uVHxX+GuXZ%z#liPX&=7oE9*jm1pG2Hng!S{uB+)9GKzCuij3y z%>EoSsur_VTg=GbPtbeNL+^ZU(BS?nF8Dts_^y~+Y)tjuKYk|@o;|P~ztetRT}&TH zpCiSx8ucCkYk}zBFnNO4gQa8DEbo<~yhaVKL;A8bie+MUd}GS5X>}fK7Hr@D#a0GD zk6IdNi71C`GO9b>Nv2qk!s))gAIZyv<>!PoT_zHawx1F1$CKl?-sMXl5H)`F_j1{w zPBzF(>*WXCbR4YrG7*P~Gc8LMLnp6xK$%hr?_uJ%z&tPsf@|uHTNn-fbNNsI^*01H z$<w`U^A;S;;g|obef^6RY7Ih)z&n+(0t8yx_kWGLfAuIfrT<OlLDz1(=;lH+_*ClW z>#y2Js@hF=n|Cw!kF7Rx&T!>xnB*NrKIl+ID@LGf`>izsA;Vt^0co6X3sBfF%^$KI zdj2__^F~j^P41ui^*#L<I~JRs^I7pu{eiB_jyZR;M(O(|$t2b;<=L~rYz7b99ecWZ zpqQq<7yz-BbgI>*8Fc;iYbAb;#HmIO0lVsCGX(@jQc!waS^}~k+X&vC&jQk(R#oDg z=Z6a231wSzo0<#0HE*R<IZwZ_dGMJq@gWoqy(GOQAw3r76SMXE#C@i69f}<{l1P{? z7pC@J-PwZC<m+0v?2zaN!&r`kc?Yic6`s!Mfdk_fQI^@$(xyNm>2Sqa?^vcPMUB~S za%_zxqcA)2F^xPKK7#i*+M^>}sU%g#&96D~0+mb7BcH_(UuOm9?Qs>m7z;btqeUZE z-~M8Sw>k36sH9j?#uBzO&zF2zEVJdAA+6R->?1XOi7aPPwyo=qRD#Z*J?ropC{^a* zl=GXNVUA?8t^oH+2i^0LsvgkIo6k>ba&S*Fs%|7I$vLh820nL%5{)+ukn{nuh>G+! zd5Ku(9Au=T-x-=EU*Uc=oh$1|x7R0+v|lN8S)ckgwM}D32={zHWLTu8_02YGaafj} zm4d*^<{*=-`TP?n^MEo!LGR&vWpYkSpo*1oa0PRsHNv7rNmfLKp3yaQvy-9+1OMqv zIpPd>UG;Fz?z10M8#(VdVA6^sxuh4@`K@yPb0z#{;0AS_JExMFuP9@xOQb&P^!Cn^ zWctDR5X78ziQrno9G>2~jh#N_;<Yi7*BBJ&BDeMre(1C43UwZ-rBT4oS1;S-Q4~|* z+bSN6X`CY`Wkabm<;`KmKl@|IX@c~=M+;n5c-(R<t<w~vAatOSehZ>YHq+Uv{+bab zXRDfQ*~-io0CW0!z{yUuV;LGBy*c=?7beCtOnM|R7wQ4kW7Mh+(rV=h*~n7YTsSPR zcq8s*oT{|m%vNHO$pp-u7|bg+i4!`!&UB%;?>}%uP_*A86{?7FXvR3q^`)c1jPh}9 zlJJHK2Y3j(Wj!}z`cVsTa1=U3X`dFDXs)5Ll9rJkOQd>yP#+}{-DXGces~T$)#K$} zzg4cdOO6PI`8C7KbVh3^s|B^b@4Bv*o}^}t2H1`x(jpAH_V#KT`Y5YXm!pPVD`#ix zDqArUcx-oCnl=VLgK2Q9{6R=%)NU$_Kjd3TNnh5BYRY&|Ke8%&48f*Z`D4uLWalH! zx6mW;w$mSZj)i6iw{ph5`Bh9}FiS|BQI}D*#QV*Q*bDX3nJ<RXQ93rYHRXMWx>E2v z*^h8{il_Dp2adV1K<xa6I#ZUG)=$w=CLuN#Qz=|c)2=OKx{SL0y(mHli>{+kV63b| zui5L-rMg7bZOb|(tr15Jr}nh#qB|LVccBh_qL-b7jFh->z2UGzp2Z70suyofN$knS zyLA;Ul@5p^BOj|IX&kSZkr}twAOBQQdUZcEHBZv5EPwfN_j|7QR9v=TctYHQxO0a3 zd$`tFo?_-IY)4gf*uY>_2opA+8WGU=HI%dw2=qXOnsgl7;e)L73I}RJf!GQJ%;2Jc zP)$t<M5mewlYR=Z>3C-2#^f4}Fd3`U2w+I~B3|o_f`EFS0$XO17FoP~KCO)!r#_nh zhH(UiCs3(7J8pt#>Kw+O;(nWNp?$`d6HVr@YB(pM<c3XM?jBG5iS-T*vaaM(P>Rbk zppwt4@N}w*d`qiICrH((NNW^xa`>bSgP@&a54(Ws;z*}?&P|;Fkh}j7uIAWOBiWb{ zJky^<Wj6B(0KXr&v|QqT!?B>U+Sa;AeEK$_oS{BG&{kp?OYHq!r-{$Y`_QY@E$v7G zM(|uHIQog>l8HzC80)1!*8fncp)_@-C1cI87W`v|3NeSQ(8N5bjgF?4C<W2PNKXin zT}>P}1n5tfEGuhnZsF+b$4obS{h?b;6L9ts0IRTnF90Sbv)9EMPi5x1O4-In5t$*U z-D@5C8j88_^?&t6k@TpWXS|RPb8w*%F{i_JE@2RSh=xQRSt&J&VdX^l_Xb(Y%4&K! zxV2pAwpI<J4iA5*i(SOF9gg3R9u7@^>khg)t>9!fXc<BLeiSh`qOxNA`%$CW(_6HN z2>l6Bh<<#tVvo{*8P}lRhfMKb_K3ftMx&wz57xOk{d%QQ%-BLHhL7pe3&uau5Kc4k z=y0i%AQf16FQ{~T!C<lHXQMyKyNKugy>Ns=u?t1CvWA^jKCFmHF?y^t<`0ju=~cG6 z<9@Lq7_mXNVpjl1b36)(2;iA7h;-m;Y@Z7uO^sBh*^)o_fkOFW4M|rDKUvt8{p@{a z?ldm>`0>-tv{hkdQ9oR2eA>0FH3a<LQ=je~JyVs{{wZxd@t(9#=QaM9PXf{07V%MI z2B|aMTn78xI?6QD)QIrzQu<h|8)n~=7<M{tl7%@Nn%(&*CFzQE7^T`uTPPzP>ot=f z>+eVGyyw$bI^y5wyD$tvuV-ddlk_1RYtw+WfU7~dlF|g0n2&koi9H4NN^z%9kDpGI zN)X&XiWDvAS0I{vh8v*Pqo)y!0$y+5{zLp*B^c2NL-fm0$^m2_Elt<Q;uL|4Ar`;u zujx56ugD6mMAwb27ER)EG4>^Ctum_sRDqW$QO`=wMI=!2VgDbTH7-7;(gV@)NQUR( zj1;HNJY$f_u@LIp^wyCit0z)DvH`_Yb<m6|xLWpVdA)C7|5X!8xL=bNHU9n=+gWW? zEPf$Cjj2bZrrp^IaQ3;<rGJqD>kQk5--wLvS*N74kQ^9^Oo~tZFiFpJyGCvFF&{@z zWx$jRgC!qQqpZkqP~v*i@i%jgDEZXgquCHsb5qrnu&8M0+eP%^*A1Yn(9oH;oz`NP zsQ^qZ$zrd{`r8*$SZYif<B>a(h(fR2oSPo1HK#RTz25`Q9SR9MPct;f_oRYbZbs_f zx&G6rSv5<m#gnt7NzXS{X>!3I0T)$7=2icV-KFtpM=zvK$EdgyD7g3UKus2}%kuIJ zJ}g~njan24)BKz-w&-nR9%hB%b>AZYVPgpVe#9$|Php|2FD7;IeyD068_>B{W$ZaG z{wE1IH5~p->L%-6Df7jcWGMSJEDh0XpFz_SqBvn`NhP1uO2yFWaclz8(33C8oN0g_ zlC(z!jk5Vb!-FqVv`&`B4T=I?Hj`lULTO`ii=jmj#qbE{@@+1FeFoooD#G5zTT>%s zQDI1kDJoHmcwBEv=JfBGm3DtXSqMHIlj*iuL?iI;tX%)Y$oi*-`o9@jH#QhMV)tKC zDe=!)$84u)k64@pb4<uLO`Qc+NXQOzJYO)oEJi2!Yy53yp5OncW+tt8Dz}0T96}3# zi{URS*g8ZtEBV53J+w*d*$QHW<Tw8<#l}kEl9WNVJ8r`U&F(%!3_{@FSopDFnM?yd z#*R}E71YU1$<Z*v|6K*y_uNKR`QMLTPE9E^C7@CTl1NAhaSg92h&@=-;=b89Acsq? zxq|3Cf1nH>RQr_jPvf5s`?TPqqr;{c+Z3xgLUxFS3wi><t`UxG8ssYA(4~=~gI|b1 zd_3Or03|i1Ipx1<q#F+GS8PHvgxFjXi$7(0fB(r}PZYCitI;$u;KyBJah-ZU(;q&6 z{%thq7$sj+r>6sBg6T_GXC;wQqhg7<3RMld?A%h%3ZU+wffOk?Ue>vIg3%3MXO8EQ z)whD5qL&onDLxpT>)gpR@s*?FqyGlTvAShgr~KxFeI9+&`M4e7v#n*j39|bh9WZcN z?bZulhiUiKz&D6v4*4ezK8~Z|UwkfT3l!Nk25d3PvB_(bYS76wWhUTlGXJjJiM=sF zxhYArewuc$THmrrw!tO;&p<#XeYZvQ(LOhuOR27xFnd%jpdrw$Dej`%&X+n#S)_kv z!Q+{IZ=#ud5ue3OdZth=9G(I3B)OU_LO0J>CFyV}rHc&>JFdM7Wa8ty8*brq*#WSV zU42~&go|<e4_4k~NEX$deQavgkEtglnq$Io*~+o;!)+RY(x$z$*Ww1?YN;S%JZuk# zJfdaN9B7KsU<z9i8zSw&-c;~L8u7`y^e)C#?<f6uPY#o`l=vLk!%hZ`7{GQref0dR zp{yZaH&Nx8mIG8meBU}rmRci8!$Enh(|SaLV_`Lnpsy1)HE2gKhS#tIWqB7y`h110 z^j6YyN@zvz3Sao(N!@V@bxDm)E!^~EexeI<^x^GPwpStIPSLwoAMD7g=b*OyR}(_t z7sT11<1j<2ZJZoEE2uA8=qaczNB&umnBo&qJ%+^V?Y0b<d0N}F#(t`0f2=Kp<R5J~ zq-_Y3<^3u^%%2tEJBLL=i`0&aSn&|1yOzD-@JD$IlZ{WW3s+|3$Dk%nk;S!=c(%nA z;Y<y#6C5D=JgM!4?~lKYO6{AdXwJV~XgY%a=~q4k^q`i85f@Q5xD{NyJ%WH*6k9aO zY>ntdM#=;nTA9yJf-xdSzO!&%Twdl;?t-jWmoXn{$9c&F(VH3#t1$z`{Q`o}F>YVy zxH$B`L-!clE`$1E8cCEI|6yFvv=-Agvl<J4_K;Clr(9+5wqc}spg}4zJwoHoc3~=E zw5OV}=3LjcUKg%L9p;jEe&R>cv?sY5OD3H}sbk4lw5+ehjjexNURdxY?Pb`SX^l^! zYt116c)ekNMi&A5T<n6ldFzB$iHeTJsmxxxj-+gG>_)H^(4Ova^qs3tC4scfnE7iR z9r_E~&Wx6M&G^3QGESWj7}+jSc_)50BQ|L|iX5dtzaL^J8(9<W%IPR{v|VKz1`kt( z+rSRlP3K4FW9KP+vo#6u#kG>T)|Qicc)#g_&M6os=c{`S<KrjS^u`scEA8SQsC!<5 z#TTx>b&0daMW|y^vT`IIR)27dQpoU+g;;LV#w&)sY8$lkklEVR^)L^mc#!emT0F11 zuOtz=O`1Q_>{UNj>Yt^%g&-7OhwT$($C6P%l4aIxM~(a{L1z07=~gtv04eW0DP`4` ztzq=9)CxgnhWK{wR7d@-Ep{&B#i0lfG`M6<YJp(yM<F|nH?M=_5(Z{%sSQ@)SxPyJ zcF<SRdRJUTTDUY=c&@2Coa7)F${f$+)|;SiK?X)WIZNA+CrjAsDyh^b_W+yHc!4+B zId+626nChSZv>4M6BiiA)~a&?66Q~%RDe>9BUgBhgMICp0?td}HdyoW3099?>;UfC zXdK{2Eb#UM-w(yzBYK@5xJpU;$U%ZZk7uG3^W#Fz*CVlz+8laPo~K++tk#t!=`=y% ze9p{F2ilqzbQZA>vF4P?M~a3;X{on}Gv5>4jziMKV_tu{t<ehe!rUK5QhcT@azH8D zQhFBcAmxWidrfgsLUO+08v9ZzT_U}x4H`>5{1)>Z<v}-jy_5)mZENzqIg3(Hy050Y zK}v=FwoFw(kDv{?_N(5Ukq*pyhJbjw)o`qwiT_7!68F&-Rg(;RwVImrOE0(?U3;k_ z`sF2ze(*>@FCpIc{od1po42;5=)RSx)X?{eLl($Y30M+ua*=?tB)l-a$%BVY&{0i3 zv6+ZEEs}Njc)L><o7j2hwWg6K;0S?M)THO;0BiFm9Y>XD4Mh)t6fO|5VhJaFvOx2y z$%TgPR@gXlN`iIo%p@@_s-d-IT5VDJ2bL6Jy2P@MkiBwPK}RSW0w_*!zgYVHh)`{H z6q(c<vD^`1OC&K;BCF5a8gEtXj_fPB9>iGvnZ8%@;S+qTUilkSiAaj{4w{n$@4@66 zNI_fJXlyw995tB##Xs)b#oV_w_n=hCN-lh`7{FFJ&f}OYlXYJBRxM5D9KSACq%5nE z(t711BeO*xf_eB5(Edi#Q1E?l4Qk;J@mCuIo&e|cm>FFP!e-WR#Zp%5=4IQK`)fOY zhY*Pw8G-72^PsTkYWk@kTDaha(Lw#>C6V)!Rc}{f${z~UN>jlfj=ZLrgpC{~mE&3D zKl+4blU@}^zSt1i9uS3SCj}4a<MWtUxX)!u5xMYZrO_%thxIr-Dc$>84weo7#gmdV zi(l)QnQeL*k&Dai7Ug-&=4e&_8I47cxlA{0!%NN)H?8GM+#!4VH3ZUqqvdW>cHdlg z4QTe1BJC%JL8^n6T+<$d!2fK9eH#-&o!aGb_k*SKIlMo!H0UrP1s`OZ7T3t$;5CN; z9Z@AChAC`j%ab`F$-B7#*WZsemi{77YS{47LPL|0ROO8cH4{RV<!y>A$Nl<O5RbZV zg&eYwsIUv>HDRv39WA~Ux54wL?L{u`$ngJb&Q7$;B8`<eujmk{ZqeR0j}<7y7CH~{ z0Bq&cLqUeAs+@B#3v%sv($UscO@}7^QJ{*Ji!f7*+scth*8E{z4i04G6_u%-qg>OZ z*5ylWYS!^4nZY5hcv|z@U5oZt!;2HmVoUin3TJHD9?~hZ^iq|;n!e$E;W%Brm$mB7 zHGjsqs2(j{3KFW(voSmLr}Jyte@6!4y)X<PwoegTcdld<7-<$FS_*z?=<^eETD9iy zM+tT}SAP9|*eYhL{(pHJps2A<FdnBkheiPX$7>gVj%&<P=enOw&IZr`305rKU;sZi zGq&Cm7sjaU8(ZqZF<A$k<Cg=@A;Lji%XBg8xSlV}nxtsDU;URqG(}5s=C=E}!zfJf z?f=WY{J#+4=cZY60K+WO^{O#R*=qkAN&n}M)_XN(NoM?hg#Y8uVw!gc&sBv!&ES7_ z|2J0r?-MK%yt*OO@<BeN(^51%T+>p|7Sc)+?z6S;W<&k#vhC}Nv>=cSHQi@EiWB3) zRA?LKm)3f5@J-Z(8c}2tl#?U#mv7hLPKds9kJ?!OicyAxz<wITee&GhYzS--S(ceX z694-V<;!4p>BNSRO&&`-W^<&I53V3;2Bg#2HB*-M`%yfW0*#2JzGRNKFjN1I|Bpgi zlNV7VL8)atm=pzgHK`M*;<H7*#EYR=!pl-6j|$*Zn#Q$l>x@cXJAmvQ0FQNkl455U zgWlxDIE*H%j29scVk&Q@3R7)j+)2`&op(<0Z>?QJn1Mv{MWy$8CLHu2Q>X#l#^5PR z{MR&*fLnai0^vo2Dcx%bV~=9ZvWxp(OkJ%mzy3usoqq{qJRwCIAryR&7ngIB<X=<r z`%!w;$(S>pt%GzyC+k2M!u0R%&7gdOffZCSsGdW8Jq4%tP$;4!{~<%(L$+VvnxCgW z!3hYbBwN%?POL}uPB5~Bzd$H;6uor0F`8e~>v}Cnb)dd=kmKnZ()m-Pr+*|UPY{lK zU5W}3N;N};&?X1kFWLQmR0D+Bg6a3RVq)Z7gvU}ye?O{4XYf-)u~PLip*@js5kbBo z%qF4wH{!U95@j7l>*ek~=yGL)j2r?pc|YNf+|zFsTJvr#NxYg@jZJRAQTIr`)0DmW zYDB3|_#pm@vH?L;Pql#O(J1^%Pm0*U`oiWz?WrlL`0@u=eCm-jrQzY!SSsf1Y2CUu z-D@sr&Rr+L1$($td4l!yvK$;=MK3ad$xnA8fR%92KKce?G5dzYMJt$*u88`lz)1P+ zP!UPCDIYBWz?3>s8vCT`d~`5*@v9G6*a@f!X{|>P@DRRkG}K5wX+g7HogxRqv~gaL zh%&vpY)u6!{Mq!K0nlF^fo)#?p#pe+7o66vzTRioPF)uII7F4y0wM(g9(TQ*_ltb| zSxQM~yc>S#y{(Yjwf9+nel%8`A(-~*@^$>F9`rWtd?9niQIHB$9c<=2_IPj6v4=J{ zw{eJ_fq~(#KHsf9II0R-thp_AA0|evFXX(j{h@S*=%r0Bmr!Xs1<`9|;XpOStNPBa z{T!4_cg6^j6|F7XeFjH#WG?!n7Cdrhsw?agButEI%J)-DK3gVBF|gBrjaLc~Ctch@ zwFx;~&Sg79aLYC@_VmHEPqsi~2RZm`hI`xQ0wmzSN`Wf4;s&YQPY^XDB-#IGZ&Ji1 z&AIV(mzzzz6nuT<4+M($3dtn1q_FS1_1M5OAEw}t;e|W4S1lopd)s|})G7Jm4?3YY z$$haHcUGasOWpy&#M;M7eIX9o?IOOw!+MTm+tA^BBfc#US4*{N*bqWt!HY~QHTX3c zL^h}5?7a1n%t_n@0#j2#3SuA11d0$BVG;w$n}v%nPbNh$f#(hXaK)Z14%YjUx8P+Y z1!31#U*$?(t<?Hp{g}MVx-RMFRkGvoduA-O^9~{5`&X;1vPe@B4~;mZaPB`UZP`)| zF?KNX(nR8pVAA+!R#vkf)N{5sO$e`)<Bw|Vo(Hx4hPTP{mg3cU1USDR>1NVKgue$I z7)5ZetQkFutIxI31J9C%V28(CyX};jDg-E|AP2pr9%$H=H;Gg`IdQ~UZ2^8|*O>5h z@t-|O2_Hrd1;MmQbo&I{Tzd~RxtD}#6cisY+KG&pR4%;RJyS49T04Y4LJg%8Oq0Y& zzM=SKUeTvzKgeROwJ4UvANrSwkgFCKpo>XiYD<(3qnMM6;NdJr!PRON<GQQHo@jK< zPAO3@hqZn5m5-bWo_R>k??)i1yAjiYzfW^TQ5P@@0s<k=Y2nixUOCCG-@<P~f=)&& zhpbtn_zHLyq#W$vmD8&){lR~o>?DIayru4h1eUc44PZ?*Gd58n%fFcahKsz{T&Osn z#pD|4Iyihr#ZUW%t74tIX~^vDUq9u4a9Ih=S?A2k{ih-K*booAvhOC@3TpHvtLhvk zO$HwYoJMO;&)^D-4bncx#Ah{-3eFy=7guVU=w0g-d)3Gk(s)uyjQpXNM<sokfKVGS zK@5ED%LQ7fs7$ipN{x5Dny>87Lo@twj}#v1F<MISxdYuHi&KN?H=vpuvHPme{=9{H zB09gPd3}h!HD&pq>B{{l6d*RFWOvZ2_<xM^+t-WgZEd{wjXWRpd257O<dRArN)Gf$ zBed4mL^d*qHWT&J2qW*R|JFTRjpz8w!p`5jt+q2U25)RQMOqH=H3X`%-aE0^RH45= zqbPr?`Pw$`_am_rUX?FTH^`OLmP)^FhQT@LJ^UhpNnf%g;#G1Jon$$QP=<`<cL~C2 z&fR%(6;&zvTxoEfGa;(7c%{xWY{Nutx}K8SBu&AzYPF3Z(mMTz=^f8MKYTwD&dO}g zOX+nDeBTSvTnK;HS<|32o8n%VB%t~s?CwQ*Z<SHF+fl9@{=u=s%ybe*AotNM!Q73R zZjnj3A9*%=qG+txO|p6_w|AJe6U%736q)ejf89fCGeB|Vr%P+M#zq;y0%pAgNALA* zXtEU~bt0@>IbLbVUw26D-%LQserAoY%7hJbbE@{4e3D4}X&ZWYS6wz;h3<SIkp+BG zh?I%mFeguC)YbctTtC1EoI$cfVVxsbY6XKMWeA}mhQABCAp!vd^52gZD4I?LA5a3Y z7Xg^vFo+J+s9EX&SBx2TzhIQ>s~xWYuKw>j8aSudL<wr~Bw8M#UB2E}K3F$4R*B)3 z;r6W3$>=<_qOroU0iuBKCC?4=IK*8N(-R>K7B+4f>PH!DTjD>Jb9%mo6@F-l>sD~x z%$H4gr(sSNUA$<V!LOLcG%OUYOoV02=p}vEBWYl@>}w0n8-yy!j#}mzkKxHkfQyV` zDR3mSob!8qflOvH0Hm@&GF^vka$dhej6f(>Dr3292$d-e)*No3QV=-V1W}MzSJe}f z8IDpsN8yB%V&EE=mUw|)IVJHFX)kBK{eQXml4S<&>M&$8@T5^l`3`v9Y?nwvfHnk* zaA}0vDJ0eX%J7@QMfgo}P%{C&<Wv&GSK8ctPq)REbqm=LoNH8Alq~EdkUz7K`}RY5 zN-95&hB_}a&eFWXRX*V+wSe*AL+CH}t=A09E1PecjccIQzaOpR`eDF~r3|Zav8Mi^ zY+E@uHsYZ@hM3@yK)mxabEAm+h-*Dp{cs(@J?;%(*LTSCfte6MhP=A1saox5916uq zsT<3xcn0}V{yA0&p4PITrfe50SpK7Y!)-M=R0*5e9OVR<$wX^+Da6w`6-RB!uMJYg z5B5a+J`)jiiI#a?Yw#R+w74~YXG4gV_umju$BOxUx7n4!k_hi1EPxm>;MW~;ur~Tk zp2*8pi+@yC<5*SekGg<b?CQOz3(ecdN#i|Ie;f@22~seJRxJcvw!~u|V+9G+3umP+ z+1|OXZyp=DGAP*w_y{fUY+ow@=^4Z~C^e*IO&~CpfDQlvB8Gh}A1(JK3gad|JcdRy zRkp!MvZ>by3De?<5Cu6;|F*g*C@A7@&RGyp@o;(A2Ujl?5OS(Ib3)8{1i2F<ThWK^ zNN%+uk+NGUnd_s?PUX)6Z_!5jOqQ_)X1dauUa+x<(cqh=(mA%!^wG{HWY|y5;Nd}s zMMTE3tS@Ljew7mk)R@bx5}>Qs`8M8beLKlO&Z0i%TkY}2kBH7MRx^?Y=sYcPhxH?Q zT>WbYv&T3!Y5iw7RQEBwX6wOG)`uR<!O|A^Gpc6XC)*-nm?Hs!0qd|>-ur30(|`QA zerHV51!)_Nr_4|fY6Z?2rYNr2#t><Nqi^_n(iuXx)WQWCfXKRAdFT!EmLH{V-3iuf zOZ1@c%wT&z$ObSFb1ov7Dm}%hr#V`ZekADs1kCa^Cz+uOdPu!tgU~E_s{H%W6O^11 zW3oBQIV;R&*RuSIN+HsNVbaKfL!NnjxsDg>Mj_5x$cws!r$6kn2oJAS;};d|D}A@O zT50@2V}|vLwD$rLC9}R?`A!<Y{8vYfUI|FlmQ^%zC}hhVjLgM>+ei|t&;jLra)e`V zaC`jJ$KyqH4jou$xU}hZGTgy-?@ii~oR>{>q#Wl3%R;-;tXwmjY!2IC+p;*AI&}(c zpH6l@5^o<0b~qSFw_j1fYz7im$xvN(5w7`@G*)O*2&I}GVKeVGMdW|hs&}E%Fm+51 zV3S+|dVXL`zTkMfkpT~L6q_EW=XqYxuo)IhIPmp+st|)qq9nH=ec_v;X7YaXJh}_W zP;I~{@Hf_+7ynd6B<#4~Z3+HDKN9*f-3tpQeLa$3>5z+yazY{$pKG$KL4M86I{<an zTOYzT1lU-6mnvl4OQorvk}0OezDa?d(Lo(~o^NBEJa+<QeL21O-c+ycZjO`9aHTgG zRx6_zoZI-M<th)!#%G)3o(G57twk&dZ1Osl*EKc2T#MOI-PqsaOChOa&a!@29hBG` zQ!o~^mDs1I5ODckUEN(7RmVQ`GCStrWyjc?M4$6KVbX4?c#7p;FPZu=s#74mzM_+T z?y>1mv|wTP1~fr%i>h83Lr66(wzkeXrD-#LiLiBo-XWd?lWl>>k}{y=YQ+~F_rq+A z&#{pGW6euPELEDApeCkn7pNHvvde>$6;)D{xTv)`NgHu%<FbI`@+B^4dJu|W63<&< zBO{F9L4NM6Vm^KN6!ZJhl9$=b`!Q7!r7ZT0mYt<Dg455mOnUPYrsb(g9FnpxdJrf_ zINFXn`cInrh*i+2LMhaerr*5e(-48|X%~L&UqYKr!4cXTPQ2^Y70-iX#?;Z)A|mNZ zg*r;c)M}9`F5)2x?6eJ4QVW&G8AhLIFM~c3Uv<#>)xXj8%jGeN7Av!Do6eJGG7tLr zw`go{WE|7fJtOFqThRbH)OH#qPJeUaGUI&NlBrNTc6jt=8Nls_^?F~4IPi7e$kShR zk?yY<d2mSCK3BfkCn_y%E*r+`K*Y16HOc6y#L<KA)N=Vsl(=&A=!pT(Y$~w7fe)gC zPj`(tiIwPF)Y6W<n3B?Mv`6$TosYtV9}=qr%YNLqpV#@j^_?OaGuM6q+R=!Cha;Id z#msJZ!g+m_%;$-D1yM4X24z?(xeApPk{0}U_~g2_JB=m+!LkZy!h!_ilsSk`swGt^ zcR*dbMnNXbxP-KZIF6DZE7fXd4id$58v6{SW~u76D0QA?e5ksl9jWy*j+r9M{!d{u zU6mMXui+czGw-3I^!TntPYC!1U;G~1w8}+)@0-{s?#m|nwTrX9snH#mtlYCm11lOF z_)o-g;ybB<nN>fVYA8goO^NMeIUx3aK1S9<DW3P&;U~u1pK^m6Y?Evc_BrTOyoVO! zsA<{->muI7Ekd3OS@viWOJ8;5_UlU<)30M(#&le`<Ao-`K3f*vA$kn(B<)FQtu`zu z^g~I_vk`EBQ$c}(dy-68$T2!U8Ny|81D$k4x=6kI5bbt42(<;`J>?roK-41kZ3Q!n ztS#ZCQHwX_;cI1Y+0psg>(n_vvh*xrc;VC0iUU!{J%7ErC)07aRbqIeI(locL6n?_ z3PD6Dl1es6y8J1-&P^)?zyc}6(*T|-L^|egg?##wq-y|ehK<|Aw^_P7EBO$4%33O5 z9yl^*g2mu=lj8RyW0m#$$F013@J5u3OsIWrxPXNqL9tam$XsyXBg+%;Xzh&ei+=8K z4fr@!!vjP4HHTFB=ZTn(X42{JcM`0mF>~nl)bD-JAhU%Ob5zQEF8e9N$K=#I*Xc5( z_Gr@^L@`xrk{N}4neT2BTOSYID(D~ZU)P5xAEyY9R8}|Vd=Yktpp?cz-}Ruqq)_fx zW6QfV{9N;iq;e9_!UE<~I?N=RtRD9(<RiFWD&Di9^d+-}6C_x&hto3kXjhG+hpr>R z*VL8vn&Gv&!JTQiAPBt4LEXJK&ZUqtvrlAkV#+PCkU`H)O`5=w`xL0LEw67NoO2I{ z;*QOvnbSe{jhLl%4@?}-gqidthgm{}CCR3it8GB##qCD-<WL5MucOJ`+ZU3KECHL7 zY+LL-7>vKYNCS;Rv1X>D@6fUTj}_HuacDN6q+i&fDGU`C0?c<EtddNfq)|__mv!LK z?ROr+<U~=|w_$FcpV>;GQ`FGLlh)#**fDVBR!hqi9H3!yu&cJgBps;Q2C{AKD<DuR zsA-u<1slBKG=VJuUY=V=`AidSN&`187Mb)fJyp#pW({Rg4%oJcBWn>}k?Oi)Hj0yP zT_xKUuj;bBTE`etB^^{}o55D%vqDtpjwfr+bCBka5Ac8|wj=p$0mxcDT77)v3~*dr zY^&K6siatNrS-DCys#(P1^H~N9L4xc+v+uDIY=hL&^L6dm26xehA|u#<8A|+-%e>y z)xKSfri*`OB!7^3?r6lwpZ^T>QV|diE=njvhM146j#>_A|9&Jh6>8|!u%K8fr{!!$ z9Be*PECEdtg^{gc)wC4-yb%<|?~%eu;Y3Z5@{Ch)4SB#<w)Ja35mHJC2^Q`u8F`8w zxy54v+zbq?WbADXG(=nOV6sz}fvoHCkfUfKBj@3MZdM~Gy|Mx(-W{U|=yBxY=G4%h zCs0@-4SDh(MzwmkA@yD)oOnt7IZe3BuPi!O!CdZFo=h~7LMZhly8cm7<N8s>MBq5T z*cQslLX;Y`MSPC7dH9mk^D9qu|HV({lRdBkC3$kw(3#>8quj?#UHyK6Frp5~{gQIi z)R05k8MpYlI9M@&-g86!7?lY2v)0Sd(@NRud^5Q6OJ9qdLV^yz?Qmq*bq`NuQ#Rk} z7TcfTARG)}94+LNmKH(}=*=JM)7Y7n+q;*?)K{Y${+~YbhEYot{cW1BheofATW}6s zddP~>#7AO(1g<LA-e(q_UaJN*1m#kYNo!b;sLv-M-Mo-#xxfKSiXEOf;73o$rKO*% zKkn~G51c<Kb9y$;Fpe$k?a5NyGqYQl4}aIxPfhlu(f}^nsdRW-9<1+zV^@@|v!gjk znpCL3pJ(UiDI=&7J=x29Iq>XnpW`*TqS#C06jJUA{apPtbheiITGTFpuSkX~6(z)f zKZ-mSly`~SrW=+@3}wZKQ5XDo^?%pV=n#pdX6ue%J&dSm5uqRTcT}Op%!mhmxZGE~ z)}xq>Q@YqM*yjztMC=$QEXXz(yy7Fs`uWmzYfVQyYHH?7Mc+x`lDYveH{m8Tc|1}5 zK82E@Lm(N(0kqoX-x`UOoF3XR8ZSA=Bt7qY=)Hh`WRw2FqO&EaiZba>N_|+)7Lob= zXy)#f)v@iQZ{T=sLlSSLvO-@@sN;h~c)L4K*+JzjW#}v0aBjN#)af~4{FwL_y+})P zC5dONe`Qt{I<6*@%$-c!DBkU~A$&+=!3GJP9Kg1s-;d7xt3jU3P016=F}ps(S*PB- z_1%lM9#)QH(GgT;8;(-n2@_;7JDuTqrj4X(FI5!s2UwY<{#uIR$<ucn^xb6e{JYZ! z%xrsSbOdc#?5|b^zAkg&I;4(L9IPnfbCCa4WJVL^AujZ5p}_^pBhKnZcKVrHOeNz7 zABY!gj%*Qwe&6ld=fYg#u~NT0u{0BMtBIszV;UMOmqqzR`9P)Kc;e2}oMJT&2@DM2 zw{FS7OV`7Z^wgnd@&s>hu^HR1RJk5%7+}wla!BdxEb2zHAf$pCfTQk^P2KU1>(B}s z2~_`s6*dD=C>I)@S?a`n)oxHYkIA{7N?hC`Um?DezA#d07~wP1v*&<c&dN){SjJX} z9uk-q6X4C#hdO%@&P(rQF`%3_pc?f=utVjVdcKo*t#P3rIwZdqW-A(ICOZDZH(f*x zZfK-1)$uNRyxhH^&_A*|g1D`kk33Ae_jY(rO<zKFR?e%fdSFj4^6>_f?U?-%rS)^7 zK%A=V?~3v|M^?ZZ{xuXb92{`|vHBP7tLK^-KOcTS;w-q0QVwoil8U-qY*Ut|IQ*;c z=~D{>ipHs`<dv#oV6UnPxUf^Tt6p~eSwmKQbh~Jjq_Bh9I#C(9avul79~&J?WhK;( z4kU+^MuAkADDK6O_?bxR=g(!O!F)HFeDPXIy&5_#mPVtM8Q1~AC374O99)aNbKMQ7 z>i*M`@bA)TG1J;pmQLN8Cr-x*?>_{y&e}xG`6DI#dgxNbEIer88#*%M#y!<7C84kO z-WKRECAp`X|7m!kg(!wM�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ΠMz8q;wTcI7c%J!Tu!QF! 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 literal 75628 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 G2~7aVK7l;| diff --git a/_images/quick_tour/no_routes_page.png b/_images/quick_tour/no_routes_page.png index 382950b6ef58b400552297612057c2ebff327296..030953a17b124dca9d47dd1c1325d42996408444 100644 GIT binary patch literal 62109 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 literal 576466 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%0DnN*FQ41vgXapyz$HLJwos)_Y;qX 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%0A&fh=C;8g<cfD3AUA7;0nXF)3r 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�QG?0rG<SfwnOf6Z0?yUES76%xt= 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 =v?e+uJ9iabis5weiE&d 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�Kh;$ zzutT<h3!p3s(LIUe5ET)pTmKs#dAU;z?5ZlISUqso9kLBr1*rAw96wTGf}!uV@2FN zebiLf($cNZzM}Y;(qCBNZJ_OOZisGmA0RhfP$_${mF+ZK?e?k(PCwA)(&9AjRsEDo zD8(eDvx0@o`axox!IoN!_UQ$_77Qm`V~tiXg$lEUPh~{+46gM--=NmKj25H1<Uw&t zF1xDnR%`lK3+O;nyz3`#Hh$sLqsd8$D<o(~N29peI}O*7-@3d;T3hBExNxG!0r=@2 z6vP8GGwqwNDbFr1D*&t`a5Uv3fK=+wU2E(Z_1L5S;Zu762vQOZdeB5vKz=F7@n{f( z1zaVruV`99T#yjwN=ooxoyCJ70SA<c6Q6HUJcwhJ<V^!l6bF3-_#b+q*M+m9JK-i! zk>J!G9-Vmp^$Qrp{1V%?xdK$nzz`!s)dH1Gazi46p&3wQ;J?85;yf<Sm*JwI$dGRq z?A}O4fBR(f==2<D)A#SH;hG}ZY_^%1**A_|&PZ|&jL(9$0(r-?K|v8JTYzl_vY{~G zG8eM>8H+HpDGp%DK&U|xBPJADz}-s$tlZ3|fKV4?GnpUA@qfADR;tVPu_v~GJzat+ z6$d0=T%5zb&Ue9X;c_CUew9X0b`@Cp>9bb>_yVg&Sxd8fF+k4eabl=c_@{gY-pJ>1 z4`U`?1>9LYLhqmkf_i;{DU+1wiC__!aSPBhx(imLVlJRRc!FpZt<jDEyf$CEdFIls z1h;*8T|`A`9v-?&)jJ_1nodhi#M=il>xBoB;SjZxacS#~FXGCIEeM@(&apcL#agjL zC6Y04sRJ$-0W-6X#3F+m0Fi?OM?|pDow$e_%;ud~J+N5-dm2R1A2{$VVN|F2Akc<l z*;ymt8!p|~+yAF`S{~k(J2$uZ|JeKLz&MWN>v^*)nQhsQZJ9z&E}R@Q<Byq{nHm23 z7=L`s%*+tx<R}M$qvR5Y!3>gi=Y1o|6IaUp)LSe0PWNT%z@vel!rtzh>en_^?FLv5 zDG?gjAV833#k`Def)xM|3{e(JRGbT~Y1f!1q5)ZBni(?3i43A%2+9qjA*!K7`!Spk zHvD2JgV`K(6>=SI@;uY>S?ac^{sM!uGR9GDA~2rxSjS@TrMQMEWne@MpF<ZoC;lY} zs54jMBt9b$+Rm=>*e!KX=t?561CSf!!r`b;^jnN6PRJDsNb&kuItvS#0ictG`Fz+Q zP$$T(Vwal^z$7~jC>k6@K^C4IDY5N+$Sy0;yC*Kh8hj0uAu80PumfiK%5j3GG2G^N zYqUk8+CFY01=?#4u?d;ns#uH{$Ebn0FJr+#lnYE9^Y8r3rd#p;rb)Nv<1!E;B3+%V z+x28tZqje(qRWvPid$`B8aDFeN_1VXNSpVzVT-t}BltF;>mH6P!iiDA@kcnxw*h^J zZf*Erwg@M_?N|V6zQuJ9L<JMI#u@s3p1OMU(krgpaq7u%rbK<Ux8s!UKm5G&KY7`g zPZ(R?>sJefh}!4;n+g=s|KN+BvSf+ftS_Ile&XZK_?OeS7r;4Zo<ad_mu+V@k7@tR z+}!UM{k};s1u`}M&fpDY2@{$iS#NJxgO3*l>)hz(@eQ>g!K}A?btbZ`)cqNneK3*U znknJ`g&%)*eb0&&%WG_qs;V$Bf=x~Jwwae*^~GE7xUW9>*vE{YwqyGs<*_A><*ghf zu~=0-(?Z4&`l>HN-@bL@EB^6kDssokTkFpf*1fYqfg`e1HX8x`ILThGsy7<_<b~IM z{r3Co?+xP{*3`fel?PYxQiRR~RH2<`rgr#<fiPq&lxq1x?LIs2y5l3Cx~AJH?z(^f zum0pSR<B;E5M~w#DXXY0YyBs#vAEtK;i`K5so6gKfd}_|^wU@G*?+jxDeE0|8w8sH zqPwd44YG|7aNT=UWYz2Gr{dkt0;P6q!RsX;7hitexhJi*Kap?)F9Ru;o&#%Kj5xt# zp1^<*vS7jEf_Z|(bWBSn%6;QNAfn7z7o8t}%o7jn5NE}S8i2nLO-IUgVMg~JEvJC2 z_!jNZ77v;Xq$#O#tCEk_8Pa5i1jR8==!F-!5EvTsghSzBWUxly+|wKlAI0FXAiKz% zqeKBpdk)>POFzSYhnZ~!rPZ)?OImNDty*ppWsHK#=+M-svX%x=FxJ&ToiM=~pI!<f zhD>dlIu(dDH=az$H^4_tBqVFR5^Ki^a}BD~v>fHA8(ueo!2=ozr-#Tqx*k||C@vCU zd)>fda??a$?^CUsh|cpb2{+~*5(5tnO`~PZT!)EA<sGI0;K<#ezbs&K054T&WaXRF zqR`{Nn0A9EG>b2q1&Hz5Pc4L8$rVVhQk_K}+9JE~MiUjzJkv!T)Oo=G!bu`XoA#n6 z_PoG;3Nj&vT%(Y$7NO@Leu5uSH0%qtLx>zd<(?Ht+{bw$oahyW{0<_V996n%ErfRB z+|S?Em<1rILl3(D@Aa!q>sNmKGgtla54>P}(*|2Kis=jmYs}~8KkIQ<eg5mymr9Vu z_YjSA%X=R>@B`1i;EdBwG@?l|HN~Ct&p8diY!Ri!VaW7aK>gBgw`|a><GJ!hK$row zsIf1e@znEY71GpBeuoIa+{x=2Ji10dFuZX<l=)9wcy+z$=z)V1x9)sk+0yO<dk(+k zc~7hh?I#3$#Qbe^{8Ddq-uaBvPr^+7vdDS|Wzj$)ANs_V_uaqifnED|-m|N&biVcO zeZTWdFJ88Ese$-dEHp2EbSiw;?!E8&z(qCW%D3-&Xz%`m)1Wll);;Bk=hSK6xbidn zkJf!iSpxPe#dle6Ghf0+FS_jdYrk;Iisehl;*Ps_?cQ@>*^=(<_wIYi^PgC&Xh3I( zi(`gRi;c)mw{z!RcfbFWSC5~ts^7D_AQ;33IXW~$Lzt0KVkE%yB5ee#B0T0vQJ7Q^ ze1;-Kx|$O1E(N4%<(@z02{QXb<|i*<j<jl!01D)A32`dSX4);5toJ}+o&;CgJ7@~T zFi&u#1v*KXL5QZynR37-sBnO;%zBW2zptzoqUP+Cv9N9}Slu3*e2AE!DUZ^yHvU09 z^%rM+M5sg!eL~u9f=04{a|0$nebGaIb70upJT}horu97*z=AqSl5^fXpv$~Fb-PzZ z05rXzLG@))xo+zMG>HdV)27Pr0=qddm;~<@!)zLh#Mz*hnY;xwJ}wCfoU<5E3m>U= z6bPbZq<-M(Ut=YSQhbcU#2G@d!~_@#2M34=WygJdA~j0FVCJ)EamH#|=L~=%BwFK; z7Bs4*&*~0U|4-kr(}9x?QRoai1kBr9Exch=OO)u|118c3CA}X%7hv@SXV?3I4a*EL zC5YKwe>Lt$45=j0c~flX4%^|(i#U*ixbO%kl-;j)^M%NLGc7NjS=7otvDn)D?AMsK z-`x4&6<1yVGe7ymMbUR9u6082#BJlh{1eaqk2ig4qbd4c{M0FN;Lz0RCvE(p7eB28 zdR3q*lWbrX6v~1w75~<~`&NyXHCRgVJx(MY=EGtk90BVn3g+!&Jia2odduzq^}{#3 z<dn4&y=v9+rGNO#FM87B&zi7X1%B^PlkpGL`3A^>Vqf{WuU~iL&hfEj{faf}`rrQU z_do9ZGx`>H`~O#JGK4jH_&Yv%!)T{mzN9<Z=Xs}X`n_NIf$@#&7dGo%0Cj^m-o0;G z2mM}uQS}C8iQDeD_dmbm^UpnfY+|ZfxvYC|vKn8v;%|TF2Tne5%cH;<<ma@{TzqBK z@26IgQz8J^6AE=eW?LC6!^~iw6m%n{A&Elt80HDpGqJ&{Fa68I3945!z>!t}^UuU5 z0u<#wj2FfY#2eGIUPdra!aJLJL1nSF_Bs}XlSb8SQAW!k)+Y)ip*#@Jac6C99SdL@ z_a-#OCR{x}kl&y*l4=?xB7|Xl_-3lMb4eo<WHbQsP$zMcuqTW^ZGTFf&W0wsTokSD zF!z|rvm!T|(;rcE-1yUZ7#31x_z<i376i8*Lpr4w5XV+>0<LB>(Pp9q&mA}h5UtpR z<2&}WE~bR#d;SCj3wk|e;0Nqswiq4O1jhys{O4lWzR)-VU~US0m%@-J3K$mt!nY6u zML-cpy}+Q}2X#7+U8JEiFg(HuAeI*hYub;6XljON`g)jWGER!<mdP-1Hu2KzW0@<H z2q&_6aWQtU?K{6?2q)%XkszG-Kj3UP{6YxR1XxfYoCGKk&!*}dc5xHj1J)5}N@BQi zY}rRXaoIDU{^ZT$ev?1|RaMm+Cw}8wcYge`uWUYHWnBPWEP4V!786tbU;K&ZZrZR` z0m9B7G{EiYw|(oTKl!<5k*xOxHTGKkq%j{BADJ>(gyN^uDWCDAvtPMw<H}`A$2X1D zxb`P)A75mJq;VHL&P1}??fmGAp7`{~pH^??xp~vtdYjXkL}yhzItVCOvEKFZkALyG zRaLE8v21+Py3Lz5)X>}Ug7<tMvUz;t-~aNn0jyuQ_PFl-8|SS$|C}AK{ELx#8Bo8^ zdYj^n8`g|(+;Gx~n`=EhI#b>?g4Q>_dE19Sam9wQ6;<W8wY1|dhlyzC5wx(fSzHf8 zfEW>p({LyWrUv2oVxCY-rAjh2#W7D5#)TljACpmy*aYYTVV=m#&ZErRAS9-m;OUft zw-bkO53K=f8edjwUo7j5#lEoS1rZ=2D>Hp=LKBWL2o=YS+gewW5050^3-XnTqugqn z=athCHTsY!-?JNYCaT6kms<o?3Ld7~UsD{;Mu%;nt5MxwB1q*b3=VGC6hKjq0Hr0p z<_4-{&F{cG7q|lxpT}JDj0D|zPk6!Hsy7RQP}qM>>c6=O@ZwwMEc3Q+20?H(K#v^A zOr1SI0rLSX2<;7mep}0db3U`e+Lh@<0ry!D-XM8nG++0?*~SVYn#^kWFw&y%_Hr3g z!#LFf`bNTsnM^W<1TPNvs9+{L5A`!e3y-KjhRAl6SQeau7B3$0+*t#S(15x$GK<(y z-mNm!FrScY(A(1ikb5I(V=l25x4`!^tQc2=VbzIe#?i3y0IDS$b;g-e))B8Wt-#u( zIWr)69RRaTG+h?S!EEg;q0D4WVg<4NP0<{S*J&IP!uX3}+Pq)5fiRoyV!ST&ScHwx zYDfuagcDHND+Y365KbDi7GTp)dedqWr6*+S!w(A5eI{;94?2%BAxl58q&402?ESJE z@A|jD|COKpsUPY0`<_3t)9LKqv+w1v|Im%!ynF5HWxZat$P-m1P=lQO{x7}odCz*n zceoUhELgAvik23iV^loS0oMrTvqjTIO9Q9*$`YfaBeUC10(jIpPem3*rz~sd>Gk?k z#|`F%<YECn61=e}N|f~vM>Vr;@1x5Z%$}AN`Ks5v_21w8v2#w|Fge*P+|c%D{=rUU z?GLntLh@BFq@67IVKU$+@q-s6lY~utH?J_Gn!tKuQRF~7A9N!{+L@Gp7xM@s>b1<U zlz2kr4UBngW+RW*D5`*2FpcoQ4C;yyUr2j2(LQt7NJ#3{ggJTaJeMSZqg|8&$q{a6 ztPabeXT?QGGk_&6=80t5Ti4e@Q#g(}=_fSSdO}ob^jQLI^{f%g8(lW7ljp|hO)Q&? zTp)PSz=xm!Nt>JzwYpw&`Pd|mU?;eSn`6(B*nje96G%bN7f#K#dm(W2{ZiTfbq<|e z3+VG%dDYt#5beU>kl}3Z!WOEf*rd*b%X0)lo24xVa8}O>H5jiq9N9c4ZlwTdHpwA+ zT{iu%HKB$FD(BQb(`riGWN#ICI8>IPZA+7QF8%}!z6?o%`DQJ1{>W&6w)Ln;rUm%7 z3?#9z7O8bS2!~94c=xSf4jy1%a_k}Uucum!!i*4Eiz2NE4(DVRwTJ<$1)3INgP|h9 zaB1B(i+=4wpNzz7z;d~so4R+h-ovV5#c7HfLpq3!R^y<|h`^Xf&}g}d1kg&(xWyfS zoF}T#mp=(iJ~Iee$&#nEKK&En?pBNJ8DMd|i0RHQv9^%|_R+AXYN&^&oVMW&@A&w) zZoR$R?UFpU4sqSu)xYrz-@oI;4ZHUq9_g0FVx<x&fqQoy{I#EY)^ncmIBJBG<Ch@o zv{~;(Ms^Th0w`+aipj%=CySOM*g-|3Hvo@D=K(qZ$%BUu>#X<UujQXVZ?pJ9JalNn zWW67C)a`V>dgCo`c+Z7rZeKq!)l*BZ;r0jeWJ)a)Lr694<O0qZNLqx&c{fdi#YWAt zKdm!o^PlOH;&p+R$bbr@fQ*kq<I);nRXcfRBIgnz&p9ckoPr|7rqmfC^&pS!vKxK- zXCpyH|Ne*(=6samMe!^SSdh*<EJ7rhp|yO}s3L1X7R<s^P``#|0)$~ZC_=xBh5yFI zRDqHX_<{9rgJ~F~6FuuCHETw$c<YSE0V%4qGd8xHJqArpfs|u^>TDi1koXph`ekR< zT!z{82Zj4C4znVwxes`Ry8&}8UWY$$eC5cs(7e+yHLu0^Fh^dF7^6muwq!NjgnU1| zZnf}MEF3K&Z?u*Y4Kr6wN$RXZeA^IjmIPQe3ju}jaU~&UIPqEpEr`JCLoXgsARY-B zNpq25tPATdN1JC#x3JFw=|~s7gmuY$l{2|?>C#mzSFBvQqSGm9)RlYG!>l;gTo<CE zRd~5(Ui0GZ?IR*cfIrrRbiYA&BH}uEoj|k!-J2Is55>r|4ReI(Z-nmGJ>QvC%rNJi z>12<M+2XZ5dk(zg-5;KuoUD(@1bX$B@e_XUSAXa+CvUuO*MZTI&Z5lCl@)p4u7kh+ zQ_p(I3!Vy~B8%@hu~_WXQi&LFc}r~d_OKGl5<t-gQHe*L9?UAJz5DjR;Vti5wX{RB zpd9{~BdAj~!9JZE-T??q3iN0J<|_-r5X5>44lyE?57_g_^P*c(*HAFQQE2FkfO_1Z z8D=P+78{{?X9he0X3`}2lJ08A3t=23HZw6Kq=sF8ew24u4MI<B8|L&NKc6zvn7u)Q zn=>ozVxeqpo)7|Qg8MgaVho~U9}(I1;Pl}IgiRbGoi~7a9ySI6tG!g1AlShS`AJDf zYh3LJWeoz%Su-NoLNawzsGN_rmv=>#?K907_idaG(q8m04<^1{>kL_*$trIqs@ovv z@$P0c$1oa>b^ur~C@!nvI2^uqYk>3cVrefHIw_Zv8@~M0l|{mvsvzw;K&z%ewok`J zR_7{>YmOX4L=o|EF?yg^vEXq?2sPuxru1UKK*;1sq5sq#<cU!A!rl$^x|`HyHWb4Y z$Yeen52|M}-I1EQ0P;y*@7qX?nQ2}`=539j(UoSK&q)Dt*?GCz3aOMo<`M+@nL)^e zOtwFUVFLk}?vTnoIF)B@cv8QhfQ65dfcO|>QYglG{eCsRVfEWTa@9qbT-EJ%62&&a z<kVE1`~Ll3|B+`s;q;yN?JLVglmf$a{atzR@Z_P1-XH(!OJ4H)r<OpqQ03k&wbW8e zEwyBDMn3ZK3opF-#x<*#_bWn9)*NAwRVfV=9+3Qu4V@(l5<Pb?`)SR;I>0snjqp16 z*cOPf;2Y8`WjK-qc&3Bola|yIKZGUpa+xE@8$(2qEzL0mzl9s<SBEoM98FuL>DNP; z{|Zi1Q})r(?(~00x<>a(txTMVB^SX20=;UD8IKLy8X?OvslY(lCqh}M{8o3yz{z?> z9JAP;a;>mAvNhvmMzx{t!v7twfdW7gPQgt$bsx*&CZ-IToT+4}#s5kpKX@Pt7D(JF zIt*ue=6?`mJa;y2IW^mjyMP1Kh7W+?B8l;BoSjFn8{l22#^6{9V0=5aLq04*(=+0Z zVhGVzKzk7IV{I=Klo?Pcp1g^r&JxX<XIRia4B5v(t4Eo7AWb8EBV0l^2Sl#D%;1lk zP9IqwAr6G^N`-?30~p^9{91A-LdI&)x0dn&8|l^~EmXN_iN4ziguJ;9lB1)eolZ#> zQ&Uq_MIb)rw|DwzvbILh*5V2?56L>C5CLi*CFXlh-;{qw3##Ro+Osy-JcVbB(3<fq zAwC_ly6^-mj<-2nhijndd;rp^NA>ArE0$bz#TTA<!5LdNZ?gNg+5OE{u3UEh**i9_ zTYlY_ZtL~>^%iFUNPag{-rcgQc>nGLXYSbi$G`bQ7o2xGXQ<73FDSLtQcEqhVE0u$ zR=oP!&;9*>eeJ1R$NGJyCW)~BsM1l`AvJshB$6XpUG5zrc($OXnXz|3BxE2NKqjG! zEDPd_$T1=|g7#cGV}vw<?8rQBPsqQa7|;}uCq6Z&U{0jRkuZUGNerk!`vi)Ly!@v7 zZo7TYUHcAgTepH*N@;WssVz8ZaAe!<dJSc_Q<AJm$ab^SL7QvB&}BDpxdlnoQ>;AO zG7vaWI3qVRH2nG7htLfMFX~1>ClJjAIn>SS?kd`;5(VTOToaJbWaYDy$=hgeGzT2$ zb16i}5`#LS)R(U0H5LAV6%y_~*z15m387p6!o(OO_$viO)(@yVNOJ+g*N3J+)*ER_ zpyjuRnqb%Y1MoV7IRxO1&%}y9_j1LgGq6NBng8-4m?MPjr<)|i0)yzN19SIkgsF>% zXkNDl{ZN*9Bp(Ol<HzD0!F+iJOr*PZ1XN0%NC1Zp9p1n1!2bOQ`uz$nb?Qhi#6m(b z&c?cqCb&;gUi)E$6VH1X;Y2$sk{+99PBx;aNg19px)1O{1`tm2tuo&i!6JkumnA|3 zVB*-hN>#DbDXXggAFq7t0}nj3WOTHu5_R8ovU|yr(HB4O$^Y<2KXKj}+wOhn;Qm7s zBi+t-Wjn|EwPlHWA3VSUKmQ|7|D)ghvC~f7UURtMTf?=~QcEqh)MmYxE?si_9XtQ& z-`~7x-7=buB2{Kak44>ex85BQoQ5Eo9J(1dz(83HM{vhc%oBS|^VmXRp18J##5{?V zOXd+Cq?8MYgMkdVUr5yg^Mv_lkpR)4Ndj5m%45F{vAKZ6+EKYS0v@b$Vxo7#x>a{v z^QQZ6e$SUb_3|3HuUnRLy20=T{#HFmdLE~<-uFGY?~>2$yyWvc_wGO3DN8-O(>YT( zbi|<v2`fp;UC(5jEZD6MXWN3nN=?CHplQD_7r_|;X%kauZd2TgtCVUGP!l248X`Vj z&w$m$;vI64N`N^)A>JT?j_q>T)=1vs9z==)xyEP$3Q0>-cknqoSP-f}9>-Lk8-Qo& zR{5pzOr<+XV(>-preYrEG(ixK6Wt8W-*&rEx1+Ol00s)ZNn3hM!;)Z4a%z2<`g+De z%%0J91Kfhv^*oo(_{T60VSQ~lv$ccSJUNVYkWhuSlJ|JV3%!lWBF`GuJR`1pnqC%A ztoR73B;zNE*V20GTvg_Do=DRUy)#j+xXW8z#pbMOs+vr!<yvF9@3BH#9(}atEuQJ8 z5`Ur5LY$198+-Zd6pS$Qt3dC<hL|5>li5VIHNN3V@EcYMA9-v&ba>Lw0|k8#f8-=- zf28In`WBV%m<o}pe*c8ED?fkZZLfIE+y4BIe{<QgrS<BEvMhbw_cRq}pK;15CvADk z7jC@dsxM#vm7VKWk1ib@DKSkfNV}y;ob(_Hv+ybvrvtX0v@97N`QhhZ@XV*4zvJYs zHCq!C3%~PTOD(n3QcG>tyZ-3=z=ON~>EGXQ|3iD%jV+(-^-7e50EAOxI6eJJ?D<9( zFsERD&k-N$=xG`36F53KBLI>@k~o4w!#(w+!mH92vqo6(D)A$BcZ#8Dj%g&W6vGD_ z$sCXH3`q&~T$#p&_=wyF)zcx9Hjs`)qX`J+gy+$Ycby3!weIl^7)cLS73)Hc@$pUF zPG@9f^zdZAz(9^;{zU;QM^Os3^Ko12{m`BRFMRd|zj@-;`p>U?_3K~!>aA;5E$#QI zpdu8!39VYq;jDrKM5AFNDQ4u>&Q9H$(k#hizg95dm@Z=SW%zVHX5u4fM;DXob|GvC ztj0bUHlJ6E%dA-s7JW_5aBPn0xf2q5R@nUOBb}m`$n{NZymO9RDCrZ>eo1sB@lB`C zg2J2vA7)TAT2jd)BCq*5@q*?ahsZ7#f%Q9d3<(?|hJu5(H=|RmW+}IIFCp!vn%B;0 zI~Ta?{x1<IsT66Zmt`1ogh_ibDOSQt^v`PY?Z?MUmKW`^>WY0QiZC(j_0)<DRxs0g zH?*+}i1!9oXC*$z9mjkbY*(KpX3k0Pqs3H-leL5Q7ivaxZs1)wK3jr-9U6ouY6PD+ z7KwF0t!p8Qwy6G<a8t#^?80NAfU0Fhv^QaLs<(a9nzw)Gisj3f{@!o>QeEAa%zYO{ zQJ){}cAoQ$$De=B>EF8T&P%WQ@>joh$AQWIWQ~6^+F3H%oh`?nCh_)=M^+X4RW;S? zA38i$u^8!=8`iCQ$#Wm~gbN<CW%Gs_t8sF2O6>a8QcEqh)Y5#Z&3f<Jz4xE~?X_24 zf77<{vHG_X1+pu<>CWj@^stYZXPfd5k=M)*E#uV>B+z6D=G(N$;6e>WyofN$7)Bi5 zs&CD(=&vwSTOMS|Rj3F)%t3HssH=QPpP*5>gZNr=B3gcDHA%XsGGlv_`4$uOoVEb6 znBK*G>C(xm$xf-&>VwSWeFJ0@m|i_K!pV)--~U&Cbl#Jm^o07)ey{)LkALC0=hrnH zJ?pEnFl(%C6dWWgsr{ST@?Zu+lJ){kq{sFmWBwV6ziG@GD4Fwtr}_~NwO9rqY27bC zTC+OJVksziIQ~#68;Jt+DIPszhR%~pdGt3|l`NINFWsmCGr&_Y895#;goc$9na?;7 zsXzNY$zB-p2ZR#UUvI()=25jRA>_<-A6k%9agZ>`6{w47zEW9qDXPK;JCLDMFyMY# zf>>Id2WT2_ggKJFv_S5{fcaE<LRipI>|Icm`*Dg$in%&4SnFzlC+i@D*`gLS(*Rfd zVGSSWnXXr)M77r9QWU9B*;sRy%g<7rz$5aWVfcCaGV9^}Mb=3SpMQ2GIdR;6`|dF5 zNgJ~kjc*G9J!($mxh1oPLtXT3&YOEDCVP)LY5nWoc_C2#&Tszw@@32FNrKINTMW>{ zhbLFBTK>56&!`K)?|*RD&0oL$+qd6y*S!zj_t5@__8!`IaPshEuh-{13%%<M`|_pT zv6V~LuURpE+UjkaH=MR(+m4gBtX#2tq}!dGnyRzjZOZ#NQA;hg)KZIZ^58?e|K&ek z_lZkBf8yq~b=LdHSe2Q{5(=cUuD;wmi||Sgy1RXV9Bw#lH7$$b2|j(+9H{&k0@F`T z(4%R_Ai*=2fatnkh>AbSb8O11c?Wzl)N2G{tW5pVI0muyTz>+7DrRq^=TdwX5xOLc zrAxXGJhbok|M(xuvYeXgjjvzXud3+$Jq`@bxnN2fp>r6Ux{U=O_<uu^$3qg?3^C-N zA_-N1=@^4OZJda<fL}|AxPZfU%ZQhGLt9dbgm{pK<kH;+X->$payTjI6S1P#@CnHR z?jeS-PP<wZ+R}Ura^QFCm8l|k)|Cx|U_roKl=Zo>#a;rOz+V$NBqR1<AQ9rbee}CI zK!yX!^9g@wS@Lpe+05-e<EHc0ra~K5^ZHQ<>_E=-ohvwEKrz+pPfhh%6tm@uq?OVw zl8ArnHTBmFmD78tgF6R$uQ%u7ivekrqn7^Vo1?!~6jQ(<wHW^(v>W-J0;b;?RM6(g zx?hN>5l-kh4O$|1Q3L{mB3MP32I!TZVvd2XMn9t)N!d#voW$c_H0D%d_hR?>Be~un zZUFxViK>%@Q=+~>=Du<C*A^@$r}~dMas6xG@u`W)$>00UUl<!(Q|G>uz}aPq8BFbd z-D7UuykYy6O$CaFcJ1A@d*A*8hbAT_>Z@c`a9&F4OfO0usi9X^tz5og{n+wlOM3l^ zWK~s%>!dsuw9vbymRf45rIs4Jt~%>|_dWOh)4#v&;w!&=(&n`jlRZ<wlc;RMKmcu? zI9D08L96B9xF&JT6J0hzpdcfyb1n%fp4O{Zb7Pq}41lO-%_*3^PS8FP5K9iU!KhUF z#R=?L9xX4TT40aZDn=MJB7k`!a+Y2*`fmtL$^uUS{i^!>S8l7SqSL|Zl}if_jaPxF zsoYGy*X!@NVC~Jfd}A6tuqbZ*_Rcf5tnT+KkwwiDy>4QBD$P-3%8<zKF_Y4fHiv6g zdY#s%asaOpnck-6fVv_|tUdq>4)gf{?yFU#V{tMfpYDuhp@;$^(~vWq*N$f;FB1rg zNU#-qFgzOpq`h1U%DnHqC%iz*2oD(wce%k5uuGSG-U~jDghxahAi$$jK{oitww_79 zuF5ef$UTx`23}j{??yX;)C{1_uTe!T!RJxEDp&wcE}hbaU-}QzcBb$WKtXc$Km?Fx z1m=T~1}5;Tuw$25{(JpuY}N8Qu~PrJXYYZ12M%>Qr5WUic0-A8fNV|#+Cst`y`)NX z@dk5NKa33EgJ4xk=y^9rwrNK1H6EDB^T<cO*OSAv@(LvY3lSY7E1unppAYw7fDQ1x zt@UquB5ZAQJ`lo*Z>>P>bhHQNVqh(XcvZq)0iJXZ7R-SA{%OF@I<PxAor!%BHVg4u zRs63<xTJWV){tx(STfT6#?FUc^o(<U@3(&Ov>hk+dOecRva^{ycBbiJm=i2i0%A7P zJ(Ef2@!P(#rIuQ1sil@?H+-(?D>vTqFE4%LSH5<~){WB$CuZVe1_~w8#mj(4aXfP1 z6NHA4K>CLLNbN`@Ve?4^W}p&DJN_X#1R#eP_0J92nYaR7p{XBM#XJ5E&4?zlfSF5@ zQKdK><=F$lydZCMtqGc;q(y($T5}h)5}F|_DKsINqA{XVq#>sri~ck7aw_yvEf&jW z56P-Zc!Mmxv#oehwU#`NEA6t1k#4#3zCE|zu)9EU&XYE*UA?T|=Wr%A7A62npp&?J z$8m23w=SMlAov)aQ>C;29JPUN1x(~X37ep1z=Gy><vMwtq}{K9JBgIKI;Om4Q?VK9 zYpf7X6$y#8{@6UDf37UpJdF~~Q>lrqxykf&*6up0JYqQmiEs0f!}jKW+76@ZMmoc@ z%|Y1|h9}JJI)OY+O@K~(4_u`P%1Ukh2_{NF@JVqybmCj7!Z!d~j?$S}_>xArKrk#A zCUj+OJn@~&882Nja_N<~{p<hyt*1TpNkzfWTzJ_({NHyy`+}|Y7<c}OZvfPZZ%g6C zx6PQv6W{h3Gk^;wzU@V8V{;Q84s?yk0Q;<7;o@2I%p)J^{?!2dvznmh48B`#G=Mnr zohCcv^FQH%#J5+9IXgt+Tl%U#onZ|cfl)CpcoJ+XxvUGjCu524fURA{w@iFH8N`?p z8CX9uUB^M902`k=a=>EA%(BoL@B8om?AM?5j3<{Rrlxw?q%%pA2VXb>aQyS#Ew$8A zOD(m9-lL-<6BARPzUZ?5`cH3Mv2<kB%B7RDTj2qqoAAPng8hPRje$T7%ji>DW$99d zYMXoJhI)Z43TYBb07<<%Es~L0pu~4918!Tf`BOXLwF-_WzT+?jjS75f7c4k$m~ZDo z_NdUc_o8w-oA@SBFytrAX>*@Hoq$aSOdh|fB&EPSp-6m-En=m=xLl!Oh1vo-ZE6=O zv*>m^b^5!Q*<z>PuY7BYserAcWZOG#iErb7&fR4qm8omC;@eeV@z_KvT_zMWW-({y zc3BFOXe()F%YCMreZWUkIPu*?2Tdc=t0g(P%(sTn&x{Re({Vz{&^%&0fkI}$P3Fip zkq`B>nYtop@W@TIsN7pGzkyV)sPCp&_#(+=({%2G)N2I9n+Ab8X_Q1)3OoPqD8HLT zWPwhUEw36gmdK}EY+7A1!3ab%LVH}MRyG}|rgwSnb~&@vaxqoG3lr6~7*2R6%eG2= zTBC>vXO_gcNVah=p|+}R$MhrqQ(sp19Dbo0UDhu~s`z+;DBdo$k|Qs$`i~-<Fz>6r z<H|Pz^PGUkIc|1H?uO39=9WW~25i!jxZ-+oF*f(ILuA_D2Lh<qbgvs*StDrw(LetC zAN}h0|L_mIXzP~o{tU_VcXQsXN?PpHQcEqh)KW|2(M3z&y7l(=edrUfeEWrGZeLrL zWsLv^BzNV4*!K?c>IP`c6Af>u#u7sl6UTI@0<nRY-gAuMr=$1B8*%DYVhY$waktJW zFy4lLB4`Z=C_{0>@uemY?5YQuW`#~+)aq3ieCs;Ul<N*}F#0JGieA6p>-Ay9imERq zpX4P#%p+zDp09v@#k>*4ku|@tm6_0yKsMeGS8zxcYANCrw@Ty|YE}5Z1@4FpaLox_ zW?L_g_q?l>KUzuMtRkrvxTh|fEB>`!cMKz=dHum()JY=JeUJ}s>_;(*VXVbWt#?zM zC&~jtVE~DH4b7@}h7F{=`JBUq`g!!SAIL!_^9+f)-87a82EzER$YSe~z5Dh*@Zdv5 z!TtLWtQs4ws@Yc6o|d8NPc%H5fAbd9GH8S4ojKE*mDv+B3dY>LQ3oJIJ!|GEX0*h) z(Mc=<+VJFoi<F5q+3P`DH?Op>LiAS*Q0-?KF$Araa9@f!fl{D(A_{0W9Z{aL0Rg*J zGMay)q*X|D9Vr)r_G>?uNE<r2bFbyfB(I67Ucb%(oW6DJpI`H#%dfuSSAYJ8pYo)~ zjg77D_4@UHOW=Dtx!qDrEw$8AOPr=+WTab`WjztN;>zn@_qGq;cISiVopM5*^6vF3 z6d;HK4fbYJ_6C!?Go(RD;FdnSyOG*VvANX^VPR6Q5QVyun9I$Z!4#njj2YZ0tx=<{ z^wT)YApvzOz7a?eI!%Ducyxf-t8axC-nDs{nN$!03a~B&gCuU6*K%tD1j_dS?#9#x zhg4ZGWid)*5@}lLLgs=>E}2^pRF#<`rmm>~LuR)lr%+o;rX}^HlMgVG<|H-|p-k;f z3+RF$YQ%cmmU~9BCmN?oAPr_gIw53NlMQ3t^%9{zHkE8cHWLkMH_&of78(9U07$1m zNpw-e0%GNjO)my^=+v8$8jNpy&F%|_0*pd?!y+K~iFs4Y36It)_VzU(y#lU5<`z&e z0~COKx+|G)Cp{zX5lsq*#bT;Np?t0WwY}VZX)<dtjx=R8ki?-dDsJrW5IIthDkyd< z1deJ%VjJY)I?59J4^BL==Maiw!`Si_%SQVZVHUDEp5h26!^2;A-sw;;QXn2iIRimF z7)cc<w#Jh{kpnNcCup55g@A+9f)JX{0bl~FJqqR0aGu$4R{NzxI6*<?O{`&8v~?W9 zi4|xlgcG}>N3femIDwY}$Y77;5xpC6oN8QvySIoSjU${GL~paD<@^v%JiE5x<}&>c zhhMCw7`H7$KzG|m{T2Iq(7F?CF~%%Mqa)pehbL~jbN5fZ;PF59gU>(r+_ToL9qaXa zRaKER>GH)+Ew$8AOD(lT^5OA+Sx#4Z-*^9mH{9^mcYom1pT72{Gq<l>IyzG04>Ysf zV+UF|IyQ6b82yCTr61KceNZ^vZWzLbCsK{?;+Q8o@!&8|3NyC}G#5fPaYzV>QD_MB z#9q-r1RC=Mb7WWP8VO*Y(2AqstaGGo?O$Xi^uW1JuozxEX;OkrqQA%{n&Gf3|MdVS zcCZR_wkBp!F~l`0=Df^_)>t5ld1B?TQ#pE$3jg8&)QREK=-=g%V!?0zwR{NW35Rs8 z`e057sIV+_9-B=sox{#&LHIuiHb#+xQL5UfFKSAoDuuvmnhrJ!_MJE(LoyCy<6zYl z*mr_R>+kfLnE}AQVIn2f51Y3%H#uA+H{)ib0l@VMolRR#O)PS7HHNU2xAq^TN(0f{ z>i4v?-<g4j8%GZO*t{cx@$H^fiEmA!)Yx9|+21%+v}N3=MHA*aled>WquDTK5;@w! zVSKYFO1RemHo@;7HIy!@fcZx%Kw8`ULM$2Wu3xjf-dv*FEvt%X+>u7WfV}{d402~e zZ6V3KZPk!)W_^ch&OQtMsC!o9<IkAhe!#E?F1c$xN%6?$Z^&qJ@=@l2k+FtwX&XuY z5{gKiLtDp50p0l^n`G7=1HnkhwJ?bO1oJMy=`X={I*NIz!GKCkV_vbb4_0{<if9sF zs#Q1(zVokj?%M<j%)|qxm+w{6U{KpmSoMwD?)ty)y5!J(I}aQ@xNhy5<;&_0vs;5i z6-6<d1Sg9{m<MmErIuQ1sm*kgvj;Qix+5b1s)~2reeWkfb?KYl`o6#Yw+}2Ydnb*L zk(`FyH9wCi;HF5;-{vIrpxqn^%uX>$QNwXNa*51+0)*^<KST(lN1{M>{w@X7paD{G zwl)2PYF2Y1I3g0$bHo*#X8_^|e%v{%IBt7aM4E5|eHBB{exNyqxEAt9*xF^)ZXUE0 z@B%^L`sTw~USR%~xKHI{DE>w}r(?qZRb$kmLL}QfzllE(aoN1N^z?Ed^FYu2BSarQ z!5ow(SYG3i9^gbIEg{w?h-)Z{YM`hBk`>>H>dr_7u}x?pwMCrI@QPwP9TA9E{LNLQ znt!3J<dnBySVzl0oT=K*+iSpNooxheduCXk%{8$rrF9IUVDnD@w4p%7cUCmNr)At& zeoxDsTD2siT3ua<Z*OQMmCiiCmW#duTfW?v`T{r>_FF9nf%DmT#kcMyw3_tdpT^Xx zEXa^vJ)mFf{om@%=DWic-=dZ|w4<qW#PBCWEsi<RI>{A!$KwD6xo}%qW_UBTQ;DrC z$y{rSXiB@&@l0EuVCzj_OId7H4Ub&wcFX#|ci*>n-{IbA+t)wsN#{Q6=}+3eZS%?% zE5^pw)XDLF)vqd6RmFyimRf45rIuRyE)iy^1W-;>r&HFY+`D(}IdI^>w{E-r(krjO z?z1=Ede5HqD@Ql1Up2kST)%=@4-O>e2S@&6HY7B=Z1~{?2EmUM<*Low-Ovc8HqZcn zhw66YrQddpL^9r}FMX8-p++1k)tI920JL_Z6@N-FGUq!uw5t8`O%_a+DrYEGRm#FF zRyETy2|b&8wW#G33<;ytO;fZU{JZTHd!uJS*H?RvTq7bR=D*9OmQjbZBHKplC=Pi- zcg@>HD@Svy1Kj(6eqjUI{7VPtsJtiHSrW9%xAS_kYLyk=x`)ZO-Y_aw*Ti<Y6npU& z1^pwT4#qfhKs+<Sh3|MoY@6F%s*z1wdWo}eIxCSklTUp6<f=JgMX-TwUS%``A7XZO zxdk|}q~J_Qld*LvEtxiOkPErQw`c|hTyo8VD41K|yJbxVMb1H;<e!xI12$D{M;w8~ zx68f3H{$K%?r+lEBvHuZ_*}VN_#r|Po><`gWIt5cyzG#PZxp7RYP3|O6W>+E*+)ts z>EOm-{-+qQhorZl=FPUo<{@h?b-QTJ=1-O3+-MW_Uz+@7QfQCDVtWe9n$C9{|32z~ z;lwu*R~iG;1gB_G=CieRj*Sl#Mi~@|?;yen3y6rw6denwo&4<1y^c;UnfSKtyH6Rz zBb>~}K@&t=c!U#U!e)C0+P51#5&9S+b@qIK+&5u|K7OoVm(w=?dK?tnpk1)tDa-ob z$;tkn{fBP2W6#sh7=PxI&N}OiQ#NckVa=M=V{6u|TD5Y;@?}ewjFe@kXsM-^T574K z?-KR<{fUXm0|yS)d-?3%Q`6pi@4f%4H-GDrYrcBJ&RtK~wr0hOrKA6ky|-YNCD*n5 z^{cbH?_>VsFb57ZGtXBZW@cu_%iMixUFdKq)N7O_yY`-kjuR)mvoe*kBs<e9<>e1w zLi#S9cjb`9SAZ$VcNG)?3!%746&WJXx>S>NIF%!aCCh>DLVgmTu1gJq`3&dD;%S9& zR3=8E`=#wY6GFczUIYUK+=QpPM&EkOd6K_7d^ZQabB^wuC*5nh={4m%2}vu=5&<u5 z*#N%F43#BCy+R%53Ch2;E^*(ilBUYWHF2g|Grkm$6c^&acg^9M`nsn&=`Gc{|C-h& z=f3^5t!L9I34A;8x2w>*z3<>ztzGC^YMDQ&@{70>h3s>oLaPseBv;vOQopz~{U+SC z^G_Fw>NyB$7x*T7Q^G8Drg$B={Q$E#Pq1L_i&VZSOBxd*DL^4acG=P;I|`!|;Z!Gi zPI0MaeA^_Pxa9aQ!1p~M)C1p6?QQVJy>g-Tq{BS|Qmgq)ode%jR3|3Gg&Y*{Y<nx7 zn17Y=9lOAHb#bEpBv|YI(gRLnBBsE%?5jf?l}~4)Vwmd*$9EuarS$Uh@{4}K{|kKc zn;-q#|L|Ym-EM8VdxNBzP12Qv=G7XbV3xJRq!rygP*;;0s`3?_cd~<D60P^Z_hmz? zw0+>)IlhC^@X{k%i*BN(0q$$2ap^3CV{Dh|I2&vS_G=Tp)iRtI$9I-Z;Cm1rgyhSH zB=IW1w?8g@!pAl6-AU7fmsKgclF8<^H<q5F?6$Ix=kP9gdAWV`@yGxDvtRy)|N09r zKlI_R`-MO9fB)zY{>Tq~d#8l&`OIg&vsc(9+osB7ZylMEVrIq8lTB?m{pXvKyjj`b z{G+SXSN=9w=sut{Z|z;>`O*&yR`Cl^ZChWVkEF8v&|s9D@KGmMUB&4?t)guq9`D%z zJ)@Ef@c>dj<En86!C}XB<?9|Cu`})5XG^bX9v^gEdAD*og-~+4HI{zI^A_+Fo%Hdu z=Ee?qq-b-a{@N*uiOXw50^j$qf8(RCeD&*}|KeBv+h@Q0xBu;D<D>hp{Uty0<3IBK zFYn%cJH`91%zf=RKH8~RzMBC^GDUH7jMo<m3{=USFS{NCzO6h9d`HM-oCDvFyVyl4 zr{&XWOn&RYcOIH_dQ)Dz7MAC{KJ((@=5ZbETr&M5Bv*R__?A>q70C&OCv?&w9QgK? z0#cMmwA!bUyg@O__*UCLm8b4!_xp~H9)@1#z;{=hCl0$jsR__$IKI7u7x6RT+xneU zAuSnaw9&;YbQ6jmHf=pv3jUjS<KA&JOLiTL?~9t5U|zeO@hzXP3W)4;GJo|&%Jxz+ z_3ulM9{66cqfFf%_^#uN`cc1J`?BPEu+w#gC0&M$;JbH0O*E5b6&6z#)LRaE4#}~~ z6->#L2EUPU=6kD-ijxpaat51oGzPc8P*oHP(oI6?kmW{fdjiRG2uY57O*WKvCJcXT zzR;a%JXq$l)rO^lp|yz+-=P=0alb2HH#$F=ieB*Fb{hQnl<p+QyHjLt!-owL$}7pM zE?TLqI7R(+)YmQvmznYN4ce>Igd#v(hReWBgU*TlGA?P0heM?~#lw0YF@rmFEvC0g zZ>F<;Kt%9rEY<j*{&6T@(y)f7qjp;AfDt|$AS&Qx)IE85TDneqCA|;5|K|M$|KCsi z(9i#WepI@D^wIk-eDTZw{eOMo+iS@``dIh7f*|reMIoue6j~37^<pCh>uKZLsY+oB z3I`8Tg@aU*27@1UlC5Qqf->9{L@-0Dx0tS^xaB4pI4(R`^2{p$*e0%To&Pqxt4W-L z?{jp{W%W>Xak714n8TP|&f4=rvhutTckUzO9O0sV^32y7i0=UYUeZ<@Ov>;iza}T) zin!HEddE7#Rk0R(MN!AAl}L1pkT2caT)}*UPXyk|6Xk&^iM&&0JK?~7t`{ZGAzuSh zM%lhd5%1uG4{jg6y!-HjcR%v|AO4YF^Yh^L@%wL=`#0WyyuR@0g4x;_I?0Iwiah52 z8uFN8b=es`53bxle#UNbd$3eX>~X(XOHsJ8%uF+HpbJ+kgt-OXD^f6j$M-FgYLfKa zf&HmiWi8n5z;$f~Pu-7AGB?fRL4KvWUqo8ElK!X>okxZL)+^L?30Vi6v)1cD7&5@* ztrY22JMRCimJUL)|D7iKcjw5m^KFT$+PS7&(#@Gzd*_os^#ci=o|+GfIpY`>H$Icw zvp-<7iD)#5YZmWV>=(+-1gxvSl%27&yTeqM<E36I*zF=h(f{ZIgFK9(M~=+2xd{dS z-%rDv^Cr#HXCI!(P#i)Y@%{Dg5N}sjCswgj?4jat75*SqC0fac`ZdSAkv%9|<H>6$ zp7*2vSUOJ1PnNUJPm25fj<~Cj3RA?}tv=16mu6z@kG@0LP%vK^Q^zh`sspQK^rjNC z&^y#lQQrIz6fI3h$jm?w#CW|2Gu6lcf&O5hIR`3cr8&g{Wl&NHQ^;goN9d9Na5^Ih zshH@QCx98n7B-|q8WMZCSdi2z=MhudoQimIed2j4gNaK;<renNN8CgAkM+^}`zHrK z{NUxo4?c)bZ@{evrAYuhq{?uPY1eYb`QI9c$2`~2!<D`tFvXbd3NBH)LrCtt^sVU; z*5}`&AUx^o`3CxK0`tnx#xlgA9W6h*Pvdk$+AYeS9K!n`errR{R~Cmt-V-+v_vk&x zkOyOu2-jcJj&Yd!9g<_abmcRg@cDzcSc-3a^L_Af$Ts%tQSW*XGc{1sJo1^VkcE|L z*cAbL*@6lTQkBLp`14Y7<ZXMWgB!SYdi*l04K<*KD!3((Pm#PY4)94FXxl1vv=dt} z+T-p_-E>i96cB!=eeJ6O3FLO`*EuUsxj+pR73GtyVjq~e<PsRH*@t13A`jt_nX)f6 zIGJnYjvldHM%2xW=EX$f9_|T-9+G|2n`RH5U6YAypx+fD?D4?$Bgmv^JZ+sG@}k7Q z^YNz8A%fvN3N5m$oer*0kv9+|A9JF=E9rfZ^5%X<)n`8Sa~g~ngE8%oCJ+?R-rY4< z^j%w~W&WZS?3=~r^QXmCl{Zw6I=U@#P(3p0{%X6GLU#Y{_Y&QSn|7A>tOStM&<xUO zi?>ShR_dX3)O6PNJhmr4rXT4-*9rJ`vdO>tH~;aIo4$L8nl9EVVvg;B8<$qE@Zxse z$>P=S5-o-aTn}`S*RwWi@~~klb;=L4Ub>b!IqSS=Dn{mgn?K9FbFNTlBiX=tTGSj; z?X<oc@44c=xZcfUi6j`a;X=}Ix@d<L1hU{Sj3%}(gh_RH-FWUJ`<W#7a!$(qsCD=C za&s@dYv~>NLix!uZD%{$cD4%f3G-BAd`l!(Qg!Q{GxW82|Fn9eT$eE_d1uYz*Ekmi zZ*G8RgS)j3=~*D!dWBW41|<9QXIqgQXHa3wV&?1WbkuDmMniz)IC`g66(y@oRxfld z<=h%{(XRH6eeaTjrael`QYXOoz!(I^f1?K4FJD5V`Y}P9)V%`L$mxs9bO+W&m^??p ztKRrRvn7<|7_JXa)LBMH?-D(Kg>1#P6?y%sBKdnUPl&5v%5c-Yz;x(e!v>Df)z519 zjZ8}&8(6LjEg#1~jIPnD`M&$3am?QF#04*u7X>3ofiP8dIMTYy8gdFVxy@4Mn_Jpk zL`rG)r6sfJrEKX%h-OXoLzPzb{KKsYN8|U0rqngq8o>EJ!=PS-qq^Hs!L?g2v2e|A za|tJbBDf@Q9tiO+Ic(Pe#lic_09`^RWKw3So;0`jr{p?W=Jc1x@+j59b^!i0%<WcR zcKQ@R?}MIsJT7>1T*hv3MYajP>zZ>?>bP(f2l(M}$~w1XqNj;V`*eCse;L3sF#Cw% zVQL+wzp*E`ccEvhB<*0%3C6VTR~{VlcNlEdpV9?RA29SNOPyepRVpUmQ?!khG=eP( z3*`)G6b0(6<~N{U&w9dB!B0NJi5r;BKs;bL;i^A+oi}4RiRVh+Q7AYrZbc8XWart- z_%K2h6B(feimP-jKfMxgQ<rJ3olOd?K=$GCt50u|=_ubl1o=W$19w@D9`&xKxGf*! z&<24Fx9N5RjWvj1cdCMMLi~yVM?ejW+nNob5OJ%XrB-IMlhQ0v5&v!v+1T9d*Pr1R z=r+Dg-)>yPWK!8JP;jxbK}`*Rm@|i;r~URP9Pz!Js?_g`=EfOThRV%-4H-bqiP&QW z=Mb<;dB?Ge9_uQ4*Vy^<cNdboxb0p_J*{`KI4J;S)Hf9c1l4FN?*LaosK0atRItkl ziUvJ~&bpvjrU<*$oabzhPqsYJAOnKxpk)So%;hBw<emTB>NNtTn^=z1Ae5N(1Y`a7 z^QcQHHD>yFp7X?Hy*}rO&Nxr7-<uPAA<RKvD0KrUcR5e`HXp8abY7N9{>xzR^!9|> z9pxmS8)nee4Ha?oR80{zGrWCJ<Euefht!8cukvP7F(>3kj+m<!+WGOv?>~NjkMFLh z<VGJ_CcO>|=X*3@E$(H_F~dIowWlEl=PSblHGp~=SjtDI>a3(|l)LNt?`gp%3Fm9s z&}N*n#bML)_VfiTyLA8_Br}teBXkDP*fwvd9a^(FFL`|fUfcbuN|KF0M#rLcM7eJ4 zf$54vH3gA!l0RLrZw>89CkQ<Ynxl|gdRmO5$oCoE7OU|5WwmfV&G${?gpl2$s_lW+ z;rMf6JBNJL8ijpSF)Gu^p!-iKY48}H6Ti8%lrc{TG-*7Z8~W~?Dtp_TRw0}5m5fpz z_y^-by7sXbWBs}};A3vwLh*$c=05W3{>r9)T<-6wDZ_~i?B$yfd^d#?h7%o9Gjt3m z=cTuWFHfEGsrZD?XHuOaJxhsiBHu5B_UDKnTGi~uYpWCb?YRm^8?aCnqm5HeVi1YX z;2AoE<b2$;i+bfl2Lz#e)XOMy!-D+Ts7&ug@WXzD9?;#!dhv=wgYt@PAI)+U`5RiE z65UglIr!`4Eidhi<N%W9l_?@VcP9Il?NW8d+eL+3n}(k&_V&K^i~F9HT(JZqY6YzU zPVy(3_a>8#SDuMfuUOrN-cm84%U-uNMBXwos>}U;`6X=)33Q)Q$l*}(rwk|*w(k7a zd}L&4;Gt|Vx#KDXQW?(cw1gItwjZFQr=W74AcR7rDU8YP7OAvBqx#Lq8GT+k+e=y# z*a$tzdEzR~IZw*Qg_^6NW>@P$rZv4M_sLg`(zRm<oSIlu&Jzj3Qk8Ildwz6&DlUy- zOCKq&cO<EF4*&Re%U=fGx9}T#Kd(K)Ts&Oz@Avon5C712c8ibD7r*q?uYKdA+l`QW zc9`v!^>ZA&=BK0HCc|H@rZ7w}dn%1qep<a(2dN!vWK{h#tvf{JnpQ(|;|n34Tx>mX z+>XC`^@p=-N_Se9tShe&Mp#>vs{K}}I!-9+ngDpz&X<&FlnlQ5acp;w8j*;hq*>;j zD}?{-@B1o?OUB_>KESvJaz*xv66UHDMH=pGDQ~l{{(7FpeC;vQx%8U-uYrX%;*T+5 z=3VplU}2NV*m9t%hRRn=jZN(4al#^x;pa&v+F*WgIiWfDsM;F3MI6kuA2RUDmytb1 zl97YCbRB&zM@P-l!OOA_S99K(p5LZ#-@Z<=L$0;=+NlcG7L%bg?OPW)pNdD!c>5a1 zt@}-Znl6@C%Y@25k>ij)Hb2Q0A}S_i`5`4|I@h)*cx3cwJxol5FupXkL<YAOrlzb) z>a$)0NfCgQZ(wQWac=HlQ#}m2c(p=XfqDRyxT4HO+a&51(Z}Q8D+A5nw(xw#OYibC z7VVL=*K1&R{O#S~Wncv&Lap8wt18i6;+(Abf`qrWhzG(xQ=Gci)&;*J4dzf)AEA9z zK;*D)5h?J`auhmqinAf?+!WcdaN`C+i7b^wQK(7tCef_`xX-MbnM2B72<Bkbe4Z_X zx#>A3UX}AC!Bf2!=ZVaq3K&u-_L&Bqa&j|E5uJ;tkg#-QY$GTw^|^_?VXm<SO#ZbG zTsG99vS0LATY`OJ4x<y%Lmgc|8~A2~EovsBQyNOl>@V-${pbJj#XtP}f9o&(CBH}! zf9Ws%jlc9a{_#)z==Z;Wudy$zeLP3)uc9l=_d?xLSo4cLa%8)cdwD9rduAFb@Dykq z&C-R~+L*Ad?Du`HRVTt7H}RLbIXhY(!ySc7BXfWnYq<E;_i>?XijS&Bb<(Ht6Ka>E zSuy5=Dv90I?CXMgY<I?E|ApK(@kY;modF^wQAzI4b3glJP$nzyYM`pn1GFC%L)|Up z3-89v6)wy!-*=~q&P3>0ThCqQ4)MYuhKGe-XftzWKo``ZKX|%~1W2W)i1y9Gq@HqF zgf<yYGA=EhfQ`Oszwfiz(EDO0cAw!yKe-GixGIzT?MKDAuz`zv7sA6#A75h;*i5S8 z(CSA;z?fspZ{7vHZ`TWD@Hc@X#5&*uHgbByGKgs*8jurDC&p^XC~kqefYs&u9oe|J z8Jbfb?n=m;e!%ofv)>T)1*k#TUbD=B)D>3^O@x#5l!}#Cg;M9(aGtqs6#_LCKRN48 zC!h80N(RS)5Z9zs=Iy$+N$BYvF{g!Tr4h>lBEcfhqWv0gKWxEiQ+<?h!}cQVV8z5~ zuvIJo$V!hk`=w4aU<NJcm2rd|?z_<(x&^3-oRj9FzN4$k7&Hs;#l*Sn2t@>{<GI?s zjoixks!xB^xCQ2%C-GC6^Q2i>zt4H%h2e?ytC(MLz<GjSIp%!uj_9JsE~a)t`OBp} z&gKiQPdQJ_D_pe(yJtB}8#dOfeEiY4pK#o(TAB!xc9(A7Deoe5yDg*GZ3dht#BnL< zw!7gxPw{qc&queT)(BM7Z))s8NZrLDHS?bNNZS8khkCK8f8RIf{m5x1`(WN2r)h~r zx&qfdg&yf@`y9T#GCtR>>U%a<x&Fo9>g|B+Eyk1ly4D(kFQ?zmI(<skCYq$+I_Gc) zm>ArDhQuSDiSG`n3mvaFQGRb~Zi>0IOsX6R$7d3_W~_(1y0F{-a@SH_d79!DdH`WO z7(>TtM1RqrVK77|&BQdm?6t9Nxtk&rNDz{9O<%u2A)|I=L{|<WryuH@=i%sE3reeA z-pZe*8mW+jyUH`687|JilO+t5F-1*nUYFrS7yFlLvOhVyz}13;iFiGR6Sp`aXE^Df zEgg!Ihdk*<p*oZDk=FQq2&5r3Qa}8ZehUPVT_N}A&NdhRr*)-lIpVq;^Dha4qr64U zRMevs?NaE$wi_vp>*=T;HWG*#&dep0`{pHGr4_r2E3;PO)A)_DVhtncS|bI#KI;Xq zNeto_$Sb|{uCA<~SDwDsTQP0dK*(Ijfu_$hnX4t%F4<VVt!1I|t2W85af`)!ChGI$ z9MwN1iT6>Z2MT)98m64ny(8P}9V&;bCA*NDQU-O;DP+7&s?;YmG-1X_Lfrua(m?BK z=!a@r_f#DeGK39XelpWEQv!`SPo)2YoF};&UGX-YCr)-zSUC$*HjH>HMp#w1E^O4m zea;j2HQwiW%EWGrI^lM072)*>*CqKXr}<PK6viK7DMxm{2)X0dAzM1m<xFZa2e7{e z^JP~(J8O!QzW2iqzVxLpfA({qi-@m%?HeDw+|=(WK8WtL#1r$O-2O&W5}W35uddNN zk(n{wwQ^8IUC81$4*bT~Sd1T~|80J#>6;43zPUe^PT7a%PXwcINs@w@*9p~p?miXK zs?Ac`VylWLHCz<t^cNrKB;RFI{d?*dWj$JtFuzJ(RXkrVC29L&rHMDMr)yWrV!z!S zHQj%c9*Qy+liDtsT%BmuSXMK+jWE@^Qz^~2-u46TzPXYEY5m$PH_rTPlR1{D%63m} zt&F0$Ku^B}+6tBQGj70X-<NCNuXQ@}veXO(*G^a8C(l)Jm`vNFy0&htw_rH2c6rTB zsUzV&q$gEApPswo6O@9A_h5QdxWQ2q2Q{R8fmWzs117}2ddQFxk;-E4C`&;3TlR)p zqaE8SUJsYK0?M!2EeA!r*&QksD}^}OGo-6De4u^1Jq~4E-zo!CGh5hb!+F-ZI`-fm zeX&ZST*d%vzt$X#6-i2*Q^oQoc?E$yUp|jdD<&khJCinOm)XRP<AyCmka?k>6j#q0 z|08{P9CMVS)9)kp$<3%kAvBk%%YJ>0TIbr(Qn}6)Py}WI7;Up!XwOY}pL4E@Q}F35 zG~-RmSVSn4>+SYHSfP9aRllvY`h?b|kQin9A|cC?O4QqoV8lwT>AR37G!5?1{USLd z!t<Ob`xAR#7{620Q^?G5-$ur{A<Rh{`Axg+rh5&XLYY2URn(l0-iF>Dzs9e+zMTG& zli1ggY!<D`j$lJ+KmPds<3IZSf95azov(f4uS@YmKk%6!{QmE`-|thoHij#-+cn%) zvOk}*oPD$Mjhk2Mja;NBhb?h}r`)Q|lRTPqbaRtuUn)4Ds7X_g*oSm%FYRy`%lWv* zbSJ}(>@#Ck<QZG<{1RU9d*yX_+G1H=UfD3}gy2G3E;rO27r(*|aRLUTYjxTCW)AIT zbH!+XoNsP`LXcPErlLtTtZ@&Nw3y+XqoI1>+4r>m2AoT&3%kV7_f4}kXP96!?g_M= zRqIN)KiB2P{Ikxs@62GCC$^km&^fIY1J5>+X*X$cDu!#dcKw1OWfnxE_U{C9OMme? z3@0)n{q1^H&SRiS<7ZFUd0)W{dMPm<p5z)J<>wqMUQ|~`3x#UDXpPL+Qge?jLhAfn zmj5n!h(JYRdtI3eS$<q0NU?28ZYk66b6cZrxq^byHxx!TWyh&LtE!OR=m!utV&cLb zDR!3qjNd_+T19?q$5_i%IJ#CU479ABhDn7vtMc-ZRo1S3INMOqOP=?4rU^R}ulQB{ znR6ko^M0jo*X-JG!(zK9+KqfbH_zI|W@?*qoYA59YK2;nAfjRT(Ipi(b7-E6iV4A= zI?it+1%cnYH-xg%gYUEc+>L>@vu@578v2BrNz{6BQ@J3VM1<yPOT$+}NGS+~Xr^(O zv6eSjQtdr}^_WA=R`tY<km{Ex+nX56fOR#gYq8D<G4xZ5^TdW2Z$sa%xdHq){Og5_ z-doiF9Ont+jZO!I80o#N@dQMIQJ%=UcvtYLe(BCi$&znW2Yh<XVW?fDuEFezNv9|| z8~eUaqZ9TDuDibPdq4dC@B2(d-0yeEl^RDkgQytz1;;%0fj5uPKJ5KsmrB7l%&dWN zf5@pj(zrE(blH0}Za3Q&2gXT&`@Jf3#X2)>7Zzn2sYLV(gEBPiiiDD})j#c5bU|^y zv8ELbZUx8k0Vv0x?T;hULi;rWXlnbIdOW>Mc8ig7vA<1hJ*qPrUQ!%VirN}N%`5ni zLwWvUyxZ|KFopVI(3+GE^cKixPin<ttkc3qwO!BEPNk_?cRyRm8#ohn#sjCp7ZjO4 z>(I$Eh&toQ@2m*XDAgM$J5hh_C>(u`E@Mr!zIkMHmTXoe6{_U39t&pA?*3h=DzK#l z%|o_GYE{uOletMEm_I8{Aa6M&=P!ce;O#FF|J#rE5VF(OFOK!wBe5&c<jj$ocDJ;F z)2qTdSUo@)bWy5Bp0&C~UY&E4)FCUXprS3Yfq($W3c!tkVBHS;w|Xbujnr)N=xvF> z{=LbTczC78qX-cZh)`wc6YC$SDA?XZ^U=f$PdD+hXi)LKaOoPlGq?XSt=RF?%Jg51 zD^WkXVHO@0Jws2!t9O{JE8M;1*X%5m-lRHOdjr{5UtSq?egC)p-Mo7PQN0TRS&4`n z8Nt-ycOCVVd)48+B8F=uhBe_OZl!5TMkWCA8AV|XuT!n1dA(68Kq|=~jR4PGuL!BI zg-cQfm6S$oshsVr8xcbn`)0{tS5#?wmh*%F0f)~D+2r3dPp#=~N(%&=gF|B+>nXSZ z*H+H_x4oj8Kn~MtI6~re+59Kd5|VLf{fH?x*IhOcGK~rkgVe}Js+@AF>Of9W=iJ!W zIqj`Md5FSvc9gTE5xVRB`}_O*T@5}nFQ{xCnlB7{g-{w?M9SI&JNkleRmzjAHe})6 zV*y#!#DhL^`ss8*#Q32s`g!z>R>Q<a+E;Fa-4y_ahjTbMJaUoNLrvJ3=5>`edEU48 zj+bQfp;aEY#GD68%DP}MK-ir%Tjil_i^-T2HOqo@J`7brnIuGISCDGm59}8C3!D_p z*KTRHl&<%J@obHJuJ(+o6LJc(-J+~%J~40D*X5#%{U;6F_xFB3(AhS?t*PbW>!4(J z^h;__)F@D<_7Zim-t)z~hiow#+Lu@*9XQ>U<3I-)6ikGMBY;kaP+zLz;N+}-GVk@> z3!!FRq)&pWw!_|7jN_A3-$&+#w_8`(w^T3HB?TOKQj%89ACj5hO}5OpwV`o_4iccL z7vm{_az+so=*h8Gj6`>xFLsxK@GSQ2Obo(*51Axc6BSO-VwQW;f>qu~@*I=hEZV>w zpOUZVZOguK-sYxnSA2c|Sk?x$M>yD4yVYp4;CX6qFFw>{1&#CLc`8j;m$M}+8c?*W zV9$0LtBq|gnoK!7mXq>_P}*;@KS5a;LuXqQxP4@+RD!lU<EZO+zat1$fl}6ApYsHe zq&Vk1Ic1)sv4Mi8X;k|ct7$KmyLkRSszIhrBNjg+yq{I&ItxFab86yC{hSk2ty?ry z(r6wT@_G7?>~toRte&pcTROjw2;>`Y6MIEYodG?U()pHWGkLo7kL*}~v3fc4zUmX+ zOC>do3P7PaW~d4Iu5GWdN4GjpYNOw&4hedmXS#np`j(Nl&+JP(%0d({ROL)4{WTA# zF>L8G_)R9j2)m2l!G&;b(CICPU3nyjoqJCx3M|L47mqhX0o3LDA={g?uq_9s2-Xdm zw2J<>`427U0!MIzae?C2_A8Etty6}Rb~OU0!HliE?9z5c>9;^gwkpOb7Vtx`YpF4J z4gCO09$UUuFzcJ+{bS2bd=Kj*$|G~kTt!;tY`1IT`En%#50kU!{Hno37|()|^L{1* zE&5ynQMh|+O8_aYQs}6qs2S)t;@;8|ZDHTa-W*+)yRCM%5yAc_!<fj$8g-KI-BDWS z+7fq4rFRydYEfxdy?y?I-`j0vsE|-vC(!WY@q<m*l}j?^<ZXbZYlYUX*~Fb21L7yY zxEZdS@snNf%1>c@cs}TkDvF=%(#9}!t&wtE>{w7#9@_bV(xdY&VuiLMY`{GJ`ddld zeI0C%&JTzx%0eSul6g?3mBv0_Sombi^yO==AY?Nr7|u<KN)}{QXQM_Sv3MEXAI9!e zF$;P#jkf%^GhTu71j(-*7i?2~!xj5b+8z^oE4gtt%;Ij)J`V<XLckO>%)->%$^GM5 zSGrvPtBZ#7JW}3M4tQ^r@@1?cGq~KpUz{WTIQG2-Zpft#hI|;OuuJg_8<Bf_AdKyM zc-^hZB{c(}5+bN#KG_}V7?bR-n*%5tsN|rqe~B%sV&BDH@B?hO5IWFCSEDjM*Te~U zX_6+34b*#xTVA1r@$Id|;Ar_5R$oQ%I6&k}wwu<NU;0=i6x!dTQKrUxJ;0P7Eu@)P zyh|=2E%(Wsha*pS7g)Q~p9(2NP<8T4eFUpjRGMK!?D_M^JM~<y36lc3<wA4f0w3eu z!Hk2=q=|=j)AaMpgDxZM8)ck8gLGqtNefu}(i7U+@L2tg<cQs~v@&YMiTRg|BjS=t zvuod=6{`oa0t1E<6E{<{j|ZEEB3>mC((8hDxuLd%`Zdb;GrI=NV7=pMBRi`OF4y)# zK!3IU)LbSqjaYT{eO=j3K>6L);x6IT1@#0#R#shgt*$OdKM2D9Y5gBeXfAxE^fhRO zO2x`4$p$283~4q9v<_#Z4++uc;M?2(a}&)$!~P<ueXp-T0Cq`VaUs=R(O2dwMI5V? z&B2WGeA@V1{~IvX9BwpKMY1X=mitO95JYip{<A;FN{)Xe6wmPU2qIAVw|)}!<l8ho zB~1rw{3!!_v(CAiD!oj|&!|~Il|QSW7*ygO1$L1=ApLo$%l6wzlxsWeSx8q=$~Z#Q zb3b-!%YU1$<4znvfJ@))if&~^U^Ez`+11fw&17ppf6+p^u(gm|7BuBmPs8@%6V?jz z7|w&CX4?>m%uI|)U*tFRpBvTWm+I;gGt#U#^|oP~+t~!Nq}h9=M!I<BxJut-te(-9 z5;9euNeh#;3dtcj?~!Vg<g=G3hgWI*;Fr~yx2wMbZ6?=B=4wuM?xpXMrpi8BsJI?} zo0iEnc(4nu*|9<1BuAbfy6Gj4)Qms3AHAo%q@1m_?ecZi^VREVo&Ak5?Jm!M?2^^N zSYmftR=r{Yq-)BFW?hC{*#{J73V-RjZo4IrX8Md-NdfyG&>CtQqs`wduv99x7yFwz z_axecWXb&Fpi)hI_1^__tNJGU9omAcG9J-E@X7<jrE0FEEgP@|^5+YZcgdC}fcBJH zH*w0q3^ZHIh>6XB3?@*xOr&c*8;q1bE#m^JyK?oa^gW?3>N#4dS<uMkdE>pP1uL6Y zFv^&tNcNgK6;Y^I5_PZ2ga#YJRK^rFyH-n{uGbuL#t)HWdiVV=?~|>d#1*||Y9gJz z#bLw+))A+G!DWhZNv6(92mkrjbW<=(R}_9(S!b6Y){*Xc@ERqZfD_BQ&)=Rk<(x`c z78Ko8ximtKIeO*#j>s>`1mbIzQkfl1XoR5NI6tZB<hocdVc~~YUNKs7bX22Lp6;Dg zCYT|*ZB`lWLa7k@+2>AjM1P{?OE-8<KXvaG?&RIGIrTf0CD*sNsOT@w4C1NesYjJb zKT=bF_WVOclSEcF93&)%DpIlrunU!q?UFl#!)HUqG?VkhB%WkqqxR|1g?rzw&0I|H zUA-c$)mS#c6Uv6>P}zgp8my_9zAMyqc`4RqYu}ZsEWQI7BB;c^gDoWO6<NcLJ}u*t z4&dV2<Ty-ngnGNvWG9Yen_>vo71BPbz!Ih&w(>S}u+1#W$)#olC1nDm#AhZ=RX5?2 zO}$NNdKbw2V@=g$pIcQ|Z#qt$sa1_5(|vcBOBGVz(LTVECMPGX2=347Buw12&%Bf~ z%0&#O^MpD&wA4*SGZWK1*q$rwuDYK~9Ts0Ot$iUw-U0gYsE-B;kl3t2D!>WrkW`M) zeEHPW^5g@UZQEpR?yiwsDeKc~_EpfUto#m|*Ey~g@+Y_VP{(k}8e-+#A)g?0bS5VH zjAx32g*-q=R4|KX;p0<Id42@pO1@Y3rD<P5<}&u>k8Qa-zd9du=dJL|*SJYU%W&cd zh5`^O&-7fK?F4QW^rGgB+{=V={bqe09FYucS6>suQUvGCVL|ia66-*=Hr&l(`5v-$ zZ>Ts9eAepkuv#FID}dMV8qg2PJ&cL5EA#-DaSSWZpheb4m1p=g=!K+wtp-Yp2&?3B zRlx>tNq_i=0R?yKK1s=23*qgBJa1tykEm&u_e08n!6PT6q02a@6@fYH`3m1vsY9Pa zwc_@>CNpyM8^gXD$AfEqX#<2|CiKvY&k>A1SdX~SmGyj*QA}8_AuLOr;xV(ybvW<< zkS8eaZ~O(+UtAQRPkt-Rp~bCu!VmH%T<Bn3BG>DsHM!t{SZOTdeDyu{%SjvP&(p>$ zrydxexlQPmlU;mb*TLs2sglyVN5;+I_=|)0e3cwX`Fcf%h-+esI>c3TD8UQ+EgX}V zVwXPe^>b+&$U4`;RnnH)`O@E{Br4=2F%cMOQEwtHl^9P;IW)?7(W$WW`!FAM`)>_? zIppb7uT-iNlPiaF%9Rd$uaXG^QjQ+BqnFyn>*~93zj(tD$9=kMyUlUYEJ5{LI_KA* zkm;n87N%!WPa@^9vD-k`Gb{DRG9jC-RP6v2j+vI8R_}T0?)F~8=qTrEbd7rF%u~#< z3$AyQ)qdFf>qoErwKP38y$;3+&7DG3LQh(ux5${KL=#i=8liNxEBE%au7n5M^Wx?o zuQZTG8&(yd<=W8cugW+rU$Mh%58%bVk5DLz9c8TFO{Tk?BsDLGZZx9cH>tJysQ@0H zhWg;|I!tyHHMtb0sNV<Ev1M0f4kNQ<+4h?h>oqDFD%B)jlR4><Wz5g1oX-mk(AW`B zZ)PgSq1d2QWZRMcTxm;=vnUOFW#Q|rNczfv9A*yI9|yCYYi!>Y*Y%yhd<7QX&?2Mc zR?kA-1-EZ%k`G+{_*PU=9m?e>(t|gWe(hojoC;#A%5?y&Gy+ydD>S<;Be+UR>cJ^& z<*^G=JbaiB)(_eG))FE;2s&SYuTZULcYX$4Q*$hxEbU2G3rnj#ua~Lqb`28iy+v<~ zEm5m;jDK{7>@Na6tv8bAz_QiwIt+OR!yv~`@^Ma%y$#p8c1^WYCh&<(6X~G(zK2a? zNA@XZ8o3(Xe%^~+%6Pb(*u;I$c-D>#;B1Vfp4|O;IIzOIGDY^q`jrIQ6zE;k(W<#B z+PPW3@V~dCqFaPl)qSyiWD)q1DK?Q@&5256!Z=Gwso*UW*YIGmIN34m$D!-&YvgX; zO+8mUqE(o)0&7uiKy^saqvgUHCU0|Z?oLT>#(WP_HI8$+bCYL0F?5`|k1>}VHP&us z%1vKaTDykhASb-fq46_QLo(#vq5YngQozoZ;Gz94N$>W?*6Dn7Nbup?Hgf3ezBhWg zdVaVJnV3eE!Tp9EoQSziM+Q>^IcOFqD$?+Kphr-QLWFGH)Me1ou3fWt-dmsuEu!&| zU40|eZ@p1KM3tpN5}r=&d#MICbSTIhb{^={^qlyluKJgSA&H3kCq1iF=e$}f4n8P` zv6Y}z$>vZi2JIFx^=)pS$)u0E&Rm+Yo$v;{C7_U3axE>$HSQ~O(DW=8-Woe0LZfz7 z50Mo;tVD>{qe;2YYZ`SXjFTsXL(MgWDIjw(Y4%O2j=#Yhy1Z%WHcNt|uPxJ+0s^%k zro_d1UW~wv7Qb2#uUo~3l*>x&^|19fESDP7f)=T_qzCcEAQ^`Q>6IetC16uH5y<&) zVK{K`>Gjws)UF<88_4SSuR7n{)>Y~`Pl)j^QZT!r{0GfBPa3g=G%%-M3J*2#(l_iO z=Ltv;#A@d|HyIBa5`kC?HPnC$3+vi8gA*MzcQ4J+L_YoDRI-E$b^Uuld4qd4Av`ne zuuCGl{otxOb%xnTPQu&W-jC|SfDI~YDxLH$HrhPtl9q=wS53ac-UlwfYS>`%Ek*;g znJUA~q?}FmLsQ{Jk;`&2r;_n)&Y|TzpaPxv*Zms55RzjxbcEiDn4{Fw#8plhGoCMH zIMnfE$dW$oz~Q&Ej9LYirUKRp@&O5_MrmIPAXGF!<-o2@Xf9nq3n9h3cefiv#QXPm zh4#5=Qoa<h=e*u=`$^?vX*;WLl!-=J_g?H69$M!kC$+0XoG)6@y4ReiOtF>X3oe}M z*!+1)vp)ikaf7Qr@0@7kd@<_0SzQYy&uccUZQG*b0XYX#Jump!@V#-?--b73mN(Z6 zjwx3JN^o{{F)Tkj>q4Qn52KYJ$Mu^|CUpzU-nN}s3bSgV#k#~i*?N{MqtRIkd<uYz zzoalQdF3AX1sjhQ(Bq{!cxB1y@5@$YfbLH50<yBA--WrkxA9M}%pvjq_yqb^fDtHr zMWG-^DXYNIB+-PJ0#;d<_|RNN6Su4zXHenVgPR4fRBFvW>bA}6zSd>0>5mUu;T=4W zxE>jFS$WQiMupAw`ICm0bA78St8lHV4Mq6_M93&cT|@~KH!R}nRhb~=w@+uF(zg>d zGd6COu_4<a5onQ`Inab#Zru^qaqXpk8%18lX4Nys&Wq~Bi2x`Lil(1$`i^LgKH=2! zLux*Y)Z4j9#1YrT6Pzau!UM}+>(^_X7W#Ode*SRIll-aUJV7Bwn@Z`Sk>tLv7i{!M zI&f#`Sq)vT_HFe1Tm4(puw>P3(y#%d43P+sY80i^KEyPq5#{ak8J<In+C?*(<A+{! zKG2wyW-*nCOC~Vov$s4D6JlE3Jv2dFUWQG(2I}Rf(I0BXJjmhHoW@~47k?~Pv0HR} z<&{q2Ol-|5>n~R`{Te{iCSe{X&zMJXyYbmCeC5ku`v~}de)Ri4czLJiY^`oF=b_Zs ziv(@Oupg8E;u``paN?)~5>LaH8lQv3@1RSLa21YJ(|P2~?xyIQ(<|pInYV7Mvij+5 zi++;i>DhCPf_nI#qAHuf1`vA>#PSymK9bht3l#T@p23<sNKGoQRhvD32<nm5JnG4~ z+Lat#(!wHrI|!BCK5f2KDrQ7An(#`DAJA{OP;zYzjw?FhM3>oYt2}_WF^WU_kZdYk zgM%WFR;4TugEJy#;?)brKn#SkqKMn#tG~snh={BNpmp&*Nr_h_!D-zBMO4@pd1dLc zgcJpCGflE$?eez2V&QqFl~1e~C`66~O<)Xn$aED;N9d_REC)h8I$U~d$}^4B<)qLP z18Hp9a=O$s%!I0T(OS8FY}w+I>yg9<rpiDi0ew(mshesQgA3bGGwpP{h)bBg8p8ES z;L7%kYEUSjg!#KR(bG3CiZ{QNt`76|H}l`r8h~?SIAlIoZQm+-U7PVXw@?c<NMRUe z*0kw~CT-m7dOG4v_VXfJHhS5wdWt&Z`C=`W{KsbLL*K^oPIZsCW#H^g<aOS!G&;1s z!}h$hTPro!bi&MPx71US>#DaZc}Jg#l}!ALH<s{7a*^t|S5PS2dOWr}o-EpzAx#83 zFX@^nvhCk?SKPT`zT^gbl{LltXGWf`9#X}|Q2B%+r3`RH18^8_!&h}ta}hVb_Vtf` z%dh)YKm0>KAjLoZ7ytHipa1g9%e$%9Y~czvYZ$wq(9EBMShwUkH!M0~y-?4WKVvwl z7pMyXIlar?uC8QlKs!Ge58;|7Xg-K^QXr&HFP7LWzCEawJ}3rMKg^rR)k@_@rZ}3I zIPk02XE-q_`{Yz6O=Q@w%H$z0Uw~QrTE}-OEvZ5g3U%!f0l}hExdjT9&~%U#R!zti zfjs6<doy#Qc-enTa+W7VQUke?lt>AoE1;vJ&HI?!wSo)7fvxszY4PYDTT(vkC8!Wx z>W5WgTJdtlRFXBDSBmnAqNR@TbW(p>dZW}a<2t_Yl}k>K`K&_`w^)_cqi@Ssx78!a zN=39+<+ds*WFqYuAyx@Jm1=)!>hwHbsrad}>N|Q$MBI!Oh*0QCK}Fz|N9|@(!G?qe zHAmT7GgKcYoDVWl_D7<tT}{nTy-idO4hU2c?Q^SHYz;M-5Is*?Kk=~7dl2f$BPkC! zly*XOvP|<BS6$T${sETtbN#{H>F|uPIjN5H+T%PiH$9)yJK#Jy&rr@5>k&!9rCAkk z!+Fvau(`kXEt)R&t|%O*qi@)pU_tRD=Lw{Id^O;;Ec`c5qn2q@ts@+jd+hXek>>n1 z^z==guKo(7BW#Ii-}8%Tuf=I`hhEBJpVJ5zJ5Sq7YRH!JME>{nmW#a^6m9XoIW<1T z61%)nbO(-o-}VG`@jkc_RNsW=^xzNnb@Tq|e4sh8zu`>_Y+hyBL;YeNP&mS&nBHv& z-lyhX=ug)(i*bfe>A991BR$Ppa2nW>2P%<nSmvkiDFpT_5GjN%+shvMc&luAV^gpj zcrEMS#<>6KfByXM{++-1PyLBM{3rj!ANmD9@BjY7SHAx4-EEhiOc5{)r9NVK_@bu0 zFEjXql50JzunRrcn^6OD$)N-j{_<mjnx(GRAa;1uJPI*c!l!ckFn4=E^^tWtZV)h_ z9i4&MoV{1kJUOP}fAGL{=L;Y*&G)e2bq54sMnY`lpi~>-$Os<j9=$>70rC+aiWf*# z3&L@u#t&ue7xjWDXLA*jw*Uh585n5~twACGb=!ioPQ4LO|8?_}tkC`|%}$ZG;P#1~ z);}WnPDS{Y$N%ukste+i%ED6=p{#^dS5(AXm;N!1K8<CC6cun%FO<GgJK)W*dqqH2 zSe5d<#kaa7E1o(dt3+3knWqQsWR++tb~`)ajf7actjX0lWF^e7cxH9+mpP8|_`TUs z2@xt43q&g#KetgbeR$=q3ugRWMT5u+pH%t*<oSO#rse3Db*+llyPf?jV|<>Kg1LgS zTqu}li(Zkp>EFTX2Fm#W@s{U~7pW=s+6Y<6PwuR9{oz|%f-}u%9i}Y6S0Gy8GgV6Y z6bpzs=-Isf!mF;rm4b=_0Ym)`0017HN_XXWVCk=#wo9^y-`Je?3CP^VNj{|&)gFP} z%^%@&7+*oL<->VD2}e<{qMi&@`()S0jDDG1NB9*-zRodwR#5O*K3iy*wU0VSfjBOj z0|_#xjiIv=?T%vE<0c2^JYIe+_sCOZ6jwZmQM_I9xKZatb}TK(c1-)R7yRm1nNs7T zm_(vfjNWgQ5GcTUy#Y+_vc99YR40o2k|ik^06>z-sKx(w2AZ)y_3C6g@^27NzYNIb z%}IGGSAjHH2B8a8{AW`9g!5;#RfzjbT}Dy2T8s%%ptV1(M830XV12U?3hgcK(dFUJ zr6DH|oh(^YjV~;QC;P6eu`#n|TIlEqVwE+{SE-#Bovq7LY!=@;+xz~&z$Q_?_-f?q z;u{S}QrPf}`l0jOjQwCGJuk1-N^<<pnoTP~e$C2f%v4Pc_l%WEC$Ki(g8P**3K?kV z`XxB-CD%^gT%Wluat+jc-0(*<;}>Ax9xZU3lb+2`^LZ_@&+-gq%=cn&J+YP0<ZV*` zB7qW1_ETf8hg=Wr=Do@*K^hYJODAMZ8d$QgxYVA7dXF~T57B5f&bEJhAw)zcq@T_= zx!Z;Ln^H03H*&NpuT27O6i!R#bqvq3Z$)sr+omFJ^$P)rK!uw;LWAbb_chxs$Zjxo zl)JvuzqfF==+L56Bg|3tR$TH!kf`@MgNtlmP+`XH3b%F-3#HrXwtyLMp0tw$h32FU zy+dD>`a)HZv@cX%*=KUpE6f+9{fnOE{?+R<vhbMALtcM9`Wv>UbefyZ&Yb7x_|vPs zpXLOn%(L1Y8`yGd%WgsyhmLwgbBTD^!F(AgBg)Qs^brYCx;S^YHUdYNrd7x}G?;Rn z4904e9DRk-AUXs#{p#&OQeOAaofI98aSTR)#cyNRSBOUO;^|xDib>_#!;pswpy_h* zyspKTVapyi6SUiob?XThhU3@ZW=w=lnN+<E_(|R@vJVjw*jA1W!%1R8mA*iI)b}gh z2(Fu9GMHHS{$9WE$G-31{rms$wXc6Yq%VBo%isGwA4ocO*pB1ar&WMZ%hK~L_TFMk zmtEQJ*Y8{FTxR;CnHitM*f+M#&@(=SJI1cNW@df>cg)OudF@s6Qhgdxvm$d=WYs=r z?|YBN8e>I$nUX>Q%2cE@!-`2lN#Ri;r8Ts)(u0YDty_gsF?jI|!tVXo4^HUnJ0Q>E z^>YY|SU5b=QxAtR&Sw#8gsGs-^DqJKp;9_`R<0qO<nG@N;l#Oo{^(FW6x^E!6@EfR z!b60UB2c!8SA*%-quiF(;vpQ!L)0%*VqreZh8yl9>c*qvZrln?t=fmZ;dGbAP|Byl zk`{C+RB1uEYpxW$j;A(1j4Sx&{1_1P@v2z8<a4gj&ekLDCWH#Hw8blGgSvGH4y=8T zp0Oe0swRMOr$$SKz;mqRBh^my@vMh><5?0Kv81~gv{*KrVkS<w1*ud&2kYq0oUEly zZ1e<eg0+?rkKJ2cBdigtyMGxpvTDCZY&lwCN!$9*gtL3tL{0mrPE8qP`+yLOs|h4~ zC)FdXmaV1`)ium_HuLS!wsRH#aZw=F5~|Y@Ye|9viz1sPguJ^G@lKE(w4lKQC{-)3 zPWWVB8o@TT`f*R~`CF%Nd-qAGw^?^n7W+S&cGV=Ggd!(VLCg(yA6&}4eBmtl4lD^v z=%vk;Vsh4^99b7^c?Ez1L*3{D{cnzWf+q=?G-rkwFi-4fYa|x0{Kl9k*KtnktLA`% zAOVbaJPeIjSXRK2#SE-Kln|hKoIl5X!-ubZ!XrqYEG9|m=oY5oJUctB3kEp>v2kkd z*qS&M!91K1^Y2b3I$6CMQysb}P4r(@r@VbBoV}-)Cg;w<RB?dTI%X+L7TaVahnMSB z8t3Ek6T@6bDzDSMd-_!1asOjjNEI!qj8F!3@;-lW?yvL#0hx!9z+TGylfxB0pt6zT zl0j7JwZSio(lIht%m6w&>+IEk3sURiY6{V$IvF9YT;Ta^ro@tW8El|~uKMKT$8Z0Z zulo~!@-P4E|M5M*FZzk!^0i<66%W#j*xf5dX}+x{TdH5oJtRqND%@`NGTWNVe$%dC zkP2U2itm$wl<l!(zYc`%Jlz#rMn7pV|K_^1C(E=e9%)acwX&{zv%3Hjrmn5@=?QNn zm{k~8eJbiLUGdo$CsYEIl-|NN<mQYDhCglgNaI$mdR&W0Ei3mx^=6&o;5&-LBP%|P z+m2q{*3!l@Zcy%M-YM@=gU1=+ruERLNH@lt#~Xz<L<PACTdVRs{<!rSGWlpHsplH3 zq9AV()e}T!J?<tzca95!GnELRja3N42!Bo(w6+k^BVi$AEv-W6fDtcMOdO&-Z(S7L zI_M0Y>UwfqhdwQJ8``zxpgaaCh3-7dJ_u~$K6WRB)+Uw{p%LzltYIU|8!=AGCoetU z%NT^Cw6Gs-1LqJOWwCBn-9DLUEiAG*NXPHk$-9H<8n}76f2n^GL}^m50*|8LvF$QT zRDy%OtRyrGTuAEhKY7*`hGJ7kiaD^=I^P$6Thw>RBItOkA9YhdJhg2zx5blDLop)V z?sCzA6^Uju-qx6O*V^INfFfPGj~3>QkCSx7!^Nap`cWtKMwspD(zx;J^P;<;)VX5r zz&Htun@!t`Yi-1CnWs3UmrNYjt|fcX9*FsFr{2WN1{9@Ey#V`@g$jLn*DyOQr2x_1 ztR#`oUFz=Cnd^uU{_kC4qHDE>HAgC*ul)!bu}U_+5p!<;zJBlcn56aB^8poRsolAU z`g5zk)Al=S%%BUICqH~#t(I7dHZYj`c6ub~@>*E4=waZ=+lChh8um=ad8m{^Dp_p) ztf0;N`<Mgtq%rkgtE-cv@~H^hX{<e%@!=_TEjlBY2U5Ar3pV99_68_Jeh@uLZ7C<l z)98#AcCw&B_)xcaXP(6%|H}IK@!`k+Ki~8d|KD#}Ykm0SlZOWZNmmZG!&M7*-F6r? zP6m(@D*>HEnW0>8A_#+gu7?qhom78=H-b9Ryym37hX=IgrLFDLP#l~x!inalHk8(D zm8O_t`noCTSmauHs5-?D5jl@s2|A`e1*qkm+ge%=TJ7~6`}WP=^*&3%r-~`MXD`uw zT`KKRKQbvKiP7!=^KJ|87|x!|D7wW{19vG;e66y{m2lc<H%9&{>~;K?fTC_hZ~nen zTk3gXX%nUcw!&nrIRnU12D{0)1f-aai0&Q>EwZ!@_oVxTu!q3|8x*Iah_R%)D6PAv z5l?of(eCYcf>zzr<f5UGIS~MGDs&J_+QKpYNSIFV^5l8EtXGq7ulBDq#_DlKQ;LJj zPLs>+(bu*VT^Z03i(}VV@@1@ALh)4fi@|I1rF`($TQC!|Qo>Q7y0NxM0HhWw4{W$) z4$2#YT@_mDE2wdpZD&d#i{`BA9E_$@nkMnZ2l!xl);B^cVl(AMg?+)mZ_6)<;u&JJ zK5fhsSwp(iN|26RAU=(p3rFr{{z=sF7v;UgSXmW=2CILUUV8DrUQ|t<qPL3;JH|;7 zXWC5T$_(+>9I8;;wE8VvcC*eU?WWNGna1fO2&?+3*5%>DVGCyeim;D%J!sp3K3qi7 z0K2r^i@j-r3Wf+mI*yx3dF`0>B|R0gUc0Jpwp__2lRdJ8t&{;3i?rxHM*;DRbb_#- z0(5x!eQ|hL>ejXtbCQR-Ye%=5`3TR{-@k<i0QNNHu`)#C%Pt2P3D&egn**1@=EUxz zbDLAmvbjLG<YkivTC!dFcCSIL-ZG$5Mvh4e372;V@X041*ZR2QG1pG(x#ET`n5Ehe z1Ne*34^d>SEKfMhbA|6merg`3Z7T9f)6W#j1zFwTHFn8?+cLt*>p^VTy!(~;yfN=T z&li)7sv01iB$u9BcXQ5!H^yG}E=j^Enw8igl6K=*o;$>DO%C{MCoxgq5_WJLfBh>K zzc-M&t7Fc4-xXf{7%kaDhOPz5CSTz|JC04}Ub<zlC&wMDETg)kqRD}3gAGcRN$jR* zTLCa!M%+nYY4d!CH_%em7XD&{gYoY1cUzP^$0D1k(q6FC5z@l;X>UWXy?4twoF5Oo z8o|P%YlV>3R_yJ*)9a?~o;V>3Za+zs37g<PB1+~d0jvHZN5!tha>6&=7ivUUdCNv{ zq6~0rnSFYLB>}4vTHx{&Yd3n^gf?MnDoMsbD#S6WhFi{_n((~Au81fko@1cOJ;G72 z+^w8AP=m+WongoS&{CZxws*ICJkeXkr4~h$6pj<Vqz>$rC3_col;`#@3mK^Y9!B{Q zgb<4!u%|igva||%%)Ts#`)&1t1)EQR0w4u@#IpzUs{DyvBV(Q*#{(N-o=`_qNBt>d zp2W6ta|!4Jt2V$qIj_t!DawHkUXFPpjfPz-%eU3eu>YOMfQ%u(xAz(O4gJvBW}q>4 zB$m#~ak?DE7~{np^X7YUYbP&)wdtE@5;$;?Uj`o<LT6mvvv2kv2b%p3rzu{=Ao6@D z2HEbp{TFn1vXE^1as|uj<1ae%Kj$h7-|vG}6D{geyn<*hT<}OluAiZw;zuB!UzM6O zGyY-CH}m_TZ=T!33nj~#&ZX!trY@4^C~H<{&i|Vm302P;(KtSKg(LM?#xxAef5;=0 zDlk7f3HJ&Q6#y7KUXTzNXZ<h|-(D~(g@6an2o?NAxf1EXMgLdGBN_%sWtovU7cmW~ zibLPFp5^CP)$OvZ4Iv)yL$1j@zPUd;;KbgYXd57dvzUa_RAV<m&QO}HS%se4T(fDA z;a3!=SJs>|ccCRiIDrBpJ1&8Do;;`UT<1aR99+f%9PXU;FE%J_^}9;+p%Y<KZw*9o zTin>PKXy89s(G+It>c|LRCai>xUGdsqcnN+DkAG6uR!72s@@)@z-@_&x#CIcV1e#z zX)RH@<UW$ef2>WweKvr{d+>?#a%pm~IUd4YWKv4|9j;CbM(6;n#yhR_QpG$kL8LpO z+PbGvR2yS|`dLL<a>C_M-9uunr9wQ)x)O_m=2r<Vp6>P6-nCJQ&I>sq<NyRiqEvsY zMilPcVl|mW;jBvBgM)=IT@*DPrm2(e+Amf?^(M<~i@((Lp?uF7Yg4V3igme1>>Z>E zb}%h+LjI%ssF0SlW$Hji%sJEXtB;<(yt8TQOU~^++1~1u`*^b`wX~la6m|LQ$!)FM zBcWT}nth+Kxv_b9o}i_^Gom{!EiJSV2o{fadULz+00t}(#K;b_al4gvus8L>r6&>b z(5Zv{cv2Sc9h<TJ7U6Z`XgY5?YW`ZGm@9CxQJhX!>i4rMYGTi-m0hp?(@a>{l4U-Z zIR7Yi9GEwwp!9&+)tWAC9L7!%opFu#fM`z$il<R)l^()MIk`l3p9EGuS&PYU&qg<K zqcYLln}cf}?E<EVgPGOYEjA?lNmrYpd+`B_D5#=jsO!*Sed}9lmTNX%#<tUHu8KRC z)`m+1^2V-z>1<QQku9-G!dJoarnK1TaNWscSQNxBnW(8;y{{c8Z?TSI9u{4^OGYtM znOF5js%mt-*_l+7;SBm8lv#0T4V!9}Ml(>cdSIap;gW~buN-POmz1Rq@;%g7TN1#H z;uvML?G%t-zi`M-8E%U;M^5oMP#L+%z=2*}^wj>O?cma4AoSo(c11>9vK<9ii>@wH z^t33T+sL4b3`tyR!VHPY?GSmMK<8ug#DmJx%9*(7bA!!~5BK|Qd;`GJb4P^xxO6S~ zee+7DJM<I#g@V2ZPV&uQ+t}G5RHXYty;%o2iu5A~9k9VEBX!F-*dEwY6aY7iWg_a) z;HP1`ZM?=-SPMH5QlnHNw?zjH%dvNP`b!bow&_vSca0LgtIAPBsJm2J&xBa@s9i&# z{`af}?<-|J{o*&`tp(E<2uDS*C%wzwaGaeUu%=Wq%PB-Tg>Z&Mvu6{(>Qpb3)~D<? z8<)A{3AS<|oD&uvmajXKwQ$#~570r%bDHg$b|B?^Tr?YE+mGScAmJJE46M>fT8tXz z33qrfY||HKQ#&P}hD@Zbv9lmN*bxUnDb`CvAq~=Ag_Wf7S$sraT+EZ*mUK1m`RTX_ zOHpGb4(;>|ztW3)THb~iv7lC4s!jl9`tbyC5Si67L1^#)CL@C6k?1sopqB6|*{s|p zrVt()N!o>DHBxIq@FoRRjaoxcPW2|~7HIzyxR=unuKkHcC7>~6KLulGtVS)zD44F* z7=Wx$s3X{uiOO^qJ@ayL>2A!2<||0`0Bl~WQxE2fF47a0-XG#o&_~^u=oeyXmc0sS zk(<q8o3u+{cgQ5n8^g$eZxCc}DJFrcXuGxQ*}KW>_vsfg&94P$8s17_B6UB<p};dQ z%o8_yk8_cU>gvk4llX2UPLd%S!KLwm{9yk~{+`pQ_Hwz+AnR8noLGJqudS2*2lK^X zU|uzT%I5k+?3}Vs#b-Mh>q#%iU~+^|LpZVEz;249XhS{1ub<1^w(IU@7OeF^z1VRB zS`P@rIrUS4Km~SS!xtEEry(bw?qNOKi-sDDssh0q@Eyl@2`s2tyb)p%LYv@MXrPaq z+e-Q!GuZ;g;agBKVr11A5ff%N+hPlGA`^>0oe?T0hRP*rVH?1?-+w}wPUf)JK^#ux zIAvzR^L2g+8_C2(ID^)6L^o^yZYO*6jTnrk<1!zGv!Z)$O?hRPhqXaNq{6d#4+p|4 z`1E&gb%;)H>kL(DAPJs79hXp3N!~c+^d!cJ8HCLU=m^Dur+MRav=$N6KhXj^+-?!@ zEnKAupc*KU6T>gp=8})A$2=irEX0w_N<ls5Ni~okjhH9Otj{n{l1zAchCvF&>oHGc z-ZbK1z@rZ|pL|O@{fi?Hm0n2y*}yg%SHt_G^QJa@{$hV1n^>MKG=az9l0u!D`*V@W z(CX%HO=i&s<+}91d4cogc~}#lw|kqO%@(<2#R1dL6b|5(!FZZ+#9O%VjG#%QLXPp4 z$%qtWFG8d!a&NkL|2*aSDdO)LNC$r8pu3ssIAQ`_Be&eq44{x87w>HzFgN+mx5In4 z#f!(1vc;!eQ7@e)`!=0BpS_J4Jh-)y_|Buz(RW_8h(KZQ9!t6?*`zq9(F94Q%-JD* zH|J)L9L*$sXJvOX*eqTYUSF#@;cSm@JJ8JUS`2kVC1&j)I$3k^x*NGP<k(|sI<@@3 zCH(?;V$7Z_Va7_<S8fcJ<d?bFYX96TBa~{U?7Wo(cO8dUF0$+G1R=D9kmsJH+u9tQ zb3<S^#$UZxI?D-v6SiSPS_@S6SjZ#edphCnuiERlUTJ%juw)<isn}9|E(8^c(Val0 z3eLj-x59gCDawas+$5zf;F@$#&W1;neF6=$YDOzg&M8XE&Ri>T>WiLySgI?~mf#F% z+M;{aP7jGu30T<fAx^wWkr7{lM&>2Uq!;WQ2=G+bvQI%gM^Uf8S4MFSi(<N~IU}Ky zaIiWj+!fTClU`_#IXIxCj50#*Bc$#$ufgOV2Ru(6H{W?qK>Nn8G{^L*dhu<m^+mS; zB#HVmS9(L(##6Ub+$azWl>?sm%BY_&d}!R(!cV!CEHd1Qu>Vb-ve?u>iC;T&+5^|t zdZ*9y7U>@^<ketF$z0~IzGZKINKZI0T!nzRe7iB^9Y`6@+WsamQlV-I{+W0x6C_$X zkxd+r4tCA3&4S1K!c#RA_U(K87HbG~ONVk-@^~5!BPkp9V1Im}67-{dNMrkc6pmNz zTgy#nPtVo88Cm$wUn6q>%zw5hj<sDnpamlE2dF9iMQ3pR&L9}`Cil!<am03WH*OrS z*l0$+Pos-@gnEXos$_;V#|(VZTXen153m^2i8`>MrT|euuD=jhiA=r$>4hR!)6x8x zflm}BkO1e9i^yjPqU~@t40UeSm+ZUg`=th3^^H^~8wN9ol~!MFAakK>f)b%?`ji<* zY{#GEvM`*zap(}FM?=Q@IyR_2;bEDJ3g^k4wbd&8;V_=XQ4x-+zbw6IwNAtnvdZ!# zD`VRj!e97e#@~_jnte3L?aEVY)6S-vJU^ZFYH?)<@&jKpd@0LeV$aK$zT_%r*ug!V z=kp!QGEv#hN=I}3OCl%tg%?npF3{fJSS56jxQP<xRXNSg78j@lnNCu$$u^rcgHbtq z?`t2cVUVGm!AE#TFzH1{f_=kxH!h5Qa_rhlfLLfXu1NbH>(d?WTWRn}+|;lZ80k#T zB9u>MqGRICi(I{5E+;#_Pwr>_Eh6hW`%B!oPazt#-W1aq`j>j<h<mV(bCN0!zv~^@ z#E2yY9zaLn1RRdU&?0Svp&Xn+I<^($>nGbg?uK%5;-JxS+2YO0y7V@nSds(X-0z5A zLrjABE%#8kw!{#&ADr$j!-`x9@}(5^wrsRLE#DgRgo1fOXge5g#t8JalDsB)<)?^7 z=Us5Ff63dp4oj$j@Ny!I{_^R2IA*vbw(*R@`O8Ajfxo75SRKh4Q!*Hj5GS~b9w1l6 zORWv76wqus|Lg7UO!4#_vC!NBd!6}jPLh|~J&X!tgF|_Te)jzgG;!v0c6q2T$2qY` zaVR>oX}Rsq=b`RfqJe$KGC*BX_YyT@Tlah4hg=j2t&+uky(r@=>DpfV>ug?alw4(w zm7Z_J4`#)xoXe7v+5s|J`A(CGQ9*P#74&3o<o{nPnmBGOGMR*J+A4Ivr(Z6v%srzt zw3=OGNzZtZ5{!vr`?3oJ%YC)Z^+t0JSNf8L#IJ6d_o%A3?QHgn%C;5MiLK%<xu1?X zF{mG!>gKBA4g=cYLx(tmG`Fyb}gDq%{2B?a6>SrAk}+2pf@WlZAB$HhWCUZcE9 z3rw6cE`5!#=-^cqrKD3?^0G@A`a;=(**L}?%41RXd4*K~SIi`b?mauY6Aq%IB~BMz z9@;!PX<5u9A{@^>;tCYUm&-Nal<S(vcMDq)rdP`dMWP&yZ-Tj%7#A*x90$PIv!!-E zW*xCqg=TSTEpZvOLNBa_Q~k=rTTy9TTjmDT4{h&6ON6>IhiWjqhUYu}#1Ad0$O z-4D_AUqb@WrjRvX^<bj*>kUwVbdGsqN_cjc-hQ@G4<0>jWETc2ufblcH;*HLSDd#I z7O8oBwAX0mOCRXJDl^o#>g_2F>MaY;;npei1=JFGJ#_v&Bc^_tf^mlnHuYUmD5gk7 zKInCxv3*?enr~3{Tk>xP<gD`;6qZ+&(F~@1AF!j}dWph<pDD$$2WHS5EtRgVVD!@A zz?Bo`73u_^;tbziK1ahzgc7YqxyP>S6j*wI1>6oiAdHY~D`V#70+-^aM0{E&QxE=t zVlx#If+*#18}5E)(;0DCuGp+Ey$Qto2--X2i$rZ<EyST-2XGFsggOOlLH%|IJ#SxX zmaP-$a+C#==g8V5pF3#pBrX%J@nk+UfcDNtm9NbUjt>Ee=j(cOMDJ{&Jv6CirX%)1 zn?(F!^Q^iXgl~Xw#%=##NRe26*3vy>j&F)_+oO*lRmI+G<Ff`7+Kj<&G~xt;xLf<@ zy_Wr-PWS_j`n6#b4)klk$Pehgbn7iABky&PLXMRaD(Io_j-V1n1|{2G!s*Uo)Etxi z^vjp7+aC+#a#o@}P^b(GUJTM)qz!5~p=r2Y-Gt)A9KmL<9k3(YG}zm=aaSh{%)*Nt zO2fw9bXYi}{EpWYLip(?#0DX`KaZZxfwy!>Pfu)SY000tv;fT~$Y2mqzaQB~c_V~% zAkU~Hi-4clU^S6)`c4y^ZYb>$0fpZL?0X+VVBVmOORkseVBgW|4M%ti_H9CcJ=nKj zdwZ~N4_OCTh&W^*2JbW5YM4;@!zcVQOL~>pf_(=p?0F1`J_a-Q&4d}f^m?%GJcS0U z6N`gZ@OS&!HZ<<1Q`N_{tX27YaZO4forogO0KL0vkc0&0@qIE1{iPU)(_#WsnxmNc z0G(1wRJ8!@s*Jrq<&5S`DrJZ^_iO)|kyBrVsjRH~97uBgUnw{~EwjdY$nrzjI#qHY zI~=dy1%tN;EJ^idFV<o}gv)Lvm!I3r^?asQ#r|UsP4iMjJp+=vjF)78I3FE*xLuw% zQefoi6z3nUp{^)|rI{l`m%H(g_2}baAym%ziu_4I1FaX5*Fbw`D>(6UQ&R&Y!Vucq z6K`KZbYvjFs&hP_XD(SerQxB2mna`PUh#ACeM<<nxhi!4Jb{NSQu63c8xm)og`cKY z?31;fV8jD8u4#z<4vk^l+D)cc-v)z?uZL2yYo?F{imh}OzQ6^63vypnJt0b?{TTiV zTd(MVO=xF@N+gp`gwAhc<@|<oCR|OI+YeCG%3=uJer`)1S1*&Su-CJqfx4z61UFqD zhTWgLHF5cm=9~UJxjajRg}Tklx(jmex}rg|*uN^AZpmuuUxG74Ji09wG7zdh*XVwU z_7Aq|g#+bh*(|2DjsdNGWRFeVR(%YV;rIu9f8jP(V>C)`QobBS2%U#Q-NTwMLHX#u z?t@i|WW65jd$F`GgME9Yb5w4QO-8Y2fA;3Uq+Ytno5P;?%FK6aC~GM|P<sY(%Wxw4 zvF8EE0lO>1N;>cqcLi$_cN-o0ih3Oe+1N-Uu)JZgU&$@yNbqrK<{SoFHdzge4KN@! zr$AtM*vW=R+-q6xKRs>BSu^s#q9{(Du2f1d*B2g~TS~4ngb{Yry^0u)T%Ot3SxPxY zEm{H6vScmgs_)o#ThseA81;sxi|8_J6AmRfYFzPU_7uOs=OX`8j0Y$G5~&C!sLZ3r z7u*N4!vtt=oBjt-Csrx*q4jE%3dPOvy+WveN$q{Q&Zh(JVHaFvKCq<ifI}D0-`jjC z_w|6pY}9onS{vRf&d|KOFF|FU*_@VM-?yVwW<Fkb{?PqFvW#78Qu5TO;3-zr-sp+? zypbqj&AfacsU9hltw|riZ7nUy-LyyAp6>JVh;4bmKiC~EGZy8)C5aaeSY7v*iZ#H& zMWj8ANQ+(~I*5VHXW`MTK=8~I^0oO}RH8@2bi$fx*Qro{xD)<eJ`=ex2l4nZTewQ( z67+~X=){vh#kQQKqX>3sRYxG=Zq>Fa*g5sIi+a`Lbs+K}KY!V@oBVA@s;7NuceL>) zP7uZ9PQFOzJ2zC9y+mKPaoUJfA8W4++<yvREJW7(b@>WsJ&pI_k^d81;+#uHcVZ65 zIev~IT`@)-GNln<zqAMrnBIg#TsbtWYqleg4yw>mONzhf35d9O?F(12sxm=qIQC|H z*2%Y7c1QVDRzyq)8P%Jf=hjn_v@e3x%r}9ffrEQq`=QY-9L>Bom#dG!qh<T$!te+$ z!p?|In%00EuQ!@wX?1`Ke>xi9#HTCMh29=3$Q{5#pu7|SS0+c(!nyNgG`w!$?+ul{ z+g;QFy|R#T9#8>f+svj=Af_;D`jwlteS_ci;>X(OK%7HR3l2p^165HpDw?euJ^bqc zg3Dqs*WnO2Gi%oumlfsE-WN}OWW`-)6r)VdM?BMS%*ST(#sDaKx5-PKd?Ki)-+7rk zr|BRkN2FeIon}vDHucc%ws<|l33>aX_cF)6$>>)J;e@#WlSK742q#Iy6_cUA)wRk( zHf}8@2q*YvoSrd1fp9zW0}8||jZet7)B9N(*-4jsJM4L1M6vV}kPhyL0J*MO2bXPx z^3=V1?Lftw7w1sYBT@0_S*RJt8<((^ecYv+pCJre#Ic7lq1ufR<Q>Gdd^t${V=S=l z#*FRD3r%b)p`fU|DZs&rE$PF@2Wj1IynlDIb<JcHpQ8MDoXpuiX{U6`%JVvevAd?t z;TDU~{#y<QaUQa{`BAV^j}ntK!N$a*m7w{P#U`ZZ=_@!F0(KP}M&Yb76JCSL<CHoL zx0ojZVfePBg_bZ0I3Hh9%#*r4y^eWe_VQ_Ao_HXmxkd~4o15j;m?v_M2AC&ui?lnC z>eeC2Z=PW(W5BD|QDL=YVW@u2VH>`^$ErJfp&rITGdJ*K_7ND}-yE-^+3+HjSBmMj zGn)Sgs^o<*8x)mo@r4gvH`k>{(pi!%XzV+9BXi`@vul%t-x~E*C@kT>r1`3$(O0aJ zjmgg1P5Hw1Je}k}lEDG(OTJ&Bf#x*cZk{Nlk1VkkO(N{aYk(G<NKu%Z1bufWneq0C zLZ#3rZz)z~@C-(jJYv^!Qa0UkhRj25()TL5IM!WTvKqz|G{%qf=grQ<NxymQOkb?4 zh0^Fm)0~N&=g5^t6WaFHSY%`||0Uh3!_&D~CEIzb5}HQVLuXklPv1@r9LM{o@C1sY z8u*c0v#-kL?(QNAFE(MC7#XprJs&*A&jvF`48$z%TA}qYicF#f_#ER`eZ>yP9<Iug zYejUnYofQK_*loCWtbn9+2fHeu@P<y=up6o@smdl&3l5jLRn}*QFLjE{qN4_&Hf#Q zd&vJ_LE&WW-;LP(<6TwxJ+dkENGt$<MiESMUTEZ8h*;Yo(cQ##ms5>v=V7@fo#>gQ zAIRrFRGV)295nKIDZTxK*(&>s>U&nH`tEl7mT&yJZ~Nx2`}(i_s)q;J^i_!@#-6LU z)B)B;pOsTA7W>28o*r2QqiAN}GP_cK*TI}Dn>m^}pQrOT^zcJ$VqZa7{sMnLb@|i} z#_;%vG~gK6w|8(M;^=XFADHZ!ZUwC+ucrnJ0O~4QoUS0&ZX8)|lJ@KW>Bfuvc7M&P zL0(S~I2&Z(Is3HgMlpihQx;wu%E;rQ@-qEUh4-7Z6hGRTcq9Of-^Jy<y=9&XF&_UL zEkJe1McO!UP<63FL*&v^QRT-9X*<k7r6F-m>@QvOsLgO`b^^9K@M2!<&3hWfm*@1k zGwYJ`0H}&B0DIc`=6HwB38K*TmGlHP6kfk}){FE-=E)^O_6T33z*a*FVW1^@iuz5C zMo=-n-CCI8Z0SWALFG1_TD1P9dYGq~5)yB9`1NlcrSH-pO|hz5#EHR0eh#`Kze!=N z*9yKj@X|qJsXb7`!p9Ym6jWRE3(5>-R17AXR=AQCm)rJXr(2Amzf~DW>(b>@j>s4n zg;Hfcdo(A9`6aDOKG@GpsuP6@DxC({IL)nEFcPT$HO_Wm86VWck{u!qB{pV|PEyuw zEDBD9&#dK&SCdQKISL3?eGAuRmW?YEJM3=>ZB+DrO%c==L6d&4<de*dw?{&nAW_l< z0z*OVkKQ_UzVd*MdS`ik?0XVWYq7Sx*wrH8Ld4v~4Tp4=f)S?h&w3PA>5>MGeHI(h z=jCgI3UMt{CPxSVE#cJ-{>OKI&oBMCKj}CA+FyNxfAjDD!*BnCf8?kAxNrUN;iLB$ zfDN)Eyp7q*o2iqMVBerRm1)ynS#up(GL7CeS)?SZ8tgdthsGvfZF<^7`)b(88?t$h z5a5g#XGK~I;SDCt6Wta{1{44m15C+fBQCK$T?8+iu8RYPfwZ`A%)hp$({z6{4Fp+V zg*_R8!1%A-TMc`7p|Ma5-p1xDzb&WZ=?#C~>h2zFu{oLcl<^`O6`$m_8QQjj?d2An zXTt&OjcDqC4iT1(&ht^manbG04oy>5+>B70w7+_yJsu65NJg6ut|FDF(!2^jS9_RQ zUpf(+dK`P@#|($CCj-ca`MmkwtbuyUPz|tlgUT4c823r3XzJx{_sqYX^fl}-0@psr zh>Bw|N6f$_Yjh`pbi$@G#6mho(1s<2S;L<$%9%P1&a)raT;Q%RZ}&nWLepd>gW|Bs zYGUq$TQbkIk|N#D_WmPBSA$n_ZG5QTPm=U&fF>Kw?QVWtQdrh`Z!&|ypN%)A_cL-j z8gG~cIuK^}S0bF$aO2y@3W*3O6nv11aN@ykUiuvnvFoY2pE3|woYAXIhgvKO+O6-r zmi9U(SXAH^PQflq58i;cS_v?NmCdHM*<)&n$|$@lo%O&b4pV&DhJ)x=f&}TS>eyxF zcqTnegg<JHaC6iV@uLmBgtv?xf4Srh?Z-C8k^w)_ykpoMzLiya+<SVv-M->0zT$S{ z3t#xchmVUlhzsMytBc77pOgyt$+efyL8?oh%-3i?HN#o5pxRi;epHC5+iYr=03V#X zhZJX<Jl7dqg5BSY*>WG)jpam{;#-g9nZA`E*CosoSehd}gn|KOxxlXjp3E^%;>;c@ z8xN@$FYp$aC+_L6l!g`A#6uK4WQTW<yR5pe+Mf(sJqE5r8B}S=U=rLT-HA`rT9QZ0 zfpzFbgY>y5TU8^4@!9KZm?xS8WDNX^>23g@5~!cqkZ-#;Wvk4{vbjo2A?>0L8$Prk z4dyuTJ+`^f|L}SMSpSRhg8{rjdBoV|=^gu%+jC>8Hly9d`))L9V%;>~IBy0W%rSc8 z(*#zeBN%epVa0Rl5sXLa)H93Pu@Y%;NTd!&9y2}#BU5Hf7BJwp*27Xa86y{%<Gh7< z<DH~>BKgUbACn!*mR*?xy1NZ9S9!xPjm7rw2pM@x6OZVD-E+<%SBT0WuquX;xaBt4 zFK+RaO{wQH3yYd@PSRGd&y2YQ5gW-ums^J==Prjp{jO_^gFZhv=Mqqm&On^@TA$kp zLpdE-n28PVQ+{B_W7UL6K*ej9e-)JnLI``OsKaQ*WXaRvsi--DZI>UY^=CtxUsY29 zJe}F8!}S1nj;i<9UVJi#13El~%8o^ZmW7U}FLWBGS=8*4f;JJR`OS4|!+`t<U|pNo zHnrz0(b((tWR!1TB9OQaZwNZ^7FbJ8Y%8sV)>0)(2VQs7$ek#EI!pcI<V}Thy-dA^ zb!KCm^?nTX6~>8uhxGo&hYuhA=l}j+H*WvuJHPX5zvA7lY#~%T?gB;(%+#8m&m`eQ zF#Z*98;^&`vWDqe_Clj8SW^Ga?HcQc?8mMUOETv~O@kQ~Dn*gX7^<n&n{?70RV)R^ zOgh^J>^lqX{hPW@L<sf9u=Tv>hRX0WQ%KL_&A8EegKvZKw;ch}rAB=Qcf$w)amn>D z?G3+dR2ohLtf(uI1&arSVda-UwAYEMA8BN-o|m*=`E~H_Ltb>3kjl8*2~)M6=UM6; zF&ef1-9Kr4gqp6UY!-48>dh}JyXSMS%QJI1Fhn+Cas&Xsxv^!s#wfL^F(A0_{O36F zvyM{WX1O|dy;BjYyr{ra2b`$M$L#uY)1AU#_}Vn^XqjEaLWf?7of~28E^Tb>6IzS+ z%gf+Ez=Ln$_nZ1nVDiPp%g%Iach&4cCXQm)ZW?EnZq;8<JfF<;WYSh$$cdtBDb^qS z`iZ8cXrhf3N_AA~RXEBH+aDg&#Z!c~A~7M)RNiWm=02s7dmZ%hd)0qo(mDEy>)i*z zoeivF(^xW)mP2(|C)W@ATC+)h^If1m0Ob_g31~pMTlpo0j`YI8sSWA4W}61(*XE*C zfNL7IXQXOCqCKn-@JaN1_t^9A6lCdp+vBf(iW8%w?er$(I2Kwu3szuVl`iyhhS`L6 zzd=~Xug3T+alLRC0p1vr4zR>{eYclTt_GfL4-G9Uq>%=pH4GxC5PqEaGn<T3X(sK7 z)QJD6zKeKXSzf{G#zwp~9WzP)mh*byeEMZzY>9Q2v@)E^gY@-Z^OgVXU;U@w{d@n= zTI>D0+yDO^-|&cYQk_U=o2{e^X3A(6NW?rjQJinr3A;J26?sN5cHcgi`0*2+VNYe3 z(7?R#ulqg(7ufahK5`{xVH*Ou&phQ=c`kVkIl)Sh<`PIvoBs&snu|uL7PpXmYJW|7 z4sZt7CQffdvs>iD8wphB7lpkV+50Hd0h$w=_On~TU9$>f;0*a=Dvz{Z!~5|O&NWM0 z+wnK%Hms#eVa){<`T!k0_^PEDhK6VGrwlLkWN}>uZTG2)gA=vE5)^=hg6#y18Usz$ zrD@mHsMjLv>C__>YAR^bU8<;Q_H@(xU9CTZFX}KHy9eI{iu;_~B>wPZayowZYTRCY z?h+cw?fRz$xWo~23<JV>2-%mK&6rz>-)s$zwwv2|tGOUg-WVto-k|kxkjO{I{DgB7 z7;_v98*1<fPMDA#TKAo&Dz`n7qTVcyznpo~p?Hm#*5zft3$iM6%Lz@!vcfXcE1^O_ zH)t+ihFQrdDefEnPuCGn#_oH@+yLRkR9Rq7>ShyvKnxL1>|RXJ;pD6g$;a+Ay02+l zrt^!aZvfsr%UERqZfh*r2)w$-nF8w1Y_`UU+NcAY>|ce=$J}fH=Hlc1&p|wk5g2?8 zT}unwVt9vqErjpTF@lN;;lx_}XhAaJ&3B#K@7IYhJ<1B7HBgi?zxS3Yvtje%eO`4t z!tEX3`1N147Lp{vcA}Sou8n~`BFLZ<UX{Yw_G0!(cfW_=C;BwC<Ih0KjtPaNp-Sy{ zkGKpFMcmWAC@WbdmV6U|cP4_V1k4i~(?;Bqe9ukStU&_pKkC{~rz5lTzi*3qLXi|J zqF!9bJW-LSjvNyI;X39?zA>NrSC#_ZIScP9cbwV8@i8{V%bL~6czLD+O?8cXUwz@R zKGk8&k~iz}Lh<Qfq&~uMe4AimLAiOxa!Nk#dDtqcGBX*%8RYG4hp;s)Rmq~}EA5fw z@!MQ;^SQyxC5)OV;~;a>mqL|z%O(c^Yo=aQc#AOlxGH@tp1Yx@+3quXs9934jew4h z_qnOk7>_U2KZfVRbwqC(+U{a*h)~{ac<Gls0$`tu+^eXURFOSeLcN`;Qrd)`X`imD z4(DcB!t#NJIYSn!5eSyVx>}$|yGex{3HQNpaV6QihHf|B-EQyR-Jlh1b`ZH5o$>DG z;_RIPkUsDGWNp-J!nVFQ58Crkb`n!qP_>cxfzXk1xqKssS)vA$4$o{WeR=e2Gq1Le zWe}Pdv#5|2mkyiz)Y8s|YazS)$U?A}WMS={6zkN6p_5wZKsW3r{bJR|bWOIAF94oy zey~?bYmBT$gV?Bi;tUUq57b|vw-K<rlJ$I7h*}%)JN>H9>bTHHvjc^A<h*o^5o=L6 zQNuhPf%>ao%6;7?(gD%`<K+YtyDwMS1S$lN#A2;YEYLQ$szo+|3c*^Zjoe?g$eipu z%W(RU22uDw7j;(Cr&u^AcxueLv#Qn+wAO>xgB~8FMdS6{X9>FLg2r1*_3*6KDOgDo zc=w~?e6?7}gXD|1Qy?7&YSnkr-y!HH$3YUYAF}&<0M?3{zS34p>>IMZtDz%tsf@#( z*<GMh?W=oz7|9Ub(Ai+nTKM||s`BFHnXxD$0W;>%NGQ?*dx69)C6sUoU^{PkeU*7j zD8#c0z0nb)id@>HZ9CqsD2Ke)SC2*yNAsHoQ@QN_7wwEH4=R_4I)vUnzG{vbG)JK$ z^1r;Vj1}tbCCiC+N=VV{3n&&`d>9+j<8(Ewyh7Fz#Wx#msHe5q!jvl;uV7FhZY;sY z2McK~;sPQAA%9(Ai}i8|=VTc!+Z5W;HUR0wa%7I}P$%vIuE<L<t4hhX)5pzc>g{;W zg3}rSW_Zya4jMvQgdc4753TkGj`H2<nhFcNTp&6*>eBul5NS+bx~?y8TMW$b^n{4q zVxuvH1IT6Yw;SL2UElY;-}hm`H-6n$y?=j`7Ez(P02PtX==q5%F_ph6b+KrP=Ll!Y zgK>pT<TA&lj=(8Q4;0BSXeNGLtNMyca$>0cIbY^`I;(MpI43RUODnWAO+PE6E~-H< z!d`Ml<~`RGFA`blUX(4~mGSmP+WM<%L<)1-oS!TkU7NoB(PM<!^Kim4;!BC$t?L!D z3PJ<wZk4VhhNx*o6)rl}Rh`V0IjN%<0l`>l0GdM^U-}XT6}(T4>zl;$s!r<LiVVNK zOqEc0-oDV!D(Yu0aW>;CeCxL^TqzuFT+?~*QZ#jvJt@!K*HAq0_BGW%XTNBGAyN** z>FupXClDQagZ6z;1UyK_@A;}m?H3gcsfbw4(=_H%jX0Ienu@zB2x$rqr1t+o5JUtI zP0E~!R=xcsga>?tla5_I>Q0;#>e^Q)=~^S|O<27sLJQ`fzH8U<pY=lY7)cOc?*rPf z;&@~`kCpvha~o7<B<TpP8aRghT*xML5hGG9q*8)XSCRFgyf1s8SaQ`myac`}jdJ}c z6O4a7VeqNTzK>5gAm+WON>wt8V+a7hT_(7r`yhNv+4;pVJeVRzgEuLk`}GXfKpE}C z6LZ=}W`bx3d-y4IwDSN-<KrW!X^eov1txhyec=o5{^`H{Z@>9B{PLgtlYYWl`pbXy zZ~v`-^pC&eo4@Yk$A@xXVuc=GL2fbl2QNG4=x4Tqc7xH=8*^$6|1w;xcR$dQP6w{( ztzF0GP?=p>OdvcGPhrwA5TotcZ-#IZ3LZ3-f21E4XWZ>MtSifn(%$jL-J<K3BgJo% zEH<?{<08Td_!Cd2|Dbf6t#(bk<^(y0=1%VOz2<N|M)<ATee|_27acqaWLgx(kc?H{ z1SjGIvtTex9SRUi>#T!W5hLuG<-BFH&}SXnges-_C&z?UVJ$iFIH6UdsjO;MJ(^4< zObe!34LET|60wUuU%)jS6TMaABcwS{T#5Rp8`7&-HQwGz5@2htMHvqjE!yJ-ys=WS zW63RkWur5{(f6|A4WMS1=om+x+9FFW44KZ^_3k(nF#TvfS9^zfB8uXy1sl`n1oNcC zzF)P*Q+t3~z4!-vi}Q$0*nZ;x^F(>{84iLq$2?KE4CNaPr_p8Qyt%MVaEy6EQEkzm zJuO|R;OmBflhI<HsDI3aX;4#3cK^=mqGv$?I>V?-4y-i;3>rZ1RGsCz9sI@p6rH^u zo3fjA;-Z_PmQF45G&uy<XHFb$NS7xp93CVHG_>j#JDJ0A-iRBZD5B0do-9<gbBo7P zWOrySA<VYDi6DAKgSS&5^PLkNNI9uqxNe+570N~E4BSy!OH<2ZX-W5cl=6`5w!EWR zfjnnjz{Fp4_9Afw(Fj92k)L~*gKV6lL}0#>kAaF-5;yoC-~Hk1zy9mK`J2D#2mgK5 zSAFI8fB0y9)_~h&OAI!+P3N5m8XT!|jx_m{=sekBe`Q#*5z4o0X=e3PR~e;kf~)5| zU4!$cuR1_D(JK*7JQOE0hC#!<85n}8&fkv3kqp$NkWL6EI)C;l8nw6nQiKyc9@gtY z2bkN|@_f$MrodlNe3Tq0L|pZ(X-H{L{&!}nfdkglEf0D_7W$L^oq2gEx?k3TV{4xk z(Xylitb|viRB%y9<G3YmLUP1sw4pkR<kez%tYczNp}la_fuf(FDNvShn~)wE);>GF zuy={RHG``-P@;{Z8=%Vsv2-94Sx9&@!X`{#U+P4t1Pk{Y>_?w1rGDF83o~xrayDL0 z8MfaqPD<+La)U;?(+GHb@RP13^J~AW#}K&j$ZY+0+cYZnK3vLhy7#~LO|MPb_wCye z>XJ-(_o8g?mEH#PgoH|NiA$lh%nZ*X6o)ZyFi$2&H#v5-MyeEZ^O_l9M0R$^@E+92 zsJVQ`c`p7Pbq+{F*zR1u=u(k*7;D;h$(KY^Es|bp40EOQvW{N~9T<8QQFcUe6ONq~ zVK3WLi?`4zTca&ST4-W+)(gH%(P%Hqk2ar}l;uaGby=@kN^4SYNoz?8UScg#|HQ^k z|I=`*B;+bVrYq}<G!3>H9npg63ZWp<@WKF<ICfqc9?H#|@CoC<H?+|$kOIDe{I~4l zve$vO9<Rmyyw*syf7X6DlIxwQ4^K!kz?)XP%#i$zy)UvG29781R&R5#NJgD9q#Qey zRG{5h>KhC)51!{0$UVrFZL<7|cejrpKl$X74<9~!^6>C*!yELMs5CG<{K)fbA(m%q zR~n+fB<QLwG;$M)f*urEaNa&e4ck(W7Ji;nFv~zw(Q&c}#xB%rlYs{?%RItMMTW%~ z_U&k)z5!eEhdxbXcw}*uk<eS4NZ4zd;__SKpj&U&S}<lptNYeZzwpc_(V{!}#buU) zqAp@z`8yj+dJ?J<dEH9Sk`Z6@qA^;OKW@}UEO)YZ{V*-TLifmnw1><Iw1^8%r?E2O zdw*5^Bog;Vvez9q3&EkfEqKzQJy;qz?Jvzbj9F`;h9|Ahd}$?6XmclArm(5vo8J7Z z{N$}2wl^l8j9mn*u(z3#d;9K7iE+Cud>q5KdrmH64TkU4<pZi>aw8h4l5K($P}Teb zbM}(op_I$HufYhl_wfcM1OA0ilH2U7txrc+wj4EY_BkfG;to$`FP#pY^35PmGdYmh z**{1qK!VP<I8!|Qv~ltT={4P3bQN$gcx~P|d2!PTJ{oT-PX{rmFZ+4=!aBlq;U!Lh zJjY(vavw__;{G~FxGq6w$AG&36pF#m=>pKQ+<L3N)XwU|UIZ<gdTv9SE*7-3bb5mt zsFMz`U;8)Vzye#;lw3VJ-=kh{!Yv`AHaLIz{>%F#1{STC*2LNDep8R-LFl2pij)-A zc$N*-W}!dw+l)su*<b@;F7ru#Qa*ji(967&xI0ny4+gt`){py^KmF(a=2v~?-_u(E z=R3dq+rRm1KR$ePdocCb1&(*{dKT;+R-qa>%}-pH7Od>Y1TmeZ`BYmsXn{VB#!R8^ zL2qJH1W6>TnscC6&!rw=2d*{d!;$^kGzh$ZcVn@Z9<+W0BS>ol{6j%`0>1F>_9IPw ze9*(k2XC-~qTvoMn~z?KaALq;c&#HuIilsj(cLG(2CPe+IVS51@7}GoBz^Mn;YY;y z?%nNnW3BbcCl6B5Ot6pZU_#v4mQ)-4Ax3V%59(bXA0Ajs=HXoeZC<;rQLU=pzXMq7 zhnRVg`VKT`-QTYoNE45*7UD$9PJHITno(GEWm88sWY#8j9_b%6=@L|K2pxmRsI6jz zRX@H{sad5)-oL-Wdi2WGgR2PnQ304CP-DR3p9@eF-=N=O6tI2A_q!YXMY7Gl0KQ%2 z(*-|aE1wcp;3?{%-cFM^!KT$M7W$J5w;z6>ueBcTPaGZVbU)A~{h-+|PT)+Ung~<j z393ba0X}~A`u#oTiMqGm+RpnQn$ebictX>IXp}&0G^BASn5S|7I?NN6G&ew;CL9L5 z=x<z)L1g)Hm~4>&=7}qFh<OsPM@SP^F0aqd*Z7)0r0GEJ9F5SM@hY!<BVt~GL1TIa zLuA{`mF?w|H91~?26k{ACdH&FOrhwh&1k8y7yDn)*E!J#Z>BFshg6wQ=Dm3-G$OAu zD>#Ii`UNy5ZseR`hfq`=i^~zkwIF;*N!MM-+4lSWEQ+2OFlxN2Hg)y263})I%YT%C zX4E@)2+>)ye%~Iw6tj1DekC~3088iGVhNPCBeJ}u79!94u6W@!q%Z06qp<*2vy>lQ z5v9e)UtKJgploxO+l~MAf4=*_|IddXf&9LK0VKB7qf7cnLYCC!&=203hQ(T%qTc9K zhpJX4@rEgGd<mwVzCa~&3X1#cWbam*DBr}@&lquF#Sz^p{YHW^$F|H55O)>et>emC zzw9(k+wEa!yUfh|n3<WGnVFfHnVFfHFW+TmKG-cJvGu>!iPq5@$76Z(&gwfL(_~nd zJeq+a>pYn6#fwMepqDwFSn9L27!0!qpI(OnV0xY8oWskxW7VczT5J1*;eF4qcRR^u zKU+JnxNm9RxdOB{AJlzyi5TSEKp)kh8ew@_A|PZf6O`(SxMct!V1~o|$>-K{y2bf) z=bId9V9kpsUOuroOsze-uQ%WAILB(Dp?v6y)AfQp0OZ)2S!+*kY`=JV8wLlKyUPn* zr)HaEn}V9UWf$7@!ikNSw=x(U+28BVrR1bC3v$F&Qqj8CBBVZ^8L~s6UqwgSoLsbq zq3BFJSwfc(I4y#l2G1Q^-|o94!J)mqPMXj}zqP*RT!*0RnHSglLzh@{bpK+KSXMs5 z36`UBi!0UGT<K##u#~Lmlp@v@<~3{#?NW}bQ>8D>8DXMv$^ov8z$4;l8LEd;ytOnr zhRDrYCZ3rLU#Pt*0_YF2$B%Dhj(Zm84({nW%Bh8Sxj=uIKm7E`1X${Ic7`YCTySss zsB~5}46atzx<?tBO*I&{t9?gtgrNF69NjZ7o<6lb?51{Q|KePlIub!mCK!?;Nw1=Y z4E%<FT55HBRRAIPSS!MbY!VzRuS@y1o$gIjCdfW()kFV%S)d)Ih6D_i(Aa!YpP~m! zerfOh(iu^DM3rvJqgtw1S%jX3p?1l7@ghk!t3Ov!neq9bhP*?mMJy#Ipz0b~GcN;T z$0Q}cY2+kRNd`ne2vaC=jV@Q39Vg!xQG<avXxO9z$c^M;sEr4!b5^%J2_zDj;y@$S zT+Y3rZ;p`yubxq-@;BAg#7&kDDPL(2qcI{Ww;)~7E=d&(3`;u%<s*8%CXzuU4yo2i zRDBY|>ug%JPP~dBei!xBE6|^oUuY<UIRy5SM9~XJAsW28nwI2b4*X{FqW)=-vf#hC z)@Ge7@UCfM(=<V$c>Z2}cZ9MHD9l1BlZ+F(eKjPDfkQ{@(0t021yFodoJvDxC@H-K zqqY}FK+w3Ps$Xm@g}57%T)o;31iHG=8RSc6+dy9Z>%iFk0&@39CrzGt@zndg%gsOY zaUTl9G)?b&;E}KS_MbVtcOi3LFdpN?+LNcZ?!5W(pZn2|&9l7MoB!|Ez4=>z;MZ0T zE@rtC{D5R2M5IaEEu~86u&js33jC;uuUQ7pnoPwO*x2gda@}R0_K6?b>2w}^__1&P z-d{Mdcj38X8{hDypLq3^mu_zLfAe?#<d6UEb!&(AWLYlesXiG3G&d`-l^p61asxQW zG{KJCNi)|;AAIuI=YITqz5Bbq?N0w6|K)#v;Aj8noWo~jxucBnRYIIql$22HPHG>0 z_T;yI*~eXd)uk}zSAXlz{_-E+uz$IiJF<qV$;2iiueTPeErv^FMIUE6lZl*DNy0#} z?*WE#5wT9KCnG-SYa0<#*yB@q?!NUaKlzf2&fVPH{>5Ma<JZ0U!KH<+bDYL}M3#*_ zqd<z5B=&_9n?Lw1pLzD`(XH+N5C7z^-TTn9yF@YAZBcRw1=D<|IygNni%wZwmGm7$ zNL=;O!DqHXDbVYQsMZ_#fK2yNy6$R29AvrUSgYsf64K~Z9^)78v)m0bCKib`X<{k2 zg?jOq!`h^*IeW?YAEJRwe_iq^O_FC`I{n`7c*Dnh<OlTTyLaFFz*m0z&!2a6Im?_} zW=gDm>Ey=S-*Wj+|G-DvBzfeK$3Edpf9R%5j`WAQlzF3qCX|KCq-=s7r=}Ls3nH;B z8lbOM5CJrTqe~WW&ZV8s_k81LUv}vQr%tW^(y#sDzy9~#`<E9o=la9U(U7!2cP<g} z>ZLr?T9@S@CCs<A#sUyYlc)$MV(P6Yuch3qDAT&=ud8T?5UX_!GDJBxQaGqyE47^s zqxz{SuH1<wogG!FOYK8L@p6J<$_3BnWO^u?v5HMXdRUPZZb_-GSqMpGUG^S`3u^T! z1V2C;2p^;YtKP5!j-gSV;X{)Tf)Xhd_NHbsVYqVV&98AB38LbiyyHS(>45J`cR{&n zN8O+fLJ0#@{UPM$E9DXOjj6UStD@#0X#kMw2P}Vp+T})i;g#UhkWfF7pqxOIue5-a zN(ly%JY9auNxkV1&;o`YncEIDV@~TRf+9~tz<Ck4D7H0<T|YvbXC|EXLSf|nu?VAe zc4LP3W2W38sqqAL<D?X$SaCv_;aa9M@eGNw=P5jaPPF7JUO6DDH=4K82)0#I9U9^* zu@dpRETcu+*^FL!9J9Cd$UyHB2y4OS&aE6={)d0R>q9^AJ+Ha?@<D%a@Zf=u{-6hb z{x|;i{Iz|9Vg5=sC`Xf6dtzho5g+<KXRod}y1`(0*F6s!;{c5PB@IDIjM($8#5Id~ zrJ9yTOr&90Eo6Pcz5ON#v4O_|!z|yof6vOwkxr+xvAI>`g<!8ccl7Atm7|9@xB5#< z3)_Rt0#(aJdO;giaSFK1Xg=X1-s{p!&fme|FaGME|LaW;>^ZAvEgm|#efZG6wbi3( zV)yM^-soolX6Bm_am`wL?B&7A%Hh?OBP4g&lI1Q4yi~JDNHHPGBoTLh=JBSS{tTy5 zFJXuTE|8Z*C&CUKnI!hSb5?g1cynu^H=pND-|gAL$Nql<37|2tcIC+79aG)h+V0NH zWx0b8StC6}T_?PAoR3!l3@W4W84CuF$VnhOB6E_;Se9q3#mk%h_kFk9@3`%HI``kN zd+YE2#lP)a?&Y~Uw}_ZFb&}+{W2fK!?XG*zcYpgdP2PIf{Xh6~e{%8J`-fTXAJsnU z35Uh@-a_U#fcy#*JZ`bEJzQR1+HvXK?%YeqP8e9f%ZFlP6}AWY;$m-g^{9niUtfRv z)Zk`ojmagK;;~oNK*$aL(H1#RC_u65^+QbBU`>{}Jqz7)b{*Q0-h6Lip_gU3P3-1I z|3lvY9d5t*x-8HC<=<cThkx;}2lg!G&dFSEjAhoWO;gwYs1zfJz&_#%nwlnN#f5m* zQlBiu&x;{@Y?gb1GoC77+L}nP&4tpjz_8kdLz&L8r66LoIj*cKC@vtPJf0v6+D3<n zYDSzIN(_DC*<$Ads_UqM#Q{ojOD{_UspcYf58*};v|u%$$O}<cKy7z&g!pAcgrZYN zS$B90_s*9XAQ)nV1`(nH2gKk?V+~`fX~m35@l7O<2OECq6q;TgH_ozW7}6I#29YDw zs5~!l6X#my0fH#sXj-I1Lu<KF(U>?GXrhAc8aN4|slLkw1=Tn{5)F$uHY1QVW?Ls~ zPPv(JWp_}6Jf*qKMs+CZXxpID(%PCLAS)W$&I%|VE&B2Rt(itZ`QARO7M5X>YTyS= z0&v;zr+)sojvYIm<+(BDgWm5wE;#$(*7hJt>}Y^=H1pl`zQ<qsqECJQtFG9IQ{KvR z_ZNTlkKgz+e|7eey~AN%gM|>BR(5#yF|&wQ$!19F4KS9@6@_<qTIS2{fTSaxb0kNr z-Z1U|n3}6FhD?*>>Z>lf>4vLrzTxWg&s{mbzMU2+#^+#2;~X7#JGMk4D*LbegBm2u zIyT|e1jf)fxBG`=NQLOgKh@~LG$n_XbeTv&=vSdJjs6V9J*+xuqHddwrVX=fFc=Po znR5hC$2!q5k)7ECk<eItrW)=Nwev5_EiyCwBZNW<V^N>d&CRq_zi1r@D^{v55jD1{ zqGW;XL3YVS=iPk$RX5#m^%a+2c;fVSVl7}aR}<l;k_3+*+dTi=qqp94?T)Lw^rCa` zeSE!>SXti^45I3!vx@%{?{?(SMJ5(5&xb|J@;tG&z`9O}NJB$98jI)wG=4ujwJ=r# zeF$#XD36>!Al+y@CP$jFJ<P7S^rD+@ymsf$6_;N4%<-+!8xa`C1FEllc(wE}oVc~; zR+Fc7$uPRoPds<3BNj;=hE9k^A#}dU%aJP&jA9&{?x&~D%S!u`(@2$aJ!8DeV4>DP zdsS}DcKt`9pAz#}%+|pP6{f1fLh7teF{0G9V3q!m?I~&~NT^U|FkBECIL7){)^Z#= zYVq7GC8YBumDL)d*Ms(1BT$nLPo6|bv6^*YEDyvf1L{&|$clfh-+_RJiV5WtbQpy# zF6v-0;bssBuqMF-)m>>+cma{oO8}ceO-ry@z_1#QuV+hPpr~q+FbHy^YFa{jm7)P+ z3fdv|^9_Zq23jFbG3uKkUU>#;sXf_L?;wl0$rdREQRb)Y$8JOLl8ZF}2%I8@3mQUX zI8ijW8he#O@c^rREN4^7Ql17BuaIT=!To3b$v@w9>rMagkstQ{{eFKZ>h`lf<%2)_ zYkvHi3l9yP0Zp3NQ>VACyKL><-}UW{F>`aBC!T!fr+)d5-sAeU{$L1;1c0?Dl-IB4 z1~pF&32R5lI96<jMbRb~=mDUZhdaj+A$GTcj#=*HNDvnC04yv<&0|H947Y8W5l+Qv z0;YJ%V!RyeM(6(zUrRh$U^ONkBy-22iJFqdJ=PYF7|`VpJoqTUQ>QkbeCmb$XN57d zz!;_h4O#r9=cqIwU`(lj@%$%Ac$I{;24;6ruRq+8SDxqdX<~sqcUK-+dic>N-+b47 z-MP-=PdvS+mpX=d&8_h)DM)rBHi|W3VALrdFNlQ~_xO>r6b7pNzsud~zTVyUKI96n zKKJ}fy}6WRsl#^6XJbk-3z3VkKG9G#7H!Pl(HX-LdLROnJY8PCwm78YNE-tY!z0D9 zVv9@g3RV&xJVi3t^b27Z-fAo`;sc$@^1Qf$v6u?(jBv}HGc>F&k_&ia9V?hK1rMgW zXbV$nqbq<Hj4Byv3Oll%7U>SXhIroT&3c^%0>v}aVOnqUEVRzkRP8kFh$MfrMaUZ% zkO+OXtUOGT@`e&Iu=MvOcx%U;civsl6JkJ2s1*Ih$;=Mk1(6&HS>Lk>cz@_!gm2S~ z#aNHSNTefFrD==|9Hq&FhF(}|;*rv9;T0PNp`JM<b+)L%nB{qYFmz;=W!;@)K-5(5 zBJ{sIb`+E}j#x21EMOtAcBzx(xf=`yfX%YpETjctVummwbqkCPm@Y_u;#r7-B@ACU zMnVLO7C`mLjPZAL(&Ksv^iPkd?sU?EbZ?ts?lk(RjK_Vc*Ex3L^jq(~4;BwU{P@*J z7mJao7<m1-IWm^9Xi9%h8Fw@}O#7we-9M$OkVdM7oDb8FYhDWr4U{@q$YcZ><Dn-> z{GjiL<AA*~=Sh(tW_@$(t#{qGxw&=X#HpvAd0}y(%i^_Xm}ULJAj|WePH!#&5Tt7q z3ZYi~WW|kWpYsH=>T4O&7Y9p-vxYv6Y&6dg8Vq~_0Yv0vM%^MC8&$ci60E|<xad5T zI}_DvIC?{vwU3b#DT<CfA*8{8C9#zW(O9wq3L=?9KS~N<teQB8MCE$bL<CXK)FmjB ztDrm(iL6v1QpuqqY=iY{HJmO#s;bHA15mdesSk=Gp<NkZkx*M}gg{HRb||T7L?46{ zU~T<DF^lrst)~@}5aduNp7aafq4EF%*Q&G_s9wdDiMd2je^i2r_#sX{N<Bdq8s?(( zq(PbFL}s05d__4-Xa*(<sEDk6oK|(OoQeW8RQwObh8LAC<qox`<*Ujl<LjJ7Z|Q=n znzC$cd@E&u>AwbznFzBRN+7kv+eGT3@{+J_ulG<2-f$9amc3|u4I0W?iENbPVp^tM zO><@9SVmZ)5S^<16c=0TRNx4j`x7>{Ui>d>XQ3mx5rkox?SW$sGc&)#JwXJaH;6ET zp!mdLW)g*&BUVThW@Z>N+nujny3wdL>zlRq&}w(l|CejF%e&o&MnD~6@0g80%JR^^ zEUPT5GmqJM&tos1bJl66oP2zi<(FK1{-ygbdF|bgc5WL~Rc+bUZ~w*DTzxrP0c2Um z$U~1k{ogodXKGgZahy++Y?2gNQM-;cjJ#nK4Enw_-~?>TwzIs<@&a>FpqJ;;-<%(g zn&pUBjD*~E92UxHRupB$q<-i#l%&OYIvd6Lrk<~lh+MYA3F5NdKORowJWldBFY~fy zgjMUX7xW|Fwk_$TBUqMonioo`Ug!s&OB8uojc0jY)S+(=dcm;gd#(#U;wygAb7vOP zh<L6uOPE}aW_eN7QQ#0bQkY}f+%IFTQ7PSSIB?sO-~1hK3*BS)ZXWhS7WJ|cLT8?r z<0QxbtgIZ%LLZoDwXRc^<)S(aVLeU@{-n8H<~ufUd4!33(zAd9oV095N$=PqgzATX zW;?d@iD~!t;frs)f6Jq9=5>AIo=v;94#1>=Q8{|9g)A`6GN`~eoIyD-deT#vS0CH} zI|OJMFfyK|_@5SfgkT5w(+jFbX05aAKy2sM!R-$||I0rycTYZi>wMd2$F?yar}-?+ z(_AAEcn)pxUgU>?tJR`r?c*RBBm`zTj^?!CE1RbLPegX(UJ&>$3>qgDF+WX<Sra~4 z<ml9O!B(=UJUBm2Gx_m%62kXgCE0cGdsK_EaoBfAq<NbX<*<-urAYB-amx#VM0^ln z@uYb!>?A9uNj{opTL$6w%{|C<UCH*W0bFwjGK0oR=~6AeQ$tTtR5+YuWlBhj5i9Z> zSnGwJTIe(ijwBe?K>(v908#UFGc$^U#f2zhlNb=NZbhMQEi0mFmP=0!sPVaFZAh5V zJ)Y)JlxiX6+7?7p2cpo!1W}6#iUtp!Z9}WiG_r0I=Y+NJ6nJG_8(*Qhb^~La#2H{H z&#|ZsoBEJouksoe>kuc`*j+lEe5;iX7S?bEe54!5I5`}rB}&NZUXxCwu{0CsF6Ma! z?@$@wlzGOc%CeGNl~Rckl+P2!I3ZKUKpPU{sV1>0h87tTHm0Rg899%BkO3kXBSV<q z3pDACpW02C2?)?cQ1YCPCrR@WP&tf50=_TGTN*7~$s003Ce5m%s)#D|9mI7m*}M|d zF_GbajgqE|${2}V|L{+|V@nTV0t5tUTT`e|rPCW~YlZXu#`7rfq+$t*Nm}3=;d6_T zS)7r;aaQiy+WYp;xT-37+oc7*m`qR0;0v&pHZ{p1j50Iu+#v8UI$!>93*?#O=!m?A z6D0+cK;k6jnyL;Lf-2JxpCuVg#oDIwT}z&2GM~!4;DDm$Gvav~C{#{n=`1P8_CIHZ zWtj~o3&ga3ZI_vha6y1uhS4Wq{Ivh7n+V{@t-T|gpWi~9VvBOewTHT3R{u>>$fdmC z51+pb20s2&#@C=IL{QhFv;dOOw>S5BvO>Ta&Gh-nL_v&zu-1w~J`Nxh_okW@a41Nk zz_W*;Kj>>71qTUCYCBYtbr|C6zi~QlDq-L-f=Cbr{@hiC6Gkq|i>0c*?!bee{gv$N zdwldj<!F-p{%<TbP4)r*>euPvJBKKc@`a+#d!87*GHc_GyKGqlnPVGkVt(0e>8IM% zcHeDNb%<G+qUKOX_>A_tQgW@#XiOVj_8?XIvXykp{1#66$9y$oY@?ve4aVpFdov7E zgXv1gOl%L#3~<?5j>b^iw)QJIY3?A^@)%p|`(E%4dkeJ+8!5aD$z=;>BU|LstXEu` zM|~`6R~_~XQmbHQsdZ<NQmtv&&R6^Psiv~_09wNlXpO#Nn{l~TBDn~?IZ5OePV+O1 z^&+3jmH&+H^qQv>v>w!3%arABN>(CWwTK!c*6NkMgClKup_Bp3%F5LGZmRYa<x0){ zX=_CqLbdr8xML?C^IdlnZi&XsgN|w!f>xb*Qfs89)p7qjLtD$S%Bt-E1;f2=2XvY@ zmObBQ#qJQ`%0#N>kG*jlW~kNjWGN@AtA&pKn#^`5RjCzHsKtX07_0T<WOq83!qDor zEH$&VxbJ_y&H~1D=Lq9}9fuqT943c3N6A5%nYk5|QA|ZKQ^i=Wpv)vJx5pTMm*m3C z<mB<^SdZZZN49o$_M6$vZ&vnCfAgJhe2tItbZ+ibAA8Tg_anG}Zf>s88GP`q!L8uh zbUIyLUjD~F|M!zW?gi~CRJX-O-$5(izZI}qO+r2oC@Np9?CqbQ#dA`E2M&09My9~9 zOge>HMZu6_v0AFOzzDd5t{izc8`TPh6z|L|lxmH3AN9YD*2rZN43W+jbCr(OKz;bV zZ*bU5rE={jKmQvj)pIuju#Em_ieh!uO|SZ$DurAq<iqSnv%7bMlg&94|DZ{jGsuTR zM(VT*5Xo$z5>1u;cCFQH2>2WTQ$Vc0VnWdF49+j(|38in`oJp!mg>&2AcK;LX`>ot zdA?9h73yxY+F_^t9-BbGYqq+_XR(9R1n`Vl$U_nSTyLX_W^UctUbVklPL9WuOtv&; zra(5}bEvoL?Ey*f-}<_Bzt>3;0-(8arI|>kkIt_^{Z(=i*cErY3#ERmH<l9o*YCPq z4vSnS#$&`8W|}LM|9^0CU2Fn6V2)B!xazfmNeFl=95zy^6rXtO=E}+v&Uyn^8MLxj zg*@Odh1t4*XrRc)Avh4Ic8_seH9H}{$)H|ZTAEC!=}d9|D4e{mDx?A|E7%OC1CtCo zN~M(JhgdS(A2P4ma^tZoGARjCf0fD~oy9H^1*KHTB8KP1+XKjZC*U%?g_5$kDU~0N z7z}}h26h1(+6}n_9y=wMVC_1+LHfFQa2%<%1~QTl6apc=C`KVOpPLr&dE+s2bdi#g zg7>{+!|gDOMEt>E9FC<9Ph*uvk9q+8ADjSvrP>_oRpeXV5Oms1P!Xh9sWuOe!<UIX zKsInW42CLvE}GBd;jVh4Rjf22Cya={1Fl(VHJpH7E45a&-o}z~jh>nI#0I?zShreh zR_h)3AD2Bo0gmt*^-3irolK_Jxk|a-wVG5P2>IMjb2eA}?)U#_*UOrn5iSm`I)WQ; zxEK*ssWtbHBbV_UAzXnO4~Z&%?(`XvV0ky_cDu}!j9kW=PNv05WAET1ov#a6to+Dx zAbs`r5Ur6ny>{L0v<Ubsi0(x4`u~TQnR4gxqG4ruY0YQlngPkHJh<UgQ3-iFtp<b@ ze3&a%p*n=&vl^JaaCN@k8G@|6D(G@LXoXyYgfp2;%GKun;bkgUgC01ELd+(E3KyXD zbQ($H=GSg}H&$IFNx;tJRrc^Sesx`yiFw?4U9Kd6CAId@ppm}&t-DsU9=UGBFyUwl z5=|DHFW)n8J0^%(__WITg?U&Ijc0+Z5du$DR(=o7<E?<oXL4nRxe0oWrL46^NR`_m zA8pjaW9S5Ab7e$RB2$%<y!pBL8E<8MXw)eblmyx+R_e`WZ((u%@$JfH(Md=VJee(2 z2g5ODgdtzFt6&jp?E$p?nr*+&V-*SclgZ6ewUJ0>&LSBAVl)vsEXW;`t+j?4O1u+d zpYkD>kr4BUnPl^&y~A*}*aRo#p4SBdTWO6{LLk5|q8VWN*X{b(0<M{1w-PsU$b_*} z8Tsl#@ALT|jA1;IYJWU+S=7M|uU@M}oDN6hTBCD(8cC!|&;wFBzBU3j|Lr?63BgTP zOc0-V>lz{CLr%?hAJ>4W!ozC0@U=Su3$2$+#kh0KFi2T2zFhC{*=>y_s<_zeq!G~= z2&N91TkBqWJLuPGl$mV7@V^U+l4B9kx!?=<pZVIZPAx;WFI8ID&Yn8T0}bf4l!B7N zcb#tUMykZ)fqk=5fmgL^nNlIczXrn*;+LiK4?4|40WaXQ!ZXcQCs(K;{2>ycUTic0 zw+Y6mRq_Qme>9FJGDvjT0X38elHfk2V<LW+StP_h)k|l~p!T6vduYRJGHQSM+rJ^G zA3xU3xq4yNHiK4oHe9o{Mpuu42ILaa=icXluV6_kTLz#9$M-r-Vv%r!ggJX}?fc%g z>v7wl{NZqxFi)cCVne4OA%j_o#8K~88r`A8q~6)`n~i$(#=719!AbaEdtpjStoiNm z{Ec*eG@hW<!A8k*3#of-Bd|AOZr{GQ=ApMk0kx9#Lw_)e#Z!Anm$_<JM-dNt04$G2 z`XxjHO!?p}Dc~=?_wBoWuU$+CM<XU2yMpV|`G%GvZn3%jWgnYfA98(2Mxq-LPv+pI zz@`l$CLsxK#ibJR%lB#f3b?G2?*HF4k?w8@0g)056lv^UT~IKvJKuGU-F4km-woRh zyIvD(?LaJ43<L~XQM$|8=l|syoqcv>{@i)v`MB)Ey>n;IoO5O_^F3$2Gq{V6wmRO| z#bs4c<~x``66ZYOm-zQlZ&e_kfg|Ys|2B())D%?rZ$jS8a#Rlc2uCLIp8Ze40}4(q z@qfGiM(}w_h{-`x$lf2WXoB>TX`B4Yv?v}>5C=PG6MX1~#TLX(`ClAak{l8ZR*g+8 zcm>XMY~r+2iGN>w4bG<%;2gM!8zK}*tl#lA{0l?p0?EezHJno+QjbJI=B73vDA=>> zSd&Q|e8cE_iKTpJQwr%J`Ltf{i57oF{g^Y(WgS;TF@A})hSc=b#fdhnN+KSy`rwc~ z$i|n5FB@;DF_-0}IkVl77%}OS#9#_Gmz6X_PTogh4iyM{nbtvsq_&npu7!_G`_W^C zS!Icy6i8~J|7UBFB_t~X-B-w}LPSV5?8r1P!|RCza?gBX1*d+@G{cyHp_U+4k(GXo zg3J^kgtbbH9qHNe^2QxUb37F{;?*i6Le_o|j+O*0OTID(U<=KDtV=Q5)j2NB6G~)W zQ)+-1U9b+WR@nSm`h|~oGtUr04K=lvNlyy?xoAwkKA}L00d&S4IW>0K=H8xGx%rh_ z)-1BKwZhu<MSkIwx!)ks5ZH81LG>q72K9*u2FfETKks)pzfHJ$^XE<b04y5lX#%T? zJC|`}%bbwl9%%Ex;p3wgZSL=DgPd-(jy2@7!m96=PVC|53jpO%+#lbsKTux(df(bl zJU!Z@zUAMpHZU}Z8a_Z%Lmg}2tn8<=7OuoHn~AECP1ZnNU7f6BqlW;9Z`KTu$zM{T zKx*2PFIW8z9$zF&-p?%feCCM$eM5nxC0w~xR#6ca++8A>e##6l)cG{;#V^0_J#{4& z2qTn~nq53Mwr@<-P~5$pbU(kaBplo?fNzxhs|gDHBqMv}>g}1ifQGeDth}nOS8%7P z<0Fyfo}Q6CY3>SRea+J9m#e;*>h9(Y9O2h3d-ohkur=3*kdL304hr!Z8$HC>$bg*p zh>JuL^m_l{Q^(FF*(nbl1%z5$UOOPX>yUwAMuz%CY)VuLNzPrkvhMdIB^5Q}h6j!x z`*A&CY*$Hn0EV)4$AS5?ckbOkH$1c_ke8EZ;y?XvTRUq5fGdC|TeN67dF+6m-8-Xq zL?@(j09${YiQlmGxJK*dZQ8WLjja62RZGWr@8(-nQhNC4S;QMUw0A}$M1HgfG~vwo zgpFH|>FKD$5RFa=NCdv~q+r*Y`R!fttYX8jdk&qvYHp<cG`}Lq&pjrxKaNtQ-6T4x zs;)k9^3so+k2_oGLno-}!!d%^psS5PF4or8$}cF~vNLXU)Bs~6Lo`Y<I`JtfE&FxL z{>zDJ$e~6eHe^B@Po9_0i0Re0SD?0*CLwPjv;%1R{)2}<ZP;5>T7`%Rax<6CABSKG zLIt;y?)RLya<I1*&?`iea`G#G`{!IIM?2tL>6y8oE?d{CWiv8y*44jRG&{PZk2^$+ zPq;Du(@kC7%t1s0AEmjE_*zx_`qSB?{JVHpR95|S?RIk${f|HD2Vh7;L;cq6`%$xg zur<;E6h2{egSQjqkRCzE#M}3me7Ds^uML?CAb)8^ZAf>okA{SsnHZt4>VU<Mglo4~ zuG^=p*@_ql<uU39NBG7>4b;)rqJ?2CY`i#o{)(>;!XXy0?COoX?x$vK_+e2SwbrQV z*opH${&LvbOb@*#^;A^XyE$4c`D8Ls=Gxkqzi!=k;{0vk=_tUW-mRKv<dqHU)oD=w zPzy5?qIOjwlkTRhTC-c3wcU_LyLjGMcUQ+3`9+&|#trTpXm4jtM~%`wYT}NaJ$C9E zKt1w?#jW&brPE`2_3Is|1+$XLPx&dYsNAvV_>cj?)|TdV_4UiYU!RnmqpPh(-Idgg zab$06zIc8t9*2@Q?>Kb$#1&obHYi4>qK1%$q0Y+XbJWz->gwvhUiItajHft&5&6dx zqWgpdb_0~GGMW?sj?Z1Zij5A)A_c;TRxlZU`Hz?YKVMXJ<oKB-KkV!1Y>EV2RF3ih z!Iv%=@9b!YD9*OsaR-iFF#))YY<x11RR5Mx!pb=X75#&~$BY~V<W6-;!OzF(*$3m! zT)CA7=o7YpP$lIxk%I$!g$3yA=`d3Y#>Lt53E!?gU}LI-+3v=}{F7TgYin;?Ra5iJ z=6#_-U0t0WP$~65^!-5GsqF_Yn(AxNy%fyL762$h6p(!Gl#ji=-2SE+{CoQr#794_ z-wj+FIQELK<^de03kuQ-UI&=yW`DW4lZ*M|r==4kLwkh>=;`W^p3-7~lTVzEN4OM8 z!AMEAFx6W$f1;&@X>M*_%*^i=PW!04pD%e;Aof7CNL#^Nim(>?K5zMEH#-B&Gqfj| z7oQhZPKoLJ(U3kUiCEOEML(*yYK9)-opR`E*4fPqx^(hJ>oC@g`QKL8)?=E5_7M7s zjS3s}@gNA9lKQC2$Yn!2+vet#0%4yLJH*?wJ&~U}XH``-;Os5?&s!L30UyVfBf!Cn z=8d<pHh=Ua>yu^cXN@1+rL(v4Okj;4R{w@@$lRH+*eCTM<<Z0iKUf-Rki9!d;s0jI zBzL!VctxnGwLWt$eqi*EpU;b!J$)RSd-OQH%gE3Ad0JN1zFqz89K7x`GILLyx`;Ut zM`e;-3os0<S5#cO@4)eW$FG_-0Ll$7BWNkFsAk@zL4Cq|w!|=g{|?2^<OgZ#S<eRc z4MC?4#+_R8`(ccI=($mt1?nj(tu{B+n?HS&n~O7L9wSwimX_^1baLJHQ|)XGU?}nu z+_(8_BO`<2lG63R>=_l=-^#+Ah)T!xmhJoFPTe#$)F5y<gIl5YR{*$mG(P`yYFm37 zfb}bX`mLm-<foNONkLVAgYk}?I6Gz8<{oYq`0GVwsmQP*$^eDvAF$*LlYb?n5>|f< z2&!N<pZ|MjX)0vqP%9eAd4~X$qe*5X^kKF>MkAc=Fruhvmd=avw289Bu%b5M=lwIH zDX8_?!r~d<RKrx$3RQrkiLO!&Ge?QD^t-BxBwNMFY|Nz4^2~t`<L(@-@p71H55<z{ zSk51Q)|xC?*b>w|h$`3)3g#kH6EL1DYi#m|BE7@!7rt_}M;5J&Ozdb?R!zRB?!Q%4 z4t<v52CUpnK!H0c@-H<pCW$1BNL&rFPc!#b>_uv0a_c2QGZD|B%2CMZ6(w#~P;7zw z3~i0LDFawjq)T~|R?<wBoss3}k?8*^jhaev@`Zbp2TBX@F%$7Pd@%z1@R>*XV4WmN zCO~Q-dJyOqvtvp|cLdpeB<27W+N$bTwlnys{>s@8!Z8z1D)AE#RiiiDn*#QtJ}imB zcd`yUlm7F_xzsc%nACKdwj^5uQXzE*GVjpw{P%v5atsj5Ug9*tbWOmKS*22u*&#%~ zid&O^>N>M=MiR9q%V{mXgMu}KF!D_7DKa5`&~<?xGnDcY{l>3EIEkHk%P{m_Vr)f{ zl9s{U&hYzndmlf^1dBJ8ra^&zll%D|+MP0U{6Je9D{|)Bfx{;&Dr?~b>S}6hzn%tK zaG>54pCWJo)`vko{eJp(UONXsW3L)82qeK#qS<$UAW3va#Xnr9|4<KBs04Yzir24e z$LPqx$l;Rkp-<6706I}CSFp%KTrhKN2lsZsL?8(TN%0+Dygc2O&KsLoTt!Z)BD>=O z`k;KDh`^T04=&P`GoZbN^Cm_1>sC}=1H?h0YzWT+u5xpA4iD`CI2#}GM=PpA6G*=P za?z9!f6wCbYDmBsoWxI26@dl-$>A$d9{dh`aLUN=xiiKhFJ2YDLjja@a<rc{HKtFH z*Ym<kB;}#-z+T<PkNL>l)EFi4AxCo&^dA6H-(JDvNA^m&k_%Jf13Brd4A#M~2y7@N ze?z&@ab1}=iH-lS+S;0|ST-#pq(=(^)x2M-;Wi!|+&^r^=aZ33PT=MiN{gdw=ocVM zFArBj2}>Tqbs(OD`iBqc>t9+?gBqyo(xn6S<mT^%L9=MMyt1x)r*^ZZjIyz^z(v|k zf(mJCX#ohH8Ph8>uME9ubdVC~LZc7{VCCf45f)~q#E)==*xJ<CXv%~rHz!MQWuU*1 z4@?y+J{>da<AF$fM49&x`8zZUnD6&r%<y!x1L%`qTJs>~A-n)mAyIUA7YF3;Ll33p zwPF5l2w)%zfws)ej36NaQIX<`EOjSGTU-Y|c;j}elR3>{WVVRDV;BeQ7}(u6I&vU1 ziC>Ao=RB<m=-U4Cg_B)f9N|vXVTeB<jP%{&*ovChAe6?hAVLZ5?l~!TIDlPJ0PPTm zA%ho~EQWbXb}{6{6_lSkruWndkpxDhqZ@VUYHJN15RP!m+dtou=5q2%pQLBw3-CVV zh8Neqffvy(0HShpbwJb#Zc<iWe)u#{Z(y~5GL}MaFJQ!>5x$dSKen~9fKbF$U~wvB zw=Uk3#ts66M|M1r<a+fsttZ3`Y3J<l-s@0aLf?=N8#TPYw}&HwVYm*X<d;@|_i0Sz z@P5DtRXc^}(4Fz4hv@0)ym|YE_m?ZwrJ>RKLgJ$r1%<>#1AF)uRo0R71IbWDbfH&B zS7fQ9KxtVyGHUU~)JW(1&nNfm6@;-!M-yS5!AQi+^ZjR&EsXV$kc&<!-p`bj#F@zi zp$zq8mGrkw-1P4i<#dFo+srZjrcWA)-l<M0B$Vau<}`is$S&T_AgzMYA^GUxVIxNj zKw;dcV~vbEs2Wqsta1JF3M-I=4fY8{70LV=6FC6EDk3sH6jWWkP1J}1gCaVkJhIMt z+j@bCfAL9dfPW{V8KPu7PyE@}$Ne9(q7@P*K%}m>M92qaR3@>853aURdd}47i0H^c z2KstLV8{;ni7;wvn6g6qgmlIZ2256HntY&)h0}(I1p48k(uib!dnd`eUzL+5T0!?1 zQ;=_&S-FS>LTpo0qY(cNd4-kG72cJ8t|ofAy09V9Mq4{eWKyG13<rIkHa?#1Nmh97 zv-}Pw>V+kh!QI`z`FuLIRgtNf9zBhZj*iyY=%L>%9EXS+O>!a%$D4BToai3@o#FcL zo+2JVomTm}0WS*lvFgj|U^Bz>=;P_L@k>_j=;&=src*M{kRy&;EA@=lb#=6&qXv_? zm$)LDgjP*WjABL&_3dDf-2j*`p=d;2zFs(HaQ|>{pg@^qb|t*vo*mr6g8fM=K-*E6 znVwZqZ@eIa{XJGJo9*M}jwwWG6a}dYW%Tv+CX5;J)3S-!ivxcl72y^hZlk6)ZDN$Y zjWrdO{4~_pn-m+>qjS5WvT6)iiD8z1-!wXpE<;-Q0nCjX_zA;*;BTz}>sP)0lUaf@ zs|}SelH7x~NNMh(Q4(JWv-hD9A<UqOf(o8!%md6aMK+QzaW3(5ucXFnQ!x=!NG`>% z#9tQ3;aK6?RANC2`h&H*h?$tgEP3l4j27nn0D6-x$$X{XC7JoZGL(Z7{LV82SO{fe z`pq;WU}H|Vh$7e;1gfDKcN{)&p~-=YB%@zUF=ph_<M&nc#yVPK2$+In0Xd*2e}K!n zBw#N|l2HRk7KJ#FChYEP+w3etyVKMO@KpPB$V;3$>8h;7|1bEXAnXGo+2|~Fh1m9e z1&@G0Fp|rBSA0mF!4{O{(<0E*ZT_RcGTS~oqGXHnw?V5A=423{_hro_SRW??l~WsQ zFoo<hNa=qf#}~*bq7bB};Wx#6Q%Tnl*fB#pD9MFh>GLw<_yYTWm@{?xx)3F+qlT9| zorrHtq#;SpSss$0LB;jRG8T#MXq0)>K2uP(*Yd}uz*H!=Zk`E*tk0~qfPq5P-TRI% zm^}dqppK3<AkLDq>fk^>EO&u;B0F`>&a)snNy{x-Jbgrfe`o9^$I25)mw%kTl$n`p zVqzEwG|trthl3%1YQorIqo#eQudDGF88AE3P>Jy&1r(}MVY%+t)fWqOFaVU5mDktR z-@2U)77n$)?>fg*fP+saJ-f6Z*3#0vz8(c%UW~t<c<Ua?gBvn1+`--!$#+2T-5e}x zYHBDp2Z#i~1S%^pFGt?%oqMVHwNu9qT|0RJn835qQG@P0NCz`A5J9v=PVmFR7?=nk zu=s>qsSne&v^2W=b@XW84ox7JaKzBw3AfW4Xb?y%jP~DGLMdPC>R&n9nu1;iJw+~d zO>OP98+Y&CPerbuk9UXg5Py_JfB~@7lgzw|${KVQO`tG%Ucs<&;?yM^O$i&>*;ymE z4k@~5)!DhNfu~v8;~b=lqm|AbI{?x`qab`qPtOIeoc1K=|7`RK5`iDoIHi?!pA7Bo z+RhQi#e)BFde((YH^4B19Khh7ovkd*0qgj9wI4Pp^vfT1I#?RuNrG6xLqOR8>WSo( zN9QiysHi9hUf-{GkhZ1<Dh~_x`)%(9V|_qB%#`{ed(t~!02&+->W}V#Wd&K2C(m4d zkopAIUE0|rFBQ4i@Y1ebeGZ+v2EJiV1_!m60?Zy7>ew}3bs;|Se##^4g%9xe4eZew z$Cn|+HNej&@qV_UzUIB0;(4)sLxTM3YU`mTz?Ub_BxGdfXliMN^z4jecJRqqTAEE5 zGi1V?l}6fXSvk*3%PRovB4Po~gzbkDT<wf=imIcm&2)8juz3Ol1b9hD59f<l@9Jo& zBj?o0(iGN&Z1BS~@prKa0C6TZD~bZgNY8BD8tezaT@Z1BJTG1qK75?z<7zNw<X`~P z@Bz>iT!_B`HUK2HhXi&7`dnZCCt%{ald5Jf--?vs7bR7Z!+L{^==JMYWo4Bo&n5t> zMnlNu9M~@eoI)6A$Rh?P28IJ*GFK<7A^pQ(ef(NoU32xu-K4vzz^%MIUAp>u0N91^ z5oKe}D6M&waP^jF2NyVonW;%sFQ3cTQ=v%=9~cFkKYpFPP#7J#m;4af!ynRQp;!Yg zkB$aVVB|^zNvy1@K7IB|>Z5dkXNHCb1N#P>n;FBkI=DMqnCKRlR%x_sNs^IKUQ@F< zMha|t`D#*mS-D4tcE~)1jF5kDzmSX99so0aoKqY#Gyo7G9sx92R9tc~;a1wi3~g;q z3=LGPuC9jEY2{Ik+z-a4slNKjvsWG4+F@uL8R+|YIX=rP0B{Tz3S23udfndD5fC0a zcq!o)gfA+qof<n7+dB~C0Q3f&6z+$^fvv5~g919++E}8qaH?U0Lzk}D29B5aE~}ub zQLt%q#HHz0vqo~a;Bugf_Ht_&eTYT?9!2VF;;sAlA3Q=juwPeics`nd+YcWck@R2# z!ZRRi3Jvxru|{m`IdLlfS>6lO<zR1v1bK`#^u@D-^PPe{PBuoQNs<E#CkNO1jl_G` z67N-1RJgi2_3s5EHh2g&E9^aXy-}uLICx!yn_0U!J79F<3Z}bbCojEz^|Fn+M(?oh zZZ3`(^3IO-!~6U1I&k609~aPHB>1<rx5Crdi*w`VeZZZ`DUa1#H}`ID+qYK`91O7X z^A`ojPhHB-FH}wx4t*kef<6TpCZ_a1&fkOuN$c=cBO`rdV*`i=zbdb&!ps0llj7ns zCkGp3praJ_*<8PQAN(y3Qq#@!+Q2zfy8(-Xz9}gs8w4pBJDRQ3EzFIx%IY1go8=c* z2KluI6#nY<Ym%An-_`TfWeoo|AaDnln6;G|YQTHy#OW(wDhKR5Y;bQYOEX+SH}55< zUA&x#?Bn)sPCdJKB5{j=?wzr5Wc$9em@Y^cFz_wRP2lG+1>QR_G2VLFx%n0*`tSWm z0U~!Ws9=1pT0Yas!T#-=H@FdZ?97y}wg<Jh$bL~qvz{n_D|rt<QP^1mqk|A8;o41T z8xGvPTgSkFE*K-2lLzz;=sn}-!M-+6^UKFYMg;fl3YDU#*w}P2Araa1@NEPY&?$uL z6z@KN@;K`Vk2ZW}<cR(l8ZbR%zI*q<>2nEa7qLCm4?TdyJTSlyBwZ_hJLc;Q9lkqJ z8FQn$I=E|UE?&NI`%VgG1I&IAp*_$f1~_zh?9zQ>y{3+^CoYXd{=y3ESHP(80%Mwu zm2$^bZsKkDTbr9n$z5#q5WM8CXxPONTaw{C5m*n3e&{UA@;Zpu(>Q^*YPMWsy-_f~ zGPTOilj8oh&P<FSUK61V;G0jBY(;!EB2HV$uaYI87hn{Xn+hc?EytGy*lZMyFLWg_ zQ>t!+Rd9_a2wX|bmSBMuwaW2ejO7F*;9mQ1Gr8<Tx%f>8Ko%_jD>sphe@Q@{a_S|H zL+wS6oE0ByO>eDG$S^)*CIuff<HKB%Y)gv2R$B00B;;E&BDaFuqQo85l(0e)pGYL} z7!|J&o0KWB;){Lgk-8$ilK3*QoY8C{zR~H93rf6CZ_(OV@&puSt<CPjcwZggh4=}} zvXvq=S)-(2`9MUi#K5nT`1y)_d+{zy0tYTqmCI<2&#=KIcvA3f#T4eB#@NUW!M8s* zUe0fcb4y~f6$Hkeh>GbQkt_<fHZIW*`(1pN;7cImQP%xFq!|<IG~G5yhn!#?V)l|% zKM_ksHv9xoh0V*q9=rxvvrj}2Fgy45?dHuGt);06sR0#j*>%L(LZ_;>zO%bsaF9PZ z0kF_bdz3zJ$<GaFY{LO!k2d}5;>ty%!$ShFUUhMHj2#hp=EAN2(`f#or3rZyGsYo~ zs^kP>uB)p9u)g}Y!+^YT(wesVUx{PV`!q;o!v%J*Fflg5>Kbs&j@@w!Hy!I{XMiej zK2}n4#=2Dt4Gr`GWp?vzzbEcIPKHw*jMyu^^5@@=$3L(%)WpRN`{U<DhmVOKitorG z9NI5%{njHCD<@b+MppLc-)_oyT7(m~;LE=qh+jH=*nqwv=s4E=QG)_kY&>FZtjT+A z)7U&vGw=@2pE0UctJXknuzFv!VaLwniFPL1fYR0;yR+=siwR?g!*c+bI<>XffAZFV zU~eR}!YH-1wTqXp%g8Oj8E6Ow>^ON3Fy-XfC?u`|kQy4`dM_pGc5)^ZWN&K;WEQlo zHxlnGSbaR8oso9K0g0_u!D3|CRo2w^4fg5i)t;c<05q3;zg4Y;1UTSY(&Gas5|%HF z^>B9qr)m$sj(+hs!BY&djHbjwE!YgcVC5c1GcEKk?qW(|QQ6EXqo8X56K)P>fR|tb z1<h|(aQzxcD9%;|T`#~RG;tyR`uM3^!oqBD>qLA?X7=-WGsXb)v9>hp=IwO!ToQ;} zfm`y<ej#atz_xx^yDjeQU2{VXr1P!bo_K6a3xJ`(gY50BObs-V{o2vRGN@-)07)%d zwE#f5X!-iQ{4$srwQP;Mx_tIW{rdz1mqF_E*byPW?mT(%#-l;~^Pm$nguoAu;)8R7 zFWbOSANnMjxd3!JcXZov<SOWHL0KNq%?rAP;!_`HkPKiLmp3coCdt5sWzSx?vSLG= zo>r@ec@-O%jnmiHg`x8ciaz^h)ANE7oPP-q-FGr^(X?T}`_KhX54Z5HPRS2*eckPK zb+n-ifK%W8u;pfQ2Kbu6LG;JvG=S!FW{iQP$cXp%alDtD0V<vmL&9N7cq0fy)^6N+ z@a$a+<+#{+?D~jazEdZB47iyr*kDQ<Bh5Q7NX|33Jt(%_ob7l2aogBXOH%T`yE<AB z>K@2*{LEEjJq^}OfW4Hg1%5tGRu-lhzwoZLn|2>KorI%b(MD}uI^sRc7EK13ua<^7 zY@vi8|B8*FQvj;I`{lT;u_hXgyM%~QO-$4v+yyDTk~kZ_q}8)WXOcyp^E7Yy%HN-4 z7l8K}zwU^;GI?a!M}vBSy65i`Jp0Z^k1@)UQ!>Ez02mHohOnMK6P9fY>0k+WEh(># z?B%1crw0ds-Vmfg2qCbWTj!1*=n*Uq=ox3|;kd>Y_<k>Q-|;KU{xQba+Z{7T*G`_n zU2i`~%fuwZ&*@S~9|m>kZnM8!NCC@c71n(5Nhknl1WSsF%YItFBmU+iJxw)eVEgHN zOJeh5Mh=GFzz-AH)$Pme=T}W12=zi&z+0CrU!U{51k@|2=jg>0uvgER9F0z4f(msp z!^RrScXVa`_U)V9dyjs#>9~`b7X0+*14#g{M~)bXC<0(*Zx@T~r-e8}5|676a+EBq zs`KmOLDFdpi;4nczw@)#SF$H7;?5?m`(|1fUr(gsx;WWgOFy8!?{sob$q$Q0JG8aI zSO%k1?6Ms_oQ(h?W5n55n!py&M}9&6oW(zZ5*pVL-q?Hk-kaC2M-1x+7#HzK_&joo z>7ol`3QqnsFF)?+nbo__+Zbse+xz0#XRCi0?&Iwap9DG5#Ifsw`Z__+&<0R-)zJwt z;ED&Y<xI+Zj*UL(ubr)pkG&yYqeT_<rp5+9hvD<+9X>YJW|^gRj#h@{b+v)ry$~aW z`oPegn^#a(^J-iq;<7e~v_VI4$ImWbv)^2=4Vt)cE%o$;#6@$**;tvQxjqpA=PoDJ z*VR#~G;|Vreet4j>#oDwj$XGl(#$TZn)-1Nu?_I_g7P{;ZT+v8g2%%amV)gL9Xa*c znu9&v%#~3d*43DK7<2FH4cmS@bk*Ki3)B4S!?$*Q^QK?#5OiKwSGS{;E-J+PE2L*P zO#bNR?K{Z}zTEKVn>PqGoxh%X<kXdw%Vs*XwS%YOadt193cQ1kBt6dmdR`>v5X`QS z{NRz3^H%P1Hqk~0PbVawJa_$zg_EqUEbvHZkl%$X&;xW!Dr_(%qQz@AY+t+QQaf{P zM3~n8aCy)EX81D(=CHQ5aJDwY7$gxX-pY%5COCgKZatj(ta8hDQ`_3vU>ZzGdoq6V zuU-7j5KPllSA*u5JUccClI4D26s&U0rb13?p+Y?C_pb(os^C<oU_dJwf-<Frddc2{ z(dBAHlGyK1vG^a>3{ecz8`1u-C8%+zZWSVFPn<48OSE1=!c!LSU~oPBpm+{`FcLA0 z+3ez**BoDKq$;i-%C#rolzb}*7@I;1qWWeRY!X#AV?KpU!|`S3d395aG>nAwP)K$> zF@DMTDw|+M{D<EccBD7aU2(DkHcTg60sW0{0P)$6g~jB|*er9100lX!muRe)6Xs}) z>V#U7DU2(UD&ETdFuPp%W%&#be4YehSCCgwMk!&=Uv_jgd4V0#BJN7DZMItWE4zc9 zqbd%ROKgjOBEwUXV<wi7=07mMM4V1GHv;4Oa+r36Uj`zP1F1<NNe2bH1Re7Oh3tM5 zf*Pu@q~IsNTclJI-4Zqd4R#PoBxY#v9|w4#siCH!-ntR`kH%|}#7Mmv-{qVeAmemy zi7hCyyG?*3hf}QxFCyCzoeXG5g71@}?`{UBC*lk2^`jy&vm5f!e4UNg{(3O?X&y3~ zaRrInSomRC3zC!T_p`ON)NzJbuTVb#uMJ3IWdo83aKXw<4_vo~x|;1QbeFB#nVtKr zxpHfBP>;^{vP!hIS~j+~3m+mq_fIgwKz`)-xtKY>m>FtW8tLe2sVQ*(1O6e<#afyg zAa@Tac~<tbw8xpDE~aX&nj_(~u)Gdkcv=67&=F{8sG*yHBvnZ~cmM0?nJcNDj;7#& z)z)m&&Bc8Fio>^(l7WoicDF7*<a8|J%jh`Zr2U6Z-+lbt&O#r@c;b*rF9(y@Z+3xJ z6}?8C*sSerV_5t0HJKgwvnZ&XU%5M5BezjfVn9buoZofgRwow=h@qvSHqggr(dM&H z(z8$}?0~%W*MBPX^>qMY;{yWKippvmQ(bI1uc?1sTJ;7{1;9`gM#?2<mqA8gY@lVR zr%5R?kbUfJqXVK6bnVSM50%JI<j5A4*YyhXM*<!0BA5J|pLdxWs3Ut9=X!y$p;dF~ zr;U37>Y+9O+5LM3<P=ol<Vj*iBmyG}vS!OsUndhiZH@m&+*`oMab)|yX-O6{vqct@ zZJ9A~>^ST&E@YW0%Y6U2kY&!^#o*0`<8WdI#cbI^3oK@4wpH&tQ_p?Jl~Ij4e$es9 zY0q?5pE~DM_0;d2`W+a(GZMniH?$58jc`5kBrlFeNY2HjrwaLO{>XFFFKlz0<XBiF zp)mlj?Kh@Q&RpysoJfogJaM+}?Og|toh&_k<aB5EK%k%3oH-24KbKlI$qkMiKl6vz zP8O!epj&@`@69WsDS-%4H9OqFg@NaW$7fb9%ZiSQ<R((W|M}F;)~-QnAqEBdP;@ju zIs88#dxa!Zh6Y&nvVv^z-=T@gj*f0j!vO(KYJ4c=RdbRf)6<dx`#@Xz2ZjOYsem^$ za}hIjjm{)5jz_<!j3ikhT~J+;8IFJKffgKN??=D;RQlpjoUI@=ihUJ!b{+A=|LlC> zU@hDs17lMI<I~iXeeg4Xuc>Q5X%S%|g?USw`X|7D@fY$*&($<^_4X&nhJa~O+puGN zh5>@hAOd}&g5|*I)bd;qyf~@$x86PY>fX`<`?%oG(k0Q4K3BZ&&~Z#788?tWz~B2& zc^f+e_>h5?o13w8NfeD!z_zM&kTQ~_j`G#Hn)=S3VLK^}p>*()+1V~I1CKVDwhYD< z*|B)Q#Po&9*}0a^ezKBzB%fTanX7Q}s_MEwKC^3idNek|vbo6-`-{)WTzihV=&%+W zQ+#ep@?r{3@|d^YJ9MJ5H90<%>q7#4b5o<f_WL)^lvd!tsM?|Z4;aE0zwxSQ>^*g+ z0tWy@PD)BxniS5EW5k?p8(EsS1iloERasSAa;|Oa!rTp8*E1m?2JrE(|NMNQuO|>Z znZE>eC_nqF$DZeNuIJG=Y+K(oH~~Yl{ZaBzWRMko<+l>plq2Obn2px@hQ{x>wvc31 ze3G&J##?*$9;+r(n<<)b*QT7<f4%-blvcDtFDRsWp=*|eceXNc&^4l82{FO+j?vmM zIL-8a37zx|3-$*vb@%wc35)E3&xT(<{_g6mm;iqt{#>^-=5*P4pmyS0*gZJNe|mP# za8#-M12Hr+#wBVgKR>_kKd^}}2FHkC&XL6Z_O8Q+kDfkMOiAL}6{(^AeqJfjfpm@Q z<utx5F^EF7_!!yTkVb)fGGJ?J8`^q?5@SNSjGCEbl2eKhCE%^}lwoeJ&G;LmfU*AN z@fRL@ZvV>67&aU*E2b8PFuLuR*vUh(h<o}|s*xMfw&||&1ge%b>7i%K>!@bIXG>BS zFOChPS|(&Baj`MbH8JMe+Pe_j-_L*h@>EpU(l@?-bs@kvk3W90bZqhhMj@LUAw9i3 z>*^c7^7H5NQzK!WW_L(ZTo?sipLy;LvdbA+6eqathV`c#`lTM^3T0|~>XD!S<>mKI zEKQ4KbCtiBhuloW_q?QH!u)^nhz)w?oOr-f&%XL!|Gjf%Ml^u6L&-Bk&XIEtc|6j% z2M!&7eCH9A6Byu4<Aw2ob?2LzFuA}#z@LiK=iB=4-*I(lSP1v<KKkR|p7&kk79AcK z6yTi{6G|Kr{(VYxGVjgz!_?gKv^*mQCKjY(EHD_q@r&oyXT>ttg$DViCWN1^YI*+U zx7nRTo_lgq;<}=ormkVaBqsm<$x~&I{A16?{CH*noP6W<L@HadaRk#7f#6N*NUx+~ z3~Di6BO=&8D>l%iIzbf~`5_S@0hB_y3_(+oVdZZPDT98YXX!_(h59;X-K`JHdE$^j zq_(2Z?{R#no}57sRX8aNq}8v|tYJx!PP4*36lILDFf>SA-GA6cq9OkhhO4#=MG(~i z9Y>0~d@@D8az<0F7Z^^Q+0eV6mFKI@tfvdnv-V$BTFbCbb)r62Gay|1nC51+RGD6r z!t|y~s|97JfKz97N+#?=o$9SZF^+4O(YLD_OggZ2AYIj?D{30U;-n|!Er@7sqLMzS z<2F#(iWK%*b&Pu~2=#S%xmfUcZM|Bduj{HpQI?C-x@5Os&_*7i)V@>tV|g=*YgPku zbAb93=NvMYtfKPC81omnb#5kcCEL~Xj5yNA)UwysNgqt*s?8W0OFJr5?X&8jR^Npd z+)sU);x}dwEx539i;}CML*~VTs%Q(Rye;bBz49$?&Zc9vhpd_2d9{i}I+9H{Y)iKj z;4Wk$5Xy-a35B9z{nj?aRsHcR_b0utIajFl2RX*c&5{~dD7a9qYJn)r`KWR9cOk%* zD8u!{|Ge_;uYCqIhnzK*{S@x|$G`UErbM#IcX(n3)(hDYz^v01E$NBj;LbE439Q+2 zzI)H1&wlDbA?CciyfflMkJk1W&V9-e>QnPTB&%{?-@wx^zIWrsWZPPO9^xBNM^enF zHu;nP{1YsrWMQ8y@5{*uTb7xya%lu`-pZmvHl9mD39v#by!i<7H;<Q`ONkAkVwG$f zzTGWFaXa7Ix3Z`J!~{L0Bt*Sm-oR*;EAy&zweK7}3&h4PatdV}<wf|Glvd^EW^p}4 zs365Hoda@ZFrWYM^t!IGPu`WpGq_}YY~sYJ%FKiiDAy(L%lOpH^*K?$_`_3B7RWs4 z%!IJRN6SjfYr$1dRd+NFOmE7L%1Vuoi43{(CciD4*TDcFE@k8LTtE|<+Gn!S&0-;8 zgAv8$P%FZWPG5l9RU()Ni%)_wc)0tJFv|r%GoXI0ode)C(6-Xwu+X5!k!c`2*(`7j z0DV=@SVD9#JO<!IG!KjgMlT7?{r!A^Sq(`~e98C<>8qJV1FkqYGSSr14o3m_R8Cg< zW54*$=`$7VI`8ctK62*#Ltp&oij`4-^(5gE$-@WcnM)0s#|K{X{;|@{=@A&$uAeys z?i&~eQRN!cOOGxJk&=`^-`(9kI=Wh3-d|dj9t|iXodwVqq~-X@voKe1O+Y|ET2hpo zF}L^7X_)8<1;JndmU_OqcX3=e)EwMWbH3@~?1jaNae;wBw{6I(t8c$?T_%_jy6*1k zY3uCs^Y*l>!U=1vRE+eu^YzUyzjfr+b&IiP|H#DJ<yl_d-rR?76JjI(>x<U`1<Dx) zu;#jrV^p$}1kLa-XT}wuE~9qcANanqp}V|ia#LD(W@=1KR0yo$<Uu33N%7G-IC+0s z0=d1M)A;GL=aQm>03)SGk;1$^FZT6!innZ9P2>ZPcs`_P-m;YNJqJ#$Ubz&EDS2^R zazZ2&5ad&nV+(Ns!-2p6r761x$I}x+p+r`GMbW8{K%dIG)`x%i8#LV1F>tnX1Ux+} zB{~jn5g%`gtddKPA1b`7vZyTBV&B*dPRkU*M|?u^GBW$y$5(Km-^kPjA8$_*nCFCh zV{>cqiK?9B@Tutwa+DYsjdjT(Crc`qEzRRuvlnI^o+3W@Dhu)REG?^nMIF7RBqgq0 zzGUzFl~G~-*W|>eq$F_<2r^tW)Mw<mAit77y7*`b{u~t=z_t}heGX{b)i-+N*x8$J z*o>Tvrh)NUU^~YS3Uy7QI*Q|JTmH@CdWNTx6Qlk7eeG$>eU&v$iBW+wGR4;r{1+DJ z{qx^F#i+rolwr93+N7Ot7w<iI3ZFS!*Ht?>y)8Q?Gc7(UBKY20{2{EMW%&>+g$Rye z(~~6?2~-ZWH_mPc+>g4iFzRp_a~iWT^b{Z52hPQyh$Uq;*KV=%IC*<R<-h&f#xtdr zgM-604IMv!?&xn`J-#j_j2j|D{n)j`6NG%QAty1LFt|iyi2uPOrKiqR6Z0!Q-_tZc zn=mnxld+g8qYnlJQi%bMZyu+V{E^&8M~|1hw!e(pm=MQH)_Y<V!tsSP%dI@u`H~Nj zU<Z2P-Q)M&b)&yO1HvaZI-;t+BQZKSD>IdwASQyhgcun6Z{PrX`lbDTL_Wep0aA%E z0CS@pOb?R`fAgw+chCDv6M`5la#zHReGk^LGqq$KFD=MIw_zcHgPl{-3y_L-4(}^I zTho@YID%=4m!KS{lEEC2{_=~5lNKiu@#5Y+`-{K%>z%i+PlX1@eA}9^w~_)Po&Wf$ z()chx0%Ky1G;V`HGQSO&TMU0+w8wm2T|2ZSZ82|1o?BH@-`zLN-XqBbGI?<}J}UUl z1ErsRXu#j!HmT10^TRM`H7z-YGL=HiO-|16+=L)csbM6eYXxahkG**4rtO<^b24}q zJZuyrkgdspS@E$m8?z(1Qq0-z0&4H+8v^d<0{aWxeNLBLtxCo4ynrW|w+O+Dj6*nU zL@A#rG=wASa>YDd2<yca5XlOmO6WQ%QGKFP+D>W3W&KOBP*HWi%k@<VE$|PjhbCE4 zC8ZP#qdn1UQ(OtpiN10jhhvrd`JU@?f$s`DQ7^Xe6vHAJuabi#jkxef3azmfA5tXL z6}L25R2}7#bMuEqISiFU!%*82T82x#T7-JDb6QuG6G8sZK}{+^qLhBrU=*%~t1})N z<qrLz6M9~6ahY;H6tEzKqG45G)-en9YN;j(s9MG>4aacBoa>0BZf^E)!JlH7m2Tx> zD77M$`BZTZ>&5Q0#1Y1a<j`>aZ;O@Fg!SZPC8VtByWyfchOk@I{J&6>S(VbJ>aLi1 zckCDopgJ*IvY>I@r&>lD#UreY6GOVa<7OM{iS#Nvgwru%Tp6!}u`nJE<#l0d$w6bv z9H|UpbfBRB&Ui1(L=H=d+p3bZ`vO$`>A#W<nX=6rbrdACkdXM^u79Uu5(}-L|LzI0 za#$4zq0_7duh#Y7+Qf9_3@56(^tWoK7$xv*&DMrl|KduwYJ6yh6V-waB!EgO6;|D` z5rNOWbpnRgYp>ZLgkbag|2+3bps$T#0DNs^cFvyeZEz*5qvS1`fRt>L&mjiA$cKiF zKOsLW@#wAwXVy0yAqL@$U;sFvwytSbt~rHyr8+R>5C^*K?i=YJpZVPV+y3+WsXo3w zaGO8}Az4B2cKYH79m$y<M4-K+i;9lqz&g(TJaBk;jEr4Y%_QjMWG;SgcZK05rwP)5 z$4-{_+_ohR07lBoIyoxTue_=eu9DD@U=TDm!p~e{bui5I_79GUrpcJ-Fp`4NVGr!Z z<KP;qt`Ki{bc)`(+l&5@aS4LCI41OwZ`>CX6%LR}PeZ_5eSE;Q<^Fo(vMuEcT77^B zvn8DF%H@51Lkl1p=Z=8}&;X!AnWt$}OH=^XksX<}=MIN>x}!R?_=zKSz~M-)W$wTd zADF<U#(<e0f9AF5sBmZsK-Qq5zJA+An_Wgm?;^_4Kk)XRBk!N84fgluLw&6znnN>< z&7EeCq(sK$YaQAFu$D~6UETfR{+@Ko6pC+sJw1kovG63(6sFLa$l&u$ou@0C$lJxu zaFv|Q)ROA<#R)MehwBd(p9X_NE#cuI%k!7~{rANme|j61V))e5)*q{A%}xrNl`f<% zH-woagEhOlx_6hh-?c6UOs98fDk&j~Bt~=sw>UNZ#0MG7#2lax$UZ#I#0H?JKi}3D z65#jnr*BP&i}LgH4+{$k2?>Na1R;TqkVj_o^!CEi5Q;Z)PTnrbzmDV^T*D+l0Z*u+ z$>%l0PJTX~yHC_S)ZPW~4Gwkn#+4__8>uCD%jSGY;kl-@t@Fg0+Qi5JCWrY=bQSsa z#F;*I|Mo``qWz_iAwdX<rSNKXauWivL7DsdhZ91)9a}cfO{;~31T%wR*|E{FH%eOW zT$N;xXBhJ0kU;N}ipH_gai~;gwQLCJJUSxa$#+V2+<Xo34}yYZ`5!!9&G1~Fmz<iM z$i032{V%<94DKB}8M-IW<uT38ZFAzXSf8-dg4Z{;NE{aDNs0`VqsepxH|xK@Fx=4O z1(YUt6?FCV*0uJ9`g;Ns%gK-Ddf4;*M<=G`E)&GyPgP@gdScYSef_?uh!BE0C?7|K zjGivzAzbG4;oaSR$V|)fts)%ib7?leVib~a4;`;qb@<rEbt`dHgeb_%fGM6Sx4WnB zGau`(s&07vg}uRkHdoaA1az~9I?B&?W~avf*S8)B4+{<m3}8MCMtGQBn3U{XNy_q= zHUY{Z1jmaQQ@Y)^!o@1s%iTEN&`hM0HsMcyW!K3}KX2%Lcmu+t(%sWPIzA2t4JLl_ zK-YJEuobnUZJ5EU>e@p5z2aiR-0WkF0SniSueT=-DGiEOpqQG@5n6F~%jKWmKE8{h zeH`QI>@ARP$<xg@JpILFr2KOo-IoP3p<}wbFm7tvHrVk2t}`4FGlw6uG7>j6CEu9x zTeGYtrw({s-$j&6gIw6!+BwXQ6F+YuF3Ni-dKuv3!IqcAgm~_sul_gR;6grLo;1bm z!H%Mu^KEb<@k(_}I_w*mo}8NGK{yYbCxQN6<}hcvhL#FX&?Rjc^RwwW%eNDjia(0W z`Cg^69Ek3e=NS&KW(9n*uqDzu=ZV^cb@Gq@e>hJ}rcw(_Wy4vsIvp6w&E`|}Lh4x# z^c^)m0InOVH!PeAT~3o0`E87O0a$b7Upi3~Bpk+yQ;7_HO?_)URJOPp`V=f3gM@WT zObykE;vveJbwVM%i@9_&y`!pLy}($8dbNUz3pv5fOUiASXsB=<Oi{(R2#hV1IKes( zl0y^bTx7x27G$^Hs^%UyCu7RctH^OQd+5i75OVOFjT?rc*)wmd&H{|D`&wAKTUC@y zzfveMty4wId?T|pi#=1{amp2nIb61?6ns<}z2zt7?5^g|yOG}Ju>R&$Q_D}8T=izs z8$>g=sW)019qP+UV%^rwWYJy=0MgZalzvHXa!moI#NCvOoLbM6S}0^|=6Caj9ObMh zoc)q^-7S^M%KBj_16Io_qbkMC0QjC+y{d?sKP(%3|MIWifiby4o+n&ktuCXJD6p_% ze1&e`c_&=YiOMXmdX7s8oD68gLN81UndgRarSC(<$5pGVNT$+=N?7km&~BbMQ0}($ zPWJZoA~k?S|G*H`sN`>&UdL)&-T*=|r+T08UgXZ28K8;^XW%AL;lW_4mnp#gvSpba z(-wxadYg9iZ2*i0h7%cBHk@f)W}3Hl4_~`3@3Rlx9Uc)z`rRT=x7nFF>U|9lkFxmp zvK>IWb01*8GC=W0C#S=Me38WbH7nQuq&!PZ3eMK6+NPwUKn-k5?qC!mq#*KQfLfqJ zJK~StYzGZ0j^wOx`Xou#JObI^aRzGiba!(!7b26?j3H!Dfrr+%4m|v+n{T*o6W}0K z>9E)I^sJp#V-N@codYCY{$Ta7hO?6W<I@*nB7zrPN*kO-eVkk#Py{5Ra;QX&;c!Tf z53g(Kl^r1~5SZA*%~0stHOn8(!GlOEY;5cO=8u2(xsUD0%T4$8^5%&s0z8gCw6v@+ z@BL$^AN|8~6nqo5!$npF$+k-HNttEnFPsmucOxTXD3-JT#V+{P%Y)biq#+RI0Mi8e zQ>^krpr0rC!jy4CwzVq@zW3WVRxHoMukZvifBpQtfO3KY{lVf$;sg<+7jPi7wsm1F zL%SnUIwI{%&(1~$+p^j*+2GV{fWI%<osv1)Q1Kq_0u6MBG=qcOXG)<~xAcGRzAco9 z1QVphCBDQK4Q?m9mc~&laI+i>S9Q#S>C+Kp13P0w1MNGCBq?`*{^c6oG*)7`|2uo$ z&&)`rajI)_8AKT=NpV2ob8{D)TiRYa)wrWDo(4@1uxr(jgAi!Gvv1_yTQ?vi>9OFp z9;T2(Bg`h0nI*p!h)eM)<YcztVp^LAWu@{hJ`;rbq`>Z;GWcOg0XSp!Xy_P(BS`X@ z7#fZ}%yB_14)s2Ms+?+p43?EE3Z8v=&(PT9^1>YU1fU#@J~T2O;<t!&T^UA_)f6$G zvX;Z&Ac&CBAt3UkxbV{2cE`noP%_U1hwGiqbM`D(2}d$oJNm~Wg2D;>$ZKeyd5K(X zKX;qa<tB`d-qEjr@)j!4`q>U&+JROA<wF5a>N?5H#yp7#_>c3!<_hmZHbByU`_(h| z)HL37{nbQh>?JYXh$XOdA~`9(ATOKX>#zRwOhaooj5JQ0k+@!a&&ZFzdhhzRMfT~? zhad2`1j6?KYCx60_YWeTWZF^SFqAVfG2K5nLP!8BEI5j-{wgFNoE&Fr`L12H4F60^ zPB_;$`A}x6yN7KSEvu+Ke4_H!o3;`ai;0Q8D#<53HJ%tHU$wQhzjmf|dv+8wM2IJA zUVus~uYLx1&%_M0>3qgM9r{-o6L_gar@;udgX3oJ%uR%{VC)56D}?F1JZ)6(8B0<> z{lJYs{N*zcG0o25>O#-^hwAKjx|>cnest7b-a5rG!}aQ<is!qW?dRx)jKCoF%nSrC z)F9wPGb+!^B`9bS(+=aE>%+o=c_)sJPn#w|RC%sKbo!e3!U~EaGzg73nduW<b-!Pg z#kfq^($^QVd>B$plSocjW%N@N<fKD}@{MwX;rc1_G^^-WL+2ngi*Q3nqN@=_odPr~ z2n#!(4aGP@C}^X)%(e(<t4m`&0wJ*hWl<oUX2qFa>U<NlzV?}dn_2;H)pxQ(`k1ib zx@t^mULVq1P&JQ=hgco0O3cBGnCUI3o3otzj!+XmRhOQ}n-p18!#KB{vf<0gxVFRs zbLG>aQ|Ht`mzM1&4`D?<)raI<C;zu#8ylv_IL}R2O{2sk)Zm1n0N<K{EUjz_PPA?? z^&eNbvtKB?=*5Sr`fMVqV%`n)u4Pko;+*@$um-{zE|LHFSt*3GD>V0Mt5Ul*h!c_2 zW`&hTHEbS2sC+P%T}Tl@F`AR`gQ4{TXIvUW=rycSg>WUlwM#9GI&HUvitSoI#E0KS z!>ww{yP<2})VcMIiZ0#Uxx=U<(?Xfgc}vL~s^_>CTj=C=ZEIo5=rGWPgqE({&76)n z!!pB(h9wH%#EozWvhznSNKFivPe6#|RiwEAI601U#`x4MSzw-^%=DImUERHdP~!^W zAm`lwo=e~W+)X$URd4}dt{s}u5iKF$*u?b8yyP!`?!oBD2r|&gz^!j+;_uGx{<`{> zqo->h`R*rI6cw<+T-nHotpFu$B++t9z7Xbw#VQ<NOCkt8eS=rUddnG<^hl^MuIitW z3E(Dx&Ti<~*kHb*30ec^qJ;(6*psYPnIP}u<3sYS1T;<eAw3gJzp{6NrxnHo@X*iR zx8?5JZ{Ql5Z*A>pZfzSH9&PXJg>4p;;fLS)Ok8ZF;IO#&)8BhhNB1B>0yCi-`4z1L zvLK|~U=Gl6zNL?dh#Ksg_fU6t3$3RE6$0>*U;NWwJ%w7XSzEATSr(hzDPc+)ICQW0 z*tRVj$T|JTb9-VV0zejBXKOgbDwIP)0q}cB*eEE-AD?&3E#gBcrz64w2rbYIF_n?A z2|!i8Dmhzq^YvFlUJ)G?cGb8@jE@EnBA=9d_7#`ie)Cp*jNIpYKe;w8E=GoP_8dN& z9v?y<UA%t@Hq2h2T4SJ>+?OLL!Z$cP21W+ZM)Lc)>hqvlw5g79AsDw5(CZx>d*G(k z58QJzksm(p=<I1~X~khWy80`t8+!Xje*EoEB`3wr$<RTf=kVw_4$r+@Pm#dkky(H> z$Gz0}0QjPCP$C}!q?T7TbawZ~$40@ad&}09ue@`FB7w9yHa4;6z{$<2VKcKAoxZY3 zcpVy@yn0RUeRtgie*(=?v9qzUb!cR?v%9aZzHQIZs#pK{lgNk&Cxi)-EPnpAHs2D_ zp*F8cGfNwM=&+(UK+P6MhXB3FTsi$nVS0h!;<fjV-EzY<>_UJkJU=Jp^?fBp%W`Oc zW@h@0cZ*}g0(eAQ&oI!WobwlXE|U1BdB_=tT^f?Cn=2dIdMS&F#+<)g=7gt@hYV5Z z2R1D*MbnHN#SuY1c(NnN2+$8$T-!5_VV5U|QfKm^yRW(JmTgFgv<;1|?d=`J8`?Yj zPM)oSh3328_!OwLY*0mh^uOum_ibT6qQe7rzIXi9_l{+x#BSTXg6#+-n=ej`=Q+T; zOO_;m^>g?A=s*98-El}~R8dCn(D;`=cH<4(ua;ci4LEmO$H3qSeqMI2et2Z+_m4gt z80h&yuV4a!4a3i85sLlL`5)5r+d3K0gE3JNzJ9*<tW7U0$mH#bL3?`o-riaJAKxEC ze#$o9e{}|17zkN0DywQ5SH#(zq^oBD$tB|lv9#IQ2}Mg$e$-{~lB`^#V`C@VhjY{8 zh243Wg4iMC1?k5JHoIeS#&2U|^OwK>Ti$)k3UiT%*|Max`snF%a1aTXzhn%hfTObv z(+L|mF6G2<{&r=W$}*5}=0a#lpkenqjnmSX3-($fywdR4^rYyf)=ucB=FFUPH@D&8 z872q09fx=f;c(2Ysgz|okMqi}ckwe)ERapaIoHM&9l~J+VD5kw7U&{$oBb`&2U;jB zCDezyhQ{;)TUVxn3TY`9)K;z2ei%6W6{Bw&rC8-uw7%m&(Uoh12`8+$7KmgNt5{*w zbwu`se#pCWJmsH?NJ<NuX2j(;EAy`MPfK{3Gm&&k*27rpmDb(T%J|T?p>IW}5@Bif zQ(+<%<95z9V6l^iIy8heJXa_l<jN+lDXcx5(F@RRmDgOK45&k2ty6(mYDB$7N1bsc z!bxQcYdi${?x@@+3g3_`$~Aehq3|&)DI+T4D&1Etva5vc7uGTB>NH%NUntuyEFPx* z%>P^eWv927vwUsC3O$5{99!q2n62rDq2Z`Z=Uf*`Y*bnISqn5@dY=623JRZ^Z%RGG ziP{v)q3|G|r=EF{G$=5#;Zdq-Nr+AVOcVam$)wLC(B#EyLjCGh`Z-1KDH>1Ev!7Tx zlxfN|yM=ZvFq|mdJ1!YcgyUvjMJdMRDOlz-F5wP0nfD?naR>}2nX;FpCQ_Rb@WPfE zdZ~69xESOca%=qP*y!1F%~z%Pn~5aK)H`dVF%7V944;!^qe?Nzxr-M~EZX^-0p!@j z<DIIuPd#vBOmq|(l$5l3_W3uy_t;yW-fn3jJ~%uXt?-p7HC?0#JU1>j+TX`ZvUQsm zfJKp3?Cs^nzhO14s%?&o@s+Tt5Ob{Y*A~Ud4dzl&z|$>V<2P?lW>-5Gz$i_F@Q~_F zX=^aXucNCE9Mi{M0+9?|aB%Yi_*+`Lhrao_JK$B|pXF6`58m^~$9}#FbO0cO{qleQ z$Mb*RS(*^#9UI~cKv|fZ;?Dn+T3hPjGz2MpJUwb!`vJb?Ydke2aqp1|zy**E3Eq+X zx5(Ws89oO)%LD?{_Kp@Mg<0E@D2*&VR(lUFgo02=fUg%%+;#Buum81Q7;g7&%38HN zXUpcbkc|L>5YKq^o%cb#ou-0lc0e13x`riPo%jKqygWKOGJIfsCdtDc7nReWts36U zMbh&j7$F03$c79KfXLf+8+7(VN1m0D;^*u8f4+Sq@e+>e+J=sv;ep}Fu`wI+MM`*H zW+J#SZbLZdKt=23oLI=*9sS+ui5&#Ar_vjo2nd>+Tf0G%!$X6~vHZoKp5I^B6X&-G z>UNp5?zhMtEGo!*5%)%f_!ignJ^G^+B<&LQY47O%+mkQ<?zPiN!Jg4Ukny;sE{*}C zr+0F6Cq(*mboSx9aP>rnLx$orG(4eTwf<Pd=H$Y0iiV=0s=4pf>9WN5>wv}cveWh! zmnFnSGZuRK`u82Lq69141x_i%_zw!5P3xD_EIozR|5tx}=AV1YV}0F2{Jf&W{M{Tz zt~1JfVb+><x@j7QXv*;7u}mfePIfFyWNh+J33xJcVP)CAIg507(xMka7K`V=Ax>>o zd$hxI%f=O*Jp+=#2KJ|x_Fjf9T0Pc0Ala_*QYxCd8>ejm-=!Isi_u|fYLX0ZaAiyH zXmWIrLr0B8T;tG5Pdj%Ft*QI?9n~r@y$5p$;Ses1iVR<p7~b1AjGHo(asgI9Ti^2^ zU%x9aHwyuv^8eEB-~8*!Lgq+*5|mX`|KV>hJ%99kTCi7Sun)evVMPX999$_CZ;8>& z(B6RNIiQZA@E{S&|M<g;RoxTY@?$rz&bfNys+{a}>LR8jC$3(WzH|3Udw@-4!pG-> zsbsi*g-islt!sSbm;c;(vS~?}PpH3FfUjp_d=wJRSDpp16(tLOZwxIMAZ(t0uCceY z>|ES+QA`b2uP+P<3LtmAp|Pc_cPMRXFoY)*R%OzF^(bRWG9wgkeBrHQ@D(v4+B$lP zk<v89F!Qofb{{H%vkJ9K2Vh#uhz;VsMj(|*X=-Zns@^FXkCc0l?9QOP)MUWJg8;yH zANljZ(8$xzzX|P$KjYTh<H37wDn4~iM#a?mc0O|%<{0|`b`m4Aux)Z=rY8q7QOnN_ zxifJtAu^Z|r_rw*Qt*sHJ;Y0s{V4tcei=&=PL$WD#D-4I%$c^12`5P8D~n4*Y(nu; zXx2144i`?S=d{~~n15|z7(_b=*GZxzrUI!SX$PV5Z7yg%@5m2yB`|>|S5tb1e8`n? zo(RppM6J-qm2;k0W`Qvb4RpR>&Xa}qP-{31_X2082P|ZTBs4vhEm`y%m9*GU8Wtv- zfwBT!7<GxEESg;yRK)|;(ej~jGigfg^IU6NYe&n6;pG3y;?9!oIJA638ctu8+uYDK zC)7!D9?lbot-7X@yJQkDG!Ycd{%i|4jD<Ntd5Xf}rZJNRq9>sz=W&g(DBaQI)+=`z zO1&)y>$o{xq6zyo3IVw`gsxO^((70$zG*HQEzD&~f2|jf77OMP`+p*yt}oK5c1Q2p zy5fI^dWGE3?C1%Gy5(3n6-Y6tp}Zhn3Toj8fZ-_4hdB%>quk7-C`KcsUO4>+*1bUW z(}hBS3$4s6%&PTHtCT1?N`|v*grR$)^MPhKaO7DkTA-kOW?PauOSnobQJvXd(`nI{ z|LcWMeCjWs{mzrH`m+8JD*wIu`$v_@!j!Xs-C-8sIoF~Xrh25EoRV`J8m>3XW!g<| zxU6!eaRo59I<Gk0xu`$p#efXqKro>9LFIeyl10h<JnI`<r7vZsr!LQ1+}%G4v}`A3 zcE2!t5y<blYd6X)RFZ=0I))?s7TN153bf+p;Smzx3Fu?br*<D0nMh8IiH(ku*P9ct z9!ODMKj0U6@j-B>vN@Z~#EQ!5?|t)ydp4xqSeQuFFV?8+p^uM?VvQ;rV99F6=UKGF zL9t;?;hBaWAPl79TTb?scipso6I;c(ko3v=rmjFAPr5AW!qZZdZroCIqPB~aSo#9i z%v}{7V|m%>6lx=bv!}Per+>r`utw<oiw2Y8{j1Nn05|hFL=-EQX4kY2dIL!swq{vg z_l(UhE6mBtT#}iQ2LHy=EeVti1qVUTZ@#^6|H-<0wxkth#4L^t?Hie<)FHIUc0fnw z!YW4OUl6A-=$#~^gNp_EEFxJ_=7&;Ikhy|_fk0*`3@mSCY$`D(bahcaN<*2weM8B? z-geN&aQ3dzrB5kuSH;krfe6P$hCcSI@BQNsKl!hpe7U}3C^|f7OMd*dd9h7xJ)ii& z)B6q`6ZV5>0qC=H@@VTcQWVbwU;=)Pjg7kV+NGql!xe(JVhcV5pIx(RDPS(j9~~V# zTiXF1hl3ri>Zm*4fZa(3-*MAs;w7l4ySt}ra02ML_Ixu)7Etoif*d?*W`^o*71=S8 z(Ao7NO=%`_2KsxKR5pTQgP@W5e$$o}1yTO%a}(BO#jeeY-L@<VJO1v6A3yNwZx8H* zCFYj=#i79Q2oJKk@4%7g_LSbgE~O~l<}ee}7o#IXNL$8X<nD)rP``?rCYh(~OX<t? zMQ0lOZQf`<e0@B3RdwySVIx`pNaE<v2ooOYb*8Mgzki5(<Ktt#_Sw6n2Li47%S2{n zM!s~yy*^$ZWS!fMXq+gieDz?(?JJU&rpKfuhC}|dc3B#rmykRs5;AuF-ckKa{xi^L z(a7iox%_0Z!w$T4<I*Fw-3~*{{YcZ$ilsS>KFox&ow%~X-(&y#R7nM8SMe4Uc;D?? zVT_@RCr*`i4vZ5EK|jg<jHcl^`>}q_@~~ikiuf^(&<SIT^Uz@bb*l@}3>WwI4@Cuf z506bx+2dX`%P4Ico24nPXC(FvjOSz~fuGI^U9JM(Mg)43&JT>pbJ_fnmzmt$GXfH7 zn{w@eoVc)ng8W>lS~Akp7|C}PB{F$}degD@kChy+Xuf}K3grYTPB=Do0hTAb@`cQ> zwjKJ_moe`*=E0CT)7baJhadXqAAkC{-~G5Smx_xsIjK>1u1WIobbJ1-qd)n@<E`zT z3>M-C%-%3gq58}7tlc>{ho=X_Arssz&%Lq>tofd`sky0<$?;)TZJ0HaaVKGM9M~Dt zlreub5fEA2gZuPzhQaSBP-d8Ukak%?mcPHho4Wz<eezs;N=$I^(X+hWurhQg3|REs z+}1HQGt1MZy@rNI_?B*7zjgh|)?r>Hw1cM6QgheP+GXjv*=cwt?L%iD8E1C@1%@<~ zyk3EF@V&aW{`ADi1IKIMd}qI%_<J^eN%F&=yQ`*k08daoM_pSew0wp#G|*~toL@t8 zJH10BO8DkxBzE?X_}E`Cl<|DCtmFRMw?OT}xO46{hLlz?fwy%H^!E1i9_0nPx~QP4 ze^OGMBesu^=ZTt*&)>5tHD$4^)iFFY%v|imEJ9n-$n1{L+$Z5`HAUFZ%O;B<bucIP zSG2$OV$Ex>)SjtlTaPq@dAr4>ls<f9nCH%|^I`LX4I!sC1#z={7#hwIR~apabxMMH z?-lbsNT`~%)M14NRk!3bTy{f$k@@=4z&yeld9-6Pv8o*1kA0QoUR=i2DxAQ8QaKjV zTpd)RD#vw}n}v?)0tM<FYHLDkV;$v$VK!%ZF(_%(Rgo0^8dh_P^<&eCDin7U^Uz&8 zFVkw)RaG3<JQex@q1Cxzd2-OxiU<=Lv%XF@oKT&pqe#6`FO#W7{fbIYk7$L)Ud&6H zZKFAx(`4!|lzKo2U72J3Zb8F5wGgir%HOJw$`*z59$6((&`!%1<rPl&V5~@`CqiGy zP5@OD^H5Ewn%6p&fnKkwax52tRyRXj&ciM&%$>sN4Z>8edc}ul@X-q)G_E7WLNq<+ z{5mI&qBxKBF=8r7IQSHYVO2p2G%tj9AF6Xvr3;8{%j37-ly=>QBsaq_rP7FRc~~!a z90;Ayix1&S!of#4ceJ3;)`GS=tej2Jjuuv$v!F!P1=U&Hbz_>oUddqyJ4_tt^X7Yp zS*wHAkVN+FuRa8PQ`_7(J~`dhH_|aM@zZa9G(Ii{4UjjwYwwZ5q|n*9xyeZiJ<hS_ zU%oVNMQTKSOF!f!=iB<D!b2coV4c6Pt*F8|N0$&_=wOl3<Tgr&WIu4{o`KP(jsf7{ zFMsAPNPZDsu3X#tC-}ePj{AG=yy0Uvt$O=x>)51i^Y|+zE&uh!8&)jOmxSGbS<s4b znVG=Aa{SgCuf1tqc6og_v=eXz>@RQs%Mb6%&&vXlr16ro6_s`*UAUN!MQDK6naakt zwhmfG!rO1zcITGD;>vcApz(?6S5Gwm<O@5ZA|s*yCQp!3W+4IIU;*-ODjbeXU!;5* zJuR#2T$PtZ3My%oG|M$0Tqs$RAIoP+)|!*Yy8DO50V~`u|3yw>Y-EV<o9`Y3g$LON z&inDh9~&8;?dTnzn3`?s7-T2@!(Vy;qth74n6JKdATcTkW}6Qh%oW|XYp)0S=^q>h z_yYWbQRh>4U-Q!G=7He}h&!+#R6LM}NJNSnjFVHd^y~^zZ}bCO_py^zP?Vq;z`jp> zWJh{(G+v4t2S+B(wGRIDt9R#QEwO`8GpEi}%-J}9450s{Q16DOb_|3k$HhdE^*=B$ z+}hC_8RQMXbo4~IOw3$WlrQTv9zIqI!w(;7RicgvlfVRXmsi$uj(^^I^R-*n<`kE= z_6>~>jZPe^Y}>YK36T<p1FC~CgfRhZFXtqv7-r_K!eJ=wP~Fr6sq~#YwgQO)y`oH8 z_Tq)P+NN&kQ+O757NpPLcwqCP$__NZpJUaX-@kvuru8d?`qr1lT?3xlb+)CggD=UK zU$HEQ;Ra&{3_J`^A=Gz~(rph(?_<-vSLgTz4BbCCR@c%O9O(DChwfyHlFZMAF9mNj zjD`9Y(++he-#k!8IxsWCMO&xVKXgM;+4*iD_2JRUW9K^l{O}#bBpA6ULH8rtq4I4+ zh+pxU`s&(xf+Eq;5rz5L*agoit*nm@@x>(=eMwP)ufKC>YI+)V1qTOw`^ygy`)lvE zji&bQA&}(ne&s>?t_9mv`TE<3*g8``FacQ#ZQ>hXlxq?~+Pa5GhOKVu%}bBF=Z+hs z6KLL{Xelbx|J{S7ot@p#F4;WfrfWA9rB^lfU_tu3?_AgCKXxNUT*oISYywx+hlTjN zU!r*der+0`?Hw5H8yqXC>D;^`eaFpPX+-Am5(Xo`6|=g2m+Ohca77Qd@rfyRu3(g# zwr`%gU@L8kXEN_`K~h|py{PFNSgoDa$1vaQhyfga>P#=AfZzdYmu%)JjW<#E@Fc?b z500O%>9}ok-t}8I&^5V3Wn^rU$;#0Ci^;5PZ}6(BvG$(fiOCraM;QuFiw!P5QPtVm z!>y#Kvw?}N7z2ZYBU7`0*R}O640#%0*A6UMD0A<D6OqCA^BlsDj7{%9bc{YwY%?__ z>G2<byrQvhU}zjY@N!w1m-3POcd!Db7v0^xFTQ!WAUO=zS^%fhRm?>MoY>s3Bq8+i z=XX_A*P&{vL2O*V>eg!tnE}XJUcjU+G-Vio^`CfQcV}0Rte^RXPv4iB6mzV)gV}Ol zS?hQ1*|6=}4S0*5wSecc+v!YQ*Qt^+&KZUU`Pt9>^r2l99Rnldyk0BoySJ{+ymQBP z<}}Fbi6|UAR=zkUn0$ZBKcB?{l4A_vs1)S)SmaT0w2ji)I6p0Td3*ll#~<Il`^UT9 z`QcB$a`$CS+zQjTwL`;sa>WfQBUFlMokm5sd=|PFx?z>$K&JsG%V1-n)FZNKi@H@% z6TOhutFdVpKGp?Qx+?UKcdC40l^ImAh>jXkC@RrOr(MQa?wFo4L*JV6odOGA)-7Sl z!_+1nn-g+XDLbkGDl7~}W&9`<tX5>z=dCW(`g$)D);S1-wI#fS!>o1PP_QOxCUt!1 zMbVo{xm}8Ar4i(F{b*P4j)%(bK2Pai<MP@X#(Yz=P;xk}GEEp3^ArtN>Csod$6whE zcLk}xh6^FhxU0TGuAyq)5cBENaH0oUAVz7zC4Y_bAg!776)^OSG*?(qRt|Q<2}Oq0 z41J-om+Gh%nm1glLQmnMD9unCRtYf7%9c)8ZIlYq3n>n*HlkD$)@%~fRU>d-QB=05 zc%_yFZF>5G1<D%p8>{15oh$Voq#sp!A+>7M-)d;$##Rpp0wGBjZ8%It#{XLkC%UVp z^E&QIljkmZxP<e8LZL-pU$2s?*4=v#KXC635+0M25+D2Z_YWUARaIS|ln_fkENNLl zW~9CzJ$~kiR}beVM`XqXmXy_8vw0n~0CBNVzy8l}y!!f{vGIw#>?MH9u`yA~D+u-J z9oiH}UIq?Q(lXfJKLGd*AiK06ch}#){qCM(vcIXbw=_QsdS!qQusLv+jP#W4Ycfxk zH#qWLz)Jk}FF$n6rqv~-=iEKq{;e>#AU_l2ki|Si;V-_n7nrhVc+wniplOs}`|-Cw zS5{elrnDN2=Fy_u?93$|Ztgs^zOm)`o%=HrLs_&tT_VsyldbE*MG+e4{jZna{^|Eq zfIp}@`;D(Wv|;^<GiR%K`cJ;SJU2TX;ZfazL&q!XI?uKYOifO5CD`lTx8E2R7JBMT zC0UsTxfwaxOCrO8MJ|AvQ3h@0vK*?n!HGc;u!)HY1gD+rw{1iNu)*xve{A4Xi|oD$ z=dl}pS8@5Kb!V^HycW_Jtn=63eEZ0;GmXvdnM;x|F3btC9O7H=9yndulpGr}H#9kK zhMh4#agu(whrQk)ywA<89od;=JBkPIyOp%Z;$x))1A{?<f#3MTy<odYLV93jRbBVs zctTVl{dVHV+G$o<48V9((a^nn|B;6tyaW6tE;i<uk9_s$@v{}@&PRlYu31@-nVtd? z2PO{U`QOj(PKgVFfS!ipBZFRg_vFpjZwB@vx<g6Bp5FF-N2-8F0o%HJ`$;z@S69MA zb@k07qf^xB6haspA6FNdhCHD}C!Kxrxp#|}<+51;hK;X(@grL{t~^s-JuooxiM(`x zX@V0x3xw!wRYQ5>;P}`$&xQWt#_Ki*`1>C@Q5GH+#OTY*Sz<S+jcdV{ke;8}+}7Ja zF#POGy9x`k=_YRW>4)xKS(Jb3Ocf9ReqmOAP6k&>3|dhjI8=Is-_aALSsAH7R9MH; z%d_<8sS}lLX>q}qs?QlJH<JL?Gf41nZSRhWjzqodRxf+`XP-KJ^lVsY5c~;6g*l<2 z!Qv97!_C)keCxg9f#EUSNUg+Ts0=oy_Iwt(y|cR*C>dZkDl*Kju@xnyHPkX)u`D}d zNeV$72DKU7Ql{0*3kDf7{4h8&S#|Dwer_gCC@TasHMjorV9gy%6F?ielmz+1r)rCj zoVtG7Cd!!>=4buk(XXSQ^9^ljDe-Go6~;zKq9vxveFu-dUs9JG7m^x6vUZ=u%Gp-( zr$@i~+S~gv5SCi8EH^YHSXm7^VKlOT4W#+X8+*U;rH>I1iiwW+?$<xDt+euNSq-s} z|J=MPJuL~7d*khuH76@t!h`(>28O7zi1Kg0bsGuG<&|}?)fePtF!@lP6aX6Y1qTJ* zylu^Udyik78?dm*z#h&p)7UV-Bgab%^K+1x8R@Ctf2a6pNp)=#;^$_iUA=K7&&B;9 z&#q}`4-51io1B4|p61Y4L0;ybm%b1CKl$m$N@~W&Cz+AJd5NJy1yfmFpAZ|Jo0EpG z5?5e6+EeB|w_mg3=!r@_TFT}QWWy0=F3e<Sryo50e<r7APM4IwvF9Yj?tJyZpPyWe zp<g~)|CPRevYsU_Z)5SUZOMoZ;8J!P5Dg+=20b-1Fx(^O8`}V#@g<sLiU7`DSyYgp zlQ}Utxqa)#C25JpN6z&14=pXoWCn&?N!X9q-`+bkJO<^u5Sq<rmu>Hp0=pR;;-63N z{K<De@8?JGi;&*!W#@iP`B}$N;_k|RO5bs<?t!t7+;R2D=y<BPCp#4&4g2{c->7eB zrjH5n(Ft*}OhnkrVK0~S`Ivx8L2~%to_!ZRun~cf%njFFeK=+Dq4!S@3=J0*W*05b zm!WHBo_BX2I@i=wkQQ@sZbGF?aJHrv>SjdqZ(Y7Melk2f!YNxKRxHckz3)-tG;Chk zUtC&LxMb7DHBh?KMonGA3p@8=NtA4=W`52SaRr<wmMI>bymN&qoQXJEYer27v%q<x z&&##OFrhMMER?3ju+Dj+vO}nq<%Lz$MbDMtyrQyo_EEz+)rqQnN4iF{$A+PR9hVov zl*odbKdmg#mGy;{%9d)+7U;w(gM_e%n^`cQT9{N=rzH|9hlcghq9+boFiDR(sTx9^ ztela`8cs<igy}lMb>&YL@31hcEZfWaA)JpG3ofK7l5ALKN1g|)(N7<SIZcT9h>JWl zS<Z%`W6cuI27>eyrQ(F1oW=E9L0C|-u+)eKJXQVJtbeR;Ozo=rfw{9t3DRjuP=u;- z8kmP6*iegXn3w9Q_4SWcW5LFU=3Y0{2~_2#HML^NPW;b|@(aCzTvIS9lbzXPC12l= zX4EyWjtxCIk=lypYfWKHL{ih#m0IK$bh5y18A`;{a!RC$&<jWYbi+awNUg-`sXpAQ zcUdW&UO74#TsUzyt8C(Ciy8@p)1m;Ddn|1tgnSoR-u9qT&;Q1!gfhEoOO~s3JQUPb zA6POpq*ub8LAf|G@Yz@P0GVytu*$|79~OGs&D(a|grtTfv;|(NI#>6Pr(PoGk@U3i z5dSCNIC|r@4Qo~xfxs?Ki2usxKPq3Hr1XNGgKhwbOVmj?M$OE@seMPW7+#xV!+*in zK{|kMfM{2(C^R1d_R-VR9~l`AhXa5q>+@Sb`dz_czW@{%Z~;JY-I}5`tCq=4@c=_$ zh2&X3^RJz4U4t><fo$hCkpN&Uvgg9XLpQBowQ=1_d5fJ*!n3`z`(H1;H9RsA6&{Ex z(5FJfBjl+e|A9UQc<br%#+P5)g&Ik}1+(6=Y0cFeR>@|8{K$%|t~vjwf4uDL?Y<<! z?_^0i)WC=r5a7GxrfVs(M{8UOm&M@VFk*li(d9dKY=_|G;h+9DX}o=XgOX%}%8)TO zxJ|UTcU|@SL)@tB3nrug*_Yl84h{re0_}p7I^m8O$?+m<e}ZYgfAkcq{pe82KRQNr z427doIASsKel1a-V?YL81~Dfde`e<ozWEt8%L4_jEGjHomM<ltvz%aASkCtyIzbjZ zlE_<?iDaHFnuZk56iNP{ocFZ2kQd)9j*p4lym2*;0PG`Fuzl+WX$unJv3p~4>t7y! zIV#u}HOfaJ(ZJ|rM^|ss;sn{|$jHc%*1<c%{TF%6^$v~`3t3*6Gc|PqwCGG}W!K<1 z51KD?)3`L3$fl&H2!|iDL<Oj;`Q-oX{NzXPz}9{~K5JJmTfMT7uiV^avZoDtd+ND2 zs8+f@EBs_h1&qmyY;hcK`m*iXb+j$fK%5^wBIt1#HS`n;@~`~xkGT5N&%XB2`**;0 zf)YUAmM_hf8jw{1Ie=@WRZSy8J`fh{_vY>sx7~a#aRM$TZMC|l(Ote>#k|?UG(x-k z51jz1gwuoJy!D#(*KArN=M!=~?Tq=;0CxEHjvKdx1_gZMKOW~6sT;0QD>yr#b)1kS z9vK#}r?@;V<-iTwHUV}Mgjm0}2&KtRVHD~Xpkc6n#;g-Q9&tH2sXg~OYjN0%Zynik z^;!lLS{fT4Cor=yDcCeCl0=61J@?8U9C%q_HZ3#D-Er$Sb2Q<!jLH)yOP_yrPeicq z%*;h1Nl(0TXwAw(0uM}#@a%u>3v#M70Cv&Bz~B%=m^n|IgKRUz!DAKq+3zDB(*kht z)~nYstC&-Ym$w(&M}GO|7gFOwt6TcYD$apE(<ULnJ9k`n`z>4LC}W6?j*XMB44nu9 zkaf#E`P@st*QDN<GaFWz@Ao~b2=e!SXa8v`f^J&Bl6lEi`t?rcnK@a-kqc!-<=uM^ zRn&E$mf`WKmbOk=+Ys~?gcNV)F+cmufukqRG7S=KMaX;aypapc`H(7zUbvK<P5cX= zdLTOD?LR&7mYLV@W)sHzImJ{A9PeA-)PdhZH_ugAfv5%>JDzy$NK_c_HhH<aHh{Be zRZ{TjvsJm-89dsZpxw|An+!4&L%6=Zf3%{iHa|Cu)OEt5<>l3sZHNr^<8d^{SZ3$J zvoF5QgHn<c7+D!hQkSGAOH0XI_1W2ryZ61%$l{$cF)_s_hB@ORxvPER1m_|{1NI)P zUVq@o?YCUV@MW6%>_>0C>-OL5*yiqpclUqWHk|!JGUT@$!xOW_-oUBr8=Dj3ZB#|P zH~^_J96};Lp40t*v33@~Z8XUqf17$ivt*E&?Qk9(GZ!2)Gcz+YUzpKhW@csvGsrB< zB$>jQ`&o0})Yc^H@uoiCmA=jHOmBBjPfPos-v0zU_^B||7HUicF*w{LiX|nRzw-Hy z<YZ;AtP8tWaZ$eV1KRL?boBU{^*c{a&P#^)MPHs0cA>&jOdiq>VM|p)W!Y!_>=A=q zSYK>vZY9PB<0>}h6)*cg(gcAzeb&)ey>tS0vBXY0_Wz)<U?fMV?h3-tU8>`5rou(7 z)XuW>@N>WWp#Aw=2<0h`O;1#2GDay+$U~*M<BG1G9>!Q7Zmfe6LvHaX9G;7fkC2wb zNnwBfH9X!pj+d^gPQ+-bL4UFKyA;D^*|c<6$H6B;Kc^QmX##|P6V*iw{SamiVWJzu z)Q}6=P2ErBK=T8n+2gudW(f{_8PYDHgt;h^9QK31CA93RkEfG~HXKbjTV&WT)c}AC zEpp7`Wf`^6b^@0!c9}{IS;7X;xDow~;#_lr(M1TIuU`oBVxti9Zo=Mjgwu-=(sAmV zQNH$V=Dz;jHSFowRUKK+pHr0(fsp5yWX3DqvxW%$ic2BFK#5>vBr<#0UGb`WuNcS4 zatFMc!%r9}lpV%cM})26EyoDAtLs8D!l05v47f4NvM<C~hVE`&R}{kx0z>=>0|sh6 zXO_|9UURC0@<N{x?sA>bP1fe0K0Nw0^Pf4X3!}@QJICtgxXC9f28ZoLWr!8QDFpwO zcLxz30j0GNU;63Xm20+yLSY)p=X1&X$s_Boy+^+J<A3@a+ac1WJ<sj`o0s(0nX68m zI%h?Y3+n|KG~ClyvS!Qq3s=DtIS;TEA=0#-h$m8IP72dZ2WbN6*?aQVqGjuwngbDV zL`eBU2vGG6n|Cc*z7ez<90v&q=e)ei8Ok;{ZQaXWg+d60-SeGaRpbBDKNc+Ca)P3~ z7wT0-q|3<i%IdWnck<}VDb<C~TX)KT@%uRkPh3m#MAJp-tgQ;lf8sGdg+Ln-A2a4} z3%AdjSAzbW;7^I=37`7<f6ZQr{+O2Hjh?+?_qJUJD4CbVrxM4(byWDym|H?&I65&# z+ziS09zMxViQRkn%%!V0C8zl#S<@(l8es_^%2f^azH93Uedm{Rw(mLw&_+vXqhuoP z?HgFXY1emuyNFQ+E|gMK19X5mSq+ke4`4{QA}IEQ2agzBC(f}aQW;zMFwoeAn|1%3 zwfxHU+elV;7N4ksH%_0s^4A&5EBtNI<3?#=qHPyrS<fIug6RcD0$C9`C|+<94~W=t zqki<4l}k!C0oicI9u-6~yaYe`&79knjnKQ(MMYqqFZR%}3)G1NI)jhE+x`+?G@gdj zxu!K-Q{!jSNIbf}F#u6MeTSxrq|W`(qloK-Kt43v$|AIlj~To5;HBUHZPA_bYET#H z92#Q=zJh6I)`C@MFIPYa?v0CDw&~c$t$V}aJ~>Q4QgW)YN8Ey?>-HTwMK8&i{DgZ& zgqLhP_4k>}>KmK!w-heB0K9JAzMryim`QM>qz6&?-a<F=UuQ2~mkUmTw)XYA&*ety z;<aZUbs)tO|HsbVE?K)BY7_}>@+qAU*YmPfTej^yBu8IxQqEtCf#X<!L9<L^hle6g z_)iTc#n(g~>p&2R%viE(_M)|tnZa%pDPrEz4P*ciQUXC{k0D<5<3PHxGu&5QTTch( z0!7oij$BKK9jEB#kpt!mz4-TjvvBja{lKZ5;ZMyb0R62y_J8kpi)cejZcV`W;>Rvr zvGx4L>v&jdB9kR+SF6_TxKmaGp38ZbAF#`50a-@KALeYDw|HG3(9YdBBkdK;o%{Fq zA3X8r=_|&J9Hjg%%<#-wu~*J_DM6)_iptvQb4t!%yhiBClPWW7a|&euqJeQCa={^l zBIc-@KJyQL{8<Y(ZrO1_GNB707-5NWMuM|-Y00KpCHu2dVj0AQn6X!GR318dn#qL` zObtn%4(Ijyt%vp=I8H|5R!Vsql$Y21ea7-ZPezEkCEXn1jbd_VQN%KEDl4O{CwAP4 zOBLI9A7VjB3W+pltet;wq6{75qV^xXG;nu7GOI96x(Dv7N@pela5GBa(&`$2XU{$E zt5OGjuiUKq?$2kQICVjqr4o)1f+gE|i`V?(pKI8w6J6*?*5Z=n!=byKu}VDaryIv` zbd1mTPG7wJPFWR0iGN@BnwNd`yRQL8$LBKt%UrG&qU7+&5K|;e%p*BBF@$4y<2j(8 zzrJP1?n8Wep)x*`6A<o~mFu?gf(wx>grJ6fBvy-O%qA2-PJHax3)d>Y_p^VVIe!@u zc0bUHjd^FyFZuCbR<PSGOIg?_#50n+3gEj0vk;brhEkN_-FzuX>O~KqH|F&Dn}?5` zmi+8|;tuhIMMVT5-x?92;io14*B9S}s@&55Tw}T~-usApEvEXf>!)SQP>3g<zZBYK zTVYGjHgkr{d18Lvb@BY_&J4$0DuiWJ-mI?9!>l>SV4J0m?Tyv3Guox!LAV-YVfMN1 zOb5e+@qU_yE^5Tw)quGlI8$|>VOk0I1eWfJJ`BXh`f1@zjbogphAE^Av0Rv;o?I+v zO<ao8Ls=Il+zWLdsFn-nR$=4Q5l_pS`qH;)%Y^bk#hQGF$dOz?w$U!wx)|-Y)CwV8 zbRp*6`oGm8z)(W0VGW9^xDkQ_gGRb==|^2z$IY}&Hlu*D%RaF!-CwFsQytJn{a8_k z4Xe;x6Q*A?sjOdf7$#0>M{XyNa*ou}-7sl(X#;2&FQa(J8DaLKHYe>P?94Y}=@URz zYUs07X=K*LY?dm7FwRy@xOQvZ`IbSN8R1r<v|x7bX-*2pMyA+uXM}CWSWaCHV%^+H zn~_>{nPg}}%%-ZP-yvmN8nutGB{$W@Q87!RkCrU0N{EX}^2P}vB3unH(h7U0NL||q ze@loR$%+ee@^Uic;-cYF04b}e^j|M;@_C|YKoO{P5D%i%yWPG2_<twmz!#C7mBw?a zzrG0^=So@Av_hXJKISn9R40|J_ZY%tFI86KP_;GKJ#g<n-5FRX=ScV%<fyfyH$6FS z^7vdz=cv_%C<Bxs+&gfsyg4H&Ce7!4(`#P}j(qh->Aur<e)rvvzUv)t9X)d7ne$iP z`K{^ie|c_EL3Uw&4i$m`VW8f(%Ie|!<_-7z4<7+v-tl+*;0y2k%qQNDBIhn#e#;ww z_W7^9HZM0LKQ|jrlwf-oB*Hh#>R}p*j~NFTC*du2`btTR;~2D}wLJu&z_T-jdr{*C zi<E;MA-G%tjF5@`R08Itd6GS`>FK`WqFk_DP=i3A<9bCCY^~8zqa~1pkk+og$pvY} z`B``pAfvph4!Yj9_OQRTJ0mG}VsSS0#lR4kua|X)`$tChrG(@mHzQHS53YvvHZdWF zfkr0HppO9BKxgS~_UN0E@8iAutjshjWO<+6-_TT9)llXSatq=?E{E{cpXiB>jUEeR z+|kuTdFUXfW24tk^2A1u8v{zx*4e|SoE=XmNJih67zdFK{|a^v^6GK{pR|Yi(Q4{= z-kVRR9+|S=?ocn-rN5yS$eW!4W1<kw+w_hPDH*9AkQYL_DbQt~rSca`dP)Mg7!X)n zM_7Rs;CD^IFk?}emr;<HnGhdC1CST!dT&=Y$40^O`rklK+7BK8A6T<7A6K*nL);OB znah}l2M7av3oCJZXYX)Ia&RmtDx*Vp*shrua$MwPL_r_i8SbZ^by87AL2ecd9@I+L zH?%ahw3SvjL$JUa2|CaimD)P{3UiW*3$k-EQ>pf?s;(zII=XwS8#~jJVhVE8UjC9P z!S>F}*UGpT5k|lVyZXQZClzNwUgSxL1%NB7sO=8-Ro1spD)2$ei@k(2b6n+nG(@Fe zfB#dwazU&fJbLDL)7KSbdKn<)d8Y$h73#mA=}Q=2Fc{SgbX9GAV^aWqD(c(4F=M7p z%%MOSko4T8+g+hPUs4<#`se_gKg`8IQT8{_@HVS%j8Su-Tir++<x7m6P?S}Wmqo37 zLsOu-wgE;U{O~`;>BJiX1HljrHiNjiv$lND_(pAT#Xr71ZOR19->_vLOv>K4ag4so z<q|IBYD-7ogxut!{7l#|qNB#b&cUifMRh}2T`<)fMN?)I(xnecJA6(l&LmZ)`Vv9R z{SD2x%WEtA?UV9-%r)%7YF3hDfI0m!@tfLua??FY-k6Nkl){1>!U&{35bU~M(d>yH zJ!Z^Ex!?nA-4VJwG2d5!hM8$tS5{dU40f~x!*JXeWqBtR=S-bkT<34Rdb1LuaApne z#k!VYNai|DB8r_j$!w_%&Dc?(lfjPg13695@+rg<#}Fh<?R`@VeL0yv%Hflfy_C=f zf}N~()YZ2&wuLiNVv!^3`X4-cbnpJ-qMT$rFV_!3J^i7c0gl7{4<;7)it=+{*g$ew zc@4qLn>sMXvwrrfmrR87inl|qT(4jkhqUB)l*fC4_V8l`iQ2U4>A%m`ue?bC%Fpm| z7f8cpmUbu{5E7qF_j%BbX5Ele_Y5dz1*U3pVjS>0_O^HRK-zAHYtesXBn9;hJeXRX zQJ9}iqJt&~maW>_MwZanUm-Ik4nM0dzNC19pB*yET12dLFdxKT)VR?p-Z-W()Et41 zFtE7&_c^O3X(<UL3f6cCd(w4Qx|d7v#x%Ee^G*njQwRMsid;<+qorc}le<l(B*l~c z*wO>eYs`s>8vWqW;IjA5iw*C4MYb<F-s|yjmo~l;L%nO4UcY*MdQo9MUyHx{)9j1a zt5}L7PM#*7<Cy>9y}tf?YzQ)Kd?w$;ys<Qr*O<D(d>!M5`j+l2Up!yOvImiym6j+M zs~TH6lvp)584SnhkyK}62&grlP=(&=fM)m#fAUSu*4%BK;eV5I7u~YdTo{1YwU+P0 z-QE2cFk^y^Va60DxVyXikROA)OmKIHKGMQ1o=#RydL^riy6e{Q$lh<Zq`ThQC%hwL zHS)-0w*7>o4uA^ft;M!u&lEhy_qJ{|U8?^4%b(>Ns(f%_S$0rXaJE!@=gRT&elT6N zkgiuupMaw*`0g&N8dW388B$A5tLad2-L$Aq#7K9G7~Y*EEP*ubAlns}eYK1<Bu8gU z5o<?Yi;S4P%L-9jtdy=QX;NnsLppTj`tMRe833ij3gdLNYnsw+Va2SbD535YLrvE> zX%eEGU!AXFUBPqVXS@2+P91Wy$p`q<Gi&N32WXm`PV39TkfhWqQ)il*7>st~WUcKX zv=eR$(z?5;QoI=ORXo<SI!aB}DUI58RR}WeT<2iDOJwdRu??B{_Gd-0Wa7J>%F4#* zdh~5h&M-F#>3)KDqIL_h30X<jbg!b#L~2u<U)(w~L&z4WO;Xq`^Vh8p{h9?!XQz~B zax5plV;UDkZb?Sfe0M=Er>Lu=xiCUukSeiVwVQUlYB=R{_E(Tnl4u>>l%OnvEcv^3 z;=4|aa)o7o>tm4|F-^_rw>~{ebIS;;S@K2QC2Q0E#3IE=O?-Ewg$rrPnSSm(@m)r+ zUwtIs?jZ49zC|lztA6|2@(?Wj?6Qa=o63K(to)d+lC-XecjLR0&Thna_e@An6Z5L# zkotu9dc#PLYw~tf#`KavNJCA;RjrMukpy%ealNH!*tT`EJLffog!|+0-_1(8+$HW7 zj-EgSEV^9{G98Y+Mui}5luRii9QNjek#y*F(<yRmZ4xF6-(eO41#M^j)q~G6U5o$~ z7qGHAiFJDZga`Yx%m4cD;T%V+6SuF52S54t_uDSJ;QVvWa*O`bD{tQW=nD+6wmzd& z{VayUM6;{~R4XUygD-x$IuYNmzW&yEmppXli3d36*8nZ1um%<Y{zQq!s!w`nEK8sp z=GdtI4n%j?L&KFErm#fJu>%7E@7x0hVGa{_-DO~nY`iHYJawbhv5}O!OhnL-Mg@KZ znZ7oj!K0=UvyUJ!o=oi<L1rY$4)*{?3u=at4I~udu>M{hGl(L;NB|Ln^7#L-56R-l z@pK9;!wv(E;_NFRN#J}MEm_O5U2c7BB&Tm04(4Xj?}O#H|I<LiC_b%)D7_BJ{r|8> zJI^jXeke34L5(l$tWj+B#t3pk2?TEu9Lqc2mpfRPS}l<HR9zkm!;8(rcdNq(>6z>5 zZ}ok{M356@9Gf$Br>!95;5e{~%pS9#IP?l05#ab^@|7gUKxH4H>j&r?0YfkE^F_2_ zkO#>Ybk9`4tWQJr>lPtI7d<|V5gul-un<u3D`9yU<ED{MRf8&f-{cbKsUWmB=s*AP zb<Xy6Jjs<eK7ti8tA#;ci~<41N<2cH%|ksYl>ML)Y;<JgSRJ?zMvN=Z0z{qID_)k@ z*L8v<#kMUfqC&v0>YarxA|wtK_8Eu1m?G&Ifh(IOXsy;_*;7m&e(-*G+<39mhn<OZ z%Uw@>^yQDc{;$uz^+V+??7uo@&$<1B7D#$&YZ9M%Xww+1>F?3lU>nkw@RSj%{||bQ z!ymUwTj+mMJ>r2q*^1W5bbHVncB=mkBsI+&c}VFf<U6JDIU?(YEu}|-z}BTr5`hf{ z*wFeDWJu09<!C8`O@8}>PkaZPF0S!C{WozL-c8D7J2syaXco&;tX*ggdfPN-TZT{* zdl7bg_5+eeT1H6-TSBNs*zl~jKS%Q(V(l2gAku)5=drP=IvOlW6Ni!tY~luKZ*0Gt z1<p$h{r&<>`ZP%>kIOGTBv4v&=>D{1mt#*r6`b@MW+*!_GUG2Ak3$WUl6n^cEtXC< zVE7$?Vyg+gUInJ{kpr>O>3W2O4KOZmbvz|RW-(y#76~c~u_YRB>kun@@4fp)7oO)# zr1kZ+f2q3)Alr2t8r|Lfi;v%DW@g5L(omV1xg98TJ6LAscCgIM%*@<=rU##SeX2y0 zj7IgI+UYI%!^_J}WRVr;#Fk$4vUlkPOWhX{rF_Y@YwvLOG0%SLWA#^czo$R<CBOaC zrTU2M5$b<%+a6oj|C=6k40mTHW;<1#8pV$-a|RV>xnmXZ<E~LXSm0_Se@q<dUjfj@ zoHn4z;$rKuCi093q|q5p0=hF$6{#nr1a%J^JQ_e2Rml*D2YVtg(ntipo!t5H3%ECy z$g&-vdPS<!^Ds+n?=*@c0-zfB&Xz*rz_*=5{yn;H6gBTv7**9bhF-eUL9+$Gcg$qz z<`T4HW-kOuV26WcV#<ur0Rg>DGWX`|U5Jqg@Kyl6vngeJCJT_{Ai50V%5XWN@uS#| zl^_p?e-XyrFd{`bC?9#rn=hsxj}|N*R?cwY?GBMl<c$s@z&SIIAaT&<fp0PY$S@Xx z?*VVO1L}ydTf!C5*F5)dCUj@naJHZ~Bs}RlWC(avO87oOQt;*pQZsoq`BwNzuQ$uU zBLm(0oT>sp5N8=^QMZ5GBO@qKMSl^Zyu~S`8xRe%bWFuVR0JWPI&ZurVx9s|rV>Vd z7~pOqQ50+>|63#!z%@bG{)75-1bLOjqwyJBBx5EiF%u$1<X7doNm`-pC06asi^uqM z!KXf%eC&^Xm-l$SjH%fw)fNj6v0lF=LxMxE`Rw*#l}Sy@p#J<Z8vT%1si+CDxbVb) zbWHFP@3Cwtr%~>qjt-o~32j+pLMFtg^C}cugEl`m3u7R`C<JFwU`}5J7wz@9e_Fz7 zYNc3KD0K;ub-|a23=d-f9iB3oU$=m^qwX{sBWsYsFk|P#MY?3)%C?sOvMzwe5_ub( zs;}`1+BO|H7$jDNY2%76<81{ol4x7I@?G*z30!~EYKxm}Fku?&$z&H1mjPg+3xrMi zLv{<5&HxJ}z)j#(6$&1$o12lw$Qn%;nj^gd^jLdQ{isAkMi=xO=O-fTmlrmyh~X3f ztQx0?C@MFM(1a#+h`FMlW^uSDWS3q8iWexLFeGxeP7L*Sb7v?%rT<#=x9+^U7F%JZ zXE9%p&+b($uT_gF3U-AUo~v+)Pp>d!s_9dEv-v;=RqIiEu^qtGT5DZGoAYtITTQRX z(Jm{qGMJ)cQi)_^i(S%FYrM4RFsyYe^Fx-5qG-@tr&nxzGwYSpnp<RG!FojdlZ&Ye zDb9D_MeNE!fjWfEG1N;fvrzx;Es8oRdbOb)u;w!`v#9SW9TPMG(pawQS?%KD?Kiyg z`S;Tl%#(>|2BGsW-ln%FKM@nQb5$v8j(bJx2Cp`04ee46MHbplI~xo<ply+$0@-$u z0N<l_p~%{Xl^GEk3}qq0--5Nb6m_um<hF#J*WLQed)`5JmZ-2l`{i$S=gPjjty3jL zti0)!w$O*lM*4nRGZ|gKAKd^?K(N0yc4(*!7pq0)I+sA}uSN4fl}p2&-X%7CdUfe2 z4%@`F(=I~xt2g@KqmZC_@5YrynTU<JgvO9Wqm}^Gz~P4;sEd?!lZs~TSX4;|w*8X} z5f|vFt*XTr+=rr}caM4xoG)wF#$j*1q{pl1nD67ESsiF8i0Bi+-pXz8>XnXQTvlRZ ze13jT9n4>rQ@4aHnHDXLfBzml>Apo-=r*n9{3<olUMAuy>A@b6Db&_mQr@~y3A@Mx z=ra=y2z_4>@v{-_hsK7LMWfv32ZO57)CC}52on(vaf59qGwq`LlTSQa3l6JCJ?ep% zzv;c7yx_`fZ(YUug}LJo-}m7Ux`(3PD*hk-bpH7l?@-DBNTvd@51DPiU(j=Ykix9# zAWr>P)n&J5Qe6$d0txxoW|-Ne4HrgqP^a|zSy?tBcBXBu5|(x`D*+vKaUI0G%Cum+ zkBv@%uyh3CFRVoYGTn-sEe5>1vT<C3nA$if%sCP?7z2u_ilm4kGi7sv8fnGdN;Kh) zGkexS%I?9$69j4$q9G+Nktqg=a?46_W?Au{IvBfgJ2rpWW7YY_R=I?`133q)z^^1n z-C?jYvI?U!oX0@H?n3NNh#tiu;2ihhFTz+GHAnCVCzsHnFOhd+lDSZ91@0udih5jN zAsxjP-{S(c1h+x)%`(`;IPqhUe%_MdFkjr#S7d-43$Ifai!2FOAk~Fr&-3wF5LiSi zpPl^LdLpB!W&{g?a6qE`wAObdv5*8!I}uGt3sWMV=dH+0^~%X>daV1o<I(o2>lTHA zNh6@CEb<SlUJ%K}(im86v{T)LJ8ILh<>k)5HP*xK<45ZFCR923cqRV|E8ylCN0!q7 zn&~(39*9b&%vB`-)pWf)!YKy;3CVRU{Tn{QqI&B*exiZlixOe<7Iqo1&c17b>!#RX z0FXBd670OpPK+6cX&8EfgcPEF?A4<Q$zV{LhaMjOaR_OC%I6qz(~USPgh|@>7|%P1 z#3|N^lTmD6=MO~p(sLsD$BP%AZ8~teCFjAzZnk)0*a9E6VrF~v8WU4<i5C)TARPsa z1j9Z@hj$0Dh;m|!S9$==D?x27QN7L?!yZ<o{wiIJdH%L*p8Mqc?7jD%`UUHdgZ2lY z%Y(o4weRZ6+L^Xa>?+&ECBp$7zkN(V^twnS;N7mpP~bS}=|?~!ewDQfs84*vUG~_0 ztL8*H_`rPuXrkoreD7y76Tg8h+iQ4rWeq)-amWA(+;d`s`7!NRGQr37ie|Netio>; zhu60UR;2$G5RowC{GS2lE_~3L?Kty6Jqalc1U`&m<Pa{&Z0QSbmokAD?k8&U;j={Y zZ!M8nq$Uzy8$iB^1fbkVrGOqH0X|B&@?~%&y0PD;g!=K%etq8Ar|LJ4d))O-M;>v= z&wl=EAZ^*Q<&=|-)gre5QffZ?`LAmtFU@+Sn>KjH<KPluh7zuhHW$Az(SiWoG%BvU zoYw`{lmP%}Z%Otx8F%(e-2EzuxtsgjD(AEyTT9W5ZwNw<N^OfARbpzM@vpveQ~ABZ z=~cZ+5efN)LZh)jvPKtPyK)>ZK-u-X!zGX7`g|E46GJ0$SmgM~G}L)ceUrTB5Oiu9 z!>e{^38gl+Nsy3dOUWC%5#&a{_?d_V0y&hW#DXZcwp1#Ilp(7zt>kE+5=fBozzfCp z;uwrNmHrZ!?RnVSHk)7QS6lHjz@nhBFr<{=6;@fp+7=#9H&UBci)xCgy33bgf^r*o zlf{cFHNccc@(34_jVc+bMU1x>o1sePtE*2E%^LD@aX`7e5hRstts~cza{(u#DT&@n zqD9=h5Wf8nJdX1d2`dSR&ZpPFrmc|`-Xtb#8yjgV8$_lJdB?Q=DY*nUWnx6bG5fiw z8jEieH(<4z%S#ngOGyy|!enODq+cM`=I)r)LX~ZD6`FIx4rR4Vey!I7T_wQVAX9kE zRY$Yw_Y>WZ5|~0qGG(nH7%UpFic3t@3Iy*hXKUJap8l+EGMU+DuRTsb<!H@Wft0j} z=eNK4{m*~nS9|ZaPFFOKmmr@1uM?4!($eDmAqVfLIiodqu&w_7#<#!o(J%ev5Ub%i zt#@P8dseyEP1VV5;r7pe_50bGHrLIBzOQqJ_!adHRKVC1rt^X$(?MxS@t-loMmr>1 zO_vgO-@NkLx4wVZ%^QzA@-Qt>dE)U$oqXak07S$xpy~fU`pGYR_G>>rXs=C{uw{x7 z3<aZu-CFPW;QMJEg=B|(wQfn44KBy@Y>ft$liTrD6mE;k-VjvHM_|D$u{8B{w0<R3 zVhxZ<b2W@0=*gkVY=|haP|!X9_aI5Y4ScWQHs!;$O6iEbP9I_?&%P3iMfo6wAPG;3 zUO9M)u_HOSl*+kY1=*;KQoVq(RMkNJaMW{}Ov1`kO~pa+vaj57Ibk_H0^TBiF=#H; z2_W90!Z1%>0hAB7;K(Ds3kW||bV)%6km5UuX(gYm$dTvzLiOi1L~zE-Q3i{J51e`K zC3M16P0S>v^E3o9kxSG?K;n`4tZhXjLE;hTLrR$B!z!2<;VVe)Vy{VLyWlx$90ifF zlX?UT5?;t@mUTNaFN_f16(>@n9Iv5~>(tR8jw>0T{iM82DZ>egUqG`<zvW-i1bUYl z3-HP;%W&fB`x}vHeMdAOPy>BP&UfNn@aKi(y<s*YKFmjizK!p`ap`a8Uwp|Wmo6_a zZri>?JRM|+CA53DckaCA(#tN_pSEq=vDcP`)s*V3POah6=fx%8MZt31-c{ke1w)&c z<RALMm>H{1xA6+e2=Uj>hjP($b5}<BGHt$DC5wE|k`tNYhEjhZrAwE((umFWomXw! zevKBeZIFKYi{HNWJs;QVlDFADj{mntCW|7X=$;n8-L`$pZEaY_4}SEE*T3uI2kf!I zQ13?auET8}?FfkzEO$VPRoTJRU@3Coj;*fa_kZ#S%fGKlDliPUc#vNWI2QY=mcu7_ zUUQfFaFDeZZ+T-^a~;*@b?u9?5LmjlKNCCzOhgR?@luzPTdQb3{e`c;|2=Pi_8BK> z8RQvFNI#j}a?34%R;%9mfscIl3*Y?ZURzggONh({awu7V3a;OH3T4(o(cpk{;h~lc z1le_}Qi5Oi^ng5|D&o410?Sl$o<NKdt_EU1!corDQqH^(lbDh~LM-K4s>YA>(ZQF} z8Pzcp6b?bm0qVsr8y0l}q(&kLx31zH>6qa1_~&6#LTBNU934SfwpQZ)8D#`HDYRdJ zXGly+UB7Tw)<SOz*HG{w$@A{=ygl$ARpKQ%vg5OWMw^JED#G25m?>5$1nL+IZpeec zsEI>3L321s?j96(9LK91f9f4ESisi~%cX>t+<G{;5x{C%vT}SQplQi&j1sRYLYEXv z^aZ4(st8`JUsqJnj#e!+mI5OIQ6V)geU5vhOJ7TT=ee4eIqr#MyryL|)7YApzFS&* zFUXfSlP5Ch(v=MpLekxlkt;q~NvX%cN(Rv-Why03JY$~60G_bAlyQ7{rwaFyyNRIv z#@C*1l$b&%yrQaAv_uAd8<$!~gfJAnpW!#u*~98i*SCibq^3e<fo+^sLbYM0FG4sL z3iiVwCG5S|*16d^AYFXvm8+`|$-0}He~SnTGL}1|+c=Eb$#_~6-#>|Z{#+jysHr97 zgCpLZi_GLwH;DQ+k+weAj%#kbEn(C0yyo#laHA$lDvfBm+bgfSK~HX2nb$n3mX)>E z<k5aU95$|COz`QcBg7%9yMw%wN{F=*cT7<zdg|-OOlST%;0^?w0rHHP;<9djNxn}S z)VYEQG0q6TpyU9WhC3a6z#a?p^S}Dt`PW{5<Ccv}ZIY9OT3}%uQ{zolNmLq1NSbT= zkOTM9I*Gsh-32$?c=OhcOQp5VxS8U4s-AeY9{_bqDpw<sMzKyi-+vCIH-P}(k)?WZ zNQ?b3<3t6sDIc$US*vrdHb)wPl~~w!ymDgE!uZQDEA5gU>9X!^SKqLju+Q$B4?lSC z#l?l+{po_={pC^(0xOHN8`mxUoxQi**CfZX{`7zHR5eu7ivwn6W@h`NufR9pOEG@+ zE%=L>nVH!yGY`)+W}fBj=|1{}&Wg~At%$5F&$NEk**Z^zwzf7YLZQ9%;}cvtU`pp* zUs1mOMsSE(KRM5J@Aunp!>$Vr`E&kIt=9**OMcv?=K9jEf73Khe#;Ia3Dfy$Gc{L{ ztH&(Ie(+N+D=8dZuf39nAdRbCU7&f)+N=Y;Iv<{p-crc+-i(8;YiLqFFw?aoX?Sgs zlt(;nQnFJnwR^zmupZEcEAGu6cFp6$>7jPaVE-Xntla7bXF8&z^yzH~S1-b@6&u$e zd@sQsCN62$++as#j{@8TL*!rKwT+HlyS#L(hJPRNQ!Xba)b-_7bvA5mLIEz`V$d7a zG_n%Is=R^1DX&)i+}Aj>^(Ncs@KnPFS$#ZH{-s`m-gFBcBYVAZAxT5Bql{@Ex~Qx< zS>?{$>buD({;XcvREy;0O7|NVIDOs$4GES;?9c8k8^>h@=w92^-Tt6M-&36r*Hl&9 z70ni;&DQ2MJO|(Cs5GFdQDo1K@Ln?tm%Y}9q|Ah_>ZX*NulD{t#y|UaehTf~^KeGu z(P=)<P45q3`}2PKTR*Hz&;1m;Wqvh*mzg|weqK|60*#MbR2VL?`NtlXoR{?|t&6PG z3-7(@&F}jIf9%~my+0=Iv#)&pedSrU>iyA*c~Y;Go9hAZ2m5<}-yeOJ-XCW8^{;&L zuAiD(lB8~#{`GlSaq6R=IQko~$i)2dOMjvM;5yC^aQrZXipS%pe%sgiVRqX0{=5JA z|9SiF`TcphfBsK@OYP-w=BCESkRvu6tw_K{A|eH^zCKAoO^CBLsLum$)H~9>FBQ7o zIXMrrrvl*!`Jl|m(qPnU8Mvqas43GGywi2}GKt6qn)S3II8--QQSQ@22?0YRdT#8| z$EW+ke91)^7gnYSYkr+QXm2#PZJk<dlV7Vlx)yvxGczpHTUidtL?qX-_p^%?`2<bs zV{0-Or;+(5C-f+`AfQUmd%_VI%7{@Kc9TntEh*tu95=@N=x{U)8ZiV5I9jZ|c8CGp z95Qx76m<s5C=|CDQADI+mq+3E^_iNp5=7@mNXWPW4i%}G)`5kr@E}Jq1BL?n&&ZRD zD{3%IT>;?)cf>;Eg&Jzpz%4mogz?1j<>$y)_P49krFS9Ac#pOB7_#qvv{6cv<`Uh~ z?5mO>Pna`=6F*y_hH#P=4h%vgDTOM82K(Lp_=Q|*4KoPuuD_7Hf2CIwjRyC;HFVe8 zXkqY1?nOA^B<hN%2YKYlbNT(C-o6c!15lE~{3~T3ko8jB{Eqh=cA*Ep!!T5rcP?sb zdVkm>zrFza_MOi4MLudHl}zme9Lg@WFMs*dAFcMjle7lBkzqtEy=$lpFjY>)+o*{v zk_cP};GiLOkzSF-8hudk6RRii6PkRN@H)zhs`B@ocV5&eLHEC0su(L7xuQ=}lAhoF zSg~LK+E-}p-Lrl;R~`hlAT1M80rN!ulab1pCx@xis0r_cc7%DNm#PMdvWMt^tI|L& zwR`<u%oA!R<wic?$W%>jX=k8@r(#qvPq6&4P_V|XM)i&}8ASvJkS#YAr*!Bpvk|&- zOFzX&esRzB#K9FSgaZ~_r<&-o0OX3Rizdal2`^cLJy8SgGZ#pL`uLJ>5}<36F$WxN zjyqD5Y3t~scGiMajP?^(_kNPF`U8nnhc%O#p{dDuErwETVo7U=W0FS#t{+$JU-bSM zZl%#0<MGX|aTvKMeevrgNt%l&L)nw5PLPzJ-DJZF6V-(mpspEQJ0A9k>hV_F!SoAR zC?@KxCh9<e1fAEEy<vfUePuNfxU*Xd2i9_$2;*8SgJr;|2<ZRUg^(sW!%(TqoPkYs z>>lG_`H9qU!?duVpI3Tk4iTgoO7~ao8xv+|%6;Tf0C&E1YYyTjwFmsEKl6)!>`(mM zpZJqMFA0c_g}+8IA_I#_T9r0*#E5C=Q<=JS7*xtZEXD>~dQdBW{7`r!%&TYN{iLdL z`okr?BDgTot;!3w6-%Wjjl*r{dSMFw$R6+3uZo<p#-$hJmGFFX@27!kWkSK8LVKl+ z6}A<c8hU>2d!I846YLMBOu4p?s2LKZkBj-Zy2%+I?|yx-y|X0Mtgm$=HQ7wi`5H%O z1}QLgwPYoYb?BlMw(a6hX6sRO!;$PjftB1Q$~+pIJst`%vch$ZO~A*-i_#A_fbV~= zk4Sce{{6OnLGW5o%v{bM{mBP$_*2s^ZZsPn>^178E0?b8*m)RDiF+MEBNG&8he$%C zLLXi36Yq`5yR`z(Y^YK6NaVe$?$0JKHE0aFK5R}Q#EDLoK?F{lZ9j~G1qM5Z*5t#Y zUkRmRVT5)xYUVD}y8T^c*Cc#>!;IK{lj4e4alz4RW@SUGLBlj;g!|=<$@szwIXKAI zVsMXRWs%diL9(2uZRE0{2CB=ed<ObVST<E-(8Hstj%XmmZ;+f$$dS@=VxDB2X(z2j z+a`(dKnK-P0ri>@X<*O0Qos{2-i^&2SpDZF8gZP=lX5i3P!Xpii`qw15pf__RhMz? zrn4Qqo2-vuXwz$ci&wJ$rD!*dg!C-+JlJ<~jlt`Bt*%73{>vJ4t#y&t&CK*147a<V zUzEFWc}TLqO;Ec`=FWT+T@_L>ldn1~^&{inJl?!{^ZxLtlO5<qE#g4`!8=o-KZ+ZH z@K?AcmmD}N{Z5GKPTaA)LZxZctCP<HNU>BhDXIV3RCn6-A`dmv4wqWfwfyP@_^({< z)OEH0`&rYm;iy1TwMr<VFTbGbxU9kn`_bnBX{d#h&pyt{qghGUBYrNNjG{`jgMz5< zFH)1eOvv>r1=-X!=Dwlys#ci#6>Q>?;z^o!dn5G6;kbw!&2<coB;%w%x9gSIasHOy z^EA9@s7JOsy_uEFr`;m+%Bh8!sI=$ns!ES#bWYdxJ}cZ8JDS*qcBpGa$G-M_3g<+r zD`jYHX)QL`3Wny+q{R-TUXyegS9gY|p-Y&au9JfIi3`)R5?W6WNIpxXE|o{1F@ltp zghL-myAKPB(syOpbycLPibV{l<WG$ZTtawjHc*E2{j#&bYRbi&W4M&{->7df_Aiqp zCjC}VPeP7f;wMR|UwfD_$o4vB>*{1V!F>>QFsyYT1wRfrH>sdc_=u^zbdbReCagG1 zoqO|4^$*g*9Ni)y20mpXsbJI)6R&N!cA#hhMVfHYOhoJFEprlc694l$!bvt5H&Fj6 z76*jUi{J>{78PWcqcmI4Z4<Trx1HTO&=-C>=-zj0#S^G#(hxZrJxbYG3V1;42q!tf z5e<e+e94x&(s`-WJISZGQUc@{He1u=Thp>2mrLMnIDeO!0=<$EL9&E{@TW2%A4f^v zv;DCOVV}0_5^5R`UhK+KwNh{5oa{57E4L!1WD?{`KA}}K?KDn9RGr`CRujP*yaqJ& z9^r1}lLAZx)9m%}yupQzw9G8n<Sy_t_iiWw^Mo4K29{zd@9iSyiE1B(@zaLwwh89R zV7vXqN};$<6%Cseq6lHgIJb2ocko&PHjIrS^m<a`4C*8^pMA*MCQ~xWR!|O%KHhOP z<^;rypoeg7p5<$b0<LrT{zXRs9uY_MF!VO>2=~9BO67F$s=a!^jHW|*g+me5C69}< zK)IDSsWN7?ud9p)2Fmp%ZNPzhU7(ATv~!<bI5=8{Jxb(47IPWIqyFZJ0jAjdi4HRf z)Y0D_zL7L8NWy5YmBh7-p^?S5X_|@T!iLCcVw95GsODwZPYeSe|MIU8n4JXn?MBL0 zoxHUWVFR33P3IWm({Kg5RSojHxEUg$`$FW)X%n!K0SEoz4A8|#fLiIp>a{X>fkt{j z&w*?-ZD<hyMS^4<>V#s5H!)?ao@V^iu`DoWS6w8rU~FnryFzb{aB^-{LCl9sJBDOx zPDHyot!iEj;Y2Za3v95S=2k(!3P^;LjZm>8;i6tQA*+f$8s%{ndLW3&fm=-|s!mfM z9@vDJSc(N{1FX2e1PNnsY5whpfNFaql8M7G?o}Y8d5ly8zz7k$!Wz;(*Mf0k<EjkD zAs)IIvxJ>Q9jvBYC?SlDS?efZw0sy(li_l8%oAQ%LO2eRQ(Q0pGU0Sxt_=8?xZ<-` zxX$txA*N%VxUpULtO@4HL`pMi%O9&>hg}A{8Tm~+RlEHYLN^2Mp7sWX4CTY*$1$P^ z5h0UCn;`Anp?0V~t%r?n3U)$y!&fI8+9{4g=7|NdX@nOnZCK2AsKLk^Tu`fHR+9X% z!&Ho>D;GJ3Fq)jif+8WrT8GwHRg=Z4IMvWPTw@S7m%ub)jHnOWe_|i=)+NO;8;npV z!Z(aMCuCk9kH?!||4#v$hGLSpa9gOK2b~aUv=~hrYETHs+Cuk={5srE?R)AJ+9Pjf ztBPnh`%?W@H8la}&Tm&ZCV2G_cx}kZiR=?oNhZ~O`Kk-OOMpf7$>rOrCz96G_|s4; zj?y?%-@BaKd73h>fACwY2YI83`DNjikIU1Z`bf<JN1FIo8*0Tj6?Zn&jlvzxSU9iS zE(yIxY9WV&ie)-5g0`+Fcm9Za;B{2k^iT$Lv484BvkhgV_Up(V^ca8aEr*9wxdr7y zic8vqKvgiqFfUr0#Gh2v!VtP;m+vi-)0S~^(U|TmA6O<KOlfqy-TXiFd0{h{@ydT5 z4n9*&gzHab7W33Ac3VL62)DaKhl=XMO3Bcoaor7>DMo{u!$`wrm#``VDL;;oV?$PK z#)DZzVlA*H4UI>I$l81`>=^BzjvD}(Ubi=CQx|oTtPDeg9z%8aB%vMqrV$!kzNnK( z7feLu4>Li&c)y2$CRQcN5u<PY9KS5f1#s~d*{o9<uh)Y&@)zA*%nA%_TP5bZP<#}V zx|__RGekcKt!<&DV*cr!$5b28D}!qgUOlz?+GsRYpInrMwc|`pS+s6&9Fz49#xAt< z=pr4(A}cERsIgysOjR~RzpMsbl}IWemZ<&muYO0;<H2WN`Lc#s<sMFPg-KN@`UG!? zG?$Aucm#z6ADV{u%&E&l-$bVN^y5ArP3pbj3q|<jk(&Zk7a3?6kqi0NHxQvG%c!tV zTSe%MbI35A3#7)lfV>M*&|vhCA#1IOcwoK6Rn8zIS5q#bQ%<O97RLi34SxOl2qU+h z1N_Z@m&}0=$=D0}3a}H6UL$&eHWkLJkDd&9&e15sL|h9Aj9<Xubhm+(lCae{rWFGw zMN|suWu$d^<y^hfWND*4>?54)zS1BX+Sprgf$mN=pKZR&Fx%p3gk4|jrkfu_GYy7A ztCjZ+T?ICgA)G8CspKJs;=m@ovMVJ%2C#|w2K4*LcqU#cdT3ydDxOK$L|YYSeK?6V z)YQY>KEQ}I;-JF5XlfPzeX%kusbD-0!bngmYDJio`wImu6st_k?l$%pS!-B+%D91E z$~YL*7@q*b;0J4B0ka^s2s@(^rzRvit!}YdHo4&FDpxR1tbQNnNz{Nm6g%dE(#v_D zfrj6Pl!Yc?ZJl*>#JFZt8@@gX8%AgfPz)+-czCzE0-Hks$q5!v$2=JXs7T9mfqR6h z3=$V~9)zhWnSXv?&EHzUV`@G0Xy+3&O?tiLCwhpq<!I-geg9a*Jn6outiHqTIz+`$ z!qD(q)tlf&QC)E+h-`mMemIbttkuIcCk-p<hDz+TP&YiG)}Ygw26^d+Ct&@Jf8Ag9 z=JEK!4}S2we$OA`L4ZLy{W1i7H1*bp{uP=8s@K#06po8lW4NjpC98YWG1Q612tpb9 zdTmjQa~K+z5CLc`9Z5^TH*r3^Nq(V2jXrDbccLb3J_!TZx#xzPW?F&zI$caAF*RlF zWWaTmQDY|7fw!rHI=d*yUl=JFtgH`u8`G>z^~jhcOlj0mm~<p-*qAPjCN&5I<vnIt zk(v)XP8q9!2viYHOw!Q`0{mYYh7%h0p=_}*fsHy7Kyahc<~@`>rQ77vpH4-vq#=~b zxWFXZneiJ5;XT+;QWOOm$^2McGGQ+^(hy<j#gd%Ign}i4D?E)kuPZV+r(#}U6|m(< zTH`|^EX-*$TJsc~LhC{zRzivpBO~~^Bdg#fTovpWvDBR~k4{;_?og&LhDzZRNzpr^ z4Npv6<HtI7c)7bAK(6>l3v4*Iv1ZUkfi8P96XeIQK;KHBAzRHHg9G<^lME{%KAB#| zJaH<x`WaiWnddd>NUu>d{eB0sW=|Ocv0*B_{dynK7^DUx^Z{3+u{RY24X>e|5|07` zpn+3$AI0y$nILbaSi_G-_Ns$?VAZ(^EN>ZUq*h)un568J9^TOA$zB5#qdFtw0jab> ziRMhvJjn0+yBDd2PMM`)ELksgP-!k^Qjrcj>!lizO?EWW2N!x1aP%h)0aD#8#@14k zT9&Aq9uI!zr+?~afA*(;>Zg9kvxE<CpGX;KhebUx0S3D^)1syt)JcPph-qga)ji<p z62?X<0c`U!hKBcn-B{UbpCI}})+9&kkFqA&JXOr4rJ>E8Qlpy6w14g`ISoYlJlWnh zzf9NcDUU2^We1ePbC9zk%Kz|wT#(h1I0nYH*Ay~BsNlD#*Eaf#c9=Dh)#p2ML&B4s zd?@)0^g1Ad#{T00pEd%s0`D5LvP+-_vb2Iq3CKPKWlV;cwC>nhLQV9)!i&*(Y>kl& zjK&jjQc=}i<ib!=hBKFsX^ms-Ri7qQFp#SPQa~N5(AP4Txd&yupE_#Dbw(9>kXMT2 zsWd8KXiW8}bKI+`IvT5dq01FkJ=L!Qld_N1q41cKO;cCEg&d8H+{WuyiVA}@F-PD% zUE{0zSm@44ZlAl$#bsm2QFj(q5AT=N%_)m5<&ZOAw3X8WBIZe8nytp2hz~A;c2th` zl1%kC15LSxGk;mt*+=z&PoADy)4ONAefzEvLT6eVF*zGoHLMIfB+da_&Qa4@Pm=<u zXD-g$>H$W|n$1XMa>@JCp^mX}d_jlmz~o|K{?05jyTXcra*Kqoq^U7yA|`D$HEN!2 zFQjG^{#i&n79=|{GxXxcL72N>sK}YuB57CsYXBiEdz-1LU~}WDlt!7SW=|7e&mUVB zk4A>3OeFW@NyC1z4xXXvu!x+RBuS(MG)c!DL6a;$QA00Th5H-T-1xE`6qH9nLC#@F zwFsS;5NWy)Q^9K155Z`L@yW0=IDo{UyFLw>oHbfZA*#54K~w!?f4`a#PWp)J;09PG zEM@De88bQ6sw8!S!Cb~RF(t7E5|!12VNF;WOp^_~F_R|*9|B_NK`u?-SH-^e{jn&p zemBC2^ID>T1)UD<@SzY+hU{UtrO<60c%U)?48Rz<=A27|&>^r%ubD5g3~Uk#XVFOp zo`SUn=5FV84Dwc)pp@K#EAmAzG_IqsxbzZCim$mRsEf}NYDAMZH-fkXj@-cu;3sz$ zTmlZMu@8O{gjB}$2*qTB@E~xHOiT;L>@wzwP65NT2za9N(hQg<D7>g>a;#p*nUtKu zUK*yhTR4GTojK-77%G=BPgHj=f~seBg179iah}CK4xFMLnn3fd8789GvELLCGe~AV zbr?3zQruJ)53a?!lE1fm8Qjjm95qnR@r0$gwwb0CG+2mAc5iN#kfy|f17??CX%=M; z;^Z-}_lnU#qqQ7B8UXL!J^$|C^ZOo;$J@7W-~X$9ZD6FLn#c_*u`a>Qs6y3kC>34^ zNk-UaB;)!qF(Zxj(bC~uaB4&1J3_0;n^p@dEJ&XW%)CAcW`<~<SFiCHW^XOEZCx*y zb!3$)B_NgE$}h;^8>~qdIXL`r)pEiTieWP-(<VgeNNWP!q9cf*PFRN;)}Beur%hZG zjJ30$?X_>+-Ky0{o>0hI(kSW<8(u4T3nxB7IFTu*64}53`(h~3p_H=Npc4rWUZD+U zLSey?odIkSPSnt`Lu*IY!cV>H#oft>B6lZb@Csj4gcJ3;QM;<$;jsyI3%Um^gu*cl zY#Pv{GySu8#Ae{cr@8=aa_^SmEKjr#Y!WfOxfRL8p(gsO-dHhjx{A7@MHfip;bP_E z5&7_lE)#vJR~mRFcvz@hg!gctGz@mRao)X2e}WvqUTQHPhNA-(<UjfTn-b<pW;*({ zEuratEGfqqtY_Gdj|{kABb9KC1GUNM@9P3PJJ`Anm?sS}>5KhK;`EU<Qe&f9@VmHp zvKJe=EJL(uimGHURC?C4o~6M=l1EP1NYZo!5NZc{ntvG{%i_#}I%nD*h=B30Q`=F| zW~nM;GWeJnyAp@VO$>F)r-C&qI#-H21-qs8l9CVggoX_Cq_8EK;+lUp;;q4U8#eM$ zQgkjwYs#RbYBY^GE`)qt8qd=2{R4mOcm3W!{0IKfpLo#lwGM(B�*ZL9)AXem|Bm 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%0Drr;+R-HK>t_?I0K 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%0DZLQL~RlKpKX8Bf-i^eyE(rvc<f@g7Y%=?T2I! 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 diff --git a/_images/quick_tour/web_debug_toolbar.png b/_images/quick_tour/web_debug_toolbar.png deleted file mode 100644 index 465020380cbe9fabcece448ca2ceb91c62afe152..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59618 zcmeGFcT`i`_67{2h#*K&dPgh>NE4)mqN1R55$PQP=~6=vO+XN^(4>k|q=WR9P(?tA z^b#QS4xtAKB=6>&>pAzHgTFDpF}`=a|HLtrxU=^vbImp9GoQKG^QF3~0y!xYDFFci z`NIeIGzbXJY7r0+){&eAu7LVp{vaSYPirkFr~Xh*jzitq(bC$^f`H(`%UEq<oyYBT zsrniu=lG~jai@#j@uDSR%}^v}zI2XC(LeZunF1ZHL9I?hNMYdhD!SVP;fA_rn0JXe zd3cx28bdmgXnyXLqf$^wAV^oT%bctWJmovV2fNO$&QAF!1m7;ukbDaAdH?cZyRrtQ z`k4;@^P2vkq{|&!FT+U*)#Wj;&RPV)n{BcDt0h>sLs&RZJl7O~|GhiO9kfo)95SZ~ z3ftSM=?HE=3-bD;OXPV`iln55>f#yyFs0`;=WP|A=bl%4J<=kNx%2(Bzp_Q?i$#L# z4?Tp*Bo+mu-Ufdv@b9F*Z9r5)&lU9J#onnFYG-HXOIp|D>{1U5leb~5%B&IXmf6v! zy8IfKFkAOMhgT$U^UjBk?d^2YU8W?=x8xXD_}Uo@^;NVSKA(AfNrwMHWLU5c`IM4R zVV_YT$|5XidS;i9<qf-ma03AWkwFFIdW$5LaEq>!jI$k_PSH1AnyFEM<Ynx%rl~`j zl#Jf>Z&4)g+H~U@$rxJ^9v}S^9wmwRnUJ&;_x!wkpRwfJ&D4eJyM8`rS`?|kVPDMd z&O)QZZys{W+XqiQJ7;AchRixg_{l;v!7}QZh`{%d=D02*+f(MWPg~A*`jp&Dy)I-I zLl{5L&N1!p<QXU~A$DFX-mz@7QbYix=n!o`Z9#m$bAS<ao#z$fPQ4KUnQ{fi(6sXI z%=LW()F$aiGmFvZG{L82CnytcpV#O4M)ckvDf3f=0Magh`V=$C9m$DPw$+w>m+we& z`okI2&tQYYi0_&EL3<vtT@OAGFxMOIWy*M{K$gj-JHg!|Q6;+e!h6DWy*=;;8@P2$ z{wSg2Q|U#*Fl>v78ArF-D`Mg=T_GwYdpLP|Qg62Js!jI=6PqhNg0q8Fo6MW|?ut$F zhY_n~JetuG-fwMUPY}K%z7W!VdUiO|FOAiKR2MV}t>T)Yte!q^z^pSJB}mOa$~-rB zrW`3u6YYelh?DK&GClH@ajt)x`SxA%{iUI#4d&7Vp>QPFw&jKILUi2F%@slS3!osw zuTkbI{x4IS5=%r^g3m-hX`;5i`l^eLZ#Ir-dR@WZZrKiFFN+ft)0crgt-nW9H%#<4 zx=}#PG3s?%>Z6A3fLftwM$U;LWs?!aNHqb+Fv3E=jXA^>F3+G1UEEY7oX|QOyNGnP zyG#%zP2`VVOX^y<bpzc`ki0Mv_Tt6Ol&7GxXKn}Jn3isnEu6Y+La|js+|@u>e48NQ zJm;Mo4^9hDgj@NueDkDBAf^k_P^ZueA~zu$qHqsjdQQM{T4h39oRHr??*rlJX|$=~ zb^yHzRUKh7N#JWLrn?GdRK6`|O75;)&~70+cf0BJvn%Hw-s!n;ic@~>lG1DEr+i<C zhF|t^!Z_Pr3xBi7pstSC<~aIhJ3}3wuBpk|e_y5h<!9cdppcIx3$7xpKNKQ<UUa=$ zbFM%h{V8&Rahu1BY*pU)gB(KxjnG+3e_iv!1a`WYSIw;xsPz3~O=)#*X+@VepnV9J zzn(3Q7Qc`^tvt#!U@6EJ>ay<Ra|(JI88|o*xhHXWc07o3%J`f}AVp*Ngeu9UD;Imt zm6BuzlQyw6J!<mY8{57xe&OZ4v)!*2PQyB{m|b(?cOr7)EeY^Q9D2BNmEz5VD|~Nh z+uzYVG<!$-AT#4f#!<%OjO7fO9^x;Yx@mT56j!+35zUx66M3@lU)h)3XY|y$bHDLk zqv0iufILA3)7U157j!RdNqtG1X`X~Lw!XWl)Shu8%kE>}<F3bS>f_gWc$j!<xK$s` z@bYVnW_YM?yfurSQpjcMf4iiRB2W8RTLZ13_86ss{P|4eF;hgGGVh0ijQ*ak9=2|o z>)o+-F?VCC6v<+FVwqwKdFwT`)I}fdK1xkD$S_Fv(b-Sj^bZdV&k0W>)wc*x%<K?~ z<&VAeq$W4TCc`FbiL~E0H~vXl-kUz<{?mO`Hdk$G`?_*>dW32&j74{)3#6m6(z4Mx z)crsD<obmBJNqd=SLRXLe6|+1X|er2@VQSsz57Q4L)I%Qc~NuPX{u?_>0a?MCz)xF z>A2`TcChcL_m7Rl8!D-m?=6Go_<pGADHjkF+$gxEr=mw$?qsjD$~{tAR%x9!$i`44 zGj1+r<ukk|H;r2SAQ>mwE$QOszF4++esO8>?Bd*_!+>-i=tJ92^F@oLf<aKuV3FD& zx@Ug5Xizp2NBlTwvH82DgITIM1=9k<8Rjr@ccwDt^UR5iUm59`MHys7J~C7@Wil3s z+1z3h84#loOSLkv@`2xLZ0Wz!{Pa`%{dedr%dB%*N-9apX-U?JFA`|q_rI4G%zp2k zG@qoMge>FGtI~U_YgfKde2*{XhVTtuz9QXptu8H}yaKHhY7*+vYb4h+)fT>F>0xx} z^#*m(LxOfqcH#Dkc1EfqsR>d}KUyNFVIz{mmWZ{AddF-_vEjm@!q&C&`b_CIXb(1v z@W-W}rs;B}&AbY{3aQhgZ6H<G?C05;ss*aX$%e@<x^}vb_`mXV^FQG?EL<vlRLE-} zP<>(4XN<0f6^vO}TQQpO`*tKiX&Zeb+LsN^^<HI4Wkfn>u=nS?)#~0-M8sn3RC#kA z0@0APYPfooV9_%5Ww$tWUuW;>!3x@Q(RP`4TY3pI4j*%bBCR3cWxv6`!=!KXaqycc zHGI0=+_2qH)6mF~{h|6!cF?)T^hVpj+PkiD;+M)V1-&!822b<hk6~h>uDQDHlwgq{ zn17XpJdFj)e|RVOVKB!>?u++A?iEJ(Fj&yVvhN^hreZ#G$39M#N8E=;KpEts-!qm9 z%o*l8uH+73oaUUSss=n}_pCR{H&E1v)C1RCxm1;t(>!iH1ieh_OIB8lQX79KC34GT zDI~|YH#sX-wN`q}?qFpx-s&0rTdI>;)~53A_h#<knBW*+?zG`ID>l38HV<r`EOE3& zm%iBw?3^l`-`$e(wDpAdNc9e6NvolijpN7DCQ}~05o$nBJ5Itn&UcNb?#uArv~?VK z;C|O#jzWU#>U_d&mDg9r<MZM{ph{slPmxFw2q_Jb!+sFdtWpRL%Zf-O>zfqHR<Yy9 zJ{*0#@I*&<&s6I$zq#~@6`5t_kCNn4pRUr64Iho?rd%Xk^yeAB>q`|`LE(ofWUq;G z$n@x$_-^P9RbGGg=!aRyRDLUr9zj>c=U02h^r6yAhxU(e$I}A+a(SQd(8js*?da6_ zGD2U$@_nnDH-B`(;+#4QV-RuLF%Y9hU8h;A+BC5vsV_I}EigRuPY_zv+GJWtqv`rA z%YvnmkLC5tO@p@ztqKM7aqi9E$>Vuhcq<$;>}VWU#%U^YJWDs``jccG+lQR<dMdx9 zD`wkx_G1c03kEAoD*7D<$Bdvyy%g9e5Gcr9R4YkKdxdk2XLQFEe7F_?tHNs3DtN2y zrwVuzdDq&0wC(Dz=^I$<9j?r!D4-tPL8Vo|ru}gNb6(2_Ddew0HiITU>`k!4vJSm4 z>I>-u&4r=M(FrU$l8Ul=17RXv)+}}%&z2liZPuhj_jPO|6gs<+c76!&(Fu>)bCJ|} zsv4?s$t)62Tx}Ly#}@;H7p=VXtt!T4lRS3ks=4P!;GwB7*Gub7!x1v{YKEJ2u7_VR zv*y|cMIwf7(2=3JKKE^KHZr;bR4HcUQavy_IndoBk+U`9hFZ3A*h5x57oM5x*S}CH z>DV>~?Y&iyhoL}sZPgBgjmLQF#C#y#giS$TLU|~8*%qa8v7xQ9Of@OBYTJA0GU+H! zA6R@ZX6ofa`#kh*c3Czpd^@dQrV`>;CtD1gj?RH>*MIXCl2Sj&UP^l+@WYsGKVnB4 zVKQZc<ekiWGsrvstbQ0XuwlQf-uLqpSOOJ-jQ9O{puW|;Gu^6oE-jTDexQ6%w;0hH zA6Jxa%>HWT)vKA37j}z}2!hB}ln5twj0m1RTwnQlis1f3cl29Q&RPM*3wvrh?y~Q~ zg$cZM30nA0bDU3oRMBX8T8MV{?I-XJvJVs#<|_OjMTot1Z}8MLQpvn}Ro6}A-*>u! ze)8M5^?^5U1Zpo0*AgUm#gFY@xf?u>VSS6a@@)CzwLtcnG{Yb}pRk3e?LeGx?)d{< z7XkvhtH*y&J=D0ePC#%f)ml@>RYyfx(%jLW-}I@YnFYUx{d3@M0s<)yN#LWsg{vut zhrOMHi=>A%=O1@S0-ujB3vhD$af_?1G^dV=I)|L2vjxX3ei42_P8m`T4h|{jr<Rf$ z_vHWcIPgDd&S$Q!&m{!}z+f;xSeW0@*-Ai2LPA17@TS1cn|#0>d@i02uBIM*4lbAf zY~)uv_bgn@ovoj{T01&$9Jgy~=IG`s&B=M((O-Z59H)hc_1`@?xcp~Yzyt-3zY!4P z7ZmubZQxO<<ExVD)*cpiI`^#YEgW2cK4gSMZ{C#p<AHyD^>>&5^{DROk4oGU{qHCL z>zn^PDJ5_`ga4Y*pW^!CDj+WzQYnGIWG_Ris_bV2EC-AAJvB|>=jr3M0ak7t_~-hc zKaW3a!=D&SR1*-~CU|)7j;6<{l`-F+22Xs6*QrTZPnkZr&lf95$ftaVgUX2Wrs=|v zxSq`|jqB$60cWgkTvy~XvyS)~cb8WsedxoP?CSziq>5#49~qswlgUYS*Po+^PoU>^ zPVnYM&*AaXnob$aXuWsp)(SP7R9Z^oSiQI3{P>mxdLtV1LmK?G#%)=zF@oUK=`$o$ z9Jl@d^}*zG!z+YCtxECDn1_VFyUG7HiLhQj*_q$A;@|N6RAa~U%X}wya@?)`sm5^X zfPeM>YecWFbLcz_?s@gw8#r{FC{CQgA1z!YI>Y-?J@LXxQ~cwGGrV2DAN}o*{w7y1 zC<^~}{{AMd5+?}nKZAcjLzRE!uC@HHx%}%+s(f+c-%IA@>A=`~*MI!}hCtf+--_in z$D`ZDZ%Hy4e>=O|#ZxT56${A~QWC9;=^~f^HRfNBkZ2_n{ziBF2?Fk&YE<NmvHa}~ zz@oeSRxBL&MaM7tzZDO^(@)k4{7(OW%e*&a1jW)Dd0g^YF=r=JlRa`BdiE(&{u&bo zgdTNio=b8ZU)xHwEj*_b&rhyzU*7+1cVp(AT1Ybm=*A6$s^?FAv)pOMRK+KQsiH5n z+W#z(*&Q;UOfZjn=&oDqZZE!C*4xwtLM3~B9{KGIU{ndN#TN-*v$_vmY9ZVG<YQmb zN;erm%tit`$b*fn?H+EyDHYf}XRd?0*Op%icReGPyNvR95Gvu2hTYCaTvBu#1dn@K z4Ozq+dWn%A`AkQOh18?Ry`O=|PgW<udY7DjN1>%xpjEY)mDChODZ@}$H5LB6OJe@j zSo0ZZtKcjgcL;BWV%C_)_r8jS7=p)c*?nohw#vrlyWRa9>5DGMVFoIpwET7JP3N|y zDi+sjQR5WWQ<x~w8iOS~Rl1__>;c^vbURbvg_`fu<A>h)WLg77#_WZ)Yc=c9xV>n5 zTujs%UT(#a-?;XGjpHF6)V>0nwLG5@PTN<;sYN2=Z|Gi>*?bdyg)f2@<Tdj~p(&7v ztcevo+CAimix!IU#2}F4uzlJizoVVO(EY7>O6iaqlg!HN{IPWLM9jMv^UqUnf_~#M zKhraK7GDIHI*ip6BmFQ}L)jwe_((hB_>?G~NXqHfd$|qSSB^;<heFc;ftzkjwaOvv z7tU^Y@;dr1>&u;&N;GN?j16V?6Su2ftxz#6gHY$6zuNOVFW5(_{IK{U+I6L*Eu<7K zQ|q36#0*=1ArLIP|4w!hDYcDpflJfxj@TB>5LnH2#F};`OUPk-uQFwLkdtYBY^(F! zYRY|*#}vw;V?DER`8ShdxGreX*zu4ng$BFph;yHa@`i-LncjoI4yddQ_{Kgz89o2` z&UgX#5iGf*hg{XsE~0rr-%+}3mACtL@uuQu1lMm`PDp5oA>xfUbk_xKKafanAHDPD z;)53Ru*QzWTeeO4x}_Qv)<KmI8ACx@qI+dSmwwX>!{y@vUX3@nNFg!vS_s6veZTl^ zg=?aT#ZShkzgwyyK>#|DPfNK9tm!Z+W}Ny>+a9d|IxO0wIXomd!`u6mljZDhZhS^X zl`k@3_bu%VFS7;$`kQ@oI~72SaQm4jfw6DiExrB?G<#)myZGjv9?V*;z~Kb3EQuJ> z$HikQC%fqtqi~aDl099;uw{~<RabKHppo~Bg358Pz<Q_`n-Q)w?dZm+FM4b;gxP@v zJnE$2v5+2GV?Jh+SJ328yGjSxmgwT;!rG8MUpc6e$K;E1s}6JD-%pRoV)v#eLCAeo zZyzT=u`$=);`vnXkRS@l>vh<jBKAQ)Nyji3H{20A^huu93wGRI+iJDfMk{@7=wZ!Z zJ%8PziX&<5$`>UJ%otN{yo`-IFy)+c8!zz#v~Ds~_Rthl=XJ1{ji`-U!>m>s4?%E8 z%`3yDk0}*ECjw{X`rEeQM#lRc+Is!nTt{HQB3ZJx0u4=O_|{F5J3f=%XrUg)<OBu} z0Cp~+tmu9OUHL%1u5h|<=Bw%6G_0$68e9frXNw*KvwOXg81G*DE(~WG0i%*33v%o> zV}6*`$Tq25c2xCz>N!?@sjj6!KQJ0Di}P7tDTO<%Ob3$jFH}I*s^|4EE2V1Y7^8?9 z_<Rc3NDGpuU9>jP@9VMNNUWco=64VrZND~JT|g#KC%A~ZVs!{?cV?F=W8A@@{s!tx zR~8u2t-wBZfWl!>LgmmCjnzc#MUuzm)5dWo7GpJT1(ZG$gyr;*$|17|t@2>)Wj;qw zrB&3i)b%$4eLHL=iFu8Wmb7i#=mq@1=W{`1XDcKYGv4WK+&$EUuGMXI1z=G150IE@ zYC-A!nRf+X=vK<Z9c@FmC*BM=Gz2#|Vj9Z&*2W7xjHwp89&z*p9Cc+!du;5H5@T}_ zwW@e}MYOnDD4W+a3~bz-VO!#?u!>8ZFt*EM+9}Hm&4zRvG}Hz;FrPbVF2$FC4MRTC z|5lq&Ahj)`rT?b<*iv2*v}QNZy*yYmPw#CG!r^D=B13-Nc8^lQv4_fK)vlXhMOA%{ zi(8`L9#6S>-7akMart+x%2iFDF!~jN`t6>8HiY*Z8NVoSeoL*-HRt*E!~LyVQ{D6Q zW<Pt7j=g9PdbRQ!+RNFpN7j{TQTNZ^#Lh#o**o<p-y+ec`=j$RVm}4PGc~|yh4X?3 zs8l_epRa9eIBof=ceHd=`Qm6n+^Wr(b0=Q`5gFYT#$*U~zktDvTvEXcZHShLa$FrL zXXQto7^-;OKXZnca465}^Z7a*7Thev@x#wWv-Y=F%WrL%d7bA@H0tHkdD(_(r1UFx zm)iIU#(hyuDY-Q!aZ%v2np@Sy=;;cC1GC3yJ^e~i{qD#>BQbk&U&UkX%8b$3c;nPQ zg*w|A7<L&ZsTqmF0R~t!3l4{1w+In!>z~%5(mnEpJ~M6~w5$2u6qym<>3d8Z3$ARd z{j#)+6k4vs?HJ?SoJo3f79pt7ou093$`j`>)Ns0&Q)kh4p!Hr`8eoDWO5NyNh*x=y zo=2@>1eV;P+LT2_d<ASYGR1Su$US*`6)W=&@eo5zwpn4VvwYmN<P~G?h}{(86mt|L z8s4&?vjanw^{N(FrFv$;o@O9F$t``+J8BbK@gDP}k^2mWVa5pCMiEwZpRUcib>F9V z!$bsVzSD(}^wz@k9qY@Tz#IGt<GXHYC;*3im6?jJZ_^)Cz*Q`G{J1q(mg=>XvpWXb zaEQZ-x*?~l>Eq|OIR70C-1cway()Nlt*XXfVsr49f5`C5Yv9ntO-XAi(OfN$j<o!q zaKW-GnK3sr_ilN9_s^Q8yAGe@?va*S{;;uQmdFJuH}zyH*&?3MyEg;Q(gu?g=S=Fo zTCQC+9R>Q@FWTSwwZByF?#}wQlUqIW$6lc}mfl+H@AFkS&#k%gXvgoAzQ(y$5y8Mj zY8{t5jf?6wJJk75+nXU!wSM8pP2AbZJ(WANMg1uplMRHFKAv*O>?QuN=Tk4acI{cm z25nwetf!*uxO}#fkjhJCHSew%_-wSA0v3@1hN*=ibc7eA4zOq#QYMr+B99%pQwV;s z^#0bW3s@b2bt$d^U1xFYdsO~oI+^`>!>LPM)?<037I$e2g9o9z<!-W}-fPudE5KaJ zVQ!+LtFYc{v#5H~+7SqIKdW(i4Ix+E+^wR;m`WsW));%$XXY|HV`%|SDLK!ky;{(F zcLkf~!*!zQLoNV*T(j=l=K6t6#zUN*@6FYvHIdKEVA^mIHYGPxpYNqlyf9&4{u@Sh z9wtX0W=qZ3duO9!V``0{m@(8Yh4<)u76>fqlHg3=QWeEje5qBKP01jYx65<h4ZvoU z$*>`8aWh4p;aPru^7t<-S}T`jBC-}~(`c#TgIya(fB~3qnB%6b$2HMI1&g89ixpM4 zEFrXe;sKg1O@bz#BF{Th29inoW~syeL=vOn?1cn6r2sen3DsF|n_}m~jW#hO9a#XA zGjU~EGv;ThU%N^&M5PpvX~4lwcRu4rD{V^lX6zIrys{><`WU*BOA#l2^=qZoKA*oV zT^TA}nSp-K7ZjKrWvECs(5G--ID{{WF5WQ$W9^lhEVkiTyvQibZT>PUFgEM`I`c_T z<1rtH&f*0>0P@v<Nw<wiP)AZXMyn<Q$<7)XIFf=j0{u-fsVgrQ_o%jgcZaPeHWWg| zLp+3_i?pZ*pW{y3u2^wWIy;UGen4tSO_wU2l`gtGUfshiuGu+Ko@-HhcD1lxx*xVE zacQG4`*M`{M_X+^m%%D{3`i?Cv(g6j<t1x2i%YL3LZYhA<mz~&@IvfOy2cI;X~aq1 zU`YMgu2e7O=IQlsJ<;1}TDphLOBE2B<8*Z-=)p<MPCfTYaEBP;&`ZNqkuJh3r?)y{ zd2N>;2m0qwXaR_&B7NGCl*o%X?q;fKT>X*Cwo3<gn)RO3xuPs>DS>IvxC0x~0WWyw zoq+bs(NaArLC?l$?zNbQx5?gUvC$*7lO*C5(zL0W&YPZ(itQ_XbRycwx@)3$hWA~y zdZP0wX`|OF=d`*cm-E-|uXf!Z#iFw^KTMtBGltfcL<{(BM3iqO+>8PSr*StRtCszb zk!4-Y^}=-QCx5{~4zeK~i!~+JW(%`DRLPwWH{)TW(hyb2#f-1MZhmzDqN}}iG;b?~ znieAWYORfN2Lhphof23KEX6dy%tn@bOY}Vs#xP@YGHlf#vTO<IzYl){<FB51tIn4e z)92`xF0umHmWTEjW>)W&l1Tu*tRbb=yxp9{0R(;RI{>9e9aG5LSX`8KYFw@7ZC5dX zi(&BtfPkzf_~t8&?>iOIb7=>C*>`sYx19hhpgH*<46_Kyd}Xd~pIx-n6)xyFURP|> zpWBr+g1$4(Jzcc6Npg(Zk3(G>%$l9@VxC?&uO@gs*haTlb@<!3!sL5z!L+>=t|r;T zW?7NAHX)?fa)BuT{ZJKoYeOVtbT>$}jeXs`^~>H1TdAVaS(HyadSt+AGW#>`r9-%v zT&WDXpxaGx`VPAK2LN&_i=LE5d8+9EA+dc@mC&ps*DOjpGcCrG*%eE{;?I5}+!nkG z5X%CB=GUDXP7w!tbi4By_otAi*VtMZ2)=Q?<H-{g+oyi*mQK!^35ip_N>L2is>+TE zEV8LI2bYD^Dl%eqN7z?pU0X%Q0YM`WmsUB{60>=HU@p_7d_`H3#xS6=z0*V{5Dd&= zAnpk~=A7(7cl6!!cY!E4c|`Px`SIMt;+~?p6W0=!55ynF-&cCoWLbB|z{sz)D)LSj zHQ~)9{lXSm7R6rxXiv@xu_=D*oG$G(?%Jzj3ZTqSA6R?acp39sKx*T=6_tRYmo|^e z!70_5bA@mvIn-EVvf+NarISJIhbEY<FBY9mj}%z@jo<Fn>#gOnW*GpGzui<31;owu zOfuBJc-sHMaq2bxCbRTbx0hI%k3-k&WM{>&RTm?Gxp*=JEMZ%06er08R=F_^#hmg_ z6k1DB7A&e?Lmqipu2kq>j91dHdTxrwe4qpdZ;w&UnNNertiW*CRZ!N{O(UV_!@!n4 z8++9r0)!<^_vsC3rh1;b6#-_3vu@3;h^)WVa>;MafjZxn+vkL_-S)q|^K^;ZD^u!w z&8DNQNNr73sxJ*UWo;BDho7P{)nn>q0LBwAdZ98cpxt)|w>JVnOzUzT;#r%MJ2}%u zfw2P-0#I=i8UaVu6kPlFqfT#ToHb4Aw6_ZKBD{PlD&}iwQ`?p`5SAA#QN#}bq56Qm z_mFAmRYpq5M1Xe4d-CGi7*-Num4a@jl&y0Ez)3|XyU%)Kz^deG=+SCRl*SzBSSyoq zT`XT`ubzmt7HFyR5AT}yHQp6)?wF4u>j;dcX-}(Ud|`DkzNGKB`7TYFl#dN^xH0hF zDs|Yt)~q%BfFjh+7oaNi`covw{3IJ6pfHuNqgA2$!@V|H2RnA#$EPneb}(oepR^73 zuF@6L=(x>_Lp9=?mLU9J;dxv**e9JD9=G#uosO9UQO?}OOM$*RrIsoQw`>PyPGP(l zURW8&Q)8LhDz>^nlm#FFRyNaW8+7|!>pTXlS_OKyOy9+1woS<`PrJB!8H16&;34bm z6fdzzO!7@NZg}6rMJ|i+r7olsu|45QZtP5!qDk)EPce{2qsW}2qFJueGPRDBb563{ zxFzhur)brKL5%HSA*+P`@$yB*ihqdN$mS<<Z#u_yzC8bK@W4AY842gkp~>q~T;3*5 zFN=;Lr5vjygm^>RDyNz!hOs7^jKAuGyZD+;jz!6v6C-UxqR|o!!yjvPs({_u4O#>t ziR&TgS|s__Je+;oWnec3l4DH7drZeM4ndX-xq`5*xc&Jw_9&^%ZvjVb>=e@5Ki69Y z{Dkbvy5%ERr=0i=YsyMgc5b}cZSD`<=^twMXIGe%_^^D=9(uUh*?fnXHO8RSdA8#? zc%RvgmN|Gf1jO@9h&GVMvAq!;e)`U7b+qJWRLj{D<6;pY<>KW51!D5hC5oU_z8&^F z;;2x7<pDpdQa3h)xzXHdcp4O|?@)d9dkUx$O8_ak<;GnWvvEVe;>Ix!jKp*v30dHp z19JhMV4y(1l79t=fF}W-Zh6cAQ_W3~!~1!vr}$a-M=HXStiiWem71K|ShW%NiZwdT zPG*SC9*^nS8sLN0lVJNv()wp1b;lfoOwz|nucL#VNhIzF*$j{iUBv)xv4icyN`-Tn zd}&lv^zCrDIYop6_L7ulr&=Vll~psHzTE|f`kjGdfJFj}MsEAkq<)h802oQ>!&c+N z)}L$Fm_($HwtG#F1AC?s60MLP+mqlYLBP`hZZa(mwyZIUjyp<^-TWNA)T;g2mLH!E zIHqe^JSGAry^$EBUVa3uwN`8D#X6&~<#~JNppd2gtCPoUVHhPB41oA|&(nDsb5Aq4 zhu&8dyoes2@dbE~P}ze|vP;rsLTS@Z0MWN<y1O!LUV-*|*>-{bEnAz!!cG9C4~Nfg zX`0F=bDu)*ZcOI45Kqw^**8dyHPV-bPSu606$t+7<rqJ6E0t-Vi2&k|5Pfb4h|MTX z%AV=s3D$4jhMr+>JN6;=`G|Ekx$g&ei$RCS(%PK1jvJE`3M@|ddi*rljMyp7_BUrA z9<`d|zKTJGwyW}LN%bIyZIIE`t-a}J$JXgJNaU31@-aD*R}++8TNLGp^QO(;MnN&s zGRl5{Ten`B2I!-OiXzPVyR^d$+IkEcfvG38T2fT_!q=Zp`c?i5%rvECUuJJ2h*>&! z{zsY7aX?}ixi3B2xYaF{>Jnsh%#=(!wH^StrpRZO_wpj(uQ|{-fwPQ5swc6T0WV2{ zUy7tYK*W$`q>!!lH~-}7ajUei^Ow1CW?|(rG~3{{O8s@@Vx``i%>>bgO-`Oro3?aX z24I-f+@fJ<xp3|BjK_}cRq&iP?6LDRut$Xy`L5bV(zl1Qw*3%8j_M#?(_v_FXW48? zAAkbNC9ifyBQ(JPHWx|E*D3j!Q@2|QK-$ziw>tyJ@wO=2<9U{%wJ$cU4F!w0!cDH8 zRq7Xx3SoP!_+i*J-|ysr;pv&Ir`*L=G<~OtS$-Nh=hldWw%vLja=m!0Dq-=g7JHUb zdRu+^t>)3{F{!aWj)qo3wyID_92VV-#h_#zFdxXBax#F(1wsLUIfWsQ>Bwej^eD9q zx*Gn1=L5szi}62m13w5MrsDgqej7gy_NrP&<eBY73ZttgCqvmC1a4_z%;8_NGSkgU zmx674t{)T=58-|w4^{SNxMYV*+u~)vj_^z{Rnm-f@?FDmyFDxeSng1OqLKWbEa9>V zV(pRhVe0@af_|-(o&lRff9?}gfLfFDV#I9S>%vv_>Cl=~z`H&Cj>GVDQtz+s;uHG$ z^~ZSt$HT9VWob#&@!`v2Al%_r^BV;=i4UP^j#1OEAcTNbvaqj>xjJJuS-e$Q;c_y8 zB*+=SeNGFDMd4%)fsk`Hn4;uBdtnmoheE%#P4%36zrI@ulV0?^o}xNUG-bn>H}d>b zZ`Kynb+Lyktyd^lyUrhnfE^*q$By}&W6)F%+i`exsw>)W`%{3ahL6r629Wpo+YvZ1 ztE)Qb!y-(49N_^Ns&qXl&vBH!GB$c7bv?ri2=|(kkcV@{?yDmXh^|o6Hl(%KFq$2^ z9%?#X=lO8#9(+$KfqWx;5|MT^oEC|A;!vExbng|y^lQjoWho$#iurQAIRT$3>a>O3 zi*lbTp*sbu&p+2XHH0$!JTE!;I2C=dwjfT0jNZ_-yTRY7q0s)?Nye<<!5R6B`7IF( zI1CJjfEIfV=vt{<Us+(izf%|U9Kcc`$b$kTX_6z<)8lB_80lN(d0xZspf@d~jm`Up z0pw`s(m3rS@CLLJb|+01yAfR}m%Lhul(8%C*P1LZ^0l|`^#FfsdO>CjN&5EnI2Ex< z^%-`J4F?cVGTX)n=z&(U(G7<L<bDcraeVSPd-Gz+^U~yYuNumJWY06rclR8?^jKmz z(Y8igi6a$41`<o3KQ+CeH`2j)<EnD4@`76<=tFIE^PE=AKVOt9cqa3t$iu<Fb2fI; z7v+r%c6Zur=L!W51710%l5Nt!DgnL0l54h7*TuuY>)+oCXBWAR3?8Gm7SID{qYa9; zD4%)IDlC(sBNIARO$U##@hn#71Jh%-)o^9Is>wCjseOIv!K*iPia&T`3-v1tk8q3| zDA^sy0{~q(5T|WWe7-a9IEMXA<o}fD8f$(Fq`*j8P`V`o^U0@`Y{PaSf6>S%5_h-W zi{$WEE{%j8Gt_o=*Bh{SA+mcxvJaroM-h)$<m!IHfU_|>4i1pie0_tjJVrDyAo^<t za(PmPxIXgcuk7(e5nz-i{Bq9fO(TwIFjH%_<b1M=4Wi}e)Tj&GK2)ciT)tRn4RVtr zMecK|EcN(iT%{{CYFk>5&2MjVb+$~B^_XKb-C6241wyz*yTqT~hH2caEzgDc2ahuZ zFO>MJGgxnA_O%jR!?H##9Y!k6A5F4jP4|GXH2Dk0$vz|nHce`Gg0lgrv!_J4WTo%C zT8Uq1gJsYAPPn=yQ`=CpZyOyc?XHyo0kO~Bog7RacE<<I9wZ|L?Dm4CDVID_#kWzH zD)It9Xt}kuec;!Z#SFvs`dtj(9^^4Axmi8nm03BCKfkYC-o@<0A$}7=yI6H1s{%^M zUNiLw5Y!h|&n1pKWUXu+p^>ub=6S-Ah$Xg7nU0_+wt7tA8aBZd4cJbNJg=|q34Y$_ zZj5L5$NL35-xy2bIyf){4UXK|IJMjV)@`h&Jr&mPY_z&1=I(J!-K^E3_b{^Ahez&| zBg7}dt5>&8dcgUb^pX*tt)buBERv3sjk~3)QyLGBT>{&bTnms@X**7iRIsbFp^_7X z%)bg`Dj9690-0V4+y*<Y+h}C@*bGCW!F=|mKSWn+<)_9(oN`KrORaDkOv;w(8_6#_ z;jP*RbiCsQUjW)vC9BiH-aum+fyBC30aQs7wVG77UxSa76?n{Ta93D;s#L}DM`FJ{ z5_d@kcZFY=J`Gd~Z0uklrF(@1;PfW#9liCv+pCNRTxyVw;1g#ia*jkR(e+T?q~$b_ zmsSG>M~r!qV8Wc-6i#%<<QyD2!vx>l?|iuY956O7j&0{^5wBK03Cg1lBq{58BIidC zpdA2&k52?2QaE{$NdY@;)uKBUAQ;zqVVk_Bu%lgDfrtS}-v%0>MqeCfl9t|IP4`Mw z8UideCTagfXmILuuMUt7i{xrcS8)v3JA5k)mlD>bG-d~XI8K5z17@qu4hAGSn}JNw z(6~F0Ckp{2==2?Ra<0X{VVj;RUl}Li9Neop(ZO4E9$+IrOV{j~92|#u-t&ri{iLBR z&JU`9`~+h4n1BXYMo{0t$b*wa1q@Fc7@qI^*EcFI0p`)tqR9a7Mi{*bV5nyTN3_iO z2Guu@G4^Uj1ib(SkQ^ctw*1bZvwX4!QYEAUyuhM_K$J})S-vq$=6jl~>?nW&2&1>N zk{n1~=DWy`vsA|!v|4*@AZ8dpoD-wW-#R(UB2hL5IFRiWW(CnmA|tQG%wxzQb_3YF z6ORf3(8CI40Tg-_q-iDx&O1M|d2%a8w7{6OTSX+kEnXM2<1WUUN5KtWg7fSu$J~!( zf46K!7lE$xo_=JR+onDaE{8nlQ{GXo0O=`PWXW5D55Gz0DuaN>%91V;Z`)j~TKUr1 z1T1hU+vag3q9A+lh%%p@C-dZNZC0hfiG>$D`ja;;$tWP7N#Ljh32^R$6<p?2T?}Lh zUr4yjy~6xBIkckk*a7y4k*~{KSawbWpk&m?n!DR=U$^nqbnAy0r7#e)WhpEdpA=+s z+~!aK&eDC#3OO;*1c-p^8n=rzX3CgFPK<_uHeX-n&}o14SngycJ3~Ul&7s5XJVKuM zyB@w>pvs^5oO9_U1abUKIB?XEMq>4>%I|uZAtBLn?(6$6Ht2twx(@_;;mPhnCt{T2 z9-M(pn1qeZ$pQk-jBo;}!TYMUcTOUn{^&{q&@+}>w@&0u055g>4e&i@_SlD$xaMOo z7Qh0WDU3>FI?)6I^ZM`r`2J0=!_VLL5C!Dt6;#N7w@B(4{wA5<ti_)Ft_Qpt;MD+7 zG`t$%)c~&se>fVvQ@~pTJT^GSM0lrwcM5nlz&nLMV+Xu7z*_^nHNaZ~yfpxJ0bUL8 zYJgXRKX$=CB89;nS84(R`sm|#0i4KM;)!KEv5e0z{K5X?^9%Si6F$v!j3n?*0q+#> zYJhhNf1VY<TLZi`z*_^nHNaZ~U>D%k0IvpkH8|b{e;jhdV*@-kz+(fvQ@~q;{~w$J zj*@@?hjZf8fBWk-y(?ps3BXHw#n#j8_q3U>Lj!NEKX|CAgC%i%!G9qrJgmn54b}BK z9;cWqVlL9o2>F|g|70M?rc)V_282u9xf|erAx!k}@uRy}hSVEO_|ki>=w+ynDqalR zl?J<8?yfzxba^}cgVS%$^KDA~R+2Z$XKrOIWvhNZb?{KF=EaF`3i)$B4e~@rmvx3e zzd8M9hUu>y!`~ln-@je_@zSsK%fC-=-vo|rzgO@0_ZPpe1k&37-P)gu^p}6(cnzFe zZx7b^zus{B?EiR6tTJ$7`&!J+-wxj2<UaG?o&EA^zpgw5j;!BIkNNGZ6M+NkBmW%m z-)(R_2F~=K%lyAyEZlwemk|D=KL2%c{5^15UHQ7jzrXl(r7>Le@6P@y!EeBE{ik=i zPy9X8KZZ=ARrX(<{c7_+g1Vgr9Au|f{J&o9`;i>K<o{ZG{F47xDe$}eU)plKXYsrI zM6m$&h$<g%*iYC^c*Fh=U-g&%;C=Zo-10wagZJepise{s@bK+K2#81QCyE7t>Kr<F z#D2nV!Ut);4dd`Z+CL-HWBm!h$K@x9<=E`t<MI>98ax$qqF4Z=2e5B=D(2t22~WlR zPZaQ1lmvXhQ!)Q7jlaT4JQZ`ISnyQL@5F+qV*c7Y|M-BXVor#XfHx4~(<;BqSmCLd z6FCPw6?39k@Knt2#Db?{@Knq{gCTq-?H};uPe6x<ZzqZcKrVRrhKFze<6!XY8=igp z=a#@D_W#);zt}cBVn0zVc*OoYvEUIq9<k#Q`!6Vp&zJvG7mocdK41Pj-thn1e0h;> zjq4)L<e$*!zYN+?6;M@RTAt^>F8$+f+JHeHj}e@ZnFR?`vn>2*oGQPc=QppYZ-~3V zAnmmsH~iCaSnCY0+;+%0tq_s{o0D%hi2$UNC`_i6SX)-FS==L<PWua`{O@oY1c6_4 zNSwysh!@Y_*605pN@3)5`jdQQI8X}HJz{Neq}<jVC^w|<nk4%7@AH_r5CPR!iWnrE zpUxUP!K#iH6lB9wQ&T%&Q&5CsG*B>M-}|bL^;*xaMx!DkSnEHAK;*&@Pz`iyB8W2T zxR_<E0y|LEXb&i4%?{LAvevNgHaSPbel1FRcW4NxKuByGn^cy1Tu*cjs8#((IiE$( z@V|GB-MIjuNXrch*~9gPm6cb9K<S(Yl|rEO%395Gp~re7@$_0PimiAcs9AtR#~RB9 z?3RCSDe}|z6Eu8GtXD<_B*!8suiXDOCAxRImH6e_+FGOWhGo7JP)n>S_Q&%rnqRSG zK>CFQLDRcFhturHX9+zv%lE%IFJ{JnEvOtH$!*y*rK8Fhfe@bI{b4v_#G_-K^po_@ zZ5xn#JMVVpg$E5i*Kdj=)lwwgf&^`!57aH%a?4*+Nt5yIO<Q36<xo$bIs0e=sFG!D z@Vt>IiS@I{nxd0uF;K0r1*nO_#J+hXNCwOXb}BG-j^AE@Hor{e8POllPJoR##MG^W zFBXf0+hNhI$vnrks+M@K%b&Gh?4+&RN<qB>swRJdQpy+fagY90IE3MB08p;(Du3O2 z)1~3fY?+;$1X&37bv{B-Ozn1Y&!`IUH*+;JFt*}c!Jpc8*hOmR@S%s~nu#^d@HUEB zfY5!ddfwqc@$4jH8t!m@*_JWtc{bDu{Fl}8vm&Yh3MY14k2Q~yuzWxsZjwo&Git;L z{L0iED##?WS_z><#A{Ej_h+e>y%g%}SQEZEb;cE01EA`S;rl(G)^J*wOV%pXq*1Xp zFjeiB-mlwSsM?!~Fc*}IH8c975@wu$F&ir@tJBXr#H~5msZ5s@qViwqT_~)(sn=x! zk>P{o9v5bdMPsaFF}gHq`ovpW2EG%Kjy~qw+uJR$!%o=wxm@1mi}~jztx=>zymDti z=kr#R#ku7jQ$!DqdCkU~?$mWnry4q8a}>TV7*<B>)QV2E;$E@)Y~=}AO>XiX@_@{H z&VAxV_)LawnN3p5)$SM0RLgA|pp84H2KYAhKxR$nFm0lX7WM0WUv#QGlrR(p^FNE~ zg=^p}^oV@J3#CQFd-t4K4XLM!`-GCmCx@=p!}C(BKu4o9@4>Dr;my0FSEn-FV&`!a zYZ4_-!w}OyG33p3Jtdi#Vxd@3*pC53ivR@sDZ!<=sREoKTrUd|J=lre$@gAszoTn~ z0PXPTHL4TwMBck!tntcysOOZ@DtIvtv?~VP{DJfPU^4spQ&jF@I&|OG@#y<hP%BVB z&PYJeEK_xo;#XYMAV@+JpdggpVKN%dkx8Nw{&G2@I4hyZ0;nM9^zBk;i;?&06CB8+ z)0i%QK%s&^ZtS`3%#Ni9{i0+#=xbf!LS(pydn@JHY&EAa8I%}=$X6+pM@Qmty?I&< zJEOM5%+nO@2*DtBP>AZSH82bm{xi!RQwhOT>Xbcuw2HX1FS*^=0c8)*fq30sf%dXL zk@O6&H$wLmO}&Reu0XvIktHQt*C-j$-3ucazKsxBANyG%?bO;O1*fgU>Wyb-8(Thg zMU~V>h7Z~&dF@SQ>Y%40Hm0+o%<(>3Yp<*v{o3Qmwd7mAu>w`BR}yu$nhtbe`?YKD zkIvMXHGa_*Izaa}85f1+V4|aUYq@%BRI9GUrGj;itUgw>KOxI*CC+lF+p5u$WiYPI z;tSKI_6~}*M95n0st7qGvA6842~@zUOG?calMBZO>-jy|1RtaluIg%!%;k^U7kb;6 zvaF})5I*tFzcX>j%pUg8J37A%XPt9YX_J!j&Z>1g8Y<?_IE+z{^Srg3YJ34~<msSX zo8Fps#c;kwWuA?l738otYV}xf>xDU-DLJinQ?;H66`gW%&{&Xr*ZZ*-jLC7?%dCC1 z)O>T>Gcww48xuvH)iw{8;*=KyY6lw8cfx!PS<o+snGHh&2Ttqrs9TQ)@i7%AKff>K zHC{Dt=;39$;@#pn=;ZOiB(t{G`=<hZ|9IY%bRtmXdlkX3VltatBu&KyD-eeciV3Z! zAW<*%Ympav=_n269{puhwbO22@Hwsx7_`|Gu09(~tr}*G-Hea*)C=F&3rASQ8`8xa zd0Ee5$;C#gQc_Z4F|F;&tu4FyQ|_&@{E<$d!l5tSN}eyB5^@ukJjJC_do7ElpD~g> zeY*9D6MEFzX<#<Vsb`nUcN~6;_1N%8hp&Iy5M`KDH2<uDkiRf;e(qcBrSn?5;iamw z(iHpCtTq_v<RG$+fpT0HWH~mt5;|?@)ZL~U?rU7x9|F(2;VHxho!=6g#-@ove30*^ zIyOREndL<w;zoL`l|Hj|dn0gtsqwj~bP6r`l`@4o+`60@s+(KH%brhj5wW-fTYA~A zCVPR>*YT0m_ER+^;hO!&+uEaLu3D~|Q8_`hXI#JTP#REUZY^RAHmiNjH_4N#BJAVh zgJNkb)gm_L2Wz@&r?ZH&?kSAG?~q+lyrhs}VxdQ>WutGqWl`qm#r>VJY_QwQwkTKO z+V?u{EcX6xOyXIRrfWa+sOG^tAufccZon+`Sj6gapmCx7@C3|;2&d%-uH75aIVf?} zs++I7TWB~`^FrbX`*x)KZ0n}?tO+%@A)n1RZ#nh0dE*jRaSxDSIMzh9ZeGB-DfWWX zp7r9>(3HyXTg%2#1r_5weqMw9PDerT?SlOFdg&-Bz9<|L)Rq{}S;5>*9l;N~K?i$H zS~-4M6=Z9+A~iMZQN3XoI0c62RbVr5s$9-e7a~wKVyQP$w@7P`>)b#3o_RC5GL+p< z+yS~jcWLy+!xEFleW98IIV{41#jpG<Zz;4yq{f|neF4E-L&FuX>5zn*{8Dk&_%G1l z2O@$3KClHS@+Wy6gewHs=iSuEl)9Oz<K*e8=;?j`vqmtloNv<W1JSHOjHoEe5y|ZW zr5!WxjTJvz#aC_PtUMm`+ybywl*JLuQX({siW|CB{qvLVO|e?(iW?up;jmU%V-2}( z@y#9T!InFaKC1AHs2GOs;v4mE6<}NM_rCki`ai9#nxLj{Mc_W;I(_!VF6bW_c@B4O zjP1Xheyh;g8IEadiA~#AuS++;B$cfqZHIOb(!S!7Hr`j&ZY&0^AH62x1+B1irMli* zDYboPv`>erpWEj$pVTgl3ia#$*f4eKObDmWBC@^AW}`sJs++o`Gs%cu&Chd}4khKl zm>+ZZ^_^uBW{@;ng777t0(5Ji?szqkWG4|XVHs+GGDX<?PV(WJhE5NU&O_8<&vxoS z?Ogbq3lR>H-hNd)?y~D);+sd9)^A?f25R4xtUz!BgR!;L`8Gl^wIzGX){k!RtVguq zuhO!*^wUwPG}F5)pf2fJ5BIw4TGaQ|0dH*W-UCThzK5sQ+53zzH994Gsa0EuPP3%3 z-RR3QqqMbs>=8PCt25$jof1~xlpnB8^)9ncwPIY*<Xcl%W2j6N?pyGJhwqVL^wl&F z|BEI*`78bIyzWuGmdUK<id<6p#-0#^=ldx;;pC`{d1WPdPMU1-wY8(3Z5_=+8N}kx zgx&V$PuQO!YW#e<?9skQUm`=qGr7+1k4;g2<J9rIIvQ?bA&9HG0n5^@%<RI5q03|M zV0<;kzfmC}fTFdALf_4PH5vHzE&!Z};doJNSZsXH=9}5x6~B5OOB62P`4zUQvsOF* zL3IJz3Acr^6@fa?ja9J<nFbz{FCH-$Xyn&2G&--A4{FWn=0s}c*q5@@^u>`c4QjCK zpuEH`>safw)mX*16=)+F;A^7%*H~S2`eg4q_8|M^c03`y+rUC|&&f(`e!Hx{_H8bh zm+%EoYsfKTzLU~s@gOkPSJvZ^L0`2#>)b3ogozAQEd)JyE_BnPNPHF^9bFhT_L0pc z-#F!T)Yj6eHYiF7E?b4#hk03Af3G%k_Ysr!p6aIm>V&DUMpX-7ugiFD<om_bfHE;C zv%}9&qm0;2*oDVfQ$GuYm5S=8XYQ-a_qX!0p%=J}w53F=D$_}{<k_D4D5q3GVh%FQ zRN%rJGt<$n@6@EJ;fG+gS9{Hatq!%(FQw5#m*rP=)*KX59%*NHedZ!YyFm{IMb9)U z?%zh_mU@vjRh-u{;tOcWn{~6x5f!Qc6{ZcdV)`M|+G3+03kC$PK90#ud~Z$DQ@06S z^Hd!LPq%Lz*i?O4N`1c(pth}Lw^IEWi-j&=OUEUo%?wGWD27hoG4Mn}l-9t>p1z~o z@t7xQ(W4D9X>x67X5AL6(+^*lPo)Q`h295i;uB$|9YiXq_-OJs*!84$lA4{<8vNBR z)-1bO;}lzNi<_#%cH5h(k(VBp49`z}brFcNP(gF>u?WjpCX0&7XHfHgbpFzks1p+y z>m6ZY5lWMvJV>9PZ(Mq<hnr>xp@p!czudv4bMHXf!}CD8>Wk6Md~o==r3gq-u)ff| z;)Y|fW6Jy(&0zA+ZpZS#SU(m*KjFUk)6CDO7aPw(lDdYx9r;Wg-R*{ln56!yskv@L zbv>GmabbrhevhZ=&6MqhS2XXs;~iUBc<w8BJ$gLqJgDDC=Tbs**)U{ofWe4He|Q@x zrzn|YcXub_i(6iN%R^L}LE@)O5VYJ?aYaLVK7TlKFR8vF{h$tMr%%Yo47k#v@vnie zRnBRjbulE=jbUegYm$k478~!!l=goAJ^7s6B0IE>g%aZ8{9Q+5WyHa$JDWe;H?R6z zC!8;Gnx7Xudk?4%OZNEr*4)yvhXh-luk&}Ws)JQ_cJ{$EY@>($4g#kmBc_TA#ikIA zy~FX#RN1-_!uIcfuU<&rvn=;3hMxB-zBw1xS1nS=mYc7;uXE$@AkgEPg<7W}TS+h0 z>G0*Wd74<?>9~0_tQCJ$XwR&s=&F`7)>mg`KW?y%0%4aF#b-PHBK1j$-DENybqe_2 z{Lt!jJY3-AY->xeIajMhD2g4F8Pqo71`Fe&8)MwkQ|1^iv9ijr$~u?l4fjcPos%fR zeNO379QZ1rB@3W1nIc#9kuvR)?xhmysbnyU9uzrRQIlq@j2V8<PvrhXUVunTxyE-p z0K=6wUQk!;r8_!cXN-Qeu-B_(=3ws^>$bQ8CzPQ=N3Vv>GAG!5#H6<Sw!QU!M?d<; zrUEIHLiD=g38=De)Kd>iqoa^WoK=x_Ut#6peFeJ_T!;6_)3M=*9vMx)@+@>!1!e5K z)-KEuDS6Gkjhi?sC;4Hm`xx0qi(I9>>&5M^?PT<tbk?R!zOTE*4du)JaVziTHAhE5 zAI&~c)E81`-J6%GmA9E(tPs_bskmY(mb6}5foqqf%N8}taoj8N;In?Tk=?Xuqwnz9 z<GvrlbN80hkDS(2vFcmoTHzF!B#lsC$D>W=o(Ey@CloVBT7sqnl|9c##?y;^QFn0N zR7!=4m)ZCof8L0GHmq?u`CxV5u}y5uWi5i+JnvnHtdIbOxcgiPXgqe#E%8apAa{Md zMEqp!6x7vz*oNUTMavSez>!^M&YoEp6tzfS*SEX`&TUk5O1?qFrZ&DYTXo<K@5}1| zQyhNFo=WgF*4FFe)X~K~_1O)~`?Mi86=vA>l@TH&BmV?KE`$DdSmiM;m$^fZ9Q*o+ zs=1Qu(fc;@pIoJC=}UxSX`^DC1qY`wQKy>s!^P|ok*I#4%B#Nd9jCbd3dAmU?y~?( z2FP}>a1|`tZvrp5IpLtH-1f@a*QK%GflEUqvdN`^yb8j0<rgtJ#Ccl6C69*7n%3o0 z-`pMUyRlc5;xwCL1$-vSN;>)Lk4^!FV?V!o!0ldFm9KLlzt5rdLEKc231NzlyH}#~ z6aZs#r7eC!cR`D#&;b>4Esf`2ZV++BzEd1*9a{`;D?LbAXXr+?l+MSuIEBUp#UF%V z#u#(qm?P1*8$Z;Ecw4iGFH<qTa(gOhr+)KHV@IvoE)jdAVO}$jmW+>ua<%WqS!UJx z)s0Lt)#&c>8U^UZ#|}!e>gF;`Vkz5&OJOn26B<VMaqF2<OHYxXWa#PZeKj4OI)Bb2 zRAF&`pV^>x9^79xD@0M)iL<=sQ?D4aTa$9N)F7yls;MaUL9pGtkavqi&O7w1aY1-n zT+z76)Imv(xs6YO`I0PqI2lwB5|nt*aWJ+RrfZDxsYBa;!tihPqBg=(v)7^-*(E=@ z?&tQ9MAK`xyoHQilSB@96Y$BF&oA~_AGNm&6_FU_R(4r0ejj)l%a7LC2)bJG!!Kp$ zN~IPxOf{ad#(wLXNnw$B5Qusz5z+OsOAKx3{#onG(njCI!?`6tkyV{kn!(Zck~8`$ zbkev8p?#NriK|Qk?==w*c9z2t*;)H4;kqRwu8uWn*5$Krm~n|+{IXs)7M;vzd2N~b zc{RrxJK{yT3i+606gXny&{9yrHQY|x{Xs--{Z8hOB5yy>?~5}0b1@?-s0eXcx@6EL zc}Ky0&qM?7jc|sPz`TzFmAauuLPF@P?6RDOJUNNsv6X|RoDN5udkMNY3mqHeeZ$f& ztO!?Yj|kU&dwX7ohp6T49|^1ZW$gM(4%K`#R#sAP`8&&ZynC;vg|pOH*Dfiq;@%G7 z$o1Pq5p{je8q;0YWIb?qlrFp+{bBmM2)NByOD;K8!E6(x`ilJW`|V!A3f>n5YOQa{ z1KZ|!E?1}$cf=29M>}0M|L*7gwF?m$wqu(b!Ns=k1dBpHVkQ3S0NQ5LNz>m~KlGSA znB!G>v-?>H)4~tRyg+6B!`A4TU%vgu%q3%=E+m9E3W?fTlpeYkm%Zz5P`ayiun$i{ zerEA0KM49#iu8HJ?6~|xK0m`#UC)T(|EcRO!`f`Nw&6Mj3KVxJE<sydTPPOXLU4B| z#T^Poino+t#a#jf*Ff>&?hsla1b2tP$NjwTeeb=WcYitN#~kxxX3d&4v(}vF%3Kaw zO)qA9&6Ey1weZaJFaSyUCYJ7myZG1XWN(;vHN7p+6HzO{fIUYIezB-CgztVo@@H6y zd4PFE$wtHdm#7!Qf4??COV4QE-N-w%dG1?2wD0{Cv%3J;JPZnka5iS@bAdPSs;Ng1 zwAZbu=$#}zs_>b@)sM)!&Z5~n&gQ(!Z?bvjC{=UaE7970f!Ak3CYfG_NS+qvfU8c+ z%BHD4N&UiA@7`oLF;%wBEB?d95uHMFkK?y>PUyXV-Xp33s6AmIWLC0iOg&;vpjTsK zZn#Iq+{T?KAQ~Z@^#~t(OI`d_Dwkh$r(^8Mfhb}+CEgVO!<N9S!a%#mvWkGy(nG<( zV?j>ZWhjOQ?Qm|bx6DM}NZif!S*3A)AZ!Ztn?%2_QAGK2ZOrVwl4sL=*9ysYDHl!Z z$n|5V>bYELawyS)JqwvFs&U9@yMTi-*u=7;VPlZ35_P7ZA7MK|#p-&;&SmR!S-jp3 zZ2QK6lk^<W28&=ZB%vkOgy-p`0+8{1I{luS@6I=8x-jk<&gsp$C7Xp}n{WD$CQ8mH zsJKvh!Ungn^M$0$OBE{5Zk^Og$J?Ct7odLY9f|sro`#D=L{vev$VRfz;jhP~wDP6b zS3fcu0{1v8SHo3e{KxO3`%7nogE{+Ew6#i<b8`V+?q=Oi6ZT3EvP|S9fN8TWwqb=9 z)zhF}yZ2}Q2&e6=?TM036Z0Ju@e}H^nTeCBZWu3OH(;%NzCY=B3GIK3{6_p(=floe z`6RDU>E`<*O0nun^G3iB>FYN`q*dQ$8to3<4}<o&&#(mqz@B=eqAxyr`|fowOf_WI z#y~_s1JwGK=SDNNl_t7Act2Xpm2bK=7Cd(CZE3IE_Y#w4?DYMWO?%e(1Qp?g0S>8! z<|?)sv7iyffq{x<)@`6E0&15$b7i}2)~6k4m<fg+?`%&L#m-wMjmLpg8?LEOBbr(A zv(r)MPlF#nc~(|0=odFR-%+i)NbAZa#_%-Lo1yL*V)d39S{pIkY{m6OSMD^7Q#{T% ziCL@dO~GIq!K#Qy#BO~#-x~PxJCpM%i`5x?=CKp2M*zy!`RtoHeZa8+$Mv7%;?56B zoi~)*t9{MoUrP7M$qW6jCdnqg=AVhdh00sa-X%0|ov9KQ#s$jhslv_M>Ik=2Q;_F9 zmNQE~$hBrN1jUR8tQ)(kHwTl?9o7bu(<HGb6xs0H5f{#l-mvi_7Zd8<E|jVS>><=0 zc7!B?CM-8!5qgS<S@|7}_J0}C(SvF1ta=pZUi?J^c;4T}r3H?%Kd8espRg}qBhFW@ zm+u0gy43}Tf9l#YPwJN=kC*kui*tksOMPVqm5<r91FABC?YH4RpV4)KHKCw`W)f&Z z+=$GtjN_n+Gf=dsqaKyIQsm^Z1&6-y>$CmY#xu43nbVQ(8~}H$uN)12ri86Qw1ZHc z1p4<)!^$>N-BPp{KhPN%?W^d$rsoc6(<PK_MO`(VWfaizT{+Eo{)5W@V1iW+xI^T! z7e995K-AfhI769|ZLit<9f=foD|;@rBM1D58T2FFYnpIwkw34_{}8!`OE{k_3VDwp zBqBmJH4nadXE>Be=Fgt@v=+9`XiDhT58c+bLVB135!~W}=X+`xfbIYXmA6&GBYplu z!tT=dANY0<nA-96S#%qmy)s~{RcD|TzN|`a@O3g77a@xvL$_kDDq^%XdYYd;D7ceP zgw(3@D0^%sxCz4!rv`#>YSNiihxGVt+WT?MS0_+0`|yOG<AIf6T|tn@;n~GO@5<!o z5(d|2^SP*r=MY`nkp5{~anjRr>!I&aW>-^>Gb<OoJt)Lo?Bx81N@?0e_gawU7wsi? zO4fI(UshQ>x;K0ZExe_+j^5>5o$$F>B1o-3!&mnR=OvoCYwr>@nSJ$*NF-1H@|Bjq zRq7{iqrn}Oq}mj(fV9A~ynuz4y;;vLQc5|l$&BPn_wk*{%j3OPeEyMw8R6@3O7mTW z;b9W3GQ+E_3f?l9vB@`)w4^-65cE4oX<Lgf@%kQ}yFYbb3}e4&s)$O60JA6K6(=lX z%OjHA)=eu1ikzK~)cF@Oz+O`=7c!|-9^LhAWTid0!M<&1=&tdV9u{{$#$}annR(52 z$lk1dX6Mz}@toXB)1^#SeF=P^5^|QEY3=Rpo-|WtMB|AF&=;%pI2XE_<+ID#(QR^= zB)&`L($Na!fa761MROba2JW1r3cK0lJkPLO`zu7pSyM2^^R`dx8<LZKZ(AA;>*UPb zW<rE6L-_u99yZswC?+{9)H`(`HU$f}tv~@|BzR{yhiRuVd<w^VwJeZ8E}xmB{yRy- z4u=usriNdwI44@H-cF}>oWz*2vsA7;m5RkEBkTz(S`9FLxovI!r`x(~k}|P=R%&_0 z2R2@B^L_tROhi)Rx)z}V=iQfNQ1Ko4@ywt%HFJ@C;_mkLp?w&-J*>`1Vy|wo{%B<F z!9IE&10a65n%P3-t0k)V!w}bDr!O=1kb0Aa&%H~c(WjJ5lbn3^K7#(v^;E#WQ!z*; zQZrU)b%J+Kxj0vFDMR1KQA9Y~smpp`M)C!oL&PV`qQ?-dg)ZGq0u93{b>AuV*l&qL zn}*Z-LSiq5e^mF~yI!lLN7r*B0U$hR<oW463A4KHAP|PqFhMGk<@x2Ec<K#D6=48` zyE*M>nvvDc=y3%0HFZEwjZn?i@j{MRDz&8El-@tL-mlzh(XZKL8}Qr!vZ+K2Dv|o7 zW1O}4Y{*js_bF}2KmhS^B~j8j`=ewt{q7=2&<8nccP(_h`Qs_17-+9^)7#HT<d3V> z=32WlwnV?beVOEO!WB4@Fj;`E!S>Qe0CgNN0I3ZyQG5dEo)%<colBUXu7JYj!q~uU zve5>~veA<T6@k31-bmx_v`o1)_a1)dU&EA?&hbVk$>U6&8Zei>=;QG(kjl;17KP`A zVGj4%2Ftlzz@!%oWjW_ST+mtaMX}K7rxgx3zjI)!+xakL^Fya@%ZOMLYxzC-z?-v* zc3#Phi<*H9-}-X76BrrnGKz`C=n2=5)y9|0EN{iL5q~`~zWiOa7ok7Fe_c35Qxd=# zc)&&bq8}qdD^+BzKUX7?<y?}ms^YlO?<M<|UHVNo8litV&SyKdndSLbWW({+5x976 z<2lJCRBLyb##d$GVe5{Qs|!qzGDPKn!#&0Hp4eVCsoJpcI(|G>Ywc8zZkn>K+Bnx? ziQ+OmD{+?Ed*{r(YrWa+paIkHHnNqRLEGCsmJ_TC3a}r!F3`4i^!C=%+$Ggp23{K{ z=1mJ+8LF_OHS}CI71(~VyZ;o7wqm<;5xwidFdIiqf%6qal_$;$4jg>M#kM7T-`~}d zZAS0RojcHK0&|TMm%noLoiq+=QeGKt0CtQvQH|Qo6ee+^%*Obxk`m<sx-~~gi&W#z znyLQ&-eeH}n4np{Ue&tfxPjI(m`D{$N!Xhy)_V6G!dGH>C`i%;AMiEX30IAl7A>)s zE?hO={}q0;5y^iz>yK^L?msY|-zD1<WZ2uwi;@407qTGBY+M1tSx#cJCDQgB_zFV? z@JEAf#bReNbR<4F`Qe6D*{X5?UDKm~xY<~0jfEvW-fn)fo?5sc;~VI1LZu$UvFT}g z+_yc`I}s;=-$wOKb^zr0q03&bXIL~Q@*6w_c(qh7@}Xs;3Ov1~Aze$#KWH3IZ!$+8 z1nlOdev>#@LMv$By9H{$<<Y$7tp10J5v7o{7)*J?V&^)|Cn4yYTl`Uoxnf^%eq&}c zFBpBT!v1USyvGEYBDWv&G>W7*bqO~{lO=jrQVMwwCAV{8uT;9{nyutTRQBF&!TDBG z-TGQLyP2*%g!l^5J-zmSb@GpN!HwH^_xu?Rfezuk&Rx#EU9-GXs~($OxoQ4d(tp#l zUs>)qB)QEKg~~)1m_`VFcmB^v6vRo!OG8P|xOK`dQk@-x+D(lp>DfRdq&`V=xujrO zAuC@ZyY)N9@fDrjHg})^*SYu<O@;q%{VlV9L~T<`#g9vGNhc(_ghKN8#P{RZwmwXy zNacG@*U7OFsho1siUhu<Axpfcq(qfzBufHH0uxa3m)k^8szhRF9zHjVwp>fzaJ(=Z z_;Q{32_QVL5j<Qn+<kQ9s<_%P&`-TZ?n22%o`w%#Sh-Lg`GSsW&71%AeO6cney}sU zS_>CFP-^0vO)5=#R?0!{s+78R`?H@(HF7`m=E{0?3&WQkZ)#*+#riBjIDKy6B%Te@ zKbh}$2Ho(v-mA1vZSd;LUp1e9hVJY}`mYx#lv0NGLPX3ano?D*mf8wD`Ff9T89)@= z=UPh@N4k5uN!7&?6`M&ey{21Y$tfau>-;2V&C@H9$v!_X`u$$}V|4IY9<R(DX6y;a zj3_N<(kjyK!cP?1BGL!wq@=A+vl;}U)vf0FyNP&5cWrRjhZQ+3XScNPxTZc8Wj%RM z2byKYxOu|B$_i9}9QownQ^)7oWIgtai04E_MBMVDb~uq(USBKN6BKQ5BeB>?pnSkM zwMqGfu6{aoIw__pvgb!-o@awQo>n6}zFa>8Gce8!5Zg{?89VUXeLcm%iv?L8?Y_d6 zB_n!Ky&tzU0E7a}eMZ(k?P`{K1tK5-H?l!k{SxVHeE%dx&W8?VSr%Ul$j}$%9N{D$ zmR05Oh+;fLTe4PGXv@HTqQ3b=m|GfOL$BZ!Hw6SeEQ~oN>{r&m>~h@fgS?7{5=V_6 zDh>Yl?5x|qDAaRG)}b>uBBY&t#2|Ka5S5+Ae&mqGGSc%K6j~qn27~e}CH%-B{a|#> zga*KE+TBTMHfo3$p~flu_OQU~bnJ5WC}s*I?K1=!jV2tMbIFO%-UYMMNXKF55Xw*$ za{;lg_XtD=?Opwzc`AM>Z2u-Dw%GwBHiF+d*R(lV9XL^?J<|S8lgr2rRLvbQ9H8xy zgEO07#6hH1SfE}p!`|f<ryLvz63!O|)hdp(#k8dCPm*6}m4?J6@*17mV{&|p7wma0 zF;y<QmUN{7o!8DF3cMUJKIjKjbd76GzHTzngX@zJy{IE0qH3c7^d`Y_?i{t2ok;r5 ze_XWEZg=$Gu1F0U*G&a1TP*UCdm31UJ^PNbYxN@~PGM}QrC_87s@a?pfJ%T}q8}^w zsFPzcU0JeoIhad?5ActUjiN8$(_3K`jBg+PQz{9+Fge3%um<hss0oyix{dp-*U$mk z_$!+X9uLzQ6(GTEvrD=I{*Tco6U;<a+FdNrjfhS3ZitG$JP*^Sl%zTSk&SSL8$=w! z3mnlz1kyr{bwOYc?O3*eTIz<=jWCym*<K#LTxFXk`baU(oL@iI$;IE3o;h{H{3@u} zG=!uHL9ZGOrq_N)q%ZL}UGcfu(m3ptrr(8%&fM@$Ce;;U1MG-PC7zXmJDS<>L3*d( zX;VJOKzw|c4WoOF*@7}cNNIW`bgMc00$8L&>jhq@#SOME6tr_IAK?vZU1B(Nnnq7- zr-m*DEir~@Q`Sh963)AAysEIZnVv1FkaXaahGv54rljynzFJ3q$a3|;0Hc4E4)E;P zN9vXSX)Z0Dn9_UgY5jEQO}hZcc20bPghs^5$eFDelw>~3m1TlKs)fygRC0!jqq3*O zvW>ZaiKcK#<D=ZRAR~{EG)y-*RK2~hrF7~7w^qPElsNNn8*{YGd5f+QIHM4ML2inb zrKI-4$9wN3U(S|OlJ?ECZ$l1I{#|@AxYrIOx3+A%J2v+c&(gRD8PJC0@}VZY4w33B zw#&fWjlu3+37kjGp<2C$*j<kZ#Ka}utQFHA^;`-2^E$d0xgqp0e|QA^TG>bLW(D$o zqkMVwA~e-`=ia8lHe|crddE{FgFY+Ta!aL5i-WI-KlB7h^jB+jB}V^#WH;&8OiJtD zKu!BWM`7=?S#54mn8&C!mXR@!%CQ!Hw(pX|q8LLDx8ppjXB+OMJaf1hVEwTC#|G1D z{d~i~%)QLdBh>|w+58P#25r`Kt2+T4=@PVsiioi69@@IDP-6bb_?RfBUX{*Yy;%e^ zanz#I!R9SKm>gyL^#bp|DsnY;sSC^p5hx`Tx%~e5u(^n-sG*Grg+k@FEDAU;AXn#{ zy<YY&-^o;g+XedUM*`6Ms$#n{*1Fw_n5@$R{#S1HGeZ08-cTRt6ARuxAi%j$tUd{K z*1h<Z%WOn=TxFvgkg2^ZT2x{lhzCK#0~7aa14kvJHjf6=EyP?MP4i>Cpo{iCQ2F$d z3LtE^;)n`yM%UkF3#Knlr4=N2_3-}|A;j}V|MR6}K3k10+hWF3cF9PeS^;EZmG`k# zUj9=@GtEL3ekp(5ncg_sINfS1-Ee1k$ugI!#HEFSds=9BLB03A$}mQnWWIidziz^j za?-hTq}mjWLj-^)iQ(<?*L}B$xXHQ^{&OdqOfxp|^e+t>NjZ_J4(V8cM&ZkbR%xEV z$ah!aPHGq9j4fH{@~cqBOj<Jj%a+MABGA=u!8d#FQ3bNwUlPob$uB`Wv<cZfCjJ5J zJxu0PTxzXsw3ki|ICQChfG<LPepRTo_@FLdl^xu@aXsQeo!O5X9R<EeoP@_%eIf4b zci@G3r5rL#v|%<TJ^TDoSJnkhw^lmukshpE+Viy2v)gpzl%fqm%Z^AOo?GwNlQVUc z@CY0xPLEw_#h_pq`nmR!bg)UmwZ3<gBARAiQIQ7f3fl`+*QB)0lf)`FqNlZU6j|T% zG_oJEPs^5+uc|srZzSV!ZUl8MPR-Y$vMFOa?Y%Pb%RiVt{q_FO8Pf(7^R<kshv3ns zm!JzY{nY19E~B&SY3MI_Ni~SoKuewU6ta68<}04`O|D3=jI_2C8_+DcZvIDq{#YHG zZ53kOFYs)>18Y=MiZ}MP6mOGANwL(Wb@M^HuamjGGvl(P4qQZJu*IG(<2HpPSotbO zQA>SwQbI6xq{JTg%6jxZ$79<jFq311@E5zg0!PL4qmU;RT*-W%V&j%fO<0cwtp7Zl zJ?||kY>BDyEg_NTNQcD57ZeaMC+XLSP;YJ;j@~ude;b<@;m&xyQdZM_2CBl)L5cR8 zca2aokq0r+yz5S_IRdNq?GP@X9As6Qn4upj-F4Eqy$*o-;pD}2KDGk?+*;EAcn2R~ z)TMz1_^YoNPMZ!9%7Dj60YYN2D<)-up!AHOVQaU(o?e-?$;`}b)MrlUm%G!0YZ|Hj zHys#i$GZW3w{dZmmqUUuds>;qk5XdN|8fz1ga?G61dRTzsnTqMQH)0q8Bh`Z{y9!Q zE<T<{M1ZzPBZ+CWMJU9euU2fVzt%60$d#%4r(pVLW1%*#r?Tkvhc9-DcCw~skJixO zf<dhO?OKBx1jCdgsBV`HT4ZG&VR~o-b{GB@zkF?kBPXmw+Yw2jA+`cEjAFO*b7zFQ zb=EX9uU5S&`-K`m#=Ab4SJZ^b6KYR>G8?JP@rF`WWdC%?RksQKz#3tF0esu7suYwg z;zTrgwVW#MWInA)8C|{AmVLBZ6BlXBSy@CotdEcN%{=M(ZV@p`(W1K%1u~4Oy5p1{ zP)Q%^`kiX?08K~tr<U<geRwgYPXP8na)o5bjX0<#WHsPXFe<B4bqoE@CCjbeB}*vM z?zr;W6%){rJFnimou$!%c=0?;E6N0>gmaF?K`HzoZVvO;=heOh7)Wst2D*|qLYXXK z=Y|QWz*}Z^%p?kHH+iP7(q|~nC<;GJo(7J1g=9Hn11c9g_kqrVcRym(KAyoo=(7I# znf7dF>xeU6)jHU4Z5DCpb9X(&`l+RMB#JZ=na_kQ8Gt#gxO+L+dr`}QC6`Asz3R*6 z!*<HI6mfn78d8VCLm(6mx?<QBTY<(qsN&btKMt>le73p;p4oLoiY!~7JbAG<HilbK zG`y)ll~Lw(Q{3@oL=*1kxF0tR=!)hroF#Z?x5@pLQ1OD>|KpW)SHRik)8OkXw6mCG zM^t~x*FTd7MMOcXyZ*LhZ(NzVULypogkVPIJWgFQve?ax5vLjoW{%6WlBP^%UlcdZ zQ%_9G<>xt{ErsHKE=QTzqw|11<t?vL1qGKJ#C@XWOcdU$sT-Eu0Qx)W+2V-N=oMbP zHqHFf?un1F;f2}8p*|vkX3qhs;pHFCaFG<~XS12wmmgZe5$Sr6(Ki&&3EOH>pO4AY zWB(BLWO>TH$&8%NsMWtk5&ydD^w|FTA2ARc{cln%4hDwKjdvsMIq@Ta5hDBQa%~VO z$9lvh*?N2aK1qp;UjeQ?jZSr7<q@y1Y<65;-7-_a`CWz4h_!v0hjz3{jbVCd%4FGg zZfG8dgtdkc^Vfm9AXhK7Cui-9!NR^mB#QwIBFRRKC7QKWZm03aD@+QYeZ&Xq^B1yi zSKpkk4iIGx-r1_GuswR{3p^wk^Zt4lhEbp*eQx4@2=*o+obdsl<elDjGWG)FPD~_; z$44|J&<z-5tIl>(LAnZ}oTf5@z$y9IPr7=spML*5p)HH$!Hz$;&30~I1ZWc+`^1tQ zi}(SrFbvCqMWxjH4qfY>QLt48#e5w3;CYBuupX^xw`*u1OmOMd2l7?7&c=#|+JcDp zHj;iSf2>ymHs*S|m7FOJ%$jlbyvjv;#E22C`{c&>bTW(nG{YjsXu68b`n^zI563hg z?`7|9mv{DWh&v*0F~)d3{5kY8&&0ZpH^mSAuz(LB;7Pa>t3`~F;7aSn^L$cHeM!<8 z<>PpwQ;pt^*0YS7<vXKQ+}{y*x75!(u&`d0ym#-$9i-;znJ`y2oRJJ<_tR5ZABxv! z@|%zj+x1d8`YeXjW(RYh+*D_z==ow|0oqAYU*+o1p0vV5MLd*xHw(cCy!KM$3ibC2 z-(H)gY2=4JCv4tB3S})}ji6xif-K7Ow{Cb(yn9e*9W^k?!W6GVIMaryoh_)9<F5Rq z%{1FL4`s-zix!e-x<IwVj3vLAddQCQ*i+i0Lx_`Jt<!u)geUdJH~Se<1Ds`$x)Eng zr>k+20!LXJrf{t<JdjKo$Nq&bf5)|7-_#ehJ7SJN3ilE6<Iy{T(p56S<+fAa>55V_ zmSEV*bL2BjBr~@8j@k$3Pj!-|G-lQt<kWF6GY>=!r_cFzOon087ZyGJnvY^(@HWC; zUI!AUzr&IHxa8oKNd&{5Vj^sX#OUO!F*`Z>=JHrwOUr_>p?-d2x{Q)ws3K=xUcejv zL9VKY=u}%w-|C!d%YK<>Ya81M9YQ8vA0_JNlJG9?>^vZ0Sd2^VdT2|X$+A$zz%>6F z%t0;ivQR+?&tCLqKhR{%9B*D&8+tr#@2S9k_X(nPYaFk2TaS?3Ud(O@?!Y>T!XyAf z9Y^1+mm0QprVlLFq<XY$A?dM%V)ZI%^Yp-#9c%`i&g&SBtAh)j1i28#x)C121t((x zY(S*8SI7&6K|eVj-fCzmSIeELgSdqb*7DekvHsKDAz}E(xI{`i@H;{F>*oNCkG-yf zQFJx4Q@u8QPQ0CiPITq&R`IM$KjVN3L<m8Qz0|oje`?oqURS*@)^E=(#2(AaA05tt zj-2;HHb07y!N1R3uUl`5;D-({_6CJSh@2RbV-?`wlrPR)ZuQuq{WKQgF<Eoo9bAB4 z!z5&D!yAj#D<J|j%fd~24wKSlLt4)PS82ahxSVjUYFezVlJ`?aThfi>0_dU>vNtam zd~!CwNf+I05h}Iu_6po?15RaRe#VY`qA~pZXLl0SGh9qa43y@2`2!ZuV#K6dpc9cA z<I@&REx@^Ryq#R!`4UihBM0ONOiCjD?FV{qPVss^H2TaV^AHQ5JTc~^Mw_<0$FXzw zv6e9iFBED!&iq(fE;gQc@|{e3W7GUzrHW@2s=O<W@=>-#cc<OEb+z~XUIgqr@cM%o z$BiT!q5&~UhN~ngNL>3d&6cAtHUQRX^vso2t8Vb^0!dW`Q)yjH?fu4z<w=dN<}h|i z<j+$^>Z?DBB2c7vG%{lIxdb0q`W<$Y_Qa7hLGvuOMJN;l#9wg2DZZmn*|fECamPcb zT(7F#S?!>Ln6}>QJ8q0Pe!p;H=`0b1D|AD+v&6GPuA+USWzTBT^~`!odgq0Bt~ntn z)omlfo_jm;q|SEscHGSGK)L9;j@+NeY*H;b&J+(XSxtBE+XKw6e-}pCpQ=wPyKp?? zeZ<$22voJuq()v3@gy#?#6MXal@`gKNbJb2&XSA!Vun2x3vB#7il615^Z=^WY?(=t zD>dwYhrIrE*%l|W*<CB-oXVl%hMsm_`&PCXl-6qQK&hG6W50SHkaycsK9vL`h$=FR zsh4O0*^QVpNxz3w(wBg%zt1?eEk^Q=$ez7$e$G4_o)jSd)KtLV7H~dn{SiG^U>&vY zoP*7Lan3?^2F?(8WMBVd%`AmPlZ&KOwxyz&7{r(vY5ROUM*7;by!|Fgf+u|X$!F%l zt||7*s>&2P?NpEU3*VmHDBIGxHuI<J+;Ie4?WPA%+4f&X$-A$;hILOfLQuR(YygHT zc&hH3t`cXh$YulM!sf+<BmvXKK=89fH3Zhu&x#Tf#V=ofoW7*<w=$V{lj~fNGSUH< zt1ThDUZ=7@Ei{uSE2bpqdSm(Bt6;Y7=qqf6s?@WHI{c4e!bW4fQ_q3v0U>Gpno$EM zUb=F45DW&6H%7u`<_f~Y$XZtiD|6mQ?V(-G<hFIjo%RAywH|Kkbr158G3qkA#~^XY zck9r#HQwbnS1s-pY`@UD0zfH{FamXS%i8}2UX}Nb(*QyP8rtx5j}567?$nhCCJp0n z3A-!tmvzHeqik4>3QDW+3M7Aa!#7WgJN4;}X`0USTDJHo+q9G@g(ZgTH+iS`9yHp6 z?Iq}Sm^p$P{&|S@;=#o6^oC*Ift)F#AxqR1jt$rw@sz<2;C;pTNCaa~0_&Cid(|2Z zqx^7SrJwsZ!=Hb&8G8<7;Aw!_Q;5XW(d7n`TxINoiickaF=mZ`-MaLKEn0!M)WMi5 z>aoWYSC-ixJxNm;P_Lwzb)~g@T^(H3G=6YQ@3+xW<eG<<AY;NN19aaXl4XQ6jL<QO z&{k77;$+W;6WDCIZHr(mfGnla5hb^B4}EZc7#1$EEX+mxuFSbpR_fUvzl9dO1@|@B zvhOu;kUes^tIJPr^GR9-d60_}ulhcz2oEQ5B|<*@*H-xYHu#Aa!PVLB(9>ZnN_KTP zR$qSIf>Ya)yhfYbriQ~}!<bN^n07*M<h&a<iTe(T`D7!wzN+f=$^NqB^a>{A2OYMY z93{3Kd^dX|HDc#(Lil1~y?U2*mO_tU?<S_@sktSu*T$BOE=;&{<^$=*_t1>=VDCP~ zJ8N&&LPd?Xb3&=#y2TP95U=;d_M`5c<&*KS*DtZHVq`D|BI&BHOV;=oFPn*{#TZ&} zd&iBJZLnYGo6WYI*Qy#ID-zC}>KE?p3cU)TyyBWy%AND}O)1E>PWzEts;EV}-V+`( zp=im9fp<ocjxX+!AvcBu%h~T=jgA@fl4^Ik5y6~Q2X*HV^w&Ke;FQV!9$fxAj6ZQQ zxI*%0XI%LqpP26MQ)3y+C1Lz&^XjX&yjU6j5AE+z_9s-yp{9Z_WPciTJ4|7BuS~zF zoR&G92H#yjN}zIxP;?rUwJIEa>n`2!K`5NH<E6RR-1Rn+PCGbpms{oxru3#T%7Bo; z$&22(v~$*YN%qgy5j88go}73E`Q{>#!wnZ_YQt5pBHJo9=D<4<eX88jR7^HCH1hs# zyLzls-h-G*F@+J-HVlOB0q7Y!4PDfs5CbCAkN!wEN-9-05rcWWnG;MhJpZU@E}o6W z)9XLDyBe3eyk}aV-$RAWCS#z|d?91>|6HRHPWRVnpY{&RKtt~H>?cEu`{a$#5lSv~ z*>bbqt49vEzE4wYF-;DXACE~CEtRC!Swr#+dkfO(r<2WH884>9)7E_Qzr64_Cm<i} zp;(MMlQ<^=tu=8;^j(zVY5i9FK6*XMo8P1Ctk$)(?ee)p(c~x!EZiDyn0NJ-4WZZg zNX9rL0;(^^pgAx@z)Uh<D<#TC4EoBI5%66}RnjD|4}<ll^O-`tLFfsMj(Jy%4#Uz3 zF2^!s_D_Tw`R<mr>z4+*=TnfP3tXE5G!AZz5)n~fwfl&Prq`IHFObm_TH-A6U28b) zl$*Pg)-y9==Wz9FvG{5v&1P&`k~G|F{}L0hq9bfUu-8COmN8MJUrl*gP12EL_dj7< zaZP<**X8-{8cEn&XP;EGj+)fBMET~ZT@QG#uBSERRZbTXlh=lsoY<o%iZXUu+hYPP zE$XQ|mQ25RKUSE0da3>V_23~@ET|&LK=L+}*c#lnl4NN*z)+5K=e?&jt5YADKBa#4 zC%d^^KxT|0!NK=&C}q8wlQ#AV6%Ua#hJi&uuO%yt%n2{*UoPzJ;*%4`lf8bR{2a{m zal-Fx0j8ftA?MU0Zm_5=8fH%Yx{&^g_>J|m0EL=#`BSMn{`37+6He5luF*#ht0l7` z9zYr+`_gjOp2%+QtdkSKH(z~{`Gtb`*BoC*n|(qs!&!4V!&J7;Tlv2dwM^H-;=dG` zDOYoKL-g=LF0S1_7?<kgS4vm-8;;NK9EZ5Kw#5ko3fmwXM)8ZJ!1!y@_hPU*-!A?9 zw#~9fe&JI1sz$JG!om#~a0`frr~;A>vNT{ru-7jj*e`Ag7e%@8*s#J(&*LdfWgPHV zt;}p**(}|?mGUk7HfjWSN{{@rg#PX||9R9yD;OD`$^QQ1ZiPp?wPy~LXrvYtd7Ut( z8vf!}DjkUXcjZ2h{DAw?$31leQKmnAG~`jfM!1`;^W6=er&PGD5Xh+JDuHWN7q&&Y zS5PwIWvhEP+$pu;e2y7w=}kA&OQvB%AI}hhW9k^^cY+R^i_{&F41;k~8OAn3+dc_8 zZH?FIGpWbaEQ}n6V^nUq;x09M!-oEdE#UMH<QFCWN0K9<k{d7KtJqY4&Li+e&;HJV z{7Pn!B?E?#m|;Q7Nrsn2C{ZIlW_S`I3GPVl_h;Tf?38sT=*Br`&tda^d)LznhI4ks zp3@IqXy^eK)9p*0#h^av*K012wXD?D!FT!LKO%X({gW$~OIMu~VHfS)u}_AKy6yJU zXcBpQj80IoRtKO*Ihx>yuUWX;CsyB3cR-ty`c<(<JuNtBo~xL4JICprcJ3JC){#Ea z0&>B^YYj~5DnV`a^WyGteb)_G`XrLkI*Mj!#f>Fk$uPUR`FNg!%@{rF%|!%lr5EfX zhAmN`w4~%~X6F8{v6UI44pi-V$~F1dk3ZbOhZm%v8f&-@?yS+TL+SgAN%2ci-gUdD zcu2q%kTZ^sKd(iBrgN3;-@wrV%!cElt~cbKD?WgIpqS%^W!X!Mt46JTIbx6%X(V;u zpkv8hodCvb<mC+0k*o!!95{rgm~u-eAZ4Kg7~giT`Mi)T6k?MTNuV<6(f*Y5Vi;E5 z1)0PK;5xl@4d4$C`X219DrU_g3<lmEaqJmdbA4{Jpa&sFv9l?bO=pJBVUBlw8?Fk* zZW8=%$OZ8V(?Nnlmci4zOEQ<oj#7ry^Wj6Zzp(0=Q8~*@;vW<1B0Xm^k9hoZ7Z{ke z_{ZQ{m;jqM&#U+0A~p_Jrre-GFDmx0I{QEN-hwJ#h<aO3%`k!QI?VhKmSW5}n`Yr+ z#g`tE5<V3#0f_tX+<yOO@_>a5>^ES!hAb+VQ9q-y=;fS$@SY<s?$i`(fG2*y@mN0C z#nb8_o|<x$4VvH&3VS13>q&u()yh4&hx$g+OB=fyLx>Mu*h(b`cl8%s%EwgQW!SJX zGGZG`H5p34$Ej5&OtOZ^lP$HGencQ4M&KgeLw;P$T|Q+3hlNKG>cW(Y(<;tTX#IQ$ z?}(0NMm6<uNC=;=)7XXym@7_zaFu3<|G1omXTL7ULrmV6qiVe6_Z+<iBE^w)ZOZKV zt|f((dj+*8O(@j3^$W&_%|8u+xQE?)uX?E48n?@1Xq2?JW1WG?4cR`)Lijo)<>_An zKraG)g;qk3rajzR**A9cMi#hUn?1u~vCOUBhFcjVEwagMlh9cYyR7njt$qS1J8wxl zyfS}IJ^;k`d6YQ%y@bc^?9;Z3+_C&2uvLIw^@zw)7(qKGi*m=SV&?9G>R-_fT{<Tf zOjb)tNK3l=hxv(&g+g%Xp)GJ#z-$Sg)vZg>VPomlb!qbP4aqM3sOlBjjXCefW&$qH zMynUHze+avcK5@yo$vN`y`29<`kV!PY$DV*kGd!c?4iogk7r@haanS3pT=E`4`*TC zF13elAJzXZBW@73gX)(0QS=O^MMS+=Qa|z+r@w67NyAj;xoI`dJtxO<!>QxS2$gbt zCu8$1h-6)PZ&RzW5I>3hM(uM+$!At>G?`O{4>40Xv~u#Ult5`x^1PtyB}C1L30f}z z$uojDB3c^V*;lsDmjj*F)W+Z@lcc6oVKby=Q_Ic!t(28Rd0ciQ7YWE6pxxU;Z3+Ak z$k%gICag7Ko`qAYFOcNrYON{NW(P4V#ALS(yBK5U^9rksw}oo)VWm#gaiz_L3(Jnu z=EWU*)K2DqTu{eiZt1@Nuz~lL;#a?kaXAt_w8>U7(L2^2>VW-7fBM+;rst0f!rn-0 z&_)Yr(1vh}Y0Xe$yD_2P#pX$}YLM1Ao-C3&@8hWGr#kC8DCrvo5E0UN>XA(GFTG)^ zX%OsNzMfBxUpl>_PI35QbZU;TjqpZM=h}%`!mohcjS1KQbhvo1ug{l5iDAc)*t?Fd z+Q1rnL&+Qbwf?xGFALcthbN2Irq3QuL}o<!GT&gKhZxW1pZ4yV_FcNTCZuu4VmVXg zDS^L9_%4fRifIiJA5@9>*dok!UdKo)r$*v$sVOJ3L^>M{PbVXrUNk;ltxy9rP8E<B z1hdfJWJWCZp<hU&>F~91_qf_~rvBi4QhVG4GwWe^PvU~%Aw5uF#w-pF6HMap#KN(% zTw-XCY|n64<Z4PUiwA1w?o0?)`uW>Eg^V^#89kU2HgmH}2`dP0Uin-LCbADStmfe@ zEhGzLQmCNVZPiGz4nm2g`(IIa4=l~8tbZ{$*`6g({=wg!-LHB$tNC>Jku!BM)r<54 zck++2+ZB}o@M~3BgP5rgrj2+#zMN&nWTOD}8jpw5qDKW6p0vLxV%o(;vTbV@+pS#g z?pkFK+c;k3x0=FM6&5I^cQXQ0MMVzG3a|kfk}U!-|JG_kAQyXF)iLP1sswqs42(<N zv~Un*|CrpY3{QF~lg1^mfAIRaWHEEzkACJVWUKKpaisk{Xw{ml7J;0?!w0mt962=J z91Uc@Cy@-2!DI)%x}3<oWenDUjCnA=>)vXa4ka$lH9tAMcNejtl;6Xm--?W<)+L}0 zOsT|RIvJfv)8)Xp(3FqS|FXM}P<;8xiT5KF@hK^`YdQ*Ud+dc#kWQvCfvviXs%=9C z(=|Ys2vhr7+hXifZn>($>D`T$-7>Ba$or7^_gh_}=kiERE~s1E?L)Dz-XHQL#4C33 z;~)`<y^*>(cdE<`g4Gx*>eyhzg|^nku>29OpH?&8=!3ekxL2i$P3xCtM(960Ku>s> zZ(y4&cg8qc3k$&hXa6GQ`&joRD1ql_teKKAHrwmZd)}RV%ad;g4?d3~p(JNF9ttan z{My8Z88&D`XaDTygIVY2fVzbra_=(e{|_b?wEF220VoG47a?P!prxk%9HKK&qFoyM zIJH*rDHfo%H<9!E-`K@Hh(Sg9WYP@!_SJ9U*_<5uq8qloZ5<<Trn8+na|2BTyU!l+ zNSL2W$(c48&xcdFth!K$#gll8EoMbNWCyV7F;+z&S2^t{t)Z%@uCUebgY)Iz6Y2J_ zx#400qfYMvybo}RPjv+1(o=V5%gvSE-=PoONr0E?cK3vAOC6c}$jF!`q5R}r$z$X! z{Myy;w#`>vS2whio}pIWKF0OUuuN|(YQ-&_T{{#HB>9<t;jE;jwq~jlHqQSlfH}fp z<>|34zK%Z2C$3k6gmVeY>SKil%Nfr_r|BLN2nApkaTf*9HJ#}CVsa$1=5~Ga64TOZ z-a9*KZP;ggYuerSS?*sZ@%9l5%|ppJ!X*Im{%<+eoz$d6M88|F_ujlkZ|Ssk+&^fN z_>vD&C=<b+>35_cb*jt8|HMuctPsi*A1OdU=l<e3AVR71c011qj5%C9z@N*AXbVX@ zI#`L|+wK=%sPq}b5)A?8RrMK`Dw@jd1A^3jk<s#5DTKw5d)f)VS`<57av8_5w*LZ_ zejdubQV;5;|90<n>7>KF*3~Nei*&HqMPg>p7%%~Xiyt4~zpR3?kuO^ZaB~X|>z;S3 zzv}tS-FngS3t~>3Dd?0@YabG!nZ45RuQ>m{-?xVNAH$!xqQoo90le?g0_q6%>BjfH zMc9H7b?rWVghiaDOpsuC_Jv3YSttao(5+iu7eZ`LMh?HqJ`Y_QtCXg!5zBv?nr30h zYiwVlb~*GgA@Gb1alN`QTdTV0zGX2W^`}nEEs=_tog26t_Gsc7XyP)JpFC|}1R(c+ zw43%;yK0?;em`s&bELs7oiRPrd8a2q$!i5F{}%zsOYlY8MBRuz(bUkp1&ja$EUBp- zG7zHu7)_acb|)cOuy~O~hlnTgpZ+edcpt?{T(MSFSMT<d8vF6$(ujTeu+;P?#X93% zDX7c=@4JNz<mSdt>~ih9hw);u<fB?T=zIN;v->Axa6ma%U~3v>gE7+f?s=;`7a|b- zn8J#lBQ`+cMcH)evnvaRQ6qQFu;7OHK*ggA{B|BqOIl+2*`f{Up}~IHYg!p@lx_}` z?5RF^YXA3`{XV5ext^g@PW(-&!>vbQ#!*kc%={(lPsXg)h7zj3at%}>Bao+AA;cdd z@b4!>COG|nckTb|T_Fj~jg|gXe*1$_X*}{vO|1qVcj!^sU@AYh<Yk{K!LzsOOr~zN z8kGVe#I-`BPC+L0IrmwG@+*;gSw*+`cDb;4_V{uS6${hu(BSZYOdFFx&6p1&2W)vX z5cC-1MO>m*fUVL;tX@C<dRUHFD2G#aQ)-$IUQyt5o!wMP!tE>AJQDD4sLlh-E~&TY zvg$N|?(X)`f!&3ARUrlVmQE<X@BKSDI6=&b&M>8=mqj?H$Y5-)PXzB4^<U>iP9<hG zRGD@@yE)FhtBGVn15KH1Ll8J>;KTKf>VITAB)nho>?{Jw1+bmc4*|{(&VWP@LbhY{ z`7#4HH=ee(c7&ES^}izgd%i&)^C9uA{q4==^C!V$*71%tMMb|30!(wREEEb_100_N z>=Hgd!|CuwrCZ|(5#I}vtZ$$m97zDuXjBI)Fe#UDVgV>#?8X0m2<C-+%KRzyj)}?3 zpR)0w1Dn@l2fV!P?j3}<XV`!E|N91d&ydxkv)6k4fz=7}zV05l>QuB`?TNV;F<s=9 zn*KeH+;n81ps4s6%iPe&C}VuCNQ`TDzV?k+c7o0Kt(XpANkr<dI=Gk#=8*We1wYU+ zaDK|wcH{Cn1WU2|t8wjJf!a#{S32pfAy*mi5~zNC?0M6f6Tk02DIkC8;M1r6VwX9~ zB=Sb>oCpq}lDbsn(JQqK_C*STpm`z?#n~W3Tx<u>LITq`9~RFe0%H7!u?c#n__oZ) z4$<PB9#>IQQ!{*R@h@BXYhk`Ve@M)%<V{!f{>;wUk-aOazc=Toh-XoUUTeDoH<Z}v zKF_12k<mY~133PC?r$~z1Bm}e<*hhD7HkD4vm;V4DQ`prtUy6W`R^0?f9pkZkM6tw zqj_&9@h7@i00jn%$N!kif32L#f4cA94-0@Wh?h|O%gh}9IUoLOC5s00-VDQ3O}l?6 zj$5-q8DqZU{D;*4&zvS19^Q9<zy|elRk-2^h2-H^{iDzSS_$&`%fV1e+-r+VA@hC- z_@o5>Ee-BJ=izNeyY=9~qZNhs@3j6W4?->O2`kjA)5)!KkXMdUP`K}!eS}%*QwOkP z1N`l8!};%1d-(ER-~NOYhN89?V<cs&hpqk9n1uId&41Xyf0Nnf!C!+ehsY+yHJ;i0 zh^}s_ICAK?Z)1#(C06*aqy61T@!&7@2xhC-mvRaFv_nXJjFEF8_exeEqXzu5(f+H7 z`5yeW+)h%tC&weA^X?{iHDaX@Ps|MEFAqW?A+Sn<|2T;LcNcFT)7`82T9!{_J1tgj zWW$e{t6__NpFr%#%X^71P0gA9<LLO`))w?k>fUtDV{9f1I)&xpCMUBd@+EtONi$J~ zk=CosZ%vs#SU~@Om+gO+YV^}{H85ryIV#N+m!ejpd1*{G=2MR{MXq$*@y9);^iIVi zrNw(CcEv;!|I2Ott+;=0q4-PW;UC%WA#Y!Ok}a%Pl=K-_VEGeH8=JL$U|O?1PqRsy z5e2f&T!*&jHr$UIflZ42@1flPR?Y)VKAwB!1`FmX{}8a5t72+$-wvyDT*w(C-xZ~D z<ml-C#vu3cWJ8^*SU9>znR4|c)^W6{liX(NjIYMV9g8A!u_0(_JWQMl3xIQd`_b(` zt@d9TJO8Ks8)jNj2e8^|=;Ky#VUF!Yfz4RX)B7+b9G6-oOS=@*b9jg0@B#0dhwM|z QgZrO?jLQ3RDU;y;54LYRSO5S3 diff --git a/_images/release-process.jpg b/_images/release-process.jpg deleted file mode 100644 index 9868404b07f3c96ce316122f012b52ca176769ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 315886 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⪼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 Gb!jVMiNHkB=&84I}V9H<0*(14jk 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 $#8Y?eX?b3TLMA$o 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%0DgoarE%x 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 X1N&e@3_$U<_~;*|g(nRcjb8gVC~13+ From 132e0b962a1bf64f2a127871a19a01cc19fd4cc5 Mon Sep 17 00:00:00 2001 From: Einenlum <yann.rabiller@gmail.com> Date: Fri, 31 Dec 2021 11:38:38 +0100 Subject: [PATCH 1370/1519] Use a backed string enum in the EnumType example A backed enum must declare the type of backed enum. Not declaring it is not valid. --- reference/forms/types/enum.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/forms/types/enum.rst b/reference/forms/types/enum.rst index 51fefe016f0..4e598f44e81 100644 --- a/reference/forms/types/enum.rst +++ b/reference/forms/types/enum.rst @@ -36,7 +36,7 @@ short) defined somewhere in your application. This enum has to be of type // src/Config/TextAlign.php namespace App\Config; - enum TextAlign + enum TextAlign: string { case Left = 'Left/Start aligned'; case Center = 'Center/Middle aligned'; From c3f359ee1024d0bbc4d5ead6a4be83f41075a641 Mon Sep 17 00:00:00 2001 From: Samuel NELA <hello@samnela.com> Date: Fri, 31 Dec 2021 23:40:24 +0100 Subject: [PATCH 1371/1519] [Doctrine] use executeQuery instead of execute --- doctrine.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doctrine.rst b/doctrine.rst index 3b6a5b46cdd..f04a98c53d9 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -851,7 +851,7 @@ In addition, you can query directly with SQL if you need to:: ORDER BY p.price ASC '; $stmt = $conn->prepare($sql); - $stmt->execute(['price' => $price]); + $stmt->executeQuery(['price' => $price]); // returns an array of arrays (i.e. a raw data set) return $stmt->fetchAllAssociative(); From 0ec5a2cff34dd84e50263efb591d4ba079f7f653 Mon Sep 17 00:00:00 2001 From: Rosemary Orchard <16113535+RosemaryOrchard@users.noreply.github.com> Date: Mon, 3 Jan 2022 20:05:07 +0000 Subject: [PATCH 1372/1519] [Cache] Fix Cache Couchbase duplicate page titles --- components/cache/adapters/couchbasebucket_adapter.rst | 2 +- components/cache/adapters/couchbasecollection_adapter.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/cache/adapters/couchbasebucket_adapter.rst b/components/cache/adapters/couchbasebucket_adapter.rst index 9ab637eb38b..898f06c45a4 100644 --- a/components/cache/adapters/couchbasebucket_adapter.rst +++ b/components/cache/adapters/couchbasebucket_adapter.rst @@ -4,7 +4,7 @@ .. _couchbase-adapter: -Couchbase Cache Adapter +Couchbase Bucket Cache Adapter ======================= .. versionadded:: 5.1 diff --git a/components/cache/adapters/couchbasecollection_adapter.rst b/components/cache/adapters/couchbasecollection_adapter.rst index f3aff72e6ac..23cd24d565b 100644 --- a/components/cache/adapters/couchbasecollection_adapter.rst +++ b/components/cache/adapters/couchbasecollection_adapter.rst @@ -4,12 +4,12 @@ .. _couchbase-collection-adapter: -Couchbase Cache Adapter +Couchbase Collection Cache Adapter ======================= .. versionadded:: 5.4 - The Couchbase Cache Adapter was introduced in Symfony 5.4. + The CouchbaseCollectionAdapter was introduced in Symfony 5.4. This adapter stores the values in-memory using one (or more) `Couchbase server`_ instances. Unlike the :ref:`APCu adapter <apcu-adapter>`, and similarly to the From 2a4693f8f5447c98752232feeb5d9d555836196e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Tue, 4 Jan 2022 13:20:09 +0100 Subject: [PATCH 1373/1519] Minor tweaks --- components/cache/adapters/couchbasebucket_adapter.rst | 4 ++-- components/cache/adapters/couchbasecollection_adapter.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/cache/adapters/couchbasebucket_adapter.rst b/components/cache/adapters/couchbasebucket_adapter.rst index 898f06c45a4..cc99db1c967 100644 --- a/components/cache/adapters/couchbasebucket_adapter.rst +++ b/components/cache/adapters/couchbasebucket_adapter.rst @@ -5,11 +5,11 @@ .. _couchbase-adapter: Couchbase Bucket Cache Adapter -======================= +============================== .. versionadded:: 5.1 - The CouchbaseBucketAdapter was introduced in Symfony 5.1. + The Couchbase Bucket adapter was introduced in Symfony 5.1. This adapter stores the values in-memory using one (or more) `Couchbase server`_ instances. Unlike the :ref:`APCu adapter <apcu-adapter>`, and similarly to the diff --git a/components/cache/adapters/couchbasecollection_adapter.rst b/components/cache/adapters/couchbasecollection_adapter.rst index 23cd24d565b..100acf14faa 100644 --- a/components/cache/adapters/couchbasecollection_adapter.rst +++ b/components/cache/adapters/couchbasecollection_adapter.rst @@ -5,11 +5,11 @@ .. _couchbase-collection-adapter: Couchbase Collection Cache Adapter -======================= +================================== .. versionadded:: 5.4 - The CouchbaseCollectionAdapter was introduced in Symfony 5.4. + The Couchbase Collection adapter was introduced in Symfony 5.4. This adapter stores the values in-memory using one (or more) `Couchbase server`_ instances. Unlike the :ref:`APCu adapter <apcu-adapter>`, and similarly to the From d913e63460137291bd357ade245de8d71e9e804b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Tue, 4 Jan 2022 15:46:23 +0100 Subject: [PATCH 1374/1519] [Security] Move Passport Attributes to their own section --- security/custom_authenticator.rst | 52 +++++++++++++++---------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/security/custom_authenticator.rst b/security/custom_authenticator.rst index cd18e7bbd81..bc5a8ea7b30 100644 --- a/security/custom_authenticator.rst +++ b/security/custom_authenticator.rst @@ -342,39 +342,39 @@ would initialize the passport like this:: } } -.. tip:: +Passport Attributes +------------------- - Besides badges, passports can define attributes, which allows the - ``authenticate()`` method to store arbitrary information in the - passport to access it from other authenticator methods (e.g. - ``createAuthenticatedToken()``):: +.. versionadded:: 5.2 - // ... - use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; + Passport attributes were introduced in Symfony 5.2. - class LoginAuthenticator extends AbstractAuthenticator - { - // ... +Besides badges, passports can define attributes, which allows the ``authenticate()`` +method to store arbitrary information in the passport to access it from other +authenticator methods (e.g. ``createAuthenticatedToken()``):: - public function authenticate(Request $request): PassportInterface - { - // ... process the request + // ... + use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; + + class LoginAuthenticator extends AbstractAuthenticator + { + // ... - $passport = new SelfValidatingPassport(new UserBadge($username), []); + public function authenticate(Request $request): PassportInterface + { + // ... process the request - // set a custom attribute (e.g. scope) - $passport->setAttribute('scope', $oauthScope); + $passport = new SelfValidatingPassport(new UserBadge($username), []); - return $passport; - } + // set a custom attribute (e.g. scope) + $passport->setAttribute('scope', $oauthScope); - public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface - { - // read the attribute value - return new CustomOauthToken($passport->getUser(), $passport->getAttribute('scope')); - } + return $passport; } -.. versionadded:: 5.2 - - Passport attributes were introduced in Symfony 5.2. + public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface + { + // read the attribute value + return new CustomOauthToken($passport->getUser(), $passport->getAttribute('scope')); + } + } From 10bc1f2ef1f1038c496deef409ff03decc754965 Mon Sep 17 00:00:00 2001 From: berbeflo <48961978+berbeflo@users.noreply.github.com> Date: Fri, 7 Jan 2022 09:44:14 +0100 Subject: [PATCH 1375/1519] fix Password Hasher php-standalone example the php-standalone example for Password Hasher had a configuration for User twice, while the comment and other examples indicated, the second should've been a configuration for PasswordAuthenticatedUserInterface --- security/passwords.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/passwords.rst b/security/passwords.rst index 6bf37d51806..e30e517f895 100644 --- a/security/passwords.rst +++ b/security/passwords.rst @@ -101,7 +101,7 @@ optionally some *algorithm options*: User::class => ['algorithm' => 'auto'], // auto hasher with custom options for all PasswordAuthenticatedUserInterface instances - User::class => [ + PasswordAuthenticatedUserInterface::class => [ 'algorithm' => 'auto', 'cost' => 15, ], From 4c5ed02bb92f91d30fcf4ae71510935b0c34a555 Mon Sep 17 00:00:00 2001 From: Ryan Weaver <ryan@thatsquality.com> Date: Thu, 23 Dec 2021 20:04:59 -0500 Subject: [PATCH 1376/1519] Adding docs for Stimulus, Turbo & Symfony UX --- .github/workflows/ci.yaml | 2 +- _build/redirection_map | 1 + frontend.rst | 3 +- frontend/encore/installation.rst | 55 +++++-- frontend/encore/page-specific-assets.rst | 27 ---- frontend/encore/simple-example.rst | 189 +++++++++++++++++++---- 6 files changed, 202 insertions(+), 75 deletions(-) delete mode 100644 frontend/encore/page-specific-assets.rst diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6c10a4eaf9b..6750bd8eb20 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -118,7 +118,7 @@ jobs: - name: Install dependencies if: ${{ steps.find-files.outputs.files }} - run: composer create-project symfony-tools/code-block-checker _checker + run: composer create-project symfony-tools/code-block-checker:@dev _checker - name: Install test application if: ${{ steps.find-files.outputs.files }} diff --git a/_build/redirection_map b/_build/redirection_map index 1acae2a1667..e7146d2fc2d 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -513,6 +513,7 @@ /components/stopwatch https://github.com/symfony/stopwatch /service_container/3.3-di-changes https://symfony.com/doc/3.4/service_container/3.3-di-changes.html /frontend/encore/shared-entry /frontend/encore/split-chunks +/frontend/encore/page-specific-assets /frontend/encore/simple-example#page-specific-javascript-or-css /testing/functional_tests_assertions /testing#testing-application-assertions /components https://symfony.com/components /components/index https://symfony.com/components diff --git a/frontend.rst b/frontend.rst index 30202523b41..4272cb8338d 100644 --- a/frontend.rst +++ b/frontend.rst @@ -40,7 +40,7 @@ Getting Started ............... * :doc:`Installation </frontend/encore/installation>` -* :doc:`First Example </frontend/encore/simple-example>` +* :doc:`Using Webpack Encore </frontend/encore/simple-example>` Adding more Features .................... @@ -67,7 +67,6 @@ Guides ...... * :doc:`Using Bootstrap CSS & JS </frontend/encore/bootstrap>` -* :doc:`Creating Page-Specific CSS/JS </frontend/encore/page-specific-assets>` * :doc:`jQuery and Legacy Applications </frontend/encore/legacy-applications>` * :doc:`Passing Information from Twig to JavaScript </frontend/encore/server-data>` * :doc:`webpack-dev-server and Hot Module Replacement (HMR) </frontend/encore/dev-server>` diff --git a/frontend/encore/installation.rst b/frontend/encore/installation.rst index c53dddd5d3f..eb4b82e8b45 100644 --- a/frontend/encore/installation.rst +++ b/frontend/encore/installation.rst @@ -82,15 +82,13 @@ is the main config file for both Webpack and Webpack Encore: /* * ENTRY CONFIG * - * Add 1 entry for each "page" of your app - * (including one that's included on every page - e.g. "app") - * * Each entry will result in one JavaScript file (e.g. app.js) * and one CSS file (e.g. app.css) if your JavaScript imports CSS. */ .addEntry('app', './assets/app.js') - //.addEntry('page1', './assets/page1.js') - //.addEntry('page2', './assets/page2.js') + + // enables the Symfony UX Stimulus bridge (used in assets/bootstrap.js) + .enableStimulusBridge('./assets/controllers.json') // When enabled, Webpack "splits" your files into smaller pieces for greater optimization. .splitEntryChunks() @@ -112,6 +110,10 @@ is the main config file for both Webpack and Webpack Encore: // enables hashed filenames (e.g. app.abc123.css) .enableVersioning(Encore.isProduction()) + .configureBabel((config) => { + config.plugins.push('@babel/plugin-proposal-class-properties'); + }) + // enables @babel/preset-env polyfills .configureBabelPresetEnv((config) => { config.useBuiltIns = 'usage'; @@ -124,16 +126,15 @@ is the main config file for both Webpack and Webpack Encore: // uncomment if you use TypeScript //.enableTypeScriptLoader() + // uncomment if you use React + //.enableReactPreset() + // uncomment to get integrity="..." attributes on your script & link tags // requires WebpackEncoreBundle 1.4 or higher //.enableIntegrityHashes(Encore.isProduction()) // uncomment if you're having problems with a jQuery plugin //.autoProvidejQuery() - - // uncomment if you use API Platform Admin (composer require api-admin) - //.enableReactPreset() - //.addEntry('admin', './assets/admin.js') ; module.exports = Encore.getWebpackConfig(); @@ -154,10 +155,8 @@ Next, open the new ``assets/app.js`` file which contains some JavaScript code // any CSS you import will output into a single css file (app.css in this case) import './styles/app.css'; - // Need jQuery? Install it with "yarn add jquery"(or "npm install jquery"), then uncomment to import it. - // import $ from 'jquery'; - - console.log('Hello Webpack Encore! Edit me in assets/app.js'); + // start the Stimulus application + import './bootstrap'; And the new ``assets/styles/app.css`` file: @@ -168,7 +167,37 @@ And the new ``assets/styles/app.css`` file: background-color: lightgray; } +You should also add an ``assets/bootstrap.js`` file, which initializes Stimulus: +a system that you'll learn about soon: + +.. code-block:: javascript + + // assets/bootstrap.js + import { startStimulusApp } from '@symfony/stimulus-bridge'; + + // Registers Stimulus controllers from controllers.json and in the controllers/ directory + export const app = startStimulusApp(require.context( + '@symfony/stimulus-bridge/lazy-controller-loader!./controllers', + true, + /\.(j|t)sx?$/ + )); + + // register any custom, 3rd party controllers here + // app.register('some_controller_name', SomeImportedController); + +And finally, create an ``assets/controllers.json`` file, which also fits into +the Stimulus system: + +```json +{ + "controllers": [], + "entrypoints": [] +} +``` + You'll customize and learn more about these files in :doc:`/frontend/encore/simple-example`. +When you execute Encore, it will ask you to install a few more dependencies based +on which features of Encore you have enabled. .. caution:: diff --git a/frontend/encore/page-specific-assets.rst b/frontend/encore/page-specific-assets.rst deleted file mode 100644 index 8f03bfb5877..00000000000 --- a/frontend/encore/page-specific-assets.rst +++ /dev/null @@ -1,27 +0,0 @@ -Creating Page-Specific CSS/JS -============================= - -If you're creating a single page app (SPA), then you probably only need to define -*one* entry in ``webpack.config.js``. But if you have multiple pages, you might -want page-specific CSS and JavaScript. - -To learn how to set this up, see the :ref:`multiple-javascript-entries` example. - -Multiple Entries Per Page? --------------------------- - -Typically, you should include only *one* JavaScript entry per page. Think of the -checkout page as its own "app", where ``checkout.js`` includes all the functionality -you need. - -However, it's pretty common to need to include some global JavaScript and CSS on -every page. For that reason, it usually makes sense to have one entry (e.g. ``app``) -that contains this global code (both JavaScript & CSS) and is included on every -page (i.e. it's included in the *layout* of your app). This means that you will -always have one, global entry on every page (e.g. ``app``) and you *may* have one -page-specific JavaScript and CSS file from a page-specific entry (e.g. ``checkout``). - -.. tip:: - - Be sure to use :doc:`split chunks </frontend/encore/split-chunks>` - to avoid duplicate and shared code between your entry files. diff --git a/frontend/encore/simple-example.rst b/frontend/encore/simple-example.rst index 8fa55913d69..64115878107 100644 --- a/frontend/encore/simple-example.rst +++ b/frontend/encore/simple-example.rst @@ -1,11 +1,14 @@ Encore: Setting up your Project =============================== -After :doc:`installing Encore </frontend/encore/installation>`, your app already has one -CSS and one JS file, organized into an ``assets/`` directory: +After :doc:`installing Encore </frontend/encore/installation>`, your app already +has a few files, organized into an ``assets/`` directory: * ``assets/app.js`` +* ``assets/bootstrap.js`` +* ``assets/controllers.json`` * ``assets/styles/app.css`` +* ``assets/controllers/hello_controller.js`` With Encore, think of your ``app.js`` file like a standalone JavaScript application: it will *require* all of the dependencies it needs (e.g. jQuery or React), @@ -19,11 +22,14 @@ application: it will *require* all of the dependencies it needs (e.g. jQuery or import './styles/app.css'; -Encore's job (via Webpack) is simple: to read and follow *all* of the ``require()`` +Encore's job (via Webpack) is simple: to read and follow *all* of the ``import`` statements and create one final ``app.js`` (and ``app.css``) that contains *everything* your app needs. Encore can do a lot more: minify files, pre-process Sass/LESS, support React, Vue.js, etc. +The other files - ``bootstrap.js``, ``controllers.json`` and ``hello_controller.js`` +relate to a topic you'll learn about soon: `Stimulus & Symfony UX`_. + Configuring Encore/Webpack -------------------------- @@ -59,27 +65,24 @@ To build the assets, run the following if you use the Yarn package manager: .. code-block:: terminal - # compile assets once - $ yarn encore dev - - # or, recompile assets automatically when files change - $ yarn encore dev --watch + # compile assets and automatically re-compile when files change + $ yarn watch - # on deploy, create a production build - $ yarn encore production + # if using npm, use "npm run" and then any of these commands + $ npm run watch -If you use the npm package manager, run the following commands instead: - -.. code-block:: terminal + # or, run a dev-server that can sometimes update your code without refreshing the page + $ yarn dev-server # compile assets once - $ npm run dev - - # or, recompile assets automatically when files change - $ npm run watch + $ yarn dev # on deploy, create a production build - $ npm run build + $ yarn build + +All of these commands - e.g. ``dev`` or ``watch`` - are shortcuts that are defined +in your ``package.json`` file. If you use the npm package manager, replace ``yarn`` +with ``npm run``. .. note:: @@ -91,8 +94,15 @@ Congrats! You now have three new files: * ``public/build/app.css`` (holds all the CSS for your "app" entry) * ``public/build/runtime.js`` (a file that helps Webpack do its job) -Next, include these in your base layout file. Two Twig helpers from WebpackEncoreBundle -can do most of the work for you: +.. note:: + + In reality, you probably have a few *more* files in ``public/build``. Some of + these are due to :doc:`code splitting </frontend/encore/split-chunks>`, an optimization + that helps performance, but doesn't affect how things work. Others help Encore + do its work. + +Next, to include these in your base layout, you can leverage two Twig helpers from +WebpackEncoreBundle: .. code-block:: html+twig @@ -130,7 +140,7 @@ That's it! When you refresh your page, all of the JavaScript from be executed. All the CSS files that were required will also be displayed. The ``encore_entry_link_tags()`` and ``encore_entry_script_tags()`` functions -read from an ``entrypoints.json`` file that's generated by Encore to know the exact +read from a ``public/build/entrypoints.json`` file that's generated by Encore to know the exact filename(s) to render. This file is *especially* useful because you can :doc:`enable versioning </frontend/encore/versioning>` or :doc:`point assets to a CDN </frontend/encore/cdn>` without making *any* changes to your @@ -155,7 +165,7 @@ Requiring JavaScript Modules ---------------------------- Webpack is a module bundler, which means that you can ``import`` other JavaScript -files. First, create a file that exports a function: +files. First, create a file that exports a function, class or any other value: .. code-block:: javascript @@ -196,14 +206,121 @@ That's it! If you previously ran ``encore dev --watch``, your final, built files have already been updated: jQuery and ``greet.js`` have been automatically added to the output file (``app.js``). Refresh to see the message! +Stimulus & Symfony UX +--------------------- + +As simple as the above example is, instead of building your application inside of +``app.js``, we recommend `Stimulus`_: a small JavaScript framework that makes it +easy to attach behavior to HTML. It's powerful, and you will love it! Symfony +even provides packages to add more features to Stimulus. These are called the +`Symfony UX Packages`_. + +If you followed the setup instructions, you should already have Stimulus installed +and ready to go! In fact, that's the purpose of the ``assets/bootstrap.js`` file: +to initialize Stimulus and automatically load any "controllers" from the +``assets/controllers/`` directory. + +Let's look at a simple Stimulus example. In a Twig template, suppose you have: + +.. code-block:: twig + + <div {{ stimulus_controller('say-hello') }}> + <input type="text" {{ stimulus_target('say-hello', 'name') }}> + + <button {{ stimulus_action('say-hello', 'greet') }}> + Greet + </button> + + <div {{ stimulus_target('say-hello', 'output') }}></div> + </div> + +The ``stimulus_controller('say-hello')`` renders a ``data-controller="say-hello"`` +attribute. Whenever this element appears on the page, Stimulus will automatically +look for and initialize a controller called ``say-hello-controller.js``. Create +that in your ``assets/controllers/`` directory: + +.. code-block:: javascript + + // assets/controllers/say-hello-controller.js + import { Controller } from '@hotwired/stimulus'; + + export default class extends Controller { + static targets = ['name', 'output'] + + greet() { + this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!` + } + } + +The result? When you click the "Greet" button, it prints your name! And if +more ``{{ stimulus_controller('say-hello') }}`` elements are added to the page - like +via Ajax - those will instantly work: no need to reinitialize anything. + +Ready to learn more about Stimulus? + +* Read the `Stimulus Documentation`_ +* Check out the `Symfony UX Packages`_ +* Learn more about the `Symfony Stimulus Bridge`_ - including the superpower of + making your controllers load lazily! + + .. admonition:: Screencast + :class: screencast + + Or check out the `Stimulus Screencast`_ on SymfonyCasts. + +Turbo: Lightning Fast Single-Page-Application Experience +-------------------------------------------------------- + +Symfony comes with tight integration with another JavaScript library called `Turbo`_. +Turbo automatically transforms all link clicks and form submits into an Ajax call, +with zero (or nearly zero) changes to your Symfony code! The result? You get the +speed of a single page application without having to write any JavaScript. + +To learn more, check out the `symfony/ux-turbo`_ package. + +.. admonition:: Screencast + :class: screencast + + Or check out the `Turbo Screencast`_ on SymfonyCasts. + +Page-Specific JavaScript or CSS +------------------------------- + +So far, you only have one final JavaScript file: ``app.js``. Encore may be split +into multiple files for performance (see :doc:`split chunks </frontend/encore/split-chunks>`), +but all of that code is still downloaded on every page. + +What if you have some extra JavaScript or CSS (e.g. for performance) that you only +want to include on *certain* pages? + +Lazy Controllers +~~~~~~~~~~~~~~~~ + +One very nice solution if you're using Stimulus is to leverage `lazy controllers`_. +To activate this on a controller, add a special ``stimulusFetch: 'lazy'`` above +your controller class: + +.. code-block:: javascript + + // assets/controllers/lazy-example-controller.js + import { Controller } from '@hotwired/stimulus'; + + /* stimulusFetch: 'lazy' */ + export default class extends Controller { + // ... + } + +That's it! This controller's code - and any modules that it imports - will be +split to *separate* files by Encore. Then, those files won't be downloaded until +the moment a matching element (e.g. ``<div data-controller="lazy-example">``) +appears on the page! + .. _multiple-javascript-entries: -Page-Specific JavaScript or CSS (Multiple Entries) --------------------------------------------------- +Multiple Entries +~~~~~~~~~~~~~~~~ -So far, you only have one final JavaScript file: ``app.js``. For small applications -or SPA's (Single Page Applications), that might be fine! However, as your app grows, -you may want to have page-specific JavaScript or CSS (e.g. checkout, account, +Another option is to create page-specific JavaScript or CSS (e.g. checkout, account, etc.). To handle this, create a new "entry" JavaScript file for each page: .. code-block:: javascript @@ -234,7 +351,7 @@ and restart Encore: .. code-block:: terminal # if you use the Yarn package manager - $ yarn encore dev --watch + $ yarn watch # if you use the npm package manager $ npm run watch @@ -263,10 +380,9 @@ you need them: Now, the checkout page will contain all the JavaScript and CSS for the ``app`` entry (because this is included in ``base.html.twig`` and there is the ``{{ parent() }}`` call) -*and* your ``checkout`` entry. - -See :doc:`/frontend/encore/page-specific-assets` for more details. To avoid duplicating -the same code in different entry files, see :doc:`/frontend/encore/split-chunks`. +*and* your ``checkout`` entry. With this, JavaScript & CSS needed for every page +can live inside the ``app`` entry and code needed only for the checkout page can +live inside ``checkout``. Using Sass/LESS/Stylus ---------------------- @@ -347,3 +463,12 @@ Encore supports many more features! For a full list of what you can do, see .. _`Encore's index.js file`: https://github.com/symfony/webpack-encore/blob/master/index.js .. _`WebpackEncoreBundle Configuration`: https://github.com/symfony/webpack-encore-bundle#configuration +.. _`Stimulus`: https://stimulus.hotwired.dev/ +.. _`Stimulus Documentation`: https://stimulus.hotwired.dev/handbook/introduction +.. _`Symfony UX Packages`: https://github.com/symfony/ux +.. _`Symfony Stimulus Bridge`: https://github.com/symfony/stimulus-bridge +.. _`Turbo`: https://turbo.hotwired.dev/ +.. _`symfony/ux-turbo`: https://github.com/symfony/ux/tree/2.x/src/Turbo +.. _`Stimulus Screencast`: https://symfonycasts.com/screencast/stimulus +.. _`Turbo Screencast`: https://symfonycasts.com/screencast/turbo +.. _`lazy controllers`: https://github.com/symfony/stimulus-bridge#lazy-controllers From 7c2612886c1196292c53d54082c1951db020c705 Mon Sep 17 00:00:00 2001 From: gnito-org <70450336+gnito-org@users.noreply.github.com> Date: Sun, 5 Dec 2021 13:36:11 -0400 Subject: [PATCH 1377/1519] [Security] Add remember me description when using custom authenticator --- security/remember_me.rst | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/security/remember_me.rst b/security/remember_me.rst index b14b012202f..ccf810bb34b 100644 --- a/security/remember_me.rst +++ b/security/remember_me.rst @@ -354,3 +354,42 @@ service you created before: ->tokenProvider(DoctrineTokenProvider::class) ; }; + +Activating Remember Me When Using a Custom Authenticator +-------------------------------------------------------- + +When you use a custom authenticator, you must add a ``RememberMeBadge`` to the ``Passport`` +for the remember me function to be activated. Without the badge, remember me will not be +active, regardless of any other remember me settings. + +For example:: + + // src/Service/LoginAuthenticator.php + namespace App\Service; + + // ... + use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; + use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge; + use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge; + use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; + use Symfony\Component\Security\Http\Authenticator\Passport\Passport; + use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface; + + class LoginAuthenticator extends AbstractAuthenticator + { + public function authenticate(Request $request): PassportInterface + { + $password = $request->request->get('password'); + $username = $request->request->get('username'); + $csrfToken = $request->request->get('csrf_token'); + + return new Passport( + new UserBadge($username), + new PasswordCredentials($password), + [ + new CsrfTokenBadge('login', $csrfToken), + new RememberMeBadge(), + ] + ); + } + } From 09b9115337070d1adb69c22eaffa46c635da17d5 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Fri, 7 Jan 2022 15:54:35 +0100 Subject: [PATCH 1378/1519] Minor tweaks --- security/remember_me.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/security/remember_me.rst b/security/remember_me.rst index 8707ee9f1f7..8ba3ede9257 100644 --- a/security/remember_me.rst +++ b/security/remember_me.rst @@ -358,9 +358,10 @@ service you created before: Activating Remember Me When Using a Custom Authenticator -------------------------------------------------------- -When you use a custom authenticator, you must add a ``RememberMeBadge`` to the ``Passport`` -for the remember me function to be activated. Without the badge, remember me will not be -active, regardless of any other remember me settings. +When you use a :doc:`custom authenticator </security/custom_authenticator>`, you +must add a ``RememberMeBadge`` to the ``Passport`` for the "Remember Me" function +to be activated. Without the badge, "Remember Me" will not be active, regardless +of any other "Remember Me" settings. For example:: From d36b9497329a0b105b0a500e2a85af66a1ac61b2 Mon Sep 17 00:00:00 2001 From: Caliendo Julien <34681928+caliendojulien@users.noreply.github.com> Date: Tue, 5 Oct 2021 23:36:33 +0200 Subject: [PATCH 1379/1519] Update remember_me.rst Add some line to the Authenticator to add a RememberMeBadge to the Passport returned --- security/remember_me.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/security/remember_me.rst b/security/remember_me.rst index 8ba3ede9257..6c39ebc8739 100644 --- a/security/remember_me.rst +++ b/security/remember_me.rst @@ -167,6 +167,29 @@ this: The user will then automatically be logged in on subsequent visits while the cookie remains valid. +Add the RememberMeBadge() to the Passport +----------------------------------------- +After uncommenting the login template and add some lines in the firewall configuration, the last thing to do is to add a new RememberMeBadge to the Password in the Authenticator. + + // src/Security/Authenticator.php + // ... + + public function authenticate(Request $request): PassportInterface + { + $email = $request->request->get('email', ''); + + $request->getSession()->set(Security::LAST_USERNAME, $email); + + return new Passport( + new UserBadge($email), + new PasswordCredentials($request->request->get('password', '')), + [ + new CsrfTokenBadge('authenticate', $request->request->get('_csrf_token')), + new RememberMeBadge(), + ] + ); + } + Forcing the User to Re-Authenticate before Accessing certain Resources ---------------------------------------------------------------------- From 2df227596ef4e391ba2065f387ec4ab29bede6ec Mon Sep 17 00:00:00 2001 From: Paul Rijke <paul@rijke.org> Date: Thu, 24 Jun 2021 17:04:52 +0200 Subject: [PATCH 1380/1519] Added the way to activate remember me in the new authentication system I had to search a while for myself not understanding why I did not have a REMEMBERME cookie when I activated the new system. So maybe handy to add it. --- security/remember_me.rst | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/security/remember_me.rst b/security/remember_me.rst index 6c39ebc8739..7b527d69ca2 100644 --- a/security/remember_me.rst +++ b/security/remember_me.rst @@ -169,26 +169,25 @@ the cookie remains valid. Add the RememberMeBadge() to the Passport ----------------------------------------- -After uncommenting the login template and add some lines in the firewall configuration, the last thing to do is to add a new RememberMeBadge to the Password in the Authenticator. - // src/Security/Authenticator.php - // ... - - public function authenticate(Request $request): PassportInterface - { - $email = $request->request->get('email', ''); - - $request->getSession()->set(Security::LAST_USERNAME, $email); - - return new Passport( - new UserBadge($email), - new PasswordCredentials($request->request->get('password', '')), - [ - new CsrfTokenBadge('authenticate', $request->request->get('_csrf_token')), - new RememberMeBadge(), - ] - ); - } +Beware that in the new Authenitaction System you have to set the RememberMeBadge() +in the authenticate method of the authenticator, like:: + + public function authenticate(Request $request): PassportInterface + { + $email = $request->request->get('email', ''); + + $request->getSession()->set(Security::LAST_USERNAME, $email); + + return new Passport( + new UserBadge($email), + new PasswordCredentials($request->request->get('password', '')), + [ + new CsrfTokenBadge('authenticate', $request->get('_csrf_token')), + new RememberMeBadge(), + ] + ); + } Forcing the User to Re-Authenticate before Accessing certain Resources ---------------------------------------------------------------------- From d5cbaf43d252625341a734730fe4888adace9b36 Mon Sep 17 00:00:00 2001 From: HypeMC <hypemc@gmail.com> Date: Sat, 8 Jan 2022 00:39:06 +0100 Subject: [PATCH 1381/1519] Reintroduce removed note --- components/serializer.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/serializer.rst b/components/serializer.rst index d6fc7ba2fc3..5f8465b9194 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -908,6 +908,11 @@ The Serializer component provides several built-in normalizers: The ``UidNormalizer`` normalization formats were introduced in Symfony 5.3. +.. note:: + + You can also create your own Normalizer to use another structure. Read more at + :doc:`/serializer/custom_normalizer`. + Certain normalizers are enabled by default when using the Serializer component in a Symfony application, additional ones can be enabled by tagging them with :ref:`serializer.normalizer <reference-dic-tags-serializer-normalizer>`. From 12fcb6a34d9ef22b09f421e19d4871e81bd04149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Schl=C3=BCter?= <malte.schlueter@qossmic.com> Date: Sat, 8 Jan 2022 17:41:23 +0100 Subject: [PATCH 1382/1519] [Security] Add deprecation information for is_anonymous --- security/expressions.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/security/expressions.rst b/security/expressions.rst index c1bc9717a70..88bebd5dc07 100644 --- a/security/expressions.rst +++ b/security/expressions.rst @@ -24,7 +24,7 @@ accepts an :class:`Symfony\\Component\\ExpressionLanguage\\Expression` object:: public function index(): Response { $this->denyAccessUnlessGranted(new Expression( - '"ROLE_ADMIN" in role_names or (not is_anonymous() and user.isSuperAdmin())' + '"ROLE_ADMIN" in role_names or (is_authenticated() and user.isSuperAdmin())' )); // ... @@ -78,6 +78,11 @@ Additionally, you have access to a number of functions inside the expression: equivalent to using the :ref:`isGranted() method <security-isgranted>` from the security service. +.. deprecated:: 5.4 + + The ``is_anonymous()`` function is + deprecated since Symfony 5.4. + .. sidebar:: ``is_remember_me()`` is different than checking ``IS_AUTHENTICATED_REMEMBERED`` The ``is_remember_me()`` and ``is_fully_authenticated()`` functions are *similar* From 0c7a542bab317ac560533863ebf0a2d2935c9390 Mon Sep 17 00:00:00 2001 From: babache <babache42@hotmail.com> Date: Sun, 9 Jan 2022 12:11:22 +0100 Subject: [PATCH 1383/1519] Remove duplicate line Remove line 325 : use Symfony\Component\Security\Http\Authenticator\Passport\Passport; Same 324 --- security/custom_authenticator.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/security/custom_authenticator.rst b/security/custom_authenticator.rst index 83aeee5cda7..fc2487c0caf 100644 --- a/security/custom_authenticator.rst +++ b/security/custom_authenticator.rst @@ -322,7 +322,6 @@ would initialize the passport like this:: use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Passport; - use Symfony\Component\Security\Http\Authenticator\Passport\Passport; class LoginAuthenticator extends AbstractAuthenticator { From 45c032a21b58074b55cee88ef870a8ecca182941 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Wed, 12 Jan 2022 08:33:34 +0100 Subject: [PATCH 1384/1519] User --webapp instead of --full --- setup.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/setup.rst b/setup.rst index 85c1c58a8cb..94628e87ffe 100644 --- a/setup.rst +++ b/setup.rst @@ -53,13 +53,13 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_directory --version=5.3 --full + $ symfony new my_project_directory --version=5.3 --webapp # run this if you are building a microservice, console application or API $ symfony new my_project_directory --version=5.3 The only difference between these two commands is the number of packages -installed by default. The ``--full`` option installs all the packages that you +installed by default. The ``--webapp`` option installs all the packages that you usually need to build web applications, so the installation size will be bigger. If you're not using the Symfony binary, run these commands to create the new @@ -68,7 +68,9 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/website-skeleton:"^5.3" my_project_directory + $ composer create-project symfony/skeleton:"^5.3" 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:"^5.3" my_project_directory From 79aa7359d4cd382b40e33f7ae3f5b67e5e12416d Mon Sep 17 00:00:00 2001 From: MarkPedron <62351451+MarkPedron@users.noreply.github.com> Date: Thu, 13 Jan 2022 07:41:38 +0100 Subject: [PATCH 1385/1519] Fix custom password hasher doc The docs confused `UserPasswordHasherInterface` with `PasswordHasherInterface`. Implementing a custom `UserPasswordHasherInterface` most likely is not what the developer wants to do. The subsequent docs configured the example at places where a `PasswordHasherInterface` is expected. --- security/passwords.rst | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/security/passwords.rst b/security/passwords.rst index e30e517f895..47f5e7f0424 100644 --- a/security/passwords.rst +++ b/security/passwords.rst @@ -781,12 +781,12 @@ Creating a custom Password Hasher If you need to create your own, it needs to follow these rules: -#. The class must implement :class:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface` - (you can also extend :class:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasher`); +#. The class must implement :class:`Symfony\\Component\\PasswordHasher\\PasswordHasherInterface` + (you can also implement :class:`Symfony\\Component\\PasswordHasher\\LegacyPasswordHasherInterface` if your hash algorithm uses a separate salt); #. The implementations of - :method:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface::hashPassword` - and :method:`Symfony\\Component\\PasswordHasher\\Hasher\\UserPasswordHasherInterface::isPasswordValid` + :method:`Symfony\\Component\\PasswordHasher\\PasswordHasherInterface::hash` + and :method:`Symfony\\Component\\PasswordHasher\\PasswordHasherInterface::verify` **must validate that the password length is no longer than 4096 characters.** This is for security reasons (see `CVE-2013-5750`_). @@ -795,21 +795,21 @@ If you need to create your own, it needs to follow these rules: .. code-block:: php - // src/Security/CustomVerySecureHasher.php - namespace App\Security; + // src/Security/Hasher/CustomVerySecureHasher.php + namespace App\Security\Hasher; + use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException; use Symfony\Component\PasswordHasher\Hasher\CheckPasswordLengthTrait; - use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasher; - use Symfony\Component\Security\Core\Exception\BadCredentialsException; + use Symfony\Component\PasswordHasher\PasswordHasherInterface; - class CustomVerySecureHasher extends UserPasswordHasher + class CustomVerySecureHasher implements PasswordHasherInterface { use CheckPasswordLengthTrait; - public function hashPassword(UserInterface $user, string $plainPassword): string + public function hash(string $plainPassword): string { - if ($this->isPasswordTooLong($user->getPassword())) { - throw new BadCredentialsException('Invalid password.'); + if ($this->isPasswordTooLong($plainPassword)) { + throw new InvalidPasswordException(); } // ... hash the plain password in a secure way @@ -817,9 +817,9 @@ If you need to create your own, it needs to follow these rules: return $hashedPassword; } - public function isPasswordValid(UserInterface $user, string $plainPassword): bool + public function verify(string $hashedPassword, string $plainPassword): bool { - if ($this->isPasswordTooLong($user->getPassword())) { + if ('' === $plainPassword || $this->isPasswordTooLong($plainPassword)) { return false; } @@ -860,21 +860,21 @@ Now, define a password hasher using the ``id`` setting: <!-- ... --> <!-- id: the service ID of your custom hasher (the FQCN using the default services.yaml) --> <security:password_hasher class="app_hasher" - id="App\Security\Hasher\MyCustomPasswordHasher"/> + id="App\Security\Hasher\CustomVerySecureHasher"/> </config> </srv:container> .. code-block:: php // config/packages/security.php - use App\Security\Hasher\MyCustomPasswordHasher; + use App\Security\Hasher\CustomVerySecureHasher; use Symfony\Config\SecurityConfig; return static function (SecurityConfig $security) { // ... $security->passwordHasher('app_hasher') // the service ID of your custom hasher (the FQCN using the default services.yaml) - ->id(MyCustomPasswordHasher::class) + ->id(CustomVerySecureHasher::class) ; }; From 7099e3f2f6cb0049f950a428ea01d652ce3bd5da Mon Sep 17 00:00:00 2001 From: Alexandre Daubois <alex.daubois@gmail.com> Date: Tue, 20 Jul 2021 10:20:58 +0200 Subject: [PATCH 1386/1519] [Validator] Add attributes documentation of composite constraints --- reference/constraints/All.rst | 22 +++++++++++++++++ reference/constraints/AtLeastOneOf.rst | 30 +++++++++++++++++++++++ reference/constraints/Collection.rst | 34 ++++++++++++++++++++++++++ reference/constraints/Sequentially.rst | 26 ++++++++++++++++++++ 4 files changed, 112 insertions(+) diff --git a/reference/constraints/All.rst b/reference/constraints/All.rst index 1577a07ec4d..f50efb5bf0d 100644 --- a/reference/constraints/All.rst +++ b/reference/constraints/All.rst @@ -39,6 +39,23 @@ entry in that array: protected $favoriteColors = []; } + .. code-block:: php-attributes + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + // IMPORTANT: nested attributes requires PHP 8.1 or higher + class User + { + #[Assert\All([ + new Assert\NotBlank, + new Assert\Length(min: 5), + ])] + protected $favoriteColors = []; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -93,6 +110,11 @@ entry in that array: } } +.. versionadded:: 5.4 + + The ``#[All]`` PHP attribute was introduced in Symfony 5.4 and requires + PHP 8.1 (which added nested attribute support). + Now, each entry in the ``favoriteColors`` array will be validated to not be blank and to be at least 5 characters long. diff --git a/reference/constraints/AtLeastOneOf.rst b/reference/constraints/AtLeastOneOf.rst index fb29a86f8d8..28f55ede51c 100644 --- a/reference/constraints/AtLeastOneOf.rst +++ b/reference/constraints/AtLeastOneOf.rst @@ -60,6 +60,31 @@ The following constraints ensure that: protected $grades; } + .. code-block:: php-attributes + + // src/Entity/Student.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + // IMPORTANT: nested attributes requires PHP 8.1 or higher + class Student + { + #[Assert\AtLeastOneOf([ + new Assert\Regex('/#/'), + new Assert\Length(min: 10), + ])] + protected $plainPassword; + + #[Assert\AtLeastOneOf([ + new Assert\Count(min: 3), + new Assert\All( + new Assert\GreaterThanOrEqual(5) + ), + ])] + protected $grades; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -149,6 +174,11 @@ The following constraints ensure that: } } +.. versionadded:: 5.4 + + The ``#[AtLeastOneOf]`` PHP attribute was introduced in Symfony 5.4 and + requires PHP 8.1 (which added nested attribute support). + Options ------- diff --git a/reference/constraints/Collection.rst b/reference/constraints/Collection.rst index c60679aa90b..0f249c1d818 100644 --- a/reference/constraints/Collection.rst +++ b/reference/constraints/Collection.rst @@ -88,6 +88,35 @@ following: ]; } + .. code-block:: php-attributes + + // src/Entity/Author.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + // IMPORTANT: nested attributes requires PHP 8.1 or higher + class Author + { + #[Assert\Collection( + fields: [ + 'personal_email' => new Assert\Email, + 'short_bio' => [ + new Assert\NotBlank, + new Assert\Length( + max: 100, + maxMessage: 'Your short bio is too long!' + ) + ] + ], + allowMissingFields: true, + )] + protected $profileData = [ + 'personal_email' => '...', + 'short_bio' => '...', + ]; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -162,6 +191,11 @@ following: } } +.. versionadded:: 5.4 + + The ``#[Collection]`` PHP attribute was introduced in Symfony 5.4 and + requires PHP 8.1 (which added nested attribute support). + Presence and Absence of Fields ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/reference/constraints/Sequentially.rst b/reference/constraints/Sequentially.rst index da7bd16f4b2..9e6f6eaefbb 100644 --- a/reference/constraints/Sequentially.rst +++ b/reference/constraints/Sequentially.rst @@ -67,6 +67,27 @@ You can validate each of these constraints sequentially to solve these issues: public $address; } + .. code-block:: php-attributes + + // src/Localization/Place.php + namespace App\Localization; + + use App\Validator\Constraints as AcmeAssert; + use Symfony\Component\Validator\Constraints as Assert; + + // IMPORTANT: nested attributes requires PHP 8.1 or higher + class Place + { + #[Assert\Sequentially([ + new Assert\NotNull, + new Assert\Type('string'), + new Assert\Length(min: 10), + new Assert\Regex(Place::ADDRESS_REGEX), + new AcmeAssert\Geolocalizable, + ])] + public $address; + } + .. code-block:: yaml # config/validator/validation.yaml @@ -128,6 +149,11 @@ You can validate each of these constraints sequentially to solve these issues: } } +.. versionadded:: 5.4 + + The ``#[Sequentially]`` PHP attribute was introduced in Symfony 5.4 and + requires PHP 8.1 (which added nested attribute support). + Options ------- From d7db41a751837a6e3f94e81f2ea3c360eb096722 Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Fri, 14 Jan 2022 15:07:38 +0100 Subject: [PATCH 1387/1519] Drop 5.4 versionadded directives --- reference/constraints/All.rst | 5 ----- reference/constraints/AtLeastOneOf.rst | 5 ----- reference/constraints/Collection.rst | 5 ----- reference/constraints/Sequentially.rst | 5 ----- 4 files changed, 20 deletions(-) diff --git a/reference/constraints/All.rst b/reference/constraints/All.rst index cfcf75343fd..ec4e76d96f9 100644 --- a/reference/constraints/All.rst +++ b/reference/constraints/All.rst @@ -107,11 +107,6 @@ entry in that array: } } -.. versionadded:: 5.4 - - The ``#[All]`` PHP attribute was introduced in Symfony 5.4 and requires - PHP 8.1 (which added nested attribute support). - Now, each entry in the ``favoriteColors`` array will be validated to not be blank and to be at least 5 characters long. diff --git a/reference/constraints/AtLeastOneOf.rst b/reference/constraints/AtLeastOneOf.rst index a548bf03149..42067f0c231 100644 --- a/reference/constraints/AtLeastOneOf.rst +++ b/reference/constraints/AtLeastOneOf.rst @@ -164,11 +164,6 @@ The following constraints ensure that: } } -.. versionadded:: 5.4 - - The ``#[AtLeastOneOf]`` PHP attribute was introduced in Symfony 5.4 and - requires PHP 8.1 (which added nested attribute support). - Options ------- diff --git a/reference/constraints/Collection.rst b/reference/constraints/Collection.rst index e708511d309..6830dcc0956 100644 --- a/reference/constraints/Collection.rst +++ b/reference/constraints/Collection.rst @@ -184,11 +184,6 @@ following: } } -.. versionadded:: 5.4 - - The ``#[Collection]`` PHP attribute was introduced in Symfony 5.4 and - requires PHP 8.1 (which added nested attribute support). - Presence and Absence of Fields ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/reference/constraints/Sequentially.rst b/reference/constraints/Sequentially.rst index ffe82deae62..49eb07c5aa0 100644 --- a/reference/constraints/Sequentially.rst +++ b/reference/constraints/Sequentially.rst @@ -142,11 +142,6 @@ You can validate each of these constraints sequentially to solve these issues: } } -.. versionadded:: 5.4 - - The ``#[Sequentially]`` PHP attribute was introduced in Symfony 5.4 and - requires PHP 8.1 (which added nested attribute support). - Options ------- From 76bd5fb5fd9e4ee18a102f4ea568bff7a7198bca Mon Sep 17 00:00:00 2001 From: Volodymyr Kupriienko <vldmr.kuprienko@gmail.com> Date: Fri, 1 Oct 2021 21:16:56 +0300 Subject: [PATCH 1388/1519] [HttpClient] HttpClientInterface::setResponseFactory method --- http_client.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/http_client.rst b/http_client.rst index 834ada0b10a..6254d816efe 100644 --- a/http_client.rst +++ b/http_client.rst @@ -1678,6 +1678,23 @@ responses dynamically when it's called:: $client = new MockHttpClient($callback); $response = $client->request('...'); // calls $callback to get the response +.. tip:: + + Instead of using the first argument, you can also set the (list of) + responses or callbacks using the ``setResponseFactory()`` method:: + + $responses = [ + new MockResponse($body1, $info1), + new MockResponse($body2, $info2), + ]; + + $client = new MockHttpClient(); + $client->setResponseFactory($responses); + + .. versionadded:: 5.4 + + The ``setResponseFactory()`` method was introduced in Symfony 5.4. + If you need to test responses with HTTP status codes different than 200, define the ``http_code`` option:: From 48008248a03d4734a0e4306d7d3d4fcec78674db Mon Sep 17 00:00:00 2001 From: Punt13140 <33422215+Punt13140@users.noreply.github.com> Date: Fri, 22 Oct 2021 00:51:43 +0200 Subject: [PATCH 1389/1519] Update form_collections.rst Hi, Shouldn't we add a delete link just to <li> childs instead of the <ul> parent ? Thanks --- form/form_collections.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/form/form_collections.rst b/form/form_collections.rst index c58bf996235..0ab38902a17 100644 --- a/form/form_collections.rst +++ b/form/form_collections.rst @@ -531,7 +531,7 @@ First, add a "delete this tag" link to each tag form: .. code-block:: javascript - const tags = document.querySelectorAll('ul.tags') + const tags = document.querySelectorAll('ul.tags li') tags.forEach((tag) => { addTagFormDeleteLink(tag) }) From 7a175b9e08f6f8ad056e18b529776deec51b8f02 Mon Sep 17 00:00:00 2001 From: soyuka <soyuka@users.noreply.github.com> Date: Wed, 27 Oct 2021 16:46:13 +0200 Subject: [PATCH 1390/1519] serializer: default context configuration #16010 --- serializer.rst | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/serializer.rst b/serializer.rst index 92250d2f5a9..f61e2709dfe 100644 --- a/serializer.rst +++ b/serializer.rst @@ -175,6 +175,49 @@ You can pass the context like following:: DateTimeNormalizer::FORMAT_KEY => 'Y-m-d H:i:s', ]); +You can also configure the default context through the framework +configuration: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/framework.yaml + framework: + # ... + serializer: + default_context: + enable_max_depth: true + + .. code-block:: xml + + <!-- config/packages/framework.xml --> + <framework:config> + <!-- ... --> + <framework:serializer> + <default-context enable-max-depth="true"/> + </framework:serializer> + </framework:config> + + .. code-block:: php + + // config/packages/framework.php + use Symfony\Config\FrameworkConfig; + use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; + + return static function (FrameworkConfig $framework) { + $framework->serializer() + ->defaultContext([ + AbstractObjectNormalizer::ENABLE_MAX_DEPTH => true + ]) + ; + }; + +.. versionadded:: 5.4 + + The ability to configure the ``default_context`` option in the + Serializer was introduced in Symfony 5.4. + .. _serializer-using-serialization-groups-annotations: Using Serialization Groups Annotations From 5ac2d260f2fe7dec95d66317fb05e76b56170bd7 Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Fri, 7 Jan 2022 17:51:56 +0100 Subject: [PATCH 1391/1519] Document the new remember me system --- _images/security/profiler-badges.png | Bin 0 -> 151450 bytes security/remember_me.rst | 616 ++++++++++++++++++--------- 2 files changed, 415 insertions(+), 201 deletions(-) create mode 100644 _images/security/profiler-badges.png diff --git a/_images/security/profiler-badges.png b/_images/security/profiler-badges.png new file mode 100644 index 0000000000000000000000000000000000000000..a19f8539581a937011667179a8958d66a2ec504c GIT binary patch literal 151450 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%0At;L5lHRDEJ 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]&lYLOmbR~I)ys5S+} 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 literal 0 HcmV?d00001 diff --git a/security/remember_me.rst b/security/remember_me.rst index 7b527d69ca2..5b3ce54fb4a 100644 --- a/security/remember_me.rst +++ b/security/remember_me.rst @@ -4,6 +4,12 @@ How to Add "Remember Me" Login Functionality ============================================ +.. caution:: + + This article documents the remember me system that was introduced in + the new authenticator system in 5.3. If you're using the deprecated + security system, refer to the `5.2 version of this documentation`_. + Once a user is authenticated, their credentials are typically stored in the session. This means that when the session ends they will be logged out and have to provide their login details again next time they wish to access the @@ -22,9 +28,8 @@ the session lasts using a cookie with the ``remember_me`` firewall option: main: # ... remember_me: - secret: '%kernel.secret%' + secret: '%kernel.secret%' # required lifetime: 604800 # 1 week in seconds - path: / # by default, the feature is enabled by checking a # checkbox in the login form (see below), uncomment the # following line to always enable it. @@ -48,11 +53,12 @@ the session lasts using a cookie with the ``remember_me`` firewall option: <firewall name="main"> <!-- ... --> - <!-- 604800 is 1 week in seconds --> + <!-- secret: required + lifetime: 604800 is 1 week in seconds --> <remember-me secret="%kernel.secret%" lifetime="604800" - path="/"/> + /> <!-- by default, the feature is enabled by checking a checkbox in the login form (see below), add always-remember-me="true" to always enable it. --> @@ -70,9 +76,8 @@ the session lasts using a cookie with the ``remember_me`` firewall option: $security->firewall('main') // ... ->rememberMe() - ->secret('%kernel.secret%') + ->secret('%kernel.secret%') // required ->lifetime(604800) // 1 week in seconds - ->path('/') // by default, the feature is enabled by checking a // checkbox in the login form (see below), uncomment @@ -81,245 +86,404 @@ the session lasts using a cookie with the ``remember_me`` firewall option: ; }; -The ``remember_me`` firewall defines the following configuration options: +The ``secret`` option is the only required option and it is used to sign +the remember me cookie. It's common to use the ``kernel.secret`` parameter, +which is defined using the ``APP_SECRET`` environment variable. -``secret`` (**required**) - The value used to encrypt the cookie's content. It's common to use the - ``secret`` value defined in 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: -``name`` (default value: ``REMEMBERME``) - The name of the cookie used to keep the user logged in. If you enable the - ``remember_me`` feature in several firewalls of the same application, make sure - to choose a different name for the cookie of each firewall. Otherwise, you'll - face lots of security related problems. +#. :ref:`Add an opt-in checkbox to active remember me <security-remember-me-activate>`; +#. :ref:`Use an authenticator that supports remember me <security-remember-me-authenticator>`; +#. Optionally, :ref:`configure the how remember me cookies are stored and validated <security-remember-me-storage>`. -``lifetime`` (default value: ``31536000``) - The number of seconds during which the user will remain logged in. By default - users are logged in for one year. +After this, the remember me cookie will be created upon successful +authentication. For some pages/actions, you can +:ref:`force a user to fully authenticate <security-remember-me-authorization>` +(i.e. not through a remember me cookie) for better security. -``path`` (default value: ``/``) - The path where the cookie associated with this feature is used. By default - the cookie will be applied to the entire website but you can restrict to a - specific section (e.g. ``/forum``, ``/admin``). +.. note:: -``domain`` (default value: ``null``) - The domain where the cookie associated with this feature is used. By default - cookies use the current domain obtained from ``$_SERVER``. + The ``remember_me`` setting contains many settings to configure the + cookie created by this feature. See `Customizing the Remember Me Cookie`_ + for a full description of these settings. -``secure`` (default value: ``false``) - If ``true``, the cookie associated with this feature is sent to the user - through an HTTPS secure connection. +.. _security-remember-me-activate: -``httponly`` (default value: ``true``) - If ``true``, the cookie associated with this feature is accessible only - through the HTTP protocol. This means that the cookie won't be accessible - by scripting languages, such as JavaScript. +Activating the Remember Me System +--------------------------------- -``samesite`` (default value: ``null``) - If set to ``strict``, the cookie associated with this feature will not - be sent along with cross-site requests, even when following a regular link. +Using the remember me cookie is not always appropriate (e.g. you should not +use it on a shared PC). This is why by default, Symfony requires your users +to opt-in to the remember me system via a request parameter. -``remember_me_parameter`` (default value: ``_remember_me``) - The name of the form field checked to decide if the "Remember Me" feature - should be enabled or not. Keep reading this article to know how to enable - this feature conditionally. +This request parameter is often set via a checkbox in the login form. This +checkbox must have a name of ``_remember_me``: -``always_remember_me`` (default value: ``false``) - If ``true``, the value of the ``remember_me_parameter`` is ignored and the - "Remember Me" feature is always enabled, regardless of the desire of the - end user. +.. code-block:: html+twig -``token_provider`` (default value: ``null``) - Defines the service id of a token provider to use. If you want to store tokens - in the database, see :ref:`remember-me-token-in-database`. + {# templates/security/login.html.twig #} + <form method="post"> + {# ... your form fields #} -``service`` (default value: ``null``) - Defines the ID of the service used to handle the Remember Me feature. It's - useful if you need to overwrite the current behavior. + <label> + <input type="checkbox" name="_remember_me" checked/> + Keep me logged in + </label> - .. versionadded:: 5.1 + {# ... #} + </form> - The ``service`` option was introduced in Symfony 5.1. +.. note:: -Forcing the User to Opt-Out of the Remember Me Feature ------------------------------------------------------- + Optionally, you can configure a custom name for this checkbox using the + ``remember_me_parameter`` setting under the ``remember_me`` section. -It's a good idea to provide the user with the option to use or not use the -remember me functionality, as it will not always be appropriate. The usual -way of doing this is to add a checkbox to the login form. By giving the checkbox -the name ``_remember_me`` (or the name you configured using ``remember_me_parameter``), -the cookie will automatically be set when the checkbox is checked and the user -successfully logs in. So, your specific login form might ultimately look like -this: +Always activating Remember Me +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code-block:: html+twig +Sometimes, you may wish to always activate the remember me system and not +allow users to opt-out. In these cases, you can use the +``always_remember_me`` setting: - {# templates/security/login.html.twig #} - <form method="post"> - {# ... your form fields #} +.. configuration-block:: - <input type="checkbox" id="remember_me" name="_remember_me" checked/> - <label for="remember_me">Keep me logged in</label> + .. code-block:: yaml - {# ... #} - </form> + # config/packages/security.yaml + security: + # ... + + firewalls: + main: + # ... + remember_me: + secret: '%kernel.secret%' + # ... + always_remember_me: true + + .. code-block:: xml + + <!-- config/packages/security.xml --> + <?xml version="1.0" encoding="UTF-8" ?> + <srv:container xmlns="http://symfony.com/schema/dic/security" + xmlns:srv="http://symfony.com/schema/dic/services" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://symfony.com/schema/dic/services + https://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/security + https://symfony.com/schema/dic/security/security-1.0.xsd"> -The user will then automatically be logged in on subsequent visits while -the cookie remains valid. + <config> + <!-- ... --> -Add the RememberMeBadge() to the Passport ------------------------------------------ + <firewall name="main"> + <!-- ... --> -Beware that in the new Authenitaction System you have to set the RememberMeBadge() -in the authenticate method of the authenticator, like:: + <remember-me + secret="%kernel.secret%" + always-remember-me="true" + /> + </firewall> + </config> + </srv:container> - public function authenticate(Request $request): PassportInterface - { - $email = $request->request->get('email', ''); + .. code-block:: php - $request->getSession()->set(Security::LAST_USERNAME, $email); + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... + $security->firewall('main') + // ... + ->rememberMe() + ->secret('%kernel.secret%') + // ... + ->alwaysRememberMe(true) + ; + }; + +Now, no request parameter is checked and each successful authentication +will produce a remember me cookie. + +.. _security-remember-me-authenticator: + +Add Remember Me Support to the Authenticator +-------------------------------------------- + +Not all authentication methods support remember me (e.g. HTTP Basic +authentication doesn't have support). An authenticator indicates support +using a ``RememberMeBadge`` on the :ref:`security passport <security-passport>`. + +After logging in, you can use the security profiler to see if this badge is +present: + +.. image:: /_images/security/profiler-badges.png + +Without this badge, remember me will be not be activated (regardless of all +other settings). + +Add Remember Me Support to Custom Authenticators +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When you use a custom authenticator, you must add a ``RememberMeBadge`` +manually:: + + // src/Service/LoginAuthenticator.php + namespace App\Service; + + // ... + use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge; + use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; + use Symfony\Component\Security\Http\Authenticator\Passport\Passport; + + class LoginAuthenticator extends AbstractAuthenticator + { + public function authenticate(Request $request): Passport + { + // ... return new Passport( - new UserBadge($email), - new PasswordCredentials($request->request->get('password', '')), + new UserBadge(...), + new PasswordCredentials(...), [ - new CsrfTokenBadge('authenticate', $request->get('_csrf_token')), new RememberMeBadge(), ] ); } + } -Forcing the User to Re-Authenticate before Accessing certain Resources ----------------------------------------------------------------------- +.. _security-remember-me-storage: -When the user returns to your site, they are authenticated automatically based -on the information stored in the remember me cookie. This allows the user -to access protected resources as if the user had actually authenticated upon -visiting the site. +Customize how Remember Me Tokens are Stored +------------------------------------------- -In some cases, however, you may want to force the user to actually re-authenticate -before accessing certain resources. For example, you might not allow "remember me" -users to change their password. You can do this by leveraging a few special -"attributes":: +Remember me cookies contain a token that is used to verify the user's +identity. As these tokens are long-lived, it is important to take +precautions to allow invalidating any generated tokens. - // src/Controller/AccountController.php - // ... +Symfony provides two ways to validate remember me tokens: - public function accountInfo(): Response - { - // allow any authenticated user - we don't care if they just - // logged in, or are logged in via a remember me cookie - $this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED'); +Signature based tokens + By default, the remember me cookie contains a signature based on + properties of the user. If the properties change, the signature changes + and already generated tokens are no longer considered valid. See + :ref:`security-remember-me-signature` for more information. - // ... - } +Persistent tokens + Persistent tokens store any generated token (e.g. in a database). This + allows you to invalidate tokens by changing the rows in the database. + See :ref:`security-remember-me-persistent` for more information. - public function resetPassword(): Response - { - // require the user to log in during *this* session - // if they were only logged in via a remember me cookie, they - // will be redirected to the login page - $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); +.. note:: - // ... - } + You can also write your own custom remember me handler by creating a + class that extends + :class:`Symfony\\Component\\Security\\Http\\RememberMe\\AbstractRememberMeHandler` + (or implements :class:`Symfony\\Component\\Security\\Http\\RememberMe\\RememberMeHandlerInterface`). + You can then configure this custom handler by configuring the service + ID in the ``service`` option under ``remember_me``. -.. tip:: + .. versionadded:: 5.1 - There is also a ``IS_REMEMBERED`` attribute that grants access *only* when the - user is authenticated via the remember me mechanism. + The ``service`` option was introduced in Symfony 5.1. -.. versionadded:: 5.1 - The ``IS_REMEMBERED`` attribute was introduced in Symfony 5.1. +.. _security-remember-me-signature: -.. _remember-me-token-in-database: +Using Signed Remember Me Tokens +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Storing Remember Me Tokens in the Database ------------------------------------------- +By default, remember me cookies contain a *hash* that is used to validate +the cookie. This hash is computed based on configured +signature properties. -The token contents, including the hashed version of the user password, are -stored by default in cookies. If you prefer to store them in a database, use the -:class:`Symfony\\Bridge\\Doctrine\\Security\\RememberMe\\DoctrineTokenProvider` -class provided by the Doctrine Bridge. +These properties are always included in the hash: -First, you need to register ``DoctrineTokenProvider`` as a service: +* The user identifier (returned by + :method:`Symfony\\Component\\Security\\Core\\User\\UserInterface::getUserIdentifier`); +* The expiration timestamp. + +On top of these, you can configure custom properties using the +``signature_properties`` setting (defaults to ``password``). The properties +are fetched from the user object using the +:doc:`PropertyAccess component </components/property_access>` (e.g. using +``getUpdatedAt()`` or a public ``$updatedAt`` property when using +``updatedAt``). .. configuration-block:: .. code-block:: yaml - # config/services.yaml - services: + # config/packages/security.yaml + security: # ... - Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider: ~ + firewalls: + main: + # ... + remember_me: + secret: '%kernel.secret%' + # ... + signature_properties: ['password', 'updatedAt'] .. code-block:: xml - <!-- config/services.xml --> + <!-- config/packages/security.xml --> <?xml version="1.0" encoding="UTF-8" ?> - <container xmlns="http://symfony.com/schema/dic/services" + <srv:container xmlns="http://symfony.com/schema/dic/security" + xmlns:srv="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd"> + xsi:schemaLocation="http://symfony.com/schema/dic/services + https://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/security + https://symfony.com/schema/dic/security/security-1.0.xsd"> + + <config> + <!-- ... --> + + <firewall name="main"> + <!-- ... --> - <services> - <service id="Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider"/> - </services> - </container> + <remember-me secret="%kernel.secret%"> + <signature-property>password</signature-property> + <signature-property>updatedAt</signature-property> + </remember-me> + </firewall> + </config> + </srv:container> .. code-block:: php - // config/services.php - use Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider; + // config/packages/security.php + use Symfony\Config\SecurityConfig; + + return static function (SecurityConfig $security) { + // ... + $security->firewall('main') + // ... + ->rememberMe() + ->secret('%kernel.secret%') + // ... + ->signatureProperties(['password', 'updatedAt']) + ; + }; + +In this example, the remember me cookie will no longer be considered valid +if the ``updatedAt``, password or user identifier for this user changes. + +.. tip:: + + Signature properties allow for some advanced usages without having to + set-up storage for all remember me tokens. For instance, you can add a + ``forceReloginAt`` field to your user and to the signature properties. + This way, you can invalidate all remember me tokens from a user by + changing this timestamp. - $container->register(DoctrineTokenProvider::class); +.. _security-remember-me-persistent: -Then you need to create a table with the following structure in your database -so ``DoctrineTokenProvider`` can store the tokens: +Storing Remember Me Tokens in the Database +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code-block:: sql +As remember me tokens are often long-lived, you might prefer to save them in +a database to have full control over them. Symfony comes with support for +persistent remember me tokens. - CREATE TABLE `rememberme_token` ( - `series` char(88) UNIQUE PRIMARY KEY NOT NULL, - `value` varchar(88) NOT NULL, - `lastUsed` datetime NOT NULL, - `class` varchar(100) NOT NULL, - `username` varchar(200) NOT NULL - ); +This implementation uses a *remember me token provider* for storing and +retrieving the tokens from the database. The DoctrineBridge provides a +token provider using Doctrine. -.. note:: +You can enable the doctrine token provider using the ``doctrine`` setting: + +.. configuration-block:: - If you use DoctrineMigrationsBundle to manage your database migrations, you - will need to tell Doctrine to ignore this new ``rememberme_token`` table: + .. code-block:: yaml + + # config/packages/security.yaml + security: + # ... + + firewalls: + main: + # ... + remember_me: + secret: '%kernel.secret%' + # ... + token_provider: + doctrine: true - .. configuration-block:: + .. code-block:: xml - .. code-block:: yaml + <!-- config/packages/security.xml --> + <?xml version="1.0" encoding="UTF-8" ?> + <srv:container xmlns="http://symfony.com/schema/dic/security" + xmlns:srv="http://symfony.com/schema/dic/services" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://symfony.com/schema/dic/services + https://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/security + https://symfony.com/schema/dic/security/security-1.0.xsd"> - # config/packages/doctrine.yaml - doctrine: - dbal: - schema_filter: ~^(?!rememberme_token)~ + <config> + <!-- ... --> - .. code-block:: xml + <firewall name="main"> + <!-- ... --> - <!-- config/packages/doctrine.xml --> - <doctrine:dbal schema-filter="~^(?!rememberme_token)~"/> + <remember-me secret="%kernel.secret%"> + <token-provider doctrine="true"/> + </remember-me> + </firewall> + </config> + </srv:container> - .. code-block:: php + .. code-block:: php - // config/packages/doctrine.php - use Symfony\Config\DoctrineConfig; + // config/packages/security.php + use Symfony\Config\SecurityConfig; - return static function (DoctrineConfig $doctrine) { - $dbalDefault = $doctrine->dbal()->connection('default'); + return static function (SecurityConfig $security) { + // ... + $security->firewall('main') // ... - $dbalDefault->schemaFilter('~^(?!rememberme_token)~'); - }; + ->rememberMe() + ->secret('%kernel.secret%') + // ... + ->tokenProvider([ + 'doctrine' => true, + ]) + ; + }; + +This also instructs Doctrine to create a table for the remember me tokens. +If you use the DoctrineMigrationsBundle, you can create a new migration for +this: + +.. code-block:: terminal + + $ php bin/console doctrine:migrations:diff + + # and optionally run the migrations locally + $ php bin/console doctrine:migrations:migrate + +Otherwise, you can use the ``doctrine:schema:update`` command: + +.. code-block:: terminal + + # get the required SQL code + $ php bin/console doctrine:schema:update --dump-sql + + # run the SQL in your DB client, or let the command run it for you + $ php bin/console doctrine:schema:update --force + +Implementing a Custom Token Provider +.................................... + +You can also create a custom token provider by creating a class that +implements :class:`Symfony\\Component\\Security\\Core\\Authentication\\RememberMe\\TokenProviderInterface`. -Finally, set the ``token_provider`` option of the ``remember_me`` config to the -service you created before: +Then, configure the service ID of your custom token provider as ``service``: .. configuration-block:: @@ -334,7 +498,8 @@ service you created before: # ... remember_me: # ... - token_provider: 'Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider' + token_provider: + service: App\Security\RememberMe\CustomTokenProvider .. code-block:: xml @@ -354,9 +519,9 @@ service you created before: <firewall name="main"> <!-- ... --> - <remember-me - token-provider="Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider" - /> + <remember-me> + <token-provider service="App\Security\RememberMe\CustomTokenProvider"/> + </remember-me> </firewall> </config> </srv:container> @@ -364,7 +529,7 @@ service you created before: .. code-block:: php // config/packages/security.php - use Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider; + use App\Security\RememberMe\CustomTokenProvider; use Symfony\Config\SecurityConfig; return static function (SecurityConfig $security) { @@ -373,46 +538,95 @@ service you created before: // ... ->rememberMe() // ... - ->tokenProvider(DoctrineTokenProvider::class) + ->tokenProvider([ + 'service' => CustomTokenProvider::class, + ]) ; }; -Activating Remember Me When Using a Custom Authenticator --------------------------------------------------------- +.. _security-remember-me-authorization: -When you use a :doc:`custom authenticator </security/custom_authenticator>`, you -must add a ``RememberMeBadge`` to the ``Passport`` for the "Remember Me" function -to be activated. Without the badge, "Remember Me" will not be active, regardless -of any other "Remember Me" settings. +Forcing the User to Re-Authenticate before Accessing certain Resources +---------------------------------------------------------------------- -For example:: +When the user returns to your site, they are authenticated automatically based +on the information stored in the remember me cookie. This allows the user +to access protected resources as if the user had actually authenticated upon +visiting the site. - // src/Service/LoginAuthenticator.php - namespace App\Service; +In some cases, however, you may want to force the user to actually re-authenticate +before accessing certain resources. For example, you might not allow "remember me" +users to change their password. You can do this by leveraging a few special +"attributes":: + // src/Controller/AccountController.php // ... - use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; - use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge; - use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge; - use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; - use Symfony\Component\Security\Http\Authenticator\Passport\Passport; - use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface; - class LoginAuthenticator extends AbstractAuthenticator + public function accountInfo(): Response { - public function authenticate(Request $request): PassportInterface - { - $password = $request->request->get('password'); - $username = $request->request->get('username'); - $csrfToken = $request->request->get('csrf_token'); + // allow any authenticated user - we don't care if they just + // logged in, or are logged in via a remember me cookie + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED'); - return new Passport( - new UserBadge($username), - new PasswordCredentials($password), - [ - new CsrfTokenBadge('login', $csrfToken), - new RememberMeBadge(), - ] - ); - } + // ... + } + + public function resetPassword(): Response + { + // require the user to log in during *this* session + // if they were only logged in via a remember me cookie, they + // will be redirected to the login page + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); + + // ... } + +.. tip:: + + There is also a ``IS_REMEMBERED`` attribute that grants access *only* + when the user is authenticated via the remember me mechanism. + +.. versionadded:: 5.1 + + The ``IS_REMEMBERED`` attribute was introduced in Symfony 5.1. + +Customizing the Remember Me Cookie +---------------------------------- + +The ``remember_me`` configuration contains many options to customize the +cookie created by the system: + +``name`` (default value: ``REMEMBERME``) + The name of the cookie used to keep the user logged in. If you enable the + ``remember_me`` feature in several firewalls of the same application, make sure + to choose a different name for the cookie of each firewall. Otherwise, you'll + face lots of security related problems. + +``lifetime`` (default value: ``31536000`` i.e. 1 year in seconds) + The number of seconds after which the cookie will be expired. This + defines the maximum time between two visits for the user to remain + authenticated. + +``path`` (default value: ``/``) + The path where the cookie associated with this feature is used. By default + the cookie will be applied to the entire website but you can restrict to a + specific section (e.g. ``/forum``, ``/admin``). + +``domain`` (default value: ``null``) + The domain where the cookie associated with this feature is used. By default + cookies use the current domain obtained from ``$_SERVER``. + +``secure`` (default value: ``false``) + If ``true``, the cookie associated with this feature is sent to the user + through an HTTPS secure connection. + +``httponly`` (default value: ``true``) + If ``true``, the cookie associated with this feature is accessible only + through the HTTP protocol. This means that the cookie won't be accessible + by scripting languages, such as JavaScript. + +``samesite`` (default value: ``null``) + If set to ``strict``, the cookie associated with this feature will not + be sent along with cross-site requests, even when following a regular link. + +.. _`5.2 version of this documentation`: https://symfony.com/doc/5.2/security/remember_me.html From 6f2ef6db89f4948f333ff964f87adf1856c3966f Mon Sep 17 00:00:00 2001 From: Mark Pedron <marktpedron@gmail.com> Date: Sat, 15 Jan 2022 13:52:50 +0100 Subject: [PATCH 1392/1519] Add missing symfony server reference Fixes the following diagnostic emitted by `_build/build.php`: ``` Found invalid reference "symfony binary web server" in file ``` "setup/docker" --- setup/docker.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/docker.rst b/setup/docker.rst index bd8eb145af8..d3d51cb781f 100644 --- a/setup/docker.rst +++ b/setup/docker.rst @@ -49,7 +49,7 @@ After installing the package, rebuild your containers by running: Symfony Binary Web Server and Docker Support -------------------------------------------- -If you're using the :ref:`symfony binary web server` (e.g. ``symfony server:start``), +If you're using the :ref:`symfony binary web server <symfony-local-web-server>` (e.g. ``symfony server:start``), then it can automatically detect your Docker services and expose them as environment variables. See :ref:`symfony-server-docker`. From 33472e5ee415cf67f09a4c27f83fdb3df430cacf Mon Sep 17 00:00:00 2001 From: Andrea Cristaudo <andrea-cristaudo@users.noreply.github.com> Date: Sat, 15 Jan 2022 11:29:33 +0100 Subject: [PATCH 1393/1519] Remove reference to jQuery from examples code --- form/form_collections.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/form/form_collections.rst b/form/form_collections.rst index 0ab38902a17..b358a4dfbc0 100644 --- a/form/form_collections.rst +++ b/form/form_collections.rst @@ -281,9 +281,7 @@ On the rendered page, the result will look something like this: and you need to adjust the following JavaScript accordingly. Now add some JavaScript to read this attribute and dynamically add new tag forms -when the user clicks the "Add a tag" link. This example uses `jQuery`_ and -assumes you have it included somewhere on your page (e.g. using Symfony's -:doc:`Webpack Encore </frontend>`). +when the user clicks the "Add a tag" link. Add a ``<script>`` tag somewhere on your page to include the required functionality with JavaScript: @@ -651,7 +649,7 @@ the relationship between the removed ``Tag`` and ``Task`` object. The Symfony community has created some JavaScript packages that provide the functionality needed to add, edit and delete elements of the collection. Check out the `@a2lix/symfony-collection`_ package for modern browsers and - the `symfony-collection`_ package based on jQuery for the rest of browsers. + the `symfony-collection`_ package based on `jQuery`_ for the rest of browsers. .. _`Owning Side and Inverse Side`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/unitofwork-associations.html .. _`jQuery`: http://jquery.com/ From f69eb0183b006172b9210a03f1dda302998e3f44 Mon Sep 17 00:00:00 2001 From: Thomas Landauer <thomas@landauer.at> Date: Mon, 8 Nov 2021 16:04:31 +0100 Subject: [PATCH 1394/1519] Removing outdated jQuery note --- form/form_collections.rst | 41 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/form/form_collections.rst b/form/form_collections.rst index b358a4dfbc0..ca104b80ab4 100644 --- a/form/form_collections.rst +++ b/form/form_collections.rst @@ -238,25 +238,26 @@ it will receive an *unknown* number of tags. Otherwise, you'll see a The ``allow_add`` option also makes a ``prototype`` variable available to you. This "prototype" is a little "template" that contains all the HTML needed to -dynamically create any new "tag" forms with JavaScript. To render the prototype, add -the following ``data-prototype`` attribute to the existing ``<ul>`` in your template: +dynamically create any new "tag" forms with JavaScript. Now add the following +``data-index`` (containing the current "form row" number for the following JavaScript) +and ``data-prototype`` attribute to the existing ``<ul>`` in your template: .. code-block:: html+twig <ul class="tags" data-index="{{ form.tags|length > 0 ? form.tags|last.vars.name + 1 : 0 }}" data-prototype="{{ form_widget(form.tags.vars.prototype)|e('html_attr') }}"></ul> -Now add a button just next to the ``<ul>`` to dynamically add a new tag: - -.. code-block:: html+twig - - <button type="button" class="add_item_link" data-collection-holder-class="tags">Add a tag</button> - On the rendered page, the result will look something like this: .. code-block:: html <ul class="tags" data-index="0" data-prototype="<div><label class=" required">__name__</label><div id="task_tags___name__"><div><label for="task_tags___name___name" class=" required">Name</label><input type="text" id="task_tags___name___name" name="task[tags][__name__][name]" required="required" maxlength="255" /></div></div></div>"> +Now add a button to dynamically add a new tag: + +.. code-block:: html+twig + + <button type="button" class="add_item_link" data-collection-holder-class="tags">Add a tag</button> + .. seealso:: If you want to customize the HTML code in the prototype, see @@ -265,7 +266,7 @@ On the rendered page, the result will look something like this: .. tip:: The ``form.tags.vars.prototype`` is a form element that looks and feels just - like the individual ``form_widget(tag)`` elements inside your ``for`` loop. + like the individual ``form_widget(tag.*)`` elements inside your ``for`` loop. This means that you can call ``form_widget()``, ``form_row()`` or ``form_label()`` on it. You could even choose to render only one of its fields (e.g. the ``name`` field): @@ -303,9 +304,9 @@ you'll replace with a unique, incrementing number (e.g. ``task[tags][3][name]``) const addFormToCollection = (e) => { const collectionHolder = document.querySelector('.' + e.currentTarget.dataset.collectionHolderClass); - const item = document.createElement('li'); + const element = document.createElement('li'); - item.innerHTML = collectionHolder + element.innerHTML = collectionHolder .dataset .prototype .replace( @@ -313,7 +314,7 @@ you'll replace with a unique, incrementing number (e.g. ``task[tags][3][name]``) collectionHolder.dataset.index ); - collectionHolder.appendChild(item); + collectionHolder.appendChild(element); collectionHolder.dataset.index++; }; @@ -540,24 +541,23 @@ First, add a "delete this tag" link to each tag form: // ... // add a delete link to the new form - addTagFormDeleteLink(item); + addTagFormDeleteLink(element); } The ``addTagFormDeleteLink()`` function will look something like this: .. code-block:: javascript - const addTagFormDeleteLink = (tagFormLi) => { - const removeFormButton = document.createElement('button') - removeFormButton.classList - removeFormButton.innerText = 'Delete this tag' + const addTagFormDeleteLink = (element) => { + const removeFormButton = document.createElement('button'); + removeFormButton.innerText = 'Delete this tag'; - tagFormLi.append(removeFormButton); + element.append(removeFormButton); removeFormButton.addEventListener('click', (e) => { - e.preventDefault() + e.preventDefault(); // remove the li for the tag form - tagFormLi.remove(); + element.remove(); }); } @@ -652,7 +652,6 @@ the relationship between the removed ``Tag`` and ``Task`` object. the `symfony-collection`_ package based on `jQuery`_ for the rest of browsers. .. _`Owning Side and Inverse Side`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/unitofwork-associations.html -.. _`jQuery`: http://jquery.com/ .. _`JSFiddle`: https://jsfiddle.net/ey8ozh6n/ .. _`@a2lix/symfony-collection`: https://github.com/a2lix/symfony-collection .. _`symfony-collection`: https://github.com/ninsuo/symfony-collection From 874f2fdcf975cd3de6e06349347f822b8c01fe1d Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Sun, 16 Jan 2022 13:01:46 +0100 Subject: [PATCH 1395/1519] Minor changes --- form/form_collections.rst | 52 ++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/form/form_collections.rst b/form/form_collections.rst index ca104b80ab4..8b34dc700aa 100644 --- a/form/form_collections.rst +++ b/form/form_collections.rst @@ -238,19 +238,26 @@ it will receive an *unknown* number of tags. Otherwise, you'll see a The ``allow_add`` option also makes a ``prototype`` variable available to you. This "prototype" is a little "template" that contains all the HTML needed to -dynamically create any new "tag" forms with JavaScript. Now add the following -``data-index`` (containing the current "form row" number for the following JavaScript) -and ``data-prototype`` attribute to the existing ``<ul>`` in your template: +dynamically create any new "tag" forms with JavaScript. To render the prototype, add +the following ``data-prototype`` attribute to the existing ``<ul>`` in your +template: .. code-block:: html+twig - <ul class="tags" data-index="{{ form.tags|length > 0 ? form.tags|last.vars.name + 1 : 0 }}" data-prototype="{{ form_widget(form.tags.vars.prototype)|e('html_attr') }}"></ul> + {# the data-index attribute is required for the JavaScript code below #} + <ul class="tags" + data-index="{{ form.tags|length > 0 ? form.tags|last.vars.name + 1 : 0 }}" + data-prototype="{{ form_widget(form.tags.vars.prototype)|e('html_attr') }}" + ></ul> On the rendered page, the result will look something like this: .. code-block:: html - <ul class="tags" data-index="0" data-prototype="<div><label class=" required">__name__</label><div id="task_tags___name__"><div><label for="task_tags___name___name" class=" required">Name</label><input type="text" id="task_tags___name___name" name="task[tags][__name__][name]" required="required" maxlength="255" /></div></div></div>"> + <ul class="tags" + data-index="0" + data-prototype="<div><label class=" required">__name__</label><div id="task_tags___name__"><div><label for="task_tags___name___name" class=" required">Name</label><input type="text" id="task_tags___name___name" name="task[tags][__name__][name]" required="required" maxlength="255" /></div></div></div>" + ></ul> Now add a button to dynamically add a new tag: @@ -282,16 +289,16 @@ Now add a button to dynamically add a new tag: and you need to adjust the following JavaScript accordingly. Now add some JavaScript to read this attribute and dynamically add new tag forms -when the user clicks the "Add a tag" link. - -Add a ``<script>`` tag somewhere on your page to include the required -functionality with JavaScript: +when the user clicks the "Add a tag" link. Add a ``<script>`` tag somewhere +on your page to include the required functionality with JavaScript: .. code-block:: javascript document .querySelectorAll('.add_item_link') - .forEach(btn => btn.addEventListener("click", addFormToCollection)); + .forEach(btn => { + btn.addEventListener("click", addFormToCollection) + }); The ``addFormToCollection()`` function's job will be to use the ``data-prototype`` attribute to dynamically add a new form when this link is clicked. The ``data-prototype`` @@ -304,9 +311,9 @@ you'll replace with a unique, incrementing number (e.g. ``task[tags][3][name]``) const addFormToCollection = (e) => { const collectionHolder = document.querySelector('.' + e.currentTarget.dataset.collectionHolderClass); - const element = document.createElement('li'); + const item = document.createElement('li'); - element.innerHTML = collectionHolder + item.innerHTML = collectionHolder .dataset .prototype .replace( @@ -314,7 +321,7 @@ you'll replace with a unique, incrementing number (e.g. ``task[tags][3][name]``) collectionHolder.dataset.index ); - collectionHolder.appendChild(element); + collectionHolder.appendChild(item); collectionHolder.dataset.index++; }; @@ -530,34 +537,35 @@ First, add a "delete this tag" link to each tag form: .. code-block:: javascript - const tags = document.querySelectorAll('ul.tags li') - tags.forEach((tag) => { - addTagFormDeleteLink(tag) - }) + document + .querySelectorAll('ul.tags li') + .forEach((tag) => { + addTagFormDeleteLink(tag) + }) // ... the rest of the block from above - function addFormToCollection() { + const addFormToCollection = (e) => { // ... // add a delete link to the new form - addTagFormDeleteLink(element); + addTagFormDeleteLink(item); } The ``addTagFormDeleteLink()`` function will look something like this: .. code-block:: javascript - const addTagFormDeleteLink = (element) => { + const addTagFormDeleteLink = (item) => { const removeFormButton = document.createElement('button'); removeFormButton.innerText = 'Delete this tag'; - element.append(removeFormButton); + item.append(removeFormButton); removeFormButton.addEventListener('click', (e) => { e.preventDefault(); // remove the li for the tag form - element.remove(); + item.remove(); }); } From 0aea09a7f054624c83b7ad3170d49cf1e32352db Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Sun, 16 Jan 2022 13:28:24 +0100 Subject: [PATCH 1396/1519] Fix merge --- messenger.rst | 71 +++++++-------------------------------------------- 1 file changed, 9 insertions(+), 62 deletions(-) diff --git a/messenger.rst b/messenger.rst index 75fd129a32d..48b0bf483da 100644 --- a/messenger.rst +++ b/messenger.rst @@ -2152,6 +2152,12 @@ the consumer (e.g. render a template with links). This middleware stores the original request context (i.e. the host, the HTTP port, etc.) which is needed when building absolute URLs. +Add the ``validation`` middleware if you need to validate the message +object using the :doc:`Validator component <validator>` before handling it. +If validation fails, a ``ValidationFailedException`` will be thrown. The +:class:`Symfony\\Component\\Messenger\\Stamp\\ValidationStamp` can be used +to configure the validation groups. + .. configuration-block:: .. code-block:: yaml @@ -2163,6 +2169,7 @@ when building absolute URLs. command_bus: middleware: - router_context + - validation .. code-block:: xml @@ -2180,6 +2187,7 @@ when building absolute URLs. <framework:messenger> <framework:bus name="command_bus"> <framework:middleware id="router_context"/> + <framework:middleware id="validation"/> </framework:bus> </framework:messenger> </framework:config> @@ -2195,70 +2203,9 @@ when building absolute URLs. $bus = $messenger->bus('command_bus'); $bus->middleware()->id('router_context'); + $bus->middleware()->id('validation'); }; - -Other Middlewares -~~~~~~~~~~~~~~~~~ - -.. versionadded:: 4.1 - - The ``validation`` middleware was introduced in Symfony 4.1. - -Add the ``validation`` middleware if you need to validate the message -object using the :doc:`Validator component <validator>` before handling it. -If validation fails, a ``ValidationFailedException`` will be thrown. The -:class:`Symfony\\Component\\Messenger\\Stamp\\ValidationStamp` can be used -to configure the validation groups. - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/messenger.yaml - framework: - messenger: - buses: - command_bus: - middleware: - - validation - - .. code-block:: xml - - <!-- config/packages/messenger.xml --> - <?xml version="1.0" encoding="UTF-8" ?> - <container xmlns="http://symfony.com/schema/dic/services" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:framework="http://symfony.com/schema/dic/symfony" - xsi:schemaLocation="http://symfony.com/schema/dic/services - https://symfony.com/schema/dic/services/services-1.0.xsd - http://symfony.com/schema/dic/symfony - https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - - <framework:config> - <framework:messenger> - <framework:bus name="command_bus"> - <framework:middleware id="validation"/> - </framework:bus> - </framework:messenger> - </framework:config> - </container> - - .. code-block:: php - - // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'buses' => [ - 'command_bus' => [ - 'middleware' => [ - 'validation', - ], - ], - ], - ], - ]); - Messenger Events ~~~~~~~~~~~~~~~~ From 61f50005ebc8e2cde512e0632ffba9e4ce3bc894 Mon Sep 17 00:00:00 2001 From: Maxime Pinot <contact@maximepinot.com> Date: Wed, 22 Dec 2021 14:05:29 +0100 Subject: [PATCH 1397/1519] [Configuration] Multiple environments in a single file --- configuration.rst | 96 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/configuration.rst b/configuration.rst index 4e31c03a3f9..f70f0fa2b61 100644 --- a/configuration.rst +++ b/configuration.rst @@ -410,6 +410,102 @@ In reality, each environment differs only somewhat from others. This means that all environments share a large base of common configuration, which is put in files directly in the ``config/packages/`` directory. +.. tip:: + + You can also define options for different environments in a single configuration file. + + .. versionadded:: 5.3 + + The ability to defined different environments in a single file was introduced in Symfony 5.3. + + .. configuration-block:: + + .. code-block:: yaml + + # config/packages/webpack_encore.yaml + webpack_encore: + # ... + output_path: '%kernel.project_dir%/public/build' + strict_mode: true + cache: false + + when@prod: + webpack_encore: + cache: true + + when@test: + webpack_encore: + strict_mode: false + + .. code-block:: xml + + <!-- config/packages/webpack_encore.xml --> + <?xml version="1.0" encoding="UTF-8" ?> + <container xmlns="http://symfony.com/schema/dic/services" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://symfony.com/schema/dic/services + https://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/symfony + https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> + <webpack-encore:config> + <!-- ... --> + </webpack-encore:config> + + <when env="prod"> + <webpack-encore:config> + <!-- ... --> + </webpack-encore:config> + </when> + + <when env="test"> + <webpack-encore:config> + <!-- ... --> + </webpack-encore:config> + </when> + </container> + + .. code-block:: php + + // config/packages/framework.php + use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; + use Symfony\Config\FrameworkConfig; + + return static function (FrameworkConfig $framework, ContainerConfigurator $container) { + // ... + + if ('prod' === $container->env()) { + // ... + } + + if ('test' === $container->env()) { + $framework->test(true); + $framework->session()->storageFactoryId('session.storage.mock_file'); + } + }; + + Also, if you are using PHP 8.0 or later, you can use the PHP attribute ``#[When]`` to tell that a class should only be registered as services in some environments : + + .. configuration-block:: + + .. code-block:: php-attributes + + use Symfony\Component\DependencyInjection\Attribute\When; + + #[When(env: 'dev')] + class SomeClass + { + // ... + } + + // you can apply more than one attribute to the same class: + + #[When(env: 'dev')] + #[When(env: 'test')] + class AnotherClass + { + // ... + } + .. seealso:: See the ``configureContainer()`` method of From dbc99b8347b1367c98f1ceb2de6f2e26d9366425 Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Sun, 16 Jan 2022 13:44:07 +0100 Subject: [PATCH 1398/1519] Move #[When] attribute to Service Container docs --- configuration.rst | 68 +++++++++++++++++-------------------------- service_container.rst | 29 ++++++++++++++++++ 2 files changed, 56 insertions(+), 41 deletions(-) diff --git a/configuration.rst b/configuration.rst index f70f0fa2b61..569e70a57f9 100644 --- a/configuration.rst +++ b/configuration.rst @@ -412,11 +412,13 @@ files directly in the ``config/packages/`` directory. .. tip:: - You can also define options for different environments in a single configuration file. - .. versionadded:: 5.3 - The ability to defined different environments in a single file was introduced in Symfony 5.3. + The ability to defined different environments in a single file was + introduced in Symfony 5.3. + + You can also define options for different environments in a single + configuration file using the special ``when`` keyword: .. configuration-block:: @@ -429,10 +431,12 @@ files directly in the ``config/packages/`` directory. strict_mode: true cache: false + # cache is enabled only in the "prod" environment when@prod: webpack_encore: cache: true + # disable strict mode only in the "test" environment when@test: webpack_encore: strict_mode: false @@ -447,20 +451,20 @@ files directly in the ``config/packages/`` directory. https://symfony.com/schema/dic/services/services-1.0.xsd http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - <webpack-encore:config> - <!-- ... --> - </webpack-encore:config> + <webpack-encore:config + output-path="%kernel.project_dir%/public/build" + strict-mode="true" + cache="false" + /> + <!-- cache is enabled only in the "test" environment --> <when env="prod"> - <webpack-encore:config> - <!-- ... --> - </webpack-encore:config> + <webpack-encore:config cache="true"/> </when> + <!-- disable strict mode only in the "test" environment --> <when env="test"> - <webpack-encore:config> - <!-- ... --> - </webpack-encore:config> + <webpack-encore:config strict-mode="false"/> </when> </container> @@ -468,43 +472,25 @@ files directly in the ``config/packages/`` directory. // config/packages/framework.php use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; - use Symfony\Config\FrameworkConfig; + use Symfony\Config\WebpackEncoreConfig; - return static function (FrameworkConfig $framework, ContainerConfigurator $container) { - // ... + return static function (WebpackEncoreConfig $webpackEncore, ContainerConfigurator $container) { + $webpackEncore + ->outputPath('%kernel.project_dir%/public/build') + ->strictMode(true) + ->cache(false) + ; + // cache is enabled only in the "prod" environment if ('prod' === $container->env()) { - // ... + $webpackEncore->cache(true); } + // disable strict mode only in the "test" environment if ('test' === $container->env()) { - $framework->test(true); - $framework->session()->storageFactoryId('session.storage.mock_file'); + $webpackEncore->strictMode(false); } }; - - Also, if you are using PHP 8.0 or later, you can use the PHP attribute ``#[When]`` to tell that a class should only be registered as services in some environments : - - .. configuration-block:: - - .. code-block:: php-attributes - - use Symfony\Component\DependencyInjection\Attribute\When; - - #[When(env: 'dev')] - class SomeClass - { - // ... - } - - // you can apply more than one attribute to the same class: - - #[When(env: 'dev')] - #[When(env: 'test')] - class AnotherClass - { - // ... - } .. seealso:: diff --git a/service_container.rst b/service_container.rst index 0e44401bef2..ff1758b1bb3 100644 --- a/service_container.rst +++ b/service_container.rst @@ -222,6 +222,35 @@ each time you ask for it. If you'd prefer to manually wire your service, that's totally possible: see :ref:`services-explicitly-configure-wire-services`. +Limiting Services to a specific Symfony Environment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.3 + + The ``#[When]`` attribute was introduced in Symfony 5.3. + +If you are using PHP 8.0 or later, you can use the ``#[When]`` PHP +attribute to only register the class as a service in some environments:: + + use Symfony\Component\DependencyInjection\Attribute\When; + + // SomeClass is only registered in the "dev" environment + + #[When(env: 'dev')] + class SomeClass + { + // ... + } + + // you can also apply more than one When attribute to the same class + + #[When(env: 'dev')] + #[When(env: 'test')] + class AnotherClass + { + // ... + } + .. _services-constructor-injection: Injecting Services/Config into a Service From 0f820dec3dccbb5d5759fb1fabdf267292a43e4b Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Fri, 7 Jan 2022 18:28:39 +0100 Subject: [PATCH 1399/1519] Advertise Symfony UX form types --- reference/forms/types/map.rst.inc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/reference/forms/types/map.rst.inc b/reference/forms/types/map.rst.inc index 8171c836a4d..52368b05b14 100644 --- a/reference/forms/types/map.rst.inc +++ b/reference/forms/types/map.rst.inc @@ -43,6 +43,14 @@ Other Fields * :doc:`FileType </reference/forms/types/file>` * :doc:`RadioType </reference/forms/types/radio>` +Symfony UX Fields +~~~~~~~~~~~~~~~~~ + +These types are part of the `Symfony UX initiative`_: + +* `CropperType`_ (using Cropper.js) +* `DropzoneType`_ + UID Fields ~~~~~~~~~~ @@ -71,3 +79,7 @@ Base Fields ~~~~~~~~~~~ * :doc:`FormType </reference/forms/types/form>` + +.. _`Symfony UX initiative`: https://github.com/symfony/ux#readme +.. _`CropperType`: https://github.com/symfony/ux/tree/2.x/src/Cropperjs#readme +.. _`DropzoneType`: https://github.com/symfony/ux/tree/2.x/src/Dropzone#readme From 3a66610cd5e40ffdc0fec583d7b3bf139d254f3c Mon Sep 17 00:00:00 2001 From: Mark Pedron <marktpedron@gmail.com> Date: Mon, 17 Jan 2022 07:25:01 +0100 Subject: [PATCH 1400/1519] Remove outdated versionadded 5.* directives For version 6.0, no versionadded <6.0 are allowed. --- configuration.rst | 5 ----- http_client.rst | 4 ---- serializer.rst | 5 ----- service_container.rst | 4 ---- 4 files changed, 18 deletions(-) diff --git a/configuration.rst b/configuration.rst index 90c3b7047e6..b0d87eea3d8 100644 --- a/configuration.rst +++ b/configuration.rst @@ -412,11 +412,6 @@ files directly in the ``config/packages/`` directory. .. tip:: - .. versionadded:: 5.3 - - The ability to defined different environments in a single file was - introduced in Symfony 5.3. - You can also define options for different environments in a single configuration file using the special ``when`` keyword: diff --git a/http_client.rst b/http_client.rst index 0b68740e398..332e2ccd6e3 100644 --- a/http_client.rst +++ b/http_client.rst @@ -1688,10 +1688,6 @@ responses dynamically when it's called:: $client = new MockHttpClient(); $client->setResponseFactory($responses); - .. versionadded:: 5.4 - - The ``setResponseFactory()`` method was introduced in Symfony 5.4. - If you need to test responses with HTTP status codes different than 200, define the ``http_code`` option:: diff --git a/serializer.rst b/serializer.rst index 296d2c7626a..ef4a8e483df 100644 --- a/serializer.rst +++ b/serializer.rst @@ -149,11 +149,6 @@ configuration: ; }; -.. versionadded:: 5.4 - - The ability to configure the ``default_context`` option in the - Serializer was introduced in Symfony 5.4. - .. _serializer-using-serialization-groups-annotations: Using Serialization Groups Annotations diff --git a/service_container.rst b/service_container.rst index 5af42e690c0..62b18134845 100644 --- a/service_container.rst +++ b/service_container.rst @@ -225,10 +225,6 @@ each time you ask for it. Limiting Services to a specific Symfony Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 5.3 - - The ``#[When]`` attribute was introduced in Symfony 5.3. - If you are using PHP 8.0 or later, you can use the ``#[When]`` PHP attribute to only register the class as a service in some environments:: From 96f0174c15cd1d86f024fd81135b6335652abe3e Mon Sep 17 00:00:00 2001 From: Mark Pedron <marktpedron@gmail.com> Date: Sat, 15 Jan 2022 14:08:11 +0100 Subject: [PATCH 1401/1519] Add missing anchor in forms/bootstrap5 Fixes the following diagnostic emitted by `_build/build.php`: ``` Found invalid reference "reference-forms-bootstrap5-error-messages" in file "form/form_customization" ``` --- form/bootstrap5.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/form/bootstrap5.rst b/form/bootstrap5.rst index 9e1f0bd3d45..0a593d0d31c 100644 --- a/form/bootstrap5.rst +++ b/form/bootstrap5.rst @@ -83,6 +83,8 @@ If you prefer to apply the Bootstrap styles on a form to form basis, include the container. If you override the ``row_attr`` class option, the ``mb-3`` will be overridden too and you will need to explicitly add it. +.. _reference-forms-bootstrap5-error-messages: + Error Messages -------------- From c36a74f778d272f16ef0aea3a80da002291d7870 Mon Sep 17 00:00:00 2001 From: Mark Pedron <marktpedron@gmail.com> Date: Sat, 15 Jan 2022 12:34:52 +0100 Subject: [PATCH 1402/1519] Fix bugs seen by `_build/build.php` diagnostics in 5.4 --- components/lock.rst | 28 ++++++++++++++-------------- reference/forms/types/enum.rst | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index 4069a238ee5..0d00885b9c2 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -350,20 +350,20 @@ Locks are created and managed in ``Stores``, which are classes that implement The component includes the following built-in store types: -========================================================= ====== ======== ======== ======= -Store Scope Blocking Expiring Sharing -========================================================= ====== ======== ======== ======= -:ref:`FlockStore <lock-store-flock>` local yes no yes -:ref:`MemcachedStore <lock-store-memcached>` remote no yes no -:ref:`MongoDbStore <lock-store-mongodb>` remote no yes no -:ref:`PdoStore <lock-store-pdo>` remote no yes no -:ref:`DoctrineDbalStore <lock-store-dbal>` remote no yes no -:ref:`PostgreSqlStore <lock-store-pgsql>` remote yes no yes -:ref:`DoctrineDbalPostgreSqlStore <lock-store-dbal-pgsql>` remote yes no yes -:ref:`RedisStore <lock-store-redis>` remote no yes yes -:ref:`SemaphoreStore <lock-store-semaphore>` local yes no no -:ref:`ZookeeperStore <lock-store-zookeeper>` remote no no no -========================================================= ====== ======== ======== ======= +========================================================== ====== ======== ======== ======= +Store Scope Blocking Expiring Sharing +========================================================== ====== ======== ======== ======= +:ref:`FlockStore <lock-store-flock>` local yes no yes +:ref:`MemcachedStore <lock-store-memcached>` remote no yes no +:ref:`MongoDbStore <lock-store-mongodb>` remote no yes no +:ref:`PdoStore <lock-store-pdo>` remote no yes no +:ref:`DoctrineDbalStore <lock-store-dbal>` remote no yes no +:ref:`PostgreSqlStore <lock-store-pgsql>` remote yes no yes +:ref:`DoctrineDbalPostgreSqlStore <lock-store-dbal-pgsql>` remote yes no yes +:ref:`RedisStore <lock-store-redis>` remote no yes yes +:ref:`SemaphoreStore <lock-store-semaphore>` local yes no no +:ref:`ZookeeperStore <lock-store-zookeeper>` remote no no no +========================================================== ====== ======== ======== ======= .. _lock-store-flock: diff --git a/reference/forms/types/enum.rst b/reference/forms/types/enum.rst index 4e598f44e81..213e6bff7d6 100644 --- a/reference/forms/types/enum.rst +++ b/reference/forms/types/enum.rst @@ -9,7 +9,7 @@ EnumType Field The ``EnumType`` form field was introduced in Symfony 5.4. A multi-purpose field used to allow the user to "choose" one or more options -defined in a `PHP enumeration`_. It extends the :doc:`ChoiceType </refernce/forms/types/enum>` +defined in a `PHP enumeration`_. It extends the :doc:`ChoiceType </reference/forms/types/enum>` field and defines the same options. +---------------------------+----------------------------------------------------------------------+ From 70690757bcf51a3bf0c9e764fd5d69225a4a361b Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Wed, 19 Jan 2022 17:14:26 +0100 Subject: [PATCH 1403/1519] [#15990] Minor changes --- messenger.rst | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/messenger.rst b/messenger.rst index 7e8d1aa640f..2d40e64c6c3 100644 --- a/messenger.rst +++ b/messenger.rst @@ -50,11 +50,15 @@ serialized:: .. _messenger-handler: +.. versionadded:: 5.4 + + The ``#[AsMessageHandler]`` PHP attribute was introduced in Symfony + 5.4. PHP attributes require at least PHP 8.0. + A message handler is a PHP callable, the recommended way to create it is to -create a class using :class:`Symfony\\Component\\Messenger\\Attribute\\AsMessageHandler` -attribute which has an ``__invoke()`` method that's type-hinted with the -message class (or a message interface) or you can create a class without the attribute, by implementing -:class:`Symfony\\Component\\Messenger\\Handler\\MessageHandlerInterface`:: +create a class that has the :class:`Symfony\\Component\\Messenger\\Attribute\\AsMessageHandler` +attribute and has an ``__invoke()`` method that's type-hinted with the +message class (or a message interface):: // src/MessageHandler/SmsNotificationHandler.php namespace App\MessageHandler; @@ -71,6 +75,12 @@ message class (or a message interface) or you can create a class without the att } } +.. note:: + + You can also create a class without the attribute (e.g. if you're + using PHP 7.4), by implementing :class:`Symfony\\Component\\Messenger\\Handler\\MessageHandlerInterface` + instead. + Thanks to :ref:`autoconfiguration <services-autoconfigure>` and the ``SmsNotification`` type-hint, Symfony knows that this handler should be called when an ``SmsNotification`` message is dispatched. Most of the time, this is all you need to do. But you can @@ -1770,12 +1780,15 @@ on a case-by-case basis via the :class:`Symfony\\Component\\Messenger\\Stamp\\Se Customizing Handlers -------------------- -.. _messenger-handler-config: +Configuring Handlers Using Attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.4 -Configuring Handlers Using Attribute -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + The ``#[AsMessageHandler]`` PHP attribute was introduced in Symfony + 5.4. PHP attributes require at least PHP 8.0. -You can configure your handler easily by passing options to the attribute:: +You can configure your handler by passing options to the attribute:: // src/MessageHandler/SmsNotificationHandler.php namespace App\MessageHandler; @@ -1793,7 +1806,6 @@ You can configure your handler easily by passing options to the attribute:: } } - Possible options to configure with the attribute are: * ``bus`` @@ -1802,6 +1814,8 @@ Possible options to configure with the attribute are: * ``method`` * ``priority`` +.. _messenger-handler-config: + Manually Configuring Handlers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 2e723657b5207fc1f6a8193f3084a745c12af417 Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Wed, 19 Jan 2022 17:28:00 +0100 Subject: [PATCH 1404/1519] Removed 5.4 versionadded --- messenger.rst | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/messenger.rst b/messenger.rst index e7f92e5ef8e..bca41791b04 100644 --- a/messenger.rst +++ b/messenger.rst @@ -50,11 +50,6 @@ serialized:: .. _messenger-handler: -.. versionadded:: 5.4 - - The ``#[AsMessageHandler]`` PHP attribute was introduced in Symfony - 5.4. PHP attributes require at least PHP 8.0. - A message handler is a PHP callable, the recommended way to create it is to create a class that has the :class:`Symfony\\Component\\Messenger\\Attribute\\AsMessageHandler` attribute and has an ``__invoke()`` method that's type-hinted with the @@ -1689,11 +1684,6 @@ Customizing Handlers Configuring Handlers Using Attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 5.4 - - The ``#[AsMessageHandler]`` PHP attribute was introduced in Symfony - 5.4. PHP attributes require at least PHP 8.0. - You can configure your handler by passing options to the attribute:: // src/MessageHandler/SmsNotificationHandler.php From 7cba7df261287fe8b070108336a1988562c6f54e Mon Sep 17 00:00:00 2001 From: OrangeVinz <orangevinz@gmail.com> Date: Wed, 19 Jan 2022 22:48:02 +0100 Subject: [PATCH 1405/1519] Update login_link.rst --- security/login_link.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/login_link.rst b/security/login_link.rst index 045c9a7963f..137fe734330 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -693,7 +693,7 @@ success handler behaves, create your own handler as a class that implements $user = $token->getUser(); $userApiToken = $user->getApiToken(); - return new JsonResponse(['apiToken' => 'userApiToken']); + return new JsonResponse(['apiToken' => $userApiToken]); } } From 683a6712aa8b3134a5ed035fa7015bd2ee0f0e39 Mon Sep 17 00:00:00 2001 From: Thomas Landauer <thomas@landauer.at> Date: Thu, 20 Jan 2022 20:29:27 +0100 Subject: [PATCH 1406/1519] Moving RexExp search to its own heading I wanted to create a heading ("Search Using a Regular Expression") for this. Is `~~~~` the lowest level already? If yes, I'd suggest to drop the "Method Reference" heading, and promote all included "Methods to..." headings one level. --- components/string.rst | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/components/string.rst b/components/string.rst index f754bfdb7ea..3fc50077094 100644 --- a/components/string.rst +++ b/components/string.rst @@ -318,10 +318,6 @@ Methods to Search and Replace // checks if the string contents are exactly the same as the given contents u('foo')->equalsTo('foo'); // true - // checks if the string content match the given regular expression - u('avatar-73647.png')->match('/avatar-(\d+)\.png/'); - // result = ['avatar-73647.png', '73647'] - // checks if the string contains any of the other given strings u('aeiou')->containsAny('a'); // true u('aeiou')->containsAny(['ab', 'efg']); // false @@ -358,6 +354,22 @@ Methods to Search and Replace The ``containsAny()`` method was introduced in Symfony 5.1. +:: + +You can use ``match()`` to search with a Regular Expression:: + + u('avatar-73647.png')->match('/avatar-(\d+)\.png/'); + // result = ['avatar-73647.png', '73647'] + +By default, PHP's ``preg_match()`` is used, and you can pass search flags as second argument:: + + $string->match('/(a)(b)/', \PREG_UNMATCHED_AS_NULL); + +When passing ``\PREG_PATTERN_ORDER`` or ``\PREG_SET_ORDER``, PHP's ``preg_match_all()`` is used. +Multiple flags can be set with the `|` operator:: + + $string->match('/(a)(b)/', \PREG_PATTERN_ORDER|\PREG_UNMATCHED_AS_NULL); + Methods to Join, Split, Truncate and Reverse ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 418426a3d8e818ac95a38ceeb49abeadb5ba35d4 Mon Sep 17 00:00:00 2001 From: andyexeter <palmer.andy@gmail.com> Date: Fri, 21 Jan 2022 09:57:53 +0000 Subject: [PATCH 1407/1519] Capitalise From and Bcc header names in global mailer configuration --- mailer.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mailer.rst b/mailer.rst index 081a88dea24..7899f449f3b 100644 --- a/mailer.rst +++ b/mailer.rst @@ -535,8 +535,8 @@ and headers. sender: 'fabien@example.com' recipients: ['foo@example.com', 'bar@example.com'] headers: - from: 'Fabien <fabien@example.com>' - bcc: 'baz@example.com' + From: 'Fabien <fabien@example.com>' + Bcc: 'baz@example.com' X-Custom-Header: 'foobar' .. code-block:: xml @@ -558,8 +558,8 @@ and headers. <framework:recipients>foo@example.com</framework:recipients> <framework:recipients>bar@example.com</framework:recipients> </framework:envelope> - <framework:header name="from">Fabien <fabien@example.com></framework:header> - <framework:header name="bcc">baz@example.com</framework:header> + <framework:header name="From">Fabien <fabien@example.com></framework:header> + <framework:header name="Bcc">baz@example.com</framework:header> <framework:header name="X-Custom-Header">foobar</framework:header> </framework:mailer> </framework:config> @@ -578,8 +578,8 @@ and headers. ->recipients(['foo@example.com', 'bar@example.com']) ; - $mailer->header('from')->value('Fabien <fabien@example.com>'); - $mailer->header('bcc')->value('baz@example.com'); + $mailer->header('From')->value('Fabien <fabien@example.com>'); + $mailer->header('Bcc')->value('baz@example.com'); $mailer->header('X-Custom-Header')->value('foobar'); }; From ba95e8ccdb594cbe076ea877b8e04e4ba920b3fd Mon Sep 17 00:00:00 2001 From: Maksim Tiugaev <tugmaks@yandex.ru> Date: Mon, 24 Jan 2022 10:19:19 +0300 Subject: [PATCH 1408/1519] Fix typo in amqp messenger --- messenger.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/messenger.rst b/messenger.rst index 48b0bf483da..24e6768bcb4 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1125,8 +1125,8 @@ The transport has a number of options: ============================================ ================================================= =================================== Option Description Default ============================================ ================================================= =================================== -``auto_setup`` Whether the table should be created ``true`` - automatically during send / get. +``auto_setup`` Whether the exchanges and queues should be ``true`` + created automatically during send / get. ``cacert`` Path to the CA cert file in PEM format. ``cert`` Path to the client certificate in PEM format. ``channel_max`` Specifies highest channel number that the server From 83e0b196d4568be54e56410ee021b2fd3d3c00e3 Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Tue, 25 Jan 2022 13:19:16 +0100 Subject: [PATCH 1409/1519] Cleanup left over 5.x mentions --- security/remember_me.rst | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/security/remember_me.rst b/security/remember_me.rst index 54bd5c58c81..780f67f8070 100644 --- a/security/remember_me.rst +++ b/security/remember_me.rst @@ -279,11 +279,6 @@ Persistent tokens You can then configure this custom handler by configuring the service ID in the ``service`` option under ``remember_me``. - .. versionadded:: 5.1 - - The ``service`` option was introduced in Symfony 5.1. - - .. _security-remember-me-signature: Using Signed Remember Me Tokens @@ -580,10 +575,6 @@ users to change their password. You can do this by leveraging a few special There is also a ``IS_REMEMBERED`` attribute that grants access *only* when the user is authenticated via the remember me mechanism. -.. versionadded:: 5.1 - - The ``IS_REMEMBERED`` attribute was introduced in Symfony 5.1. - Customizing the Remember Me Cookie ---------------------------------- @@ -622,5 +613,3 @@ cookie created by the system: ``samesite`` (default value: ``null``) If set to ``strict``, the cookie associated with this feature will not be sent along with cross-site requests, even when following a regular link. - -.. _`5.2 version of this documentation`: https://symfony.com/doc/5.2/security/remember_me.html From bb9dbe31ab1664b73b228071cc59189342ac6a00 Mon Sep 17 00:00:00 2001 From: Florent Morselli <florent@morselli.fr> Date: Sun, 23 Jan 2022 12:36:33 +0100 Subject: [PATCH 1410/1519] Typo There was a typo where the option `--domain` is in fact `--domains` --- translation.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/translation.rst b/translation.rst index 2d9a66f1c35..3e726e50437 100644 --- a/translation.rst +++ b/translation.rst @@ -750,12 +750,12 @@ now use the following commands to push (upload) and pull (download) translations # push new local translations to the Loco provider for the French locale # and the validators domain. # it will **not** update existing translations already on the provider. - $ php bin/console translation:push loco --locales fr --domain validators + $ php bin/console translation:push loco --locales fr --domains validators # push new local translations and delete provider's translations that not # exists anymore in local files for the French locale and the validators domain. # it will **not** update existing translations already on the provider. - $ php bin/console translation:push loco --delete-missing --locales fr --domain validators + $ php bin/console translation:push loco --delete-missing --locales fr --domains validators # check out the command help to see its options (format, domains, locales, etc.) $ php bin/console translation:push --help @@ -770,7 +770,7 @@ now use the following commands to push (upload) and pull (download) translations # pull new translations from the Loco provider to local files for the French # locale and the validators domain. # it will **not** overwrite your local files, only add new translations. - $ php bin/console translation:pull loco --locales fr --domain validators + $ php bin/console translation:pull loco --locales fr --domains validators # check out the command help to see its options (format, domains, locales, intl-icu, etc.) $ php bin/console translation:pull --help From 4efdd760db1be434254e10bb114456272c9f67df Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Tue, 25 Jan 2022 14:54:34 +0100 Subject: [PATCH 1411/1519] Include match examples in the code block --- components/string.rst | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/components/string.rst b/components/string.rst index 3fc50077094..d5110cac96f 100644 --- a/components/string.rst +++ b/components/string.rst @@ -318,6 +318,16 @@ Methods to Search and Replace // checks if the string contents are exactly the same as the given contents u('foo')->equalsTo('foo'); // true + // checks if the string content match the given regular expression. + // You can pass flags for preg_match() as second argument. If PREG_PATTERN_ORDER + // or PREG_SET_ORDER are passed, preg_match_all() will be used. + u('avatar-73647.png')->match('/avatar-(\d+)\.png/'); + // result = ['avatar-73647.png', '73647'] + u('avatar-73647.png')->match('/avatar-(\d+)(-\d+)?\.png/', \PREG_UNMATCHED_AS_NULL); + // result = ['avatar-73647.png', '73647', null] + u('206-555-0100 and 800-555-1212')->match('/\d{3}-\d{3}-\d{4}/', \PREG_PATTERN_ORDER); + // result = [['206-555-0100', '800-555-1212']] + // checks if the string contains any of the other given strings u('aeiou')->containsAny('a'); // true u('aeiou')->containsAny(['ab', 'efg']); // false @@ -354,22 +364,6 @@ Methods to Search and Replace The ``containsAny()`` method was introduced in Symfony 5.1. -:: - -You can use ``match()`` to search with a Regular Expression:: - - u('avatar-73647.png')->match('/avatar-(\d+)\.png/'); - // result = ['avatar-73647.png', '73647'] - -By default, PHP's ``preg_match()`` is used, and you can pass search flags as second argument:: - - $string->match('/(a)(b)/', \PREG_UNMATCHED_AS_NULL); - -When passing ``\PREG_PATTERN_ORDER`` or ``\PREG_SET_ORDER``, PHP's ``preg_match_all()`` is used. -Multiple flags can be set with the `|` operator:: - - $string->match('/(a)(b)/', \PREG_PATTERN_ORDER|\PREG_UNMATCHED_AS_NULL); - Methods to Join, Split, Truncate and Reverse ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From a358418348cc1bca21f487c2a487950f13e7a1f9 Mon Sep 17 00:00:00 2001 From: Nicolas Jourdan <nicolas.jourdan.c@gmail.com> Date: Wed, 26 Jan 2022 00:52:04 +0100 Subject: [PATCH 1412/1519] Update Traverse.rst Added missing ";" --- reference/constraints/Traverse.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/constraints/Traverse.rst b/reference/constraints/Traverse.rst index dfb92943050..2302139cbb9 100644 --- a/reference/constraints/Traverse.rst +++ b/reference/constraints/Traverse.rst @@ -25,7 +25,7 @@ that all have constraints on their properties. namespace App\Entity; use Doctrine\Common\Collections\ArrayCollection; - use Doctrine\Common\Collections\Collection + use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; From 279da7d7082c01a7f6d3d6148602ca7b2712c6ae Mon Sep 17 00:00:00 2001 From: Kamil P <pesek.kamil@seznam.cz> Date: Fri, 28 Jan 2022 14:16:44 +0100 Subject: [PATCH 1413/1519] Update access_control.rst I believe there should be PUBLIC_ACCESS instead of IS_AUTHENTICATED_ANONYMOUSLY for Symfony 6 --- security/access_control.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/security/access_control.rst b/security/access_control.rst index a19faee19ba..04b05f8bfb4 100644 --- a/security/access_control.rst +++ b/security/access_control.rst @@ -236,7 +236,7 @@ pattern so that it is only accessible by requests from the local server itself: access_control: # # the 'ips' option supports IP addresses and subnet masks - - { path: '^/internal', roles: IS_AUTHENTICATED_ANONYMOUSLY, ips: [127.0.0.1, ::1, 192.168.0.1/24] } + - { 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 @@ -255,7 +255,7 @@ pattern so that it is only accessible by requests from the local server itself: <!-- ... --> <!-- the 'ips' option supports IP addresses and subnet masks --> - <rule path="^/internal" role="IS_AUTHENTICATED_ANONYMOUSLY"> + <rule path="^/internal" role="PUBLIC_ACCESS"> <ip>127.0.0.1</ip> <ip>::1</ip> </rule> @@ -274,7 +274,7 @@ pattern so that it is only accessible by requests from the local server itself: $security->accessControl() ->path('^/internal') - ->roles(['IS_AUTHENTICATED_ANONYMOUSLY']) + ->roles(['PUBLIC_ACCESS']) // the 'ips' option supports IP addresses and subnet masks ->ips(['127.0.0.1', '::1']) ; @@ -302,7 +302,7 @@ address): * Now, the first access control rule is enabled as both the ``path`` and the ``ip`` match: access is allowed as the user always has the - ``IS_AUTHENTICATED_ANONYMOUSLY`` role. + ``PUBLIC_ACCESS`` role. * The second access rule is not examined as the first rule matched. @@ -407,7 +407,7 @@ access those URLs via a specific port. This could be useful for example for security: # ... access_control: - - { path: ^/cart/checkout, roles: IS_AUTHENTICATED_ANONYMOUSLY, port: 8080 } + - { path: ^/cart/checkout, roles: PUBLIC_ACCESS, port: 8080 } .. code-block:: xml @@ -424,7 +424,7 @@ access those URLs via a specific port. This could be useful for example for <config> <!-- ... --> <rule path="^/cart/checkout" - role="IS_AUTHENTICATED_ANONYMOUSLY" + role="PUBLIC_ACCESS" port="8080" /> </config> @@ -440,7 +440,7 @@ access those URLs via a specific port. This could be useful for example for $security->accessControl() ->path('^/cart/checkout') - ->roles(['IS_AUTHENTICATED_ANONYMOUSLY']) + ->roles(['PUBLIC_ACCESS']) ->port(8080) ; }; @@ -461,7 +461,7 @@ the user will be redirected to ``https``: security: # ... access_control: - - { path: ^/cart/checkout, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https } + - { path: ^/cart/checkout, roles: PUBLIC_ACCESS, requires_channel: https } .. code-block:: xml @@ -478,7 +478,7 @@ the user will be redirected to ``https``: <config> <!-- ... --> <rule path="^/cart/checkout" - role="IS_AUTHENTICATED_ANONYMOUSLY" + role="PUBLIC_ACCESS" requires-channel="https" /> </config> @@ -494,7 +494,7 @@ the user will be redirected to ``https``: $security->accessControl() ->path('^/cart/checkout') - ->roles(['IS_AUTHENTICATED_ANONYMOUSLY']) + ->roles(['PUBLIC_ACCESS']) ->requiresChannel('https') ; }; From 6d80ef905b259c9510e2ffb0853f078410f3d28a Mon Sep 17 00:00:00 2001 From: "Phil E. Taylor" <phil@phil-taylor.com> Date: Sun, 30 Jan 2022 01:30:31 +0000 Subject: [PATCH 1414/1519] tidy MESSENGER_CONSUMER_NAME --- messenger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index 19702d4330e..bbdb25f8775 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1504,7 +1504,7 @@ sentinel_master String, if null or empty Sentinel null There should never be more than one ``messenger:consume`` command running with the same combination of ``stream``, ``group`` and ``consumer``, or messages could end up being handled more than once. If you run multiple queue workers, ``consumer`` can be set to an - environment variable (like ``%env(MESSENGER_CONSUMER_NAME)%``) set by Supervisor + environment variable, like ``%env(MESSENGER_CONSUMER_NAME)%``, set by Supervisor (example below) or any other service used to manage the worker processes. In a container environment, the ``HOSTNAME`` can be used as the consumer name, since there is only one worker per container/host. If using Kubernetes to orchestrate the From c6d8d262a8be12bec03c6f02e3805f3b574ba616 Mon Sep 17 00:00:00 2001 From: Ryan Weaver <ryan@thatsquality.com> Date: Mon, 31 Jan 2022 13:52:33 -0500 Subject: [PATCH 1415/1519] Removing extra links from rebasing --- reference/forms/types/map.rst.inc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/reference/forms/types/map.rst.inc b/reference/forms/types/map.rst.inc index c90c6430e70..19fa4c7897c 100644 --- a/reference/forms/types/map.rst.inc +++ b/reference/forms/types/map.rst.inc @@ -41,9 +41,7 @@ Other Fields * :doc:`CheckboxType </reference/forms/types/checkbox>` * :doc:`FileType </reference/forms/types/file>` -* `DropzoneType`_ * :doc:`RadioType </reference/forms/types/radio>` -* `CropperType`_ (to crop images with JavaScript) Symfony UX Fields ~~~~~~~~~~~~~~~~~ @@ -53,12 +51,6 @@ These types are part of the :doc:`Symfony UX initiative </frontend/ux>`: * `CropperType`_ (using Cropper.js) * `DropzoneType`_ -UID Fields -~~~~~~~~~~ - -* :doc:`UuidType </reference/forms/types/uuid>` -* :doc:`UlidType </reference/forms/types/ulid>` - Field Groups ~~~~~~~~~~~~ From 428a0dfbe172a4df8dbb68b2b51c0825e1c63a6b Mon Sep 17 00:00:00 2001 From: "Phil E. Taylor" <phil@phil-taylor.com> Date: Tue, 1 Feb 2022 19:07:45 +0000 Subject: [PATCH 1416/1519] Correct PHP Code block for messenger resetOnMessage --- messenger.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/messenger.rst b/messenger.rst index bbdb25f8775..798dad06636 100644 --- a/messenger.rst +++ b/messenger.rst @@ -768,10 +768,7 @@ reset the service container between two messages: return static function (FrameworkConfig $framework) { $messenger = $framework->messenger(); - $messenger->transport('async') - ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') - ->resetOnMessage(true) - ; + $messenger->resetOnMessage(true); }; .. versionadded:: 5.4 From 6667e41ae309870bdad58e38420d80e95cb2e584 Mon Sep 17 00:00:00 2001 From: fridde <f@hehl.se> Date: Fri, 4 Feb 2022 10:31:35 +0100 Subject: [PATCH 1417/1519] Removed redundancy in package requirements Acoording to [symfony/testpack](https://github.com/symfony/test-pack/blob/main/composer.json) the ```phpunit/phpunit``` package is explictly included. There might be a point in keeping both for clarity, but this redundancy created more confusion than necessary. --- testing.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing.rst b/testing.rst index 43b3b8c631f..863fde4f15d 100644 --- a/testing.rst +++ b/testing.rst @@ -15,13 +15,13 @@ Symfony integrates with an independent library called `PHPUnit`_ to give you a rich testing framework. This article won't cover PHPUnit itself, which has its own excellent `documentation`_. -Before creating your first test, install ``phpunit/phpunit`` and the -``symfony/test-pack``, which installs some other packages providing useful +Before creating your first test, install ``phpunit/phpunit`` by installing +``symfony/test-pack``, which also installs some other packages providing useful Symfony test utilities: .. code-block:: terminal - $ composer require --dev phpunit/phpunit symfony/test-pack + $ composer require --dev symfony/test-pack After the library is installed, try running PHPUnit: From 50b6978fd2c389d5c11df75b2d25b96519bab79c Mon Sep 17 00:00:00 2001 From: jmsche <contact@jmsche.fr> Date: Tue, 1 Feb 2022 15:01:14 +0100 Subject: [PATCH 1418/1519] Fix Markdown code syntax instead of RST --- frontend/encore/installation.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/encore/installation.rst b/frontend/encore/installation.rst index eb4b82e8b45..bcd59f8395e 100644 --- a/frontend/encore/installation.rst +++ b/frontend/encore/installation.rst @@ -188,12 +188,12 @@ a system that you'll learn about soon: And finally, create an ``assets/controllers.json`` file, which also fits into the Stimulus system: -```json -{ - "controllers": [], - "entrypoints": [] -} -``` +.. code-block:: json + + { + "controllers": [], + "entrypoints": [] + } You'll customize and learn more about these files in :doc:`/frontend/encore/simple-example`. When you execute Encore, it will ask you to install a few more dependencies based From 53f91fe49616d9837bd8986f9ba1fd6b3b6b4956 Mon Sep 17 00:00:00 2001 From: BahmanMD <bahman.mehrdad@gmail.com> Date: Thu, 3 Feb 2022 14:55:15 +0330 Subject: [PATCH 1419/1519] Update Twig links and change symfony/var-dumper package installation command --- components/form.rst | 2 +- contributing/documentation/standards.rst | 2 +- form/form_customization.rst | 2 +- form/form_themes.rst | 4 ++-- reference/configuration/twig.rst | 2 +- reference/dic_tags.rst | 4 ++-- reference/twig_reference.rst | 2 +- templates.rst | 20 ++++++++++---------- templating/twig_extension.rst | 6 +++--- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/components/form.rst b/components/form.rst index 64551b72041..93befdf3d1d 100644 --- a/components/form.rst +++ b/components/form.rst @@ -784,4 +784,4 @@ Learn more /form/* .. _Twig: https://twig.symfony.com -.. _`Twig Configuration`: https://twig.symfony.com/doc/2.x/intro.html +.. _`Twig Configuration`: https://twig.symfony.com/doc/3.x/intro.html diff --git a/contributing/documentation/standards.rst b/contributing/documentation/standards.rst index dc43258052e..8e266f68cab 100644 --- a/contributing/documentation/standards.rst +++ b/contributing/documentation/standards.rst @@ -191,7 +191,7 @@ In addition, documentation follows these rules: * trivial .. _`the Sphinx documentation`: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks -.. _`Twig Coding Standards`: https://twig.symfony.com/doc/2.x/coding_standards.html +.. _`Twig Coding Standards`: https://twig.symfony.com/doc/3.x/coding_standards.html .. _`reserved by the IANA`: https://tools.ietf.org/html/rfc2606#section-3 .. _`American English`: https://en.wikipedia.org/wiki/American_English .. _`American English Oxford Dictionary`: https://www.lexico.com/definition/american_english diff --git a/form/form_customization.rst b/form/form_customization.rst index b5c5a23f841..7c1fc159404 100644 --- a/form/form_customization.rst +++ b/form/form_customization.rst @@ -443,4 +443,4 @@ Variable Usage variables a particular field has, find the source code for the form field (and its parent fields) and look at the above two functions. -.. _`the Twig documentation`: https://twig.symfony.com/doc/2.x/templates.html#test-operator +.. _`the Twig documentation`: https://twig.symfony.com/doc/3.x/templates.html#test-operator diff --git a/form/form_themes.rst b/form/form_themes.rst index 1b605e75b49..d048a7c6472 100644 --- a/form/form_themes.rst +++ b/form/form_themes.rst @@ -656,5 +656,5 @@ is a collection of fields (e.g. a whole form), and not just an individual field: .. _`Foundation CSS framework`: https://get.foundation/ .. _`tailwind_2_layout.html.twig`: https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Twig/Resources/views/Form/tailwind_2_layout.html.twig .. _`Tailwind CSS form plugin`: https://tailwindcss-forms.vercel.app/ -.. _`Twig "use" tag`: https://twig.symfony.com/doc/2.x/tags/use.html -.. _`Twig parent() function`: https://twig.symfony.com/doc/2.x/functions/parent.html +.. _`Twig "use" tag`: https://twig.symfony.com/doc/3.x/tags/use.html +.. _`Twig parent() function`: https://twig.symfony.com/doc/3.x/functions/parent.html diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst index c1407d7fbb5..8ac4068517e 100644 --- a/reference/configuration/twig.rst +++ b/reference/configuration/twig.rst @@ -344,5 +344,5 @@ If set to ``true``, Symfony shows an exception whenever a Twig variable, attribute or method doesn't exist. If set to ``false`` these errors are ignored and the non-existing values are replaced by ``null``. -.. _`the optimizer extension`: https://twig.symfony.com/doc/2.x/api.html#optimizer-extension +.. _`the optimizer extension`: https://twig.symfony.com/doc/3.x/api.html#optimizer-extension .. _`XSS attacks`: https://en.wikipedia.org/wiki/Cross-site_scripting diff --git a/reference/dic_tags.rst b/reference/dic_tags.rst index a60148f008b..ce8fcf195d4 100644 --- a/reference/dic_tags.rst +++ b/reference/dic_tags.rst @@ -1333,6 +1333,6 @@ Then, tag it with the ``validator.initializer`` tag (it has no options). For an example, see the ``DoctrineInitializer`` class inside the Doctrine Bridge. -.. _`Twig's documentation`: https://twig.symfony.com/doc/2.x/advanced.html#creating-an-extension -.. _`Twig Loader`: https://twig.symfony.com/doc/2.x/api.html#loaders +.. _`Twig's documentation`: https://twig.symfony.com/doc/3.x/advanced.html#creating-an-extension +.. _`Twig Loader`: https://twig.symfony.com/doc/3.x/api.html#loaders .. _`PHP class preloading`: https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.preload diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index d2246edef52..e905a4d2b05 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -669,4 +669,4 @@ The ``app`` variable is injected automatically by Symfony in all templates and provides access to lots of useful application information. Read more about the :ref:`Twig global app variable <twig-app-variable>`. -.. _`default filters and functions defined by Twig`: https://twig.symfony.com/doc/2.x/#reference +.. _`default filters and functions defined by Twig`: https://twig.symfony.com/doc/3.x/#reference diff --git a/templates.rst b/templates.rst index 5382604cbf0..280a5f9b6df 100644 --- a/templates.rst +++ b/templates.rst @@ -707,7 +707,7 @@ First, make sure that the VarDumper component is installed in the application: .. code-block:: terminal - $ composer require symfony/var-dumper + $ composer require --dev symfony/var-dumper Then, use either the ``{% dump %}`` tag or the ``{{ dump() }}`` function depending on your needs: @@ -1217,16 +1217,16 @@ Learn more /templating/* .. _`Twig`: https://twig.symfony.com -.. _`tags`: https://twig.symfony.com/doc/2.x/tags/index.html -.. _`filters`: https://twig.symfony.com/doc/2.x/filters/index.html -.. _`functions`: https://twig.symfony.com/doc/2.x/functions/index.html -.. _`with_context`: https://twig.symfony.com/doc/2.x/functions/include.html -.. _`Twig template loader`: https://twig.symfony.com/doc/2.x/api.html#loaders -.. _`Twig raw filter`: https://twig.symfony.com/doc/2.x/filters/raw.html -.. _`Twig output escaping docs`: https://twig.symfony.com/doc/2.x/api.html#escaper-extension +.. _`tags`: https://twig.symfony.com/doc/3.x/tags/index.html +.. _`filters`: https://twig.symfony.com/doc/3.x/filters/index.html +.. _`functions`: https://twig.symfony.com/doc/3.x/functions/index.html +.. _`with_context`: https://twig.symfony.com/doc/3.x/functions/include.html +.. _`Twig template loader`: https://twig.symfony.com/doc/3.x/api.html#loaders +.. _`Twig raw filter`: https://twig.symfony.com/doc/3.x/filters/raw.html +.. _`Twig output escaping docs`: https://twig.symfony.com/doc/3.x/api.html#escaper-extension .. _`snake case`: https://en.wikipedia.org/wiki/Snake_case -.. _`Twig template inheritance`: https://twig.symfony.com/doc/2.x/tags/extends.html -.. _`Twig block tag`: https://twig.symfony.com/doc/2.x/tags/block.html +.. _`Twig template inheritance`: https://twig.symfony.com/doc/3.x/tags/extends.html +.. _`Twig block tag`: https://twig.symfony.com/doc/3.x/tags/block.html .. _`Cross-Site Scripting`: https://en.wikipedia.org/wiki/Cross-site_scripting .. _`GitHub Actions`: https://docs.github.com/en/free-pro-team@latest/actions .. _`UX Twig Component`: https://symfony.com/bundles/ux-twig-component/current/index.html diff --git a/templating/twig_extension.rst b/templating/twig_extension.rst index 03fcd7a9471..fc4751dee12 100644 --- a/templating/twig_extension.rst +++ b/templating/twig_extension.rst @@ -170,7 +170,7 @@ If you're using the default ``services.yaml`` configuration, this will already work! Otherwise, :ref:`create a service <service-container-creating-service>` for this class and :doc:`tag your service </service_container/tags>` with ``twig.runtime``. -.. _`Twig Extensions`: https://twig.symfony.com/doc/2.x/advanced.html#creating-an-extension -.. _`default Twig filters and functions`: https://twig.symfony.com/doc/2.x/#reference +.. _`Twig Extensions`: https://twig.symfony.com/doc/3.x/advanced.html#creating-an-extension +.. _`default Twig filters and functions`: https://twig.symfony.com/doc/3.x/#reference .. _`official Twig extensions`: https://github.com/twigphp?q=extra -.. _`global variables`: https://twig.symfony.com/doc/2.x/advanced.html#id1 +.. _`global variables`: https://twig.symfony.com/doc/3.x/advanced.html#id1 From ad0ebaf3d2847751944f1267013cdfadf03256b3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Fri, 4 Feb 2022 10:49:16 +0100 Subject: [PATCH 1420/1519] Remove an unused link --- reference/forms/types/map.rst.inc | 1 - 1 file changed, 1 deletion(-) diff --git a/reference/forms/types/map.rst.inc b/reference/forms/types/map.rst.inc index 100a0b3f5fe..b7ff4fa05cd 100644 --- a/reference/forms/types/map.rst.inc +++ b/reference/forms/types/map.rst.inc @@ -75,6 +75,5 @@ Base Fields * :doc:`FormType </reference/forms/types/form>` -.. _`Symfony UX initiative`: https://github.com/symfony/ux#readme .. _`CropperType`: https://github.com/symfony/ux/tree/2.x/src/Cropperjs#readme .. _`DropzoneType`: https://github.com/symfony/ux/tree/2.x/src/Dropzone#readme From 5b6abf0219422d3374d39b5a95d2b13ef39200d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20K=C3=A4fer?= <michael.kaefer1@gmx.at> Date: Mon, 7 Feb 2022 11:41:04 +0100 Subject: [PATCH 1421/1519] Sync generated values docs for: UUIDs and ULIDs --- components/uid.rst | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index 1e44c6e308f..5f07b8d4dcd 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -166,29 +166,26 @@ type, which converts to/from UUID objects automatically:: The UUID type was introduced in Symfony 5.2. -There is no generator to assign UUIDs automatically as the value of your entity -primary keys, but you can use the following:: +There's also a Doctrine generator to help auto-generate UUID values for the +entity primary keys:: namespace App\Entity; use Doctrine\ORM\Mapping as ORM; + use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator; use Symfony\Component\Uid\Uuid; - // ... class User implements UserInterface { /** * @ORM\Id * @ORM\Column(type="uuid", unique=true) + * @ORM\GeneratedValue(strategy="CUSTOM") + * @ORM\CustomIdGenerator(class=UuidGenerator::class) */ private $id; - public function __construct() - { - $this->id = Uuid::v4(); - } - - public function getId(): Uuid + public function getId(): ?Uuid { return $this->id; } @@ -345,12 +342,12 @@ type, which converts to/from ULID objects automatically:: There's also a Doctrine generator to help auto-generate ULID values for the entity primary keys:: + namespace App\Entity; + + use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator; use Symfony\Component\Uid\Ulid; - /** - * @ORM\Entity(repositoryClass="App\Repository\ProductRepository") - */ class Product { /** @@ -361,8 +358,6 @@ entity primary keys:: */ private $id; - // ... - public function getId(): ?Ulid { return $this->id; From 7a842f1f9359dac67c62e9513e2b315e303e7294 Mon Sep 17 00:00:00 2001 From: Antoine Makdessi <amakdessi@me.com> Date: Tue, 28 Dec 2021 11:17:07 +0100 Subject: [PATCH 1422/1519] [Console] Document AsCommand attribute --- console.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/console.rst b/console.rst index 042554fe006..9215f07d7c6 100644 --- a/console.rst +++ b/console.rst @@ -151,6 +151,30 @@ with the ``console.command`` tag. If you're using the :ref:`default services.yaml configuration <service-container-services-load-example>`, this is already done for you, thanks to :ref:`autoconfiguration <services-autoconfigure>`. +On PHP 8, you can use native attribute ``AsCommand`` to configure:: + + // src/Command/CreateUserCommand.php + namespace App\Command; + + use Symfony\Component\Console\Attribute\AsCommand; + use Symfony\Component\Console\Command\Command; + + #[AsCommand( + name: 'app:create-user', + description: 'Creates a new user.', + hidden: false, + aliases: ['app:add-user'] + )] + class CreateUserCommand extends Command + { + // ... + } + +.. versionadded:: 5.3 + + The ability to use PHP attributes to configure commands was introduced in + Symfony 5.3. + Executing the Command --------------------- From 85322e3f14dfb73ad6f197e885999f0df63fc99f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Wed, 9 Feb 2022 09:27:50 +0100 Subject: [PATCH 1423/1519] Tweaks --- console.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/console.rst b/console.rst index 0c150298859..9de02a4b882 100644 --- a/console.rst +++ b/console.rst @@ -146,12 +146,8 @@ available in the ``configure()`` method:: Registering the Command ----------------------- -Symfony commands must be registered as services and :doc:`tagged </service_container/tags>` -with the ``console.command`` tag. If you're using the -:ref:`default services.yaml configuration <service-container-services-load-example>`, -this is already done for you, thanks to :ref:`autoconfiguration <services-autoconfigure>`. - -On PHP 8, you can use native attribute ``AsCommand`` to configure:: +In PHP 8 and newer versions, you can register the command by adding the +``AsCommand`` attribute to it:: // src/Command/CreateUserCommand.php namespace App\Command; @@ -175,6 +171,11 @@ On PHP 8, you can use native attribute ``AsCommand`` to configure:: The ability to use PHP attributes to configure commands was introduced in Symfony 5.3. +If you can't use PHP attributes, register the command as a service and +:doc:`tag it </service_container/tags>` with the ``console.command`` tag. If you're using the +:ref:`default services.yaml configuration <service-container-services-load-example>`, +this is already done for you, thanks to :ref:`autoconfiguration <services-autoconfigure>`. + Executing the Command --------------------- From ef97649c397256232a6d489d086a1a5318e49b73 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Wed, 9 Feb 2022 09:28:15 +0100 Subject: [PATCH 1424/1519] Remove versionadded directive --- console.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/console.rst b/console.rst index f65228b744f..ec66a73d028 100644 --- a/console.rst +++ b/console.rst @@ -152,11 +152,6 @@ In PHP 8 and newer versions, you can register the command by adding the // ... } -.. versionadded:: 5.3 - - The ability to use PHP attributes to configure commands was introduced in - Symfony 5.3. - If you can't use PHP attributes, register the command as a service and :doc:`tag it </service_container/tags>` with the ``console.command`` tag. If you're using the :ref:`default services.yaml configuration <service-container-services-load-example>`, From 1ec427ad3fb796398b7ee908510aed09b1fccf22 Mon Sep 17 00:00:00 2001 From: Steve <steve.clifton@outlook.com> Date: Wed, 26 Jan 2022 21:24:10 +1300 Subject: [PATCH 1425/1519] Update doctrine.rst Update deprecated command to new Doctrine 2.2 syntax ``` User Deprecated: Since doctrine/doctrine-bundle 2.2: The "Doctrine\Bundle\DoctrineBundle\Command\Proxy\RunSqlDoctrineCommand" (doctrine:query:sql) is deprecated, use dbal:run-sql command instead. ``` --- doctrine.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doctrine.rst b/doctrine.rst index 911c2951f69..e0376774b25 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -397,10 +397,10 @@ you can query the database directly: .. code-block:: terminal - $ php bin/console doctrine:query:sql 'SELECT * FROM product' + $ php bin/console dbal:run-sql 'SELECT * FROM product' # on Windows systems not using Powershell, run this command instead: - # php bin/console doctrine:query:sql "SELECT * FROM product" + # php bin/console dbal:run-sql "SELECT * FROM product" Take a look at the previous example in more detail: From 61a855b01482b6317ac6aa3db7efaf471863a203 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Sun, 16 Jan 2022 15:26:16 +0100 Subject: [PATCH 1426/1519] Update section about http cache --- http_cache.rst | 82 ++++++---------------- reference/configuration/framework.rst | 97 ++++++++++++++++++++++++++- 2 files changed, 115 insertions(+), 64 deletions(-) diff --git a/http_cache.rst b/http_cache.rst index 51d42a5cf71..57750e4b9c8 100644 --- a/http_cache.rst +++ b/http_cache.rst @@ -77,79 +77,35 @@ but it is a great way to start. For details on setting up Varnish, see :doc:`/http_cache/varnish`. -To enable the proxy, first create a caching kernel:: +To enable the proxy for the ``prod`` env, enable the ``framework.http_cache`` setting: - // src/CacheKernel.php - namespace App; +.. configuration-block:: - use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; + .. code-block:: yaml - class CacheKernel extends HttpCache - { - } - -Modify the code of your front controller to wrap the default kernel into the -caching kernel: + # config/packages/framework.yaml + when@prod: + framework: + http_cache: true -.. code-block:: diff + .. code-block:: php - // public/index.php + // config/packages/framework.php + use Symfony\Config\FrameworkConfig; - + use App\CacheKernel; - use App\Kernel; - - // ... - $kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); - + // Wrap the default Kernel with the CacheKernel one in 'prod' environment - + if ('prod' === $kernel->getEnvironment()) { - + return new CacheKernel($kernel); - + } - return $kernel; + return static function (FrameworkConfig $framework) use ($env) { + if ('prod' === $env) { + $framework->httpCache()->enabled(true); + } + }; - -The caching kernel will immediately act as a reverse proxy: caching responses +The kernel will immediately act as a reverse proxy: caching responses from your application and returning them to the client. -.. caution:: - - If you're using the :ref:`framework.http_method_override <configuration-framework-http_method_override>` - option to read the HTTP method from a ``_method`` parameter, see the - above link for a tweak you need to make. - -.. tip:: - - The cache kernel has a special ``getLog()`` method that returns a string - representation of what happened in the cache layer. In the development - environment, use it to debug and validate your cache strategy:: - - error_log($kernel->getLog()); - -The ``CacheKernel`` object has a sensible default configuration, but it can be -finely tuned via a set of options you can set by overriding the -:method:`Symfony\\Bundle\\FrameworkBundle\\HttpCache\\HttpCache::getOptions` -method:: - - // src/CacheKernel.php - namespace App; - - use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; - - class CacheKernel extends HttpCache - { - protected function getOptions(): array - { - return [ - 'default_ttl' => 0, - // ... - ]; - } - } - -For a full list of the options and their meaning, see the -:method:`HttpCache::__construct() documentation <Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache::__construct>`. +The proxy has a sensible default configuration, but it can be +finely tuned via `a set of options<configuration-framework-http_cache>`. -When you're in debug mode (the second argument of ``Kernel`` constructor in the -front controller is ``true``), Symfony automatically adds an ``X-Symfony-Cache`` +When in debug mode, Symfony automatically adds an ``X-Symfony-Cache`` header to the response. You can also use the ``trace_level`` config option and set it to either ``none``, ``short`` or ``full`` to add this information. diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 434952b7da6..b3e72757128 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -53,7 +53,102 @@ will invalidate all signed URIs and Remember Me cookies. That's why, after changing this value, you should regenerate the application cache and log out all the application users. -.. _configuration-framework-http_method_override: +.. _configuration-framework-http_cache: + +http_cache +~~~~~~~~~~ + +.. versionadded:: 5.2 + + The ``http_cache`` option was introduced in Symfony 5.2. + +enabled +....... + +**type**: ``boolean`` **default**: ``false`` + +debug +..... + +**type**: ``boolean`` **default**: ``%kernel.debug%`` + +If true, exceptions are thrown when things go wrong. Otherwise, the cache will +try to carry on and deliver a meaningful response. + +trace_level +........... + +**type**: ``string`` **possible values**: ``'none'``, ``'short'`` or ``'full'`` + +For 'short', a concise trace of the main request will be added as an HTTP header. +'full' will add traces for all requests (including ESI subrequests). +(default: 'full' if in debug; 'none' otherwise) + +trace_header +............ + +**type**: ``string`` + +Header name to use for traces. (default: X-Symfony-Cache) + +default_ttl +........... + +**type**: ``integer`` + +The number of seconds that a cache entry should be considered fresh when no +explicit freshness information is provided in a response. Explicit +Cache-Control or Expires headers override this value. (default: 0) + +private_headers +............... + +**type**: ``array`` + +Set of request headers that trigger "private" cache-control behavior on responses +that don't explicitly state whether the response is public or private via a +Cache-Control directive. (default: Authorization and Cookie) + +allow_reload +............ + +**type**: ``string`` + +Specifies whether the client can force a cache reload by including a +Cache-Control "no-cache" directive in the request. Set it to ``true`` +for compliance with RFC 2616. (default: false) + +allow_revalidate +................ + +**type**: ``string`` + +Specifies whether the client can force a cache revalidate by including a +Cache-Control "max-age=0" directive in the request. Set it to ``true`` +for compliance with RFC 2616. (default: false) + +stale_while_revalidate +...................... + +**type**: ``integer`` + +Specifies the default number of seconds (the granularity is the second as the +Response TTL precision is a second) during which the cache can immediately return +a stale response while it revalidates it in the background (default: 2). +This setting is overridden by the stale-while-revalidate HTTP Cache-Control +extension (see RFC 5861). + +stale_if_error +.............. + +**type**: ``integer`` + +Specifies the default number of seconds (the granularity is the second) during +which the cache can serve a stale response when an error is encountered +(default: 60). This setting is overridden by the stale-if-error HTTP +Cache-Control extension (see RFC 5861). + + .. _configuration-framework-http_method_override: http_method_override ~~~~~~~~~~~~~~~~~~~~ From 8e24122b289f6a816acdef854bdb0ee98b2c3c68 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Wed, 9 Feb 2022 17:36:06 +0100 Subject: [PATCH 1427/1519] Tweaks --- http_cache.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/http_cache.rst b/http_cache.rst index 57750e4b9c8..ba58e38bee7 100644 --- a/http_cache.rst +++ b/http_cache.rst @@ -77,7 +77,8 @@ but it is a great way to start. For details on setting up Varnish, see :doc:`/http_cache/varnish`. -To enable the proxy for the ``prod`` env, enable the ``framework.http_cache`` setting: +Use the ``framework.http_cache`` option to enable the proxy for the +:ref:`prod environment <configuration-environments>`: .. configuration-block:: @@ -103,12 +104,12 @@ The kernel will immediately act as a reverse proxy: caching responses from your application and returning them to the client. The proxy has a sensible default configuration, but it can be -finely tuned via `a set of options<configuration-framework-http_cache>`. +finely tuned via `a set of options <configuration-framework-http_cache>`. -When in debug mode, Symfony automatically adds an ``X-Symfony-Cache`` -header to the response. You can also use the ``trace_level`` config -option and set it to either ``none``, ``short`` or ``full`` to -add this information. +When in :ref:`debug mode <debug-mode>`, Symfony automatically adds an +``X-Symfony-Cache`` header to the response. You can also use the ``trace_level`` +config option and set it to either ``none``, ``short`` or ``full`` to add this +information. ``short`` will add the information for the main request only. It's written in a concise way that makes it easy to record the From af41b73cf39a71d4b9e022e961f3856a162dff30 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Wed, 9 Feb 2022 17:36:57 +0100 Subject: [PATCH 1428/1519] Remove a versionadded directive --- reference/configuration/framework.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index c6daf914edf..d9199fed06c 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -58,10 +58,6 @@ out all the application users. http_cache ~~~~~~~~~~ -.. versionadded:: 5.2 - - The ``http_cache`` option was introduced in Symfony 5.2. - enabled ....... From 10ad5ac55b6291ed727ecb43a91c58d8168083fd Mon Sep 17 00:00:00 2001 From: Oskar Stark <oskarstark@googlemail.com> Date: Thu, 10 Feb 2022 22:08:48 +0100 Subject: [PATCH 1429/1519] Fix: Remove space --- messenger.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/messenger.rst b/messenger.rst index 798dad06636..8fb3ccd8c86 100644 --- a/messenger.rst +++ b/messenger.rst @@ -546,8 +546,8 @@ different messages to them. For example: queue_name: low routing: - 'App\Message\SmsNotification': async_priority_low - 'App\Message\NewUserWelcomeEmail': async_priority_high + 'App\Message\SmsNotification': async_priority_low + 'App\Message\NewUserWelcomeEmail': async_priority_high .. code-block:: xml From 91872e4133b522ac5a7f9e600f08063f325500ad Mon Sep 17 00:00:00 2001 From: Pierre Joube <pierre.joube@gmail.com> Date: Fri, 11 Feb 2022 16:42:52 +0100 Subject: [PATCH 1430/1519] Update uid.rst Reference https://github.com/symfony/symfony/issues/44938#issuecomment-1007229881 --- components/uid.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/uid.rst b/components/uid.rst index 5f07b8d4dcd..e6f68f376fa 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -172,7 +172,6 @@ entity primary keys:: namespace App\Entity; use Doctrine\ORM\Mapping as ORM; - use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator; use Symfony\Component\Uid\Uuid; class User implements UserInterface @@ -181,7 +180,7 @@ entity primary keys:: * @ORM\Id * @ORM\Column(type="uuid", unique=true) * @ORM\GeneratedValue(strategy="CUSTOM") - * @ORM\CustomIdGenerator(class=UuidGenerator::class) + * @ORM\CustomIdGenerator(class="doctrine.uuid_generator") */ private $id; @@ -345,7 +344,6 @@ entity primary keys:: namespace App\Entity; use Doctrine\ORM\Mapping as ORM; - use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator; use Symfony\Component\Uid\Ulid; class Product @@ -354,7 +352,7 @@ entity primary keys:: * @ORM\Id * @ORM\Column(type="ulid", unique=true) * @ORM\GeneratedValue(strategy="CUSTOM") - * @ORM\CustomIdGenerator(class=UlidGenerator::class) + * @ORM\CustomIdGenerator(class="doctrine.ulid_generator") */ private $id; From 9829b13dbfb36b194583f957bde0a5c4c02d85d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jib=C3=A9=20Barth?= <barth.jib@gmail.com> Date: Sat, 12 Feb 2022 19:03:35 +0100 Subject: [PATCH 1431/1519] [Lock] Fix code example for Doctrine based stores --- components/lock.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index 0d00885b9c2..6660b9c9965 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -507,11 +507,11 @@ The DoctrineDbalStore saves locks in an SQL database. It is identical to PdoStor but requires a `Doctrine DBAL Connection`_, or a `Doctrine DBAL URL`_. This store does not support blocking, and expects a TTL to avoid stalled locks:: - use Symfony\Component\Lock\Store\PdoStore; + use Symfony\Component\Lock\Store\DoctrineDbalStore; - // a PDO, a Doctrine DBAL connection or DSN for lazy connecting through PDO + // a Doctrine DBAL connection or DSN $connectionOrURL = 'mysql://myuser:mypassword@127.0.0.1/app'; - $store = new PdoStore($connectionOrURL); + $store = new DoctrineDbalStore($connectionOrURL); .. note:: @@ -566,11 +566,11 @@ The DoctrineDbalPostgreSqlStore uses `Advisory Locks`_ provided by PostgreSQL. It is identical to PostgreSqlStore but requires a `Doctrine DBAL Connection`_ or a `Doctrine DBAL URL`_. It supports native blocking, as well as sharing locks:: - use Symfony\Component\Lock\Store\PostgreSqlStore; + use Symfony\Component\Lock\Store\DoctrineDbalPostgreSqlStore; - // a PDO instance or DSN for lazy connecting through PDO - $databaseConnectionOrDSN = 'pgsql:host=localhost;port=5634;dbname=lock'; - $store = new PostgreSqlStore($databaseConnectionOrDSN, ['db_username' => 'myuser', 'db_password' => 'mypassword']); + // a Doctrine Connection or DSN + $databaseConnectionOrDSN = 'postgresql+advisory://myuser:mypassword@127.0.0.1:5634/lock'; + $store = new DoctrineDbalPostgreSqlStore($databaseConnectionOrDSN); In opposite to the ``DoctrineDbalStore``, the ``DoctrineDbalPostgreSqlStore`` does not need a table to store locks and does not expire. From 17aa593d23a6b31ef22b92dd16b2a7888d727052 Mon Sep 17 00:00:00 2001 From: JakeFr <JakeFr@users.noreply.github.com> Date: Sun, 13 Feb 2022 09:30:01 +0100 Subject: [PATCH 1432/1519] Update event_dispatcher.rst AddEventAliasesPass and RegisterListenersPass constructors were removed in 6.0 --- components/event_dispatcher.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/event_dispatcher.rst b/components/event_dispatcher.rst index 04cb8422d79..0cb9eb87074 100644 --- a/components/event_dispatcher.rst +++ b/components/event_dispatcher.rst @@ -254,13 +254,11 @@ determine which instance is passed. Note that ``AddEventAliasesPass`` has to be processed before ``RegisterListenersPass``. - By default, the listeners pass assumes that the event dispatcher's service + The listeners pass assumes that the event dispatcher's service id is ``event_dispatcher``, that event listeners are tagged with the ``kernel.event_listener`` tag, that event subscribers are tagged with the ``kernel.event_subscriber`` tag and that the alias mapping is - stored as parameter ``event_dispatcher.event_aliases``. You can change these - default values by passing custom values to the constructors of - ``RegisterListenersPass`` and ``AddEventAliasesPass``. + stored as parameter ``event_dispatcher.event_aliases``. .. _event_dispatcher-closures-as-listeners: From e3f19205edfb65be4ee0b0276ad2b8d6a7d71ea3 Mon Sep 17 00:00:00 2001 From: Gabriel Solomon <hello@gabrielsolomon.ro> Date: Sun, 13 Feb 2022 22:24:46 +0200 Subject: [PATCH 1433/1519] Remove reference to PHP Templates in translation --- translation.rst | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/translation.rst b/translation.rst index d32a85b0290..6c18cf3e6f0 100644 --- a/translation.rst +++ b/translation.rst @@ -437,16 +437,6 @@ The ``trans`` filter can be used to translate *variable texts* and complex expre Note that this only influences the current template, not any "included" template (in order to avoid side effects). -PHP Templates -~~~~~~~~~~~~~ - -The translator service is accessible in PHP templates through the -``translator`` helper: - -.. code-block:: html+php - - <?= $view['translator']->trans('Symfony is great') ?> - Forcing the Translator Locale ----------------------------- From 85470c59fdee80982eeb4760808e0376d3ecbe69 Mon Sep 17 00:00:00 2001 From: Issam KHADIRI <khadiri.issam@gmail.com> Date: Sun, 13 Feb 2022 21:23:03 +0100 Subject: [PATCH 1434/1519] Update create_form_type_extension.rst Hello, I think the condition `image_url is not null` is not enough as if we create a FileType form field without the `image_property` it causes an error. Adding `image_url is defined` is necessary because the variable `image_url` is only defined and passed to the view when `image_property` is already defined. --- form/create_form_type_extension.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/form/create_form_type_extension.rst b/form/create_form_type_extension.rst index 9bb0abc2d8e..9e0066d7be8 100644 --- a/form/create_form_type_extension.rst +++ b/form/create_form_type_extension.rst @@ -192,7 +192,7 @@ Specifically, you need to override the ``file_widget`` block: {% block file_widget %} {{ block('form_widget') }} - {% if image_url is not null %} + {% if image_url is defined and image_url is not null %} <img src="{{ asset(image_url) }}"/> {% endif %} {% endblock %} From 4f5845bde259ad62c3347e3f3c07f05c9e785b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= <postmaster@greg0ire.fr> Date: Wed, 16 Feb 2022 10:31:50 +0100 Subject: [PATCH 1435/1519] Recommend a better charset for MySQL UTF8 is meant to be used when using PostgreSQL, and the example is mainly about MySQL. In the case of MySQL, utf8 is a deprecated charset and should not be used. --- reference/configuration/doctrine.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/configuration/doctrine.rst b/reference/configuration/doctrine.rst index 3d2435e73a0..fc85ef8f341 100644 --- a/reference/configuration/doctrine.rst +++ b/reference/configuration/doctrine.rst @@ -62,7 +62,7 @@ The following block shows all possible configuration keys: unix_socket: /tmp/mysql.sock # the DBAL wrapperClass option wrapper_class: App\DBAL\MyConnectionWrapper - charset: UTF8 + charset: utf8mb4 logging: '%kernel.debug%' platform_service: App\DBAL\MyDatabasePlatformService server_version: '5.7' @@ -96,7 +96,7 @@ The following block shows all possible configuration keys: memory="true" unix-socket="/tmp/mysql.sock" wrapper-class="App\DBAL\MyConnectionWrapper" - charset="UTF8" + charset="utf8mb4" logging="%kernel.debug%" platform-service="App\DBAL\MyDatabasePlatformService" server-version="5.7"> From eaa7f027e53988a3153ece0a4142f9d65ceb1188 Mon Sep 17 00:00:00 2001 From: Antoine Makdessi <amakdessi@me.com> Date: Thu, 17 Feb 2022 18:12:48 +0100 Subject: [PATCH 1436/1519] Update route from annotation to attribute --- notifier.rst | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/notifier.rst b/notifier.rst index 1fb68b6416c..25a2ee442fb 100644 --- a/notifier.rst +++ b/notifier.rst @@ -479,9 +479,7 @@ To send a notification, autowire the class InvoiceController extends AbstractController { - /** - * @Route("/invoice/create") - */ + #[Route('/invoice/create')] public function create(NotifierInterface $notifier) { // ... @@ -613,9 +611,7 @@ sent using the Slack transport:: // ... class InvoiceController extends AbstractController { - /** - * @Route("/invoice/create") - */ + #[Route('/invoice/create')] public function invoice(NotifierInterface $notifier) { // ... From 9dc01ff28ad215d3f1cdbb9ae4586568877e4cd9 Mon Sep 17 00:00:00 2001 From: Louis-Marie GABORIT <lm.gabo@gmail.com> Date: Thu, 17 Feb 2022 19:12:49 +0100 Subject: [PATCH 1437/1519] firewall option replace with allowedHosts --- frontend/encore/virtual-machine.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/frontend/encore/virtual-machine.rst b/frontend/encore/virtual-machine.rst index 23010b9f169..04f3c16b1f1 100644 --- a/frontend/encore/virtual-machine.rst +++ b/frontend/encore/virtual-machine.rst @@ -96,7 +96,7 @@ Fix "Invalid Host header" Issue ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Webpack will respond ``Invalid Host header`` when trying to access files from -the dev-server. To fix this, set the ``firewall`` option: +the dev-server. To fix this, set the ``allowedHosts`` option: .. code-block:: javascript @@ -107,16 +107,15 @@ the dev-server. To fix this, set the ``firewall`` option: // ... .configureDevServerOptions(options => { - options.firewall = false; + options.allowedHosts = all; }) .. caution:: - Beware that `it's not recommended to disable the firewall`_ in general, but - here it's required to solve the issue when using Encore in a virtual machine. + Beware that `it's not recommended to set allowedHosts to all`_. Read the dedicated doc to select the value for your environment. .. _`VirtualBox`: https://www.virtualbox.org/ .. _`VMWare`: https://www.vmware.com .. _`NFS`: https://en.wikipedia.org/wiki/Network_File_System .. _`polling`: https://webpack.js.org/configuration/watch/#watchoptionspoll -.. _`it's not recommended to disable the firewall`: https://webpack.js.org/configuration/dev-server/#devserverdisablehostcheck +.. _`it's not recommended to set allowedHosts to all`: https://webpack.js.org/configuration/dev-server/#devserverallowedhosts From 96df4160fc11dbe003eebb48a7dfbb6a45d4e538 Mon Sep 17 00:00:00 2001 From: Antoine Makdessi <amakdessi@me.com> Date: Fri, 18 Feb 2022 14:05:02 +0100 Subject: [PATCH 1438/1519] Update _ux-libraries.rst.inc --- frontend/_ux-libraries.rst.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/_ux-libraries.rst.inc b/frontend/_ux-libraries.rst.inc index 3355d4926e4..c88b6b623ef 100644 --- a/frontend/_ux-libraries.rst.inc +++ b/frontend/_ux-libraries.rst.inc @@ -1,18 +1,18 @@ * `ux-turbo`_: Integration with `Turbo Drive`_ for a single-page-app experience * `ux-live-component`_: Build Dynamic Interfaces with Zero JavaScript * `ux-twig-component`_: Build Twig Components Backed by a PHP Class +* `ux-swup`_: Integration with Swup * `ux-chartjs`_: Easy charts with Chart.js * `ux-lazy-image`_: Optimize Image Loading with BlurHash * `ux-cropperjs`_: Form Type and tools for cropping images * `ux-dropzone`_: Form type for stylized "drop zone" for file uploads -* `ux-swup`_: Integration with Swup .. _`ux-turbo`: https://symfony.com/bundles/ux-turbo/current/index.html .. _`ux-live-component`: https://symfony.com/bundles/ux-live-component/current/index.html .. _`ux-twig-component`: https://symfony.com/bundles/ux-twig-component/current/index.html +.. _`ux-swup`: https://symfony.com/bundles/ux-swup/current/index.html .. _`ux-chartjs`: https://symfony.com/bundles/ux-chartjs/current/index.html .. _`ux-lazy-image`: https://symfony.com/bundles/ux-lazy-image/current/index.html .. _`ux-cropperjs`: https://symfony.com/bundles/ux-cropperjs/current/index.html .. _`ux-dropzone`: https://symfony.com/bundles/ux-dropzone/current/index.html -.. _`ux-swup`: https://symfony.com/bundles/ux-swup/current/index.html .. _`Turbo Drive`: https://turbo.hotwired.dev/ From 20367902b88bf1ba168c6f7ce051f82df94a0e18 Mon Sep 17 00:00:00 2001 From: AymDev <aymericmayeux@gmail.com> Date: Thu, 17 Feb 2022 15:20:32 +0100 Subject: [PATCH 1439/1519] Fix broken link to DoctrineReceiver in Messenger Updates the FQCN for DoctrineReceiver as the class moved in a Bridge namespace after Symfony 6.0 --- messenger/custom-transport.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger/custom-transport.rst b/messenger/custom-transport.rst index ae15b15bbeb..e496fcf6263 100644 --- a/messenger/custom-transport.rst +++ b/messenger/custom-transport.rst @@ -127,7 +127,7 @@ Here is a simplified example of a database transport:: The implementation above is not runnable code but illustrates how a :class:`Symfony\\Component\\Messenger\\Transport\\TransportInterface` could be implemented. For real implementations see :class:`Symfony\\Component\\Messenger\\Transport\\InMemoryTransport` -and :class:`Symfony\\Component\\Messenger\\Transport\\Doctrine\\DoctrineReceiver`. +and :class:`Symfony\\Component\\Messenger\\Bridge\\Doctrine\\Transport\\DoctrineReceiver`. Register your Factory --------------------- From 9a13511af8f439a7116914414ec9b5da5d71cfb1 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Fri, 18 Feb 2022 17:08:08 +0100 Subject: [PATCH 1440/1519] Minor tweak --- frontend/encore/virtual-machine.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/encore/virtual-machine.rst b/frontend/encore/virtual-machine.rst index 04f3c16b1f1..793a74e3d40 100644 --- a/frontend/encore/virtual-machine.rst +++ b/frontend/encore/virtual-machine.rst @@ -112,7 +112,8 @@ the dev-server. To fix this, set the ``allowedHosts`` option: .. caution:: - Beware that `it's not recommended to set allowedHosts to all`_. Read the dedicated doc to select the value for your environment. + Beware that `it's not recommended to set allowedHosts to all`_ in general, but + here it's required to solve the issue when using Encore in a virtual machine. .. _`VirtualBox`: https://www.virtualbox.org/ .. _`VMWare`: https://www.vmware.com From e66b990a14f58fdeef1ed66bd6f744f84ae3a9ac Mon Sep 17 00:00:00 2001 From: Maxime Doutreluingne <maxime.doutreluingne@gmail.com> Date: Sat, 19 Feb 2022 22:11:24 +0100 Subject: [PATCH 1441/1519] Update route from annotation to attribute --- mailer.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mailer.rst b/mailer.rst index 8a27f222d4d..ef99bb86138 100644 --- a/mailer.rst +++ b/mailer.rst @@ -345,9 +345,7 @@ and create an :class:`Symfony\\Component\\Mime\\Email` object:: class MailerController extends AbstractController { - /** - * @Route("/email") - */ + #[Route('/email')] public function sendEmail(MailerInterface $mailer): Response { $email = (new Email()) From 2d6fa201748355e1ec1b9cb204bbb33c7fd61d25 Mon Sep 17 00:00:00 2001 From: Antoine Makdessi <amakdessi@me.com> Date: Sun, 20 Feb 2022 11:25:41 +0100 Subject: [PATCH 1442/1519] Update README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 2139c1599ac..0544eb9db19 100644 --- a/README.markdown +++ b/README.markdown @@ -23,7 +23,7 @@ We love contributors! For more information on how you can contribute, please rea the [Symfony Docs Contributing Guide](https://symfony.com/doc/current/contributing/documentation/overview.html) **Important**: use `4.4` branch as the base of your pull requests, unless you are -documenting a feature that was introduced *after* Symfony 4.4 (e.g. in Symfony 5.2). +documenting a feature that was introduced *after* Symfony 4.4 (e.g. in Symfony 5.4). Build Documentation Locally --------------------------- From 2ebec3bf1a75d1572e405b63215faa01a137be31 Mon Sep 17 00:00:00 2001 From: Issam KHADIRI <khadiri.issam@gmail.com> Date: Sun, 20 Feb 2022 11:40:50 +0100 Subject: [PATCH 1443/1519] Update filesystem.rst Hello, According to the `getLongestCommonBasePath` signature, the method accepts a variadic string parameter $paths and not an array. It means when calling the `Path::getLongestCommonBasePath` with an array, a `TypeError` occurs. I think even the PHPDoc of the `Path::getLongestCommonBasePath` should be updated too as it is mentionned that it can accept an array argument. --- components/filesystem.rst | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/components/filesystem.rst b/components/filesystem.rst index e60e0b389af..091c42c5df3 100644 --- a/components/filesystem.rst +++ b/components/filesystem.rst @@ -438,15 +438,13 @@ Especially when storing many paths, the amount of duplicated information is noticeable. You can use :method:`Symfony\\Component\\Filesystem\\Path::getLongestCommonBasePath` to check a list of paths for a common base path:: - $paths = [ + Path::getLongestCommonBasePath( '/var/www/vhosts/project/httpdocs/config/config.yaml', '/var/www/vhosts/project/httpdocs/config/routing.yaml', '/var/www/vhosts/project/httpdocs/config/services.yaml', '/var/www/vhosts/project/httpdocs/images/banana.gif', - '/var/www/vhosts/project/httpdocs/uploads/images/nicer-banana.gif', - ]; - - Path::getLongestCommonBasePath($paths); + '/var/www/vhosts/project/httpdocs/uploads/images/nicer-banana.gif' + ); // => /var/www/vhosts/project/httpdocs Use this path together with :method:`Symfony\\Component\\Filesystem\\Path::makeRelative` From 1f902e17c9d9e98657370cedece476cfaf7dde25 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Wed, 23 Feb 2022 12:08:43 +0100 Subject: [PATCH 1444/1519] Fix doc for String --- components/string.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/components/string.rst b/components/string.rst index 85f020eb6ed..caff1413382 100644 --- a/components/string.rst +++ b/components/string.rst @@ -334,12 +334,11 @@ Methods to Search and Replace u('foo')->equalsTo('foo'); // true // checks if the string content match the given regular expression. - // You can pass flags for preg_match() as second argument. If PREG_PATTERN_ORDER - // or PREG_SET_ORDER are passed, preg_match_all() will be used. u('avatar-73647.png')->match('/avatar-(\d+)\.png/'); - // result = ['avatar-73647.png', '73647'] - u('avatar-73647.png')->match('/avatar-(\d+)(-\d+)?\.png/', \PREG_UNMATCHED_AS_NULL); // result = ['avatar-73647.png', '73647', null] + + // You can pass flags for preg_match() as second argument. If PREG_PATTERN_ORDER + // or PREG_SET_ORDER are passed, preg_match_all() will be used. u('206-555-0100 and 800-555-1212')->match('/\d{3}-\d{3}-\d{4}/', \PREG_PATTERN_ORDER); // result = [['206-555-0100', '800-555-1212']] From 60eb02497144ffc0eb8c8b01c36a71934b41986f Mon Sep 17 00:00:00 2001 From: Thibault RICHARD <thibault@widop.com> Date: Tue, 1 Mar 2022 13:14:53 +0100 Subject: [PATCH 1445/1519] [FrameworkBundle] Change exceptions title level --- reference/configuration/framework.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index b3e72757128..1ffd77d90f1 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -3476,7 +3476,7 @@ a normal workflow or a state machine. Read :doc:`this article </workflow/workflo to know their differences. exceptions -"""""""""" +~~~~~~~~~~ **type**: ``array`` From 9dd602067c574ab73d4993865d1c4a0fd936b766 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Fri, 4 Mar 2022 08:57:55 +0100 Subject: [PATCH 1446/1519] Fix wrong markup --- http_cache.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http_cache.rst b/http_cache.rst index ba58e38bee7..e4efce9077c 100644 --- a/http_cache.rst +++ b/http_cache.rst @@ -104,7 +104,7 @@ The kernel will immediately act as a reverse proxy: caching responses from your application and returning them to the client. The proxy has a sensible default configuration, but it can be -finely tuned via `a set of options <configuration-framework-http_cache>`. +finely tuned via :ref:`a set of options <configuration-framework-http_cache>`. When in :ref:`debug mode <debug-mode>`, Symfony automatically adds an ``X-Symfony-Cache`` header to the response. You can also use the ``trace_level`` From 90cd82a6f378f5c485bbdc015f88ffda32ade2a0 Mon Sep 17 00:00:00 2001 From: Julien Dephix <jdephix@hotmail.com> Date: Tue, 8 Mar 2022 08:19:05 +0100 Subject: [PATCH 1447/1519] Update filesystem.rst so backslash is displayed Hi, here's my very modest contribution! Thanks --- components/filesystem.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/filesystem.rst b/components/filesystem.rst index 091c42c5df3..83f9c59de3f 100644 --- a/components/filesystem.rst +++ b/components/filesystem.rst @@ -348,7 +348,7 @@ following rules iteratively until no further processing can be done: - "." segments are removed; - ".." segments are resolved; -- backslashes ("\") are converted into forward slashes ("/"); +- backslashes ("\\") are converted into forward slashes ("/"); - root paths ("/" and "C:/") always terminate with a slash; - non-root paths never terminate with a slash; - schemes (such as "phar://") are kept; From 01c2ec90bc3ef39121802fe5569c45419a5eb39c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Tue, 8 Mar 2022 09:44:31 +0100 Subject: [PATCH 1448/1519] Remove unused reference --- controller/argument_value_resolver.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/controller/argument_value_resolver.rst b/controller/argument_value_resolver.rst index d79b7a481b9..5d5abc7ed62 100644 --- a/controller/argument_value_resolver.rst +++ b/controller/argument_value_resolver.rst @@ -255,4 +255,3 @@ passing the user along sub-requests). .. _`@ParamConverter`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html .. _`yield`: https://www.php.net/manual/en/language.generators.syntax.php -.. _`SecurityBundle`: https://github.com/symfony/security-bundle From 0d520c9a837844e7e3d1506a05829ca358d7a968 Mon Sep 17 00:00:00 2001 From: mark2016 <markgiglio@gmail.com> Date: Mon, 7 Mar 2022 16:36:38 +1100 Subject: [PATCH 1449/1519] Update doctrine.rst Fix the line numbering of the description of the ProductController to correctly align with the described line (the second half of them were about 2 out). --- doctrine.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doctrine.rst b/doctrine.rst index e0376774b25..044da160db8 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -414,13 +414,13 @@ Take a look at the previous example in more detail: *entity manager* object, which is the most important object in Doctrine. It's responsible for saving objects to, and fetching objects from, the database. -* **lines 20-23** In this section, you instantiate and work with the ``$product`` +* **lines 18-21** In this section, you instantiate and work with the ``$product`` object like any other normal PHP object. -* **line 26** The ``persist($product)`` call tells Doctrine to "manage" the +* **line 24** The ``persist($product)`` call tells Doctrine to "manage" the ``$product`` object. This does **not** cause a query to be made to the database. -* **line 29** When the ``flush()`` method is called, Doctrine looks through +* **line 27** When the ``flush()`` method is called, Doctrine looks through all of the objects that it's managing to see if they need to be persisted to the database. In this example, the ``$product`` object's data doesn't exist in the database, so the entity manager executes an ``INSERT`` query, From 4172b97fb687fab9b5cebdf8eda06d08348bd5d0 Mon Sep 17 00:00:00 2001 From: Johan de Jager <johan@laptify.nl> Date: Wed, 9 Mar 2022 19:16:51 +0100 Subject: [PATCH 1450/1519] Typo --- security/voters.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/voters.rst b/security/voters.rst index 026716e0deb..600fee884dd 100644 --- a/security/voters.rst +++ b/security/voters.rst @@ -55,7 +55,7 @@ which makes creating a voter even easier:: .. tip:: - Checking each voter several times can be time consumming for applications + Checking each voter several times can be time consuming for applications that perform a lot of permission checks. To improve performance in those cases, you can make your voters implement the :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\CacheableVoterInterface`. This allows the access decision manager to remember the attribute and type From c3afa28bb106f6347919ecb73578cad6344af869 Mon Sep 17 00:00:00 2001 From: Pierre Joube <pierre.joube@gmail.com> Date: Thu, 10 Mar 2022 16:52:12 +0100 Subject: [PATCH 1451/1519] Update configurators.rst The first example at https://symfony.com/doc/current/service_container/configurators.html#using-the-configurator will never work because ConfiguratorTrait::configurator(string|array|ReferenceConfigurator $configurator) expect only one parameter. Configurator will try to call special __invoke() (which is probably undefined at this point) method while the user expects to call configure() method. We must provide an array in this case. --- service_container/configurators.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service_container/configurators.rst b/service_container/configurators.rst index 1ade37244c3..7cf3f4e09c5 100644 --- a/service_container/configurators.rst +++ b/service_container/configurators.rst @@ -181,10 +181,10 @@ all the classes are already loaded as services. All you need to do is specify th // override the services to set the configurator // In versions earlier to Symfony 5.1 the service() function was called ref() $services->set(NewsletterManager::class) - ->configurator(service(EmailConfigurator::class), 'configure'); + ->configurator([service(EmailConfigurator::class), 'configure']); $services->set(GreetingCardManager::class) - ->configurator(service(EmailConfigurator::class), 'configure'); + ->configurator([service(EmailConfigurator::class), 'configure']); }; .. _configurators-invokable: From 81faf5e3503409a001ea52c92b2a3acfd4baa935 Mon Sep 17 00:00:00 2001 From: Thomas Landauer <thomas@landauer.at> Date: Thu, 10 Mar 2022 18:11:22 +0100 Subject: [PATCH 1452/1519] Fixing link --- reference/forms/types/enum.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/forms/types/enum.rst b/reference/forms/types/enum.rst index 213e6bff7d6..b2e960a21ec 100644 --- a/reference/forms/types/enum.rst +++ b/reference/forms/types/enum.rst @@ -9,7 +9,7 @@ EnumType Field The ``EnumType`` form field was introduced in Symfony 5.4. A multi-purpose field used to allow the user to "choose" one or more options -defined in a `PHP enumeration`_. It extends the :doc:`ChoiceType </reference/forms/types/enum>` +defined in a `PHP enumeration`_. It extends the :doc:`ChoiceType </reference/forms/types/choice>` field and defines the same options. +---------------------------+----------------------------------------------------------------------+ From dab392b1ffb8ac7a2bfa5932ee1af67c990a3b8e Mon Sep 17 00:00:00 2001 From: Issam KHADIRI <khadiri.issam@gmail.com> Date: Sat, 12 Feb 2022 15:17:50 +0100 Subject: [PATCH 1453/1519] [Form] Update choice_loader.rst.inc --- reference/forms/types/options/choice_loader.rst.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/forms/types/options/choice_loader.rst.inc b/reference/forms/types/options/choice_loader.rst.inc index c44601ed3eb..9ab1fa2c4bb 100644 --- a/reference/forms/types/options/choice_loader.rst.inc +++ b/reference/forms/types/options/choice_loader.rst.inc @@ -42,9 +42,9 @@ better performance:: class ConstantsType extends AbstractType { - public static function getExtendedTypes(): iterable + public function getParent(): string { - return [ChoiceType::class]; + return ChoiceType::class; } public function configureOptions(OptionsResolver $resolver) From 48124cf2f4d92220f8cf10c040c9209b6f8086fc Mon Sep 17 00:00:00 2001 From: BahmanMD <bahman.mehrdad@gmail.com> Date: Sat, 5 Feb 2022 11:00:34 +0330 Subject: [PATCH 1454/1519] Update session.rst v5.4/6 --- session.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/session.rst b/session.rst index 1bea562164c..0331b964cfd 100644 --- a/session.rst +++ b/session.rst @@ -26,6 +26,7 @@ sessions, check their default configuration: # improves the security of the cookies used for sessions cookie_secure: auto cookie_samesite: lax + storage_factory_id: session.storage.factory.native .. code-block:: xml @@ -48,7 +49,8 @@ sessions, check their default configuration: --> <framework:session handler-id="null" cookie-secure="auto" - cookie-samesite="lax"/> + cookie-samesite="lax" + storage_factory_id="session.storage.factory.native"/> </framework:config> </container> @@ -68,6 +70,7 @@ sessions, check their default configuration: // improves the security of the cookies used for sessions ->cookieSecure('auto') ->cookieSamesite('lax') + ->storage_factory_id('session.storage.factory.native') ; }; From 30e02a99fb5e36da8c29b68bdbcf0376db860b3f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Fri, 11 Mar 2022 16:41:03 +0100 Subject: [PATCH 1455/1519] Removed redundancy in package requirements --- testing.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/testing.rst b/testing.rst index 44cd42f964d..c978c7a1ace 100644 --- a/testing.rst +++ b/testing.rst @@ -15,13 +15,12 @@ Symfony integrates with an independent library called `PHPUnit`_ to give you a rich testing framework. This article won't cover PHPUnit itself, which has its own excellent `documentation`_. -Before creating your first test, install ``phpunit/phpunit`` and the -``symfony/test-pack``, which installs some other packages providing useful -Symfony test utilities: +Before creating your first test, install ``symfony/test-pack``, which installs +some other packages needed for testing (such as ``phpunit/phpunit``): .. code-block:: terminal - $ composer require --dev phpunit/phpunit symfony/test-pack + $ composer require --dev symfony/test-pack After the library is installed, try running PHPUnit: From 0b1f3021bd2f6faebdc1664317612aa2dbad06ca Mon Sep 17 00:00:00 2001 From: Thomas Landauer <thomas@landauer.at> Date: Sat, 12 Mar 2022 15:01:33 +0100 Subject: [PATCH 1456/1519] Typo --- reference/constraints/All.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/constraints/All.rst b/reference/constraints/All.rst index cfcf75343fd..70a8b9e4fe4 100644 --- a/reference/constraints/All.rst +++ b/reference/constraints/All.rst @@ -43,7 +43,7 @@ entry in that array: use Symfony\Component\Validator\Constraints as Assert; - // IMPORTANT: nested attributes requires PHP 8.1 or higher + // IMPORTANT: nested attributes require PHP 8.1 or higher class User { #[Assert\All([ From eb2ce88c6d6a09ec4d541b16f6d2c80af1e4e898 Mon Sep 17 00:00:00 2001 From: Ahmed Bouras <48674780+ahmedbrs@users.noreply.github.com> Date: Sun, 13 Mar 2022 16:04:04 +0100 Subject: [PATCH 1457/1519] Update service_container.rst Hi ! If I'm not mistaking, we should extending the AbstractController to add a service in a controller. --- service_container.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/service_container.rst b/service_container.rst index ff1758b1bb3..3dea1fe9825 100644 --- a/service_container.rst +++ b/service_container.rst @@ -32,10 +32,11 @@ service's class or interface name. Want to :doc:`log </logging>` something? No p namespace App\Controller; use Psr\Log\LoggerInterface; + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; - class ProductController + class ProductController extends AbstractController { /** * @Route("/products") From 0d166d7093d487080c41e59cc35297331a2a2e05 Mon Sep 17 00:00:00 2001 From: Maxime Doutreluingne <maxime.doutreluingne@gmail.com> Date: Wed, 16 Mar 2022 14:49:37 +0100 Subject: [PATCH 1458/1519] [Security] Fix wrong anchor --- security.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security.rst b/security.rst index 16442d23b58..d29f1480f78 100644 --- a/security.rst +++ b/security.rst @@ -28,7 +28,7 @@ creates a ``security.yaml`` configuration file for you: # config/packages/security.yaml security: enable_authenticator_manager: true - # https://symfony.com/doc/current/security.html#c-hashing-passwords + # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords password_hashers: Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers From 052071e8331ffae8bae7ae649f244a6cf8cd6082 Mon Sep 17 00:00:00 2001 From: Antoine Makdessi <amakdessi@me.com> Date: Wed, 16 Mar 2022 17:46:40 +0100 Subject: [PATCH 1459/1519] Reference the internal ErrorDetailsStamp Close https://github.com/symfony/symfony-docs/issues/14319 --- components/messenger.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/messenger.rst b/components/messenger.rst index 2e853f69ab6..99946b72b7e 100644 --- a/components/messenger.rst +++ b/components/messenger.rst @@ -162,6 +162,8 @@ Here are some important envelope stamps that are shipped with the Symfony Messen to configure the serialization groups used by the transport. #. :class:`Symfony\\Component\\Messenger\\Stamp\\ValidationStamp`, to configure the validation groups used when the validation middleware is enabled. +#. :class:`Symfony\\Component\\Messenger\\Stamp\\ErrorDetailsStamp`, + an internal stamp when a messages fails due to an exception in the handler. Instead of dealing directly with the messages in the middleware you receive the envelope. Hence you can inspect the envelope content and its stamps, or add any:: From c22dc202295691bbdf2168af3ddaab8a26258935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= <jerome@tamarelle.net> Date: Wed, 16 Mar 2022 18:03:42 +0100 Subject: [PATCH 1460/1519] Documentation for env() function in route condition --- routing.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/routing.rst b/routing.rst index 9f7a1fca581..74e3a7fee02 100644 --- a/routing.rst +++ b/routing.rst @@ -414,6 +414,11 @@ and can use any of these variables created by Symfony: The :ref:`Symfony Request <component-http-foundation-request>` object that represents the current request. +Additionnal functions are provided: + +``env(string $name)`` + Read a variable using :doc:`Environment Variable Processors <configuration/env_var_processors>` + Behind the scenes, expressions are compiled down to raw PHP. Because of this, using the ``condition`` key causes no extra overhead beyond the time it takes for the underlying PHP to execute. From 9cb56a29c1100f528d362ae8d02369abd3f58b7d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano <j.boggiano@seld.be> Date: Thu, 17 Mar 2022 10:11:09 +0100 Subject: [PATCH 1461/1519] Add hint how to debug argument resolver order --- controller/argument_value_resolver.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/controller/argument_value_resolver.rst b/controller/argument_value_resolver.rst index 5d5abc7ed62..bc023101fce 100644 --- a/controller/argument_value_resolver.rst +++ b/controller/argument_value_resolver.rst @@ -242,6 +242,13 @@ Otherwise, set a priority lower than ``100`` to make sure the argument resolver is not triggered when the ``Request`` attribute is present (for example, when passing the user along sub-requests). +To ensure your resolvers are added in the right position you can run the following +command to see which argument resolvers are present and in which order they run. + +.. code-block:: terminal + + $ php bin/console debug:container debug.argument_resolver.inner --show-arguments + .. tip:: As you can see in the ``UserValueResolver::supports()`` method, the user From a8c4ec341ab87239f07325cc0936635fbeab920d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano <j.boggiano@seld.be> Date: Thu, 17 Mar 2022 10:20:36 +0100 Subject: [PATCH 1462/1519] Add hint about #[CurrentUser] to the argument_value_resolver page --- controller/argument_value_resolver.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/controller/argument_value_resolver.rst b/controller/argument_value_resolver.rst index 5d5abc7ed62..0c96f1a3663 100644 --- a/controller/argument_value_resolver.rst +++ b/controller/argument_value_resolver.rst @@ -49,9 +49,10 @@ In addition, some components and official bundles provide other value resolvers: :class:`Symfony\\Component\\Security\\Http\\Controller\\UserValueResolver` Injects the object that represents the current logged in user if type-hinted - with ``UserInterface``. Default value can be set to ``null`` in case - the controller can be accessed by anonymous users. It requires installing - the :doc:`SecurityBundle </security>`. + with ``UserInterface``. You can also type-hint your own ``User`` class but you + must then add the ``#[CurrentUser]`` attribute to the argument. Default value + can be set to ``null`` in case the controller can be accessed by anonymous + users. It requires installing the :doc:`SecurityBundle </security>`. Adding a Custom Value Resolver ------------------------------ From a9171b66203b121932b39e703aff3967bd8029d2 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano <j.boggiano@seld.be> Date: Fri, 18 Mar 2022 10:39:34 +0100 Subject: [PATCH 1463/1519] Update CI to php 8.1 --- .github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6750bd8eb20..33d174e3b8d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -23,7 +23,7 @@ jobs: - name: "Set-up PHP" uses: shivammathur/setup-php@v2 with: - php-version: 8.0 + php-version: 8.1 coverage: none tools: "composer:v2" @@ -91,7 +91,7 @@ jobs: - name: Set-up PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.0 + php-version: 8.1 coverage: none - name: Fetch branch from where the PR started From c8d9c56715443edcfa06106a1d1849416af7957a Mon Sep 17 00:00:00 2001 From: Jeroen <1517978+Jeroeny@users.noreply.github.com> Date: Fri, 18 Mar 2022 11:13:18 +0100 Subject: [PATCH 1464/1519] Reference latest feature branch --- contributing/code/pull_requests.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/contributing/code/pull_requests.rst b/contributing/code/pull_requests.rst index 22c144423c8..d56c95ee9cf 100644 --- a/contributing/code/pull_requests.rst +++ b/contributing/code/pull_requests.rst @@ -129,7 +129,7 @@ work: </contributing/code/maintenance>` (you may have to choose a higher branch if the feature you are fixing was introduced in a later version); -* ``5.x``, if you are adding a new feature. +* ``6.1``, if you are adding a new feature. The only exception is when a new :doc:`major Symfony version </contributing/community/releases>` (5.0, 6.0, etc.) comes out every two years. Because of the @@ -152,7 +152,7 @@ topic branch: .. code-block:: terminal - $ git checkout -b BRANCH_NAME 5.x + $ git checkout -b BRANCH_NAME 6.1 Or, if you want to provide a bug fix for the ``4.4`` branch, first track the remote ``4.4`` branch locally: @@ -281,15 +281,15 @@ while to finish your changes): .. code-block:: terminal - $ git checkout 5.x + $ git checkout 6.1 $ git fetch upstream - $ git merge upstream/5.x + $ git merge upstream/6.1 $ git checkout BRANCH_NAME - $ git rebase 5.x + $ git rebase 6.1 .. tip:: - Replace ``5.x`` with the branch you selected previously (e.g. ``4.4``) + Replace ``6.1`` with the branch you selected previously (e.g. ``4.4``) if you are working on a bug fix. When doing the ``rebase`` command, you might have to fix merge conflicts. @@ -502,7 +502,7 @@ PR. Before re-submitting the PR, rebase with ``upstream/5.x`` or .. code-block:: terminal - $ git rebase -f upstream/5.x + $ git rebase -f upstream/6.1 $ git push --force origin BRANCH_NAME .. note:: From 440c1e3d246537bddec877ee9d4c33b0ddee1ca3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Mon, 21 Mar 2022 14:54:10 +0100 Subject: [PATCH 1465/1519] Use PHP attribute to define the route --- service_container.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/service_container.rst b/service_container.rst index 8a97ecc234e..772d01249a4 100644 --- a/service_container.rst +++ b/service_container.rst @@ -126,9 +126,7 @@ inside your controller:: class ProductController extends AbstractController { - /** - * @Route("/products/new") - */ + #[Route('/products/new')] public function new(MessageGenerator $messageGenerator): Response { // thanks to the type-hint, the container will instantiate a From 0f437c08a31b32391dbe3cf4d51c978f261c0d56 Mon Sep 17 00:00:00 2001 From: Mokhtar Tlili <tlili.mokhtar@gmail.com> Date: Mon, 6 Sep 2021 19:49:39 +0200 Subject: [PATCH 1466/1519] Update upload_file.rst --- controller/upload_file.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/upload_file.rst b/controller/upload_file.rst index 2abf1dc34c0..8f64fb10f80 100644 --- a/controller/upload_file.rst +++ b/controller/upload_file.rst @@ -199,7 +199,7 @@ There are some important things to consider in the code of the above controller: #. A well-known security best practice is to never trust the input provided by users. This also applies to the files uploaded by your visitors. The ``UploadedFile`` class provides methods to get the original file extension - (:method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::getExtension`), + (:method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::getClientOriginalExtension`), the original file size (:method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::getSize`) and the original file name (:method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::getClientOriginalName`). However, they are considered *not safe* because a malicious user could tamper From 8f6defb36f5ce26418a89118d46509e1d35916de Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Mon, 21 Mar 2022 16:09:42 +0100 Subject: [PATCH 1467/1519] Minor syntax issue --- security/expressions.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/security/expressions.rst b/security/expressions.rst index 88bebd5dc07..319a26ea659 100644 --- a/security/expressions.rst +++ b/security/expressions.rst @@ -80,8 +80,7 @@ Additionally, you have access to a number of functions inside the expression: .. deprecated:: 5.4 - The ``is_anonymous()`` function is - deprecated since Symfony 5.4. + The ``is_anonymous()`` function is deprecated since Symfony 5.4. .. sidebar:: ``is_remember_me()`` is different than checking ``IS_AUTHENTICATED_REMEMBERED`` From cbfac3de0d04d344f914fd51c7b82c2976116003 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Mon, 21 Mar 2022 16:10:31 +0100 Subject: [PATCH 1468/1519] Remove deprecated features --- security/expressions.rst | 8 -------- 1 file changed, 8 deletions(-) diff --git a/security/expressions.rst b/security/expressions.rst index 319a26ea659..7e5bc03b06a 100644 --- a/security/expressions.rst +++ b/security/expressions.rst @@ -64,10 +64,6 @@ Additionally, you have access to a number of functions inside the expression: ``is_authenticated()`` Returns ``true`` if the user is authenticated via "remember-me" or authenticated "fully" - i.e. returns true if the user is "logged in". -``is_anonymous()`` - Returns ``true`` if the user is anonymous. That is, the firewall confirms that it - does not know this user's identity. This is different from ``IS_AUTHENTICATED_ANONYMOUSLY``, - which is granted to *all* users, including authenticated ones. ``is_remember_me()`` Similar, but not equal to ``IS_AUTHENTICATED_REMEMBERED``, see below. ``is_fully_authenticated()`` @@ -78,10 +74,6 @@ Additionally, you have access to a number of functions inside the expression: equivalent to using the :ref:`isGranted() method <security-isgranted>` from the security service. -.. deprecated:: 5.4 - - The ``is_anonymous()`` function is deprecated since Symfony 5.4. - .. sidebar:: ``is_remember_me()`` is different than checking ``IS_AUTHENTICATED_REMEMBERED`` The ``is_remember_me()`` and ``is_fully_authenticated()`` functions are *similar* From 9e6b105a830ba5e233cb923e01aa58e0c30f2a1c Mon Sep 17 00:00:00 2001 From: Thomas Landauer <thomas@landauer.at> Date: Mon, 3 Jan 2022 15:14:41 +0100 Subject: [PATCH 1469/1519] Explaining how to actually get the session from `Request` Question: Shouldn't `Request` be shown as preferred way (not `RequestStack`), since injecting `Request` is needed for forms anyway (whereas I've never needed to inject `RequestStack`)? --- session.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/session.rst b/session.rst index 0331b964cfd..3b469bb7ff5 100644 --- a/session.rst +++ b/session.rst @@ -135,7 +135,7 @@ Check out the Symfony config reference to learn more about the other available Basic Usage ----------- -The session is available through the Request and the RequestStack. +The session is available through ``->getSession()`` from the ``Request`` and the ``RequestStack``. Symfony provides a request_stack service that is injected in your services and controllers if you type-hint an argument with :class:`Symfony\\Component\\HttpFoundation\\RequestStack`:: From 540b18391f3326cd4eefac19aa1c2bbce259d3ff Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Mon, 21 Mar 2022 17:15:09 +0100 Subject: [PATCH 1470/1519] Minor reword --- session.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/session.rst b/session.rst index 3b469bb7ff5..ec9982ae921 100644 --- a/session.rst +++ b/session.rst @@ -135,10 +135,9 @@ Check out the Symfony config reference to learn more about the other available Basic Usage ----------- -The session is available through ``->getSession()`` from the ``Request`` and the ``RequestStack``. -Symfony provides a request_stack service that is injected in your services and -controllers if you type-hint an argument with -:class:`Symfony\\Component\\HttpFoundation\\RequestStack`:: +The session is available through the ``Request`` object and the ``RequestStack`` +service. Symfony injects the ``request_stack`` service in services and controllers +if you type-hint an argument with :class:`Symfony\\Component\\HttpFoundation\\RequestStack`:: use Symfony\Component\HttpFoundation\RequestStack; From a4b642217fce82d7e388918c19a35d53d80d188b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Zaj=C4=85c?= <bzajacc@gmail.com> Date: Fri, 31 Dec 2021 20:24:43 +0100 Subject: [PATCH 1471/1519] [Messenger] Fix check_delayed_interval option in messenger doctrine psqltransport --- messenger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index 18b1e5d6911..c7749b13dc8 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1359,7 +1359,7 @@ in the table. Option Description Default ======================= ========================================== ====================== use_notify Whether to use LISTEN/NOTIFY. true -check_delayed_interval The interval to check for delayed 1000 +check_delayed_interval The interval to check for delayed 60000 messages, in milliseconds. Set to 0 to disable checks. get_notify_timeout The length of time to wait for a 0 From bcc13a0b81ea46226206b2b32850c146febcca5f Mon Sep 17 00:00:00 2001 From: Andrea Cristaudo <andrea-cristaudo@users.noreply.github.com> Date: Sat, 11 Sep 2021 10:07:57 +0200 Subject: [PATCH 1472/1519] Add a note on "--no-plugins" Composer option effects When you use the "--no-plugins" Composer option the autoload_runtime.php file won't be created. --- components/runtime.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/runtime.rst b/components/runtime.rst index aaa532a380f..a6d25ae230a 100644 --- a/components/runtime.rst +++ b/components/runtime.rst @@ -53,6 +53,12 @@ the component. This file runs the following logic: .. caution:: +<<<<<<< HEAD +======= + If you use the Composer ``--no-plugins`` option the ``autoload_runtime.php`` + file won't be created. + +>>>>>>> af698f2b2 (Add a note on "--no-plugins" Composer option effects) If you use the Composer ``--no-scripts`` option, make sure your Composer version is ``>=2.1.3``; otherwise the ``autoload_runtime.php`` file won't be created. From 75862b664c5afdee67b909e9ccdd374a4ba70e64 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Tue, 22 Mar 2022 09:07:25 +0100 Subject: [PATCH 1473/1519] Minor syntax fixes --- components/runtime.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/components/runtime.rst b/components/runtime.rst index a6d25ae230a..979a5a13aa7 100644 --- a/components/runtime.rst +++ b/components/runtime.rst @@ -53,12 +53,9 @@ the component. This file runs the following logic: .. caution:: -<<<<<<< HEAD -======= - If you use the Composer ``--no-plugins`` option the ``autoload_runtime.php`` + If you use the Composer ``--no-plugins`` option, the ``autoload_runtime.php`` file won't be created. ->>>>>>> af698f2b2 (Add a note on "--no-plugins" Composer option effects) If you use the Composer ``--no-scripts`` option, make sure your Composer version is ``>=2.1.3``; otherwise the ``autoload_runtime.php`` file won't be created. From 5c488c8e0a5b0439618ea5264603ac1455c3b68e Mon Sep 17 00:00:00 2001 From: Vincent Huck <vincent.huck.pro@gmail.com> Date: Thu, 24 Mar 2022 07:27:58 +0100 Subject: [PATCH 1474/1519] Add missing signature_properties config --- security/login_link.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/security/login_link.rst b/security/login_link.rst index 137fe734330..40679e50071 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -61,7 +61,9 @@ under the firewall. You must configure a ``check_route`` and <config> <firewall name="main"> - <login-link check-route="login_check"/> + <login-link check-route="login_check"> + <signature-property>id</signature-property> + </login-link> </firewall> </config> </srv:container> @@ -75,6 +77,7 @@ under the firewall. You must configure a ``check_route`` and $security->firewall('main') ->loginLink() ->checkRoute('login_check') + ->signatureProperties(['id']) ; }; From c3fe53a61695371e3d9034d7968c929181232051 Mon Sep 17 00:00:00 2001 From: Antoine Makdessi <amakdessi@me.com> Date: Wed, 23 Mar 2022 18:54:55 +0100 Subject: [PATCH 1475/1519] Update uid.rst --- components/uid.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/uid.rst b/components/uid.rst index e6f68f376fa..c2a0c79315b 100644 --- a/components/uid.rst +++ b/components/uid.rst @@ -120,7 +120,10 @@ UUID objects created with the ``Uuid`` class can use the following methods // getting the UUID datetime (it's only available in certain UUID types) $uuid = Uuid::v1(); - $uuid->getDateTime(); // returns a \DateTimeImmutable instance + $uuid->getDateTime(); // returns a \DateTimeImmutable instance + + // checking if a given value is valid as UUID + $isValid = Uuid::isValid($uuid); // true or false // comparing UUIDs and checking for equality $uuid1 = Uuid::v1(); From d106d63da931f623ecff146aea0af45b253238ba Mon Sep 17 00:00:00 2001 From: Manuel Transfeld <auipga@users.noreply.github.com> Date: Fri, 25 Mar 2022 15:25:04 +0100 Subject: [PATCH 1476/1519] Fix minor typo --- setup/upgrade_major.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/upgrade_major.rst b/setup/upgrade_major.rst index a9381d49854..af6544e3849 100644 --- a/setup/upgrade_major.rst +++ b/setup/upgrade_major.rst @@ -237,7 +237,7 @@ method: The behavior of this script can be modified using the ``SYMFONY_PATCH_TYPE_DECLARATIONS`` env var. The value of this env var is url-encoded (e.g. -``param1=value2¶m2=value2``), the following parameters are available: +``param1=value1¶m2=value2``), the following parameters are available: ``force`` Enables fixing return types, the value must be one of: From 85b5b9d42944ef10f972c9998d3b6d9aeb3b2840 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Fri, 25 Mar 2022 15:56:21 +0100 Subject: [PATCH 1477/1519] Fix minor typo --- setup/upgrade_major.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/upgrade_major.rst b/setup/upgrade_major.rst index f2cffe9679c..49fc1acf192 100644 --- a/setup/upgrade_major.rst +++ b/setup/upgrade_major.rst @@ -241,7 +241,7 @@ method: The behavior of this script can be modified using the ``SYMFONY_PATCH_TYPE_DECLARATIONS`` env var. The value of this env var is url-encoded (e.g. -``param1=value2¶m2=value2``), the following parameters are available: +``param1=value1¶m2=value2``), the following parameters are available: ``force`` Enables fixing return types, the value must be one of: From 5e159d7ab8549afa24eeea5b75f7d19e910f0ad8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Fri, 25 Mar 2022 16:57:51 +0100 Subject: [PATCH 1478/1519] Tweaks --- routing.rst | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/routing.rst b/routing.rst index 74e3a7fee02..877f21b87cc 100644 --- a/routing.rst +++ b/routing.rst @@ -370,6 +370,8 @@ arbitrary matching logic: condition: "context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'" # expressions can also include configuration parameters: # condition: "request.headers.get('User-Agent') matches '%app.allowed_browsers%'" + # expressions can even use environment variables: + # condition: "context.getHost() == env('APP_MAIN_HOST')" .. code-block:: xml @@ -384,6 +386,8 @@ arbitrary matching logic: <condition>context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'</condition> <!-- expressions can also include configuration parameters: --> <!-- <condition>request.headers.get('User-Agent') matches '%app.allowed_browsers%'</condition> --> + <!-- expressions can even use environment variables: --> + <!-- <condition>context.getHost() == env('APP_MAIN_HOST')</condition> --> </route> </routes> @@ -398,7 +402,9 @@ arbitrary matching logic: ->controller([DefaultController::class, 'contact']) ->condition('context.getMethod() in ["GET", "HEAD"] and request.headers.get("User-Agent") matches "/firefox/i"') // expressions can also include configuration parameters: - // 'request.headers.get("User-Agent") matches "%app.allowed_browsers%"' + // ->condition('request.headers.get("User-Agent") matches "%app.allowed_browsers%"') + // expressions can even use environment variables: + // ->condition('context.getHost() == env("APP_MAIN_HOST")') ; }; @@ -414,10 +420,10 @@ and can use any of these variables created by Symfony: The :ref:`Symfony Request <component-http-foundation-request>` object that represents the current request. -Additionnal functions are provided: +You can also use this function: ``env(string $name)`` - Read a variable using :doc:`Environment Variable Processors <configuration/env_var_processors>` + Returns the value of a variable using :doc:`Environment Variable Processors <configuration/env_var_processors>` Behind the scenes, expressions are compiled down to raw PHP. Because of this, using the ``condition`` key causes no extra overhead beyond the time it takes From ab67a3f3e7fd73b6029c5ca5e7a8b8a4fabdcbad Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Fri, 25 Mar 2022 17:30:00 +0100 Subject: [PATCH 1479/1519] Added the versionadded directive --- components/messenger.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/messenger.rst b/components/messenger.rst index 99946b72b7e..17586282221 100644 --- a/components/messenger.rst +++ b/components/messenger.rst @@ -163,7 +163,11 @@ Here are some important envelope stamps that are shipped with the Symfony Messen #. :class:`Symfony\\Component\\Messenger\\Stamp\\ValidationStamp`, to configure the validation groups used when the validation middleware is enabled. #. :class:`Symfony\\Component\\Messenger\\Stamp\\ErrorDetailsStamp`, - an internal stamp when a messages fails due to an exception in the handler. + an internal stamp when a message fails due to an exception in the handler. + +.. versionadded:: 5.2 + + The ``ErrorDetailsStamp`` stamp was introduced in Symfony 5.2. Instead of dealing directly with the messages in the middleware you receive the envelope. Hence you can inspect the envelope content and its stamps, or add any:: From 14badd3649cc7d9e35ce6c9a98f8d0d00e1f3c81 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Fri, 25 Mar 2022 17:30:45 +0100 Subject: [PATCH 1480/1519] Remove the versionadded directive --- components/messenger.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/components/messenger.rst b/components/messenger.rst index 17586282221..7ca24d02ec3 100644 --- a/components/messenger.rst +++ b/components/messenger.rst @@ -165,10 +165,6 @@ Here are some important envelope stamps that are shipped with the Symfony Messen #. :class:`Symfony\\Component\\Messenger\\Stamp\\ErrorDetailsStamp`, an internal stamp when a message fails due to an exception in the handler. -.. versionadded:: 5.2 - - The ``ErrorDetailsStamp`` stamp was introduced in Symfony 5.2. - Instead of dealing directly with the messages in the middleware you receive the envelope. Hence you can inspect the envelope content and its stamps, or add any:: From 274053351d008608e59b5b0c7a7cc22aecf69c37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= <kevin@dunglas.fr> Date: Sun, 27 Mar 2022 22:05:10 +0200 Subject: [PATCH 1481/1519] [Security] fix method name in custom_authenticator.rst --- security/custom_authenticator.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/custom_authenticator.rst b/security/custom_authenticator.rst index fc2487c0caf..f75cb8df444 100644 --- a/security/custom_authenticator.rst +++ b/security/custom_authenticator.rst @@ -350,7 +350,7 @@ Passport Attributes Besides badges, passports can define attributes, which allows the ``authenticate()`` method to store arbitrary information in the passport to access it from other -authenticator methods (e.g. ``createAuthenticatedToken()``):: +authenticator methods (e.g. ``createToken()``):: // ... use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; @@ -371,7 +371,7 @@ authenticator methods (e.g. ``createAuthenticatedToken()``):: return $passport; } - public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface + public function createToken(PassportInterface $passport, string $firewallName): TokenInterface { // read the attribute value return new CustomOauthToken($passport->getUser(), $passport->getAttribute('scope')); From 69d9bed9a621d54b00dd1f6981419f1c9ff70040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20P?= <n3wborn@protonmail.com> Date: Sat, 2 Apr 2022 20:46:10 +0200 Subject: [PATCH 1482/1519] [HttpFoundation] replace attributes with query Fix: https://github.com/symfony/symfony-docs/issues/16678 --- create_framework/front_controller.rst | 6 +++--- create_framework/http_foundation.rst | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/create_framework/front_controller.rst b/create_framework/front_controller.rst index 3480ee7a40e..fded71a7b1c 100644 --- a/create_framework/front_controller.rst +++ b/create_framework/front_controller.rst @@ -38,7 +38,7 @@ Let's see it in action:: // framework/index.php require_once __DIR__.'/init.php'; - $name = $request->attributes->get('name', 'World'); + $name = $request->query->get('name', 'World'); $response->setContent(sprintf('Hello %s', htmlspecialchars($name, ENT_QUOTES, 'UTF-8'))); $response->send(); @@ -98,7 +98,7 @@ Such a script might look like the following:: And here is for instance the new ``hello.php`` script:: // framework/hello.php - $name = $request->attributes->get('name', 'World'); + $name = $request->query->get('name', 'World'); $response->setContent(sprintf('Hello %s', htmlspecialchars($name, ENT_QUOTES, 'UTF-8'))); In the ``front.php`` script, ``$map`` associates URL paths with their @@ -190,7 +190,7 @@ And the ``hello.php`` script can now be converted to a template: .. code-block:: html+php <!-- example.com/src/pages/hello.php --> - <?php $name = $request->attributes->get('name', 'World') ?> + <?php $name = $request->query->get('name', 'World') ?> Hello <?= htmlspecialchars($name, ENT_QUOTES, 'UTF-8') ?> diff --git a/create_framework/http_foundation.rst b/create_framework/http_foundation.rst index e6a5c8b2714..dd838e9a5e2 100644 --- a/create_framework/http_foundation.rst +++ b/create_framework/http_foundation.rst @@ -141,7 +141,7 @@ Now, let's rewrite our application by using the ``Request`` and the $request = Request::createFromGlobals(); - $name = $request->attributes->get('name', 'World'); + $name = $request->query->get('name', 'World'); $response = new Response(sprintf('Hello %s', htmlspecialchars($name, ENT_QUOTES, 'UTF-8'))); From bd41d26f1300665f4459f0d203c30b45e917acf6 Mon Sep 17 00:00:00 2001 From: Maksim Tiugaev <tugmaks@yandex.ru> Date: Mon, 4 Apr 2022 20:49:39 +0300 Subject: [PATCH 1483/1519] Minor fixes in partial denormalizing --- components/serializer.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/serializer.rst b/components/serializer.rst index 8cfbc5d4927..acd7de09d6a 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -1248,7 +1248,7 @@ collect all exceptions at once, and to get the object partially denormalized:: ]); } catch (PartialDenormalizationException $e) { $violations = new ConstraintViolationList(); - /** @var NotNormalizableValueException */ + /** @var NotNormalizableValueException $exception */ foreach ($e->getErrors() as $exception) { $message = sprintf('The type must be one of "%s" ("%s" given).', implode(', ', $exception->getExpectedTypes()), $exception->getCurrentType()); $parameters = []; @@ -1256,7 +1256,7 @@ collect all exceptions at once, and to get the object partially denormalized:: $parameters['hint'] = $exception->getMessage(); } $violations->add(new ConstraintViolation($message, '', $parameters, null, $exception->getPath(), null)); - }; + } return $this->json($violations, 400); } From 07bce89fe688c15f18a8580baa7b7c61d5ff2b7c Mon Sep 17 00:00:00 2001 From: David Buchmann <david.buchmann@liip.ch> Date: Tue, 5 Apr 2022 15:13:19 +0200 Subject: [PATCH 1484/1519] add note how to avoid amqp queues autocreation --- messenger.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/messenger.rst b/messenger.rst index afb3426e7d4..e900ae832c7 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1193,6 +1193,7 @@ it in the ``port`` parameter of the DSN (e.g. ``amqps://localhost?cacert=/etc/ss By default, the transport will automatically create any exchanges, queues and binding keys that are needed. That can be disabled, but some functionality may not work correctly (like delayed queues). + To not autocreate any queues, you can configure a transport with `queues: []`. .. note:: From 3b6ade97b409401ade5c95f87e1a581f2b5eb89b Mon Sep 17 00:00:00 2001 From: Norbert Schultheisz <schultheisz.norbert@webshippy.com> Date: Wed, 6 Apr 2022 07:28:02 +0000 Subject: [PATCH 1485/1519] Revert "[Messenger] Redis Sentinel support" This reverts commit c4fe71f03557c8c847557f569337bfc3dd6db729. --- messenger.rst | 78 +++++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 46 deletions(-) diff --git a/messenger.rst b/messenger.rst index afb3426e7d4..f5d2277a93d 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1454,47 +1454,38 @@ A number of options can be configured via the DSN or via the ``options`` key under the transport in ``messenger.yaml``: -======================= ===================================== ================================= -Option Description Default -======================= ===================================== ================================= -stream The Redis stream name messages -group The Redis consumer group name symfony -consumer Consumer name used in Redis consumer -auto_setup Create the Redis group automatically? true -auth The Redis password -delete_after_ack If ``true``, messages are deleted false - automatically after processing them -delete_after_reject If ``true``, messages are deleted true - automatically if they are rejected -lazy Connect only when a connection is false - really needed -serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` - in Redis (the - ``Redis::OPT_SERIALIZER`` option) -stream_max_entries The maximum number of entries which ``0`` (which means "no trimming") - the stream will be trimmed to. Set - it to a large enough number to - avoid losing pending messages -tls Enable TLS support for the connection false -redeliver_timeout Timeout before retrying a pending ``3600`` - message which is owned by an - abandoned consumer (if a worker died - for some reason, this will occur, - eventually you should retry the - message) - in seconds. -claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) - messages should be checked for to - claim - in milliseconds -sentinel_persistent_id String, if null connection is null - non-persistent. -sentinel_retry_interval Int, value in milliseconds ``0`` -sentinel_read_timeout Float, value in seconds ``0`` - default indicates unlimited -sentinel_timeout Float, value in seconds ``0`` - default indicates unlimited -sentinel_master String, if null or empty Sentinel null - support is disabled -======================= ===================================== ================================= +=================== ===================================== ================================= +Option Description Default +=================== ===================================== ================================= +stream The Redis stream name messages +group The Redis consumer group name symfony +consumer Consumer name used in Redis consumer +auto_setup Create the Redis group automatically? true +auth The Redis password +delete_after_ack If ``true``, messages are deleted false + automatically after processing them +delete_after_reject If ``true``, messages are deleted true + automatically if they are rejected +lazy Connect only when a connection is false + really needed +serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` + in Redis (the + ``Redis::OPT_SERIALIZER`` option) +stream_max_entries The maximum number of entries which ``0`` (which means "no trimming") + the stream will be trimmed to. Set + it to a large enough number to + avoid losing pending messages +tls Enable TLS support for the connection false +redeliver_timeout Timeout before retrying a pending ``3600`` + message which is owned by an + abandoned consumer (if a worker died + for some reason, this will occur, + eventually you should retry the + message) - in seconds. +claim_interval Interval on which pending/abandoned ``60000`` (1 Minute) + messages should be checked for to + claim - in milliseconds +=================== ===================================== ================================= .. caution:: @@ -1523,11 +1514,6 @@ sentinel_master String, if null or empty Sentinel null The ``delete_after_reject`` and ``lazy`` options were introduced in Symfony 5.2. -.. versionadded:: 5.4 - - The ``sentinel_persistent_id``, ``sentinel_retry_interval``, ``sentinel_read_timeout``, - ``sentinel_timeout``, and ``sentinel_master`` options were introduced in Symfony 5.4. - .. deprecated:: 5.4 Not setting a explicit value for the ``delete_after_ack`` option is From f083d696482e44cb84f915f9ab0f3509a58a99a4 Mon Sep 17 00:00:00 2001 From: HypeMC <hypemc@gmail.com> Date: Wed, 6 Apr 2022 22:39:48 +0200 Subject: [PATCH 1486/1519] [Config] Add Kernel method override example for php/xml formats --- configuration.rst | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/configuration.rst b/configuration.rst index 6fcab2514ad..679240d7a54 100644 --- a/configuration.rst +++ b/configuration.rst @@ -65,7 +65,26 @@ shown in these three formats. Starting from Symfony 5.1, by default Symfony only loads the configuration files defined in YAML format. If you define configuration in XML and/or PHP formats, update the ``src/Kernel.php`` file to add support for the ``.xml`` - and ``.php`` file extensions. + and ``.php`` file extensions by overriding the + :method:`Symfony\\Component\\HttpKernel\\Kernel::configureContainer` method:: + + // src/Kernel.php + use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; + + private function configureContainer(ContainerConfigurator $container): void + { + $configDir = $this->getConfigDir(); + + $container->import($configDir.'/{packages}/*.{yaml,php}'); + $container->import($configDir.'/{packages}/'.$this->environment.'/*.{yaml,php}'); + + if (is_file($configDir.'/services.yaml')) { + $container->import($configDir.'/services.yaml'); + $container->import($configDir.'/{services}_'.$this->environment.'.yaml'); + } else { + $container->import($configDir.'/{services}.php'); + } + } There isn't any practical difference between formats. In fact, Symfony transforms and caches all of them into PHP before running the application, so From 1695ba7156c8cfd0e48c132e4d9cd63d453ff5d4 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Fri, 8 Apr 2022 16:06:13 +0200 Subject: [PATCH 1487/1519] Minor syntax fix --- messenger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index f91125d7000..605561e39d5 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1193,7 +1193,7 @@ it in the ``port`` parameter of the DSN (e.g. ``amqps://localhost?cacert=/etc/ss By default, the transport will automatically create any exchanges, queues and binding keys that are needed. That can be disabled, but some functionality may not work correctly (like delayed queues). - To not autocreate any queues, you can configure a transport with `queues: []`. + To not autocreate any queues, you can configure a transport with ``queues: []``. .. note:: From d75e3c51d5e55b0b5c7b54af5ace79882e783b70 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Fri, 8 Apr 2022 16:27:59 +0200 Subject: [PATCH 1488/1519] Minor tweak --- configuration.rst | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/configuration.rst b/configuration.rst index 679240d7a54..ef6050ba34f 100644 --- a/configuration.rst +++ b/configuration.rst @@ -70,19 +70,25 @@ shown in these three formats. // src/Kernel.php use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; + use Symfony\Component\HttpKernel\Kernel as BaseKernel; - private function configureContainer(ContainerConfigurator $container): void + class Kernel extends BaseKernel { - $configDir = $this->getConfigDir(); + // ... + + private function configureContainer(ContainerConfigurator $container): void + { + $configDir = $this->getConfigDir(); - $container->import($configDir.'/{packages}/*.{yaml,php}'); - $container->import($configDir.'/{packages}/'.$this->environment.'/*.{yaml,php}'); + $container->import($configDir.'/{packages}/*.{yaml,php}'); + $container->import($configDir.'/{packages}/'.$this->environment.'/*.{yaml,php}'); - if (is_file($configDir.'/services.yaml')) { - $container->import($configDir.'/services.yaml'); - $container->import($configDir.'/{services}_'.$this->environment.'.yaml'); - } else { - $container->import($configDir.'/{services}.php'); + if (is_file($configDir.'/services.yaml')) { + $container->import($configDir.'/services.yaml'); + $container->import($configDir.'/{services}_'.$this->environment.'.yaml'); + } else { + $container->import($configDir.'/{services}.php'); + } } } From c1993e8e73922d8f06ef25a025ad8f7006759316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Tibensk=C3=BD?= <ttibensky@users.noreply.github.com> Date: Sun, 10 Apr 2022 14:23:47 +0200 Subject: [PATCH 1489/1519] Fix invalid interface mention in security.rst SerializableInterface doesn't exist, I assume it was meant to be https://www.php.net/manual/en/class.serializable.php, the motivation behind this change is described here https://stackoverflow.com/questions/42074225/symfony-userinterface-is-serializing-the-entire-massive-user-entity/71816482#71816482 --- security.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security.rst b/security.rst index d29f1480f78..e04a67e41a6 100644 --- a/security.rst +++ b/security.rst @@ -2503,9 +2503,9 @@ However, in some cases, this process can cause unexpected authentication problem If you're having problems authenticating, it could be that you *are* authenticating successfully, but you immediately lose authentication after the first redirect. -In that case, review the serialization logic (e.g. ``SerializableInterface``) on +In that case, review the serialization logic (e.g. ``\Serializable`` interface) on you user class (if you have any) to make sure that all the fields necessary are -serialized. +serialized and also exclude all the fields not necessary to be serialized (relations). Comparing Users Manually with EquatableInterface ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 2e5a64da828f1bafdb1b4170680a12c7c54d18dd Mon Sep 17 00:00:00 2001 From: Christian Flothmann <christian.flothmann@qossmic.com> Date: Wed, 13 Apr 2022 13:36:58 +0200 Subject: [PATCH 1490/1519] add back information on accessing the context in guard events This information was present in older versions of the documentation, but got lost when the `versionadded` directive was removed in the `6.0` branch. --- workflow.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/workflow.rst b/workflow.rst index 49486c00074..730ddc0926b 100644 --- a/workflow.rst +++ b/workflow.rst @@ -382,14 +382,14 @@ order: $workflow->apply($subject, $transitionName, [Workflow::DISABLE_ANNOUNCE_EVENT => true]); - The context is accessible in all events:: +The context is accessible in all events except for the ``workflow.guard`` events:: - // $context must be an array - $context = ['context_key' => 'context_value']; - $workflow->apply($subject, $transitionName, $context); + // $context must be an array + $context = ['context_key' => 'context_value']; + $workflow->apply($subject, $transitionName, $context); - // in an event listener (workflow.guard events) - $context = $event->getContext(); // returns ['context'] + // in an event listener (workflow.guard events) + $context = $event->getContext(); // returns ['context'] .. note:: From 612ec53fa615dabcc9341712bc5674496d7d1a43 Mon Sep 17 00:00:00 2001 From: Christian Flothmann <christian.flothmann@qossmic.com> Date: Wed, 13 Apr 2022 13:38:48 +0200 Subject: [PATCH 1491/1519] move versionadded directive out of list item This information is not only related to the `workflow.announce` event, but provides important information for other events too. --- workflow.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/workflow.rst b/workflow.rst index b44b417f333..5d972858c28 100644 --- a/workflow.rst +++ b/workflow.rst @@ -386,17 +386,17 @@ order: The ``Workflow::DISABLE_ANNOUNCE_EVENT`` constant was introduced in Symfony 5.1. - .. versionadded:: 5.2 +.. versionadded:: 5.2 - In Symfony 5.2, the context is customizable for all events except for - ``workflow.guard`` events, which will not receive the custom ``$context``:: + In Symfony 5.2, the context is customizable for all events except for + ``workflow.guard`` events, which will not receive the custom ``$context``:: - // $context must be an array - $context = ['context_key' => 'context_value']; - $workflow->apply($subject, $transitionName, $context); + // $context must be an array + $context = ['context_key' => 'context_value']; + $workflow->apply($subject, $transitionName, $context); - // in an event listener - $context = $event->getContext(); // returns ['context'] + // in an event listener + $context = $event->getContext(); // returns ['context'] .. note:: From 2d13ead362106f6d83d2811cb4b77d57efadae0e Mon Sep 17 00:00:00 2001 From: Florian-B <Florian-B@users.noreply.github.com> Date: Wed, 13 Apr 2022 13:54:13 +0200 Subject: [PATCH 1492/1519] Update configuration.rst --- configuration.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/configuration.rst b/configuration.rst index ef6050ba34f..114fcb8cb51 100644 --- a/configuration.rst +++ b/configuration.rst @@ -465,6 +465,12 @@ files directly in the ``config/packages/`` directory. when@test: webpack_encore: strict_mode: false + + # you can use "Yaml anchors" to share config between multiple environments (make "test" config identical to "prod") + when@prod: &webpack_prod + webpack_encore: + # ... + when@test: *webpack_prod .. code-block:: xml From 38902a52438c2457109c1936bf8e63cb18bdaad2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Wed, 13 Apr 2022 17:12:59 +0200 Subject: [PATCH 1493/1519] Minor reword --- configuration.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/configuration.rst b/configuration.rst index 114fcb8cb51..e74eaa8b862 100644 --- a/configuration.rst +++ b/configuration.rst @@ -465,8 +465,9 @@ files directly in the ``config/packages/`` directory. when@test: webpack_encore: strict_mode: false - - # you can use "Yaml anchors" to share config between multiple environments (make "test" config identical to "prod") + + # YAML syntax allows to reuse contents using "anchors" (&some_name) and "aliases" (*some_name). + # In this example, 'test' configuration uses the exact same configuration as in 'prod' when@prod: &webpack_prod webpack_encore: # ... From 3ae47aa3819fc687d42402d2effbcd10916094c0 Mon Sep 17 00:00:00 2001 From: Florian-B <Florian-B@users.noreply.github.com> Date: Tue, 19 Apr 2022 16:48:50 +0200 Subject: [PATCH 1494/1519] Add InteractiveAuthenticatorInterface reference --- security/custom_authenticator.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/security/custom_authenticator.rst b/security/custom_authenticator.rst index f75cb8df444..773e31360b7 100644 --- a/security/custom_authenticator.rst +++ b/security/custom_authenticator.rst @@ -176,6 +176,13 @@ can define what happens in these cases: above. Use :class:`Symfony\\Component\\Security\\Core\\Exception\\CustomUserMessageAuthenticationException` if you want to set custom error messages. +.. tip:: + + If your login method is interactive, which means that the user actively logged into your application, you may want your authenticator to implement the + :class:`Symfony\\Component\\Security\\Http\\Authenticator\\InteractiveAuthenticatorInterface` + so that it dispatches an + :class:`Symfony\\Component\\Security\\Http\\Event\\InteractiveLoginEvent` + .. _security-passport: Security Passports From 3feb2baee28cc5cf09f4e94bb91771247a473595 Mon Sep 17 00:00:00 2001 From: Maxime Nicole <101107892+ncsmnicole@users.noreply.github.com> Date: Fri, 15 Apr 2022 15:47:02 +0200 Subject: [PATCH 1495/1519] Replace duplicate medium configuration --- notifier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier.rst b/notifier.rst index 25a2ee442fb..786614e2ecd 100644 --- a/notifier.rst +++ b/notifier.rst @@ -601,7 +601,7 @@ specify what channels should be used for specific levels (using ->channelPolicy('high', ['chat/slack']) // Use browser for medium and low notifications ->channelPolicy('medium', ['browser']) - ->channelPolicy('medium', ['browser']) + ->channelPolicy('low', ['browser']) ; }; From 90acacaac608762e3d6948c58134ac1cd5f1661f Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Sat, 16 Apr 2022 16:57:03 +0200 Subject: [PATCH 1496/1519] Document console completion --- _images/components/console/completion.gif | Bin 0 -> 154106 bytes console.rst | 142 +++++++++++++++++----- console/input.rst | 87 +++++++++++++ page_creation.rst | 7 ++ 4 files changed, 203 insertions(+), 33 deletions(-) create mode 100644 _images/components/console/completion.gif diff --git a/_images/components/console/completion.gif b/_images/components/console/completion.gif new file mode 100644 index 0000000000000000000000000000000000000000..011ae0b935e51f8cd41a291e9f2c0d0e3d422259 GIT binary patch literal 154106 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[$%RG0^F`AU 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ν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 (1xD}r(kc=uTc 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 literal 0 HcmV?d00001 diff --git a/console.rst b/console.rst index 9de02a4b882..9dd9cecddb4 100644 --- a/console.rst +++ b/console.rst @@ -9,15 +9,90 @@ The Symfony framework provides lots of commands through the ``bin/console`` scri created with the :doc:`Console component </components/console>`. You can also use it to create your own commands. -The Console: APP_ENV & APP_DEBUG ---------------------------------- +Running Commands +---------------- + +Each Symfony application comes with a large set of commands. You can use +the ``list`` command to view all available commands in the application: + +.. code-block:: terminal + + $ php bin/console list + ... + + Available commands: + about Display information about the current project + completion Dump the shell completion script + help Display help for a command + list List commands + assets + assets:install Install bundle's web assets under a public directory + cache + cache:clear Clear the cache + ... + +If you find the command you need, you can run it with the ``--help`` option +to view the command's documentation: + +.. code-block:: terminal + + $ php bin/console assets:install --help + +APP_ENV & APP_DEBUG +~~~~~~~~~~~~~~~~~~~ Console commands run in the :ref:`environment <config-dot-env>` defined in the ``APP_ENV`` variable of the ``.env`` file, which is ``dev`` by default. It also reads the ``APP_DEBUG`` value to turn "debug" mode on or off (it defaults to ``1``, which is on). To run the command in another environment or debug mode, edit the value of ``APP_ENV`` -and ``APP_DEBUG``. +and ``APP_DEBUG``. You can also define this env vars when running the +command, for instance: + +.. code-block:: terminal + + # clears the cache for the prod environment + $ APP_ENV=prod php bin/console cache:clear + +.. _console-completion-setup: + +Console Completion +~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 5.4 + + Console completion for Bash was introduced in Symfony 5.4. + +If you are using the Bash shell, you can install Symfony's completion +script to get auto completion when typing commands in the terminal. All +commands support name and option completion, and some can even complete +values. + +.. image:: /_images/components/console/completion.gif + +First, make sure you installed and setup the "bash completion" package for +your OS (typically named ``bash-completion``). Then, install the Symfony +completion bash script *once* by running the ``completion`` command in a +Symfony app installed on your computer: + +.. code-block:: terminal + + $ php bin/console completion bash | sudo tee /etc/bash_completion.d/console-events-terminate + # after the installation, restart the shell + +Now you are all set to use the auto completion for all Symfony Console +applications on your computer. By default, you can get a list of complete +options by pressing the Tab key. + +.. tip:: + + Many PHP tools are built using the Symfony Console component (e.g. + Composer, PHPstan and Behat). If they are using version 5.4 or higher, + you can also install their completion script to enable console completion: + + .. code-block:: terminal + + $ php vendor/bin/phpstan completion bash | sudo tee /etc/bash_completion.d/phpstan Creating a Command ------------------ @@ -38,11 +113,6 @@ want a command to create a user:: // the name of the command (the part after "bin/console") protected static $defaultName = 'app:create-user'; - protected function configure(): void - { - // ... - } - protected function execute(InputInterface $input, OutputInterface $output): int { // ... put here the code to create the user @@ -74,37 +144,41 @@ want a command to create a user:: The ``Command::INVALID`` constant was introduced in Symfony 5.3 Configuring the Command ------------------------ +~~~~~~~~~~~~~~~~~~~~~~~ You can optionally define a description, help message and the -:doc:`input options and arguments </console/input>`:: +:doc:`input options and arguments </console/input>` by overriding the +``configure()`` method:: - // ... - // the command description shown when running "php bin/console list" - protected static $defaultDescription = 'Creates a new user.'; + // src/Command/CreateUserCommand.php // ... - protected function configure(): void + class CreateUserCommand extends Command { - $this - // If you don't like using the $defaultDescription static property, - // you can also define the short description using this method: - // ->setDescription('...') + // the command description shown when running "php bin/console list" + protected static $defaultDescription = 'Creates a new user.'; - // the command help shown when running the command with the "--help" option - ->setHelp('This command allows you to create a user...') - ; + // ... + protected function configure(): void + { + $this + // the command help shown when running the command with the "--help" option + ->setHelp('This command allows you to create a user...') + ; + } } -Defining the ``$defaultDescription`` static property instead of using the -``setDescription()`` method allows to get the command description without -instantiating its class. This makes the ``php bin/console list`` command run -much faster. +.. tip:: + + Defining the ``$defaultDescription`` static property instead of using the + ``setDescription()`` method allows to get the command description without + instantiating its class. This makes the ``php bin/console list`` command run + much faster. -If you want to always run the ``list`` command fast, add the ``--short`` option -to it (``php bin/console list --short``). This will avoid instantiating command -classes, but it won't show any description for commands that use the -``setDescription()`` method instead of the static property. + If you want to always run the ``list`` command fast, add the ``--short`` option + to it (``php bin/console list --short``). This will avoid instantiating command + classes, but it won't show any description for commands that use the + ``setDescription()`` method instead of the static property. .. versionadded:: 5.3 @@ -144,7 +218,7 @@ available in the ``configure()`` method:: } Registering the Command ------------------------ +~~~~~~~~~~~~~~~~~~~~~~~ In PHP 8 and newer versions, you can register the command by adding the ``AsCommand`` attribute to it:: @@ -155,6 +229,8 @@ In PHP 8 and newer versions, you can register the command by adding the use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; + // the "name" and "description" arguments of AsCommand replace the + // static $defaultName and $defaultDescription properties #[AsCommand( name: 'app:create-user', description: 'Creates a new user.', @@ -176,8 +252,8 @@ If you can't use PHP attributes, register the command as a service and :ref:`default services.yaml configuration <service-container-services-load-example>`, this is already done for you, thanks to :ref:`autoconfiguration <services-autoconfigure>`. -Executing the Command ---------------------- +Running the Command +~~~~~~~~~~~~~~~~~~~ After configuring and registering the command, you can run it in the terminal: @@ -468,7 +544,7 @@ call ``setAutoExit(false)`` on it to get the command result in ``CommandTester`` $application = new Application(); $application->setAutoExit(false); - + $tester = new ApplicationTester($application); .. note:: diff --git a/console/input.rst b/console/input.rst index 3bbba7e5fce..efdacee2ce5 100644 --- a/console/input.rst +++ b/console/input.rst @@ -308,4 +308,91 @@ The above code can be simplified as follows because ``false !== null``:: $yell = ($optionValue !== false); $yellLouder = ($optionValue === 'louder'); +Adding Argument/Option Value Completion +--------------------------------------- + +.. versionadded:: 5.4 + + Console completion was introduced in Symfony 5.4. + +If :ref:`Console completion is installed <console-completion-setup>`, +command and option names will be auto completed by the shell. However, you +can also implement value completion for the input in your commands. For +instance, you may want to complete all usernames from the database in the +``name`` argument of your greet command. + +To achieve this, override the ``complete()`` method in the command:: + + // ... + use Symfony\Component\Console\Completion\CompletionInput; + use Symfony\Component\Console\Completion\CompletionSuggestions; + + class GreetCommand extends Command + { + // ... + + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + if ($input->mustSuggestArgumentValuesFor('names')) { + // the user asks for completion input for the "names" option + + // the value the user already typed, e.g. when typing "app:greet Fa" before + // pressing Tab, this will contain "Fa" + $currentValue = $input->getCompletionValue(); + + // get the list of username names from somewhere (e.g. the database) + // you may use $currentValue to filter down the names + $availableUsernames = ...; + + // then add the retrieved names as suggested values + $suggestions->suggestValues($availableUsernames); + } + } + } + +That's all you need! Assuming users "Fabien" and "Fabrice" exist, pressing +tab after typing ``app:greet Fa`` will give you these names as a suggestion. + +.. tip:: + + The bash shell is able to handle huge amounts of suggestions and will + automatically filter the suggested values based on the existing input + from the user. You do not have to implement any filter logic in the + command. + + You may use ``CompletionInput::getCompletionValue()`` to get the + current input if that helps improving performance (e.g. by reducing the + number of rows fetched from the database). + +Testing the Completion script +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Console component comes with a special +:class:`Symfony\\Component\\Console\\Test\\CommandCompletionTester`` class +to help you unit test the completion logic:: + + // ... + use Symfony\Component\Console\Application; + + class GreetCommandTest extends TestCase + { + public function testComplete() + { + $application = new Application(); + $application->add(new GreetCommand()); + + // create a new tester with the greet command + $tester = new CommandCompletionTester($application->get('app:greet')); + + // complete the input without any existing input (the empty string represents + // the position of the cursor) + $suggestions = $tester->complete(['']); + $this->assertSame(['Fabien', 'Fabrice', 'Wouter'], $suggestions); + + // complete the input with "Fa" as input + $suggestions = $tester->complete(['Fa']); + $this->assertSame(['Fabien', 'Fabrice'], $suggestions); + } + } + .. _`docopt standard`: http://docopt.org/ diff --git a/page_creation.rst b/page_creation.rst index a8d97aac618..af315b188c4 100644 --- a/page_creation.rst +++ b/page_creation.rst @@ -195,6 +195,13 @@ the debugging routes in the next section. You'll learn about many more commands as you continue! +.. tip:: + + If you are using the Bash shell, you can set up completion support. + This autocompletes commands and other input when using ``bin/console``. + See :ref:`the Console document <console-completion-setup>` for more + information on how to set up completion. + .. _web-debug-toolbar: The Web Debug Toolbar: Debugging Dream From 6e7b827d77a83bb606dc644eae78e31b2c374406 Mon Sep 17 00:00:00 2001 From: Wouter de Jong <wouter@wouterj.nl> Date: Thu, 21 Apr 2022 14:06:12 +0200 Subject: [PATCH 1497/1519] No longer mention a deprecated interface --- security.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/security.rst b/security.rst index e04a67e41a6..3db9857f17a 100644 --- a/security.rst +++ b/security.rst @@ -2503,9 +2503,10 @@ However, in some cases, this process can cause unexpected authentication problem If you're having problems authenticating, it could be that you *are* authenticating successfully, but you immediately lose authentication after the first redirect. -In that case, review the serialization logic (e.g. ``\Serializable`` interface) on -you user class (if you have any) to make sure that all the fields necessary are -serialized and also exclude all the fields not necessary to be serialized (relations). +In that case, review the serialization logic (e.g. the ``__serialize()`` or +``serialize()`` methods) on you user class (if you have any) to make sure +that all the fields necessary are serialized and also exclude all the +fields not necessary to be serialized (e.g. Doctrine relations). Comparing Users Manually with EquatableInterface ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 8cfd997854af1d5979350dc69b662a49ec623853 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Mon, 25 Apr 2022 17:51:47 +0200 Subject: [PATCH 1498/1519] [Console] Remove some unneeded versionadded directives --- console.rst | 4 ---- console/input.rst | 4 ---- 2 files changed, 8 deletions(-) diff --git a/console.rst b/console.rst index d1c66031899..1d1e149afea 100644 --- a/console.rst +++ b/console.rst @@ -59,10 +59,6 @@ command, for instance: Console Completion ~~~~~~~~~~~~~~~~~~ -.. versionadded:: 5.4 - - Console completion for Bash was introduced in Symfony 5.4. - If you are using the Bash shell, you can install Symfony's completion script to get auto completion when typing commands in the terminal. All commands support name and option completion, and some can even complete diff --git a/console/input.rst b/console/input.rst index 9c1914500dd..36718199e6f 100644 --- a/console/input.rst +++ b/console/input.rst @@ -307,10 +307,6 @@ The above code can be simplified as follows because ``false !== null``:: Adding Argument/Option Value Completion --------------------------------------- -.. versionadded:: 5.4 - - Console completion was introduced in Symfony 5.4. - If :ref:`Console completion is installed <console-completion-setup>`, command and option names will be auto completed by the shell. However, you can also implement value completion for the input in your commands. For From 979bf2a1a4a201c73e12616672f1d837f633fb51 Mon Sep 17 00:00:00 2001 From: Jon Green <jon@tjs.co.uk> Date: Thu, 21 Apr 2022 17:30:20 +0100 Subject: [PATCH 1499/1519] Fix tag attribute in event XML example --- security.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security.rst b/security.rst index 3db9857f17a..ba1e521711b 100644 --- a/security.rst +++ b/security.rst @@ -2561,7 +2561,7 @@ for these events. <service id="App\EventListener\CustomLogoutSubscriber"> <tag name="kernel.event_subscriber" - dispacher="security.event_dispatcher.main" + dispatcher="security.event_dispatcher.main" /> </service> </services> From 834839d2795bf492d46911d79ab1ce1f6e292a2a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Tue, 26 Apr 2022 09:35:45 +0200 Subject: [PATCH 1500/1519] Minor tweak --- security/custom_authenticator.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/custom_authenticator.rst b/security/custom_authenticator.rst index 773e31360b7..bc2f116bbc4 100644 --- a/security/custom_authenticator.rst +++ b/security/custom_authenticator.rst @@ -178,7 +178,8 @@ can define what happens in these cases: .. tip:: - If your login method is interactive, which means that the user actively logged into your application, you may want your authenticator to implement the + If your login method is interactive, which means that the user actively + logged into your application, you may want your authenticator to implement the :class:`Symfony\\Component\\Security\\Http\\Authenticator\\InteractiveAuthenticatorInterface` so that it dispatches an :class:`Symfony\\Component\\Security\\Http\\Event\\InteractiveLoginEvent` From 9fa967eca837b89dd2798d12ac3f168ddc1af517 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson <jon.johnson@ucsf.edu> Date: Tue, 26 Apr 2022 21:03:32 -0700 Subject: [PATCH 1501/1519] Update Length Validator Empty String Docs Empty strings are no longer valid if a min is passed, null values still validate. --- reference/constraints/Length.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/reference/constraints/Length.rst b/reference/constraints/Length.rst index c9569a7227d..140f804092e 100644 --- a/reference/constraints/Length.rst +++ b/reference/constraints/Length.rst @@ -113,7 +113,7 @@ and ``50``, you might add the following: } } -.. include:: /reference/constraints/_empty-values-are-valid.rst.inc +.. include:: /reference/constraints/_null-values-are-valid.rst.inc Options ------- @@ -199,9 +199,9 @@ the given value's length is **less** than this min value. This option is required when the ``max`` option is not defined. -It is important to notice that NULL values and empty strings are considered -valid no matter if the constraint required a minimum length. Validators -are triggered only if the value is not blank. +It is important to notice that ``null`` values are considered +valid no matter if the constraint requires a minimum length. Validators +are triggered only if the value is not ``null``. ``minMessage`` ~~~~~~~~~~~~~~ From f7318bba58ed9281d8c24551d889d7c86aa731e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20FUCHS?= <sebastienfuchs@tousvoisins.fr> Date: Wed, 27 Apr 2022 14:58:41 +0200 Subject: [PATCH 1502/1519] [Form] [Forms] rounding default const up to down --- reference/forms/types/options/rounding_mode.rst.inc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/reference/forms/types/options/rounding_mode.rst.inc b/reference/forms/types/options/rounding_mode.rst.inc index 525f5d99cdf..84069894723 100644 --- a/reference/forms/types/options/rounding_mode.rst.inc +++ b/reference/forms/types/options/rounding_mode.rst.inc @@ -1,7 +1,14 @@ rounding_mode ~~~~~~~~~~~~~ -**type**: ``integer`` **default**: ``\NumberFormatter::ROUND_HALFUP`` +**type**: ``integer`` + +* IntegerType +**default**: ``\NumberFormatter::ROUND_DOWN`` + +* MoneyType and NumberType +**default**: ``\NumberFormatter::ROUND_HALF_UP`` + If a submitted number needs to be rounded (based on the `scale`_ option), you have several configurable options for that rounding. Each option is a constant From 274438d0a4bc024f1709fb6fff377ad71726b3ed Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Fri, 29 Apr 2022 16:38:47 +0200 Subject: [PATCH 1503/1519] Minor tweak --- reference/forms/types/options/rounding_mode.rst.inc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/reference/forms/types/options/rounding_mode.rst.inc b/reference/forms/types/options/rounding_mode.rst.inc index 84069894723..53403056585 100644 --- a/reference/forms/types/options/rounding_mode.rst.inc +++ b/reference/forms/types/options/rounding_mode.rst.inc @@ -1,7 +1,8 @@ rounding_mode ~~~~~~~~~~~~~ -**type**: ``integer`` +**type**: ``integer`` **default**: ``\NumberFormatter::ROUND_DOWN`` for ``IntegerType`` +and ``\NumberFormatter::ROUND_HALF_UP`` for ``MoneyType`` and ``NumberType`` * IntegerType **default**: ``\NumberFormatter::ROUND_DOWN`` From e875eff0ca70cb6de5aad863fb184bf6555fcc7f Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Sun, 1 May 2022 04:04:12 +0200 Subject: [PATCH 1504/1519] Fix build errors --- form/form_collections.rst | 2 +- form/form_customization.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/form/form_collections.rst b/form/form_collections.rst index 8b34dc700aa..ca7dd6228f7 100644 --- a/form/form_collections.rst +++ b/form/form_collections.rst @@ -657,7 +657,7 @@ the relationship between the removed ``Tag`` and ``Task`` object. The Symfony community has created some JavaScript packages that provide the functionality needed to add, edit and delete elements of the collection. Check out the `@a2lix/symfony-collection`_ package for modern browsers and - the `symfony-collection`_ package based on `jQuery`_ for the rest of browsers. + the `symfony-collection`_ package based on jQuery for the rest of browsers. .. _`Owning Side and Inverse Side`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/unitofwork-associations.html .. _`JSFiddle`: https://jsfiddle.net/ey8ozh6n/ diff --git a/form/form_customization.rst b/form/form_customization.rst index 7c1fc159404..738ac6a947e 100644 --- a/form/form_customization.rst +++ b/form/form_customization.rst @@ -270,7 +270,7 @@ Renders any errors for the given field. In the Bootstrap 4 form theme, ``form_errors()`` is already included in ``form_label()``. Read more about this in the - :ref:`Bootstrap 4 theme documentation <reference-forms-bootstrap5-error-messages>`. + :ref:`Bootstrap 4 theme documentation <reference-forms-bootstrap4-error-messages>`. .. _reference-forms-twig-widget: From c150197d314e45c6f97cb9d53bca8218f18be021 Mon Sep 17 00:00:00 2001 From: Kevin Bond <kevinbond@gmail.com> Date: Fri, 29 Apr 2022 13:35:51 -0400 Subject: [PATCH 1505/1519] [Messenger] fix xml block --- messenger.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/messenger.rst b/messenger.rst index 605561e39d5..56ef5af1382 100644 --- a/messenger.rst +++ b/messenger.rst @@ -753,8 +753,8 @@ reset the service container between two messages: https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> <framework:config> - <framework:messenger> - <framework:transport name="async" dsn="%env(MESSENGER_TRANSPORT_DSN)%" reset-on-message="true"> + <framework:messenger reset-on-message="true"> + <framework:transport name="async" dsn="%env(MESSENGER_TRANSPORT_DSN)%"> </framework:transport> </framework:messenger> </framework:config> @@ -775,6 +775,12 @@ reset the service container between two messages: The ``reset_on_message`` option was introduced in Symfony 5.4. +.. note:: + + ``reset_on_message`` will default to true (with no other allowed value) in + Symfony 6. To disable this behavior, execute the ``messenger:consume`` + command with the ``--no-reset`` option. + .. _messenger-retries-failures: Retries & Failures From 24311262be5e375c389d99b2b2d2311bd21b1308 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Tue, 3 May 2022 16:50:09 +0200 Subject: [PATCH 1506/1519] Readd some missing contents --- http_client.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/http_client.rst b/http_client.rst index 852ec84c7b7..8123c081aa7 100644 --- a/http_client.rst +++ b/http_client.rst @@ -1837,9 +1837,16 @@ Testing Request Data The ``MockResponse`` class comes with some helper methods to test the request: +* ``getRequestMethod()`` - returns the HTTP method; +* ``getRequestUrl()`` - returns the URL the request would be sent to; * ``getRequestOptions()`` - returns an array containing other information about the request such as headers, query parameters, body content etc. +.. versionadded:: 5.2 + + The ``getRequestMethod()`` and ``getRequestUrl()`` methods were introduced + in Symfony 5.2. + Usage example:: $mockResponse = new MockResponse('', ['http_code' => 204]); @@ -1852,6 +1859,12 @@ Usage example:: ], ]); + $mockResponse->getRequestMethod(); + // returns "DELETE" + + $mockResponse->getRequestUrl(); + // returns "https://example.com/api/article/1337" + $mockResponse->getRequestOptions()['headers']; // returns ["Accept: */*", "Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l"] @@ -1925,6 +1938,8 @@ test it in a real application:: $responseData = $service->createArticle($requestData); // Assert + self::assertSame('POST', $mockResponse->getRequestMethod()); + self::assertSame('https://example.com/api/article', $mockResponse->getRequestUrl()); self::assertContains( 'Content-Type: application/json', $mockResponse->getRequestOptions()['headers'] From 3f4fb3c73bad60cf9a2b539900627c6fb5987143 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Tue, 3 May 2022 16:50:45 +0200 Subject: [PATCH 1507/1519] Removed a versionadded directive --- http_client.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/http_client.rst b/http_client.rst index ca6d4cca534..332e2ccd6e3 100644 --- a/http_client.rst +++ b/http_client.rst @@ -1800,11 +1800,6 @@ The ``MockResponse`` class comes with some helper methods to test the request: * ``getRequestOptions()`` - returns an array containing other information about the request such as headers, query parameters, body content etc. -.. versionadded:: 5.2 - - The ``getRequestMethod()`` and ``getRequestUrl()`` methods were introduced - in Symfony 5.2. - Usage example:: $mockResponse = new MockResponse('', ['http_code' => 204]); From 3820455780e09c28f73c489f42445ae0580ad8cc Mon Sep 17 00:00:00 2001 From: Ryan Weaver <ryan@thatsquality.com> Date: Wed, 4 May 2022 09:50:20 -0400 Subject: [PATCH 1508/1519] removing references to flex.symfony.com --- page_creation.rst | 2 +- quick_tour/flex_recipes.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/page_creation.rst b/page_creation.rst index af315b188c4..48e20b08e0b 100644 --- a/page_creation.rst +++ b/page_creation.rst @@ -368,4 +368,4 @@ Go Deeper with HTTP & Framework Fundamentals .. _`Twig`: https://twig.symfony.com .. _`Composer`: https://getcomposer.org .. _`Stellar Development with Symfony`: https://symfonycasts.com/screencast/symfony/setup -.. _`Flex recipes`: https://flex.symfony.com +.. _`Flex recipes`: https://github.com/symfony/recipes/blob/flex/main/RECIPES.md diff --git a/quick_tour/flex_recipes.rst b/quick_tour/flex_recipes.rst index 7df715aca5a..7135c6b3ecd 100644 --- a/quick_tour/flex_recipes.rst +++ b/quick_tour/flex_recipes.rst @@ -53,7 +53,7 @@ It's a way for a library to automatically configure itself by adding and modifyi files. Thanks to recipes, adding features is seamless and automated: install a package and you're done! -You can find a full list of recipes and aliases by going to `https://flex.symfony.com`_. +You can find a full list of recipes and aliases inside `RECIPES.md on the recipes repository`_. What did this recipe do? In addition to automatically enabling the feature in ``config/bundles.php``, it added 3 things: @@ -264,6 +264,6 @@ and it's the most important yet. I want to show you how Symfony empowers you to build features *without* sacrificing code quality or performance. It's all about the service container, and it's Symfony's super power. Read on: about :doc:`/quick_tour/the_architecture`. -.. _`https://flex.symfony.com`: https://flex.symfony.com +.. _`RECIPES.md on the recipes repository`: https://github.com/symfony/recipes/blob/flex/main/RECIPES.md .. _`API Platform`: https://api-platform.com/ .. _`Twig`: https://twig.symfony.com/ From 1f2f0e4870c15943e06a0b0b1f30f5bbe7d67ac6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Wed, 4 May 2022 16:20:49 +0200 Subject: [PATCH 1509/1519] Remove an unused reference --- frontend/encore/simple-example.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/encore/simple-example.rst b/frontend/encore/simple-example.rst index b8838354235..21a3bad9093 100644 --- a/frontend/encore/simple-example.rst +++ b/frontend/encore/simple-example.rst @@ -467,7 +467,6 @@ Encore supports many more features! For a full list of what you can do, see .. _`WebpackEncoreBundle Configuration`: https://github.com/symfony/webpack-encore-bundle#configuration .. _`Stimulus`: https://stimulus.hotwired.dev/ .. _`Stimulus Documentation`: https://stimulus.hotwired.dev/handbook/introduction -.. _`Symfony UX Packages`: https://github.com/symfony/ux .. _`Symfony Stimulus Bridge`: https://github.com/symfony/stimulus-bridge .. _`Turbo`: https://turbo.hotwired.dev/ .. _`symfony/ux-turbo`: https://symfony.com/bundles/ux-turbo/current/index.html From 9ac9388fc0e381103ba646246dbfd686c6a0f691 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Wed, 4 May 2022 17:24:09 +0200 Subject: [PATCH 1510/1519] Minor tweak --- messenger.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/messenger.rst b/messenger.rst index 56ef5af1382..016274aec79 100644 --- a/messenger.rst +++ b/messenger.rst @@ -777,8 +777,8 @@ reset the service container between two messages: .. note:: - ``reset_on_message`` will default to true (with no other allowed value) in - Symfony 6. To disable this behavior, execute the ``messenger:consume`` + ``reset_on_message`` will default to ``true`` (with no other allowed value) + in Symfony 6. To disable this behavior, execute the ``messenger:consume`` command with the ``--no-reset`` option. .. _messenger-retries-failures: From f9b31a094fcaf46373d904ff6582c9745d5ce852 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Wed, 4 May 2022 17:36:08 +0200 Subject: [PATCH 1511/1519] [Messenger] remove reset_on_message config --- messenger.rst | 48 +++--------------------------------------------- 1 file changed, 3 insertions(+), 45 deletions(-) diff --git a/messenger.rst b/messenger.rst index 007bc80f6cf..f5426faf7ae 100644 --- a/messenger.rst +++ b/messenger.rst @@ -711,51 +711,9 @@ states to prevent information and/or memory leakage. However, certain Symfony services, such as the Monolog :ref:`fingers crossed handler <logging-handler-fingers_crossed>`, leak by design. -In those cases, use the ``reset_on_message`` transport option to automatically -reset the service container between two messages: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/messenger.yaml - framework: - messenger: - reset_on_message: true - transports: - async: - dsn: '%env(MESSENGER_TRANSPORT_DSN)%' - - .. code-block:: xml - - <!-- config/packages/messenger.xml --> - <?xml version="1.0" encoding="UTF-8" ?> - <container xmlns="http://symfony.com/schema/dic/services" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:framework="http://symfony.com/schema/dic/symfony" - xsi:schemaLocation="http://symfony.com/schema/dic/services - https://symfony.com/schema/dic/services/services-1.0.xsd - http://symfony.com/schema/dic/symfony - https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - - <framework:config> - <framework:messenger reset-on-message="true"> - <framework:transport name="async" dsn="%env(MESSENGER_TRANSPORT_DSN)%"> - </framework:transport> - </framework:messenger> - </framework:config> - </container> - - .. code-block:: php - - // config/packages/messenger.php - use Symfony\Config\FrameworkConfig; - - return static function (FrameworkConfig $framework) { - $messenger = $framework->messenger(); - - $messenger->resetOnMessage(true); - }; +That's why, by default, the service container is reset between consuming messages. +To disable this behavior, execute the ``messenger:consume`` command with the +``--no-reset`` option. .. _messenger-retries-failures: From 01eb82e95189f2c4b288af443cfd3dc8b746e5a2 Mon Sep 17 00:00:00 2001 From: wadjeroudi <wahid@wonetek.com> Date: Fri, 6 May 2022 10:32:10 +0200 Subject: [PATCH 1512/1519] Fix typo php-fpm => php-pm --- components/runtime.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/runtime.rst b/components/runtime.rst index 979a5a13aa7..adfec8c3622 100644 --- a/components/runtime.rst +++ b/components/runtime.rst @@ -6,7 +6,7 @@ The Runtime Component ====================== The Runtime Component decouples the bootstrapping logic from any global state - to make sure the application can run with runtimes like PHP-FPM, ReactPHP, + to make sure the application can run with runtimes like PHP-PM, ReactPHP, Swoole, etc. without any changes. .. versionadded:: 5.3 From 0ba643e6d838e508e57d1ce83dd149439bc786e8 Mon Sep 17 00:00:00 2001 From: Maxime Doutreluingne <maxime.doutreluingne@gmail.com> Date: Sat, 7 May 2022 17:59:13 +0200 Subject: [PATCH 1513/1519] Remove RetryTillSaveStore class --- components/lock.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index 2d4027fcc4c..76e4badb587 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -106,15 +106,12 @@ can be created, pass ``true`` as the argument of the ``acquire()`` method. This is called a **blocking lock** because the execution of your application stops until the lock is acquired. -Some of the built-in ``Store`` classes support this feature. When they don't, -they can be decorated with the ``RetryTillSaveStore`` class:: +Some of the built-in ``Store`` classes support this feature. use Symfony\Component\Lock\LockFactory; use Symfony\Component\Lock\Store\RedisStore; - use Symfony\Component\Lock\Store\RetryTillSaveStore; $store = new RedisStore(new \Predis\Client('tcp://localhost:6379')); - $store = new RetryTillSaveStore($store); $factory = new LockFactory($store); $lock = $factory->createLock('notification-flush'); From 1c76da83b90a2c5c0358edea3d8656c7812f8efd Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER <laurent.voullemier@gmail.com> Date: Mon, 9 May 2022 17:06:26 +0200 Subject: [PATCH 1514/1519] Remove enable_authenticator_manager --- security.rst | 4 ---- security/custom_authenticator.rst | 3 +-- security/entry_point.rst | 1 - security/login_link.rst | 7 ------- 4 files changed, 1 insertion(+), 14 deletions(-) diff --git a/security.rst b/security.rst index b3cc007d9bf..dac009b6c66 100644 --- a/security.rst +++ b/security.rst @@ -27,7 +27,6 @@ creates a ``security.yaml`` configuration file for you: # config/packages/security.yaml security: - enable_authenticator_manager: true # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords password_hashers: Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' @@ -1354,8 +1353,6 @@ You must enable this using the ``login_throttling`` setting: # config/packages/security.yaml security: - # you must use the authenticator manager - enable_authenticator_manager: true firewalls: # ... @@ -2289,7 +2286,6 @@ the login page): # config/packages/security.yaml security: - enable_authenticator_manager: true # ... access_control: diff --git a/security/custom_authenticator.rst b/security/custom_authenticator.rst index 6a7e80e039f..4178e254904 100644 --- a/security/custom_authenticator.rst +++ b/security/custom_authenticator.rst @@ -86,7 +86,6 @@ The authenticator can be enabled using the ``custom_authenticators`` setting: # config/packages/security.yaml security: - enable_authenticator_manager: true # ... firewalls: @@ -179,7 +178,7 @@ can define what happens in these cases: If your login method is interactive, which means that the user actively logged into your application, you may want your authenticator to implement the :class:`Symfony\\Component\\Security\\Http\\Authenticator\\InteractiveAuthenticatorInterface` - so that it dispatches an + so that it dispatches an :class:`Symfony\\Component\\Security\\Http\\Event\\InteractiveLoginEvent` .. _security-passport: diff --git a/security/entry_point.rst b/security/entry_point.rst index daee51493fa..db1141a95c6 100644 --- a/security/entry_point.rst +++ b/security/entry_point.rst @@ -18,7 +18,6 @@ You can configure this using the ``entry_point`` setting: # config/packages/security.yaml security: - enable_authenticator_manager: true # ... firewalls: diff --git a/security/login_link.rst b/security/login_link.rst index 9b99534d2c8..899c7a1c82a 100644 --- a/security/login_link.rst +++ b/security/login_link.rst @@ -14,13 +14,6 @@ This authentication method can help you eliminate most of the customer support related to authentication (e.g. I forgot my password, how can I change or reset my password, etc.) -.. note:: - - Login links are only supported by Symfony when using the - :doc:`authenticator system </security>`. Before using this - authenticator, make sure you have enabled it with - ``enable_authenticator_manager: true`` in your ``security.yaml`` file. - Using the Login Link Authenticator ---------------------------------- From cb96633c2e0d3dda415765bc36361483b64eba06 Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER <laurent.voullemier@gmail.com> Date: Tue, 10 May 2022 11:13:51 +0200 Subject: [PATCH 1515/1519] Creating a route for logout is always required Even if the default value is used --- reference/configuration/security.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index e65fc6ec26d..06d56d91008 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -382,8 +382,7 @@ the current firewall and not the other ones. **type**: ``string`` **default**: ``/logout`` -The path which triggers logout. If you change it from the default value ``/logout``, -you need to set up a route with a matching path. +The path which triggers logout. You need to set up a route with a matching path. target ~~~~~~ From e0e8a746985057c61b8affc44dabb3684a8452f5 Mon Sep 17 00:00:00 2001 From: Jules Pietri <heahdude@yahoo.fr> Date: Sat, 14 May 2022 11:46:25 +0200 Subject: [PATCH 1516/1519] Use PHP-DSL `env()` configurator when possible --- configuration.rst | 8 ++++++++ configuration/env_var_processors.rst | 10 +++++++++- configuration/secrets.rst | 2 +- doctrine/multiple_entity_managers.rst | 4 ++-- lock.rst | 2 +- mailer.rst | 8 ++++---- messenger.rst | 14 +++++++------- notifier.rst | 12 ++++++------ reference/configuration/framework.rst | 14 +++++++------- security/access_control.rst | 4 ++-- session/database.rst | 4 ++-- translation.rst | 2 +- 12 files changed, 50 insertions(+), 34 deletions(-) diff --git a/configuration.rst b/configuration.rst index e74eaa8b862..621cbc27094 100644 --- a/configuration.rst +++ b/configuration.rst @@ -644,10 +644,18 @@ This example shows how you could configure the database connection using an env 'dbal' => [ // by convention the env var names are always uppercase 'url' => '%env(resolve:DATABASE_URL)%', + // or + 'url' => env('DATABASE_URL')->resolve(), ], ]); }; +.. versionadded:: 5.3 + + The ``env()`` configurator syntax was introduced in 5.3. + In ``PHP`` configuration files, it will allow to autocomplete methods based + on processors name (i.e. ``env('SOME_VAR')->default('foo')``). + .. seealso:: The values of env vars can only be strings, but Symfony includes some diff --git a/configuration/env_var_processors.rst b/configuration/env_var_processors.rst index 2e73b823da4..4d2615fc3b6 100644 --- a/configuration/env_var_processors.rst +++ b/configuration/env_var_processors.rst @@ -50,10 +50,18 @@ processor to turn the value of the ``HTTP_PORT`` env var into an integer: return static function (FrameworkConfig $framework) { $framework->router() + ->httpPort('%env(int:HTTP_PORT)%') + // or ->httpPort(env('HTTP_PORT')->int()) ; }; +.. versionadded:: 5.3 + + The ``env()`` configurator syntax was introduced in 5.3. + In ``PHP`` configuration files, it will allow to autocomplete methods based + on processors name (i.e. ``env('SOME_VAR')->default('foo')``). + Built-In Environment Variable Processors ---------------------------------------- @@ -241,7 +249,7 @@ Symfony provides the following env var processors: $container->setParameter('env(HEALTH_CHECK_METHOD)', 'Symfony\Component\HttpFoundation\Request::METHOD_HEAD'); $security->accessControl() ->path('^/health-check$') - ->methods(['%env(const:HEALTH_CHECK_METHOD)%']); + ->methods([env('HEALTH_CHECK_METHOD')->const()]); }; ``env(base64:FOO)`` diff --git a/configuration/secrets.rst b/configuration/secrets.rst index 950f68528a3..5783ca9d918 100644 --- a/configuration/secrets.rst +++ b/configuration/secrets.rst @@ -148,7 +148,7 @@ If you stored a ``DATABASE_PASSWORD`` secret, you can reference it by: return static function (DoctrineConfig $doctrine) { $doctrine->dbal() ->connection('default') - ->password('%env(DATABASE_PASSWORD)%') + ->password(env('DATABASE_PASSWORD')) ; }; diff --git a/doctrine/multiple_entity_managers.rst b/doctrine/multiple_entity_managers.rst index e94ef907f57..856e796a2e9 100644 --- a/doctrine/multiple_entity_managers.rst +++ b/doctrine/multiple_entity_managers.rst @@ -136,7 +136,7 @@ The following configuration code shows how you can configure two entity managers // configure these for your database server $doctrine->dbal() ->connection('default') - ->url('%env(resolve:DATABASE_URL)%') + ->url(env('DATABASE_URL')->resolve()) ->driver('pdo_mysql') ->serverVersion('5.7') ->charset('utf8mb4'); @@ -144,7 +144,7 @@ The following configuration code shows how you can configure two entity managers // configure these for your database server $doctrine->dbal() ->connection('customer') - ->url('%env(resolve:DATABASE_CUSTOMER_URL)%') + ->url(env('DATABASE_CUSTOMER_URL')->resolve()) ->driver('pdo_mysql') ->serverVersion('5.7') ->charset('utf8mb4'); diff --git a/lock.rst b/lock.rst index 9fb207b927f..5d864fb0089 100644 --- a/lock.rst +++ b/lock.rst @@ -149,7 +149,7 @@ this behavior by using the ``lock`` key like: ->resource('default', ['sqlsrv:server=127.0.0.1;Database=app']) ->resource('default', ['oci:host=127.0.0.1;dbname=app']) ->resource('default', ['mongodb://127.0.0.1/app?collection=lock']) - ->resource('default', ['%env(LOCK_DSN)%']) + ->resource('default', [env('LOCK_DSN')]) // named locks ->resource('invoice', ['semaphore', 'redis://r2.docker']) diff --git a/mailer.rst b/mailer.rst index b79a61bb5cb..07fe907ab9a 100644 --- a/mailer.rst +++ b/mailer.rst @@ -60,7 +60,7 @@ over SMTP by configuring the DSN in your ``.env`` file (the ``user``, return static function (ContainerConfigurator $containerConfigurator): void { $containerConfigurator->extension('framework', [ 'mailer' => [ - 'dsn' => '%env(MAILER_DSN)%', + 'dsn' => env('MAILER_DSN'), ], ]); }; @@ -1170,8 +1170,8 @@ This can be configured by replacing the ``dsn`` configuration entry with a return static function (FrameworkConfig $framework) { $framework->mailer() - ->transport('main', '%env(MAILER_DSN)%') - ->transport('alternative', '%env(MAILER_DSN_IMPORTANT)%') + ->transport('main', env('MAILER_DSN')) + ->transport('alternative', env('MAILER_DSN_IMPORTANT')) ; }; @@ -1243,7 +1243,7 @@ you have a transport called ``async``, you can route the message there: return static function (FrameworkConfig $framework) { $framework->messenger() - ->transport('async')->dsn('%env(MESSENGER_TRANSPORT_DSN)%'); + ->transport('async')->dsn(env('MESSENGER_TRANSPORT_DSN')); $framework->messenger() ->routing('Symfony\Component\Mailer\Messenger\SendEmailMessage') diff --git a/messenger.rst b/messenger.rst index 016274aec79..4e1dae322de 100644 --- a/messenger.rst +++ b/messenger.rst @@ -193,12 +193,12 @@ that uses this configuration: return static function (FrameworkConfig $framework) { $framework->messenger() ->transport('async') - ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->dsn(env('MESSENGER_TRANSPORT_DSN')) ; $framework->messenger() ->transport('async') - ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->dsn(env('MESSENGER_TRANSPORT_DSN')) ->options([]) ; }; @@ -593,11 +593,11 @@ different messages to them. For example: $messenger = $framework->messenger(); $messenger->transport('async_priority_high') - ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->dsn(env('MESSENGER_TRANSPORT_DSN')) ->options(['queue_name' => 'high']); $messenger->transport('async_priority_low') - ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->dsn(env('MESSENGER_TRANSPORT_DSN')) ->options(['queue_name' => 'low']); $messenger->routing('App\Message\SmsNotification')->senders(['async_priority_low']); @@ -847,7 +847,7 @@ this is configurable for each transport: $messenger = $framework->messenger(); $messenger->transport('async_priority_high') - ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->dsn(env('MESSENGER_TRANSPORT_DSN')) // default configuration ->retryStrategy() ->maxRetries(3) @@ -1063,7 +1063,7 @@ override the failure transport for only specific transports: $messenger->failureTransport('failed_default'); $messenger->transport('async_priority_high') - ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->dsn(env('MESSENGER_TRANSPORT_DSN')) ->failureTransport('failed_high_priority'); // since no failed transport is configured, the one used will be @@ -1151,7 +1151,7 @@ options. Options can be passed to the transport via a DSN string or configuratio $messenger = $framework->messenger(); $messenger->transport('my_transport') - ->dsn('%env(MESSENGER_TRANSPORT_DSN)%') + ->dsn(env('MESSENGER_TRANSPORT_DSN')) ->options(['auto_setup' => false]); }; diff --git a/notifier.rst b/notifier.rst index 786614e2ecd..79b4480a096 100644 --- a/notifier.rst +++ b/notifier.rst @@ -158,7 +158,7 @@ configure the ``texter_transports``: return static function (FrameworkConfig $framework) { $framework->notifier() - ->texterTransport('twilio', '%env(TWILIO_DSN)%') + ->texterTransport('twilio', env('TWILIO_DSN')) ; }; @@ -255,7 +255,7 @@ Chatters are configured using the ``chatter_transports`` setting: return static function (FrameworkConfig $framework) { $framework->notifier() - ->chatterTransport('slack', '%env(SLACK_DSN)%') + ->chatterTransport('slack', env('SLACK_DSN')) ; }; @@ -319,7 +319,7 @@ notification emails: return static function (FrameworkConfig $framework) { $framework->mailer() - ->dsn('%env(MAILER_DSN)%') + ->dsn(env('MAILER_DSN')) ->envelope() ->sender('notifications@example.com') ; @@ -390,7 +390,7 @@ configure the ``texter_transports``: return static function (FrameworkConfig $framework) { $framework->notifier() - ->texterTransport('expo', '%env(EXPO_DSN)%') + ->texterTransport('expo', env('EXPO_DSN')) ; }; @@ -454,10 +454,10 @@ transport: $framework->notifier() // Send notifications to Slack and use Telegram if // Slack errored - ->chatterTransport('main', '%env(SLACK_DSN)% || %env(TELEGRAM_DSN)%') + ->chatterTransport('main', env('SLACK_DSN').' || '.env('TELEGRAM_DSN')) // Send notifications to the next scheduled transport calculated by round robin - ->chatterTransport('roundrobin', '%env(SLACK_DSN)% && %env(TELEGRAM_DSN)%') + ->chatterTransport('roundrobin', env('SLACK_DSN').' && '.env('TELEGRAM_DSN')) ; }; diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index ce8f8291db2..d5ee18b0e1a 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -298,7 +298,7 @@ some environment variable that stores the name of the IDE/editor: return static function (FrameworkConfig $framework) { // the env var stores the IDE/editor name (e.g. 'phpstorm', 'vscode', etc.) - $framework->ide('%env(resolve:CODE_EDITOR)%'); + $framework->ide(env('CODE_EDITOR')->resolve()); }; .. versionadded:: 5.3 @@ -596,14 +596,14 @@ can also :ref:`disable CSRF protection on individual forms <form-csrf-customizat .. configuration-block:: .. code-block:: yaml - + # config/packages/framework.yaml framework: # ... csrf_protection: true - + .. code-block:: xml - + <!-- config/packages/framework.xml --> <?xml version="1.0" encoding="UTF-8" ?> <container xmlns="http://symfony.com/schema/dic/services" @@ -617,9 +617,9 @@ can also :ref:`disable CSRF protection on individual forms <form-csrf-customizat <framework:csrf-protection enabled="true"/> </framework:config> </container> - + .. code-block:: php - + // config/packages/framework.php use Symfony\Config\FrameworkConfig; return static function (FrameworkConfig $framework) { @@ -3210,7 +3210,7 @@ A list of lock stores to be created by the framework extension. return static function (FrameworkConfig $framework) { $framework->lock() - ->resource('default', ['%env(LOCK_DSN)%']); + ->resource('default', [env('LOCK_DSN')]); }; .. seealso:: diff --git a/security/access_control.rst b/security/access_control.rst index 57c70fce5df..df9536fef2c 100644 --- a/security/access_control.rst +++ b/security/access_control.rst @@ -120,12 +120,12 @@ Take the following ``access_control`` entries as an example: $security->accessControl() ->path('^/admin') ->roles(['ROLE_USER_IP']) - ->ips(['%env(TRUSTED_IPS)%']) + ->ips([env('TRUSTED_IPS')]) ; $security->accessControl() ->path('^/admin') ->roles(['ROLE_USER_IP']) - ->ips(['127.0.0.1', '::1', '%env(TRUSTED_IPS)%']) + ->ips(['127.0.0.1', '::1', env('TRUSTED_IPS')]) ; }; diff --git a/session/database.rst b/session/database.rst index 16715c2b150..050eebb6a9d 100644 --- a/session/database.rst +++ b/session/database.rst @@ -229,7 +229,7 @@ first register a new handler service with your database credentials: $services->set(PdoSessionHandler::class) ->args([ - '%env(DATABASE_URL)%', + env('DATABASE_URL'), // you can also use PDO configuration, but requires passing two arguments: // 'mysql:dbname=mydatabase; host=myhost; port=myport', // ['db_username' => 'myuser', 'db_password' => 'mypassword'], @@ -334,7 +334,7 @@ passed to the ``PdoSessionHandler`` service: $services->set(PdoSessionHandler::class) ->args([ - '%env(DATABASE_URL)%', + env('DATABASE_URL'), ['db_table' => 'customer_session', 'db_id_col' => 'guid'], ]) ; diff --git a/translation.rst b/translation.rst index 6c18cf3e6f0..dc5288a09f0 100644 --- a/translation.rst +++ b/translation.rst @@ -714,7 +714,7 @@ configure the ``providers`` option: 'translator' => [ 'providers' => [ 'loco' => [ - 'dsn' => '%env(LOCO_DSN)%', + 'dsn' => env('LOCO_DSN'), 'domains' => ['messages'], 'locales' => ['en', 'fr'], ], From 5eb3931dfc592dc6670c157fe71161ad4a51d650 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Mon, 16 May 2022 17:32:43 +0200 Subject: [PATCH 1517/1519] Remove some unneeded versionadded directives --- configuration.rst | 6 ------ configuration/env_var_processors.rst | 6 ------ 2 files changed, 12 deletions(-) diff --git a/configuration.rst b/configuration.rst index 9995eeb0929..85e3e23adf4 100644 --- a/configuration.rst +++ b/configuration.rst @@ -645,12 +645,6 @@ This example shows how you could configure the database connection using an env ]); }; -.. versionadded:: 5.3 - - The ``env()`` configurator syntax was introduced in 5.3. - In ``PHP`` configuration files, it will allow to autocomplete methods based - on processors name (i.e. ``env('SOME_VAR')->default('foo')``). - .. seealso:: The values of env vars can only be strings, but Symfony includes some diff --git a/configuration/env_var_processors.rst b/configuration/env_var_processors.rst index 8d10c433549..84bccba97d5 100644 --- a/configuration/env_var_processors.rst +++ b/configuration/env_var_processors.rst @@ -56,12 +56,6 @@ processor to turn the value of the ``HTTP_PORT`` env var into an integer: ; }; -.. versionadded:: 5.3 - - The ``env()`` configurator syntax was introduced in 5.3. - In ``PHP`` configuration files, it will allow to autocomplete methods based - on processors name (i.e. ``env('SOME_VAR')->default('foo')``). - Built-In Environment Variable Processors ---------------------------------------- From 7fb76a59ae1f2cda0505750c5c522b5097af4c26 Mon Sep 17 00:00:00 2001 From: Tomas <norkunas.tom@gmail.com> Date: Tue, 10 May 2022 15:09:54 +0300 Subject: [PATCH 1518/1519] [Security] Fix typehint in custom user provider --- security/user_providers.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/security/user_providers.rst b/security/user_providers.rst index 07212acbf0b..0e202283a83 100644 --- a/security/user_providers.rst +++ b/security/user_providers.rst @@ -290,6 +290,7 @@ command will generate a nice skeleton to get you started:: use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Symfony\Component\Security\Core\Exception\UserNotFoundException; + use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; @@ -347,13 +348,13 @@ command will generate a nice skeleton to get you started:: } /** - * Upgrades the encoded password of a user, typically for using a better hash algorithm. + * Upgrades the hashed password of a user, typically for using a better hash algorithm. */ - public function upgradePassword(UserInterface $user, string $newEncodedPassword): void + public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void { - // TODO: when encoded passwords are in use, this method should: + // TODO: when hashed passwords are in use, this method should: // 1. persist the new password in the user storage - // 2. update the $user object with $user->setPassword($newEncodedPassword); + // 2. update the $user object with $user->setPassword($newHashedPassword); } } From 125124e16dfe65cc1ae4315e2451599608bc2986 Mon Sep 17 00:00:00 2001 From: guesmiii <med.guesmi1992@gmail.com> Date: Wed, 18 May 2022 20:06:19 +0200 Subject: [PATCH 1519/1519] Update input.rst VALUE_IS_ARRAY can't be used alone and must be combined with VALUE_REQUIRED or VALUE_OPTIONAL else we will get InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.') --- console/input.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/input.rst b/console/input.rst index 36718199e6f..cf8365455aa 100644 --- a/console/input.rst +++ b/console/input.rst @@ -221,7 +221,7 @@ There are five option variants you can use: Accept either the flag (e.g. ``--yell``) or its negation (e.g. ``--no-yell``). -You can combine ``VALUE_IS_ARRAY`` with ``VALUE_REQUIRED`` or +``VALUE_IS_ARRAY`` works only combined with ``VALUE_REQUIRED`` or ``VALUE_OPTIONAL`` like this:: $this